mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 00:52:50 +00:00
Passenger portal build issue resolution
This commit is contained in:
@@ -1,10 +1,9 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
output: 'export',
|
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
transpilePackages: ['@edr/types', '@edr/ui-common'],
|
transpilePackages: ['@edr/types', '@edr/ui-common'],
|
||||||
images: {
|
images: {
|
||||||
unoptimized: true, // Required for static export
|
unoptimized: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { useRouter } from 'next/navigation';
|
|||||||
import { useBookingStore } from '@/lib/booking-store';
|
import { useBookingStore } from '@/lib/booking-store';
|
||||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||||
import { apiClient } from '@/lib/api-client';
|
import { apiClient } from '@/lib/api-client';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState, useRef } from 'react';
|
||||||
import { CheckCircle, Download, Share2, Copy, Printer, Mail, Train } from 'lucide-react';
|
import { CheckCircle, Download, Share2, Copy, Printer, Mail, Train } from 'lucide-react';
|
||||||
import { QRCodeSVG } from 'qrcode.react';
|
import { QRCodeSVG } from 'qrcode.react';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
@@ -15,6 +15,7 @@ export default function ConfirmationPage() {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { bookingId, pnr, selectedSchedule, passengers, clearBooking } = useBookingStore();
|
const { bookingId, pnr, selectedSchedule, passengers, clearBooking } = useBookingStore();
|
||||||
const [copied, setCopied] = useState(false);
|
const [copied, setCopied] = useState(false);
|
||||||
|
const confirmAttempted = useRef(false);
|
||||||
|
|
||||||
const confirmMutation = useMutation({
|
const confirmMutation = useMutation({
|
||||||
mutationFn: () => apiClient.patch(`/bookings/${bookingId}/confirm`, { status: 'SUCCEEDED' }),
|
mutationFn: () => apiClient.patch(`/bookings/${bookingId}/confirm`, { status: 'SUCCEEDED' }),
|
||||||
@@ -27,7 +28,6 @@ export default function ConfirmationPage() {
|
|||||||
return await apiClient.get(`/bookings/${bookingId}`);
|
return await apiClient.get(`/bookings/${bookingId}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('Booking API not available, using local data');
|
console.log('Booking API not available, using local data');
|
||||||
// Return mock booking data
|
|
||||||
return {
|
return {
|
||||||
id: bookingId,
|
id: bookingId,
|
||||||
pnr,
|
pnr,
|
||||||
@@ -40,10 +40,11 @@ export default function ConfirmationPage() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (bookingId && !confirmMutation.isSuccess && !confirmMutation.isPending) {
|
if (bookingId && !confirmAttempted.current) {
|
||||||
|
confirmAttempted.current = true;
|
||||||
confirmMutation.mutate();
|
confirmMutation.mutate();
|
||||||
}
|
}
|
||||||
}, [bookingId]);
|
}, [bookingId, confirmMutation]);
|
||||||
|
|
||||||
const copyPNR = () => {
|
const copyPNR = () => {
|
||||||
if (pnr) {
|
if (pnr) {
|
||||||
@@ -54,7 +55,6 @@ export default function ConfirmationPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDownloadTickets = () => {
|
const handleDownloadTickets = () => {
|
||||||
// Mock download - in production this would call the API
|
|
||||||
alert('Ticket download will be available soon. Your tickets are displayed below.');
|
alert('Ticket download will be available soon. Your tickets are displayed below.');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
// This is the updated onSubmit function for passengers/page.tsx
|
|
||||||
// Replace the existing onSubmit function with this one
|
|
||||||
|
|
||||||
const onSubmit = async (data: FormData) => {
|
|
||||||
setSaving(true);
|
|
||||||
try {
|
|
||||||
let passengerId = '';
|
|
||||||
|
|
||||||
console.log('[Passengers] onSubmit called, isAuthenticated:', isAuthenticated, 'user:', user);
|
|
||||||
|
|
||||||
// For authenticated users, fetch the passenger profile to get the passengerId
|
|
||||||
if (isAuthenticated && user?.id) {
|
|
||||||
try {
|
|
||||||
console.log('[Passengers] Fetching passenger profile from /passengers/me');
|
|
||||||
const passengerProfile: any = await apiClient.get('/passengers/me');
|
|
||||||
console.log('[Passengers] Passenger profile response:', passengerProfile);
|
|
||||||
passengerId = passengerProfile?.id || '';
|
|
||||||
console.log('[Passengers] Extracted passengerId:', passengerId);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('[Passengers] Failed to fetch passenger profile:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('[Passengers] passengerId before saving:', passengerId);
|
|
||||||
|
|
||||||
const passengerDetails = data.passengers.map((p, i) => ({
|
|
||||||
name: p.name,
|
|
||||||
dateOfBirth: p.dateOfBirth,
|
|
||||||
gender: p.gender,
|
|
||||||
nationality: p.nationality,
|
|
||||||
nationalId: p.nationalId,
|
|
||||||
passportNumber: p.passportNumber,
|
|
||||||
passportCountry: p.passportCountry,
|
|
||||||
phone: p.phone,
|
|
||||||
email: p.email,
|
|
||||||
isPrimaryPassenger: i === 0,
|
|
||||||
passengerId: i === 0 && passengerId ? passengerId : undefined,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const deviceId = typeof window !== 'undefined'
|
|
||||||
? (localStorage.getItem('deviceId') || crypto.randomUUID())
|
|
||||||
: crypto.randomUUID();
|
|
||||||
|
|
||||||
await apiClient.post('/passengers/save-details', {
|
|
||||||
passengers: passengerDetails,
|
|
||||||
userId: user?.id,
|
|
||||||
deviceId,
|
|
||||||
});
|
|
||||||
|
|
||||||
setPassengers(passengerDetails);
|
|
||||||
setCreateAccount(data.createAccount);
|
|
||||||
|
|
||||||
// Save passengerId to booking store for later use
|
|
||||||
if (isAuthenticated && passengerId) {
|
|
||||||
const { setPassengerId } = useBookingStore.getState();
|
|
||||||
setPassengerId(passengerId);
|
|
||||||
console.log('[Passengers] Saved passengerId to booking store:', passengerId);
|
|
||||||
} else {
|
|
||||||
console.warn('[Passengers] Not saving passengerId - isAuthenticated:', isAuthenticated, 'passengerId:', passengerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store in localStorage as additional backup
|
|
||||||
if (typeof window !== 'undefined' && passengerId) {
|
|
||||||
localStorage.setItem('booking_passengerId', passengerId);
|
|
||||||
console.log('[Passengers] Stored passengerId in localStorage:', 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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
const onSubmit = async (data: FormData) => {
|
|
||||||
setSaving(true);
|
|
||||||
try {
|
|
||||||
let passengerId = '';
|
|
||||||
|
|
||||||
// For authenticated users, fetch the passenger profile to get the passengerId
|
|
||||||
if (isAuthenticated && user?.id) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const passengerDetails = data.passengers.map((p, i) => ({
|
|
||||||
name: p.name,
|
|
||||||
dateOfBirth: p.dateOfBirth,
|
|
||||||
gender: p.gender,
|
|
||||||
nationality: p.nationality,
|
|
||||||
nationalId: p.nationalId,
|
|
||||||
passportNumber: p.passportNumber,
|
|
||||||
passportCountry: p.passportCountry,
|
|
||||||
phone: p.phone,
|
|
||||||
email: p.email,
|
|
||||||
isPrimaryPassenger: i === 0,
|
|
||||||
passengerId: i === 0 && passengerId ? passengerId : undefined,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const deviceId = typeof window !== 'undefined'
|
|
||||||
? (localStorage.getItem('deviceId') || crypto.randomUUID())
|
|
||||||
: crypto.randomUUID();
|
|
||||||
|
|
||||||
await apiClient.post('/passengers/save-details', {
|
|
||||||
passengers: passengerDetails,
|
|
||||||
userId: user?.id,
|
|
||||||
deviceId,
|
|
||||||
});
|
|
||||||
|
|
||||||
setPassengers(passengerDetails);
|
|
||||||
setCreateAccount(data.createAccount);
|
|
||||||
|
|
||||||
// Save passengerId to booking store for later use
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
const onSubmit = async (data: FormData) => {
|
|
||||||
setSaving(true);
|
|
||||||
try {
|
|
||||||
const passengerDetails = data.passengers.map((p, i) => ({\n name: p.name,\n dateOfBirth: p.dateOfBirth,\n gender: p.gender,\n nationality: p.nationality,\n nationalId: p.nationalId,\n passportNumber: p.passportNumber,\n passportCountry: p.passportCountry,\n phone: p.phone,\n email: p.email,\n isPrimaryPassenger: i === 0,\n passengerId: i === 0 && isAuthenticated ? user?.passenger?.id : undefined,\n }));\n\n const deviceId = typeof window !== 'undefined'\n ? (localStorage.getItem('deviceId') || crypto.randomUUID())\n : crypto.randomUUID();\n\n await apiClient.post('/passengers/save-details', {\n passengers: passengerDetails,\n userId: user?.id,\n deviceId,\n });\n\n setPassengers(passengerDetails);\n setCreateAccount(data.createAccount);\n \n // Save passengerId from authenticated user to booking store\n if (isAuthenticated && user?.passenger?.id) {\n const { setPassengerId } = useBookingStore.getState();\n setPassengerId(user.passenger.id);\n }\n \n router.push('/booking/seats');\n } catch (error) {\n console.error('Failed to save passenger details:', error);\n alert('Failed to save passenger details. Please try again.');\n } finally {\n setSaving(false);\n }\n };
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
export const dynamic = 'force-dynamic';
|
|
||||||
|
|
||||||
import { useForm, useFieldArray } from 'react-hook-form';
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
|
||||||
@@ -52,7 +52,6 @@ export default function PassengersPage() {
|
|||||||
const { user, isAuthenticated, updateUser } = useAuthStore();
|
const { user, isAuthenticated, updateUser } = useAuthStore();
|
||||||
const [faydaEnabled, setFaydaEnabled] = useState(true);
|
const [faydaEnabled, setFaydaEnabled] = useState(true);
|
||||||
const [verificationStatus, setVerificationStatus] = useState<Record<number, 'success' | 'error'>>({});
|
const [verificationStatus, setVerificationStatus] = useState<Record<number, 'success' | 'error'>>({});
|
||||||
const [updatingUser, setUpdatingUser] = useState(false);
|
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
const [formInitialized, setFormInitialized] = useState(false);
|
const [formInitialized, setFormInitialized] = useState(false);
|
||||||
const [nationalityMismatch, setNationalityMismatch] = useState(false);
|
const [nationalityMismatch, setNationalityMismatch] = useState(false);
|
||||||
@@ -309,7 +308,9 @@ export default function PassengersPage() {
|
|||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
clearBooking();
|
clearBooking();
|
||||||
window.location.href = '/booking/search';
|
if (typeof window !== 'undefined') {
|
||||||
|
window.location.href = '/booking/search';
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
className="btn-primary w-full flex items-center justify-center gap-2"
|
className="btn-primary w-full flex items-center justify-center gap-2"
|
||||||
>
|
>
|
||||||
@@ -378,14 +379,9 @@ export default function PassengersPage() {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={() => openFaydaVerification(index)}
|
onClick={() => openFaydaVerification(index)}
|
||||||
className="btn-primary flex items-center justify-center gap-2 mx-auto"
|
className="btn-primary flex items-center justify-center gap-2 mx-auto"
|
||||||
disabled={updatingUser}
|
|
||||||
>
|
>
|
||||||
{updatingUser ? (
|
<ExternalLink className="w-5 h-5" />
|
||||||
<Loader2 className="w-5 h-5 animate-spin" />
|
{isLoggedInNotVerified ? 'Verify with Fayda' : 'Verify with Fayda'}
|
||||||
) : (
|
|
||||||
<ExternalLink className="w-5 h-5" />
|
|
||||||
)}
|
|
||||||
{updatingUser ? 'Updating Profile...' : 'Verify with Fayda'}
|
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
// Save passengerId to booking store for later use
|
|
||||||
if (isAuthenticated && passengerId) {
|
|
||||||
const { setPassengerId } = useBookingStore.getState();
|
|
||||||
setPassengerId(passengerId);
|
|
||||||
console.log('Saved passengerId to booking store:', passengerId);
|
|
||||||
|
|
||||||
// Also save to localStorage as backup
|
|
||||||
if (typeof window !== 'undefined') {
|
|
||||||
localStorage.setItem('booking_passengerId', passengerId);
|
|
||||||
console.log('Saved passengerId to localStorage:', passengerId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
// Key changes needed in passengers/page.tsx onSubmit function:
|
|
||||||
|
|
||||||
const onSubmit = async (data: FormData) => {
|
|
||||||
setSaving(true);
|
|
||||||
try {
|
|
||||||
// Build passenger details - ALWAYS create new records, don't reuse
|
|
||||||
const passengerDetails = data.passengers.map((p, i) => ({
|
|
||||||
name: p.name,
|
|
||||||
dateOfBirth: p.dateOfBirth,
|
|
||||||
gender: p.gender,
|
|
||||||
nationality: p.nationality,
|
|
||||||
nationalId: p.nationalId,
|
|
||||||
passportNumber: p.passportNumber,
|
|
||||||
passportCountry: p.passportCountry,
|
|
||||||
phone: p.phone,
|
|
||||||
email: p.email,
|
|
||||||
isPrimaryPassenger: i === 0,
|
|
||||||
// IMPORTANT: Don't include passengerId here - it's only needed in booking creation
|
|
||||||
}));
|
|
||||||
|
|
||||||
const deviceId = typeof window !== 'undefined'
|
|
||||||
? (localStorage.getItem('deviceId') || crypto.randomUUID())
|
|
||||||
: crypto.randomUUID();
|
|
||||||
|
|
||||||
// Save passenger details (this is for UI reference, not booking creation)
|
|
||||||
await apiClient.post('/passengers/save-details', {
|
|
||||||
passengers: passengerDetails,
|
|
||||||
userId: user?.id,
|
|
||||||
deviceId,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Store in booking store for the next step (seats selection)
|
|
||||||
setPassengers(passengerDetails);
|
|
||||||
setCreateAccount(data.createAccount);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
// Key changes needed in review/page.tsx handleConfirm function:
|
|
||||||
|
|
||||||
const handleConfirm = async () => {
|
|
||||||
console.log('handleConfirm called');
|
|
||||||
try {
|
|
||||||
const { searchCriteria } = useBookingStore.getState();
|
|
||||||
|
|
||||||
// Validate required data
|
|
||||||
if (!seatHold?.holdId) {
|
|
||||||
alert('Please select seats before continuing.');
|
|
||||||
router.push('/booking/seats');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!searchCriteria?.originStationId || !searchCriteria?.destinationStationId) {
|
|
||||||
alert('Missing search criteria. Please start over.');
|
|
||||||
router.push('/booking/search');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get seat class
|
|
||||||
let seatClassId = 'default-seat-class-id';
|
|
||||||
try {
|
|
||||||
const seatClasses: any = await apiClient.get('/seat-classes');
|
|
||||||
if (seatClasses && seatClasses.length > 0) {
|
|
||||||
seatClassId = seatClasses[0].id;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Failed to fetch seat classes:', err);
|
|
||||||
}
|
|
||||||
|
|
||||||
let bookingData: any;
|
|
||||||
|
|
||||||
if (isAuthenticated) {
|
|
||||||
// For authenticated users: get passengerId from user profile
|
|
||||||
let passengerId = '';
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Fetch user's passenger profile
|
|
||||||
const passengerProfile: any = await apiClient.get('/passengers/me');
|
|
||||||
passengerId = passengerProfile?.id;
|
|
||||||
console.log('Got passengerId from profile:', passengerId);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to get passenger profile:', error);
|
|
||||||
throw new Error('Unable to retrieve your passenger profile. Please try again.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!passengerId) {
|
|
||||||
throw new Error('Passenger profile not found. Please update your profile and try again.');
|
|
||||||
}
|
|
||||||
|
|
||||||
bookingData = {
|
|
||||||
scheduleId: selectedSchedule?.id || '',
|
|
||||||
holdId: seatHold.holdId,
|
|
||||||
originStationId: searchCriteria.originStationId,
|
|
||||||
destinationStationId: searchCriteria.destinationStationId,
|
|
||||||
seatClassId: seatClassId,
|
|
||||||
displayCurrency: 'ETB',
|
|
||||||
passengerId: passengerId,
|
|
||||||
passengers: passengers.map((p) => {
|
|
||||||
const isEthiopian = p.nationality === 'ETHIOPIAN' || p.nationality === 'Ethiopian';
|
|
||||||
return {
|
|
||||||
seatId: p.seatId || '',
|
|
||||||
passengerName: p.name,
|
|
||||||
dateOfBirth: p.dateOfBirth,
|
|
||||||
idDocumentType: isEthiopian ? 'NATIONAL_ID' : 'PASSPORT',
|
|
||||||
idDocumentNumber: isEthiopian ? (p.nationalId || '') : '',
|
|
||||||
passportNumber: !isEthiopian ? (p.passportNumber || '') : '',
|
|
||||||
passportCountry: !isEthiopian ? (p.passportCountry || '') : '',
|
|
||||||
nationality: p.nationality,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
// For guests: send full passenger details
|
|
||||||
bookingData = {
|
|
||||||
scheduleId: selectedSchedule?.id || '',
|
|
||||||
holdId: seatHold.holdId,
|
|
||||||
originStationId: searchCriteria.originStationId,
|
|
||||||
destinationStationId: searchCriteria.destinationStationId,
|
|
||||||
seatClassId: seatClassId,
|
|
||||||
displayCurrency: 'ETB',
|
|
||||||
passengers: passengers.map(p => {
|
|
||||||
const isEthiopian = p.nationality === 'ETHIOPIAN' || p.nationality === 'Ethiopian';
|
|
||||||
return {
|
|
||||||
seatId: p.seatId || '',
|
|
||||||
passengerName: p.name,
|
|
||||||
dateOfBirth: p.dateOfBirth,
|
|
||||||
idDocumentType: isEthiopian ? 'NATIONAL_ID' : 'PASSPORT',
|
|
||||||
idDocumentNumber: isEthiopian ? (p.nationalId || '') : '',
|
|
||||||
passportNumber: !isEthiopian ? (p.passportNumber || '') : '',
|
|
||||||
passportCountry: !isEthiopian ? (p.passportCountry || '') : '',
|
|
||||||
nationality: p.nationality,
|
|
||||||
phone: p.phone || '',
|
|
||||||
email: p.email || '',
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
createAccount: createAccount || false,
|
|
||||||
savePassengerDetails: true,
|
|
||||||
deviceId: typeof window !== 'undefined' ? (localStorage.getItem('deviceId') || `device-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`) : undefined,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof window !== 'undefined' && !isAuthenticated && bookingData.deviceId && !localStorage.getItem('deviceId')) {
|
|
||||||
localStorage.setItem('deviceId', bookingData.deviceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Creating booking with payload:', bookingData);
|
|
||||||
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.');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -77,7 +77,7 @@ export default function SeatsPage() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const coaches = (seatMapData as any)?.coaches || [];
|
const coaches = useMemo(() => (seatMapData as any)?.coaches || [], [seatMapData]);
|
||||||
|
|
||||||
const filteredCoaches = useMemo(() => {
|
const filteredCoaches = useMemo(() => {
|
||||||
return selectedSchedule?.selectedSeatClass
|
return selectedSchedule?.selectedSeatClass
|
||||||
@@ -221,7 +221,7 @@ export default function SeatsPage() {
|
|||||||
) : seats.length === 0 ? (
|
) : seats.length === 0 ? (
|
||||||
<div className="text-center py-8 text-gray-500 dark:text-gray-400">
|
<div className="text-center py-8 text-gray-500 dark:text-gray-400">
|
||||||
<p>No seats available in this coach</p>
|
<p>No seats available in this coach</p>
|
||||||
<p className="text-sm mt-2">Please select a different coach</p>
|
<p className="text-sm mt-2\">Please select a different coach</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { zodResolver } from '@hookform/resolvers/zod';
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { useRouter, useSearchParams } from 'next/navigation';
|
import { useRouter, useSearchParams } from 'next/navigation';
|
||||||
import { useAuthStore } from '@/lib/auth-store';
|
import { useAuthStore } from '@/lib/auth-store';
|
||||||
import { useBookingStore } from '@/lib/booking-store';
|
|
||||||
import { useState, Suspense } from 'react';
|
import { useState, Suspense } from 'react';
|
||||||
import { Train } from 'lucide-react';
|
import { Train } from 'lucide-react';
|
||||||
|
|
||||||
@@ -20,7 +19,6 @@ function LoginContent() {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const login = useAuthStore((s) => s.login);
|
const login = useAuthStore((s) => s.login);
|
||||||
const { searchCriteria } = useBookingStore();
|
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { format, toZonedTime } from 'date-fns-tz';
|
import { format } from 'date-fns';
|
||||||
|
|
||||||
const ADDIS_TZ = 'Africa/Addis_Ababa';
|
|
||||||
|
|
||||||
export const formatCurrency = (amount: number, currency: string = 'ETB'): string => {
|
export const formatCurrency = (amount: number, currency: string = 'ETB'): string => {
|
||||||
return new Intl.NumberFormat('en-US', {
|
return new Intl.NumberFormat('en-US', {
|
||||||
@@ -11,16 +9,13 @@ export const formatCurrency = (amount: number, currency: string = 'ETB'): string
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const formatDate = (date: string | Date, formatStr: string = 'MMM dd, yyyy'): string => {
|
export const formatDate = (date: string | Date, formatStr: string = 'MMM dd, yyyy'): string => {
|
||||||
const zonedDate = toZonedTime(new Date(date), ADDIS_TZ);
|
return format(new Date(date), formatStr);
|
||||||
return format(zonedDate, formatStr, { timeZone: ADDIS_TZ });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const formatDateTime = (date: string | Date): string => {
|
export const formatDateTime = (date: string | Date): string => {
|
||||||
const zonedDate = toZonedTime(new Date(date), ADDIS_TZ);
|
return format(new Date(date), 'MMM dd, yyyy HH:mm');
|
||||||
return format(zonedDate, 'MMM dd, yyyy HH:mm', { timeZone: ADDIS_TZ });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const formatTime = (date: string | Date): string => {
|
export const formatTime = (date: string | Date): string => {
|
||||||
const zonedDate = toZonedTime(new Date(date), ADDIS_TZ);
|
return format(new Date(date), 'HH:mm');
|
||||||
return format(zonedDate, 'HH:mm', { timeZone: ADDIS_TZ });
|
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user