import Link from 'next/link'; import { BedDouble, CalendarCheck, Plus, Euro, Search } from 'lucide-react'; import { getTranslations } from 'next-intl/server'; import { createBookingManagementApi } from '@kit/booking-management/api'; import { formatDate, formatCurrencyAmount } 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'; import { BOOKING_STATUS_VARIANT as STATUS_BADGE_VARIANT, BOOKING_STATUS_LABEL_KEYS as STATUS_LABEL_KEYS, } from '~/lib/status-badges'; interface PageProps { params: Promise<{ account: string }>; searchParams: Promise>; } const PAGE_SIZE = 25; export default async function BookingsPage({ params, searchParams, }: PageProps) { const { account } = await params; const search = await searchParams; const client = getSupabaseServerClient(); const t = await getTranslations('bookings'); 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; 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((booking) => { const room = booking.room as Record | null; const guest = booking.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( (booking) => booking.status === 'confirmed' || booking.status === 'checked_in', ); const totalPages = Math.ceil(total / PAGE_SIZE); return (
{/* Header */}

{t('list.manage')}

{/* Stats */}
} /> } /> } />
{/* Search */}
{searchQuery && ( )}
{/* Table or Empty State */} {bookingsData.length === 0 ? ( } title={searchQuery ? t('list.noResults') : t('list.noBookings')} description={ searchQuery ? t('list.noResultsFor', { query: searchQuery }) : t('list.createFirst') } actionLabel={searchQuery ? undefined : t('list.newBooking')} actionHref={ searchQuery ? undefined : `/home/${account}/bookings/new` } /> ) : ( {searchQuery ? t('list.searchResults', { count: bookingsData.length }) : t('list.allBookings', { count: total })}
{bookingsData.map((booking) => { const room = booking.room as Record< string, string > | null; const guest = booking.guest as Record< string, string > | null; return ( ); })}
{t('list.room')} {t('list.guest')} {t('list.checkIn')} {t('list.checkOut')} {t('list.status')} {t('list.amount')}
{room ? `${room.room_number}${room.name ? ` – ${room.name}` : ''}` : '—'} {guest ? `${guest.first_name} ${guest.last_name}` : '—'} {formatDate(booking.check_in as string)} {formatDate(booking.check_out as string)} {t( STATUS_LABEL_KEYS[String(booking.status)] ?? String(booking.status), )} {booking.total_price != null ? formatCurrencyAmount( booking.total_price as number, ) : '—'}
{/* Pagination */} {totalPages > 1 && !searchQuery && (

{t('common.page')} {page} {t('common.of')} {totalPages} ( {total} {t('common.entries')})

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