feat: add admin views, a booking horizon and confirmation modals
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
1 parent
8caf618950
commit
1a3640b15c
27 files changed
+1269
-62
No files matched your search
@@ -4,7 +4,8 @@
|
||||
differing from it.
|
||||
|
||||
Releasing lives here too rather than on the floor plan, so the SVG needs no confirm dialogs
|
||||
or inline CSRF tokens -- clicking your own desk always just opens this.
|
||||
or inline CSRF tokens -- clicking your own desk always just opens this. The release button
|
||||
opens the shared confirmation modal over this one.
|
||||
#}
|
||||
{% extends 'htmx_modal.html.twig' %}
|
||||
|
||||
@@ -32,14 +33,13 @@
|
||||
{% include 'booking/_fields.html.twig' %}
|
||||
|
||||
<div class="flex flex-wrap justify-between gap-2 pt-6">
|
||||
{# type="button" with its own hx-post: htmx issues the release request directly, so
|
||||
this never submits the surrounding edit form and no nested <form> is needed. #}
|
||||
{# type="button" with its own hx-get: htmx opens the confirmation modal over this
|
||||
one, so nothing submits the surrounding edit form and no nested <form> is needed.
|
||||
Confirming removes both modals -- see BookingController::boardResponse(). #}
|
||||
<button type="button" class="button button--small button--warning"
|
||||
hx-post="{{ path('app_booking_release', { id: booking.id }) }}"
|
||||
hx-vals='{{ { _token: csrf_token('release-' ~ booking.id) }|json_encode }}'
|
||||
hx-confirm="{{ resource.label }} am {{ booking.date|date('d.m.Y') }} freigeben?"
|
||||
hx-target="#htmx-modal"
|
||||
hx-swap="outerHTML">
|
||||
hx-get="{{ path('app_booking_release', { id: booking.id }) }}"
|
||||
hx-target="body"
|
||||
hx-swap="beforeend">
|
||||
Freigeben
|
||||
</button>
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
{% extends 'htmx_confirmation_modal.html.twig' %}
|
||||
|
||||
{% block title %}Serie beenden?{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p>
|
||||
{{ series.resource.label }} · {{ series.describe }}
|
||||
{% if series.user.id != app.user.id %}
|
||||
— Serie von <em>{{ series.user.name }}</em>
|
||||
{% endif %}
|
||||
</p>
|
||||
<p class="pt-3 text-sm text-gray-500">
|
||||
Alle Termine ab heute werden entfernt. Vergangene Termine bleiben als Historie stehen.
|
||||
</p>
|
||||
{% endblock %}
|
||||
|
||||
{% block button_confirm %}Serie beenden{% endblock %}
|
||||
@@ -0,0 +1,22 @@
|
||||
{% extends 'htmx_confirmation_modal.html.twig' %}
|
||||
|
||||
{% block title %}Buchung freigeben?{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p>
|
||||
{{ booking.resource.type.label }} <em>{{ booking.resource.label }}</em>
|
||||
{%- if booking.resource.group %} ({{ booking.resource.group.label }}){% endif %}
|
||||
am {{ booking.date|format_datetime(pattern: 'EEEE, d. MMMM y') }}, {{ booking.timeRange }}
|
||||
{% if not booking.belongsTo(app.user) %}
|
||||
— gebucht von <em>{{ booking.user.name }}</em>
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
{% if booking.partOfSeries %}
|
||||
<p class="pt-3 text-sm text-gray-500">
|
||||
Teil einer Serie: {{ booking.series.describe }}. Es wird nur dieser Tag freigegeben.
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block button_confirm %}Freigeben{% endblock %}
|
||||
@@ -22,12 +22,14 @@
|
||||
{{ entry.describe }} · bis {{ entry.endDate|format_datetime(pattern: 'd. MMMM y') }}
|
||||
</div>
|
||||
</div>
|
||||
{# Ends the series from today on; past occurrences are history and stay put. #}
|
||||
<form method="post" action="{{ path('app_series_end', { id: entry.id }) }}"
|
||||
onsubmit="return confirm('Serie ab heute beenden? Alle künftigen Termine werden entfernt.')">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token('end-series-' ~ entry.id) }}">
|
||||
<button type="submit" class="button button--small button--neutral">Serie beenden</button>
|
||||
</form>
|
||||
{# Opens the confirmation modal; the CSRF token and the actual POST live in
|
||||
there, which is why this row carries neither a form nor a token. #}
|
||||
<button type="button" class="button button--small button--neutral"
|
||||
hx-get="{{ path('app_series_end', { id: entry.id, return: 'bookings' }) }}"
|
||||
hx-target="body"
|
||||
hx-swap="beforeend">
|
||||
Serie beenden
|
||||
</button>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
@@ -62,12 +64,14 @@
|
||||
<div class="flex items-center gap-3">
|
||||
<a class="text-sm underline"
|
||||
href="{{ path('app_board', { type: booking.resource.type.value, date: booking.date|date('Y-m-d') }) }}">Im Plan</a>
|
||||
{# Ordinary form post: this page has no board fragments to swap, so it
|
||||
reloads afterwards rather than pretending to be htmx. #}
|
||||
<form method="post" action="{{ path('app_booking_release', { id: booking.id }) }}">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token('release-' ~ booking.id) }}">
|
||||
<button type="submit" class="button button--small button--neutral">Freigeben</button>
|
||||
</form>
|
||||
{# ?return=bookings: this page has no board fragments to swap, so the
|
||||
confirmed release navigates back here instead. #}
|
||||
<button type="button" class="button button--small button--neutral"
|
||||
hx-get="{{ path('app_booking_release', { id: booking.id, return: 'bookings' }) }}"
|
||||
hx-target="body"
|
||||
hx-swap="beforeend">
|
||||
Freigeben
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
|
||||
Reference in new issue
Block a user