diff --git a/src/Controller/Booking/CreateStep2Controller.php b/src/Controller/Booking/CreateStep2Controller.php index a375bd5..73b68ac 100644 --- a/src/Controller/Booking/CreateStep2Controller.php +++ b/src/Controller/Booking/CreateStep2Controller.php @@ -4,11 +4,11 @@ declare(strict_types=1); namespace App\Controller\Booking; +use App\Controller\Traits\HtmxControllerTrait; use App\Form\BookingCreateStep2Type; use App\Form\Model\BookingCreateDto; use App\Form\Model\ParticipantDto; use App\Service\BookingService; -use App\Validator\Constraints\Participant; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -23,6 +23,7 @@ use Symfony\Component\Routing\Attribute\Route; class CreateStep2Controller extends AbstractController { use BookingCreateTrait; + use HtmxControllerTrait; public function __construct( private readonly BookingService $bookingService, @@ -61,9 +62,12 @@ class CreateStep2Controller extends AbstractController return $this->redirectToRoute('app_booking_create_step_3'); } + $roomAssignmentCounts = $this->bookingService->getRoomAssignmentCounts($bookingCreateDto); + return $this->render('booking/create_step_2.html.twig', [ 'bookingCreateDto' => $bookingCreateDto, 'participantsCount' => $participantsCount, + 'assignmentCounts' => $roomAssignmentCounts, 'form' => $form->createView(), ]); } @@ -76,6 +80,7 @@ class CreateStep2Controller extends AbstractController public function refreshParticipantForm(Request $request): Response { $bookingCreateDto = $this->bookingService->getOrCreateBookingCreateDto($request); + $participantsCount = $this->getParticipantsCount($bookingCreateDto); // Process form data without validation to capture current state $form = $this->createForm(BookingCreateStep2Type::class, $bookingCreateDto, [ @@ -85,9 +90,20 @@ class CreateStep2Controller extends AbstractController $form->handleRequest($request); - return $this->renderBlock('booking/create_step_2.html.twig', 'participants_form', [ - 'form' => $form->createView(), - ]); + $roomAssignmentCounts = $this->bookingService->getRoomAssignmentCounts($bookingCreateDto); + + // The DTO is now updated with the latest selection. + // We can now render the blocks with the fresh data. + return $this->htmxOobResponse( + 'booking/create_step_2.html.twig', + ['participants_form', 'booking_summary'], + [ + 'form' => $form->createView(), + 'bookingCreateDto' => $bookingCreateDto, + 'participantsCount' => $participantsCount, + 'assignmentCounts' => $roomAssignmentCounts, + ] + ); } private function getParticipantsCount(BookingCreateDto $bookingCreateDto): int diff --git a/src/Controller/Traits/HtmxControllerTrait.php b/src/Controller/Traits/HtmxControllerTrait.php new file mode 100644 index 0000000..818d200 --- /dev/null +++ b/src/Controller/Traits/HtmxControllerTrait.php @@ -0,0 +1,37 @@ + $context the context to pass to the template + */ + protected function htmxOobResponse(string $templateName, array $blockNames, array $context = []): Response + { + $html = ''; + // Add a flag to the context so templates can conditionally add the hx-swap-oob attribute. + $oobContext = $context + ['htmx_oob_swap' => true]; + + foreach ($blockNames as $blockName) { + // Use renderBlockView() to get the raw HTML string for each block. + $html .= $this->renderBlockView($templateName, $blockName, $oobContext); + } + + return new Response($html); + } +} diff --git a/src/Service/BookingService.php b/src/Service/BookingService.php index 82b795b..7f32b9e 100644 --- a/src/Service/BookingService.php +++ b/src/Service/BookingService.php @@ -102,4 +102,22 @@ class BookingService return $participantsCount; } + + + /** + * Calculates the number of participants assigned to each room ID. + * + * @return array an array where the key is the room ID and the value is the count of assigned participants + */ + public function getRoomAssignmentCounts(BookingCreateDto $bookingCreateDto): array + { + $counts = []; + foreach ($bookingCreateDto->participants as $participant) { + if (null !== $participant->assignedRoomId) { + $counts[$participant->assignedRoomId] = ($counts[$participant->assignedRoomId] ?? 0) + 1; + } + } + + return $counts; + } } diff --git a/templates/booking/create_step_2.html.twig b/templates/booking/create_step_2.html.twig index 77d109e..d224c53 100644 --- a/templates/booking/create_step_2.html.twig +++ b/templates/booking/create_step_2.html.twig @@ -2,14 +2,15 @@ {% block content %} {% include '_partials/_flashes.html.twig' %} -

Neue Buchung

+

Neue Buchung

Teilnehmer

{{ form_start(form) }} {% do form.participants.setRendered %} + {# This block contains the participant form fields #} {% block participants_form %} -
+
{% for participant in form.participants %}
@@ -27,12 +28,11 @@ {{ form_row(participant.mobile) }}
+ {# hx-swap="none" tells HTMX not to do a normal swap, as OOB will handle it #} {{ form_row(participant.assignedRoomId, { 'attr': { 'hx-post': path('app_booking_create_step_2_refresh'), - 'hx-target': '#participants-form', - 'hx-select': '#participants-form', - 'hx-swap': 'outerHTML' + 'hx-swap': 'none' } }) }}
@@ -48,43 +48,52 @@ {{ form_end(form) }}
-

Zusammenfassung

-

- Reise -

-

- {{ bookingCreateDto.travelData.label }} -

-

- Datum -

-

- {{ bookingCreateDto.travelData.dateFrom | date('d.m.Y') }} - {{ bookingCreateDto.travelData.dateTo | date('d.m.Y') }} -

-

- Unterkunft -

-

- {{ bookingCreateDto.travelData.hotel.name }} -

- {% if participantsCount > 0 %} -

- Anzahl Teilnehmer -

-

- {{ participantsCount }} -

- {% endif %} -

- Zimmer -

-
    - {% for roomSelection in bookingCreateDto.selectedRooms %} -
  • - {{ roomSelection.quantity }}x {{ roomSelection.roomLabel }} -
  • - {% endfor %} -
+ {# This block contains the booking summary #} + {% block booking_summary %} +
+

Zusammenfassung

+

+ Reise +

+

+ {{ bookingCreateDto.travelData.label }} +

+

+ Datum +

+

+ {{ bookingCreateDto.travelData.dateFrom | date('d.m.Y') }} - {{ bookingCreateDto.travelData.dateTo | date('d.m.Y') }} +

+

+ Unterkunft +

+

+ {{ bookingCreateDto.travelData.hotel.name }} +

+ {% if participantsCount > 0 %} +

+ Anzahl Teilnehmer +

+

+ {{ participantsCount }} +

+ {% endif %} +

+ Zimmer +

+
    + {% for roomSelection in bookingCreateDto.selectedRooms %} + {% set assignedCount = assignmentCounts[roomSelection.roomId] ?? 0 %} +
  • + {{ roomSelection.roomLabel }} + + ({{ assignedCount }}/{{ roomSelection.quantity }}) + +
  • + {% endfor %} +
+
+ {% endblock %}
{% endblock %}