"use server"; import { redirect } from "next/navigation"; import { getDb } from "../../lib/db"; import { requireAdmin } from "../../lib/auth"; import { DEFAULT_PROJECT_STATUS, isProjectStatus } from "../../lib/projectStatus"; import { listAccountNames } from "../../lib/platform-db"; import { readProjectPlan } from "../../lib/projectPlan"; import { BONUS_MALUS_OPTIONS, DEFAULT_REKENMETHODE, isBeschikbareRekenmethode, } from "../../lib/rikxCalculatie"; // "+ Project toevoegen": maakt direct een nieuw project aan (status Aanvraag) en opent de projectpagina, // waar naam, ronde, impactmaker en het project plan worden ingevuld. export async function createProject() { const session = await requireAdmin(); const result = getDb() .prepare("INSERT INTO projects (name, status) VALUES (?, ?)") .run("Nieuw project", DEFAULT_PROJECT_STATUS); redirect(`/projecten/${Number(result.lastInsertRowid)}`); } // 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; } // Geeft het id van een bestaande sociaal ondernemer (platform-account) terug, of null. function readImpactmakerId(formData: FormData): number | null { const id = Number(formData.get("impactmaker_account_id")); if (!id) return null; return listAccountNames().some((a) => a.id === 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 requireAdmin(); const id = Number(formData.get("id")); if (!id) redirect("/projecten"); // Terug naar de tab waar de gebruiker op stond, ook bij een fout const tab = formData.get("tab") === "calculatie" ? "&tab=calculatie" : ""; const name = ((formData.get("name") as string) ?? "").trim(); const rawStatus = formData.get("status"); if (!name) redirect(`/projecten/${id}?error=missing${tab}`); 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 rawRekenmethode = formData.get("rekenmethode"); const rekenmethode = isBeschikbareRekenmethode(rawRekenmethode) ? rawRekenmethode : DEFAULT_REKENMETHODE; const rawBeoordeling = formData.get("beoordeling"); const beoordeling = rawBeoordeling === "goedgekeurd" || rawBeoordeling === "afgekeurd" ? rawBeoordeling : null; const beoordelingReden = ((formData.get("beoordeling_reden") as string) ?? "").trim().slice(0, 10_000) || null; const rawBonusMalus = (formData.get("bonus_malus") as string) ?? ""; const bonusMalus = BONUS_MALUS_OPTIONS.some((o) => o.id === rawBonusMalus) && rawBonusMalus ? rawBonusMalus : null; const valid = inRange(projectkosten, 0) && inRange(deelnemersWerk, 0) && inRange(deelnemersSkills, 0) && inRange(externBedrag, 0) && inRange(externPct, 0, 100); if (!valid) redirect(`/projecten/${id}?error=invalid${tab}`); const planResult = readProjectPlan(formData); if ("error" in planResult) redirect(`/projecten/${id}?error=${planResult.error}${tab}`); // Expertscores worden niet hier opgeslagen maar door de experts zelf (app/expert) const db = getDb(); db.prepare( `UPDATE projects SET name = ?, status = COALESCE(?, status), projectkosten = ?, deelnemers_werk = ?, deelnemers_skills = ?, financiering_extern_bedrag = ?, financiering_extern_pct = ?, project_plan = ?, rekenmethode = ?, bonus_malus = ?, beoordeling = ?, beoordeling_reden = ?, ronde_id = ?, impactmaker_account_id = ?, updated_at = datetime('now') WHERE id = ?` ).run( name, isProjectStatus(rawStatus) ? rawStatus : null, projectkosten, deelnemersWerk, deelnemersSkills, externBedrag, externPct, JSON.stringify(planResult.plan), rekenmethode, bonusMalus, beoordeling, beoordelingReden, readRondeId(db, formData), readImpactmakerId(formData), id ); redirect(`/projecten/${id}?opgeslagen=1${tab}`); }