wip: finalize offer layout
This commit is contained in:
1 parent
e7bfb19ac9
commit
a1751f699b
20 files changed
+487
-541
No files matched your search
@@ -11,7 +11,7 @@
|
||||
{{ form_row(form.maxAdolescentAge) }}
|
||||
{{ form_row(form.currency) }}
|
||||
</div>
|
||||
{% if cmsData is defined and cmsData.name is defined %}
|
||||
{% if cmsData is not null and cmsData.name is not null %}
|
||||
<div class="space-y-4">
|
||||
{% if cmsData.images.resized.m | length > 0 %}
|
||||
{% set image = cmsData.images.resized.m[0] %}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<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">
|
||||
<div class="shrink-0 px-4 lg:px-8 py-4 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>
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
{# Accommodation info #}
|
||||
{% set hasImage = ctx.hotelCmsData is not null
|
||||
and ctx.hotelCmsData.images is defined
|
||||
and ctx.hotelCmsData.images is not null
|
||||
and ctx.hotelCmsData.images.resized is defined
|
||||
and ctx.hotelCmsData.images.resized.l is defined
|
||||
and ctx.hotelCmsData.images.resized.l[0] is defined %}
|
||||
@@ -45,7 +45,7 @@
|
||||
{% 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 %}
|
||||
{% if ctx.hotelCmsData is not null and ctx.hotelCmsData.address is not null %}
|
||||
<div class="text-sm text-gray-500 mt-1">{{ ctx.hotelCmsData.address|nl2br }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -180,25 +180,17 @@
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if booking.remarks %}
|
||||
<div class="border border-primary-bg mt-4">
|
||||
<div class="p-2 bg-primary-bg uppercase font-semibold">Anmerkungen</div>
|
||||
<div class="p-2 text-sm">
|
||||
{{ booking.remarks | nl2br }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
{# Footer: booking action / accepted-at status #}
|
||||
{% if booking.inquiry %}
|
||||
<div class="shrink-0 px-4 lg:px-8 py-4 border-t border-primary-bg">
|
||||
<button type="button"
|
||||
class="button button--primary w-full"
|
||||
hx-get="{{ path('app_groups_booking_offer_confirm', { uuid: booking.uuid }) }}"
|
||||
hx-target="body"
|
||||
hx-swap="beforeend">
|
||||
Angebot verbindlich buchen
|
||||
</button>
|
||||
</div>
|
||||
{% elseif booking.acceptedAt is not null %}
|
||||
<div class="shrink-0 px-4 lg:px-8 py-4 border-t border-primary-bg">
|
||||
<p class="text-gray-500">
|
||||
Angenommen am {{ booking.acceptedAt | date('d.m.Y') }} um {{ booking.acceptedAt | date('H:i') }} Uhr
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -14,6 +14,9 @@
|
||||
<span class="text-gray-600 font-semibold">Verpflegung:</span>
|
||||
{% if selectedBoardService %}
|
||||
{{ selectedBoardService.label }}
|
||||
{% if selectedBoardService.price > 0 %}
|
||||
— {{ (selectedBoardService.price / 100)|format_currency(ctx.accommodation.currency) }} pro Person und Nacht
|
||||
{% endif %}
|
||||
{% if selectedBoardService.description %}
|
||||
<div class="text-xs text-gray-500">{{ selectedBoardService.description|nl2br }}</div>
|
||||
{% endif %}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
{# Accommodation info #}
|
||||
{% set hasImage = ctx.hotelCmsData is not null
|
||||
and ctx.hotelCmsData.images is defined
|
||||
and ctx.hotelCmsData.images is not null
|
||||
and ctx.hotelCmsData.images.resized is defined
|
||||
and ctx.hotelCmsData.images.resized.l is defined
|
||||
and ctx.hotelCmsData.images.resized.l[0] is defined %}
|
||||
@@ -46,7 +46,7 @@
|
||||
{% 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 %}
|
||||
{% if ctx.hotelCmsData is not null and ctx.hotelCmsData.address is not null %}
|
||||
<div class="text-sm text-gray-500 mt-1">{{ ctx.hotelCmsData.address|nl2br }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
{% extends 'layout_booking.html.twig' %}
|
||||
|
||||
{% macro imageGallery(images, thumbImages, defaultAlt) %}
|
||||
{% if images|length > 0 %}
|
||||
<div class="grid md:grid-cols-2 gap-8" {{ stimulus_controller('gallery') }}>
|
||||
{% for image in images %}
|
||||
<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 ?? defaultAlt }}">
|
||||
<img src="{{ thumbImages[loop.index0].url ?? image.url }}"
|
||||
alt="{{ image.alt ?? defaultAlt }}"
|
||||
class="block w-full h-auto">
|
||||
{% if loop.index0 == 1 and images|length > 2 %}
|
||||
<div class="absolute inset-0 bg-black/50 flex items-center justify-center text-white font-bold text-lg">
|
||||
+{{ images|length - 2 }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% import _self as macros %}
|
||||
|
||||
{% block title %}{{ booking.inquiry ? 'Dein Angebot' : 'Deine Buchung' }}{% endblock %}
|
||||
|
||||
{% block background %}bg-outer bg-outer--summer{% endblock %}
|
||||
@@ -23,18 +47,25 @@
|
||||
</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">
|
||||
<div class="flex-1 order-2 lg:order-1 lg:col-span-3 bg-white flex flex-col gap-y-8 min-h-0 overflow-y-auto px-4 lg:px-8 py-8">
|
||||
{% include '_partials/_flashes.html.twig' %}
|
||||
|
||||
<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>
|
||||
<hgroup>
|
||||
<h1 class="text-2xl lg:text-4xl font-bold mb-2">
|
||||
{{ booking.inquiry ? 'Dein Angebot' : 'Deine Buchung' }}
|
||||
</h1>
|
||||
<p class="text-2xl">
|
||||
{{ ctx.accommodation.name }}
|
||||
</p>
|
||||
</hgroup>
|
||||
|
||||
{# 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">
|
||||
<div>
|
||||
<h2 class="text-xl font-bold mb-2">
|
||||
{{ booking.inquiry ? 'Angefragte' : 'Gebuchte' }} Leistungen
|
||||
</h2>
|
||||
<ul class="list-disc pl-4">
|
||||
{% if booking.boardServiceLabel %}
|
||||
<li>{{ booking.boardServiceLabel }}</li>
|
||||
{% endif %}
|
||||
@@ -45,150 +76,141 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if booking.inquiry %}
|
||||
<div>
|
||||
<button type="button"
|
||||
class="button button--primary w-full"
|
||||
hx-get="{{ path('app_groups_booking_offer_confirm', { uuid: booking.uuid }) }}"
|
||||
hx-target="body"
|
||||
hx-swap="beforeend">
|
||||
Angebot verbindlich buchen
|
||||
</button>
|
||||
</div>
|
||||
{% elseif booking.acceptedAt is not null %}
|
||||
<div class="flex items-center space-x-2">
|
||||
{{ icon('info', 'w-5 h-5') }}
|
||||
<div class="text-gray-500">
|
||||
Angebot angenommen am {{ booking.acceptedAt | date('d.m.Y') }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# hotel description #}
|
||||
{% 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 {{ stimulus_controller('toggle', { 'open': false }, { 'closed': 'hidden', 'iconOpen': 'rotate-180' }) }}>
|
||||
<button type="button"
|
||||
class="flex items-center justify-between w-full text-left"
|
||||
data-action="toggle#toggle">
|
||||
<h2>
|
||||
Die Unterkunft
|
||||
</h2>
|
||||
<svg class="w-5 h-5 shrink-0 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 class="rte-content" data-toggle-target="content">
|
||||
{% set icons = ctx.hotelCmsData.icons %}
|
||||
{% if icons is not empty %}
|
||||
<ul class="grid grid-cols-2 md:grid-cols-3 gap-2">
|
||||
{% for icon, label in icons %}
|
||||
<li class="flex items-center gap-2">
|
||||
<div class="border-2 border-gray-900 rounded-full w-16 h-16 flex flex-col items-center justify-center">
|
||||
{{ icon(icon, 'w-8 h-8 shrink-0 text-gray-900') }}
|
||||
</div>
|
||||
{{ label }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{{ 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 }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% set visibleIcons = (ctx.hotelCmsData.icons ?? null) | visible_cms_icons %}
|
||||
{% if visibleIcons is not empty %}
|
||||
<ul class="grid grid-cols-2 md:grid-cols-3 gap-2 mt-6 text-sm text-gray-600">
|
||||
{% for item in visibleIcons %}
|
||||
<li class="flex items-center gap-2">
|
||||
{{ icon(item.key, 'w-5 h-5 shrink-0') }}
|
||||
{{ item.label }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{{ macros.imageGallery(ctx.hotelCmsData.images.resized.l, ctx.hotelCmsData.images.resized.m, ctx.accommodation.name) }}
|
||||
{% endif %}
|
||||
|
||||
{% if ctx.hotelCmsData is not null and ctx.hotelCmsData.region is defined %}
|
||||
{# region description #}
|
||||
{% if ctx.hotelCmsData is not null and ctx.hotelCmsData.region is not null %}
|
||||
{% set region = ctx.hotelCmsData.region %}
|
||||
<div class="rte-content mt-8">
|
||||
<h2>Die Region {{ region.name }}</h2>
|
||||
{% if region.altitude or region.length or region.lifts %}
|
||||
<ul class="flex flex-wrap gap-x-6 text-sm not-prose">
|
||||
{% if region.altitude %}
|
||||
<li>{{ region.altitude }} m Höhe</li>
|
||||
{% endif %}
|
||||
{% if region.length %}
|
||||
<li>{{ region.length }} km Pisten</li>
|
||||
{% endif %}
|
||||
{% if region.lifts %}
|
||||
<li>{{ region.lifts }} Lifte</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% if region.webcam %}
|
||||
<p>
|
||||
<a href="{{ region.webcam }}" target="_blank" rel="noopener">Webcam der Region</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
{{ region.description | default('') | raw }}
|
||||
<h2>Skigebiet</h2>
|
||||
{{ region.ski_area | default('') | raw }}
|
||||
{{ region.ski_area_extended | default('') | raw }}
|
||||
{% if region.news %}
|
||||
<h2>Aktuelles aus der Region</h2>
|
||||
{{ region.news | raw }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if region.region_maps is defined and region.region_maps | length > 0 %}
|
||||
<div class="grid md:grid-cols-2 gap-8 mt-6" {{ stimulus_controller('gallery') }}>
|
||||
{% for mapUrl in region.region_maps %}
|
||||
<div class="relative block w-full h-auto cursor-pointer{{ loop.index0 >= 2 ? ' hidden' : '' }}"
|
||||
data-gallery-target="item"
|
||||
data-gallery-href="{{ mapUrl }}"
|
||||
data-gallery-alt="{{ region.name }}">
|
||||
<img src="{{ mapUrl }}" alt="{{ region.name }}" class="block w-full h-auto">
|
||||
{% if loop.index0 == 1 and region.region_maps | length > 2 %}
|
||||
<div class="absolute inset-0 bg-black/50 flex items-center justify-center text-white font-bold text-lg">
|
||||
+{{ region.region_maps | length - 2 }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% set regionLargeImages = region.images.resized.l ?? [] %}
|
||||
{% set regionMediumImages = region.images.resized.m ?? [] %}
|
||||
{% if regionLargeImages | length > 0 %}
|
||||
<div class="grid md:grid-cols-2 gap-8 mt-6" {{ stimulus_controller('gallery') }}>
|
||||
{% for image in regionLargeImages %}
|
||||
<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 ?? region.name }}">
|
||||
<img src="{{ regionMediumImages[loop.index0].url ?? image.url }}"
|
||||
alt="{{ image.alt ?? region.name }}"
|
||||
class="block w-full h-auto">
|
||||
{% if loop.index0 == 1 and regionLargeImages | length > 2 %}
|
||||
<div class="absolute inset-0 bg-black/50 flex items-center justify-center text-white font-bold text-lg">
|
||||
+{{ regionLargeImages | length - 2 }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<div {{ stimulus_controller('toggle', { 'open': false }, { 'closed': 'hidden', 'iconOpen': 'rotate-180' }) }}>
|
||||
<button type="button"
|
||||
class="flex items-center justify-between w-full text-left"
|
||||
data-action="toggle#toggle">
|
||||
<h2>
|
||||
Die Region {{ region.name }}
|
||||
</h2>
|
||||
<svg class="w-5 h-5 shrink-0 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>
|
||||
|
||||
{% 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 class="rte-content" data-toggle-target="content">
|
||||
{% if region.altitude or region.length or region.lifts %}
|
||||
<ul class="flex flex-wrap gap-x-6 text-sm not-prose">
|
||||
{% if region.altitude %}
|
||||
<li>{{ region.altitude }} m Höhe</li>
|
||||
{% endif %}
|
||||
{% if region.length %}
|
||||
<li>{{ region.length }} km Pisten</li>
|
||||
{% endif %}
|
||||
{% if region.lifts %}
|
||||
<li>{{ region.lifts }} Lifte</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% if region.webcam %}
|
||||
<p>
|
||||
<a href="{{ region.webcam }}" target="_blank" rel="noopener">Webcam der Region</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
{{ region.description | default('') | raw }}
|
||||
|
||||
<h2>
|
||||
Skigebiet
|
||||
</h2>
|
||||
{{ region.skiArea | default('') | raw }}
|
||||
{{ region.skiAreaExtended | default('') | raw }}
|
||||
|
||||
{% if region.news %}
|
||||
<h2>Aktuelles aus der Region</h2>
|
||||
{{ region.news | raw }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if region.regionMaps is not null and region.regionMaps | length > 0 %}
|
||||
{% set regionMapImages = region.regionMaps | map(url => {url: url}) %}
|
||||
{{ macros.imageGallery(regionMapImages, [], region.name) }}
|
||||
{% endif %}
|
||||
|
||||
{{ macros.imageGallery(region.images.resized.l ?? [], region.images.resized.m ?? [], region.name) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{% 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.'],
|
||||
} %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
Reference in new issue
Block a user