diff --git a/apps/edr-passenger-api/src/modules/segments/booking-flow-example.ts b/apps/edr-passenger-api/src/modules/segments/booking-flow-example.ts deleted file mode 100644 index 7e912a6e2..000000000 --- a/apps/edr-passenger-api/src/modules/segments/booking-flow-example.ts +++ /dev/null @@ -1,238 +0,0 @@ -/** - * SEGMENT-BASED SEAT RESERVATION EXAMPLE - * - * Demonstrates the complete flow for booking Addis Ababa → Dire Dawa - * on the Addis Ababa → Djibouti route with segment-based seat management. - * - * Route: Addis Ababa (seq:1) → Adama (seq:2) → Awash (seq:3) → Dire Dawa (seq:4) → Aysha (seq:5) → Djibouti (seq:6) - * Booking: Addis Ababa → Dire Dawa (segments: 1→2, 2→3, 3→4) - */ - -import { PrismaClient } from '@prisma/client'; - -const prisma = new PrismaClient(); - -async function exampleBookingFlow() { - console.log('=== SEGMENT-BASED BOOKING FLOW ===\n'); - - const scheduleId = 'schedule_add_dji_001'; - const passengerId = 'passenger_kelemu'; - const seatIds = ['seat_coach_a_1a', 'seat_coach_a_1b']; - const originStationId = 'st_ADD'; - const destinationStationId = 'st_DRE'; - - try { - console.log('1. Checking seat availability...'); - const segments = await getJourneySegments(scheduleId, originStationId, destinationStationId); - console.log('Journey segments:', segments.map(s => `${s.fromName} → ${s.toName}`)); - - console.log('\n2. Holding seats...'); - const holdResult = await holdSeatsTransaction(scheduleId, seatIds, passengerId, originStationId, destinationStationId); - console.log('Hold created:', holdResult); - - console.log('\n3. Processing payment...'); - await new Promise(resolve => setTimeout(resolve, 5000)); - - console.log('\n4. Confirming booking...'); - const bookingId = 'booking_' + Date.now(); - const confirmResult = await confirmBookingTransaction(holdResult.holdId, bookingId, segments); - console.log('Booking confirmed:', confirmResult); - - console.log('\n5. Simulating trip progress...'); - await simulateTripProgress(scheduleId, segments); - - } catch (error) { - console.error('Booking flow error:', error); - } -} - -async function getJourneySegments(scheduleId: string, originStationId: string, destinationStationId: string) { - const stopTimes = await prisma.tripStopTime.findMany({ - where: { scheduleId }, - include: { station: true }, - orderBy: { sequence: 'asc' }, - }); - - const originStop = stopTimes.find(st => st.stationId === originStationId); - const destinationStop = stopTimes.find(st => st.stationId === destinationStationId); - - if (!originStop || !destinationStop || originStop.sequence >= destinationStop.sequence) { - throw new Error('Invalid origin/destination'); - } - - const segments = []; - for (let i = originStop.sequence; i < destinationStop.sequence; i++) { - const fromStop = stopTimes.find(st => st.sequence === i); - const toStop = stopTimes.find(st => st.sequence === i + 1); - if (fromStop && toStop) { - segments.push({ - fromStationId: fromStop.stationId, - toStationId: toStop.stationId, - fromSequence: fromStop.sequence, - toSequence: toStop.sequence, - fromName: fromStop.station.name, - toName: toStop.station.name, - }); - } - } - return segments; -} - -async function holdSeatsTransaction(scheduleId: string, seatIds: string[], passengerId: string, originStationId: string, destinationStationId: string) { - return prisma.$transaction(async (tx) => { - console.log(' → Starting seat hold transaction...'); - - const seats = await tx.seat.findMany({ where: { id: { in: seatIds } }, include: { coach: true } }); - if (seats.length !== seatIds.length) throw new Error('Some seats not found'); - - for (const seat of seats) { - if (seat.status !== 'AVAILABLE') { - throw new Error(`Seat ${seat.seatNumber} is not available (status: ${seat.status})`); - } - } - - const expiresAt = new Date(Date.now() + 10 * 60 * 1000); - const seatHold = await tx.seatHold.create({ - data: { scheduleId, seatIds, passengerId, expiresAt }, - }); - - await tx.seat.updateMany({ where: { id: { in: seatIds } }, data: { status: 'HELD', heldUntil: expiresAt } }); - - console.log(' → Seats held successfully'); - return { holdId: seatHold.id, expiresAt, seats: seatIds.length }; - }); -} - -async function confirmBookingTransaction(holdId: string, bookingId: string, segments: any[]) { - return prisma.$transaction(async (tx) => { - console.log(' → Starting booking confirmation transaction...'); - - const hold = await tx.seatHold.findUnique({ where: { id: holdId } }); - if (!hold || hold.expiresAt < new Date()) throw new Error('Hold expired or not found'); - - const booking = await tx.booking.create({ - data: { - id: bookingId, - bookingRef: 'BK' + Date.now().toString().slice(-6), - passengerId: hold.passengerId, - scheduleId: hold.scheduleId, - status: 'CONFIRMED', - totalMinor: 45000, - currency: 'ETB', - }, - }); - - const journey = await tx.journey.create({ - data: { passengerId: hold.passengerId, status: 'CONFIRMED', totalMinor: 45000, currency: 'ETB' }, - }); - - for (const seatId of hold.seatIds) { - for (let i = 0; i < segments.length; i++) { - await tx.journeySegment.create({ - data: { - journeyId: journey.id, - scheduleId: hold.scheduleId, - segmentOrder: i + 1, - seatId, - departureStationId: segments[i].fromStationId, - arrivalStationId: segments[i].toStationId, - }, - }); - } - } - - for (const seatId of hold.seatIds) { - await tx.bookingSeat.create({ data: { bookingId, seatId, passengerName: 'Kelemu Ketsela' } }); - } - - await tx.seat.updateMany({ where: { id: { in: hold.seatIds } }, data: { status: 'BOOKED', heldUntil: null } }); - await tx.seatHold.delete({ where: { id: holdId } }); - - console.log(' → Booking confirmed successfully'); - return { bookingId, bookingRef: booking.bookingRef, confirmedSeats: hold.seatIds.length, segments: segments.length }; - }); -} - -async function simulateTripProgress(scheduleId: string, bookedSegments: any[]) { - console.log(' → Simulating trip progress...'); - - for (const segment of bookedSegments) { - console.log(` → Train approaching ${segment.toName}...`); - - await prisma.tripLiveStatus.upsert({ - where: { scheduleId }, - update: { currentLocationLabel: segment.toName, progressPercent: Math.round((segment.toSequence / 4) * 100) }, - create: { - scheduleId, - state: 'EN_ROUTE', - currentLocationLabel: segment.toName, - progressPercent: Math.round((segment.toSequence / 4) * 100), - delayMinutes: 0, - }, - }); - - if (segment.toName === 'Dire Dawa') { - console.log(' → Passengers reached destination, releasing seats...'); - await releaseSeatsAtStation(scheduleId, segment.toStationId); - } - - await new Promise(resolve => setTimeout(resolve, 2000)); - } -} - -async function releaseSeatsAtStation(scheduleId: string, stationId: string) { - return prisma.$transaction(async (tx) => { - const completedSegments = await tx.journeySegment.findMany({ - where: { scheduleId, arrivalStationId: stationId }, - include: { journey: { include: { journeySegments: { where: { scheduleId } } } } }, - }); - - const seatsToRelease: string[] = []; - - for (const segment of completedSegments) { - const passengerSegments = segment.journey.journeySegments.filter((js: any) => js.seatId === segment.seatId); - const maxOrder = Math.max(...passengerSegments.map((js: any) => js.segmentOrder)); - if (segment.segmentOrder === maxOrder) seatsToRelease.push(segment.seatId!); - } - - if (seatsToRelease.length > 0) { - await tx.seat.updateMany({ where: { id: { in: seatsToRelease } }, data: { status: 'AVAILABLE' } }); - console.log(` → Released ${seatsToRelease.length} seats at station`); - } - - return seatsToRelease; - }); -} - -async function checkOverlappingReservations(tx: any, scheduleId: string, seatId: string, segments: any[]) { - const activeHolds = await tx.seatHold.findMany({ - where: { scheduleId, seatIds: { has: seatId }, expiresAt: { gt: new Date() } }, - }); - - const activeBookings = await tx.journeySegment.findMany({ - where: { - scheduleId, - seatId, - journey: { status: { in: ['PENDING_PAYMENT', 'CONFIRMED'] } }, - }, - }); - - return [...activeHolds, ...activeBookings]; -} - -if (require.main === module) { - exampleBookingFlow() - .then(() => console.log('\n=== EXAMPLES COMPLETED ===')) - .catch(console.error) - .finally(() => prisma.$disconnect()); -} - -export { - exampleBookingFlow, - getJourneySegments, - holdSeatsTransaction, - confirmBookingTransaction, - simulateTripProgress, - releaseSeatsAtStation, - checkOverlappingReservations, -}; diff --git a/apps/edr-passenger-web/backoffice/src/app/app-releases/page.tsx b/apps/edr-passenger-web/backoffice/src/app/app-releases/page.tsx index 2e036f31e..c5d5d7fa9 100644 --- a/apps/edr-passenger-web/backoffice/src/app/app-releases/page.tsx +++ b/apps/edr-passenger-web/backoffice/src/app/app-releases/page.tsx @@ -165,7 +165,7 @@ export default function AppReleasesPage() {
setFormOpen(false)}>Cancel - + {editing ? 'Save Changes' : 'Create Release'}
diff --git a/apps/edr-passenger-web/backoffice/src/app/tickets/page.tsx b/apps/edr-passenger-web/backoffice/src/app/tickets/page.tsx index e17391f32..7fe523398 100644 --- a/apps/edr-passenger-web/backoffice/src/app/tickets/page.tsx +++ b/apps/edr-passenger-web/backoffice/src/app/tickets/page.tsx @@ -9,6 +9,7 @@ import Badge from '@/components/ui/Badge'; import ActionButton from '@/components/ui/ActionButton'; import ConfirmDialog from '@/components/ui/ConfirmDialog'; import Modal from '@/components/ui/Modal'; +import Image from 'next/image'; import { ticketsApi, apiClient, stationsApi, excessBaggageApi } from '@/lib/api'; import { formatDateTime, formatCurrency, formatDateTimeShort } from '@/lib/utils'; import { useAuthStore } from '@/lib/auth-store'; @@ -844,10 +845,13 @@ export default function TicketsPage() {
- {`QR

{t.ticketNumber}

diff --git a/apps/edr-passenger-web/backoffice/test-routes.html b/apps/edr-passenger-web/backoffice/test-routes.html deleted file mode 100644 index e34849a03..000000000 --- a/apps/edr-passenger-web/backoffice/test-routes.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - Test Routes API - - - -

Routes API Test

- - - - -
- - - - diff --git a/apps/edr-passenger-web/backoffice/test-stations-crud.js b/apps/edr-passenger-web/backoffice/test-stations-crud.js deleted file mode 100644 index 7964cc813..000000000 --- a/apps/edr-passenger-web/backoffice/test-stations-crud.js +++ /dev/null @@ -1,132 +0,0 @@ -// Test script for Stations CRUD operations -// Run this in the browser console on the backoffice app - -async function testStationsCRUD() { - const API_URL = 'http://localhost:4000'; - const token = localStorage.getItem('auth_token'); - - const headers = { - 'Content-Type': 'application/json', - 'Authorization': token ? `Bearer ${token}` : '' - }; - - console.log('🧪 Testing Stations CRUD Operations...\n'); - - try { - // 1. CREATE - Add a new station - console.log('1️⃣ Testing CREATE Station...'); - const newStation = { - code: 'TEST', - name: 'Test Station', - city: 'Test City', - countryCode: 'ET', - lat: '9.0320', - lng: '38.7469', - timezone: 'Africa/Addis_Ababa', - isOperational: true - }; - - const createResponse = await fetch(`${API_URL}/stations`, { - method: 'POST', - headers, - body: JSON.stringify(newStation) - }); - - if (!createResponse.ok) { - throw new Error(`CREATE failed: ${createResponse.status} ${await createResponse.text()}`); - } - - const createdStation = await createResponse.json(); - console.log('✅ Station created:', createdStation); - const stationId = createdStation.id || createdStation.data?.id; - - if (!stationId) { - throw new Error('No station ID returned from create'); - } - - // 2. READ - Get the created station - console.log('\n2️⃣ Testing READ Station...'); - const readResponse = await fetch(`${API_URL}/stations/${stationId}`, { - method: 'GET', - headers - }); - - if (!readResponse.ok) { - throw new Error(`READ failed: ${readResponse.status}`); - } - - const readStation = await readResponse.json(); - console.log('✅ Station retrieved:', readStation); - - // 3. UPDATE - Modify the station - console.log('\n3️⃣ Testing UPDATE Station...'); - const updateData = { - name: 'Test Station Updated', - city: 'Test City Updated', - isOperational: false - }; - - const updateResponse = await fetch(`${API_URL}/stations/${stationId}`, { - method: 'PATCH', - headers, - body: JSON.stringify(updateData) - }); - - if (!updateResponse.ok) { - throw new Error(`UPDATE failed: ${updateResponse.status} ${await updateResponse.text()}`); - } - - const updatedStation = await updateResponse.json(); - console.log('✅ Station updated:', updatedStation); - - // 4. LIST - Get all stations - console.log('\n4️⃣ Testing LIST Stations...'); - const listResponse = await fetch(`${API_URL}/stations`, { - method: 'GET', - headers - }); - - if (!listResponse.ok) { - throw new Error(`LIST failed: ${listResponse.status}`); - } - - const stations = await listResponse.json(); - console.log('✅ Stations list retrieved:', stations); - - // 5. DELETE - Remove the test station - console.log('\n5️⃣ Testing DELETE Station...'); - const deleteResponse = await fetch(`${API_URL}/stations/${stationId}`, { - method: 'DELETE', - headers - }); - - if (!deleteResponse.ok) { - throw new Error(`DELETE failed: ${deleteResponse.status} ${await deleteResponse.text()}`); - } - - console.log('✅ Station deleted successfully'); - - // 6. Verify deletion - console.log('\n6️⃣ Verifying deletion...'); - const verifyResponse = await fetch(`${API_URL}/stations/${stationId}`, { - method: 'GET', - headers - }); - - if (verifyResponse.status === 404) { - console.log('✅ Station deletion verified (404 Not Found)'); - } else { - console.warn('⚠️ Station might still exist'); - } - - console.log('\n🎉 All tests passed!'); - return { success: true, message: 'All CRUD operations working correctly' }; - - } catch (error) { - console.error('❌ Test failed:', error); - return { success: false, error: error.message }; - } -} - -// Run the test -testStationsCRUD(); 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 fca170a2c..c56ccd304 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 @@ -37,7 +37,6 @@ export default function ConfirmationPage() { try { return await apiClient.get(`/bookings/${bookingId}`); } catch (error) { - console.log('Booking API not available, using local data'); return { id: bookingId || '', pnr: pnr || undefined, @@ -57,13 +56,9 @@ export default function ConfirmationPage() { // For other payment methods, ticket is generated by the payment webhook after payment completes apiClient.get(`/bookings/${bookingId}`).then((data: any) => { if (data?.status === 'CONFIRMED') { - apiClient.post(`/tickets/generate/${bookingId}`).catch((err) => { - console.error('Failed to generate ticket:', err); - }); + apiClient.post(`/tickets/generate/${bookingId}`).catch(() => {}); } - }).catch((err) => { - console.error('Failed to fetch booking status:', err); - }); + }).catch(() => {}); } }, [bookingId]); @@ -142,7 +137,6 @@ export default function ConfirmationPage() { if (i < passengers.length - 1) await new Promise(r => setTimeout(r, 400)); } } catch (error) { - console.error('❌ Failed to generate voucher:', error); alert(`Failed to generate voucher: ${error instanceof Error ? error.message : 'Unknown error'}`); } finally { setIsGeneratingVoucher(false); 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 f01ab89c6..5087b7e4d 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 @@ -34,9 +34,7 @@ function BookingDetailContent() { queryKey: ['booking-detail', bookingRef], queryFn: async () => { if (!bookingRef) throw new Error('No booking reference provided'); - console.log('🔍 Fetching Booking:', bookingRef); const response = await apiClient.get(`/bookings/${bookingRef}`); - console.log('✅ Booking Response:', response); // Handle wrapped response return (response as any)?.data || response; }, @@ -56,7 +54,6 @@ function BookingDetailContent() { return response; }, onSuccess: async (data: any) => { - console.log('Payment intent created:', data); await apiClient.patch(`/bookings/${booking?.id}/confirm`, { paymentIntentId: data.id, paymentMethod: selectedPaymentMethod, @@ -64,7 +61,6 @@ function BookingDetailContent() { refetch(); }, onError: (error: any) => { - console.error('Payment failed:', error); alert(error?.response?.data?.message || 'Payment failed. Please try again.'); }, }); @@ -99,11 +95,9 @@ function BookingDetailContent() { setIsGeneratingVoucher(true); try { - console.log('📄 Generating voucher for booking:', booking); const { generateVoucherPDF } = await import('@/lib/generate-voucher'); await generateVoucherPDF(booking as any); } catch (error) { - console.error('Failed to generate voucher:', error); alert(`Failed to generate voucher: ${error instanceof Error ? error.message : 'Unknown error'}`); } finally { setIsGeneratingVoucher(false); @@ -148,11 +142,6 @@ function BookingDetailContent() { const isExpired = booking.status === 'EXPIRED'; const isCancelled = booking.status === 'CANCELLED'; - console.log('📊 Booking Status:', booking.status); - console.log('📊 isPendingPayment:', isPendingPayment); - console.log('📊 isConfirmed:', isConfirmed); - console.log('📊 isExpired:', isExpired); - console.log('📊 isCancelled:', isCancelled); const StatusBadge = () => { const statusConfig = { diff --git a/apps/edr-passenger-web/portal/src/app/booking/passengers/page.tsx b/apps/edr-passenger-web/portal/src/app/booking/passengers/page.tsx index d5857ac98..4263108d1 100644 --- a/apps/edr-passenger-web/portal/src/app/booking/passengers/page.tsx +++ b/apps/edr-passenger-web/portal/src/app/booking/passengers/page.tsx @@ -736,7 +736,6 @@ export default function PassengersPage() { // Remove code/state from the URL so a refresh doesn't re-trigger router.replace('/booking/passengers'); } catch (error) { - console.error('Failed to complete Fayda verification:', error); setVerificationStatus((prev) => ({ ...prev, [targetIndex]: 'error' })); setFaydaErrors((prev) => ({ ...prev, [targetIndex]: 'Fayda verification failed. Please try again or enter details manually.' })); } finally { @@ -768,7 +767,6 @@ export default function PassengersPage() { try { // Fetch passenger profile from backend const passengerData: any = await apiClient.get(`/passengers/me`); - console.log('Fetched passenger data:', passengerData); if (!passengerData) { setFormInitialized(true); @@ -776,7 +774,6 @@ export default function PassengersPage() { } // Only populate first passenger - console.log('Setting passenger 0 values'); setValue('passengers.0.name', passengerData?.fullName || user.fullName || ''); setValue('passengers.0.dateOfBirth', passengerData?.dateOfBirth || user.dateOfBirth || ''); if (passengerData?.gender || user.gender) setValue('passengers.0.gender', (passengerData?.gender || user.gender) as any); @@ -793,7 +790,6 @@ export default function PassengersPage() { setFormInitialized(true); } catch (error) { - console.error('Failed to fetch passenger data:', error); setFormInitialized(true); } }; @@ -879,7 +875,6 @@ export default function PassengersPage() { setFaydaErrors((prev) => ({ ...prev, [index]: 'Fayda verification was not completed. Please try again or enter details manually.' })); } } catch (error) { - console.error('Failed to get verification status:', error); setVerificationStatus((prev) => ({ ...prev, [index]: 'error' })); setFaydaErrors((prev) => ({ ...prev, [index]: 'Failed to confirm verification status. Please try again or enter details manually.' })); } finally { @@ -889,7 +884,6 @@ export default function PassengersPage() { } }, 1000); } catch (error) { - console.error('Failed to start Fayda verification:', error); setVerificationStatus((prev) => ({ ...prev, [index]: 'error' })); setFaydaErrors((prev) => ({ ...prev, [index]: 'Failed to start verification. Please try again.' })); setVerifyingIndex(null); @@ -918,9 +912,7 @@ export default function PassengersPage() { try { const passengerProfile: any = await apiClient.get('/passengers/me'); passengerId = passengerProfile?.id || ''; - console.log('Fetched passengerId:', passengerId); } catch (error) { - console.error('Failed to fetch passenger profile:', error); } } @@ -958,12 +950,10 @@ export default function PassengersPage() { if (isAuthenticated && passengerId) { const { setPassengerId } = useBookingStore.getState(); setPassengerId(passengerId); - console.log('Saved passengerId to booking store:', passengerId); } router.push('/booking/seats'); } catch (error) { - console.error('Failed to save passenger details:', error); alert('Failed to save passenger details. Please try again.'); } finally { setSaving(false); 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 ecba48945..5413af78c 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 @@ -59,9 +59,7 @@ export default function PaymentPage() { queryKey: ['bookingAmount', bookingId, amountCurrency, selectedMethod], queryFn: async () => { const url = `/payments/booking-amount?bookingId=${bookingId}¤cy=${amountCurrency}`; - console.log('[BookingAmount] Request:', { url, bookingId, currency: amountCurrency, selectedMethod }); const response: any = await apiClient.get(url); - console.log('[BookingAmount] Response:', response); return response; }, enabled: !!selectedMethod && !!bookingId, @@ -115,7 +113,6 @@ export default function PaymentPage() { router.push("/booking/confirmation"); }, onError: (error: any) => { - console.error("Payment failed:", error); updateStatus("FAILED"); setPaymentError( error?.response?.data?.message || @@ -160,10 +157,6 @@ export default function PaymentPage() { // Add a small delay to allow state to be set from previous page const timer = setTimeout(() => { if (!bookingId || !pnr) { - console.log( - "Payment page: Missing booking data, redirecting to search", - ); - console.log("bookingId:", bookingId, "pnr:", pnr); router.push("/booking/search"); } }, 500); diff --git a/apps/edr-passenger-web/portal/src/app/booking/results/page.tsx b/apps/edr-passenger-web/portal/src/app/booking/results/page.tsx index 70ada8f7c..6a54fe010 100644 --- a/apps/edr-passenger-web/portal/src/app/booking/results/page.tsx +++ b/apps/edr-passenger-web/portal/src/app/booking/results/page.tsx @@ -107,11 +107,9 @@ export default function ResultsPage() { payload.returnDate = searchData.returnDate; } - console.log('🚂 Search Request:', JSON.stringify(payload, null, 2)); const response = await apiClient.post('/search', payload) as any; - console.log('✅ Search Response:', JSON.stringify(response, null, 2)); return response; }, 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 241e6fea9..4dcf82bd9 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 @@ -15,13 +15,11 @@ import { isChild, isFirstChild, formatFare } from '@/utils/fare-utils'; function getPassengerIdFromToken(token: string): string | null { try { if (!token) { - console.warn('No token provided'); return null; } const parts = token.split('.'); if (parts.length !== 3) { - console.warn('Invalid token format - expected 3 parts, got', parts.length); return null; } @@ -33,21 +31,16 @@ function getPassengerIdFromToken(token: string): string | null { try { decoded = JSON.parse(atob(padded)); } catch (e) { - console.error('Failed to parse base64:', e); return null; } - console.log('Decoded JWT payload keys:', Object.keys(decoded)); - console.log('passengerId from JWT:', decoded.passengerId); if (!decoded.passengerId) { - console.warn('No passengerId in JWT payload, available keys:', Object.keys(decoded)); return null; } return decoded.passengerId; } catch (error) { - console.error('Error in getPassengerIdFromToken:', error); return null; } } @@ -149,7 +142,6 @@ export default function ReviewPage() { setSeatDetails(details); } catch (error) { - console.error('Failed to fetch seat details:', error); } }; @@ -159,9 +151,6 @@ export default function ReviewPage() { const createBookingMutation = useMutation({ mutationFn: (data: any) => { const endpoint = isAuthenticated ? '/bookings' : '/bookings/guest'; - console.log('=== API REQUEST ==='); - console.log('Endpoint:', endpoint); - console.log('Request Data:', JSON.stringify(data, null, 2)); return apiClient.post(endpoint, data); }, onSuccess: (data: any) => { @@ -201,7 +190,6 @@ export default function ReviewPage() { } if (!searchCriteria?.originStationId || !searchCriteria?.destinationStationId) { - console.error('Missing search criteria'); alert('Missing search criteria. Please start over.'); router.push('/booking/search'); return; @@ -225,10 +213,8 @@ export default function ReviewPage() { seatClassId = outboundClassName ? findByName(outboundClassName) : seatClasses[0].id; returnSeatClassId = returnClassName ? findByName(returnClassName) : seatClasses[0].id; - console.log('Seat class lookup:', { outboundClassName, returnClassName, seatClassId, returnSeatClassId }); } } catch (err) { - console.error('Failed to fetch seat classes:', err); } if (!seatClassId) { @@ -242,11 +228,9 @@ export default function ReviewPage() { const token = typeof window !== 'undefined' ? localStorage.getItem('auth_token') : null; if (!token) { - console.error('No token in localStorage'); throw new Error('Authentication token not found. Please log in again.'); } - console.log('Token found, length:', token.length); let passengerId = getPassengerIdFromToken(token); @@ -274,7 +258,6 @@ export default function ReviewPage() { const me: any = await apiClient.get('/passengers/me'); passengerId = me?.id || me?.passengerId || ''; } catch (err) { - console.error('Failed to resolve passengerId from /passengers/me:', err); } } @@ -379,11 +362,8 @@ export default function ReviewPage() { localStorage.setItem('deviceId', bookingData.deviceId); } - console.log('Creating booking with payload:', JSON.stringify(bookingData, null, 2)); - console.log('API endpoint:', isAuthenticated ? '/bookings' : '/bookings/guest'); await createBookingMutation.mutateAsync(bookingData); } catch (error) { - console.error('Error in handleConfirm:', error); alert(error instanceof Error ? error.message : 'An unexpected error occurred. Please try again.'); } }; @@ -392,29 +372,18 @@ export default function ReviewPage() { if (isRoundTrip) { if (!outboundSchedule || !inboundSchedule || !passengers.length) { if (!createBookingMutation.isPending && !createBookingMutation.isSuccess) { - console.log('Redirecting to search - missing round trip data'); router.push('/booking/search'); } } } else { if (!selectedSchedule || !passengers.length) { if (!createBookingMutation.isPending && !createBookingMutation.isSuccess) { - console.log('Redirecting to search - missing data'); router.push('/booking/search'); } } } }, [isRoundTrip, selectedSchedule, outboundSchedule, inboundSchedule, passengers.length, createBookingMutation.isPending, createBookingMutation.isSuccess, router]); - if (isRoundTrip && (!outboundSchedule || !inboundSchedule || !passengers.length)) { - return null; - } - - if (!isRoundTrip && (!selectedSchedule || !passengers.length)) { - return null; - } - - const fetchFareBreakdown = useCallback(async (scheduleId: string, originStationId: string, destinationStationId: string) => { try { const seatClasses: any[] = await apiClient.get('/seat-classes'); @@ -445,7 +414,6 @@ export default function ReviewPage() { const result: any = await apiClient.get(`/search/fare-breakdown?${params}`); setFareBreakdown(result); } catch (err) { - console.error('Failed to fetch fare breakdown:', err); } }, [passengers, selectedSchedule, outboundSchedule, isRoundTrip, searchCriteria, displayCurrency]); @@ -456,6 +424,14 @@ 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 total = packageTierPriceMinor ?? fareBreakdown?.totalMinor ?? 0; // Shared fare sidebar — rendered in right column (desktop) and inline (mobile) 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 5c717bd39..537e20623 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 @@ -173,21 +173,11 @@ export default function SeatsPage() { queryKey: ["seatmap", currentSchedule?.id, coachTypeId, currentJourneyType], queryFn: async () => { const endpoint = `/seats/seatmap/${currentSchedule?.id}?coachTypeId=${coachTypeId}&journeyDirection=${journeyDirection}`; - console.log("🪑 Seatmap Request:", { - endpoint, - }); const response = await apiClient.get(endpoint); - console.log("✅ Seatmap Response:", { - endpoint, - fullResponse: response, - dataCoaches: (response as any)?.data?.coaches?.length || 0, - rootCoaches: (response as any)?.coaches?.length || 0, - }); const finalData = (response as any)?.data || response; - console.log("🎯 Final data structure:", finalData); return finalData; }, enabled: !!currentSchedule?.id && !!coachTypeId, @@ -210,7 +200,6 @@ export default function SeatsPage() { const originId = (scheduleForHold as any)?.originStationId || searchCriteria?.originStationId; const destinationId = (scheduleForHold as any)?.destinationStationId || searchCriteria?.destinationStationId; - console.log('🎫 Hold request:', { scheduleId: currentSchedule?.id, originId, destinationId, isInbound }); return apiClient.post(`/seats/hold`, { scheduleId: currentSchedule?.id, originStationId: originId, @@ -258,29 +247,10 @@ export default function SeatsPage() { (seatMapData as any)?.coaches || (seatMapData as any)?.data?.coaches || []; - console.log("📦 Raw coaches data:", { - fromRoot: (seatMapData as any)?.coaches?.length || 0, - fromData: (seatMapData as any)?.data?.coaches?.length || 0, - using: rawCoaches.length, - hasRooms: rawCoaches.some((c: any) => c.rooms?.length > 0), - sampleRooms: rawCoaches[0]?.rooms?.length || 0, - }); return rawCoaches; }, [seatMapData]); const filteredCoaches = useMemo(() => { - console.log("🔍 Filtering coaches:", { - totalCoaches: coaches.length, - selectedSeatClass: currentSchedule?.selectedSeatClass, - coachesData: coaches.map((c: any) => ({ - id: c.id, - name: c.name, - label: c.label, - seatClass: c.seatClass, - seatClasses: c.seatClasses, - seatsCount: c.seats?.length || 0, - })), - }); const coachesWithSeats = coaches.filter((c: any) => { // Bed coaches store occupants in rooms.beds, not seats @@ -288,12 +258,8 @@ export default function SeatsPage() { return c.seats && c.seats.length > 0; }); - console.log( - "✅ Returning all coaches with seats/beds:", - coachesWithSeats.length, - ); return coachesWithSeats; - }, [coaches, currentSchedule?.selectedSeatClass]); + }, [coaches]); const selectedCoachData = useMemo( diff --git a/apps/edr-passenger-web/portal/src/types/index.ts b/apps/edr-passenger-web/portal/src/types/index.ts index 1e073dcc0..d1a906cbb 100644 --- a/apps/edr-passenger-web/portal/src/types/index.ts +++ b/apps/edr-passenger-web/portal/src/types/index.ts @@ -28,6 +28,8 @@ export interface Schedule { }; originStation?: Station; // For backward compatibility destinationStation?: Station; // For backward compatibility + originStationId?: string; // For backward compatibility + destinationStationId?: string; // For backward compatibility departureAt?: string; // API returns this arrivalAt?: string; // API returns this departureTime?: string; // For backward compatibility