From f185da2163555f39c4e5deedf05022d51df8e535 Mon Sep 17 00:00:00 2001 From: Roba Boru Date: Wed, 15 Jul 2026 21:28:35 +0300 Subject: [PATCH] Update seatmap for blocked seats --- .../src/modules/bookings/bookings.service.ts | 2 + .../portal/src/app/booking/detail/page.tsx | 2 + .../portal/src/app/booking/review/page.tsx | 63 ++++++++++++++----- .../portal/src/app/booking/seats/page.tsx | 2 +- 4 files changed, 53 insertions(+), 16 deletions(-) diff --git a/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts b/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts index 2a9de63d2..a6703f55e 100644 --- a/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts +++ b/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts @@ -1879,6 +1879,8 @@ export class BookingsService { adultCount: booking.adultCount, childCount: booking.childCount, displayCurrency: booking.displayCurrency, displayTotalMinor: booking.displayTotalMinor ?? undefined, bookingType: booking.bookingType, + packageId: (booking as any).packageId ?? null, + isPackageBooking: !!(booking as any).packageId, returnLegStatus: (booking as any).returnLegStatus ?? null, outboundBoardedAt: (booking as any).outboundBoardedAt ?? null, returnBoardedAt: (booking as any).returnBoardedAt ?? null, diff --git a/apps/edr-passenger-web/portal/src/app/booking/detail/page.tsx b/apps/edr-passenger-web/portal/src/app/booking/detail/page.tsx index 025c212bf..c0c9f56bb 100644 --- a/apps/edr-passenger-web/portal/src/app/booking/detail/page.tsx +++ b/apps/edr-passenger-web/portal/src/app/booking/detail/page.tsx @@ -427,6 +427,7 @@ function BookingDetailContent() { + {!booking.isPackageBooking && booking.bookingType !== "PACKAGE" && (

Fare breakdown @@ -481,6 +482,7 @@ function BookingDetailContent() { ); })}

+ )}
diff --git a/apps/edr-passenger-web/portal/src/app/booking/review/page.tsx b/apps/edr-passenger-web/portal/src/app/booking/review/page.tsx index 10051f0d3..95d390182 100644 --- a/apps/edr-passenger-web/portal/src/app/booking/review/page.tsx +++ b/apps/edr-passenger-web/portal/src/app/booking/review/page.tsx @@ -52,6 +52,7 @@ export default function ReviewPage() { const [timeLeft, setTimeLeft] = useState(''); const [seatDetails, setSeatDetails] = useState>({}); const [fareBreakdown, setFareBreakdown] = useState(null); + const [returnFareBreakdown, setReturnFareBreakdown] = useState(null); const [computedTotal, setComputedTotal] = useState(0); const isRoundTrip = searchCriteria?.tripType === 'ROUND_TRIP'; @@ -173,16 +174,27 @@ const adultPassengerCount = searchCriteria?.adultCount ?? passengers.filter(p => // Prefers displayFareMinor (converted) from the fare breakdown API when available. // Falls back to raw ETB seat fares (which are always in minor units). const getPassengerSeatFare = (p: any, index?: number): number | null => { + if (isRoundTrip) { + // Seat-specific fares (set during seat selection) cover each leg separately — use them first. + if (p.outboundSeatFareMinor != null || p.inboundSeatFareMinor != null) { + if (isPackageBooking) return (p.outboundSeatFareMinor ?? 0) * 2; + return (p.outboundSeatFareMinor ?? 0) + (p.inboundSeatFareMinor ?? 0); + } + // No seat-specific fares: fall back to the per-leg fare-breakdown totals for both legs. + if (!isPackageBooking && fareBreakdown?.passengers && returnFareBreakdown?.passengers && index != null) { + const obLine = fareBreakdown.passengers[index]; + const retLine = returnFareBreakdown.passengers[index]; + const obFare = obLine?.displayFareMinor ?? obLine?.fareMinor; + const retFare = retLine?.displayFareMinor ?? retLine?.fareMinor; + if (obFare != null && retFare != null) return obFare + retFare; + } + return null; + } if (!isPackageBooking && fareBreakdown?.passengers && index != null) { const line = fareBreakdown.passengers[index]; const displayFare = line?.displayFareMinor ?? line?.fareMinor; if (displayFare != null) return displayFare; } - if (isRoundTrip) { - if (p.outboundSeatFareMinor == null && p.inboundSeatFareMinor == null) return null; - if (isPackageBooking) return (p.outboundSeatFareMinor ?? 0) * 2; - return (p.outboundSeatFareMinor ?? 0) + (p.inboundSeatFareMinor ?? 0); - } if (p.seatFareMinor == null) return null; return isPackageBooking ? p.seatFareMinor * 2 : p.seatFareMinor; }; @@ -541,6 +553,22 @@ const adultPassengerCount = searchCriteria?.adultCount ?? passengers.filter(p => const result: any = await apiClient.get(`/search/fare-breakdown?${params}`); setFareBreakdown(result); + + // For round-trips, also fetch the return leg's fare breakdown so the review page + // can display and send the correct combined total (outbound + return per passenger). + if (isRoundTrip && inboundSchedule) { + const returnScheduleId = (inboundSchedule as any).id; + const returnParams = new URLSearchParams({ + scheduleId: returnScheduleId, + originStationId: searchCriteria.destinationStationId, + destinationStationId: searchCriteria.originStationId, + passengers: passengersParam, + displayCurrency: displayCurrencyCode, + ...(searchCriteria.promoCode ? { promoCode: searchCriteria.promoCode } : {}), + }); + const returnResult: any = await apiClient.get(`/search/fare-breakdown?${returnParams}`); + setReturnFareBreakdown(returnResult); + } } catch (err) { } })(); @@ -566,7 +594,11 @@ const adultPassengerCount = searchCriteria?.adultCount ?? passengers.filter(p => const isFreeChild = line?.isFree ?? (isChildPassenger && isFirstChild(passengers, i)); if (isFreeChild) return sum; const seatFare = getPassengerSeatFare(p, i); - const displayFare = line?.displayFareMinor ?? line?.fareMinor; + // For round-trips the fallback must combine both legs; for one-way it's the single-leg fare. + const obFare = line?.displayFareMinor ?? line?.fareMinor; + const retLine = returnFareBreakdown?.passengers?.[i]; + const retFare = retLine?.displayFareMinor ?? retLine?.fareMinor; + const displayFare = isRoundTrip && retFare != null ? (obFare ?? 0) + retFare : obFare; return sum + (seatFare ?? displayFare ?? 0); }, 0); @@ -586,26 +618,27 @@ const adultPassengerCount = searchCriteria?.adultCount ?? passengers.filter(p => ? isPkgFreeChild(i) : (line?.isFree ?? (isChild(p) && isFirstChild(passengers, i))); - // Per-leg fares for round trips — use converted amounts from fareBreakdown when available - const displayFare = line?.displayFareMinor ?? line?.fareMinor; + // Per-leg fares for round trips — prefer seat-specific fares, then per-leg breakdowns. + const retLine = returnFareBreakdown?.passengers?.[i]; + const obBreakdownFare = line?.displayFareMinor ?? line?.fareMinor; + const retBreakdownFare = retLine?.displayFareMinor ?? retLine?.fareMinor; const outboundFare: number | null = isRoundTrip ? (isPackageBooking ? (packageTierPriceMinor ?? null) - : (displayFare != null - ? Math.round(displayFare / 2) - : ((p as any).outboundSeatFareMinor ?? null))) + : ((p as any).outboundSeatFareMinor ?? obBreakdownFare ?? null)) : null; const inboundFare: number | null = isRoundTrip ? (isPackageBooking ? (packageTierPriceMinor ?? null) - : (displayFare != null - ? Math.round(displayFare / 2) - : ((p as any).inboundSeatFareMinor ?? null))) + : ((p as any).inboundSeatFareMinor ?? retBreakdownFare ?? null)) : null; const seatFare = getPassengerSeatFare(p, i); + const combinedDisplayFare = isRoundTrip && retBreakdownFare != null + ? (obBreakdownFare ?? 0) + retBreakdownFare + : obBreakdownFare; const passengerTotal = isPackageBooking ? (isFreeChild ? 0 : (seatFare ?? (isChildPassenger ? pkgChildFare : pkgAdultFare))) - : (isFreeChild ? 0 : (seatFare ?? displayFare ?? 0)); + : (isFreeChild ? 0 : (seatFare ?? combinedDisplayFare ?? 0)); return (
diff --git a/apps/edr-passenger-web/portal/src/app/booking/seats/page.tsx b/apps/edr-passenger-web/portal/src/app/booking/seats/page.tsx index a143f7a1e..b38e3aee9 100644 --- a/apps/edr-passenger-web/portal/src/app/booking/seats/page.tsx +++ b/apps/edr-passenger-web/portal/src/app/booking/seats/page.tsx @@ -52,7 +52,7 @@ const BedCard = memo(({ bed, isSelected, isAssignedToOther, onToggle }: any) => ? "bg-purple-50 border-purple-300 cursor-not-allowed dark:bg-purple-900/20 dark:border-purple-700" : bed.status === "AVAILABLE" ? "bg-green-50 border-green-300 hover:bg-green-100 hover:border-green-400 dark:bg-green-900/20 dark:border-green-700" - : bed.status === "BOOKED" + : bed.status === "BOOKED" || bed.status === "BLOCKED" ? "bg-red-50 border-red-300 cursor-not-allowed dark:bg-red-900/20 dark:border-red-700" : "bg-gray-100 border-gray-300 cursor-not-allowed dark:bg-gray-800 dark:border-gray-700" }`}