diff --git a/src/Controller/Groups/AbstractAccommodationController.php b/src/Controller/Groups/Booking/AbstractController.php similarity index 91% rename from src/Controller/Groups/AbstractAccommodationController.php rename to src/Controller/Groups/Booking/AbstractController.php index f8f0168..c41efaf 100644 --- a/src/Controller/Groups/AbstractAccommodationController.php +++ b/src/Controller/Groups/Booking/AbstractController.php @@ -2,15 +2,15 @@ declare(strict_types=1); -namespace App\Controller\Groups; +namespace App\Controller\Groups\Booking; use App\Exception\AccommodationSessionNotFoundException; use App\Form\Model\AccommodationBookingDto; -use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController as SymfonyAbstractController; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Response; -abstract class AbstractAccommodationController extends AbstractController +abstract class AbstractController extends SymfonyAbstractController { protected function validateStepAccess(AccommodationBookingDto $dto, int $expectedStep): ?RedirectResponse { diff --git a/src/Controller/Groups/IndexController.php b/src/Controller/Groups/Booking/IndexController.php similarity index 96% rename from src/Controller/Groups/IndexController.php rename to src/Controller/Groups/Booking/IndexController.php index e006b24..96f5cf9 100644 --- a/src/Controller/Groups/IndexController.php +++ b/src/Controller/Groups/Booking/IndexController.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Controller\Groups; +namespace App\Controller\Groups\Booking; use App\Htmx\HxTrait; use App\Model\AccommodationBookingQueryParams; @@ -14,7 +14,7 @@ use Symfony\Component\HttpFoundation\Session\FlashBagAwareSessionInterface; use Symfony\Component\HttpKernel\Attribute\MapQueryString; use Symfony\Component\Routing\Attribute\Route; -class IndexController extends AbstractAccommodationController +class IndexController extends AbstractController { use HxTrait; diff --git a/src/Controller/Groups/Step1Controller.php b/src/Controller/Groups/Booking/Step1Controller.php similarity index 99% rename from src/Controller/Groups/Step1Controller.php rename to src/Controller/Groups/Booking/Step1Controller.php index 9096b6d..c5bd371 100644 --- a/src/Controller/Groups/Step1Controller.php +++ b/src/Controller/Groups/Booking/Step1Controller.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Controller\Groups; +namespace App\Controller\Groups\Booking; use App\BpnConnect\ContingentsClient; use App\BpnConnect\Exception\BpnConnectException; @@ -24,7 +24,7 @@ use Symfony\Component\Routing\Attribute\Route; use Symfony\Contracts\Cache\CacheInterface; use Symfony\Contracts\Cache\ItemInterface; -class Step1Controller extends AbstractAccommodationController +class Step1Controller extends AbstractController { use HxTrait; diff --git a/src/Controller/Groups/Step2Controller.php b/src/Controller/Groups/Booking/Step2Controller.php similarity index 98% rename from src/Controller/Groups/Step2Controller.php rename to src/Controller/Groups/Booking/Step2Controller.php index a3a89e8..6585f71 100644 --- a/src/Controller/Groups/Step2Controller.php +++ b/src/Controller/Groups/Booking/Step2Controller.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Controller\Groups; +namespace App\Controller\Groups\Booking; use App\Entity\Groups\AdditionalService; use App\Entity\Groups\BoardService; @@ -19,7 +19,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; -class Step2Controller extends AbstractAccommodationController +class Step2Controller extends AbstractController { use HxTrait; diff --git a/src/Controller/Groups/Step3Controller.php b/src/Controller/Groups/Booking/Step3Controller.php similarity index 96% rename from src/Controller/Groups/Step3Controller.php rename to src/Controller/Groups/Booking/Step3Controller.php index 0a5cee2..19600de 100644 --- a/src/Controller/Groups/Step3Controller.php +++ b/src/Controller/Groups/Booking/Step3Controller.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Controller\Groups; +namespace App\Controller\Groups\Booking; use App\Entity\Groups\Accommodation; use App\Exception\AccommodationSessionNotFoundException; @@ -15,7 +15,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; -class Step3Controller extends AbstractAccommodationController +class Step3Controller extends AbstractController { public function __construct( private readonly AccommodationBookingService $bookingService, diff --git a/src/Controller/Groups/Step4Controller.php b/src/Controller/Groups/Booking/Step4Controller.php similarity index 95% rename from src/Controller/Groups/Step4Controller.php rename to src/Controller/Groups/Booking/Step4Controller.php index 7e46c69..e613422 100644 --- a/src/Controller/Groups/Step4Controller.php +++ b/src/Controller/Groups/Booking/Step4Controller.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Controller\Groups; +namespace App\Controller\Groups\Booking; use App\Entity\Groups\Accommodation; use App\Entity\Groups\AdditionalService; @@ -20,7 +20,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; -class Step4Controller extends AbstractAccommodationController +class Step4Controller extends AbstractController { use HxTrait; @@ -80,7 +80,7 @@ class Step4Controller extends AbstractAccommodationController $inquiryForm = $this->createForm(AccommodationInquiryConfirmationType::class); - return $this->render('groups/booking/_step4_inquiry_confirmation_modal.html.twig', [ + return $this->render('groups/booking/modal_inquiry_confirmation.html.twig', [ 'inquiryForm' => $inquiryForm, ]); } @@ -107,7 +107,7 @@ class Step4Controller extends AbstractAccommodationController return $this->htmxRedirect($request, $this->generateUrl('app_groups_booking_success')); } - return $this->render('groups/booking/_step4_booking_confirmation_modal.html.twig', [ + return $this->render('groups/booking/modal_booking_confirmation.html.twig', [ 'confirmationForm' => $confirmationForm, ]); } diff --git a/src/Controller/Groups/OfferController.php b/src/Controller/Groups/Offer/IndexController.php similarity index 86% rename from src/Controller/Groups/OfferController.php rename to src/Controller/Groups/Offer/IndexController.php index 3ec954a..7c5ef90 100644 --- a/src/Controller/Groups/OfferController.php +++ b/src/Controller/Groups/Offer/IndexController.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Controller\Groups; +namespace App\Controller\Groups\Offer; use App\Entity\Groups\AccommodationBooking; use App\Form\Model\OfferAcceptDto; @@ -20,7 +20,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; -class OfferController extends AbstractController +class IndexController extends AbstractController { use HxTrait; @@ -38,35 +38,35 @@ class OfferController extends AbstractController * authorizes the session for this booking, and redirects to the plain * (session-gated) offer page — nothing downstream needs the signature again. */ - #[Route(path: '/groups/booking/offer/{uuid}', name: 'app_groups_booking_offer', methods: ['GET'])] + #[Route(path: '/groups/booking/offer/{uuid}', name: 'app_groups_offer', methods: ['GET'])] public function access(string $uuid, Request $request): Response { $booking = $this->bookingRepository->findOneBy(['uuid' => $uuid]); if (null === $booking || false === $this->linkSigner->isValidLinkRequest($request, $booking)) { - return $this->render('groups/booking/offer_unavailable.html.twig'); + return $this->render('groups/offer/unavailable.html.twig'); } if (!$this->isCustomerVisible($booking)) { - return $this->render('groups/booking/offer_unavailable.html.twig'); + return $this->render('groups/offer/unavailable.html.twig'); } $this->linkSigner->authorizeSession($request, $booking); - return new RedirectResponse($this->generateUrl('app_groups_booking_offer_view', ['uuid' => $uuid])); + return new RedirectResponse($this->generateUrl('app_groups_offer_view', ['uuid' => $uuid])); } - #[Route(path: '/groups/booking/offer/{uuid}/view', name: 'app_groups_booking_offer_view', methods: ['GET'])] + #[Route(path: '/groups/booking/offer/{uuid}/view', name: 'app_groups_offer_view', methods: ['GET'])] public function view(string $uuid, Request $request): Response { $booking = $this->bookingRepository->findOneBy(['uuid' => $uuid]); if (null === $booking || false === $this->linkSigner->isSessionAuthorized($request, $booking)) { - return $this->render('groups/booking/offer_unavailable.html.twig'); + return $this->render('groups/offer/unavailable.html.twig'); } if (!$this->isCustomerVisible($booking)) { - return $this->render('groups/booking/offer_unavailable.html.twig'); + return $this->render('groups/offer/unavailable.html.twig'); } $accommodation = $booking->getAccommodation() ?? throw $this->createNotFoundException('Booking has no accommodation.'); @@ -78,14 +78,14 @@ class OfferController extends AbstractController priceBreakdown: $priceBreakdown, ); - return $this->render('groups/booking/offer.html.twig', [ + return $this->render('groups/offer/view.html.twig', [ 'booking' => $booking, 'priceBreakdown' => $priceBreakdown, 'ctx' => $ctx, ]); } - #[Route(path: '/groups/booking/offer/{uuid}/confirm', name: 'app_groups_booking_offer_confirm', methods: ['GET', 'POST'])] + #[Route(path: '/groups/booking/offer/{uuid}/confirm', name: 'app_groups_offer_confirm', methods: ['GET', 'POST'])] public function confirm(string $uuid, Request $request): Response { $booking = $this->bookingRepository->findOneBy(['uuid' => $uuid]); @@ -115,7 +115,7 @@ class OfferController extends AbstractController return $this->redirectToOfferPage($request, $uuid); } - return $this->render('groups/booking/_offer_accept_confirmation_modal.html.twig', [ + return $this->render('groups/offer/modal_accept_confirmation.html.twig', [ 'booking' => $booking, 'confirmationForm' => $confirmationForm, ]); @@ -138,7 +138,7 @@ class OfferController extends AbstractController */ private function redirectToOfferPage(Request $request, string $uuid): Response { - $url = $this->generateUrl('app_groups_booking_offer_view', ['uuid' => $uuid]); + $url = $this->generateUrl('app_groups_offer_view', ['uuid' => $uuid]); return $this->htmxRedirect($request, $url); } diff --git a/src/Service/AccommodationBookingLinkSigner.php b/src/Service/AccommodationBookingLinkSigner.php index 8b608ca..34a1d3c 100644 --- a/src/Service/AccommodationBookingLinkSigner.php +++ b/src/Service/AccommodationBookingLinkSigner.php @@ -34,7 +34,7 @@ class AccommodationBookingLinkSigner } $url = $this->urlGenerator->generate( - 'app_groups_booking_offer', + 'app_groups_offer', ['uuid' => $booking->getUuid(), self::TIMESTAMP_PARAM => $issuedAt->getTimestamp()], UrlGeneratorInterface::ABSOLUTE_URL, ); diff --git a/templates/email/_price_breakdown.html.twig b/templates/email/_price_breakdown.html.twig index 67c5668..b5be216 100644 --- a/templates/email/_price_breakdown.html.twig +++ b/templates/email/_price_breakdown.html.twig @@ -1,5 +1,5 @@ {#- Prices only — travel dates and group size belong to _stay_details.html.twig and the - PDF's own data block. Mirrors groups/booking/_offer_summary.html.twig, but with inline + PDF's own data block. Mirrors groups/offer/_summary.html.twig, but with inline styles: neither the email layout nor dompdf ships table styling or Tailwind. Context: booking, priceBreakdown, currency (set in AccommodationBookingService and AccommodationBookingPdfGenerator). -#} diff --git a/templates/groups/booking/_step4_personal_data_recap.html.twig b/templates/groups/booking/_step4_personal_data_recap.html.twig deleted file mode 100644 index 051f09d..0000000 --- a/templates/groups/booking/_step4_personal_data_recap.html.twig +++ /dev/null @@ -1,31 +0,0 @@ -
-
Persönliche Daten
-
-
- Gruppenname: - {{ dto.groupName }} -
-
- Name: - {{ dto.salutation }} {{ dto.firstName }} {{ dto.lastName }} -
-
- E-Mail: - {{ dto.email }} -
-
- Telefon: - {{ dto.phone }} -
-
- Adresse: - {{ dto.street }}, {{ dto.zip }} {{ dto.city }} -
- {% if dto.remarks %} -
- Anmerkungen: - {{ dto.remarks }} -
- {% endif %} -
-
diff --git a/templates/groups/booking/_step4_services_recap.html.twig b/templates/groups/booking/_step4_services_recap.html.twig deleted file mode 100644 index ca4c190..0000000 --- a/templates/groups/booking/_step4_services_recap.html.twig +++ /dev/null @@ -1,42 +0,0 @@ -{% set selectedBoardService = null %} -{% for service in ctx.boardServices %} - {% if service.id == dto.selectedBoardServiceId %} - {% set selectedBoardService = service %} - {% endif %} -{% endfor %} - -{% set selectedAdditionalServices = ctx.additionalServices|filter(service => service.id in dto.selectedAdditionalServiceIds) %} - -
-
Ausgewählte Leistungen
-
-
- Verpflegung: - {% if selectedBoardService %} - {{ selectedBoardService.label }} - {% if selectedBoardService.price > 0 %} - — {{ (selectedBoardService.price / 100)|format_currency(ctx.accommodation.currency) }} pro Person und Nacht - {% endif %} - {% if selectedBoardService.description %} -
{{ selectedBoardService.description|nl2br }}
- {% endif %} - {% else %} - Selbstversorgung - {% endif %} -
- - {% if selectedAdditionalServices is not empty %} -
- Zusatzleistungen: -
    - {% for service in selectedAdditionalServices %} -
  • - {{ service.label }} - — {{ (service.price / 100)|format_currency(ctx.accommodation.currency) }} {{ service.type.label|trans }} -
  • - {% endfor %} -
-
- {% endif %} -
-
diff --git a/templates/groups/booking/_step4_booking_confirmation_modal.html.twig b/templates/groups/booking/modal_booking_confirmation.html.twig similarity index 100% rename from templates/groups/booking/_step4_booking_confirmation_modal.html.twig rename to templates/groups/booking/modal_booking_confirmation.html.twig diff --git a/templates/groups/booking/_step4_inquiry_confirmation_modal.html.twig b/templates/groups/booking/modal_inquiry_confirmation.html.twig similarity index 100% rename from templates/groups/booking/_step4_inquiry_confirmation_modal.html.twig rename to templates/groups/booking/modal_inquiry_confirmation.html.twig diff --git a/templates/groups/booking/step_4.html.twig b/templates/groups/booking/step_4.html.twig index fbf508d..f1150f2 100644 --- a/templates/groups/booking/step_4.html.twig +++ b/templates/groups/booking/step_4.html.twig @@ -40,8 +40,80 @@ } %} {% endif %} - {% include 'groups/booking/_step4_services_recap.html.twig' with { 'dto': dto, 'ctx': ctx } %} - {% include 'groups/booking/_step4_personal_data_recap.html.twig' with { 'dto': dto } %} + {% set selectedBoardService = null %} + {% for service in ctx.boardServices %} + {% if service.id == dto.selectedBoardServiceId %} + {% set selectedBoardService = service %} + {% endif %} + {% endfor %} + + {% set selectedAdditionalServices = ctx.additionalServices|filter(service => service.id in dto.selectedAdditionalServiceIds) %} + +
+
Ausgewählte Leistungen
+
+
+ Verpflegung: + {% if selectedBoardService %} + {{ selectedBoardService.label }} + {% if selectedBoardService.price > 0 %} + — {{ (selectedBoardService.price / 100)|format_currency(ctx.accommodation.currency) }} pro Person und Nacht + {% endif %} + {% if selectedBoardService.description %} +
{{ selectedBoardService.description|nl2br }}
+ {% endif %} + {% else %} + Selbstversorgung + {% endif %} +
+ + {% if selectedAdditionalServices is not empty %} +
+ Zusatzleistungen: +
    + {% for service in selectedAdditionalServices %} +
  • + {{ service.label }} + — {{ (service.price / 100)|format_currency(ctx.accommodation.currency) }} {{ service.type.label|trans }} +
  • + {% endfor %} +
+
+ {% endif %} +
+
+ +
+
Persönliche Daten
+
+
+ Gruppenname: + {{ dto.groupName }} +
+
+ Name: + {{ dto.salutation }} {{ dto.firstName }} {{ dto.lastName }} +
+
+ E-Mail: + {{ dto.email }} +
+
+ Telefon: + {{ dto.phone }} +
+
+ Adresse: + {{ dto.street }}, {{ dto.zip }} {{ dto.city }} +
+ {% if dto.remarks %} +
+ Anmerkungen: + {{ dto.remarks }} +
+ {% endif %} +
+
diff --git a/templates/groups/booking/_offer_summary.html.twig b/templates/groups/offer/_summary.html.twig similarity index 100% rename from templates/groups/booking/_offer_summary.html.twig rename to templates/groups/offer/_summary.html.twig diff --git a/templates/groups/booking/_offer_accept_confirmation_modal.html.twig b/templates/groups/offer/modal_accept_confirmation.html.twig similarity index 93% rename from templates/groups/booking/_offer_accept_confirmation_modal.html.twig rename to templates/groups/offer/modal_accept_confirmation.html.twig index 9d69f1e..2f053b1 100644 --- a/templates/groups/booking/_offer_accept_confirmation_modal.html.twig +++ b/templates/groups/offer/modal_accept_confirmation.html.twig @@ -12,7 +12,7 @@

{{ form_start(confirmationForm, { - 'action': path('app_groups_booking_offer_confirm', { uuid: booking.uuid }), + 'action': path('app_groups_offer_confirm', { uuid: booking.uuid }), 'attr': { 'hx-target': '#htmx-modal', 'hx-swap': 'outerHTML', diff --git a/templates/groups/booking/offer_unavailable.html.twig b/templates/groups/offer/unavailable.html.twig similarity index 100% rename from templates/groups/booking/offer_unavailable.html.twig rename to templates/groups/offer/unavailable.html.twig diff --git a/templates/groups/booking/offer.html.twig b/templates/groups/offer/view.html.twig similarity index 98% rename from templates/groups/booking/offer.html.twig rename to templates/groups/offer/view.html.twig index 9e6b2da..f8a8001 100644 --- a/templates/groups/booking/offer.html.twig +++ b/templates/groups/offer/view.html.twig @@ -37,7 +37,7 @@
- {% include 'groups/booking/_offer_summary.html.twig' with { + {% include 'groups/offer/_summary.html.twig' with { booking: booking, ctx: ctx, currency: currency, @@ -78,7 +78,7 @@