86 lines
2.8 KiB
TypeScript
86 lines
2.8 KiB
TypeScript
import { TerminStatus, TerminType, UserRole } from "@prisma/client";
|
|
|
|
import { getDailyAbsences } from "@/actions/absences";
|
|
import { requireRole } from "@/lib/auth-utils";
|
|
import { prisma } from "@/lib/prisma";
|
|
import { absenceDate, absenceToday, isAbsenceDate } from "@/lib/absence-policy";
|
|
import { AbsencesClient } from "./_components/absences-client";
|
|
import { type AbsenceTableItem } from "./absence-table";
|
|
|
|
export const metadata = { title: "Abwesenheiten · Kita-Planer" };
|
|
|
|
export default async function AdminAbwesenheitenPage({
|
|
searchParams,
|
|
}: {
|
|
searchParams: Promise<{ date?: string }>;
|
|
}) {
|
|
const session = await requireRole([
|
|
UserRole.ADMIN,
|
|
UserRole.KOORDINATOR,
|
|
UserRole.ERZIEHER,
|
|
]);
|
|
const resolvedSearchParams = await searchParams;
|
|
const kitaId = session.user.kitaId!;
|
|
const todayKey = absenceToday();
|
|
const today = absenceDate(todayKey);
|
|
const selectedDate = parseDateParam(resolvedSearchParams.date, today);
|
|
const dateKey = selectedDate.toISOString().slice(0, 10);
|
|
const result = await getDailyAbsences({ date: dateKey });
|
|
const absences = result.absences ?? [];
|
|
const childCount = await prisma.child.count({
|
|
where: { kitaId, active: true },
|
|
});
|
|
const upcomingAbsenceCount = await prisma.absence.count({
|
|
where: {
|
|
kitaId,
|
|
startDate: { gt: selectedDate },
|
|
},
|
|
});
|
|
const closure = await prisma.termin.findFirst({
|
|
where: {
|
|
kitaId,
|
|
status: TerminStatus.CONFIRMED,
|
|
type: { in: [TerminType.SCHLIESSTAG, TerminType.TEAMTAG] },
|
|
startDate: { lte: selectedDate },
|
|
endDate: { gte: selectedDate },
|
|
},
|
|
select: { title: true, type: true },
|
|
orderBy: { startDate: "asc" },
|
|
});
|
|
const isToday = dateKey === todayKey;
|
|
const isTooFarFuture = (selectedDate.getTime() - today.getTime()) / 86_400_000 > 30;
|
|
const isClosedDay = [0, 6].includes(selectedDate.getUTCDay()) || !!closure;
|
|
const tableItems: AbsenceTableItem[] = absences.map((absence) => ({
|
|
id: absence.id,
|
|
childName: absence.childName,
|
|
familyName: absence.familyName,
|
|
reason: absence.reason,
|
|
note: absence.note,
|
|
startDate: absence.startDate,
|
|
endDate: absence.endDate,
|
|
updatedAt: absence.updatedAt,
|
|
}));
|
|
|
|
return (
|
|
<div className="mx-auto max-w-[1280px] px-11 py-9 pb-16 max-[760px]:px-5">
|
|
<AbsencesClient
|
|
initialAbsences={tableItems}
|
|
childCount={childCount}
|
|
upcomingAbsenceCount={upcomingAbsenceCount}
|
|
closure={closure}
|
|
dateKey={dateKey}
|
|
selectedDateStr={dateKey}
|
|
isToday={isToday}
|
|
isTooFarFuture={isTooFarFuture}
|
|
isClosedDay={isClosedDay}
|
|
todayStr={todayKey}
|
|
error={result.error ?? null}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function parseDateParam(value: string | undefined, fallback: Date) {
|
|
return value && isAbsenceDate(value) ? absenceDate(value) : fallback;
|
|
}
|