53 lines
1.7 KiB
Markdown
53 lines
1.7 KiB
Markdown
# Patroon: Server Action
|
|
|
|
Altijd in `actions/[domein].ts`. Nooit inline in page.tsx.
|
|
|
|
```ts
|
|
'use server'
|
|
|
|
import { revalidatePath } from 'next/cache'
|
|
import { getIronSession } from 'iron-session'
|
|
import { cookies } from 'next/headers'
|
|
import { z } from 'zod'
|
|
import { prisma } from '@/lib/prisma'
|
|
import { SessionData, sessionOptions } from '@/lib/session'
|
|
|
|
const schema = z.object({
|
|
productId: z.string().cuid(),
|
|
title: z.string().min(1).max(200),
|
|
priority: z.number().int().min(1).max(4),
|
|
})
|
|
|
|
export async function createPbi(formData: FormData) {
|
|
// 1. Auth
|
|
const session = await getIronSession<SessionData>(await cookies(), sessionOptions)
|
|
if (!session.userId) return { error: 'Niet ingelogd' }
|
|
if (session.isDemo) return { error: 'Niet beschikbaar in demo-modus' }
|
|
|
|
// 2. Validatie
|
|
const parsed = schema.safeParse({
|
|
productId: formData.get('productId'),
|
|
title: formData.get('title'),
|
|
priority: Number(formData.get('priority')),
|
|
})
|
|
if (!parsed.success) return { error: parsed.error.flatten().fieldErrors }
|
|
|
|
// 3. Eigenaarschap controleren
|
|
const product = await prisma.product.findFirst({
|
|
where: { id: parsed.data.productId, user_id: session.userId }
|
|
})
|
|
if (!product) return { error: 'Product niet gevonden' }
|
|
|
|
// 4. Schrijven
|
|
const last = await prisma.pbi.findFirst({
|
|
where: { product_id: parsed.data.productId, priority: parsed.data.priority },
|
|
orderBy: { sort_order: 'desc' },
|
|
})
|
|
const pbi = await prisma.pbi.create({
|
|
data: { ...parsed.data, product_id: parsed.data.productId, sort_order: (last?.sort_order ?? 0) + 1.0 },
|
|
})
|
|
|
|
revalidatePath(`/products/${parsed.data.productId}`)
|
|
return { success: true, pbi }
|
|
}
|
|
```
|