285 lines
8.8 KiB
Markdown
285 lines
8.8 KiB
Markdown
# Loading Indicators Implementation Plan
|
|
|
|
## Overview
|
|
|
|
Add loading indicators to Step 3 and Step 4 of the booking flow to provide visual feedback during slow API calls.
|
|
|
|
**Date:** 2025-10-06
|
|
**Status:** 📋 Planned (not yet implemented)
|
|
|
|
## Problem Statement
|
|
|
|
**Current User Experience:**
|
|
- Step 3: User clicks "Weiter" → 2-3 second wait (inquiry API) → No visual feedback
|
|
- Step 4: User clicks "Verbindlich buchen" → 1-2 second wait (booking API) → No visual feedback
|
|
- Users may click multiple times thinking the form didn't submit
|
|
- No indication that processing is happening
|
|
|
|
## Solution
|
|
|
|
Use HTMX for form submissions with built-in loading indicators.
|
|
|
|
### Why HTMX?
|
|
|
|
1. ✅ Already extensively used in the project (Step 2 form refreshes)
|
|
2. ✅ Built-in loading state management via `hx-indicator`
|
|
3. ✅ Better error handling (no page reload on validation errors)
|
|
4. ✅ Progressive enhancement (graceful degradation)
|
|
5. ✅ Consistent with existing architecture
|
|
|
|
## Implementation Details
|
|
|
|
### Step 1: Add HTMX Indicator Styles
|
|
|
|
**File:** `assets/styles/app.css`
|
|
|
|
Add global styles for HTMX loading indicators:
|
|
|
|
```css
|
|
/* HTMX Loading Indicator */
|
|
.htmx-indicator {
|
|
display: none;
|
|
}
|
|
|
|
.htmx-request .htmx-indicator {
|
|
display: flex;
|
|
}
|
|
|
|
.htmx-request.htmx-indicator {
|
|
display: flex;
|
|
}
|
|
```
|
|
|
|
### Step 2: Update Step 3 Form
|
|
|
|
**File:** `templates/booking/create_step_3.html.twig`
|
|
|
|
**Changes:**
|
|
|
|
1. Add HTMX attributes to form:
|
|
```twig
|
|
{{ form_start(form, {
|
|
'attr': {
|
|
'novalidate': 'novalidate',
|
|
'hx-post': path('app_booking_create_step_3'),
|
|
'hx-swap': 'none',
|
|
'hx-indicator': '#step3-loading'
|
|
}
|
|
}) }}
|
|
```
|
|
|
|
2. Add loading overlay before form close:
|
|
```twig
|
|
{# Loading indicator #}
|
|
<div id="step3-loading" class="htmx-indicator fixed inset-0 bg-gray-900 bg-opacity-50 flex items-center justify-center z-50">
|
|
<div class="bg-white rounded-lg p-8 shadow-xl">
|
|
<div class="flex items-center space-x-4">
|
|
<svg class="animate-spin h-8 w-8 text-primary-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
</svg>
|
|
<span class="text-lg font-medium">Buchung wird validiert...</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{ form_end(form) }}
|
|
```
|
|
|
|
**File:** `src/Controller/Booking/CreateStep3Controller.php`
|
|
|
|
**Changes:**
|
|
|
|
Add HTMX detection and response handling:
|
|
|
|
```php
|
|
public function step3(Request $request): Response
|
|
{
|
|
// ... existing validation logic ...
|
|
|
|
if ($form->isSubmitted() && $form->isValid()) {
|
|
try {
|
|
// ... existing inquiry + price validation logic ...
|
|
|
|
// Validation successful - proceed to confirmation step
|
|
$bookingCreateDto->currentStep = 4;
|
|
$this->bookingService->saveBookingCreateDto($request, $bookingCreateDto);
|
|
|
|
// Handle HTMX requests
|
|
if ($request->headers->get('HX-Request')) {
|
|
return new Response('', 200, [
|
|
'HX-Redirect' => $this->generateUrl('app_booking_create_step_4')
|
|
]);
|
|
}
|
|
|
|
return $this->redirectToRoute('app_booking_create_step_4');
|
|
} catch (\Exception $e) {
|
|
// ... existing error handling ...
|
|
}
|
|
}
|
|
|
|
return $this->render('booking/create_step_3.html.twig', [
|
|
'bookingCreateDto' => $bookingCreateDto,
|
|
'form' => $form->createView(),
|
|
...$this->getSummaryVariables($bookingCreateDto),
|
|
]);
|
|
}
|
|
```
|
|
|
|
### Step 3: Update Step 4 Form
|
|
|
|
**File:** `templates/booking/create_step_4.html.twig`
|
|
|
|
**Changes:**
|
|
|
|
1. Add HTMX attributes to form (find `form_start`):
|
|
```twig
|
|
{{ form_start(form, {
|
|
'attr': {
|
|
'novalidate': 'novalidate',
|
|
'hx-post': path('app_booking_create_step_4'),
|
|
'hx-swap': 'none',
|
|
'hx-indicator': '#step4-loading'
|
|
}
|
|
}) }}
|
|
```
|
|
|
|
2. Add loading overlay before submit button:
|
|
```twig
|
|
{# Loading indicator #}
|
|
<div id="step4-loading" class="htmx-indicator fixed inset-0 bg-gray-900 bg-opacity-50 flex items-center justify-center z-50">
|
|
<div class="bg-white rounded-lg p-8 shadow-xl">
|
|
<div class="flex items-center space-x-4">
|
|
<svg class="animate-spin h-8 w-8 text-primary-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
</svg>
|
|
<span class="text-lg font-medium">Buchung wird durchgeführt...</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{ form_end(form) }}
|
|
```
|
|
|
|
**File:** `src/Controller/Booking/CreateStep4Controller.php`
|
|
|
|
**Changes:**
|
|
|
|
Add HTMX response handling:
|
|
|
|
```php
|
|
public function step4(Request $request): Response
|
|
{
|
|
// ... existing code ...
|
|
|
|
if ($form->isSubmitted() && $form->isValid()) {
|
|
try {
|
|
// Submit final booking (already validated in Step 3)
|
|
$bookingResponse = $this->apiClient->createBooking($bookingCreateDto);
|
|
|
|
// ... existing error handling ...
|
|
|
|
// Success: Store booking number in flash and clear session
|
|
$this->addFlash('booking_number', $bookingResponse->transactionNumber);
|
|
$this->bookingService->clearBookingCreateDto($request);
|
|
|
|
// Handle HTMX requests
|
|
if ($request->headers->get('HX-Request')) {
|
|
return new Response('', 200, [
|
|
'HX-Redirect' => $this->generateUrl('app_booking_success')
|
|
]);
|
|
}
|
|
|
|
return $this->redirectToRoute('app_booking_success');
|
|
} catch (\Exception $e) {
|
|
// ... existing error handling ...
|
|
}
|
|
}
|
|
|
|
return $this->render('booking/create_step_4.html.twig', [
|
|
'bookingCreateDto' => $bookingCreateDto,
|
|
'form' => $form->createView(),
|
|
...$this->getSummaryVariables($bookingCreateDto),
|
|
]);
|
|
}
|
|
```
|
|
|
|
## Alternative: Stimulus-Only Approach
|
|
|
|
If HTMX is not desired, use the existing `loading_controller.js`:
|
|
|
|
**Template:**
|
|
```twig
|
|
<div data-controller="loading" data-loading-hidden-class="hidden">
|
|
{{ form_start(form, {'attr': {'data-action': 'submit->loading#toggle'}}) }}
|
|
|
|
<div data-loading-target="indicator" class="hidden fixed inset-0 bg-gray-900 bg-opacity-50 flex items-center justify-center z-50">
|
|
<div class="bg-white rounded-lg p-8 shadow-xl">
|
|
<!-- Loading spinner -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Form fields -->
|
|
|
|
<button type="submit">Weiter</button>
|
|
{{ form_end(form) }}
|
|
</div>
|
|
```
|
|
|
|
**Pros:** Simpler, no controller changes
|
|
**Cons:**
|
|
- Loading indicator persists if server returns error
|
|
- Page reload happens anyway
|
|
- No error handling improvement
|
|
|
|
## Files to Modify
|
|
|
|
### Templates:
|
|
1. `templates/booking/create_step_3.html.twig` - Add HTMX attributes + loading indicator
|
|
2. `templates/booking/create_step_4.html.twig` - Add HTMX attributes + loading indicator
|
|
|
|
### Controllers:
|
|
3. `src/Controller/Booking/CreateStep3Controller.php` - Add HTMX response handling
|
|
4. `src/Controller/Booking/CreateStep4Controller.php` - Add HTMX response handling
|
|
|
|
### Styles:
|
|
5. `assets/styles/app.css` - Add `.htmx-indicator` styles (if not already present)
|
|
|
|
## Benefits
|
|
|
|
**User Experience:**
|
|
- ✅ Clear visual feedback during API calls
|
|
- ✅ Prevents duplicate submissions (button disabled during request)
|
|
- ✅ Professional loading experience
|
|
- ✅ Reduced user confusion and frustration
|
|
|
|
**Technical:**
|
|
- ✅ Better error handling (no page reload on validation errors)
|
|
- ✅ Consistent with existing HTMX usage in Step 2
|
|
- ✅ Progressive enhancement (works without JavaScript)
|
|
- ✅ Flash messages still work via HX-Redirect
|
|
|
|
## Testing Checklist
|
|
|
|
- [ ] Step 3: Loading indicator shows during inquiry API call
|
|
- [ ] Step 3: Form disabled during submission
|
|
- [ ] Step 3: Success redirects to Step 4
|
|
- [ ] Step 3: Validation errors show inline without reload
|
|
- [ ] Step 4: Loading indicator shows during booking API call
|
|
- [ ] Step 4: Form disabled during submission
|
|
- [ ] Step 4: Success redirects to success page with flash message
|
|
- [ ] Step 4: Errors show inline without reload
|
|
- [ ] Works without JavaScript (graceful degradation)
|
|
- [ ] No duplicate submissions possible
|
|
|
|
## Implementation Priority
|
|
|
|
**High Priority** - Significantly improves UX during slow API operations
|
|
|
|
## Notes
|
|
|
|
- HTMX already included in project dependencies
|
|
- Loading indicators match existing design system
|
|
- Compatible with all existing validation logic
|
|
- No changes to backend business logic required |