Files
kita-planer/src/app/dashboard/admin/abwesenheiten/page.tsx
T

92 lines
2.9 KiB
TypeScript

import { differenceInCalendarDays, format, isWeekend } from "date-fns";
import { TerminStatus, TerminType, UserRole } from "@prisma/client";
import { getDailyAbsences } from "@/actions/absences";
import { requireRole } from "@/lib/auth-utils";
import { prisma } from "@/lib/prisma";
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 today = startOfLocalDay(new Date());
const selectedDate = parseDateParam(resolvedSearchParams.date, today);
const dateKey = format(selectedDate, "yyyy-MM-dd");
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 === format(today, "yyyy-MM-dd");
const isTooFarFuture = differenceInCalendarDays(selectedDate, today) > 30;
const isClosedDay = isWeekend(selectedDate) || !!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,
}));
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={selectedDate.toISOString()}
isToday={isToday}
isTooFarFuture={isTooFarFuture}
isClosedDay={isClosedDay}
todayStr={today.toISOString()}
error={result.error ?? null}
/>
</div>
);
}
function parseDateParam(value: string | undefined, fallback: Date) {
if (!value) return fallback;
const parsed = new Date(`${value}T00:00:00`);
return Number.isNaN(parsed.getTime()) ? fallback : parsed;
}
function startOfLocalDay(date: Date) {
const nextDate = new Date(date);
nextDate.setHours(0, 0, 0, 0);
return nextDate;
}