import type { Prisma, SprintStatus } from '@prisma/client' import { prisma } from '@/lib/prisma' import { mergeSettings, parseUserSettings, type UserSettings, } from '@/lib/user-settings' export type ActiveSprint = { id: string code: string status: SprintStatus } async function readSettings(userId: string): Promise { const user = await prisma.user.findUnique({ where: { id: userId }, select: { settings: true }, }) return parseUserSettings(user?.settings) } async function writeSettings(userId: string, next: UserSettings): Promise { await prisma.user.update({ where: { id: userId }, data: { settings: next as unknown as Prisma.InputJsonValue }, }) } async function notifyUserSettings( userId: string, patch: Partial, ): Promise { await prisma.$executeRaw` SELECT pg_notify('scrum4me_changes', ${JSON.stringify({ kind: 'user_settings', userId, patch, })}::text) ` } type StoredActiveSprintState = | { kind: 'unset' } | { kind: 'cleared' } | { kind: 'set'; sprintId: string } export function readStoredActiveSprintState( settings: UserSettings, productId: string, ): StoredActiveSprintState { const map = settings.layout?.activeSprints if (!map || !(productId in map)) return { kind: 'unset' } const value = map[productId] if (value === null) return { kind: 'cleared' } return { kind: 'set', sprintId: value } } export async function setActiveSprintInSettings( userId: string, productId: string, sprintId: string, ): Promise { const current = await readSettings(userId) const patch: Partial = { layout: { activeSprints: { ...(current.layout?.activeSprints ?? {}), [productId]: sprintId, }, }, } await writeSettings(userId, mergeSettings(current, patch)) await notifyUserSettings(userId, patch) } export async function clearActiveSprintInSettings( userId: string, productId: string, ): Promise { const current = await readSettings(userId) const nextActiveSprints: Record = { ...(current.layout?.activeSprints ?? {}), [productId]: null, } const next: UserSettings = { ...current, layout: { ...current.layout, activeSprints: nextActiveSprints }, } await writeSettings(userId, next) await notifyUserSettings(userId, { layout: { activeSprints: nextActiveSprints }, }) } /** * PBI-79: persisteer sprint-keuze + bijbehorende PBI/story-selectie atomair. * Sprintkeuze blijft 'sleutel met null = bewust geen sprint'-contract trouw; * activePbi/activeStory volgen dezelfde semantiek (null = expliciet leeg). */ export async function setActiveSelectionInSettings( userId: string, productId: string, selection: { sprintId: string | null pbiId?: string | null storyId?: string | null }, ): Promise { const current = await readSettings(userId) const nextActiveSprints: Record = { ...(current.layout?.activeSprints ?? {}), [productId]: selection.sprintId, } const nextActivePbis: Record = { ...(current.layout?.activePbis ?? {}), } if (selection.pbiId !== undefined) { nextActivePbis[productId] = selection.pbiId } const nextActiveStories: Record = { ...(current.layout?.activeStories ?? {}), } if (selection.storyId !== undefined) { nextActiveStories[productId] = selection.storyId } const next: UserSettings = { ...current, layout: { ...current.layout, activeSprints: nextActiveSprints, activePbis: nextActivePbis, activeStories: nextActiveStories, }, } await writeSettings(userId, next) await notifyUserSettings(userId, { layout: { activeSprints: nextActiveSprints, activePbis: nextActivePbis, activeStories: nextActiveStories, }, }) } export async function resolveActiveSprint( productId: string, userId: string, ): Promise { const settings = await readSettings(userId) const state = readStoredActiveSprintState(settings, productId) if (state.kind === 'cleared') return null if (state.kind === 'set') { const sprint = await prisma.sprint.findFirst({ where: { id: state.sprintId, product_id: productId }, select: { id: true, code: true, status: true }, }) if (sprint) return sprint } const open = await prisma.sprint.findFirst({ where: { product_id: productId, status: 'OPEN' }, orderBy: { created_at: 'desc' }, select: { id: true, code: true, status: true }, }) if (open) return open const closed = await prisma.sprint.findFirst({ where: { product_id: productId, status: 'CLOSED' }, orderBy: { created_at: 'desc' }, select: { id: true, code: true, status: true }, }) return closed ?? null }