3d6607e6c8
Build & Deploy / Build & Push Docker Image (push) Successful in 8m27s
Test / Type Check (all packages) (push) Successful in 3m34s
Build & Deploy / Deploy to VPS (push) Successful in 2s
Test / API Unit Tests (push) Failing after 3m16s
Test / Homepage Unit Tests (push) Failing after 2m40s
Test / Storefront Unit Tests (push) Failing after 24s
Test / Admin Unit Tests (push) Failing after 22s
Test / Dashboard Unit Tests (push) Failing after 24s
Test / API Integration Tests (push) Failing after 33s
635 lines
18 KiB
Markdown
635 lines
18 KiB
Markdown
# Progressive Reservation Creation: Action Plan
|
||
|
||
## 1. Objective
|
||
|
||
Replace the single long reservation form at:
|
||
|
||
`/dashboard/reservations/new`
|
||
|
||
with a progressive wizard that:
|
||
|
||
* Shows one focused section at a time.
|
||
* Validates only the current section before continuing.
|
||
* Preserves entered information when moving backward or forward.
|
||
* Provides a final review before creating the reservation.
|
||
* Works correctly in English, French, and Arabic.
|
||
* Supports desktop, mobile, light mode, dark mode, LTR, and RTL.
|
||
* Prevents duplicate submissions and handles partial API failures safely.
|
||
|
||
The reservation should not be created until the user confirms the final review step.
|
||
|
||
---
|
||
|
||
## 2. Problems in the Current Implementation
|
||
|
||
The existing page combines all responsibilities inside one component:
|
||
|
||
* Customer search and selection.
|
||
* New customer creation.
|
||
* Customer identity information.
|
||
* Driver license information.
|
||
* License image upload.
|
||
* Vehicle selection.
|
||
* Rental dates and locations.
|
||
* Deposit and payment method.
|
||
* Additional driver information.
|
||
* Notes.
|
||
* Validation.
|
||
* Customer creation and updates.
|
||
* Reservation submission.
|
||
* Translated copy.
|
||
|
||
This creates several practical problems:
|
||
|
||
1. The user sees too much information at once.
|
||
2. Validation returns one generic error instead of identifying the exact field.
|
||
3. Adding a customer is confusing because required identity and license fields appear outside the customer creation panel.
|
||
4. Navigation away from the page loses the entire form.
|
||
5. Customer updates, license uploads, and reservation creation can partially succeed.
|
||
6. The component will become increasingly difficult to maintain.
|
||
7. Vehicle availability is currently based only on `status === 'AVAILABLE'`, not the selected rental dates. That does not reliably prevent conflicting reservations.
|
||
|
||
---
|
||
|
||
## 3. Proposed Wizard Structure
|
||
|
||
Use six fixed steps. Six is the upper reasonable limit here. More steps would create needless clicking; fewer would leave several sections overloaded.
|
||
|
||
### Step 1: Customer
|
||
|
||
Purpose: Identify who is making the reservation.
|
||
|
||
Fields and actions:
|
||
|
||
* Choose `Existing customer` or `New customer`.
|
||
* Search existing customers.
|
||
* Select an existing customer.
|
||
* For a new customer:
|
||
|
||
* First name.
|
||
* Arabic first name.
|
||
* Last name.
|
||
* Arabic last name.
|
||
* Email.
|
||
* Phone.
|
||
|
||
Completion requirements:
|
||
|
||
* Existing customer mode: a customer must be selected.
|
||
* New customer mode: first name, last name, email, and phone must be valid.
|
||
|
||
Important behavior:
|
||
|
||
* Selecting an existing customer preloads known identity and license data.
|
||
* Creating a new customer should not call the API at this step.
|
||
* Switching between existing and new customer modes must not silently mix the two records.
|
||
* Changing the selected customer after editing loaded data should display a confirmation before replacing those edits.
|
||
|
||
### Step 2: Identity
|
||
|
||
Purpose: Verify the renter’s personal information.
|
||
|
||
Fields:
|
||
|
||
* Date of birth.
|
||
* Nationality.
|
||
* CIN or passport number.
|
||
* Full address.
|
||
* International permit number, optional.
|
||
|
||
Completion requirements:
|
||
|
||
* Date of birth is present and in the past.
|
||
* Nationality is present.
|
||
* Identity document number is present.
|
||
* Full address is present.
|
||
|
||
The section should display whether values were loaded from an existing customer and allow the user to correct them.
|
||
|
||
### Step 3: Driver License
|
||
|
||
Purpose: Verify that the primary renter is legally eligible to drive.
|
||
|
||
Fields:
|
||
|
||
* Driver license number.
|
||
* License country.
|
||
* License issue date.
|
||
* License expiry date.
|
||
* License category.
|
||
* License image, optional unless business rules later require it.
|
||
|
||
Completion requirements:
|
||
|
||
* Required license fields are complete.
|
||
* Issue date is not in the future.
|
||
* Expiry date is after the issue date.
|
||
* Expiry date has not already passed.
|
||
* Uploaded file is a supported image type and within the configured size limit.
|
||
|
||
The current image and newly selected preview should be clearly distinguished.
|
||
|
||
### Step 4: Rental Details
|
||
|
||
Purpose: Define what is being rented and when.
|
||
|
||
Recommended field order:
|
||
|
||
1. Start date and time.
|
||
2. End date and time.
|
||
3. Vehicle.
|
||
4. Pickup location.
|
||
5. Return location.
|
||
|
||
Completion requirements:
|
||
|
||
* Start date is valid.
|
||
* End date is later than the start date.
|
||
* A vehicle is selected.
|
||
* The vehicle remains available for the chosen period.
|
||
|
||
Important correction:
|
||
|
||
The current implementation lists vehicles using only their general `AVAILABLE` status. The final implementation should request or revalidate date-based availability. A vehicle can be marked available now while already reserved for the requested dates.
|
||
|
||
If the API does not currently support date-based availability, this must be recorded as a backend dependency rather than pretending the status filter is sufficient.
|
||
|
||
### Step 5: Payment and Extras
|
||
|
||
Purpose: Collect optional and commercial details.
|
||
|
||
Main fields:
|
||
|
||
* Deposit amount.
|
||
* Payment method.
|
||
* Notes.
|
||
|
||
Optional additional driver:
|
||
|
||
* Display a compact `Add another driver` control.
|
||
* Opening it reveals an additional-driver panel or nested form.
|
||
* Allow removal before submission.
|
||
* Structure the state as an array even if the current interface initially supports only one driver.
|
||
|
||
Additional-driver fields:
|
||
|
||
* First and last name.
|
||
* Arabic first and last name.
|
||
* Email, optional.
|
||
* Phone, optional.
|
||
* Date of birth, optional.
|
||
* Nationality, optional.
|
||
* License number.
|
||
* License issue date, optional.
|
||
* License expiry date, optional.
|
||
|
||
Completion requirements:
|
||
|
||
* Deposit cannot be negative.
|
||
* A payment method must be selected.
|
||
* If an additional driver is enabled, name and license number are required.
|
||
* Any entered additional-driver dates must be logically valid.
|
||
|
||
### Step 6: Review and Confirm
|
||
|
||
Purpose: Prevent avoidable mistakes before committing data.
|
||
|
||
Display concise summaries for:
|
||
|
||
* Customer.
|
||
* Identity.
|
||
* Primary driver license.
|
||
* Vehicle.
|
||
* Rental period.
|
||
* Pickup and return locations.
|
||
* Payment.
|
||
* Additional drivers.
|
||
* Notes.
|
||
|
||
Each summary section should include an `Edit` action that returns directly to the relevant step.
|
||
|
||
Final actions:
|
||
|
||
* Back.
|
||
* Cancel.
|
||
* Create reservation.
|
||
|
||
The final button must display a loading state and remain disabled after the first click until the request succeeds or fails.
|
||
|
||
---
|
||
|
||
## 4. Navigation and Progress Behavior
|
||
|
||
### Desktop
|
||
|
||
Use a horizontal stepper containing:
|
||
|
||
* Step number.
|
||
* Short step label.
|
||
* Completed state.
|
||
* Current state.
|
||
* Future state.
|
||
|
||
### Mobile
|
||
|
||
Use a compact header:
|
||
|
||
`Step 3 of 6 · Driver license`
|
||
|
||
Include a progress bar rather than compressing all six labels into unusable decorative confetti.
|
||
|
||
### Navigation rules
|
||
|
||
* `Continue` validates the current step.
|
||
* `Back` never discards information.
|
||
* Completed steps may be revisited.
|
||
* Future incomplete steps cannot be opened directly.
|
||
* The final review step is available only after all previous steps are valid.
|
||
* Pressing Enter must not accidentally submit the final reservation from an earlier step.
|
||
* The footer containing Back and Continue should remain visible on long steps where practical.
|
||
|
||
---
|
||
|
||
## 5. Validation Strategy
|
||
|
||
Replace the current generic `Please fill all required fields` behavior with step-specific validation.
|
||
|
||
Use Zod, which is already installed, to create separate schemas:
|
||
|
||
* `customerStepSchema`
|
||
* `identityStepSchema`
|
||
* `licenseStepSchema`
|
||
* `rentalStepSchema`
|
||
* `paymentExtrasStepSchema`
|
||
* `completeReservationSchema`
|
||
|
||
Validation behavior:
|
||
|
||
* Validate on Continue.
|
||
* Show the message beside the invalid field.
|
||
* Focus the first invalid field.
|
||
* Clear an error once the value becomes valid.
|
||
* Run complete validation again before final submission.
|
||
* Translate validation messages into English, French, and Arabic.
|
||
|
||
Do not depend on disabled buttons alone. A disabled button gives the user no useful explanation and is a remarkably efficient way to make software feel broken.
|
||
|
||
---
|
||
|
||
## 6. State Management Refactor
|
||
|
||
Replace the large collection of independent `useState` calls with one structured draft state managed by `useReducer`.
|
||
|
||
Suggested shape:
|
||
|
||
```ts
|
||
type ReservationDraft = {
|
||
customer: {
|
||
mode: 'existing' | 'new'
|
||
selectedCustomerId: string | null
|
||
firstName: BilingualField
|
||
lastName: BilingualField
|
||
email: string
|
||
phone: string
|
||
}
|
||
identity: {
|
||
dateOfBirth: string
|
||
nationality: string
|
||
fullAddress: string
|
||
identityDocumentNumber: string
|
||
internationalLicenseNumber: string
|
||
}
|
||
license: {
|
||
number: string
|
||
country: string
|
||
issuedAt: string
|
||
expiry: string
|
||
category: string
|
||
existingImageUrl: string | null
|
||
newImageFile: File | null
|
||
}
|
||
rental: {
|
||
vehicleId: string
|
||
startDate: string
|
||
endDate: string
|
||
pickupLocation: string
|
||
returnLocation: string
|
||
}
|
||
payment: {
|
||
depositAmount: string
|
||
paymentMode: string
|
||
notes: string
|
||
}
|
||
additionalDrivers: AdditionalDriverDraft[]
|
||
}
|
||
```
|
||
|
||
The reducer should support explicit actions such as:
|
||
|
||
* Select existing customer.
|
||
* Start new customer.
|
||
* Update step field.
|
||
* Add additional driver.
|
||
* Remove additional driver.
|
||
* Hydrate customer information.
|
||
* Clear customer information.
|
||
* Store a newly created customer ID after partial submission.
|
||
* Reset the entire draft.
|
||
|
||
This makes state transitions testable and prevents unrelated fields from being scattered throughout the page.
|
||
|
||
---
|
||
|
||
## 7. Component Structure
|
||
|
||
Reduce `page.tsx` to a data-loading and route-level shell.
|
||
|
||
Suggested structure:
|
||
|
||
```text
|
||
src/components/reservations/new/
|
||
├── ReservationWizard.tsx
|
||
├── ReservationStepper.tsx
|
||
├── ReservationWizardActions.tsx
|
||
├── ReservationReview.tsx
|
||
├── reservationWizard.types.ts
|
||
├── reservationWizard.reducer.ts
|
||
├── reservationWizard.schemas.ts
|
||
├── reservationWizard.copy.ts
|
||
├── reservationWizard.submit.ts
|
||
├── steps/
|
||
│ ├── CustomerStep.tsx
|
||
│ ├── IdentityStep.tsx
|
||
│ ├── LicenseStep.tsx
|
||
│ ├── RentalDetailsStep.tsx
|
||
│ ├── PaymentExtrasStep.tsx
|
||
│ └── ReviewStep.tsx
|
||
└── __tests__/
|
||
```
|
||
|
||
Responsibilities:
|
||
|
||
* `page.tsx`: load customers and vehicles, render the wizard.
|
||
* `ReservationWizard`: control current step and draft state.
|
||
* Step components: render fields only.
|
||
* Schemas: validation only.
|
||
* Reducer: state transitions only.
|
||
* Submission module: API orchestration only.
|
||
* Copy file: typed English, French, and Arabic labels.
|
||
* Review component: display formatted summaries only.
|
||
|
||
---
|
||
|
||
## 8. API Submission Strategy
|
||
|
||
No customer or reservation records should be created merely because the user moved to another step.
|
||
|
||
On final confirmation:
|
||
|
||
1. Validate the complete draft.
|
||
2. Revalidate vehicle availability.
|
||
3. For a new customer:
|
||
|
||
* Create the customer using the accumulated customer, identity, and license fields.
|
||
4. For an existing customer:
|
||
|
||
* Patch only changed customer fields.
|
||
5. Upload the license image when a new image was selected.
|
||
6. Create the reservation.
|
||
7. Redirect to the new reservation details page.
|
||
|
||
### Partial-failure handling
|
||
|
||
The current operations are not atomic. For example, customer creation may succeed while reservation creation fails.
|
||
|
||
The wizard must therefore:
|
||
|
||
* Remember the newly created customer ID in memory.
|
||
* Retry using that customer instead of creating another duplicate.
|
||
* Show which operation failed.
|
||
* Keep all form data available for correction or retry.
|
||
* Never redirect until reservation creation succeeds.
|
||
|
||
### Recommended backend improvement
|
||
|
||
The strongest solution is a dedicated backend operation that creates or updates the customer, uploads document metadata, validates vehicle availability, and creates the reservation as one controlled workflow.
|
||
|
||
Without such an endpoint, the frontend can handle retries carefully, but it cannot provide a true database transaction across the current independent requests.
|
||
|
||
---
|
||
|
||
## 9. Data Loading and Customer Hydration
|
||
|
||
Current customer and vehicle loading should be extracted from the form component.
|
||
|
||
Required behavior:
|
||
|
||
* Show a proper loading state for the wizard shell.
|
||
* Show separate customer-load and vehicle-load errors where possible.
|
||
* Do not overwrite user-edited customer data when background data refreshes.
|
||
* Hydrate fields only when the selected customer actually changes.
|
||
* Cancel or ignore stale requests when the component unmounts.
|
||
* Avoid loading arbitrary large lists indefinitely as the database grows.
|
||
|
||
Future improvement:
|
||
|
||
Replace `pageSize=100` customer loading with server-side customer search. Loading the first 100 customers and searching them in the browser will eventually fail as a business grows, which is traditionally when software chooses to reveal its assumptions.
|
||
|
||
---
|
||
|
||
## 10. Draft-Loss Protection
|
||
|
||
For the first implementation:
|
||
|
||
* Keep all information when navigating between wizard steps.
|
||
* Warn before leaving the page when unsaved changes exist.
|
||
* Do not persist license images in browser storage.
|
||
* Clear the draft after successful creation.
|
||
* Clear object URLs used for image previews.
|
||
|
||
Do not automatically store sensitive customer identity and license information in long-lived local storage.
|
||
|
||
A server-side draft feature can be designed separately if staff need to resume reservations across devices or sessions.
|
||
|
||
---
|
||
|
||
## 11. Accessibility and Localization
|
||
|
||
The wizard must preserve the application’s existing multilingual requirements.
|
||
|
||
Requirements:
|
||
|
||
* English and French use LTR.
|
||
* Arabic uses true RTL.
|
||
* Step order and navigation layout adapt correctly in RTL.
|
||
* Every field has an associated label.
|
||
* Required fields are announced to assistive technology.
|
||
* Errors use `aria-describedby`.
|
||
* The active step uses `aria-current="step"`.
|
||
* Focus moves to the step heading after navigation.
|
||
* Keyboard users can operate all controls.
|
||
* Color is not the only indicator of progress or error.
|
||
* Buttons and inputs remain usable in dark mode.
|
||
* Dates and amounts are presented using the active locale on the review screen.
|
||
|
||
The current hardcoded English license-image alt text must also be localized.
|
||
|
||
---
|
||
|
||
## 12. Testing Plan
|
||
|
||
### Unit tests
|
||
|
||
Test:
|
||
|
||
* Reducer actions.
|
||
* Step validation schemas.
|
||
* Date relationships.
|
||
* Deposit normalization.
|
||
* Existing customer hydration.
|
||
* Switching customer modes.
|
||
* Additional-driver add and remove behavior.
|
||
* Final payload construction.
|
||
|
||
### Component tests
|
||
|
||
Test:
|
||
|
||
* Only the active step is displayed.
|
||
* Continue blocks invalid data.
|
||
* Back preserves data.
|
||
* Completed steps can be revisited.
|
||
* Existing customer details are prefilled.
|
||
* New customer information remains in draft state.
|
||
* Additional-driver fields appear conditionally.
|
||
* Edit actions on the review page open the correct step.
|
||
* Arabic step layout uses RTL correctly.
|
||
|
||
### Submission tests
|
||
|
||
Test:
|
||
|
||
* Existing customer reservation.
|
||
* New customer reservation.
|
||
* License image upload.
|
||
* Customer update failure.
|
||
* Image upload failure.
|
||
* Reservation creation failure after customer creation.
|
||
* Retry without duplicate customer creation.
|
||
* Double-click prevention.
|
||
* Vehicle availability conflict.
|
||
|
||
### Required verification
|
||
|
||
Run:
|
||
|
||
```bash
|
||
npm run type-check
|
||
npm run test
|
||
npm run build
|
||
```
|
||
|
||
for the dashboard workspace after implementation.
|
||
|
||
---
|
||
|
||
## 13. Implementation Sequence
|
||
|
||
### Phase 1: Extract and stabilize
|
||
|
||
* Create typed draft models.
|
||
* Extract copy, validation, and payload-building logic.
|
||
* Add tests around current behavior.
|
||
* Do not change the visible interface yet.
|
||
|
||
### Phase 2: Build the wizard shell
|
||
|
||
* Add stepper.
|
||
* Add reducer.
|
||
* Add navigation.
|
||
* Add shared action footer.
|
||
* Render one step at a time.
|
||
|
||
### Phase 3: Move form sections
|
||
|
||
* Move customer fields.
|
||
* Move identity fields.
|
||
* Move license fields.
|
||
* Move rental fields.
|
||
* Move payment and optional driver fields.
|
||
* Build the review screen.
|
||
|
||
### Phase 4: Correct submission behavior
|
||
|
||
* Delay new-customer creation until final confirmation.
|
||
* Add partial-failure recovery.
|
||
* Prevent duplicate requests.
|
||
* Revalidate vehicle availability.
|
||
* Preserve the draft after recoverable errors.
|
||
|
||
### Phase 5: Accessibility and responsive refinement
|
||
|
||
* Add keyboard and screen-reader behavior.
|
||
* Verify mobile presentation.
|
||
* Verify dark mode.
|
||
* Verify Arabic RTL.
|
||
* Verify translated error messages.
|
||
|
||
### Phase 6: Testing and regression review
|
||
|
||
* Complete unit and component tests.
|
||
* Run type-check, tests, and production build.
|
||
* Verify both existing-customer and new-customer flows manually.
|
||
* Confirm redirect to the created reservation.
|
||
|
||
---
|
||
|
||
## 14. Acceptance Criteria
|
||
|
||
The work is complete only when:
|
||
|
||
* Exactly one focused step is displayed at a time.
|
||
* The user can see their current position and progress.
|
||
* Invalid current-step fields prevent progression and explain why.
|
||
* Going backward does not lose information.
|
||
* New customers are not created before final confirmation.
|
||
* Existing-customer data is loaded without repeatedly overwriting edits.
|
||
* Additional drivers remain optional.
|
||
* The final review contains all reservation information.
|
||
* Every review section can be edited.
|
||
* Duplicate reservations cannot be created by repeated clicks.
|
||
* Partial API failures do not force the user to restart.
|
||
* Vehicle availability is revalidated for the selected dates.
|
||
* English, French, and Arabic are complete.
|
||
* Arabic layout is true RTL.
|
||
* Mobile, desktop, light mode, and dark mode work.
|
||
* Type-check, tests, and production build pass.
|
||
|
||
---
|
||
|
||
## 15. Scope Boundaries
|
||
|
||
Included:
|
||
|
||
* Progressive reservation wizard.
|
||
* Refactoring of the current new-reservation page.
|
||
* Step validation.
|
||
* Review screen.
|
||
* Existing and new customer flows.
|
||
* License image handling.
|
||
* Additional-driver handling.
|
||
* API failure recovery.
|
||
* Responsive, multilingual, and accessible behavior.
|
||
* Relevant tests.
|
||
|
||
Not included unless separately approved:
|
||
|
||
* Redesigning the reservation details page.
|
||
* Server-side saved drafts.
|
||
* OCR extraction from driver licenses.
|
||
* Multiple primary renters.
|
||
* Payment processing.
|
||
* Contract generation.
|
||
* Changing unrelated dashboard pages.
|
||
* Broad customer-management redesign.
|