import Link from 'next/link'; import { BedDouble, CalendarCheck, Plus, Euro, Search } from 'lucide-react'; import { createBookingManagementApi } from '@kit/booking-management/api'; import { formatDate } from '@kit/shared/dates'; import { getSupabaseServerClient } from '@kit/supabase/server-client'; import { Badge } from '@kit/ui/badge'; import { Button } from '@kit/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@kit/ui/card'; import { Input } from '@kit/ui/input'; import { AccountNotFound } from '~/components/account-not-found'; import { CmsPageShell } from '~/components/cms-page-shell'; import { EmptyState } from '~/components/empty-state'; import { StatsCard } from '~/components/stats-card'; interface PageProps { params: Promise<{ account: string }>; searchParams: Promise>; } const PAGE_SIZE = 25; const STATUS_BADGE_VARIANT: Record< string, 'secondary' | 'default' | 'info' | 'outline' | 'destructive' > = { pending: 'secondary', confirmed: 'default', checked_in: 'info', checked_out: 'outline', cancelled: 'destructive', }; const STATUS_LABEL: Record = { pending: 'Ausstehend', confirmed: 'Bestätigt', checked_in: 'Eingecheckt', checked_out: 'Ausgecheckt', cancelled: 'Storniert', no_show: 'Nicht erschienen', }; export default async function BookingsPage({ params, searchParams, }: PageProps) { const { account } = await params; const search = await searchParams; const client = getSupabaseServerClient(); const { data: acct } = await client .from('accounts') .select('id') .eq('slug', account) .single(); if (!acct) { return ( ); } const searchQuery = typeof search.q === 'string' ? search.q : ''; const page = Number(search.page) || 1; const api = createBookingManagementApi(client); const rooms = await api.listRooms(acct.id); // Fetch bookings with joined room & guest names (avoids displaying raw UUIDs) const bookingsQuery = client .from('bookings') .select( '*, room:rooms(id, room_number, name), guest:guests(id, first_name, last_name)', { count: 'exact' }, ) .eq('account_id', acct.id) .order('check_in', { ascending: false }) .range((page - 1) * PAGE_SIZE, page * PAGE_SIZE - 1); const { data: bookingsRaw, count: bookingsTotal } = await bookingsQuery; /* eslint-disable @typescript-eslint/no-explicit-any */ let bookingsData = (bookingsRaw ?? []) as Array>; const total = bookingsTotal ?? 0; // Post-filter by search query (guest name or room name/number) if (searchQuery) { const q = searchQuery.toLowerCase(); bookingsData = bookingsData.filter((b) => { const room = b.room as Record | null; const guest = b.guest as Record | null; const roomName = (room?.name ?? '').toLowerCase(); const roomNumber = (room?.room_number ?? '').toLowerCase(); const guestFirst = (guest?.first_name ?? '').toLowerCase(); const guestLast = (guest?.last_name ?? '').toLowerCase(); return ( roomName.includes(q) || roomNumber.includes(q) || guestFirst.includes(q) || guestLast.includes(q) ); }); } const activeBookings = bookingsData.filter( (b) => b.status === 'confirmed' || b.status === 'checked_in', ); const totalPages = Math.ceil(total / PAGE_SIZE); return (
{/* Header */}

Zimmer und Buchungen verwalten

{/* Stats */}
} /> } /> } />
{/* Search */}
{searchQuery && ( )}
{/* Table or Empty State */} {bookingsData.length === 0 ? ( } title={ searchQuery ? 'Keine Buchungen gefunden' : 'Keine Buchungen vorhanden' } description={ searchQuery ? `Keine Ergebnisse für „${searchQuery}".` : 'Erstellen Sie Ihre erste Buchung, um loszulegen.' } actionLabel={searchQuery ? undefined : 'Neue Buchung'} actionHref={ searchQuery ? undefined : `/home/${account}/bookings/new` } /> ) : ( {searchQuery ? `Ergebnisse (${bookingsData.length})` : `Alle Buchungen (${total})`}
{bookingsData.map((booking) => { const room = booking.room as Record< string, string > | null; const guest = booking.guest as Record< string, string > | null; return ( ); })}
Zimmer Gast Anreise Abreise Status Betrag
{room ? `${room.room_number}${room.name ? ` – ${room.name}` : ''}` : '—'} {guest ? `${guest.first_name} ${guest.last_name}` : '—'} {formatDate(booking.check_in)} {formatDate(booking.check_out)} {STATUS_LABEL[String(booking.status)] ?? String(booking.status)} {booking.total_price != null ? `${Number(booking.total_price).toFixed(2)} €` : '—'}
{/* Pagination */} {totalPages > 1 && !searchQuery && (

Seite {page} von {totalPages} ({total} Einträge)

{page > 1 ? ( ) : ( )} {page < totalPages ? ( ) : ( )}
)}
)}
); }