feat: htmx powered requests, improved loading indicator
feat: loading indicator and htmx form submit
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
<div class="invisible fixed top-0 left-0 inset-0 z-10 bg-white/90 flex items-center justify-center"
|
||||
<div class="invisible fixed top-0 left-0 inset-0 z-10 bg-white/90 flex items-center justify-center transition-all duration-100"
|
||||
{{ stimulus_target('loading', 'indicator') }}>
|
||||
{% include '_partials/_spinner.html.twig' with { 'class': 'w-32 h-32 lg:w-48 lg:h-48'} %}
|
||||
</div>
|
||||
|
||||
@@ -17,56 +17,62 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="grid grid-cols-3 gap-8">
|
||||
<div class="col-span-2">
|
||||
<div id="form-wrapper" class="col-span-2">
|
||||
<h2 class="pb-4">
|
||||
Unterkunft
|
||||
</h2>
|
||||
{{ form_start(form) }}
|
||||
{{ form_errors(form) }}
|
||||
{% if groupedRooms.by_room is not empty %}
|
||||
<h3>
|
||||
Zimmer
|
||||
</h3>
|
||||
{% for roomId, room in groupedRooms.by_room %}
|
||||
{{ form_row(form.roomSelections[roomId], {
|
||||
'attr': {
|
||||
'hx-post': path('app_booking_create_step_1_room_summary'),
|
||||
'hx-target': '#booking-summary',
|
||||
'hx-swap': 'innerHTML',
|
||||
'hx-trigger': 'change'
|
||||
}
|
||||
}) }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if groupedRooms.by_pax is not empty %}
|
||||
<h3>
|
||||
Betten
|
||||
</h3>
|
||||
{% for roomId, room in groupedRooms.by_pax %}
|
||||
{{ form_row(form.roomSelections[roomId], {
|
||||
'attr': {
|
||||
'hx-post': path('app_booking_create_step_1_room_summary'),
|
||||
'hx-target': '#booking-summary',
|
||||
'hx-swap': 'innerHTML',
|
||||
'hx-trigger': 'change'
|
||||
}
|
||||
}) }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% do form.roomSelections.setRendered %}
|
||||
{# This block contains the room selection form fields #}
|
||||
{% block room_selection_form %}
|
||||
<div id="room-selection-form"{% if htmx_oob_swap is defined and htmx_oob_swap %} hx-swap-oob="true"{% endif %}>
|
||||
{{ form_errors(form) }}
|
||||
{% if groupedRooms.by_room is not empty %}
|
||||
<h3>
|
||||
Zimmer
|
||||
</h3>
|
||||
{% for roomId, room in groupedRooms.by_room %}
|
||||
{{ form_row(form.roomSelections[roomId], {
|
||||
'attr': {
|
||||
'hx-post': path('app_booking_create_step_1_refresh'),
|
||||
'hx-swap': 'none',
|
||||
'hx-trigger': 'change'
|
||||
}
|
||||
}) }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if groupedRooms.by_pax is not empty %}
|
||||
<h3>
|
||||
Betten
|
||||
</h3>
|
||||
{% for roomId, room in groupedRooms.by_pax %}
|
||||
{{ form_row(form.roomSelections[roomId], {
|
||||
'attr': {
|
||||
'hx-post': path('app_booking_create_step_1_refresh'),
|
||||
'hx-swap': 'none',
|
||||
'hx-trigger': 'change'
|
||||
}
|
||||
}) }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
<div class="flex justify-end pt-4">
|
||||
<button type="submit" class="button bg-button bg-button--secondary">Weiter</button>
|
||||
<button type="submit" class="button bg-button bg-button--secondary" {{ stimulus_action('loading', 'toggle') }}>Weiter</button>
|
||||
</div>
|
||||
{{ form_rest(form) }}
|
||||
{{ form_end(form) }}
|
||||
</div>
|
||||
<div id="booking-summary">
|
||||
{% include 'booking/_summary.html.twig' with {
|
||||
'bookingCreateDto': bookingCreateDto,
|
||||
'participantCount': participantCount,
|
||||
'pricingData': pricingData,
|
||||
'groupedSelectedRooms': groupedSelectedRooms,
|
||||
'assignmentCounts': []
|
||||
} %}
|
||||
</div>
|
||||
{% block booking_summary %}
|
||||
<div id="booking-summary"{% if htmx_oob_swap is defined and htmx_oob_swap %} hx-swap-oob="true"{% endif %}>
|
||||
{% include 'booking/_summary.html.twig' with {
|
||||
'bookingCreateDto': bookingCreateDto,
|
||||
'participantCount': participantCount,
|
||||
'pricingData': pricingData,
|
||||
'groupedSelectedRooms': groupedSelectedRooms,
|
||||
'assignmentCounts': []
|
||||
} %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<div {{ stimulus_controller('toast') }}></div>
|
||||
<h1>Neue Buchung</h1>
|
||||
<div class="grid grid-cols-3 gap-8">
|
||||
<div class="col-span-2">
|
||||
<div id="form-wrapper" class="col-span-2">
|
||||
<h2>Teilnehmer</h2>
|
||||
{{ form_start(form) }}
|
||||
{% do form.participants.setRendered %}
|
||||
@@ -318,7 +318,7 @@
|
||||
{% endblock %}
|
||||
<div class="flex justify-between">
|
||||
<a href="{{ path('app_booking_create_step_1') }}" class="button bg-button bg-button--secondary">Zurück</a>
|
||||
<button type="submit" class="button bg-button bg-button--secondary">Weiter</button>
|
||||
<button type="submit" class="button bg-button bg-button--secondary" {{ stimulus_action('loading', 'toggle') }}>Weiter</button>
|
||||
</div>
|
||||
{{ form_rest(form) }}
|
||||
{{ form_end(form) }}
|
||||
|
||||
@@ -27,10 +27,18 @@
|
||||
<h1>Neue Buchung</h1>
|
||||
|
||||
<div class="grid grid-cols-3 gap-8">
|
||||
<div class="col-span-2">
|
||||
<div id="form-wrapper" class="col-span-2">
|
||||
<h2 class="mb-6">Zahlungsart</h2>
|
||||
|
||||
{{ form_start(form, {'attr': {'novalidate': 'novalidate'}}) }}
|
||||
{{ form_start(form, {
|
||||
'attr': {
|
||||
'novalidate': 'novalidate',
|
||||
'hx-post': path('app_booking_create_step_3'),
|
||||
'hx-target': '#form-wrapper',
|
||||
'hx-select': '#form-wrapper',
|
||||
'hx-swap': 'outerHTML'
|
||||
}
|
||||
}) }}
|
||||
|
||||
{# Payment method selection with HTMX #}
|
||||
<div id="form-payment"
|
||||
@@ -63,7 +71,7 @@
|
||||
|
||||
<div class="flex justify-between pt-6">
|
||||
<a href="{{ path('app_booking_create_step_2') }}" class="button bg-button bg-button--secondary">Zurück</a>
|
||||
<button type="submit" class="button bg-button bg-button--secondary">Weiter</button>
|
||||
<button type="submit" class="button bg-button bg-button--secondary" {{ stimulus_action('loading', 'toggle') }}>Weiter</button>
|
||||
</div>
|
||||
|
||||
{{ form_end(form) }}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div>
|
||||
<div id="form-wrapper">
|
||||
<h2 class="mb-6">Buchung bestätigen</h2>
|
||||
|
||||
{# Travel Summary #}
|
||||
@@ -290,7 +290,15 @@
|
||||
</div>
|
||||
|
||||
{# Confirmation Form #}
|
||||
{{ form_start(form, {'attr': {'novalidate': 'novalidate'}}) }}
|
||||
{{ form_start(form, {
|
||||
'attr': {
|
||||
'novalidate': 'novalidate',
|
||||
'hx-post': path('app_booking_create_step_4'),
|
||||
'hx-target': '#form-wrapper',
|
||||
'hx-select': '#form-wrapper',
|
||||
'hx-swap': 'outerHTML'
|
||||
}
|
||||
}) }}
|
||||
|
||||
<div class="mb-8 p-6 bg-blue-50 border border-blue-200 rounded-lg">
|
||||
{{ form_row(form.confirmationAccepted, {
|
||||
@@ -300,7 +308,7 @@
|
||||
|
||||
<div class="flex justify-between pt-6">
|
||||
<a href="{{ path('app_booking_create_step_3') }}" class="button bg-button bg-button--secondary">Zurück</a>
|
||||
<button type="submit" class="button bg-button bg-button--primary">Verbindlich buchen</button>
|
||||
<button type="submit" class="button bg-button bg-button--primary" {{ stimulus_action('loading', 'toggle') }}>Verbindlich buchen</button>
|
||||
</div>
|
||||
|
||||
{{ form_end(form) }}
|
||||
|
||||
@@ -53,11 +53,23 @@
|
||||
{% block content %}
|
||||
{% include '_partials/_flashes.html.twig' %}
|
||||
<div {{ stimulus_controller('toast') }}></div>
|
||||
<h1 class="text-3xl font-semibold pb-8">Buchung bearbeiten</h1>
|
||||
|
||||
{# Header with reload button #}
|
||||
<div class="flex justify-between items-center pb-8">
|
||||
<h1 class="text-3xl font-semibold">Buchung bearbeiten</h1>
|
||||
|
||||
<button type="button"
|
||||
hx-post="{{ path('app_booking_edit_reload', {id: bookingData.id}) }}"
|
||||
hx-confirm="Alle nicht gespeicherten Änderungen gehen verloren. Fortfahren?"
|
||||
{{ stimulus_action('loading', 'toggle') }}
|
||||
class="px-4 py-2 bg-gray-200 hover:bg-gray-300 text-gray-800 rounded transition-colors">
|
||||
🔄 Änderungen verwerfen
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{# Grid layout with 2/3 form + 1/3 summary #}
|
||||
<div class="grid grid-cols-3 gap-8">
|
||||
<div class="col-span-2">
|
||||
<div id="form-wrapper" class="col-span-2">
|
||||
<h2>Teilnehmer</h2>
|
||||
{{ form_start(form) }}
|
||||
{% do form.participants.setRendered %}
|
||||
@@ -362,7 +374,7 @@
|
||||
{% endblock %}
|
||||
<div class="flex justify-between">
|
||||
<a href="{{ path('app_bookings') }}" class="button bg-button bg-button--secondary">Zurück</a>
|
||||
<button type="submit" class="button bg-button bg-button--secondary">Aktualisieren</button>
|
||||
<button type="submit" class="button bg-button bg-button--secondary" {{ stimulus_action('loading', 'toggle') }}>Aktualisieren</button>
|
||||
</div>
|
||||
{{ form_rest(form) }}
|
||||
{{ form_end(form) }}
|
||||
@@ -379,4 +391,4 @@
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user