Files
edr-platform/apps/edr-passenger-web/portal/README.md
2026-06-02 20:48:14 +03:00

337 lines
9.2 KiB
Markdown

# EDR Passenger Portal
Modern Next.js 14 web application for the Ethio-Djibouti Railway passenger booking system.
## Features
### Complete Booking Flow
1. **Search** - Find trains by route, date, and passenger count
2. **Results** - View available schedules with pricing
3. **Auth Check** - Sign in or continue as guest
4. **Passengers** - Collect passenger details with Fayda verification
5. **Seats** - Select seats with visual seat map
6. **Review** - Confirm booking details and fare breakdown
7. **Payment** - Choose payment method and process payment
8. **Confirmation** - View PNR, tickets with QR codes
### Key Capabilities
- **Fayda 2.0 Integration** - Ethiopian national ID verification
- **Age-Based Pricing** - First child travels free
- **Multi-Currency Support** - ETB, DJF, USD display
- **Seat Hold System** - 2-hour seat reservation
- **Guest Booking** - Book without account, optional registration
- **QR Code Tickets** - Digital tickets with QR codes
- **Responsive Design** - Mobile-first, works on all devices
## Tech Stack
- **Framework:** Next.js 14 with App Router
- **Styling:** Tailwind CSS
- **State Management:**
- TanStack Query (React Query) for server state
- Zustand for client state (booking flow, auth, payment)
- **Forms:** React Hook Form with Zod validation
- **API Client:** Axios with interceptors
- **Date Handling:** date-fns
- **QR Codes:** qrcode.react
## Getting Started
### Prerequisites
- Node.js >= 20.x
- pnpm >= 9.x
- EDR Passenger API running on port 3002
### Installation
```bash
# Install dependencies
pnpm install
# Create environment file
cp .env.example .env.local
# Update .env.local with API URL
NEXT_PUBLIC_API_URL=http://localhost:3002
```
### Development
```bash
# Run development server
pnpm dev
# Access at http://localhost:5174
```
### Build
```bash
# Build for production
pnpm build
# Start production server
pnpm start
```
## Project Structure
```
src/
├── app/ # Next.js App Router pages
│ ├── booking/
│ │ ├── search/ # Search trains
│ │ ├── results/ # Search results
│ │ ├── auth-check/ # Login or guest
│ │ ├── passengers/ # Passenger details + Fayda
│ │ ├── seats/ # Seat selection
│ │ ├── review/ # Booking review
│ │ ├── payment/ # Payment processing
│ │ └── confirmation/ # Booking confirmation
│ ├── login/ # Login page
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Home (redirects to search)
│ ├── providers.tsx # React Query provider
│ └── globals.css # Global styles
├── components/ # Reusable components
├── lib/ # Core utilities
│ ├── api-client.ts # Axios client with interceptors
│ ├── auth-store.ts # Auth state (Zustand)
│ ├── booking-store.ts # Booking flow state (Zustand)
│ └── payment-store.ts # Payment state (Zustand)
├── types/ # TypeScript types
│ └── index.ts
└── hooks/ # Custom React hooks
```
## State Management
### Booking Store (Zustand)
Persists booking flow state across pages:
- Search criteria
- Selected schedule
- Passenger details
- Seat hold information
- Booking ID and PNR
- Payment method
### Auth Store (Zustand)
Manages user authentication:
- User profile
- JWT token
- Login/logout/register
- Persisted to localStorage
### Payment Store (Zustand)
Tracks payment flow:
- Payment intent ID
- Payment status
- Selected currency
## API Integration
### Endpoints Used
| Endpoint | Method | Purpose |
|----------|--------|---------|
| `/stations` | GET | Fetch all stations |
| `/search` | POST | Search available trains |
| `/passengers/verify-fayda` | POST | Verify Ethiopian national ID |
| `/seatmap/{scheduleId}` | GET | Get coaches and seats |
| `/seatmap/{scheduleId}/hold` | POST | Hold seats (2 hours) |
| `/bookings/create` | POST | Create booking + generate PNR |
| `/bookings/{id}/confirm` | PATCH | Confirm booking after payment |
| `/payments/intent` | POST | Create payment intent |
| `/auth/login` | POST | User login |
| `/auth/register` | POST | User registration |
## Booking Flow
### 1. Search
- User selects origin, destination, date, passengers
- Validates form with Zod schema
- Stores criteria in booking store
- Navigates to results
### 2. Results
- Fetches schedules from API
- Displays available trains with pricing
- User selects a schedule
- Stores selection and navigates to auth check
### 3. Auth Check
- Checks if user is authenticated
- Offers "Sign In" or "Continue as Guest"
- Authenticated users can use saved profiles
### 4. Passengers
- Collects details for each passenger
- **Ethiopian nationals:** Fayda verification
- Calls `/passengers/verify-fayda`
- Auto-fills name and DOB on success
- Allows manual entry on failure
- **Non-Ethiopians:** Passport details
- Optional account creation checkbox
- Stores passenger data in booking store
### 5. Seats
- Fetches coaches and seat map
- Visual seat selection (4-column grid)
- Color-coded seat status:
- Green: Available
- Blue: Selected
- Yellow: Held by others
- Gray: Booked/Blocked
- Calls `/seatmap/{scheduleId}/hold` on selection
- Stores hold ID and expiry (2 hours)
- Option to skip (auto-assign)
### 6. Review
- Displays trip summary
- Lists all passengers
- Shows fare breakdown
- Displays seat hold countdown timer
- Calls `/bookings/create` on confirm
- Generates 6-character PNR
- Navigates to payment
### 7. Payment
- Displays PNR prominently
- Payment method selection:
- Telebirr
- CBE Birr
- eBirr
- Card
- Wallet
- Shows order summary
- Calls `/payments/intent`
- Processes payment (simulated for now)
### 8. Confirmation
- Calls `/bookings/{id}/confirm`
- Displays success message
- Shows PNR with copy button
- Generates QR codes for each ticket
- Lists all passenger tickets
- Download and share options
- "Book Another Trip" button clears state
## Form Validation
All forms use React Hook Form + Zod:
```typescript
// Example: Search form validation
const searchSchema = z.object({
originStationId: z.string().min(1, 'Please select origin'),
destinationStationId: z.string().min(1, 'Please select destination'),
departureDate: z.string().min(1, 'Please select date'),
adultCount: z.number().min(1).max(9),
childCount: z.number().min(0).max(9),
nationality: z.enum(['ETHIOPIAN', 'DJIBOUTIAN', 'OTHER']),
}).refine((data) => data.originStationId !== data.destinationStationId, {
message: 'Origin and destination must be different',
path: ['destinationStationId'],
});
```
## Styling
### Tailwind Utility Classes
Custom component classes in `globals.css`:
```css
.btn-primary /* Primary action button */
.btn-secondary /* Secondary action button */
.input-field /* Form input styling */
.card /* Card container */
```
### Theme Colors
Primary brand color: `rgb(20, 113, 76)` (EDR green)
Shades available: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900
## Error Handling
- Network errors: Retry button with exponential backoff
- Validation errors: Inline field-level messages
- API errors: User-friendly error messages
- Seat hold expiry: Alert and re-selection option
- 401 Unauthorized: Auto-redirect to login
## Accessibility
- Semantic HTML elements
- ARIA labels on interactive elements
- Keyboard navigation support
- Color contrast WCAG AA compliant
- Screen reader announcements for validation errors
## Mobile Responsiveness
- Mobile-first design approach
- Responsive grid layouts (md: breakpoint)
- Touch-friendly button sizes
- Scrollable seat maps on small screens
- Optimized forms for mobile input
## Testing Checklist
- [ ] Search form validation
- [ ] Results display and selection
- [ ] Guest vs authenticated flow
- [ ] Fayda verification (Ethiopian)
- [ ] Passport form (non-Ethiopian)
- [ ] Seat selection and hold
- [ ] Hold countdown timer
- [ ] PNR generation
- [ ] Payment method selection
- [ ] Confirmation with QR codes
- [ ] Mobile responsiveness
- [ ] Error states
- [ ] Back navigation
## Environment Variables
```bash
NEXT_PUBLIC_API_URL=http://localhost:3002 # Passenger API URL
```
## Known Limitations
1. Payment processing is simulated (no real provider integration yet)
2. Ticket PDF download not implemented (placeholder button)
3. Share booking feature not implemented (placeholder button)
4. Seat hold release on expiry requires manual refresh
5. No internationalization (English only)
## Future Enhancements
- [ ] Real payment provider integration (Stripe, Telebirr, etc.)
- [ ] PDF ticket generation and download
- [ ] Email/SMS sharing functionality
- [ ] Real-time seat availability updates (WebSocket)
- [ ] Booking history page
- [ ] User profile management
- [ ] Saved passenger profiles
- [ ] Multi-language support (Amharic, Arabic)
- [ ] Accessibility improvements
- [ ] Analytics tracking
## Contributing
Follow the EDR Platform standards in `CLAUDE.md`:
- TypeScript strict mode
- Conventional commits
- ESLint + Prettier
- pnpm only (no npm/yarn)
## License
Proprietary - Ethio-Djibouti Railway Platform
## Support
For issues or questions, contact the EDR Platform team.