224 lines
14 KiB
Twig
224 lines
14 KiB
Twig
{% extends 'layout_booking.html.twig' %}
|
|
|
|
{% block title %}Schritt 2: Personen & Leistungen{% endblock %}
|
|
|
|
{% block background %}bg-outer bg-outer--summer{% endblock %}
|
|
|
|
{% block content %}
|
|
{% form_theme form 'booking/_form_theme.html.twig' %}
|
|
|
|
{{ form_start(form, {
|
|
'attr': {
|
|
'class': 'flex-1 flex flex-col min-h-0',
|
|
}
|
|
}) }}
|
|
|
|
{# Pagination - mobile only (above summary) #}
|
|
<div class="lg:hidden">
|
|
{% include 'groups/booking/_pagination.html.twig' with { 'current_step': 2 } %}
|
|
</div>
|
|
|
|
<div class="flex-1 flex flex-col lg:grid lg:grid-cols-5 min-h-0 relative">
|
|
|
|
{# Sidebar summary #}
|
|
{% block accommodation_summary %}
|
|
<div id="accommodation-summary"
|
|
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' }) }}
|
|
{% if htmx_oob_swap is defined and htmx_oob_swap %}hx-swap-oob="true"{% endif %}>
|
|
{% include 'groups/booking/_summary.html.twig' with { 'dto': dto, 'ctx': ctx } %}
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{# Main form #}
|
|
{% block accommodation_form %}
|
|
<div id="accommodation-form"
|
|
class="flex-1 order-2 lg:order-1 lg:col-span-3 bg-white flex flex-col min-h-0"
|
|
{% if htmx_oob_swap is defined and htmx_oob_swap %}hx-swap-oob="true"{% endif %}>
|
|
|
|
{% 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': 2 } %}
|
|
</div>
|
|
|
|
<div id="participant-form"
|
|
class="flex-1 overflow-y-auto px-4 lg:px-8 py-8"
|
|
hx-post="{{ path('app_groups_booking_step_2_refresh') }}"
|
|
hx-trigger="change delay:300ms"
|
|
hx-swap="none">
|
|
|
|
{# Validation errors #}
|
|
{% from '_partials/_validation_errors.html.twig' import validation_alert %}
|
|
{{ validation_alert(form) }}
|
|
|
|
{% if dto.isInquiry %}
|
|
{% include '_partials/_alert.html.twig' with {
|
|
level: 'warning',
|
|
title: 'Diese Buchung wird als unverbindliche Anfrage behandelt',
|
|
messages: dto.inquiryReasons
|
|
} %}
|
|
{% endif %}
|
|
|
|
{# Pax counts #}
|
|
<h2 class="pb-4">
|
|
Personenanzahl und gewünschte Leistungen
|
|
</h2>
|
|
|
|
<div class="grid lg:grid-cols-3 lg:gap-x-8">
|
|
{{ form_row(form.paxCount) }}
|
|
{{ form_row(form.minorsCount) }}
|
|
{{ form_row(form.childrenCount) }}
|
|
</div>
|
|
|
|
{# Board services — rendered manually so price is formatted in Twig #}
|
|
{% do form.selectedBoardServiceId.setRendered %}
|
|
{% if ctx.boardServices is not empty %}
|
|
<div class="pb-4">
|
|
<fieldset class="border border-primary-bg">
|
|
<legend class="w-full bg-primary-bg p-2 font-semibold uppercase">
|
|
Verpflegungsleistungen
|
|
</legend>
|
|
<table class="w-full table-fixed border-collapse">
|
|
{% for service in ctx.boardServices %}
|
|
<tr>
|
|
<td class="border border-primary-bg p-2 align-top">
|
|
<label for="board_service_{{ service.id }}" class="cursor-pointer">{{ service.label }}</label>
|
|
{% if service.description %}
|
|
<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">{{ service.description|nl2br }}</div>
|
|
</template>
|
|
</div>
|
|
{% endif %}
|
|
</td>
|
|
<td class="border border-primary-bg p-2 align-top w-32 text-right">
|
|
<div>{% if service.price == 0 %}inkl.{% else %}{{ (service.price / 100)|format_currency(ctx.accommodation.currency) }}{% endif %}</div>
|
|
{% if service.price != 0 %}
|
|
<div class="text-xs text-gray-500">pro Person und Nacht</div>
|
|
{% endif %}
|
|
</td>
|
|
<td class="border border-primary-bg p-2 align-top w-12 text-center">
|
|
<input type="radio"
|
|
id="board_service_{{ service.id }}"
|
|
name="{{ form.selectedBoardServiceId.vars.full_name }}"
|
|
value="{{ service.id }}"
|
|
{% if dto.selectedBoardServiceId == service.id %}checked{% endif %}
|
|
class="form-radio">
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</table>
|
|
</fieldset>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{# Additional services — rendered manually to support checkbox/radio mix #}
|
|
{% do form.selectedAdditionalServiceIds.setRendered %}
|
|
{% set selectedAdditionalServiceBaseName = form.selectedAdditionalServiceIds.vars.full_name|replace({'[]': ''}) %}
|
|
|
|
{% if ctx.ungroupedAdditionalServices is not empty or ctx.groupedAdditionalServices is not empty %}
|
|
|
|
{# Ungrouped → checkboxes #}
|
|
{% if ctx.ungroupedAdditionalServices is not empty %}
|
|
<div class="pb-4">
|
|
<fieldset class="border border-primary-bg">
|
|
<legend class="w-full bg-primary-bg p-2 font-semibold uppercase">
|
|
Optionale Zusatzleistungen
|
|
</legend>
|
|
<table class="w-full table-fixed border-collapse">
|
|
{% for service in ctx.ungroupedAdditionalServices %}
|
|
<tr>
|
|
<td class="border border-primary-bg p-2 align-top">
|
|
<label for="add_service_{{ service.id }}" class="cursor-pointer">{{ service.label }}</label>
|
|
{% if service.description %}
|
|
<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">{{ service.description|nl2br }}</div>
|
|
</template>
|
|
</div>
|
|
{% endif %}
|
|
</td>
|
|
<td class="border border-primary-bg p-2 align-top w-32 text-right">
|
|
<div>{% if service.price == 0 %}inkl.{% else %}{{ (service.price / 100)|format_currency(ctx.accommodation.currency) }}{% endif %}</div>
|
|
<div class="text-xs text-gray-500">{{ service.type.label | trans }}</div>
|
|
</td>
|
|
<td class="border border-primary-bg p-2 align-top w-12 text-center">
|
|
<input type="checkbox"
|
|
id="add_service_{{ service.id }}"
|
|
name="{{ form.selectedAdditionalServiceIds.vars.full_name }}"
|
|
value="{{ service.id }}"
|
|
{% if service.id in dto.selectedAdditionalServiceIds %}checked{% endif %}
|
|
class="form-checkbox">
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</table>
|
|
</fieldset>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{# Grouped → radio buttons per group, one fieldset per group #}
|
|
{% for groupName, services in ctx.groupedAdditionalServices %}
|
|
<div class="pb-4">
|
|
<fieldset class="border border-primary-bg">
|
|
<legend class="w-full bg-primary-bg p-2 font-semibold uppercase">{{ groupName }}</legend>
|
|
<table class="w-full table-fixed border-collapse">
|
|
{% for service in services %}
|
|
<tr>
|
|
<td class="border border-primary-bg p-2 align-top">
|
|
<label for="add_service_{{ service.id }}" class="cursor-pointer">{{ service.label }}</label>
|
|
{% if service.description %}
|
|
<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">{{ service.description|nl2br }}</div>
|
|
</template>
|
|
</div>
|
|
{% endif %}
|
|
</td>
|
|
<td class="border border-primary-bg p-2 align-top w-32 text-right">
|
|
<div>{% if service.price == 0 %}inkl.{% else %}{{ (service.price / 100)|format_currency(ctx.accommodation.currency) }}{% endif %}</div>
|
|
<div class="text-xs text-gray-500">{{ service.type.label | trans }}</div>
|
|
</td>
|
|
<td class="border border-primary-bg p-2 align-top w-12 text-center">
|
|
<input type="radio"
|
|
id="add_service_{{ service.id }}"
|
|
name="{{ selectedAdditionalServiceBaseName }}[{{ groupName|e('html_attr') }}]"
|
|
value="{{ service.id }}"
|
|
{% if service.id in dto.selectedAdditionalServiceIds %}checked{% endif %}
|
|
class="form-radio">
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</table>
|
|
</fieldset>
|
|
</div>
|
|
{% endfor %}
|
|
|
|
{% endif %}
|
|
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
</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_1') }}" class="button button--secondary">
|
|
Zurück
|
|
</a>
|
|
<button type="submit" class="button button--primary">
|
|
Weiter zu Schritt 3
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{{ form_rest(form) }}
|
|
{{ form_end(form) }}
|
|
{% endblock %}
|