Files
myep/docs/LOADING_INDICATORS_IMPLEMENTATION.md
T

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