"use server"; import { auth } from "@/auth"; import { db } from "@/lib/db"; import { hasPermission } from "@/lib/permissions"; import { revalidatePath } from "next/cache"; import { Prisma } from "@prisma/client"; import { z } from "zod"; const schema = z.object({ code: z.string().trim().min(1, "Project code is required"), }); type Result = { ok: true } | { error: string }; async function guard(): Promise<{ ok: true } | { error: string }> { const session = await auth(); if (!session?.user || !hasPermission(session.user.role, "manage_project_codes")) { return { error: "Forbidden" }; } return { ok: true }; } export async function createProjectCode(formData: FormData): Promise { const g = await guard(); if ("error" in g) return g; const parsed = schema.safeParse(Object.fromEntries(formData)); if (!parsed.success) return { error: parsed.error.errors[0].message }; try { await db.projectCode.create({ data: { code: parsed.data.code } }); } catch (e) { if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2002") { return { error: "That project code already exists." }; } throw e; } revalidatePath("/admin/project-codes"); return { ok: true }; } export async function updateProjectCode(id: string, formData: FormData): Promise { const g = await guard(); if ("error" in g) return g; const parsed = schema.safeParse(Object.fromEntries(formData)); if (!parsed.success) return { error: parsed.error.errors[0].message }; try { await db.projectCode.update({ where: { id }, data: { code: parsed.data.code } }); } catch (e) { if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2002") { return { error: "That project code already exists." }; } throw e; } revalidatePath("/admin/project-codes"); return { ok: true }; } export async function toggleProjectCodeActive(id: string): Promise { const g = await guard(); if ("error" in g) return g; const code = await db.projectCode.findUnique({ where: { id }, select: { isActive: true } }); if (!code) return { error: "Not found" }; await db.projectCode.update({ where: { id }, data: { isActive: !code.isActive } }); revalidatePath("/admin/project-codes"); return { ok: true }; } export async function deleteProjectCode(id: string): Promise { const g = await guard(); if ("error" in g) return g; // Safe to delete: POs keep their project code as a text snapshot, so no // purchase order references this row. await db.projectCode.delete({ where: { id } }); revalidatePath("/admin/project-codes"); return { ok: true }; }