/** * Kalenderansicht (plan.md Abschnitt 7): Monat / Woche / Tag. * * Serverkomponente: laedt Kalender + Reservierungen des Zeitraums * serverseitig (Berechtigungspruefung via requireCalendarContext). * Die Ansicht selbst ist eine reine Darstellung; das Umschalten der * Ansicht/Periode erfolgt ueber URL-Parameter (sharebar, kein State). */ import { redirect } from 'next/navigation'; import { prisma } from '@/lib/db/client'; import { requireCalendarContext } from '@/lib/api/context'; import { displayName } from '@/lib/privacy/display'; import { CalendarView } from '@/components/calendar/CalendarView'; import { NewReservationButton } from '@/components/reservation/NewReservationButton'; interface PageProps { params: Promise<{ id: string }>; searchParams: Promise<{ view?: string; date?: string }>; } export default async function CalendarPage({ params, searchParams }: PageProps) { const { id } = await params; const { view = 'week', date } = await searchParams; const context = await requireCalendarContext(id).catch(() => null); if (!context) { redirect('/login'); } // Zeitfenster bestimmen (UTC-Grenzen; Anzeige in Kalender-Zeitzone). const referenceDate = date ? new Date(date) : new Date(); const { windowStart, windowEnd } = computeWindow(view, referenceDate); const reservations = await prisma.reservation.findMany({ where: { calendarId: id, status: 'CONFIRMED', startAt: { lt: windowEnd }, endAt: { gt: windowStart }, }, orderBy: { startAt: 'asc' }, select: { id: true, userId: true, title: true, startAt: true, endAt: true, user: { select: { email: true, username: true } }, }, }); return (

{context.calendar.title}

{context.calendar.description && (

{context.calendar.description}

)} {!context.calendar.isActive && (

Dieser Kalender ist deaktiviert; neue Reservierungen sind nicht moeglich.

)}
({ id: reservation.id, title: reservation.title, startAt: reservation.startAt.toISOString(), endAt: reservation.endAt.toISOString(), ownerName: displayName( reservation.user.username, reservation.user.email, ), isOwn: reservation.userId === context.user.id, }))} />
); } /** Berechnet das Zeitfenster der gewaehlten Ansicht. */ function computeWindow( view: string, reference: Date, ): { windowStart: Date; windowEnd: Date } { const start = new Date(reference); start.setHours(0, 0, 0, 0); const end = new Date(start); switch (view) { case 'day': end.setDate(end.getDate() + 1); break; case 'month': start.setDate(1); end.setMonth(end.getMonth() + 1, 1); break; case 'week': default: // Woche startet montags. const weekday = (start.getDay() + 6) % 7; start.setDate(start.getDate() - weekday); end.setTime(start.getTime()); end.setDate(end.getDate() + 7); break; } return { windowStart: start, windowEnd: end }; }