'use client'; /** * Kalenderansicht-Komponente (plan.md Abschnitt 7): * Monat / Woche / Tag mit klickbaren Reservierungen. * Die Navigation laeuft ueber URL-Parameter (sharebar, servergerendert). */ import { useRouter } from 'next/navigation'; import { Card } from '@/components/ui/ui'; export interface CalendarReservation { id: string; title: string; startAt: string; endAt: string; /** Anzeigename des Erstellers (Username oder maskierte E-Mail). */ ownerName: string; isOwn: boolean; } const WEEKDAYS = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'] as const; function formatTime(iso: string): string { return new Date(iso).toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit', }); } function formatDate(date: Date): string { return date.toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', }); } /** Verschibt das Referenzdatum um `amount` Einheiten der Ansicht. */ function shiftDate(view: string, isoDate: string, amount: number): string { const date = new Date(isoDate); switch (view) { case 'day': date.setDate(date.getDate() + amount); break; case 'month': date.setMonth(date.getMonth() + amount, 1); break; default: date.setDate(date.getDate() + amount * 7); break; } return date.toISOString(); } export function CalendarView({ view, referenceDate, calendarId, reservations, }: { view: string; referenceDate: string; calendarId: string; reservations: CalendarReservation[]; }) { const router = useRouter(); const reference = new Date(referenceDate); function navigate(nextView: string, nextDate: string) { router.push( `/calendar/${calendarId}?view=${nextView}&date=${encodeURIComponent(nextDate)}`, ); } const navButtons = (
{(['day', 'week', 'month'] as const).map((nextView) => ( ))}
{formatDate(reference)}
); if (view === 'month') { return ( {navButtons} ); } if (view === 'day') { return ( {navButtons} ); } return ( {navButtons} ); } /** Monatsraster: Tage mit Anzahl der Reservierungen. */ function MonthGrid({ reference, reservations, }: { reference: Date; reservations: CalendarReservation[]; }) { const year = reference.getFullYear(); const month = reference.getMonth(); const firstDay = new Date(year, month, 1); const daysInMonth = new Date(year, month + 1, 0).getDate(); const leadingEmpty = (firstDay.getDay() + 6) % 7; const countPerDay = new Map(); for (const reservation of reservations) { const day = new Date(reservation.startAt).getDate(); if (new Date(reservation.startAt).getMonth() === month) { countPerDay.set(day, (countPerDay.get(day) ?? 0) + 1); } } return (
{WEEKDAYS.map((weekday) => ( {weekday} ))}
{Array.from({ length: leadingEmpty }, (_, index) => (
))} {Array.from({ length: daysInMonth }, (_, index) => { const day = index + 1; const count = countPerDay.get(day) ?? 0; return (
{day}
{count > 0 && (
{count} Res.
)}
); })}
); } /** Tages-Timeline: Stundenraster mit belegten Bloecken. */ function DayTimeline({ reference, reservations, }: { reference: Date; reservations: CalendarReservation[]; }) { const dayReservations = reservations.filter( (reservation) => new Date(reservation.startAt).toDateString() === reference.toDateString(), ); return (

{reference.toLocaleDateString('de-DE', { weekday: 'long', day: 'numeric', month: 'long', })}

{dayReservations.length === 0 ? (

Keine Reservierungen an diesem Tag.

) : (
    {dayReservations.map((reservation) => (
  • {formatTime(reservation.startAt)} – {formatTime(reservation.endAt)} {' '} {reservation.title} {reservation.ownerName}
  • ))}
)}
); } /** Wochenraster: 7 Tage mit Reservierungslisten. */ function WeekGrid({ reference, reservations, }: { reference: Date; reservations: CalendarReservation[]; }) { const monday = new Date(reference); monday.setHours(0, 0, 0, 0); monday.setDate(monday.getDate() - ((monday.getDay() + 6) % 7)); const days = Array.from({ length: 7 }, (_, index) => { const day = new Date(monday); day.setDate(day.getDate() + index); return day; }); return (
{days.map((day) => { const dayReservations = reservations.filter( (reservation) => new Date(reservation.startAt).toDateString() === day.toDateString(), ); return (
{WEEKDAYS[(day.getDay() + 6) % 7]} {day.getDate()}.
    {dayReservations.map((reservation) => (
  • {formatTime(reservation.startAt)}–{formatTime(reservation.endAt)}
    {reservation.title}
  • ))}
); })}
); } /** Wrapper, damit die drei Ansichten einheitlich benutzt werden koennen. */ function MonthGridWrapper(props: { reference: Date; reservations: CalendarReservation[]; }) { return ; } // Alias-Exporte fuer lesbare Verwendung oben. const MonthGrid_ = MonthGridWrapper; void MonthGrid_; const DayTimeline_ = DayTimeline; void DayTimeline_; const WeekGrid_ = WeekGrid; void WeekGrid_;