import type { AdminViewServerProps } from "payload"; import { getAdminCalendarItems, type AdminCalendarItem } from "@/lib/booking/adminCalendar"; import styles from "./AdminCalendarView.module.css"; const WEEKDAY_LABELS = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]; const STATUS_LABEL: Record = { pending: "Anfrage", confirmed: "Bestätigt", rejected: "Abgelehnt", cancelled: "Storniert", public: "Öffentlich", }; const DOT_CLASS: Record = { pending: styles.dotPending, confirmed: styles.dotConfirmed, rejected: styles.dotRejected, cancelled: styles.dotCancelled, public: styles.dotPublic, }; const BADGE_CLASS: Record = { pending: styles.badgePending, confirmed: styles.badgeConfirmed, rejected: styles.badgeRejected, cancelled: styles.badgeCancelled, public: styles.badgePublic, }; function dateKey(d: Date) { return d.toISOString().slice(0, 10); } function parseMonthParam(value: string | null): Date { if (value && /^\d{4}-\d{2}$/.test(value)) { const [y, m] = value.split("-").map(Number); return new Date(y, m - 1, 1); } return new Date(new Date().getFullYear(), new Date().getMonth(), 1); } function monthParam(d: Date) { return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`; } function fmtTime(iso: string) { return new Date(iso).toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" }); } export async function AdminCalendarView({ initPageResult }: AdminViewServerProps) { const req = initPageResult.req; const searchParams = req.searchParams; const month = parseMonthParam(searchParams.get("month")); const selectedDayParam = searchParams.get("day"); const selectedDay = selectedDayParam ? new Date(`${selectedDayParam}T00:00:00`) : null; const gridStart = new Date(month.getFullYear(), month.getMonth(), 1); const firstWeekday = (gridStart.getDay() + 6) % 7; const rangeStart = new Date(gridStart); rangeStart.setDate(rangeStart.getDate() - firstWeekday); const daysInMonth = new Date(month.getFullYear(), month.getMonth() + 1, 0).getDate(); const rangeEnd = new Date(rangeStart); rangeEnd.setDate(rangeEnd.getDate() + 41); // 6 full weeks const items = await getAdminCalendarItems(req.payload, { from: rangeStart, to: rangeEnd }); const itemsByDay = new Map(); for (const item of items) { const key = dateKey(new Date(item.date)); itemsByDay.set(key, [...(itemsByDay.get(key) ?? []), item]); } const cells: (Date | null)[] = []; for (let i = 0; i < firstWeekday; i++) cells.push(null); for (let d = 1; d <= daysInMonth; d++) cells.push(new Date(month.getFullYear(), month.getMonth(), d)); while (cells.length % 7 !== 0) cells.push(null); const prevMonth = new Date(month.getFullYear(), month.getMonth() - 1, 1); const nextMonth = new Date(month.getFullYear(), month.getMonth() + 1, 1); const today = dateKey(new Date()); const monthLabel = month.toLocaleDateString("de-DE", { month: "long", year: "numeric" }); const dayItems = selectedDay ? (itemsByDay.get(dateKey(selectedDay)) ?? []) : []; const hours = Array.from({ length: 13 }, (_, i) => i + 8); // 08:00–20:00 return (

Kalender

Alle bestätigten und vorgeschlagenen Termine, private Einzelbuchungen und öffentliche Veranstaltungen.

{monthLabel}
{WEEKDAY_LABELS.map((d) => (
{d}
))} {cells.map((day, i) => { if (!day) return
; const key = dateKey(day); const dayEntries = itemsByDay.get(key) ?? []; const isSelected = selectedDayParam === key; return ( {day.getDate()} {dayEntries.length > 0 && ( {dayEntries.slice(0, 4).map((entry, j) => ( ))} )} ); })}
{Object.entries(STATUS_LABEL).map(([status, label]) => ( {label} ))}
{selectedDay ? selectedDay.toLocaleDateString("de-DE", { weekday: "long", day: "2-digit", month: "long", year: "numeric" }) : "Wähle einen Tag im Kalender"}
{!selectedDay &&

Klicke auf einen Tag, um die Tagesübersicht zu sehen.

} {selectedDay && dayItems.length === 0 &&

An diesem Tag ist nichts eingetragen.

} {selectedDay && dayItems.length > 0 && hours.map((hour) => { const hourEntries = dayItems.filter((item) => new Date(item.startTime).getHours() === hour); return ( ); })}
); }