90 lines
2.7 KiB
TypeScript
90 lines
2.7 KiB
TypeScript
import type { NotdienstAlarm } from "@prisma/client";
|
||
import {
|
||
addDays,
|
||
dateSchema,
|
||
dateKey,
|
||
todayKey,
|
||
minuteClock,
|
||
} from "@/lib/staff/calculations";
|
||
|
||
export { dateKey, todayKey };
|
||
const berlin = new Intl.DateTimeFormat("en-CA", {
|
||
timeZone: "Europe/Berlin",
|
||
year: "numeric",
|
||
month: "2-digit",
|
||
day: "2-digit",
|
||
hour: "2-digit",
|
||
minute: "2-digit",
|
||
hourCycle: "h23",
|
||
});
|
||
export function berlinInstant(date: string, minute: number) {
|
||
dateSchema.parse(date);
|
||
const target = new Date(`${date}T00:00:00Z`).getTime() + minute * 60_000;
|
||
let value = target;
|
||
for (let i = 0; i < 3; i++) {
|
||
const parts = Object.fromEntries(
|
||
berlin.formatToParts(new Date(value)).map((p) => [p.type, p.value]),
|
||
);
|
||
const represented = Date.parse(
|
||
`${parts.year}-${parts.month}-${parts.day}T${parts.hour}:${parts.minute}:00Z`,
|
||
);
|
||
const diff = target - represented;
|
||
if (!diff) return new Date(value);
|
||
value += diff;
|
||
}
|
||
throw new Error(
|
||
"Diese Uhrzeit existiert wegen der Zeitumstellung nicht. Bitte eine andere Uhrzeit wählen.",
|
||
);
|
||
}
|
||
export function endOfAlarm(
|
||
date: string,
|
||
wholeDay: boolean,
|
||
endMinute?: number | null,
|
||
) {
|
||
return wholeDay
|
||
? berlinInstant(addDays(date, 1), 0)
|
||
: berlinInstant(date, endMinute!);
|
||
}
|
||
export function durationLabel(
|
||
alarm: Pick<NotdienstAlarm, "wholeDay" | "startMinute" | "endMinute">,
|
||
) {
|
||
return alarm.wholeDay
|
||
? "Ganzer Kita-Tag"
|
||
: `${minuteClock(alarm.startMinute!)}–${minuteClock(alarm.endMinute!)} Uhr`;
|
||
}
|
||
export function instantLabel(value: Date | string) {
|
||
return new Intl.DateTimeFormat("de-DE", {
|
||
timeZone: "Europe/Berlin",
|
||
day: "2-digit",
|
||
month: "2-digit",
|
||
hour: "2-digit",
|
||
minute: "2-digit",
|
||
}).format(new Date(value));
|
||
}
|
||
export function alarmLabel(
|
||
alarm: Pick<NotdienstAlarm, "status" | "deadline" | "expiresAt">,
|
||
now = new Date(),
|
||
) {
|
||
if (alarm.status === "CANCELLED") return "Storniert";
|
||
if (alarm.status === "CONFIRMED") return "Übernahme bestätigt";
|
||
if (alarm.status === "DECLINED") return "Klärung erforderlich – Absage";
|
||
if (alarm.status === "LATE_CONFIRMATION")
|
||
return "Verspätete Zusage – Freigabe erforderlich";
|
||
if (alarm.status === "REVIEW_REQUIRED")
|
||
return "Klärung erforderlich – bisherige Rückmeldungen prüfen";
|
||
if (alarm.deadline <= now || alarm.expiresAt <= now)
|
||
return "Klärung erforderlich – Frist abgelaufen";
|
||
return "Antwort ausstehend";
|
||
}
|
||
export function needsClarification(
|
||
alarm: Pick<NotdienstAlarm, "status" | "deadline" | "expiresAt">,
|
||
now = new Date(),
|
||
) {
|
||
return (
|
||
!["CONFIRMED", "CANCELLED"].includes(alarm.status) &&
|
||
(alarm.status !== "PENDING" ||
|
||
alarm.deadline <= now ||
|
||
alarm.expiresAt <= now)
|
||
);
|
||
}
|