continued the kita-planer

This commit is contained in:
t.indorf
2026-05-08 14:32:14 +02:00
parent b686e714ff
commit 7aff691803
85 changed files with 9434 additions and 588 deletions
+198
View File
@@ -0,0 +1,198 @@
"use server";
import { revalidatePath } from "next/cache";
import { AbsenceReason, UserRole } from "@prisma/client";
import { z } from "zod";
import { requireKitaSession, requireRole } from "@/lib/auth-utils";
import { prisma } from "@/lib/prisma";
const reportAbsenceSchema = z.object({
childId: z.string().min(1),
startDate: z.string().min(1),
endDate: z.string().min(1),
reason: z.nativeEnum(AbsenceReason),
note: z.string().trim().max(500).optional(),
});
const dailyAbsenceSchema = z.object({
date: z.string().min(1),
});
export type DailyAbsenceDto = {
id: string;
childName: string;
familyName: string;
reason: AbsenceReason;
note: string | null;
startDate: string;
endDate: string;
};
function parseDateOnly(value: string) {
const date = new Date(`${value.slice(0, 10)}T00:00:00`);
if (Number.isNaN(date.getTime())) {
throw new Error("Ungueltiges Datum.");
}
return date;
}
function toDateKey(date: Date) {
return date.toISOString().slice(0, 10);
}
export async function reportAbsence(rawPayload: unknown) {
const session = await requireKitaSession();
const parsed = reportAbsenceSchema.safeParse(rawPayload);
if (!parsed.success) {
return { error: "Ungültige Eingabedaten." };
}
if (!session.user.familyId) {
return { error: "Dein Account ist noch keinem Haushalt zugeordnet." };
}
const startDate = parseDateOnly(parsed.data.startDate);
const endDate = parseDateOnly(parsed.data.endDate);
if (endDate < startDate) {
return { error: "Das Enddatum darf nicht vor dem Startdatum liegen." };
}
const child = await prisma.child.findFirst({
where: {
id: parsed.data.childId,
kitaId: session.user.kitaId,
familyId: session.user.familyId,
active: true,
},
select: { id: true },
});
if (!child) {
return { error: "Dieses Kind gehört nicht zu deinem Haushalt." };
}
const overlappingAbsence = await prisma.absence.findFirst({
where: {
kitaId: session.user.kitaId,
childId: child.id,
startDate: { lte: endDate },
endDate: { gte: startDate },
},
select: { id: true },
});
if (overlappingAbsence) {
return { error: "Für diesen Zeitraum existiert bereits eine Abmeldung." };
}
await prisma.absence.create({
data: {
kitaId: session.user.kitaId,
childId: child.id,
startDate,
endDate,
reason: parsed.data.reason,
note: parsed.data.note || null,
},
});
revalidatePath("/dashboard");
revalidatePath("/dashboard/admin/abwesenheiten");
return { success: true };
}
export async function deleteAbsence(id: string) {
const session = await requireKitaSession();
if (!session.user.familyId) {
return { error: "Dein Account ist noch keinem Haushalt zugeordnet." };
}
const absence = await prisma.absence.findFirst({
where: {
id,
kitaId: session.user.kitaId,
child: {
familyId: session.user.familyId,
},
},
select: { id: true },
});
if (!absence) {
return { error: "Diese Abmeldung gehört nicht zu deinem Haushalt." };
}
await prisma.absence.delete({
where: { id: absence.id },
});
revalidatePath("/dashboard");
revalidatePath("/dashboard/admin/abwesenheiten");
return { success: true };
}
export async function getDailyAbsences(
rawPayload: unknown,
): Promise<{ absences?: DailyAbsenceDto[]; error?: string }> {
const session = await requireRole([
UserRole.ADMIN,
UserRole.KOORDINATOR,
UserRole.ERZIEHER,
]);
if (!session.user.kitaId) {
return { error: "Kein Mandant zugeordnet." };
}
const parsed = dailyAbsenceSchema.safeParse(rawPayload);
if (!parsed.success) {
return { error: "Ungültiges Datum." };
}
const date = parseDateOnly(parsed.data.date);
const rows = await prisma.absence.findMany({
where: {
kitaId: session.user.kitaId,
startDate: { lte: date },
endDate: { gte: date },
},
select: {
id: true,
reason: true,
note: true,
startDate: true,
endDate: true,
child: {
select: {
firstName: true,
lastName: true,
family: {
select: {
name: true,
},
},
},
},
},
orderBy: [
{ child: { lastName: "asc" } },
{ child: { firstName: "asc" } },
],
});
return {
absences: rows.map((absence) => ({
id: absence.id,
childName: `${absence.child.firstName} ${absence.child.lastName}`,
familyName: absence.child.family.name,
reason: absence.reason,
note: absence.note,
startDate: toDateKey(absence.startDate),
endDate: toDateKey(absence.endDate),
})),
};
}