From 30661a2699df3a91f5e406f9b0cf87057da8d2b7 Mon Sep 17 00:00:00 2001 From: Stephanos A Date: Tue, 7 Jul 2026 08:52:00 +0300 Subject: [PATCH] Build issue resolutions --- .../src/app/booking/confirmation/page.tsx | 30 +++++++++++++++---- .../portal/src/app/booking/payment/page.tsx | 4 +-- .../portal/src/app/booking/review/page.tsx | 8 ----- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/apps/edr-passenger-web/portal/src/app/booking/confirmation/page.tsx b/apps/edr-passenger-web/portal/src/app/booking/confirmation/page.tsx index 5d992af93..e77ab70b4 100644 --- a/apps/edr-passenger-web/portal/src/app/booking/confirmation/page.tsx +++ b/apps/edr-passenger-web/portal/src/app/booking/confirmation/page.tsx @@ -27,7 +27,7 @@ type BookingWithTicket = { export default function ConfirmationPage() { const router = useRouter(); - const { bookingId, pnr, selectedSchedule, outboundSchedule, inboundSchedule, searchCriteria, passengers, clearBooking, packageName, packageTierPriceMinor, packageId, reviewedTotalMinor, reviewedPassengerFares } = useBookingStore(); + const { bookingId, pnr, selectedSchedule, outboundSchedule, inboundSchedule, searchCriteria, passengers, clearBooking, packageName, packageId, reviewedTotalMinor, reviewedPassengerFares } = useBookingStore(); // The currency/amount actually confirmed for the payment option the user selected — // null when no payment step ran (e.g. a fully-discounted, zero-amount booking). const { selectedCurrency: paidCurrency, paidAmountMinor } = usePaymentStore(); @@ -92,14 +92,32 @@ export default function ConfirmationPage() { const activeSchedule = isRoundTrip ? outboundSchedule : selectedSchedule; // Prefer the amount/currency actually confirmed for the selected payment option; // only fall back to the ETB booking fare when no payment step ran (e.g. $0 total). - const totalFare = reviewedTotalMinor - ?? paidAmountMinor - ?? _booking?.totalMinor - ?? passengers.reduce((s) => s + (activeSchedule?.baseFareAdult || 0), 0); const voucherCurrency = 'ETB'; const createdAt = _booking?.createdAt || new Date().toISOString(); const status = _booking?.status || 'CONFIRMED'; + // Compute per-passenger fares using the same logic as the review/payment pages. + // reviewedPassengerFares is the authoritative source; rebuild from package context + // as a fallback so free children always show ETB 0.00 on their voucher. + const { packageTierPriceMinor } = useBookingStore.getState(); + const isPackageBooking = packageTierPriceMinor != null; + const adultCount = searchCriteria?.adultCount ?? passengers.filter(p => !isChild(p)).length; + const pkgMultiplier = isPackageBooking && isRoundTrip ? 2 : 1; + const pkgAdultFare = isPackageBooking ? packageTierPriceMinor! * pkgMultiplier : 0; + const pkgChildFare = pkgAdultFare; + + const getVoucherFare = (idx: number): number => { + if (reviewedPassengerFares?.[idx] != null) return reviewedPassengerFares[idx].fareMinor; + if (isPackageBooking) { + const isPkgChild = idx >= adultCount; + const isFreeChild = isPkgChild && (idx - adultCount) < adultCount; + if (isFreeChild) return 0; + return isPkgChild ? pkgChildFare : pkgAdultFare; + } + const totalFare = reviewedTotalMinor ?? paidAmountMinor ?? _booking?.totalMinor ?? 0; + return Math.round(totalFare / passengers.length); + }; + const outbound = { trainNumber: activeSchedule?.trainNumber || 'N/A', trainName: 'EDR Express', @@ -137,7 +155,7 @@ export default function ConfirmationPage() { outboundSchedule: outbound, inboundSchedule: inbound, isRoundTrip, - fareMinor: reviewedPassengerFares?.[i]?.fareMinor ?? Math.round(totalFare / passengers.length), + fareMinor: getVoucherFare(i), currency: voucherCurrency, createdAt, }); diff --git a/apps/edr-passenger-web/portal/src/app/booking/payment/page.tsx b/apps/edr-passenger-web/portal/src/app/booking/payment/page.tsx index 5366bfefb..0b27dfa87 100644 --- a/apps/edr-passenger-web/portal/src/app/booking/payment/page.tsx +++ b/apps/edr-passenger-web/portal/src/app/booking/payment/page.tsx @@ -9,7 +9,7 @@ import { useState, useEffect } from "react"; import { PaymentMethod } from "@/types"; import { format } from "date-fns"; import { formatTime, getTimePeriod } from '@/utils/format'; -import { calculatePassengerFare, isChild, isFirstChild, formatFare } from '@/utils/fare-utils'; +import { isChild, isFirstChild, formatFare } from '@/utils/fare-utils'; import { CreditCard, Smartphone, @@ -28,7 +28,7 @@ const getIconForMethod = (methodId: string) => { export default function PaymentPage() { const router = useRouter(); - const { bookingId, pnr, selectedSchedule, outboundSchedule, inboundSchedule, passengers, searchCriteria, packageName, packageTierPriceMinor, reviewedTotalMinor, reviewedPassengerFares } = useBookingStore(); + const { bookingId, pnr, selectedSchedule, outboundSchedule, inboundSchedule, passengers, searchCriteria, packageName, reviewedTotalMinor, reviewedPassengerFares } = useBookingStore(); const { setPaymentIntent, updateStatus, setCurrency, setPaidAmount } = usePaymentStore(); const [selectedMethod, setSelectedMethod] = useState(null); const [selectedMethodCurrency, setSelectedMethodCurrency] = useState(null); 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 a0a335c9e..194b47dff 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 @@ -474,14 +474,6 @@ export default function ReviewPage() { fetchFareBreakdown(scheduleId, searchCriteria.originStationId, searchCriteria.destinationStationId); }, [fetchFareBreakdown, isRoundTrip, outboundSchedule?.id, selectedSchedule?.id, searchCriteria?.originStationId, searchCriteria?.destinationStationId]); - if (isRoundTrip && (!outboundSchedule || !inboundSchedule || !passengers.length)) { - return null; - } - - if (!isRoundTrip && (!selectedSchedule || !passengers.length)) { - return null; - } - const isPackageBooking = packageTierPriceMinor !== null; // packageTierPriceMinor is the per-adult fare for ONE leg. // Round-trip packages multiply by 2.