feat: add household emergency duty alarms and deadline worker
This commit is contained in:
@@ -1,14 +1,15 @@
|
||||
import Link from "next/link";
|
||||
import { addMonths, getYear, getMonth, format } from "date-fns";
|
||||
import { de } from "date-fns/locale";
|
||||
import { TerminType, UserRole } from "@prisma/client";
|
||||
import { TerminType } from "@prisma/client";
|
||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||
|
||||
import { requireRole } from "@/lib/auth-utils";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { getWorkingDaysOfMonth } from "@/lib/date-utils";
|
||||
import { PlanView } from "./plan-view";
|
||||
import { SettingsModal } from "./_components/settings-modal";
|
||||
import { requireAlarmActor } from "@/lib/alarms/auth";
|
||||
import { todayKey } from "@/lib/alarms/format";
|
||||
|
||||
export const metadata = { title: "Plan-Generierung · Kita-Planer" };
|
||||
|
||||
@@ -17,14 +18,18 @@ export default async function PlanungsZentralePage({
|
||||
}: {
|
||||
searchParams: Promise<{ year?: string; month?: string }>;
|
||||
}) {
|
||||
const session = await requireRole([UserRole.ADMIN, UserRole.KOORDINATOR]);
|
||||
const kitaId = session.user.kitaId!;
|
||||
const actor = await requireAlarmActor();
|
||||
const kitaId = actor.kitaId;
|
||||
|
||||
const resolvedSearchParams = await searchParams;
|
||||
const now = new Date();
|
||||
const nextMonth = addMonths(now, 1);
|
||||
const targetYear = resolvedSearchParams.year ? parseInt(resolvedSearchParams.year, 10) : getYear(nextMonth);
|
||||
const targetMonth = resolvedSearchParams.month ? parseInt(resolvedSearchParams.month, 10) : (getMonth(nextMonth) + 1);
|
||||
const targetYear = resolvedSearchParams.year
|
||||
? parseInt(resolvedSearchParams.year, 10)
|
||||
: getYear(nextMonth);
|
||||
const targetMonth = resolvedSearchParams.month
|
||||
? parseInt(resolvedSearchParams.month, 10)
|
||||
: getMonth(nextMonth) + 1;
|
||||
|
||||
const monthDate = new Date(targetYear, targetMonth - 1, 1);
|
||||
const monthName = format(monthDate, "MMMM", { locale: de });
|
||||
@@ -33,79 +38,84 @@ export default async function PlanungsZentralePage({
|
||||
const monthStart = new Date(targetYear, targetMonth - 1, 1);
|
||||
const monthEnd = new Date(targetYear, targetMonth, 1);
|
||||
|
||||
const [plan, families, availabilities, closureCount, kita] = await Promise.all([
|
||||
prisma.notdienstPlan.findUnique({
|
||||
where: {
|
||||
kitaId_year_month: { kitaId, year: targetYear, month: targetMonth },
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
status: true,
|
||||
publishedAt: true,
|
||||
assignments: {
|
||||
select: {
|
||||
id: true,
|
||||
childId: true,
|
||||
date: true,
|
||||
createdAt: true,
|
||||
const [plan, families, availabilities, closureCount, kita] =
|
||||
await Promise.all([
|
||||
prisma.notdienstPlan.findUnique({
|
||||
where: {
|
||||
kitaId_year_month: { kitaId, year: targetYear, month: targetMonth },
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
status: true,
|
||||
publishedAt: true,
|
||||
assignments: {
|
||||
select: {
|
||||
id: true,
|
||||
childId: true,
|
||||
date: true,
|
||||
createdAt: true,
|
||||
alarms: {
|
||||
where: { activeAssignmentId: { not: null } },
|
||||
select: { id: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
prisma.family.findMany({
|
||||
where: {
|
||||
kitaId,
|
||||
children: { some: { active: true } },
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
children: {
|
||||
where: { active: true },
|
||||
select: { id: true },
|
||||
}),
|
||||
prisma.family.findMany({
|
||||
where: {
|
||||
kitaId,
|
||||
children: { some: { active: true } },
|
||||
},
|
||||
},
|
||||
orderBy: { name: "asc" },
|
||||
}),
|
||||
prisma.notdienstAvailability.findMany({
|
||||
where: {
|
||||
kitaId,
|
||||
date: {
|
||||
gte: monthStart,
|
||||
lt: monthEnd,
|
||||
},
|
||||
},
|
||||
select: {
|
||||
date: true,
|
||||
child: {
|
||||
select: {
|
||||
familyId: true,
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
children: {
|
||||
where: { active: true },
|
||||
select: { id: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: { date: "asc" },
|
||||
}),
|
||||
prisma.termin.count({
|
||||
where: {
|
||||
kitaId,
|
||||
type: TerminType.SCHLIESSTAG,
|
||||
startDate: {
|
||||
gte: monthStart,
|
||||
lt: monthEnd,
|
||||
orderBy: { name: "asc" },
|
||||
}),
|
||||
prisma.notdienstAvailability.findMany({
|
||||
where: {
|
||||
kitaId,
|
||||
date: {
|
||||
gte: monthStart,
|
||||
lt: monthEnd,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
prisma.kita.findUniqueOrThrow({
|
||||
where: { id: kitaId },
|
||||
select: {
|
||||
notdienstMinPerChildPerMonth: true,
|
||||
notdienstReminderDaysBefore: true,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
select: {
|
||||
date: true,
|
||||
child: {
|
||||
select: {
|
||||
familyId: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: { date: "asc" },
|
||||
}),
|
||||
prisma.termin.count({
|
||||
where: {
|
||||
kitaId,
|
||||
type: TerminType.SCHLIESSTAG,
|
||||
startDate: {
|
||||
gte: monthStart,
|
||||
lt: monthEnd,
|
||||
},
|
||||
},
|
||||
}),
|
||||
prisma.kita.findUniqueOrThrow({
|
||||
where: { id: kitaId },
|
||||
select: {
|
||||
notdienstMinPerChildPerMonth: true,
|
||||
notdienstReminderDaysBefore: true,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
// Wir laden auch alle aktiven Kinder (inkl. Eltern-Namen) für das manuelle Dropdown.
|
||||
// Idealerweise gruppiert man das nach "Verfügbar an diesem Tag" und "Alle",
|
||||
// Idealerweise gruppiert man das nach "Verfügbar an diesem Tag" und "Alle",
|
||||
// aber für MVP reichen alle aktiven Kinder.
|
||||
const allChildrenRaw = await prisma.child.findMany({
|
||||
where: { kitaId, active: true },
|
||||
@@ -179,7 +189,7 @@ export default async function PlanungsZentralePage({
|
||||
// Wir mappen die Assignments auf die Werktage
|
||||
const daysWithAssignments = workingDays.map((day) => {
|
||||
const assignment = plan?.assignments.find(
|
||||
(a) => a.date.getTime() === day.getTime()
|
||||
(a) => a.date.getTime() === day.getTime(),
|
||||
);
|
||||
const isOriginallyUnassigned =
|
||||
!assignment ||
|
||||
@@ -190,6 +200,11 @@ export default async function PlanungsZentralePage({
|
||||
assignmentId: assignment?.id || null,
|
||||
childId: assignment?.childId || null,
|
||||
isOriginallyUnassigned: !!isOriginallyUnassigned,
|
||||
activeAlarmId: assignment?.alarms[0]?.id ?? null,
|
||||
canAlarm:
|
||||
!!assignment &&
|
||||
plan?.status === "PUBLISHED" &&
|
||||
day.toISOString().slice(0, 10) >= todayKey(),
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user