From 68c4f69cff6861e761847fd214e05b64c0969b10 Mon Sep 17 00:00:00 2001 From: Stephanos A Date: Fri, 10 Jul 2026 20:20:39 +0300 Subject: [PATCH 1/2] Help content updates --- .../portal/src/app/help/page.tsx | 56 +------------------ .../portal/src/components/ThemeToggle.tsx | 24 ++------ 2 files changed, 7 insertions(+), 73 deletions(-) diff --git a/apps/edr-passenger-web/portal/src/app/help/page.tsx b/apps/edr-passenger-web/portal/src/app/help/page.tsx index eb8a6a150..c3f84ed91 100644 --- a/apps/edr-passenger-web/portal/src/app/help/page.tsx +++ b/apps/edr-passenger-web/portal/src/app/help/page.tsx @@ -60,16 +60,6 @@ const FAQ_CATEGORIES: FAQCategory[] = [ answer: 'Yes. When booking as a logged-in user you can save passenger profiles. On subsequent bookings you can select a saved passenger instead of re-entering their details.', }, - { - question: 'How do I modify my booking?', - answer: - 'Log in and go to your profile, find the booking, and select Modify. Changes are allowed up to 24 hours before departure. Fare differences may apply.', - }, - { - question: 'What is the cancellation policy?', - answer: - 'Cancellations made at least 48 hours before departure receive a full refund. Cancellations within 48 hours may be subject to a fee. Refunds are returned to your original payment method or wallet.', - }, ], }, { @@ -84,28 +74,13 @@ const FAQ_CATEGORIES: FAQCategory[] = [ { question: 'What are the passenger age categories?', answer: - 'Adults are passengers aged 5 years and above and pay 100% of the fare. Children are passengers under 5 years old — the first child in a booking travels free, and any additional children pay the full fare.', + 'Adults are passengers aged 5 years and above and pay 100% of the fare. Children are passengers under 5 years old — the first child per adult travels free, and any additional children pay the full fare.', }, { question: 'How is a child\'s age determined?', answer: 'Age is calculated automatically from the date of birth you enter for each passenger. Make sure to enter the correct date of birth so the right fare is applied.', }, - { - question: 'Example: how much does a family of 2 adults + 3 children pay?', - answer: - 'The first child is free, so you pay for 2 adults + 2 children = 4× the base fare for that seat class and distance.', - }, - { - question: 'What seat classes are available?', - answer: - 'Three classes are available: Economy Regular (standard seating), Economy Bed (sleeping berth in economy), and VIP Bed (premium sleeping berth). Each has its own base fare.', - }, - { - question: 'What is the nationality field for?', - answer: - 'Nationality determines which ID verification path applies. Ethiopian nationals are verified via the Verifayda national ID system. Djiboutian and other international passengers use their passport instead.', - }, ], }, { @@ -153,11 +128,6 @@ const FAQ_CATEGORIES: FAQCategory[] = [ answer: 'On the search page, tap the From or To field and browse or search the full list of stations. Each station shows its code and country.', }, - { - question: 'Are prices shown in my local currency?', - answer: - 'All transactions are processed in Ethiopian Birr (ETB). You can view prices in ETB, Djiboutian Franc (DJF), or US Dollar (USD) by selecting your preferred display currency on the fare or booking screen.', - }, ], }, { @@ -167,22 +137,12 @@ const FAQ_CATEGORIES: FAQCategory[] = [ { question: 'What payment methods are accepted?', answer: - 'We accept Telebirr, CBE Birr, eBirr, credit/debit cards, and EDR Wallet balance. You can choose your preferred method at checkout.', - }, - { - question: 'What is the EDR Wallet?', - answer: - 'The EDR Wallet is a stored-value account linked to your profile. You can top it up and use it to pay for tickets instantly. Your wallet balance and transaction history are available in your profile.', - }, - { - question: 'When will I receive my refund?', - answer: - 'Refunds are processed within 5–7 business days to your original payment method. If you paid via EDR Wallet, the refund is credited to your wallet immediately.', + 'We accept Telebirr, Waafi, D-Money, CBE Birr, and more. You can choose your preferred method at checkout.', }, { question: 'Is my payment information secure?', answer: - 'Yes. We do not store card details. All payments are processed through certified payment providers. Transactions are encrypted end-to-end.', + 'Yes. All payments are processed through certified payment providers. Transactions are encrypted end-to-end.', }, ], }, @@ -226,16 +186,6 @@ const FAQ_CATEGORIES: FAQCategory[] = [ answer: 'Tap "Forgot password" on the login page, enter your registered email, and follow the reset link sent to your inbox.', }, - { - question: 'How do I set up Verifayda on my account?', - answer: - 'Go to your profile and find the Fayda Setup section. Enter your national ID to link your verified identity to your account. This enables faster booking as your details are pre-filled.', - }, - { - question: 'Can I use the app in multiple languages?', - answer: - 'Yes. The app supports English, Amharic (አማርኛ), Afaan Oromoo, and French. Change your language from the navigation bar.', - }, ], }, ]; diff --git a/apps/edr-passenger-web/portal/src/components/ThemeToggle.tsx b/apps/edr-passenger-web/portal/src/components/ThemeToggle.tsx index 501c85005..5368876d2 100644 --- a/apps/edr-passenger-web/portal/src/components/ThemeToggle.tsx +++ b/apps/edr-passenger-web/portal/src/components/ThemeToggle.tsx @@ -1,6 +1,6 @@ 'use client'; -import { Moon, Sun, Monitor } from 'lucide-react'; +import { Moon, Sun } from 'lucide-react'; import { useTheme } from './ThemeProvider'; import { useEffect, useState } from 'react'; @@ -12,27 +12,11 @@ export default function ThemeToggle() { setMounted(true); }, []); - const cycleTheme = () => { - if (theme === 'light') { - setTheme('dark'); - } else if (theme === 'dark') { - setTheme('system'); - } else { - setTheme('light'); - } - }; + const cycleTheme = () => setTheme(theme === 'light' ? 'dark' : 'light'); - const getIcon = () => { - if (theme === 'light') return ; - if (theme === 'dark') return ; - return ; - }; + const getIcon = () => theme === 'dark' ? : ; - const getLabel = () => { - if (theme === 'light') return 'Light'; - if (theme === 'dark') return 'Dark'; - return 'System'; - }; + const getLabel = () => theme === 'dark' ? 'Dark' : 'Light'; // Prevent hydration mismatch by not rendering until mounted if (!mounted) { From 952d68be07ea25c738d498647aa67011ad01bb83 Mon Sep 17 00:00:00 2001 From: Abubeker Yasin Date: Fri, 10 Jul 2026 21:30:20 +0300 Subject: [PATCH 2/2] feat: ( fayda ) implement fayda for passengers --- .../src/app/booking/passengers/page.tsx | 301 ++++++++++++------ 1 file changed, 196 insertions(+), 105 deletions(-) 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 d389bd9cb..34cf1fe5d 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 @@ -72,6 +72,36 @@ function clearPendingFaydaIndex() { window.sessionStorage.removeItem(FAYDA_PENDING_INDEX_KEY); } +// Verification is a full-page redirect out to Fayda and back (same flow on desktop and mobile — +// no popup). The in-progress form only lives in React memory, which the reload wipes, so we +// snapshot it to sessionStorage before leaving and restore it (in the form's defaultValues) on +// return. sessionStorage survives a same-tab navigation, including the cross-origin round trip. +const FAYDA_FORM_SNAPSHOT_KEY = 'edr_fayda_form_snapshot'; + +function saveFaydaFormSnapshot(snapshot: unknown) { + if (typeof window === 'undefined') return; + try { + window.sessionStorage.setItem(FAYDA_FORM_SNAPSHOT_KEY, JSON.stringify(snapshot)); + } catch { + // sessionStorage full/unavailable — verification still works, only unsaved fields are lost. + } +} + +function getFaydaFormSnapshot(): { passengers?: any[]; createAccount?: boolean } | null { + if (typeof window === 'undefined') return null; + try { + const raw = window.sessionStorage.getItem(FAYDA_FORM_SNAPSHOT_KEY); + return raw ? JSON.parse(raw) : null; + } catch { + return null; + } +} + +function clearFaydaFormSnapshot() { + if (typeof window === 'undefined') return; + window.sessionStorage.removeItem(FAYDA_FORM_SNAPSHOT_KEY); +} + // Fayda may return gender as "MALE"/"M" etc — normalize to the form's expected values function normalizeFaydaGender(raw: unknown): 'Male' | 'Female' | '' { const g = String(raw || '').trim().toUpperCase(); @@ -85,11 +115,13 @@ function DobPickerModal({ onChange, error, passengerType = 'ADULT', + disabled = false, }: { value: string; onChange: (iso: string) => void; error?: string; passengerType?: 'ADULT' | 'CHILD'; + disabled?: boolean; }) { const [open, setOpen] = useState(false); const [manualMode, setManualMode] = useState(false); @@ -286,9 +318,10 @@ function DobPickerModal({