8.8 KiB
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?
- ✅ Already extensively used in the project (Step 2 form refreshes)
- ✅ Built-in loading state management via
hx-indicator - ✅ Better error handling (no page reload on validation errors)
- ✅ Progressive enhancement (graceful degradation)
- ✅ Consistent with existing architecture
Implementation Details
Step 1: Add HTMX Indicator Styles
File: assets/styles/app.css
Add global styles for HTMX loading indicators:
/* 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:
- Add HTMX attributes to form:
{{ form_start(form, {
'attr': {
'novalidate': 'novalidate',
'hx-post': path('app_booking_create_step_3'),
'hx-swap': 'none',
'hx-indicator': '#step3-loading'
}
}) }}
- Add loading overlay before form close:
{# 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:
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:
- Add HTMX attributes to form (find
form_start):
{{ form_start(form, {
'attr': {
'novalidate': 'novalidate',
'hx-post': path('app_booking_create_step_4'),
'hx-swap': 'none',
'hx-indicator': '#step4-loading'
}
}) }}
- Add loading overlay before submit button:
{# 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:
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:
<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:
templates/booking/create_step_3.html.twig- Add HTMX attributes + loading indicatortemplates/booking/create_step_4.html.twig- Add HTMX attributes + loading indicator
Controllers:
src/Controller/Booking/CreateStep3Controller.php- Add HTMX response handlingsrc/Controller/Booking/CreateStep4Controller.php- Add HTMX response handling
Styles:
assets/styles/app.css- Add.htmx-indicatorstyles (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