wip: group inquiries and booking

This commit is contained in:
Björn Fromme committed 2026-07-14 11:29:43 +02:00
1 parent 732a0f1d19
commit 3632d2f23d
34 files changed
+1810 -436

No files matched your search

@@ -0,0 +1,31 @@
{% extends 'htmx_modal.html.twig' %}
{% block title %}Angebot verbindlich buchen{% endblock %}
{% block content %}
{% from '_partials/_validation_errors.html.twig' import validation_alert %}
{{ validation_alert(confirmationForm, 'Bitte akzeptiere die AGB, um die Buchung abzuschließen.', false) }}
<p class="mb-6">
Möchtest du dieses Angebot jetzt verbindlich buchen?
</p>
{{ form_start(confirmationForm, {
'action': path('app_groups_booking_offer_confirm', { uuid: booking.uuid }),
'attr': {
'hx-target': '#htmx-modal',
'hx-swap': 'outerHTML',
}
}) }}
{{ form_row(confirmationForm.termsAccepted) }}
<div class="mt-6 flex flex-col space-y-4 md:flex-row md:space-y-0 justify-between">
<button type="button" class="button button--secondary" {{ stimulus_action('modal', 'close') }}>
Abbrechen
</button>
<button type="submit" class="button button--primary">
Jetzt verbindlich buchen
</button>
</div>
{{ form_end(confirmationForm) }}
{% endblock %}
@@ -0,0 +1,168 @@
{% block booking_summary %}
<div class="bg-white h-full flex flex-col lg:border-l lg:border-primary-bg"
id="booking-summary">
{# Header #}
<div class="shrink-0 px-4 lg:px-8 py-4 lg:flex lg:flex-col lg:justify-center shadow-md relative z-10">
{% if ctx.priceBreakdown is not null %}
<div class="flex items-center justify-between pb-2">
<span class="block uppercase font-semibold">Gesamtpreis</span>
<span class="font-semibold">{{ (displayTotal / 100)|format_currency(currency) }}</span>
</div>
{% endif %}
<div class="flex items-center justify-between">
<span class="block uppercase font-semibold">Übersicht</span>
<button type="button"
class="lg:hidden button button--small bg-primary-light"
data-action="toggle#toggle">
<svg class="w-4 h-4 text-white transition-transform"
data-toggle-target="icon"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 256 256">
<rect width="256" height="256" fill="none"/>
<polyline points="208 96 128 176 48 96" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
</svg>
</button>
</div>
</div>
{# Content #}
<div class="hidden lg:block flex-1 min-h-0 bg-white shadow-lg lg:shadow-none overflow-y-auto px-4 lg:px-8 py-8"
data-toggle-target="content">
{# Accommodation info #}
{% set hasImage = ctx.hotelCmsData is not null
and ctx.hotelCmsData.images is defined
and ctx.hotelCmsData.images.resized is defined
and ctx.hotelCmsData.images.resized.l is defined
and ctx.hotelCmsData.images.resized.l[0] is defined %}
<div class="border border-primary-bg mb-4">
<div class="p-2 bg-primary-bg uppercase font-semibold">Unterkunft</div>
<div class="grid grid-cols-3 gap-x-4 p-2">
{% if hasImage %}
<img src="{{ ctx.hotelCmsData.images.resized.l[0].url }}"
alt="{{ ctx.hotelCmsData.images.resized.l[0].alt ?? ctx.accommodation.name }}"
class="block w-full h-auto">
{% endif %}
<div class="{{ hasImage ? 'col-span-2' : 'col-span-3' }}">
<span class="block font-semibold">{{ ctx.accommodation.name }}</span>
{% if ctx.hotelCmsData is not null and ctx.hotelCmsData.address is defined %}
<div class="text-sm text-gray-500 mt-1">{{ ctx.hotelCmsData.address|nl2br }}</div>
{% endif %}
</div>
</div>
</div>
{# Price breakdown #}
{% if ctx.priceBreakdown is not null %}
<div class="border border-primary-bg mt-4">
<div class="p-2 bg-primary-bg uppercase font-semibold">Preise</div>
<table class="w-full table-fixed text-sm">
<tr>
<td class="p-2">
Zeitraum
</td>
<td class="p-2 text-right">
{{ booking.dateFrom|date('d.m.Y') }} – {{ booking.dateTo|date('d.m.Y') }},
<br>
{{ booking.nights }} {{ booking.nights != 1 ? 'Nächte' : 'Nacht' }}
</td>
</tr>
<tr>
<td class="p-2">
Anzahl Personen
</td>
<td class="p-2 text-right">
{{ booking.paxCount }}
</td>
</tr>
{% if booking.minorsCount > 0 %}
<tr>
<td class="p-2">davon Kinder (0–3 J.)</td>
<td class="p-2 text-right">{{ booking.minorsCount }}</td>
</tr>
{% endif %}
{% if booking.childrenCount > 0 %}
<tr>
<td class="p-2">davon Kinder (4–{{ ctx.accommodation.maxAdolescentAge }} J.)</td>
<td class="p-2 text-right">{{ booking.childrenCount }}</td>
</tr>
{% endif %}
{% if ctx.priceBreakdown.basePrice > 0 %}
<tr>
<td class="p-2">
Basispreis
<p class="text-xs text-gray-500">für {{ ctx.priceBreakdown.includedPax }} Pers.</p>
</td>
<td class="p-2 text-right whitespace-nowrap">{{ (ctx.priceBreakdown.basePrice / 100)|format_currency(currency) }}</td>
</tr>
{% endif %}
{% if ctx.priceBreakdown.additionalPersonsPrice > 0 %}
<tr>
<td class="p-2">
Aufpreis Personenzahl
<p class="text-xs text-gray-500">für {{ ctx.priceBreakdown.effectivePax - ctx.priceBreakdown.includedPax }} Pers.</p>
</td>
<td class="p-2 text-right whitespace-nowrap">{{ (ctx.priceBreakdown.additionalPersonsPrice / 100)|format_currency(currency) }}</td>
</tr>
{% endif %}
{% if ctx.priceBreakdown.shortTermSurcharge > 0 %}
<tr>
<td class="p-2">Aufpreis Kurzzeit</td>
<td class="p-2 text-right whitespace-nowrap">{{ (ctx.priceBreakdown.shortTermSurcharge / 100)|format_currency(currency) }}</td>
</tr>
{% endif %}
{% if ctx.priceBreakdown.boardPrice > 0 %}
<tr>
<td class="p-2">Verpflegung{% if booking.boardServiceLabel %} ({{ booking.boardServiceLabel }}){% endif %}</td>
<td class="p-2 text-right whitespace-nowrap">{{ (ctx.priceBreakdown.boardPrice / 100)|format_currency(currency) }}</td>
</tr>
{% endif %}
{% if ctx.priceBreakdown.undersubscriptionSurcharge > 0 %}
<tr>
<td class="p-2">
Verpflegungs-Aufschlag
<p class="text-xs text-gray-500">für Gruppen unter {{ ctx.priceBreakdown.undersubscriptionThreshold }} Pers.</p>
</td>
<td class="p-2 text-right whitespace-nowrap">{{ (ctx.priceBreakdown.undersubscriptionSurcharge / 100)|format_currency(currency) }}</td>
</tr>
{% endif %}
{% for service in ctx.priceBreakdown.serviceDetails %}
{% if service.price > 0 %}
<tr>
<td class="p-2">{{ service.label }}</td>
<td class="p-2 text-right whitespace-nowrap">{{ (service.price / 100)|format_currency(currency) }}</td>
</tr>
{% endif %}
{% endfor %}
{% if ctx.priceBreakdown.runningCosts > 0 %}
<tr>
<td class="p-2">Strom- und Abfallgebühren</td>
<td class="p-2 text-right whitespace-nowrap">{{ (ctx.priceBreakdown.runningCosts / 100)|format_currency(currency) }}</td>
</tr>
{% endif %}
<tr class="border-t border-primary-bg font-semibold text-base">
<td class="p-2">
Gesamtpreis
<p class="text-xs font-bold">zzgl. ortsabhängiger Gebühren</p>
</td>
<td class="p-2 text-right whitespace-nowrap">
{{ (ctx.priceBreakdown.total / 100)|format_currency(currency) }}
</td>
</tr>
{% if booking.discount is not null %}
<tr class="text-green-700">
<td class="p-2">Rabatt {{ booking.discount }}&nbsp;%</td>
<td class="p-2 text-right whitespace-nowrap">– {{ (discountAmount / 100)|format_currency(currency) }}</td>
</tr>
<tr class="border-t border-primary-bg font-bold text-base text-green-700">
<td class="p-2">Gesamtpreis nach Rabatt</td>
<td class="p-2 text-right whitespace-nowrap">{{ (discountedTotal / 100)|format_currency(currency) }}</td>
</tr>
{% endif %}
</table>
</div>
{% endif %}
</div>
</div>
{% endblock %}
@@ -3,9 +3,10 @@
1: 'app_groups_booking_step_1',
2: 'app_groups_booking_step_2',
3: 'app_groups_booking_step_3',
4: 'app_groups_booking_step_4',
} %}
<nav class="pagination">
{% for step in 1..3 %}
{% for step in 1..4 %}
<div class="pagination-item">
{% if step < current_step %}
<a href="{{ path(step_routes[step]) }}"
@@ -7,9 +7,8 @@
{{ validation_alert(confirmationForm, 'Bitte akzeptiere die AGB, um die Buchung abzuschließen.', false) }}
{{ form_start(confirmationForm, {
'action': path('app_groups_booking_step_3_confirm'),
'action': path('app_groups_booking_step_4_confirm'),
'attr': {
'hx-post': path('app_groups_booking_step_3_confirm'),
'hx-target': '#htmx-modal',
'hx-swap': 'outerHTML',
}
@@ -17,8 +16,12 @@
{{ form_row(confirmationForm.termsAccepted) }}
<div class="mt-6 flex flex-col space-y-4 md:flex-row md:space-y-0 justify-between">
<button type="submit" class="button button--primary">Buchung verbindlich absenden</button>
<button type="button" class="button button--secondary" {{ stimulus_action('modal', 'close') }}>Abbrechen</button>
<button type="submit" class="button button--primary">
Buchung verbindlich absenden
</button>
<button type="button" class="button button--secondary" {{ stimulus_action('modal', 'close') }}>
Abbrechen
</button>
</div>
{{ form_end(confirmationForm) }}
{% endblock %}
@@ -0,0 +1,18 @@
{% extends 'htmx_modal.html.twig' %}
{% block title %}Anfrage bestätigen{% endblock %}
{% block content %}
<p class="mb-6">Möchtest du diese unverbindliche Anfrage jetzt absenden?</p>
{{ form_start(inquiryForm, { 'action': path('app_groups_booking_step_4') }) }}
<div class="flex flex-col space-y-4 md:flex-row md:space-y-0 justify-between">
<button type="submit" class="button button--primary">
Jetzt anfragen
</button>
<button type="button" class="button button--secondary" {{ stimulus_action('modal', 'close') }}>
Abbrechen
</button>
</div>
{{ form_end(inquiryForm) }}
{% endblock %}
@@ -0,0 +1,31 @@
<div class="border border-primary-bg mb-4">
<div class="p-2 bg-primary-bg uppercase font-semibold">Persönliche Daten</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-2 p-2 text-sm">
<div>
<span class="text-gray-600 font-semibold">Gruppenname:</span>
{{ dto.groupName }}
</div>
<div>
<span class="text-gray-600 font-semibold">Name:</span>
{{ dto.salutation }} {{ dto.firstName }} {{ dto.lastName }}
</div>
<div>
<span class="text-gray-600 font-semibold">E-Mail:</span>
{{ dto.email }}
</div>
<div>
<span class="text-gray-600 font-semibold">Telefon:</span>
{{ dto.phone }}
</div>
<div class="md:col-span-2">
<span class="text-gray-600 font-semibold">Adresse:</span>
{{ dto.street }}, {{ dto.zip }} {{ dto.city }}
</div>
{% if dto.remarks %}
<div class="md:col-span-2">
<span class="text-gray-600 font-semibold">Anmerkungen:</span>
{{ dto.remarks }}
</div>
{% endif %}
</div>
</div>
@@ -0,0 +1,39 @@
{% 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) %}
<div class="border border-primary-bg mb-4">
<div class="p-2 bg-primary-bg uppercase font-semibold">Ausgewählte Leistungen</div>
<div class="p-2 text-sm">
<div class="mb-2">
<span class="text-gray-600 font-semibold">Verpflegung:</span>
{% if selectedBoardService %}
{{ selectedBoardService.label }}
{% if selectedBoardService.description %}
<div class="text-xs text-gray-500">{{ selectedBoardService.description|nl2br }}</div>
{% endif %}
{% else %}
Selbstversorgung
{% endif %}
</div>
{% if selectedAdditionalServices is not empty %}
<div>
<span class="text-gray-600 font-semibold">Zusatzleistungen:</span>
<ul class="list-disc list-inside">
{% for service in selectedAdditionalServices %}
<li>
{{ service.label }}
— {{ (service.price / 100)|format_currency(ctx.accommodation.currency) }} {{ service.type.label|trans }}
</li>
{% endfor %}
</ul>
</div>
{% endif %}
</div>
</div>
+121 -68
View File
@@ -1,85 +1,138 @@
{% extends 'layout.html.twig' %}
{% extends 'layout_booking.html.twig' %}
{% block title %}{{ booking.inquiry ? 'Dein Angebot' : 'Deine Buchung' }}{% endblock %}
{% block background %}bg-outer bg-outer--summer{% endblock %}
{% block content %}
<div class="max-w-2xl w-full mx-auto p-8">
<h1 class="text-2xl font-bold mb-2">
{{ booking.inquiry ? 'Dein Angebot' : 'Deine Buchung' }}
</h1>
<p class="text-gray-500 mb-6">{{ booking.accommodation.name }}</p>
{% set currency = booking.pricingCurrency ?? priceBreakdown.currency %}
{% if booking.discount is not null and priceBreakdown is not null %}
{% set discountAmount = (priceBreakdown.total * booking.discount / 100) | round | number_format(0, '.', '') %}
{% set discountedTotal = booking.totalPrice ?? (priceBreakdown.total - discountAmount) %}
{% endif %}
{% set displayTotal = discountedTotal ?? (priceBreakdown.total ?? null) %}
<div class="grid grid-cols-2 gap-y-2 text-sm mb-8">
<dt class="font-medium">Anreise</dt>
<dd>{{ booking.dateFrom | date('d.m.Y') }}</dd>
<dt class="font-medium">Abreise</dt>
<dd>{{ booking.dateTo | date('d.m.Y') }}</dd>
<dt class="font-medium">Nächte</dt>
<dd>{{ booking.nights }}</dd>
<dt class="font-medium">Personen</dt>
<dd>{{ booking.paxCount }}</dd>
{% if booking.boardServiceLabel %}
<dt class="font-medium">Verpflegung</dt>
<dd>{{ booking.boardServiceLabel }}</dd>
<div class="flex-1 flex flex-col lg:grid lg:grid-cols-5 min-h-0 relative">
{# Sidebar summary #}
<div id="booking-summary-wrapper"
class="order-1 lg:order-2 lg:flex-1 lg:min-h-0 lg:col-span-2"
{{ stimulus_controller('toggle', { 'open': false }, { 'closed': 'hidden', 'open': 'absolute inset-0 z-20', 'iconOpen': 'rotate-180' }) }}>
{% include 'groups/booking/_offer_summary.html.twig' with {
booking: booking,
ctx: ctx,
currency: currency,
displayTotal: displayTotal,
discountAmount: discountAmount ?? null,
discountedTotal: discountedTotal ?? null,
} %}
</div>
{# Main area #}
<div class="flex-1 order-2 lg:order-1 lg:col-span-3 bg-white flex flex-col min-h-0 overflow-y-auto px-4 lg:px-8 py-8">
<h1 class="text-2xl font-bold mb-2">
{{ booking.inquiry ? 'Dein Angebot' : 'Deine Buchung' }}
</h1>
<p class="text-gray-500 mb-6">{{ ctx.accommodation.name }}</p>
{# Booked services #}
{% if booking.boardServiceLabel or booking.additionalServices | length > 0 %}
<div class="mb-8">
<h2 class="text-lg font-bold mb-2">Gebuchte Leistungen</h2>
<ul class="text-sm list-disc list-inside">
{% if booking.boardServiceLabel %}
<li>{{ booking.boardServiceLabel }}</li>
{% endif %}
{% for service in booking.additionalServices %}
<li>{{ service.label }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% if ctx.hotelCmsData is not null %}
<div class="rte-content">
<h2>
Die Unterkunft
</h2>
{{ ctx.hotelCmsData.description | raw }}
<h2>
Details zur Unterkunft
</h2>
{{ ctx.hotelCmsData.features | raw }}
<h2>
Die Zimmer
</h2>
{{ ctx.hotelCmsData.roomTypes | raw }}
<h2>
Weitere Infos
</h2>
{{ ctx.hotelCmsData.additionalInformation | raw }}
<h2>
Bilder
</h2>
</div>
{% set largeImages = ctx.hotelCmsData.images.resized.l %}
{% set mediumImages = ctx.hotelCmsData.images.resized.m %}
{% if largeImages | length > 0 %}
<div class="grid md:grid-cols-2 gap-8" {{ stimulus_controller('gallery') }}>
{% for image in largeImages %}
<div class="relative block w-full h-auto cursor-pointer{{ loop.index0 >= 2 ? ' hidden' : '' }}"
data-gallery-target="item"
data-gallery-href="{{ image.url }}"
data-gallery-alt="{{ image.alt ?? ctx.accommodation.name }}">
<img src="{{ mediumImages[loop.index0].url ?? image.url }}"
alt="{{ image.alt ?? ctx.accommodation.name }}"
class="block w-full h-auto">
{% if loop.index0 == 1 and largeImages | length > 2 %}
<div class="absolute inset-0 bg-black/50 flex items-center justify-center text-white font-bold text-lg">
+{{ largeImages | length - 2 }}
</div>
{% endif %}
</div>
{% endfor %}
</div>
{% endif %}
{% endif %}
{# TODO: additional hotel and location information fetched from the CMS #}
{% if booking.remarks %}
<div class="mb-8">
<h2 class="text-lg font-bold mb-2">Anmerkungen</h2>
<p class="text-sm">{{ booking.remarks | nl2br }}</p>
</div>
{% endif %}
{% if booking.inquiry %}
<div>
<button type="button"
class="button button--primary"
hx-get="{{ path('app_groups_booking_offer_confirm', { uuid: booking.uuid }) }}"
hx-target="body"
hx-swap="beforeend">
Angebot verbindlich buchen
</button>
</div>
{% else %}
{% if booking.acceptedAt is not null %}
<p class="text-sm text-gray-500">
Angenommen am {{ booking.acceptedAt | date('d.m.Y') }} um {{ booking.acceptedAt | date('H:i') }} Uhr
</p>
{% endif %}
{% endif %}
</div>
{% if booking.additionalServices | length > 0 %}
<div class="mb-8">
<h2 class="text-lg font-bold mb-2">Zusatzleistungen</h2>
<ul class="text-sm list-disc list-inside">
{% for service in booking.additionalServices %}
<li>{{ service.label }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
</div>
{% if priceBreakdown is not null %}
{% set currency = booking.pricingCurrency ?? priceBreakdown.currency %}
<div class="mb-8">
<h2 class="text-lg font-bold mb-2">Preise</h2>
<table class="w-full text-sm">
<tr class="border-t border-gray-200 font-semibold">
<td class="pt-2">
Gesamtpreis
<span class="block text-xs font-normal text-gray-500">zzgl. ortsabhängiger Gebühren</span>
</td>
<td class="pt-2 text-right whitespace-nowrap">{{ (priceBreakdown.total / 100) | format_currency(currency) }}</td>
</tr>
{% if booking.discount is not null %}
{% set discountAmount = (priceBreakdown.total * booking.discount / 100) | round | number_format(0, '.', '') %}
{% set discountedTotal = booking.totalPrice ?? (priceBreakdown.total - discountAmount) %}
<tr class="text-green-700">
<td class="pt-1">Rabatt {{ booking.discount }}&nbsp;%</td>
<td class="pt-1 text-right whitespace-nowrap">– {{ (discountAmount / 100) | format_currency(currency) }}</td>
</tr>
<tr class="border-t border-gray-200 font-bold text-green-700">
<td class="pt-2">Gesamtpreis nach Rabatt</td>
<td class="pt-2 text-right whitespace-nowrap">{{ (discountedTotal / 100) | format_currency(currency) }}</td>
</tr>
{% endif %}
</table>
</div>
{% endif %}
{% if booking.inquiry %}
<form method="post" action="{{ app.request.requestUri }}">
<input type="hidden"
name="_token"
value="{{ csrf_token('accept_accommodation_offer_' ~ booking.uuid) }}">
<button type="submit" class="button button--primary">
Angebot verbindlich buchen
</button>
</form>
{% else %}
{% if justAccepted %}
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 max-w-lg w-full z-30">
{% include '_partials/_alert.html.twig' with {
level: 'success',
title: 'Bestätigt',
messages: ['Deine Buchung ist verbindlich bestätigt.'],
} %}
{% endif %}
</div>
</div>
{% endif %}
{% endblock %}
+3 -6
View File
@@ -96,16 +96,13 @@
Zurück
</a>
<div class="space-x-2">
<button type="submit" name="submitInquiry" class="button button--secondary">anfragen</button>
<button type="submit" name="submitBooking" class="{{ html_classes('button button--primary', { 'opacity-50': dto.isInquiry }) }}"{% if dto.isInquiry %} disabled{% endif %}>buchen</button>
<button type="submit" class="button button--primary">
weiter zu Schritt 4
</button>
</div>
</div>
</div>
{{ form_rest(form) }}
{{ form_end(form) }}
{% if confirmationForm is defined %}
{% include 'groups/booking/_step3_confirmation_modal.html.twig' with { confirmationForm: confirmationForm } %}
{% endif %}
{% endblock %}
+74
View File
@@ -0,0 +1,74 @@
{% extends 'layout_booking.html.twig' %}
{% block title %}Buchung bestätigen{% endblock %}
{% block background %}bg-outer bg-outer--summer{% endblock %}
{% block content %}
{# Pagination - mobile only (above summary) #}
<div class="lg:hidden">
{% include 'groups/booking/_pagination.html.twig' with { 'current_step': 4 } %}
</div>
<div class="flex-1 flex flex-col lg:grid lg:grid-cols-5 min-h-0 relative">
{# Static sidebar recap #}
<div class="order-1 lg:order-2 lg:flex-1 lg:min-h-0 lg:col-span-2"
{{ stimulus_controller('toggle', { 'open': false }, { 'closed': 'hidden', 'open': 'absolute inset-0 z-20', 'iconOpen': 'rotate-180' }) }}>
{% include 'groups/booking/_summary.html.twig' with { 'dto': dto, 'ctx': ctx } %}
</div>
{# Confirmation recap #}
<div class="flex-1 order-2 lg:order-1 lg:col-span-3 bg-white flex flex-col min-h-0">
{% include '_partials/_flashes.html.twig' %}
{# Pagination - desktop only (fixed above scrollable content) #}
<div class="hidden lg:block shrink-0">
{% include 'groups/booking/_pagination.html.twig' with { 'current_step': 4 } %}
</div>
<div class="flex-1 overflow-y-auto px-4 lg:px-8 py-8">
<h2 class="pb-4">
Bitte bestätige deine Angaben
</h2>
{% if dto.isInquiry %}
{% include '_partials/_alert.html.twig' with {
level: 'warning',
title: 'Diese Buchung wird als unverbindliche Anfrage behandelt',
messages: dto.inquiryReasons
} %}
{% 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 } %}
</div>
</div>
</div>
<div class="shrink-0 bg-primary-dark px-4 lg:px-8 py-2 lg:py-4 z-20">
<div class="flex items-center justify-between">
<a href="{{ path('app_groups_booking_step_3') }}" class="button button--secondary">
Zurück
</a>
<div class="space-x-2">
<button type="button"
class="button button--secondary"
hx-get="{{ path('app_groups_booking_step_4_confirm_inquiry') }}"
hx-target="body"
hx-swap="beforeend">
anfragen
</button>
<button type="button"
class="{{ html_classes('button button--primary', { 'opacity-50': dto.isInquiry }) }}"
{% if dto.isInquiry %}disabled{% endif %}
hx-get="{{ path('app_groups_booking_step_4_confirm') }}"
hx-target="body"
hx-swap="beforeend">
Jetzt verbindlich buchen
</button>
</div>
</div>
</div>
{% endblock %}