"use server"; import { redirect } from "next/navigation"; import { getDb } from "../../lib/db"; import { getSession } from "../../lib/auth"; import { DEFAULT_PROJECT_STATUS, isProjectStatus } from "../../lib/projectStatus"; import { readProjectPlan } from "../../lib/projectPlan"; import { BONUS_MALUS_OPTIONS, EXPERT_COUNT, EXPERT_CRITERIA } from "../../lib/rikxCalculatie"; export async function createProject(formData: FormData) { const session = await getSession(); if (!session) redirect("/login"); const name = ((formData.get("name") as string) ?? "").trim(); const rawStatus = formData.get("status"); const status = isProjectStatus(rawStatus) ? rawStatus : DEFAULT_PROJECT_STATUS; if (!name) redirect("/projecten/nieuw?error=missing"); const db = getDb(); db.prepare("INSERT INTO projects (name, status, ronde_id) VALUES (?, ?, ?)").run( name, status, readRondeId(db, formData) ); redirect("/projecten"); } // Geeft het id van een bestaande Rikx Ronde terug, of null bij "geen ronde"/onbekend id. function readRondeId(db: ReturnType, formData: FormData): number | null { const id = Number(formData.get("ronde_id")); if (!id) return null; return db.prepare("SELECT id FROM rikx_rondes WHERE id = ?").get(id) ? id : null; } // Leeg veld → null; accepteert zowel 1234.5 als 1234,5 function parseNumber(value: FormDataEntryValue | null): number | null { if (typeof value !== "string" || value.trim() === "") return null; const n = Number(value.replace(",", ".")); return Number.isFinite(n) ? n : NaN; } function inRange(n: number | null, min: number, max = Infinity) { return n === null || (n >= min && n <= max); } export async function updateProject(formData: FormData) { const session = await getSession(); if (!session) redirect("/login"); const id = Number(formData.get("id")); if (!id) redirect("/projecten"); const name = ((formData.get("name") as string) ?? "").trim(); const rawStatus = formData.get("status"); if (!name) redirect(`/projecten/${id}?error=missing`); const projectkosten = parseNumber(formData.get("projectkosten")); const deelnemersWerk = parseNumber(formData.get("deelnemers_werk")); const deelnemersSkills = parseNumber(formData.get("deelnemers_skills")); const externBedrag = parseNumber(formData.get("financiering_extern_bedrag")); const externPct = parseNumber(formData.get("financiering_extern_pct")); const rawBonusMalus = (formData.get("bonus_malus") as string) ?? ""; const bonusMalus = BONUS_MALUS_OPTIONS.some((o) => o.id === rawBonusMalus) && rawBonusMalus ? rawBonusMalus : null; const expertScores = Array.from({ length: EXPERT_COUNT }, (_, i) => EXPERT_CRITERIA.map((c) => parseNumber(formData.get(`expert_${i + 1}_${c.id}`))) ); const valid = inRange(projectkosten, 0) && inRange(deelnemersWerk, 0) && inRange(deelnemersSkills, 0) && inRange(externBedrag, 0) && inRange(externPct, 0, 100) && expertScores.every((scores) => scores.every((s) => inRange(s, 1, 10))); if (!valid) redirect(`/projecten/${id}?error=invalid`); const planResult = readProjectPlan(formData); if ("error" in planResult) redirect(`/projecten/${id}?error=${planResult.error}`); const db = getDb(); db.exec("BEGIN"); try { db.prepare( `UPDATE projects SET name = ?, status = COALESCE(?, status), projectkosten = ?, deelnemers_werk = ?, deelnemers_skills = ?, financiering_extern_bedrag = ?, financiering_extern_pct = ?, project_plan = ?, bonus_malus = ?, ronde_id = ?, updated_at = datetime('now') WHERE id = ?` ).run( name, isProjectStatus(rawStatus) ? rawStatus : null, projectkosten, deelnemersWerk, deelnemersSkills, externBedrag, externPct, JSON.stringify(planResult.plan), bonusMalus, readRondeId(db, formData), id ); const upsert = db.prepare( `INSERT INTO project_expert_scores (project_id, expert, duur_impact, levensdomeinen, basissituatie) VALUES (?, ?, ?, ?, ?) ON CONFLICT (project_id, expert) DO UPDATE SET duur_impact = excluded.duur_impact, levensdomeinen = excluded.levensdomeinen, basissituatie = excluded.basissituatie` ); expertScores.forEach((scores, i) => upsert.run(id, i + 1, ...scores)); db.exec("COMMIT"); } catch (err) { db.exec("ROLLBACK"); throw err; } redirect(`/projecten/${id}?opgeslagen=1`); } // Schuif "Rikx calculatie" op de projectpagina; wordt direct opgeslagen. export async function setRikxCalculatie(id: number, aan: boolean) { const session = await getSession(); if (!session) redirect("/login"); getDb() .prepare("UPDATE projects SET rikx_calculatie_aan = ?, updated_at = datetime('now') WHERE id = ?") .run(aan ? 1 : 0, id); }