feat: loading indicator on initial page load

This commit is contained in:
Björn Fromme
2026-03-16 12:00:56 +01:00
parent f3f2dc6cec
commit 3c2ade9299
2 changed files with 44 additions and 15 deletions
@@ -37,26 +37,46 @@ class IndexController extends AbstractController
) { ) {
} }
/**
* Entry point for starting a new booking.
*
* Renders a loading page that triggers the actual initialization via HTMX.
* This provides immediate visual feedback while BusProNet API calls are made.
*/
#[Route(
path: '/bookings/create',
name: 'app_booking_create',
)]
public function index(#[MapQueryString] ?BookingQueryParams $params): Response
{
if (null === $params) {
throw $this->createNotFoundException('Invalid booking parameters provided');
}
return $this->render('booking/create/index.html.twig', [
'params' => $params,
]);
}
/** /**
* Initializes a fresh booking session and redirects to the login page. * Initializes a fresh booking session and redirects to the login page.
* *
* This endpoint provides a clean way to start the booking flow with just * This endpoint is triggered via HTMX from the loading page. It clears any
* dateId and hotelId parameters. It clears any existing booking session, * existing booking session, creates a fresh BookingDto, and redirects to
* creates a fresh BookingDto, and redirects to the login page where users * the login page where users can authenticate or continue as guest.
* can authenticate (for prepopulation) or continue as guest.
* *
* Optionally accepts an agency code parameter. If provided and valid, the * Optionally accepts an agency code parameter. If provided and valid, the
* corresponding agency ID is stored in the booking. If not provided or invalid, * corresponding agency ID is stored in the booking. If not provided or invalid,
* defaults to agency code '0001'. * defaults to agency code '0001'.
*/ */
#[Route( #[Route(
path: '/bookings/create', path: '/bookings/create/init',
name: 'app_booking_create_init', name: 'app_booking_create_init',
)] )]
public function init(Request $request, #[MapQueryString] ?BookingQueryParams $params): Response public function init(Request $request, #[MapQueryString] ?BookingQueryParams $params): Response
{ {
if (null === $params) { if (null === $params) {
throw $this->createNotFoundException('Invalid booking parameters provided'); return $this->htmxRedirect($request, $this->generateUrl('app_booking_create_error'));
} }
$dateId = $params->dateId; $dateId = $params->dateId;
@@ -85,15 +105,9 @@ class IndexController extends AbstractController
); );
// Redirect to login page (optional authentication before Step 1) // Redirect to login page (optional authentication before Step 1)
return $this->redirectToRoute('app_login'); return $this->htmxRedirect($request, $this->generateUrl('app_login'));
} catch (TravelNotFoundException) { } catch (TravelNotFoundException|HotelNotFoundException|HotelNotInTravelException|NoRoomsAvailableException) {
throw $this->createNotFoundException(sprintf('Travel not found for date ID %d', $dateId)); return $this->htmxRedirect($request, $this->generateUrl('app_booking_create_error'));
} catch (HotelNotFoundException) {
throw $this->createNotFoundException(sprintf('Hotel not found for hotel ID %d', $hotelId));
} catch (HotelNotInTravelException) {
throw $this->createNotFoundException(sprintf('Hotel ID %d is not available for travel ID %d', $hotelId, $dateId));
} catch (NoRoomsAvailableException) {
throw $this->createNotFoundException('No rooms available for this travel.');
} }
} }
+15
View File
@@ -0,0 +1,15 @@
{% extends 'layout_booking.html.twig' %}
{% block content %}
<div class="flex-1 flex items-center justify-center"
hx-get="{{ path('app_booking_create_init', {
date_id: params.dateId,
hotel_id: params.hotelId,
agency: params.agency,
theme: params.theme,
r: params.returnUrl
}) }}"
hx-trigger="load"
hx-swap="none">
</div>
{% endblock %}