feat: implement screendesign
This commit is contained in:
@@ -1,193 +1,240 @@
|
||||
<div class="booking-summary p-8 bg-gray-50 rounded-lg border sticky top-4">
|
||||
<h3 class="font-bold text-xl mb-6 text-gray-800">Buchungsübersicht</h3>
|
||||
|
||||
{# Inquiry booking notification #}
|
||||
{% if bookingCreateDto is defined and bookingCreateDto.isInquiryBooking() %}
|
||||
<div class="mb-4 p-3 bg-yellow-50 border border-yellow-200 rounded text-sm text-yellow-800">
|
||||
<span class="font-semibold">Anfragebuchung:</span> Diese Reise ist ausgebucht. Ihre Buchung wird als Anfrage verarbeitet.
|
||||
<div class="bg-white h-full flex flex-col lg:border-l lg:border-primary-bg">
|
||||
{# Header - always visible #}
|
||||
<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="flex items-center justify-between pb-2">
|
||||
<span class="block uppercase font-semibold">Gesamtpreis</span>
|
||||
<span class="font-semibold">{{ summaryData.payableAmount|format_currency('EUR') }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Mutability information (edit mode only) #}
|
||||
{% if bookingCreateDto.mode == constant('App\\Form\\Model\\BookingDto::MODE_EDIT') and mutableData %}
|
||||
<div class="mb-6 pb-4 border-b border-gray-200">
|
||||
<h4 class="font-semibold text-lg mb-3 text-gray-800">Aktualisierung möglich bis</h4>
|
||||
<ul class="space-y-1 text-sm text-gray-600">
|
||||
<li class="flex items-start">
|
||||
<span class="mr-2">•</span>
|
||||
<span>
|
||||
<span class="font-medium">Zusatzleistungen:</span>
|
||||
{% if mutableData.items['additional_services'].mutable %}
|
||||
{{ mutableData.items['additional_services'].mutableBefore|date('d.m.Y') }}
|
||||
{% else %}
|
||||
<span class="text-red-600">nicht mehr möglich</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
</li>
|
||||
<li class="flex items-start">
|
||||
<span class="mr-2">•</span>
|
||||
<span>
|
||||
<span class="font-medium">Beförderung:</span>
|
||||
{% if mutableData.items['transportation'].mutable %}
|
||||
{{ mutableData.items['transportation'].mutableBefore|date('d.m.Y') }}
|
||||
{% else %}
|
||||
<span class="text-red-600">nicht mehr möglich</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
</li>
|
||||
<li class="flex items-start">
|
||||
<span class="mr-2">•</span>
|
||||
<span>
|
||||
<span class="font-medium">Zustiege:</span>
|
||||
{% if mutableData.items['pickup'].mutable %}
|
||||
{{ mutableData.items['pickup'].mutableBefore|date('d.m.Y') }}
|
||||
{% else %}
|
||||
<span class="text-red-600">nicht mehr möglich</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Travel Information #}
|
||||
<div class="mb-6 pb-4 border-b border-gray-200">
|
||||
{% if summaryData.cmsData.hotel.images is defined %}
|
||||
<img src="{{ summaryData.cmsData.hotel.images.resized.l[0].url }}" alt="{{ summaryData.cmsData.hotel.images.resized.s[0].alt }}" class="w-full rounded mb-4">
|
||||
{% endif %}
|
||||
<div class="space-y-2 text-sm text-gray-600">
|
||||
<div><span class="font-medium">Reise:</span> {{ bookingCreateDto.travel.label }}</div>
|
||||
{% if summaryData.cmsData.region is defined %}
|
||||
<div><span class="font-medium">Gebiet:</span> {{ summaryData.cmsData.region.name }}</div>
|
||||
{% endif %}
|
||||
{% if summaryData.cmsData.country is defined %}
|
||||
<div><span class="font-medium">Land:</span> {{ summaryData.cmsData.country.name }}</div>
|
||||
{% endif %}
|
||||
<div><span class="font-medium">Zeitraum:</span> {{ bookingCreateDto.travel.dateFrom|date('d.m.Y') }} - {{ bookingCreateDto.travel.dateTo|date('d.m.Y') }}</div>
|
||||
<div><span class="font-medium">Unterkunft:</span> {{ bookingCreateDto.travel.hotel.name }}{% if summaryData.cmsData.hotel.address is defined %}, {{ summaryData.cmsData.hotel.address | replace({"\n": ', '}) }}{% endif %}</div>
|
||||
<div><span class="font-medium">Anzahl Teilnehmer:</span> {{ summaryData.participantCount }}</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="block uppercase font-semibold">Buchungsü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>
|
||||
|
||||
{# Rooms Section #}
|
||||
{% if summaryData.pricingData.rooms is not empty %}
|
||||
<div class="mb-6 pb-4 border-b border-gray-200">
|
||||
<h4 class="font-semibold text-lg mb-3 text-gray-800">Unterkunft</h4>
|
||||
<div class="space-y-2">
|
||||
{% for roomPricing in summaryData.pricingData.rooms %}
|
||||
<div class="flex justify-between items-start">
|
||||
<div class="text-sm text-gray-600">
|
||||
<span class="font-medium">{{ roomPricing.quantity }}x {{ roomPricing.label }}</span>
|
||||
{% if summaryData.assignmentCounts[roomPricing.roomId] is defined %}
|
||||
<span class="block text-xs text-gray-500">{{ summaryData.assignmentCounts[roomPricing.roomId] }} belegt</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div class="text-gray-900">
|
||||
€{{ roomPricing.totalPrice|number_format(2, ',', '.') }}
|
||||
</div>
|
||||
<div class="text-xs text-gray-500">
|
||||
€{{ roomPricing.unitPrice|number_format(2, ',', '.') }} pro Person
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{# Content - toggleable on mobile, always visible on desktop #}
|
||||
<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">
|
||||
{# Travel Information #}
|
||||
<div class="pb-4">
|
||||
<table>
|
||||
<tr>
|
||||
<th class="text-left align-top border-r-2 border-gray-300 pr-2">
|
||||
Reise
|
||||
</th>
|
||||
<td class="pl-2">
|
||||
{{ bookingCreateDto.travel.label }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="text-left align-top border-r-2 border-gray-300 pr-2">
|
||||
Zeitraum
|
||||
</th>
|
||||
<td class="pl-2">
|
||||
{{ bookingCreateDto.travel.dateFrom|date('d.m.Y') }} - {{ bookingCreateDto.travel.dateTo|date('d.m.Y') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="text-left align-top border-r-2 border-gray-300 pr-2">
|
||||
Unterkunft
|
||||
</th>
|
||||
<td class="pl-2">
|
||||
{{ bookingCreateDto.travel.hotel.name }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="text-left align-top border-r-2 border-gray-300 pr-2">
|
||||
Teilnehmer
|
||||
</th>
|
||||
<td class="pl-2">
|
||||
{{ summaryData.participantCount }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Services Section #}
|
||||
{% if summaryData.pricingData.services is not empty %}
|
||||
<div class="mb-6">
|
||||
<h4 class="font-semibold text-lg mb-3 text-gray-800">Leistungen</h4>
|
||||
{% for serviceGroup in summaryData.pricingData.services %}
|
||||
<div class="mb-4 last:mb-0">
|
||||
<h5 class="font-medium text-sm text-gray-700 mb-2 uppercase tracking-wide">{{ serviceGroup.groupName }}</h5>
|
||||
<div class="space-y-1 ml-4">
|
||||
{% for servicePricing in serviceGroup.services %}
|
||||
<div class="flex justify-between items-center text-sm">
|
||||
<span class="text-gray-600">
|
||||
{{ servicePricing.participantCount }}x {{ servicePricing.label }}
|
||||
</span>
|
||||
<span class="font-medium text-gray-900">
|
||||
€{{ servicePricing.totalPrice|number_format(2, ',', '.') }}
|
||||
</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% include 'booking/_summary_hotel.html.twig' %}
|
||||
|
||||
{# Inquiry booking notification #}
|
||||
{% if bookingCreateDto is defined and bookingCreateDto.isInquiryBooking() %}
|
||||
<div>
|
||||
Deine Buchung wird als Anfrage verarbeitet.
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Mutability information (edit mode only) #}
|
||||
{% if bookingCreateDto.mode == constant('App\\Form\\Model\\BookingDto::MODE_EDIT') and mutableData %}
|
||||
<div class="border border-primary-bg mb-4">
|
||||
<div class="p-2 bg-primary-bg uppercase font-semibold">
|
||||
Aktualisierung möglich bis
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<table class="w-full table-fixed">
|
||||
<tr>
|
||||
<td class="p-2 align-top">
|
||||
Zusatzleistungen
|
||||
</td>
|
||||
<td class="p-2 align-top w-24 text-right whitespace-nowrap">
|
||||
{% if mutableData.items['additional_services'].mutable %}
|
||||
{{ mutableData.items['additional_services'].mutableBefore|date('d.m.Y') }}
|
||||
{% else %}
|
||||
nicht mehr möglich
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="p-2 align-top">
|
||||
Beförderung
|
||||
</td>
|
||||
<td class="p-2 align-top w-24 text-right whitespace-nowrap">
|
||||
{% if mutableData.items['transportation'].mutable %}
|
||||
{{ mutableData.items['transportation'].mutableBefore|date('d.m.Y') }}
|
||||
{% else %}
|
||||
nicht mehr möglich
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="p-2 align-top">
|
||||
Zustiege
|
||||
</td>
|
||||
<td class="p-2 align-top w-24 text-right whitespace-nowrap">
|
||||
{% if mutableData.items['pickup'].mutable %}
|
||||
{{ mutableData.items['pickup'].mutableBefore|date('d.m.Y') }}
|
||||
{% else %}
|
||||
nicht mehr möglich
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Surcharges Section (Edit mode only) #}
|
||||
{% if summaryData.pricingData.surcharges is defined and summaryData.pricingData.surcharges is not empty %}
|
||||
<div class="mb-6 pb-4 border-b border-gray-200">
|
||||
<h4 class="font-semibold text-lg mb-3 text-gray-800">Zuschläge</h4>
|
||||
<div class="space-y-1">
|
||||
{% for surchargePricing in summaryData.pricingData.surcharges %}
|
||||
<div class="flex justify-between items-center text-sm">
|
||||
<span class="text-gray-600">
|
||||
{{ surchargePricing.participantCount }}x {{ surchargePricing.label }}
|
||||
</span>
|
||||
<span class="font-medium text-gray-900">
|
||||
€{{ surchargePricing.totalPrice|number_format(2, ',', '.') }}
|
||||
</span>
|
||||
{# Rooms Section #}
|
||||
{% if summaryData.pricingData.rooms is not empty %}
|
||||
<div class="border border-primary-bg mb-4">
|
||||
<div class="p-2 bg-primary-bg uppercase font-semibold">
|
||||
Unterkunft
|
||||
</div>
|
||||
<table class="w-full table-fixed">
|
||||
{% for roomPricing in summaryData.pricingData.rooms %}
|
||||
<tr>
|
||||
<td class="p-2 align-top">
|
||||
<div>{{ roomPricing.quantity }}x {{ roomPricing.label }}</div>
|
||||
{% if summaryData.assignmentCounts[roomPricing.roomId] is defined %}
|
||||
<div class="text-sm text-gray-600">{{ summaryData.assignmentCounts[roomPricing.roomId] }}x Erwachsener</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="p-2 align-top w-24 text-right whitespace-nowrap">
|
||||
{{ roomPricing.totalPrice | format_currency('EUR') }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Services Section #}
|
||||
{% if summaryData.pricingData.services is not empty %}
|
||||
<div class="border border-primary-bg mb-4">
|
||||
<div class="p-2 bg-primary-bg uppercase font-semibold">
|
||||
Leistungen
|
||||
</div>
|
||||
{% for serviceGroup in summaryData.pricingData.services %}
|
||||
<div class="p-2 text-primary-dark/70 uppercase font-semibold">
|
||||
{{ serviceGroup.groupName }}
|
||||
</div>
|
||||
<table class="w-full table-fixed">
|
||||
{% for servicePricing in serviceGroup.services %}
|
||||
<tr>
|
||||
<td class="px-2 pb-2 align-top">
|
||||
{{ servicePricing.participantCount }}x {{ servicePricing.label }}
|
||||
</td>
|
||||
<td class="px-2 pb-2 align-top w-24 text-right whitespace-nowrap">
|
||||
{{ servicePricing.totalPrice | format_currency('EUR') }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{# Total Section #}
|
||||
{% if summaryData.pricingData.grandTotal is defined and summaryData.pricingData.grandTotal > 0 %}
|
||||
<div class="pt-4 border-t-2 border-gray-300">
|
||||
{# Surcharges Section (Edit mode only) #}
|
||||
{% if summaryData.pricingData.surcharges is defined and summaryData.pricingData.surcharges is not empty %}
|
||||
<div class="border border-primary-bg mb-4">
|
||||
<div class="p-2 bg-primary-bg uppercase font-semibold">
|
||||
Zu-/Abschläge
|
||||
</div>
|
||||
<table class="w-full table-fixed">
|
||||
{% for surchargePricing in summaryData.pricingData.surcharges %}
|
||||
<tr>
|
||||
<td class="px-2 pb-2 align-top">
|
||||
{{ surchargePricing.participantCount }}x {{ surchargePricing.label }}
|
||||
</td>
|
||||
<td class="px-2 pb-2 align-top w-24 text-right whitespace-nowrap">
|
||||
{{ surchargePricing.totalPrice|format_currency('EUR') }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Total Section #}
|
||||
{% if summaryData.totalPrice > 0 %}
|
||||
{# Show subtotal and voucher discounts when vouchers are applied #}
|
||||
{% set acceptedVouchers = bookingCreateDto.getAcceptedVouchers() %}
|
||||
{% if acceptedVouchers and acceptedVouchers.hasVouchers() %}
|
||||
{# Subtotal before vouchers #}
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<span class="text-gray-600">Gesamtpreis:</span>
|
||||
<span class="text-gray-900">
|
||||
€{{ summaryData.pricingData.grandTotal|number_format(2, ',', '.') }}
|
||||
</span>
|
||||
<div class="border border-primary-bg mb-4">
|
||||
<div class="p-2 bg-primary-bg uppercase font-semibold">
|
||||
Kostenübersicht
|
||||
</div>
|
||||
<table class="w-full table-fixed">
|
||||
{# Subtotal before vouchers #}
|
||||
<tr>
|
||||
<td class="px-2 pb-2 align-top">
|
||||
Gesamtpreis
|
||||
</td>
|
||||
<td class="px-2 pb-2 align-top w-24 text-right whitespace-nowrap">
|
||||
{{ summaryData.totalPrice|format_currency('EUR') }}
|
||||
</td>
|
||||
</tr>
|
||||
{# Voucher discounts breakdown #}
|
||||
{% for voucher in acceptedVouchers.vouchers %}
|
||||
<tr>
|
||||
<td class="px-2 pb-2 align-top">
|
||||
{% if voucher.promotional %}
|
||||
Aktionsgutschein ({{ voucher.code }})
|
||||
{% elseif voucher.goodwill %}
|
||||
Kulanzgutschein ({{ voucher.code }})
|
||||
{% elseif voucher.purchase %}
|
||||
Kaufgutschein ({{ voucher.code }})
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="px-2 pb-2 align-top w-24 text-right whitespace-nowrap">
|
||||
- {{ voucher.amount|format_currency('EUR') }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{# Voucher discounts breakdown #}
|
||||
<div class="mb-3 space-y-1">
|
||||
{% for voucher in acceptedVouchers.vouchers %}
|
||||
<div class="flex justify-between items-center text-sm">
|
||||
<span class="text-gray-600">
|
||||
{% if voucher.promotional %}
|
||||
Aktionsgutschein ({{ voucher.code }})
|
||||
{% elseif voucher.goodwill %}
|
||||
Kulanzgutschein ({{ voucher.code }})
|
||||
{% elseif voucher.purchase %}
|
||||
Kaufgutschein ({{ voucher.code }})
|
||||
{% endif %}
|
||||
</span>
|
||||
<span class="font-medium text-green-600">
|
||||
-€{{ voucher.amount|number_format(2, ',', '.') }}
|
||||
</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{# Amount to pay after vouchers #}
|
||||
<div class="flex justify-between items-center pt-2 border-t border-gray-200">
|
||||
<span class="font-bold text-lg text-gray-800">Zu zahlen:</span>
|
||||
<span class="font-bold text-xl text-gray-900" {{ qa_attribute('summary-total') }}>
|
||||
€{{ (summaryData.pricingData.grandTotal - acceptedVouchers.totalDiscount)|number_format(2, ',', '.') }}
|
||||
</span>
|
||||
<div class="flex items-center justify-between px-2 pb-2">
|
||||
<span class="block uppercase font-semibold">Zu zahlen</span>
|
||||
<span class="font-semibold">{{ summaryData.payableAmount|format_currency('EUR') }}</span>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="font-bold text-lg text-gray-800">Gesamtpreis:</span>
|
||||
<span class="font-bold text-xl text-gray-900" {{ qa_attribute('summary-total') }}>
|
||||
€{{ summaryData.pricingData.grandTotal|number_format(2, ',', '.') }}
|
||||
</span>
|
||||
<div class="flex items-center justify-between pb-2">
|
||||
<span class="block uppercase font-semibold">Gesamtpreis</span>
|
||||
<span class="font-semibold">{{ summaryData.payableAmount|format_currency('EUR') }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user