From f3e7896169abd22391e785bd3ce841916600a871 Mon Sep 17 00:00:00 2001 From: brooktewabe Date: Wed, 15 Apr 2026 14:52:44 +0300 Subject: [PATCH] shuttle and image render updates --- src/app/profile/ProfilePageClient.tsx | 51 ++++++++++++++++++++++++++- src/components/RoomSelectBooking.tsx | 6 ++-- src/lib/guest-hotel-api.ts | 23 ++++++++++++ src/types/room.ts | 1 + 4 files changed, 77 insertions(+), 4 deletions(-) diff --git a/src/app/profile/ProfilePageClient.tsx b/src/app/profile/ProfilePageClient.tsx index c1a9fc7..7e75302 100644 --- a/src/app/profile/ProfilePageClient.tsx +++ b/src/app/profile/ProfilePageClient.tsx @@ -10,8 +10,10 @@ import { guestOrders, guestPointsHistory, guestSpaBookings, + guestShuttles, type PointLedgerRow, type SpaBookingRow, + type ShuttleRow, } from "@/lib/guest-hotel-api"; const orderTabs: { id: OrderCategory | "all"; label: string }[] = [ @@ -68,6 +70,7 @@ function ProfileContent() { const [apiLedger, setApiLedger] = useState([]); const [apiOrders, setApiOrders] = useState([]); const [appointments, setAppointments] = useState([]); + const [apiShuttles, setApiShuttles] = useState([]); useEffect(() => { if (!accessToken || !session) return; @@ -80,6 +83,17 @@ function ProfileContent() { const ph = await guestPointsHistory(pid, accessToken); const ord = await guestOrders(pid, accessToken); const spa = await guestSpaBookings(pid, accessToken); + let shuttles: ShuttleRow[] = []; + if (session.bookingId) { + try { + const sh = await guestShuttles(pid, session.bookingId, accessToken); + shuttles = (sh.data ?? []).sort( + (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() + ); + } catch { + // Ignore if shuttles fail (e.g. no access or 404) + } + } if (!cancelled) { setApiBalance(me.balance); @@ -105,11 +119,13 @@ function ProfileContent() { })), ); setAppointments(spa.data ?? []); + setApiShuttles(shuttles); } } catch { if (!cancelled) { setApiOrders([]); setAppointments([]); + setApiShuttles([]); } } })(); @@ -180,7 +196,7 @@ function ProfileContent() { {(apiBalance ?? session.points).toLocaleString()}

- {apiBalance != null ? "Live balance" : "Balance unavailable"} + {apiBalance != null ? "Balance" : "Balance unavailable"}

@@ -214,6 +230,39 @@ function ProfileContent() { )} + {session.bookingId && ( +
+

Airport shuttle

+ {apiShuttles.length === 0 ? ( +

+ No airport shuttles requested. +

+ ) : ( +
    + {apiShuttles.map((s) => ( +
  • +

    + {s.status} +

    +

    + {s.direction === "AIRPORT_TO_HOTEL" ? "Airport pickup (to hotel)" : s.direction === "HOTEL_TO_AIRPORT" ? "Hotel drop-off (to airport)" : s.direction.replace(/_/g, " ")} +

    +

    + Requested for: {formatWhen(s.requestedAt)} +

    + {s.flightRef && ( +

    Flight: {s.flightRef}

    + )} +
  • + ))} +
+ )} +
+ )} +

Orders

diff --git a/src/components/RoomSelectBooking.tsx b/src/components/RoomSelectBooking.tsx index 83d8368..bded96f 100644 --- a/src/components/RoomSelectBooking.tsx +++ b/src/components/RoomSelectBooking.tsx @@ -41,7 +41,7 @@ export function RoomSelectBooking({ selected, onSelect }: Props) { <>

{selected.name} ) : ( - Choose a room category… + Choose a room )} {open ? "▴" : "▾"} @@ -80,7 +80,7 @@ export function RoomSelectBooking({ selected, onSelect }: Props) { >
{room.name} +new Date(b.createdAt) - +new Date(a.createdAt)) }; } } + +export type ShuttleRow = { + id: string; + bookingId: string; + direction: string; + requestedAt: string; + flightRef: string | null; + notes: string | null; + status: string; + createdAt: string; + updatedAt: string; +}; + +export async function guestShuttles( + propertyId: string, + bookingId: string, + accessToken: string, +): Promise<{ data: ShuttleRow[] }> { + return apiFetch(`/properties/${propertyId}/hotel/guest/bookings/${bookingId}/shuttles`, { + method: "GET", + accessToken, + }); +} diff --git a/src/types/room.ts b/src/types/room.ts index a6e0f95..f479023 100644 --- a/src/types/room.ts +++ b/src/types/room.ts @@ -1,6 +1,7 @@ export type Room = { id: string; slug: string; + imageKeys?: string[]; name: string; shortDescription: string; longDescription: string;