diff --git a/actions/admin/products.ts b/actions/admin/products.ts new file mode 100644 index 0000000..b6f4ad0 --- /dev/null +++ b/actions/admin/products.ts @@ -0,0 +1,86 @@ +'use server' + +import { revalidatePath } from 'next/cache' +import { z } from 'zod' +import { prisma } from '@/lib/prisma' +import { requireAdmin } from '@/lib/auth-guard' + +const adminProductSchema = z.object({ + name: z.string().min(1).max(100), + description: z.string().optional(), + repo_url: z.string().url().optional().or(z.literal('')), + definition_of_done: z.string().min(1), + auto_pr: z.boolean().default(false), + owner_user_id: z.string().cuid(), +}) + +const adminProductUpdateSchema = adminProductSchema.omit({ owner_user_id: true }) + +export async function adminCreateProductAction(data: unknown) { + await requireAdmin() + + const parsed = adminProductSchema.safeParse(data) + if (!parsed.success) throw new Error(parsed.error.message) + + const owner = await prisma.user.findUnique({ where: { id: parsed.data.owner_user_id } }) + if (!owner) throw new Error('Eigenaar niet gevonden') + + await prisma.product.create({ + data: { + user_id: parsed.data.owner_user_id, + name: parsed.data.name, + description: parsed.data.description, + repo_url: parsed.data.repo_url || null, + definition_of_done: parsed.data.definition_of_done, + auto_pr: parsed.data.auto_pr, + }, + }) + revalidatePath('/admin/products') +} + +export async function adminUpdateProductAction(productId: string, data: unknown) { + await requireAdmin() + + const parsed = adminProductUpdateSchema.safeParse(data) + if (!parsed.success) throw new Error(parsed.error.message) + + await prisma.product.update({ + where: { id: productId }, + data: { + name: parsed.data.name, + description: parsed.data.description, + repo_url: parsed.data.repo_url || null, + definition_of_done: parsed.data.definition_of_done, + auto_pr: parsed.data.auto_pr, + }, + }) + revalidatePath('/admin/products') +} + +export async function adminArchiveProductAction(productId: string, archived: boolean) { + await requireAdmin() + await prisma.product.update({ where: { id: productId }, data: { archived } }) + revalidatePath('/admin/products') +} + +export async function adminDeleteProductAction(productId: string) { + await requireAdmin() + await prisma.product.delete({ where: { id: productId } }) + revalidatePath('/admin/products') +} + +export async function adminAddMemberAction(productId: string, userId: string) { + await requireAdmin() + await prisma.productMember.upsert({ + where: { product_id_user_id: { product_id: productId, user_id: userId } }, + create: { product_id: productId, user_id: userId }, + update: {}, + }) + revalidatePath(`/admin/products/${productId}`) +} + +export async function adminRemoveMemberAction(productId: string, userId: string) { + await requireAdmin() + await prisma.productMember.deleteMany({ where: { product_id: productId, user_id: userId } }) + revalidatePath(`/admin/products/${productId}`) +}