"use server"; import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { prisma } from "@/lib/prisma"; import { requireAdmin } from "@/lib/rbac"; import { classSchema } from "@/lib/validators"; export type ClassState = { error?: string } | undefined; function nullable(v: string | undefined | null) { const t = (v ?? "").trim(); return t === "" ? null : t; } function parseDate(v: string | undefined | null) { const t = (v ?? "").trim(); if (!t) return null; const d = new Date(t); return Number.isNaN(d.getTime()) ? null : d; } export async function createClassAction(_prev: ClassState, formData: FormData): Promise { await requireAdmin(); const parsed = classSchema.safeParse(Object.fromEntries(formData)); if (!parsed.success) return { error: parsed.error.issues[0]?.message ?? "Data tidak valid." }; const d = parsed.data; const exists = await prisma.class.findUnique({ where: { code: d.code } }); if (exists) return { error: `Kode kelas ${d.code} sudah dipakai.` }; try { await prisma.class.create({ data: { name: d.name, code: d.code, description: nullable(d.description), level: d.level, teacherId: nullable(d.teacherId), totalMeetings: d.totalMeetings, packagePrice: d.packagePrice, pricePerMeeting: d.pricePerMeeting && d.pricePerMeeting > 0 ? d.pricePerMeeting : null, capacity: d.capacity, schedule: nullable(d.schedule), color: nullable(d.color) ?? "#7C5CFC", status: d.status, startDate: parseDate(d.startDate), }, }); } catch (e) { return { error: e instanceof Error ? e.message : "Gagal membuat kelas." }; } revalidatePath("/classes"); redirect("/classes"); } export async function updateClassAction(_prev: ClassState, formData: FormData): Promise { await requireAdmin(); const id = String(formData.get("id")); const parsed = classSchema.safeParse(Object.fromEntries(formData)); if (!parsed.success) return { error: parsed.error.issues[0]?.message ?? "Data tidak valid." }; const d = parsed.data; try { await prisma.class.update({ where: { id }, data: { name: d.name, code: d.code, description: nullable(d.description), level: d.level, teacherId: nullable(d.teacherId), totalMeetings: d.totalMeetings, packagePrice: d.packagePrice, pricePerMeeting: d.pricePerMeeting && d.pricePerMeeting > 0 ? d.pricePerMeeting : null, capacity: d.capacity, schedule: nullable(d.schedule), color: nullable(d.color) ?? "#7C5CFC", status: d.status, startDate: parseDate(d.startDate), }, }); } catch (e) { return { error: e instanceof Error ? e.message : "Gagal memperbarui kelas." }; } revalidatePath("/classes"); revalidatePath(`/classes/${id}`); redirect("/classes"); } export async function archiveClassAction(formData: FormData) { await requireAdmin(); const id = String(formData.get("id")); await prisma.class.update({ where: { id }, data: { status: "ARCHIVED" } }); revalidatePath("/classes"); redirect("/classes"); } export async function generateSessionsAction(formData: FormData) { await requireAdmin(); const classId = String(formData.get("classId")); const cls = await prisma.class.findUnique({ where: { id: classId }, include: { sessions: true } }); if (!cls) redirect("/classes"); const existing = new Set(cls.sessions.map((s) => s.meetingNumber)); const base = cls.startDate ?? new Date(); const created = []; for (let i = 1; i <= cls.totalMeetings; i++) { if (existing.has(i)) continue; const date = new Date(base); date.setDate(date.getDate() + (i - 1) * 7); const s = await prisma.session.create({ data: { classId, meetingNumber: i, date, topic: `Pertemuan ${i}: ${cls.name}`, teacherId: cls.teacherId }, }); created.push(s.id); } revalidatePath(`/classes/${classId}`); redirect(`/classes/${classId}`); }