diff --git a/actions/ideas.ts b/actions/ideas.ts index 1ae5e47..dbfa806 100644 --- a/actions/ideas.ts +++ b/actions/ideas.ts @@ -10,6 +10,8 @@ import { revalidatePath } from 'next/cache' import { cookies } from 'next/headers' import { getIronSession } from 'iron-session' +import { z } from 'zod' + import { prisma } from '@/lib/prisma' import { SessionData, sessionOptions } from '@/lib/session' import { enforceUserRateLimit } from '@/lib/rate-limit' @@ -165,6 +167,63 @@ export async function deleteIdeaAction(id: string): Promise { return { success: true } } +// --------------------------------------------------------------------------- +// Secondary products + +const secondaryProductsSchema = z.object({ + ideaId: z.string().cuid(), + productIds: z.array(z.string().cuid()).max(10), +}) + +export async function updateSecondaryProductsAction( + ideaId: string, + productIds: string[], +): Promise { + const session = await getSession() + if (!session.userId) return { error: 'Niet ingelogd', code: 401 } + if (session.isDemo) return { error: 'Niet beschikbaar in demo-modus', code: 403 } + + const parsed = secondaryProductsSchema.safeParse({ ideaId, productIds }) + if (!parsed.success) return { error: 'Ongeldige invoer', code: 422 } + + const idea = await prisma.idea.findFirst({ + where: { id: parsed.data.ideaId, user_id: session.userId }, + select: { id: true, product_id: true }, + }) + if (!idea) return { error: 'Idee niet gevonden', code: 404 } + + // Verwijder primair product uit de lijst (mag niet dubbel) + const filtered = parsed.data.productIds.filter((pid) => pid !== idea.product_id) + + // Valideer dat alle gevraagde producten toegankelijk zijn voor de user + if (filtered.length > 0) { + const { productAccessFilter } = await import('@/lib/product-access') + const accessible = await prisma.product.findMany({ + where: { id: { in: filtered }, ...productAccessFilter(session.userId) }, + select: { id: true }, + }) + if (accessible.length !== filtered.length) + return { error: 'Een of meer producten zijn niet toegankelijk', code: 403 } + } + + // Atomisch: verwijder alle bestaande, voeg nieuwe in + await prisma.$transaction([ + prisma.ideaProduct.deleteMany({ where: { idea_id: idea.id } }), + ...(filtered.length > 0 + ? [ + prisma.ideaProduct.createMany({ + data: filtered.map((pid) => ({ idea_id: idea.id, product_id: pid })), + skipDuplicates: true, + }), + ] + : []), + ]) + + revalidatePath('/ideas/' + idea.id, 'page') + revalidatePath('/ideas', 'page') + return { success: true } +} + // --------------------------------------------------------------------------- // Markdown-edits (grill_md & plan_md handmatig fine-tunen)