feat(ST-1109.4): support status in PBI create/update actions

- Optional status field in Zod schemas (lowercase API: ready/blocked/done)
- pbiStatusFromApi() maps to DB enum before persistence
- Status omitted on create => Prisma @default(READY) takes effect
- Update preserves existing status when not provided
- Demo-check unchanged

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-04-29 17:09:48 +02:00
parent 445e1522c8
commit 878fa161ef

View file

@ -9,6 +9,7 @@ import { SessionData, sessionOptions } from '@/lib/session'
import { getAccessibleProduct } from '@/lib/product-access'
import { isValidCode, MAX_CODE_LENGTH, normalizeCode } from '@/lib/code'
import { createWithCodeRetry, generateNextPbiCode } from '@/lib/code-server'
import { pbiStatusFromApi } from '@/lib/task-status'
async function getSession() {
return getIronSession<SessionData>(await cookies(), sessionOptions)
@ -16,12 +17,15 @@ async function getSession() {
const codeField = z.string().max(MAX_CODE_LENGTH).optional()
const statusField = z.enum(['ready', 'blocked', 'done']).optional()
const createPbiSchema = z.object({
productId: z.string(),
code: codeField,
title: z.string().min(1, 'Titel is verplicht').max(200),
description: z.string().max(2000).optional(),
priority: z.coerce.number().int().min(1).max(4),
status: statusField,
})
const updatePbiSchema = z.object({
@ -30,6 +34,7 @@ const updatePbiSchema = z.object({
title: z.string().min(1, 'Titel is verplicht').max(200),
description: z.string().max(2000).optional(),
priority: z.coerce.number().int().min(1).max(4),
status: statusField,
})
export async function createPbiAction(_prevState: unknown, formData: FormData) {
@ -43,6 +48,7 @@ export async function createPbiAction(_prevState: unknown, formData: FormData) {
title: formData.get('title'),
description: formData.get('description') || undefined,
priority: formData.get('priority'),
status: (formData.get('status') as string) || undefined,
})
if (!parsed.success) return { error: parsed.error.flatten().fieldErrors }
@ -64,6 +70,8 @@ export async function createPbiAction(_prevState: unknown, formData: FormData) {
})
const sort_order = (last?.sort_order ?? 0) + 1.0
const status = parsed.data.status ? pbiStatusFromApi(parsed.data.status) ?? undefined : undefined
const insert = (code: string | null) =>
prisma.pbi.create({
data: {
@ -73,6 +81,7 @@ export async function createPbiAction(_prevState: unknown, formData: FormData) {
description: parsed.data.description ?? null,
priority: parsed.data.priority,
sort_order,
...(status ? { status } : {}),
},
})
@ -103,6 +112,7 @@ export async function updatePbiAction(_prevState: unknown, formData: FormData) {
title: formData.get('title'),
description: formData.get('description') || undefined,
priority: formData.get('priority'),
status: (formData.get('status') as string) || undefined,
})
if (!parsed.success) return { error: parsed.error.flatten().fieldErrors }
@ -125,6 +135,8 @@ export async function updatePbiAction(_prevState: unknown, formData: FormData) {
if (dup) return { error: { code: ['Deze code is al in gebruik binnen dit product'] } }
}
const status = parsed.data.status ? pbiStatusFromApi(parsed.data.status) ?? undefined : undefined
await prisma.pbi.update({
where: { id: parsed.data.id },
data: {
@ -132,6 +144,7 @@ export async function updatePbiAction(_prevState: unknown, formData: FormData) {
title: parsed.data.title,
description: parsed.data.description ?? null,
priority: parsed.data.priority,
...(status ? { status } : {}),
},
})