Files
myep/templates/booking/_participant_form.html.twig
T

656 lines
38 KiB
Twig
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{# Macro to render a form field or static value based on field state #}
{% macro field_or_static(form, fieldName, label, staticValue, bookingDto, participantIndex, options = {}) %}
{% if form[fieldName] is defined %}
{# Field is in form structure - render normally as form input #}
{{ form_row(form[fieldName], options) }}
{% elseif is_static_text(fieldName, bookingDto, participantIndex) %}
{# Field excluded from form - render as static text in fieldset/table style #}
<div class="pb-4">
<fieldset class="border border-primary-bg">
<legend class="w-full bg-primary-bg p-2 font-semibold uppercase">{{ label }}</legend>
<table class="w-full table-fixed border-collapse">
<tr>
<td class="border border-primary-bg p-2">{{ staticValue ?: '-' }}</td>
</tr>
</table>
</fieldset>
</div>
{% endif %}
{# If neither condition is true, don't render anything (truly hidden) #}
{% endmacro %}
{# Macro to render a service field with consistent fieldset/table structure #}
{% macro service_field(form, fieldName, label, options = {}, undefinedLabel = 'Nicht wählbar') %}
{% if form[fieldName] is defined %}
{{ form_row(form[fieldName], options) }}
{% else %}
<div class="pb-4">
<fieldset class="border border-primary-bg">
<legend class="w-full bg-primary-bg p-2 font-semibold uppercase">{{ label }}</legend>
<div class="p-2 text-sm text-gray-500">{{ undefinedLabel }}</div>
</fieldset>
</div>
{% endif %}
{% endmacro %}
{# Macro to render a service choice table row with optional price and tooltip #}
{% macro service_choice_row(child, price, tooltipText, tooltipLabel, widgetAttr = {}, showIncludedLabel = true) %}
{% set isReadonly = child.vars.attr.readonly is defined %}
<tr>
<td class="border border-primary-bg p-2 align-top">
<div>{{ child.vars.label }}</div>
{%- if tooltipText is not null -%}
<div {{ stimulus_controller('tooltip') }}>
<button type="button" data-tooltip-target="trigger" class="text-sm text-primary-light">
{{ tooltipLabel|default('Details') }}
</button>
<template data-tooltip-target="template">
<div class="text-sm">{{ tooltipText|raw }}</div>
</template>
</div>
{%- endif -%}
</td>
<td class="border border-primary-bg p-2 align-top w-24 text-right whitespace-nowrap">
{{ price | format_service_price(showIncludedLabel) }}
</td>
<td class="border border-primary-bg p-2 align-top w-12 text-center">
{% set childTooltip = child.vars.attr['data-tooltip']|default(null) %}
<div class="{{ html_classes({ 'cursor-not-allowed': isReadonly }) }}"{% if childTooltip is not null %} {{ stimulus_controller('tooltip', { 'content': childTooltip }) }}{% endif %}>
<div class="{{ isReadonly ? 'pointer-events-none' : '' }}">
{{ form_widget(child, { 'attr': widgetAttr }) }}
</div>
</div>
</td>
</tr>
{% endmacro %}
{# Macro to render a checkbox table row (for trailing checkboxes like rental insurance, parking, bulk insurance) #}
{% macro checkbox_row(checkboxField, label, price, tooltipText, tooltipLabel, widgetAttr = {}, showPrice = true) %}
{% set isReadonly = checkboxField.vars.attr.readonly is defined %}
<tr>
<td class="border border-primary-bg p-2 align-top">
<div>{{ label }}</div>
{%- if tooltipText is not null -%}
<div {{ stimulus_controller('tooltip') }}>
<button type="button" data-tooltip-target="trigger" class="text-sm text-primary-light">
{{ tooltipLabel|default('Info') }}
</button>
<template data-tooltip-target="template">
<div class="text-sm">{{ tooltipText|raw }}</div>
</template>
</div>
{%- endif -%}
</td>
<td class="border border-primary-bg p-2 align-top w-24 text-right whitespace-nowrap">
{{ price | format_service_price(showPrice) }}
</td>
<td class="border border-primary-bg p-2 align-top w-12 text-center">
{% set fieldTooltip = checkboxField.vars.attr['data-tooltip']|default(null) %}
<div class="{{ html_classes({ 'cursor-not-allowed': isReadonly }) }}"{% if fieldTooltip is not null %} {{ stimulus_controller('tooltip', { 'content': fieldTooltip }) }}{% endif %}>
<div class="{{ isReadonly ? 'pointer-events-none' : '' }}">
{{ form_widget(checkboxField, { 'attr': widgetAttr }) }}
</div>
</div>
</td>
</tr>
{% endmacro %}
{# Macro to render insurance choice table row with product info links #}
{% macro insurance_choice_row(child, choiceData, widgetAttr = {}) %}
{% set isReadonly = child.vars.attr.readonly is defined %}
{% set isNoInsurance = choiceData.noInsurance|default(false) %}
{% set price = choiceData.price|default(null) %}
{% set urlsProductInfo = choiceData ? choiceData.getAllUrlsProductInfo() : [] %}
<tr>
<td class="border border-primary-bg p-2 align-top">
<div>{{ child.vars.label }}</div>
{%- if urlsProductInfo is not empty -%}
<div {{ stimulus_controller('tooltip') }}>
<button type="button" data-tooltip-target="trigger" class="text-sm text-primary-light">
Details
</button>
<template data-tooltip-target="template">
<div class="text-sm">
{%- for url in urlsProductInfo -%}
<a href="{{ url }}" target="_blank" rel="noopener noreferrer" class="block">
Produktinformation {{ urlsProductInfo|length > 1 ? loop.index : '' }}
</a>
{%- endfor -%}
</div>
</template>
</div>
{%- endif -%}
</td>
<td class="border border-primary-bg p-2 align-top w-24 text-right whitespace-nowrap">
{{ price | format_service_price(not isNoInsurance) }}
</td>
<td class="border border-primary-bg p-2 align-top w-12 text-center">
{% set childTooltip = child.vars.attr['data-tooltip']|default(null) %}
{% if isReadonly or childTooltip is not null %}
<div{% if isReadonly %} class="cursor-not-allowed"{% endif %}{% if childTooltip is not null %} {{ stimulus_controller('tooltip', { 'content': childTooltip }) }}{% endif %}>
<div{% if isReadonly %} class="pointer-events-none"{% endif %}>
{{ form_widget(child, { 'attr': widgetAttr }) }}
</div>
</div>
{% else %}
{{ form_widget(child, { 'attr': widgetAttr }) }}
{% endif %}
</td>
</tr>
{% endmacro %}
{# Standalone participant form view (replaces main content area) #}
{% block participant_form %}
{% form_theme form 'booking/_form_theme.html.twig' %}
{% import _self as macros %}
<div class="flex items-center gap-4 pb-4 mb-4 border-b border-primary-bg">
<div class="{{ html_classes('w-12 h-12 inline-flex flex-shrink-0 items-center justify-center rounded-full text-white text-2xl font-bold', {
'bg-primary-dark': booking_theme() == 'base',
'bg-sbw-primary': booking_theme() == 'sbw',
'bg-snz-primary-dark': booking_theme() == 'snz',
'bg-ser-primary': booking_theme() == 'ser',
}) }}">
{{ participantIndex + 1 }}
</div>
<div class="text-2xl">
{{ participantIndex == 0 and not bookingDto.isInternalAgencyBooking() ? 'Anmelder:in' : 'Teilnehmer:in ' ~ (participantIndex + 1) }}
</div>
</div>
<div id="participant-form" class="space-y-4" hx-disinherit="hx-boost">
{% from '_partials/_validation_errors.html.twig' import validation_alert %}
{{ validation_alert(form) }}
{# Eligibility checks #}
{% set participantData = form.vars.data.participant %}
{% set hasDateOfBirth = participantData and participantData.dateOfBirth %}
{% set isEligible = hasDateOfBirth and is_participant_eligible(bookingDto, participantIndex) %}
{% if not hasDateOfBirth %}
{% include '_partials/_alert.html.twig' with {
level: 'info',
messages: ['Leistungen sind erst nach Angabe des Geburtsdatums buchbar']
} %}
{% elseif not isEligible %}
{% include '_partials/_alert.html.twig' with {
level: 'error',
messages: ['Buchung wegen des Alters von Teilnehmer:in ' ~ (participantIndex + 1) ~ ' nicht möglich']
} %}
{% endif %}
{# Personal data and address section #}
{% set isPersonalDataStatic = is_static_text('firstName', bookingDto, participantIndex) %}
{% set isAddressStatic = is_static_text('address', bookingDto, participantIndex) %}
{% if isPersonalDataStatic and isAddressStatic %}
{# Both personal data and address are static - render in two-column grid with tables #}
{% set participant = form.vars.data.participant %}
{% set addressSource = (0 == participantIndex and bookingDto.booking) ? bookingDto.booking.applicant : bookingDto.participants[participantIndex] %}
{% set genderLabel = participant.gender == 'M' ? 'männlich' : (participant.gender == 'W' ? 'weiblich' : (participant.gender == 'D' ? 'divers' : null)) %}
<div class="grid lg:grid-cols-2 lg:gap-x-8 pb-4">
{# Personal data #}
<div class="pb-4 lg:pb-0">
<fieldset class="border border-primary-bg">
<legend class="w-full bg-primary-bg p-2 font-semibold uppercase">Persönliche Daten</legend>
<table class="w-full table-fixed border-collapse">
<tr>
<td class="border border-primary-bg p-2">
<strong>Name:</strong> {{ participant.firstName }} {{ participant.lastName }}<br>
<strong>Geburtsdatum:</strong> {{ participant.dateOfBirth ? participant.dateOfBirth|date('d.m.Y') : '-' }}<br>
<strong>Geschlecht:</strong> {{ genderLabel ?: '-' }}<br>
<strong>Nationalität:</strong> {{ participant.nationality ? participant.nationality|map_nationality : '-' }}<br>
<strong>E-Mail:</strong> {{ participant.email ?: '-' }}<br>
<strong>Telefon:</strong> {{ participant.mobile ?: '-' }}
</td>
</tr>
</table>
</fieldset>
</div>
{# Address #}
<div>
<fieldset class="border border-primary-bg">
<legend class="w-full bg-primary-bg p-2 font-semibold uppercase">Adresse</legend>
<table class="w-full table-fixed border-collapse">
<tr>
<td class="border border-primary-bg p-2">
{% if addressSource.address %}
{% if addressSource.address.street %}{{ addressSource.address.street }}<br>{% endif %}
{% if addressSource.address.postCode or addressSource.address.city %}
{{ addressSource.address.postCode }} {{ addressSource.address.city }}<br>
{% endif %}
{% if addressSource.address.country %}{{ addressSource.address.country|map_country }}{% endif %}
{% else %}
-
{% endif %}
</td>
</tr>
</table>
</fieldset>
</div>
</div>
{% else %}
{# Editable form fields for personal data #}
<div class="grid lg:grid-cols-2 lg:gap-x-8">
{{ macros.field_or_static(form, 'firstName', 'Vorname', form.vars.data.participant.firstName, bookingDto, participantIndex) }}
{{ macros.field_or_static(form, 'lastName', 'Nachname', form.vars.data.participant.lastName, bookingDto, participantIndex) }}
{{ macros.field_or_static(
form,
'dateOfBirth',
'Geburtsdatum',
form.vars.data.participant.dateOfBirth ? form.vars.data.participant.dateOfBirth|date('d.m.Y') : null,
bookingDto,
participantIndex,
{
'attr': {
'hx-trigger': htmx_change_trigger,
'hx-post': path(refreshRouteName, refreshRouteParams|default({index: participantIndex})),
'hx-target': '#main-content',
'hx-swap': 'innerHTML'
}
}
) }}
{% set genderLabel = form.vars.data.participant.gender == 'M' ? 'männlich' : (form.vars.data.participant.gender == 'W' ? 'weiblich' : (form.vars.data.participant.gender == 'D' ? 'divers' : null)) %}
{{ macros.field_or_static(form, 'gender', 'Geschlecht', genderLabel, bookingDto, participantIndex) }}
{{ macros.field_or_static(form, 'nationality', 'Nationalität', form.vars.data.participant.nationality|map_nationality, bookingDto, participantIndex) }}
{# Contact information #}
{{ macros.field_or_static(form, 'email', 'E-Mail', form.vars.data.participant.email, bookingDto, participantIndex) }}
{{ macros.field_or_static(form, 'mobile', 'Telefon (mobil)', form.vars.data.participant.mobile, bookingDto, participantIndex) }}
</div>
{# Address #}
{% if form.address is defined %}
<div class="grid lg:grid-cols-2 lg:gap-x-8">
{# Address field is in form - render as editable form fields #}
{{ form_row(form.address.street) }}
{{ form_row(form.address.postCode) }}
{{ form_row(form.address.city) }}
{{ form_row(form.address.country) }}
</div>
{% endif %}
{% endif %}
{# Room assignment - hidden until date of birth is provided, or shown as static text in edit mode #}
{% if form.assignedRoomId is defined or is_static_text('assignedRoomId', bookingDto, participantIndex) %}
<div>
{% set assignedRoom = bookingDto.travel.getRoomById(form.vars.data.participant.assignedRoomId) %}
{% set roomLabel = assignedRoom ? assignedRoom.label : 'Kein Zimmer zugewiesen' %}
<h3 class="font-semibold text-lg mb-4">
Unterkunft
</h3>
{{ macros.field_or_static(form, 'assignedRoomId', 'Zimmer', roomLabel, bookingDto, participantIndex, {
'attr': {
'hx-trigger': htmx_change_trigger,
'hx-post': path(refreshRouteName, refreshRouteParams|default({index: participantIndex})),
'hx-target': '#main-content',
'hx-swap': 'innerHTML'
}
}) }}
{% if form.remarksRoom is defined %}
{{ form_row(form.remarksRoom) }}
{% endif %}
</div>
{% endif %}
{# Service selection #}
{% if isEligible %}
<h3 class="font-semibold text-lg mb-4">
Leistungen
</h3>
{{ macros.service_field(form, 'skiPass', 'Skipass', {
'attr': {
'hx-trigger': htmx_change_trigger,
'hx-post': path(refreshRouteName, refreshRouteParams|default({index: participantIndex})),
'hx-target': '#main-content', 'hx-swap': 'innerHTML'
}
}) }}
{{ macros.service_field(form, 'courses', 'Kurse', {
'attr': {
'hx-trigger': htmx_change_trigger,
'hx-post': path(refreshRouteName, refreshRouteParams|default({index: participantIndex})),
'hx-target': '#main-content', 'hx-swap': 'innerHTML'
}
}) }}
{{ macros.service_field(form, 'additionalServices', 'Zusatzleistungen', {
'attr': {
'hx-trigger': htmx_change_trigger,
'hx-post': path(refreshRouteName, refreshRouteParams|default({index: participantIndex})),
'hx-target': '#main-content', 'hx-swap': 'innerHTML'
}
}) }}
{# Board and VEG fields combined in one fieldset #}
{% if form.board is defined or form.veg is defined %}
<div class="pb-4">
<fieldset class="border border-primary-bg">
<legend class="w-full bg-primary-bg p-2 font-semibold uppercase">Verpflegung</legend>
{% if form.board is defined %}
{{ form_widget(form.board, {
'attr': {
'hx-trigger': htmx_change_trigger,
'hx-post': path(refreshRouteName, refreshRouteParams|default({index: participantIndex})),
'hx-target': '#main-content', 'hx-swap': 'innerHTML'
}
}) }}
{% endif %}
{% if form.veg is defined %}
<div class="p-2 border-t border-primary-bg">
{{ form_widget(form.veg, {
'attr': {
'hx-trigger': htmx_change_trigger,
'hx-post': path(refreshRouteName, refreshRouteParams|default({index: participantIndex})),
'hx-target': '#main-content', 'hx-swap': 'innerHTML'
}
}) }}
{{ form_errors(form.veg) }}
</div>
{% endif %}
</fieldset>
{% if form.board is defined %}
{{ form_errors(form.board) }}
{% endif %}
<div class="text-sm mt-2 px-2 flex items-start space-x-1">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 flex-shrink-0">
<path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" />
</svg>
<span>Bitte teile uns eventuelle Unverträglichkeiten an <a href="mailto:{{ customer_service_email }}" class="text-primary-light hover:underline">{{ customer_service_email }}</a> (inkl. der Buchungsnummer) mit.</span>
</div>
</div>
{% else %}
<div class="pb-4">
<fieldset class="border border-primary-bg">
<legend class="w-full bg-primary-bg p-2 font-semibold uppercase">Verpflegung</legend>
<div class="p-2 text-sm text-gray-500">Nicht wählbar</div>
</fieldset>
</div>
{% endif %}
{% set htmxAttr = {
'hx-trigger': htmx_change_trigger,
'hx-post': path(refreshRouteName, refreshRouteParams|default({index: participantIndex})),
'hx-target': '#main-content',
'hx-swap': 'innerHTML'
} %}
<div class="pb-4">
<fieldset class="border border-primary-bg">
<legend class="{{ html_classes('w-full bg-primary-bg p-2 font-semibold uppercase', { 'text-red-500': form.rentals is defined and not form.rentals.vars.valid }) }}">
Leihmaterial
{% if form.rentals is defined and form.rentals.vars.required %}<span>*</span>{% endif %}
</legend>
{% if form.rentals is defined %}
<table class="w-full table-fixed border-collapse">
{% for child in form.rentals %}
{% set choiceData = form.rentals.vars.choices[loop.index0].data %}
{{ macros.service_choice_row(child, choiceData.price|default(null), child.vars.attr['data-description']|default(null), 'Details', htmxAttr) }}
{% endfor %}
{% if form.rentalInsurance is defined %}
{% set rentalInsuranceService = bookingDto.travel.getAdditionalServicesBySubTypes(constant('App\\BusProNet\\Constants::TOKEN_RENTAL_INSURANCE'), true)|first %}
{{ macros.checkbox_row(
form.rentalInsurance,
constant('App\\BusProNet\\Constants::SERVICE_LABELS')[constant('App\\BusProNet\\Constants::TOKEN_RENTAL_INSURANCE')],
rentalInsuranceService.price|default(null),
form.rentalInsurance.vars.help|default(null),
'Info',
htmxAttr
) }}
{% endif %}
</table>
{% elseif form.skiPass is defined and not form.vars.data.participant.skiPass %}
{# Skipass field exists but no skipass selected yet #}
<div class="p-2 text-sm text-gray-500">Bitte zuerst den Skipass auswählen</div>
{% else %}
{# No skipass field or skipass selected but no matching rentals #}
<div class="p-2 text-sm text-gray-500">Nicht wählbar</div>
{% endif %}
</fieldset>
{% if form.rentals is defined %}
{{ form_errors(form.rentals) }}
{{ form_help(form.rentals) }}
{% endif %}
</div>
{% if form.bodyDimensions is defined %}
<div class="grid lg:grid-cols-3 lg:gap-x-4 pb-4">
{{ form_row(form.bodyDimensions.height) }}
{{ form_row(form.bodyDimensions.shoeSize) }}
{{ form_row(form.bodyDimensions.weight) }}
<div class="lg:col-span-3 text-sm -mt-2 px-2 flex items-start space-x-1">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 flex-shrink-0">
<path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" />
</svg>
<span>{{ form.bodyDimensions.vars.help }}</span>
</div>
</div>
{% endif %}
{# Insurance display for edit mode (read-only) - only show if insurance is selected #}
{% if bookingDto.mode == constant('App\\Form\\Model\\BookingDto::MODE_EDIT') %}
{% if form.vars.data.participant.insurance %}
{% set editInsurance = form.vars.data.participant.insurance %}
<div class="pb-4">
<fieldset class="border border-primary-bg">
<legend class="w-full bg-primary-bg p-2 font-semibold uppercase">
Reiseversicherung
</legend>
<table class="w-full table-fixed border-collapse">
<tr>
<td class="border border-primary-bg p-2 align-top">
<div>{{ editInsurance.label }}</div>
{%- if editInsurance.getAllUrlsProductInfo() is not empty -%}
<div {{ stimulus_controller('tooltip') }}>
<button type="button" data-tooltip-target="trigger" class="text-sm text-primary-light">
Details
</button>
<template data-tooltip-target="template">
<div class="text-sm">
{%- for url in editInsurance.getAllUrlsProductInfo() -%}
<a href="{{ url }}" target="_blank" rel="noopener noreferrer" class="block">
Produktinformation {{ editInsurance.getAllUrlsProductInfo()|length > 1 ? loop.index : '' }}
</a>
{%- endfor -%}
</div>
</template>
</div>
{%- endif -%}
</td>
<td class="border border-primary-bg p-2 align-top w-24 text-right whitespace-nowrap">
{% if editInsurance.price and editInsurance.price > 0 %}
{{ editInsurance.price | format_currency('EUR') }}
{% endif %}
</td>
<td class="border border-primary-bg p-2 align-top w-12"></td>
</tr>
</table>
</fieldset>
</div>
{% endif %}
{# In edit mode without insurance: don't show the section at all #}
{# Insurance field OR assigned insurance display for dependent participants (create mode) #}
{% else %}
{% set showBulkInsurance = participantIndex > 0 and bookingDto.participants[0].bulkInsuranceBooking %}
{% if showBulkInsurance %}
{% set applicantInsurance = bookingDto.participants[0].insurance %}
<div class="pb-4">
<fieldset class="border border-primary-bg">
<legend class="w-full bg-primary-bg p-2 font-semibold uppercase">
Reiseversicherung* <span class="font-normal normal-case text-sm text-gray-600 italic"> wie {{ bookingDto.isInternalAgencyBooking() ? 'Teilnehmer:in 1' : 'Anmelder:in' }}</span>
</legend>
{% if applicantInsurance %}
<table class="w-full table-fixed border-collapse">
<tr>
<td class="border border-primary-bg p-2 align-top">
<div>{{ applicantInsurance.label }}</div>
{%- if applicantInsurance.getAllUrlsProductInfo() is not empty -%}
<div {{ stimulus_controller('tooltip') }}>
<button type="button" data-tooltip-target="trigger" class="text-sm text-primary-light">
Details
</button>
<template data-tooltip-target="template">
<div class="text-sm">
{%- for url in applicantInsurance.getAllUrlsProductInfo() -%}
<a href="{{ url }}" target="_blank" rel="noopener noreferrer" class="block">
Produktinformation {{ applicantInsurance.getAllUrlsProductInfo()|length > 1 ? loop.index : '' }}
</a>
{%- endfor -%}
</div>
</template>
</div>
{%- endif -%}
</td>
<td class="border border-primary-bg p-2 align-top w-24 text-right whitespace-nowrap">
{% if applicantInsurance.price and applicantInsurance.price > 0 %}
{{ applicantInsurance.price | format_currency('EUR') }}
{% endif %}
</td>
<td class="border border-primary-bg p-2 align-top w-12"></td>
</tr>
</table>
{% else %}
<table class="w-full table-fixed border-collapse">
<tr>
<td class="border border-primary-bg p-2 align-top text-sm text-gray-500 italic">wie {{ bookingDto.isInternalAgencyBooking() ? 'Teilnehmer:in 1' : 'Anmelder:in' }}</td>
<td class="border border-primary-bg p-2 align-top w-24"></td>
<td class="border border-primary-bg p-2 align-top w-12"></td>
</tr>
</table>
{% endif %}
</fieldset>
</div>
{% else %}
<div class="pb-4">
<fieldset class="border border-primary-bg">
<legend class="{{ html_classes('w-full bg-primary-bg p-2 font-semibold uppercase', { 'text-red-500': form.insurance is defined and not form.insurance.vars.valid }) }}">
Reiseversicherung*
</legend>
{% if form.insurance is defined %}
<table class="w-full table-fixed border-collapse">
{% if form.bulkInsuranceBooking is defined %}
{{ macros.checkbox_row(
form.bulkInsuranceBooking,
form.bulkInsuranceBooking.vars.label,
null,
form.bulkInsuranceBooking.vars.attr['data-description']|default(null),
'Info',
htmxAttr,
false
) }}
{% endif %}
{% for child in form.insurance %}
{% set choiceData = form.insurance.vars.choices[loop.index0].data %}
{{ macros.insurance_choice_row(child, choiceData, htmxAttr) }}
{% endfor %}
</table>
{% else %}
<div class="p-2 text-sm text-gray-500">Nicht wählbar</div>
{% endif %}
</fieldset>
{% if form.insurance is defined %}
{{ form_errors(form.insurance) }}
{{ form_help(form.insurance) }}
{% endif %}
</div>
{% endif %}
{% endif %}
{# Transportation Services Section #}
<h3 class="font-semibold text-lg mb-4">
Anreise
</h3>
{% if form.transportationOutbound is defined %}
<div class="pb-4">
<fieldset class="border border-primary-bg">
<legend class="{{ html_classes('w-full bg-primary-bg p-2 font-semibold uppercase', { 'text-red-500': not form.transportationOutbound.vars.valid }) }}">
{{ form.transportationOutbound.vars.label }}
{% if form.transportationOutbound.vars.required %}<span>*</span>{% endif %}
</legend>
<table class="w-full table-fixed border-collapse">
{% for child in form.transportationOutbound %}
{% set choiceData = form.transportationOutbound.vars.choices[loop.index0].data %}
{% set isPkw = choiceData.subType is defined and choiceData.subType in ['PKW', 'CAR'] %}
{{ macros.service_choice_row(child, choiceData.price|default(null), child.vars.attr['data-description']|default(null), 'Details', htmxAttr, not isPkw) }}
{% endfor %}
{% if form.parking is defined %}
{% set parkingService = bookingDto.travel.getAdditionalServicesBySubTypes(constant('App\\BusProNet\\Constants::TOKEN_PARKING'))|first %}
{{ macros.checkbox_row(
form.parking,
'Parkplatz',
parkingService.price|default(null),
null,
null,
htmxAttr
) }}
{% endif %}
</table>
</fieldset>
{{ form_errors(form.transportationOutbound) }}
{{ form_help(form.transportationOutbound) }}
</div>
{% endif %}
{% if form.transportationInbound is defined %}
{{ form_row(form.transportationInbound, {
'attr': {
'hx-trigger': htmx_change_trigger,
'hx-post': path(refreshRouteName, refreshRouteParams|default({index: participantIndex})),
'hx-target': '#main-content', 'hx-swap': 'innerHTML'
}
}) }}
{% endif %}
{% if form.pickup is defined %}
{{ form_row(form.pickup, {
'attr': {
'hx-trigger': htmx_change_trigger,
'hx-post': path(refreshRouteName, refreshRouteParams|default({index: participantIndex})),
'hx-target': '#main-content', 'hx-swap': 'innerHTML'
}
}) }}
{% endif %}
{% if form.licensePlate is defined %}
{{ form_row(form.licensePlate) }}
{% endif %}
{% endif %}
{# Voucher fields - available for all participants regardless of eligibility #}
{% if form.purchaseVoucherCode is defined or form.promoVoucherCode is defined %}
<h3 class="font-semibold text-lg mb-4">
Gutscheine
</h3>
<div class="grid lg:grid-cols-2 lg:gap-x-4">
{% if form.purchaseVoucherCode is defined %}
{{ form_row(form.purchaseVoucherCode) }}
{% endif %}
{% if form.promoVoucherCode is defined %}
{{ form_row(form.promoVoucherCode) }}
{% endif %}
</div>
{% endif %}
</div>
{% endblock %}
{# Sidebar summary with conditional OOB swap - only render for HTMX requests #}
{% if htmx_oob_swap|default(false) %}
{% block booking_summary %}
<div id="booking-summary" hx-swap-oob="innerHTML">
{% include 'booking/_summary.html.twig' with {
'bookingCreateDto': bookingDto,
'summaryData': summaryData,
'mutableData': mutableData|default(null)
} %}
</div>
{% endblock %}
{% endif %}