"use server"; import { revalidatePath } from "next/cache"; import { EventParticipationStatus, RsvpMode, TerminStatus, UserRole, } from "@prisma/client"; import { rsvpSubmissionSchema } from "@/lib/rsvp"; import { lockEvent } from "@/lib/event-lock"; import { requireKitaSession, requireRole } from "@/lib/auth-utils"; import { prisma } from "@/lib/prisma"; export type EventParticipantDto = { childId: string; childName: string; familyName: string; status: EventParticipationStatus | null; }; export async function submitEventRsvp( rawPayload: unknown, ): Promise<{ error?: string; success?: boolean }> { const session = await requireKitaSession(); const parsed = rsvpSubmissionSchema.safeParse(rawPayload); if (!parsed.success) return { error: "Bitte alle Antworten und bei Familienzusagen die Anzahl Erwachsener angeben.", }; if (!session.user.familyId || session.user.role === UserRole.ERZIEHER) { return { error: "Für Rückmeldungen ist ein Elternkonto mit Haushalt erforderlich.", }; } const kitaId = session.user.kitaId; const familyId = session.user.familyId; const payload = parsed.data; try { const result = await prisma.$transaction(async (tx) => { await lockEvent(tx, payload.eventId, kitaId); const event = await tx.termin.findFirst({ where: { id: payload.eventId, kitaId }, select: { status: true, requiresRsvp: true, rsvpMode: true, rsvpDeadline: true, startDate: true, kita: { select: { terminModuleEnabled: true } }, }, }); if ( !event?.kita.terminModuleEnabled || !event.requiresRsvp || event.status !== TerminStatus.CONFIRMED ) { return { error: "Für diesen Termin ist keine Rückmeldung aktiv." }; } if (event.rsvpMode !== payload.mode) return { error: "Die Antwortart wurde geändert. Bitte lade den Termin erneut.", }; if (payload.mode === RsvpMode.FAMILY) { const family = await tx.family.findFirst({ where: { id: familyId, kitaId }, select: { id: true }, }); if (!family) return { error: "Haushalt wurde nicht gefunden." }; if ( (event.rsvpDeadline ?? event.startDate) <= new Date() || event.startDate <= new Date() ) { return { error: "Die Rückmeldefrist ist bereits abgelaufen." }; } await tx.familyEventParticipation.upsert({ where: { eventId_familyId: { eventId: payload.eventId, familyId } }, create: { kitaId, eventId: payload.eventId, familyId, status: payload.status, adultCount: payload.adultCount, }, update: { status: payload.status, adultCount: payload.adultCount }, }); } else { const children = await tx.child.findMany({ where: { kitaId, familyId, active: true }, select: { id: true }, }); const ids = new Set(children.map((child) => child.id)); if ( payload.responses.length !== ids.size || payload.responses.some((row) => !ids.has(row.childId)) ) { return { error: "Bitte antworte für alle eigenen aktiven Kinder. Lade den Termin bei Änderungen erneut.", }; } if ( (event.rsvpDeadline ?? event.startDate) <= new Date() || event.startDate <= new Date() ) { return { error: "Die Rückmeldefrist ist bereits abgelaufen." }; } for (const response of payload.responses) { await tx.eventParticipation.upsert({ where: { eventId_childId: { eventId: payload.eventId, childId: response.childId, }, }, create: { kitaId, eventId: payload.eventId, ...response }, update: { status: response.status }, }); } } return { success: true }; }); if (result.error) return result; revalidatePath("/dashboard"); revalidatePath("/dashboard/kalender"); revalidatePath("/dashboard/admin/kalender"); return result; } catch (error) { console.error("Rückmeldung konnte nicht gespeichert werden:", error); return { error: "Rückmeldung konnte nicht gespeichert werden. Bitte versuche es erneut.", }; } } export async function getEventParticipants( eventId: string, ): Promise<{ participants?: EventParticipantDto[]; error?: string }> { const session = await requireRole([UserRole.ADMIN, UserRole.KOORDINATOR]); const kitaId = session.user.kitaId; if (!kitaId) { return { error: "Kein Mandant zugeordnet." }; } const event = await prisma.termin.findFirst({ where: { id: eventId, kitaId }, select: { id: true }, }); if (!event) { return { error: "Termin wurde nicht gefunden." }; } const children = await prisma.child.findMany({ where: { kitaId, active: true, }, select: { id: true, firstName: true, lastName: true, family: { select: { name: true, }, }, eventParticipations: { where: { eventId }, select: { status: true }, take: 1, }, }, orderBy: [ { family: { name: "asc" } }, { lastName: "asc" }, { firstName: "asc" }, ], }); return { participants: children.map((child) => ({ childId: child.id, childName: `${child.firstName} ${child.lastName}`, familyName: child.family.name, status: child.eventParticipations[0]?.status ?? null, })), }; }