feat: groups price calculator admin crud, booking/offer flow and api

This commit is contained in:
Björn Fromme
2026-08-03 15:25:10 +02:00
parent eabed8295a
commit 9d2aa11fdb
258 changed files with 16231 additions and 582 deletions
@@ -0,0 +1,80 @@
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 pb-4">
{% for monthData in months %}
<div class="mb-10">
<h3 class="text-base font-semibold mb-3">{{ monthData.label }}</h3>
{# Weekday headers (MonSun) #}
<div class="grid grid-cols-7 text-center text-xs font-medium text-gray-400 mb-1">
<div>Mo</div>
<div>Di</div>
<div>Mi</div>
<div>Do</div>
<div>Fr</div>
<div>Sa</div>
<div>So</div>
</div>
{# Day grid #}
<div class="grid grid-cols-7 gap-0.5">
{% for week in monthData.weeks %}
{% for dayData in week %}
{% if dayData.inMonth %}
{% set dateStr = dayData.date|date('Y-m-d') %}
{% set entry = enrichedByDate[dateStr] ?? null %}
{% set status = (dateStr < todayStr) ? 'past' : (entry ? entry.status : 'ok') %}
{% set minNights = entry ? entry.minNights : 0 %}
<button type="button"
class="pc-day"
data-price-calendar-target="day"
data-action="price-calendar#selectDate"
data-date="{{ dateStr }}"
data-status="{{ status }}"
data-min-nights="{{ minNights }}"
{% if status == 'blocked' %}title="Nicht verfügbar"{% elseif minNights > 1 %}title="Mindestaufenthalt {{ minNights }} Nächte"{% endif %}>
{{ dayData.date|date('j') }}
</button>
{% else %}
<div class="pc-day pc-day--out-of-month"></div>
{% endif %}
{% endfor %}
{% endfor %}
</div>
</div>
{% endfor %}
</div>
<div class="flex justify-between">
{# Status message (arrival hint, short-stay warning, etc.) #}
<div class="text-sm text-primary-medium mb-2 min-h-[1.25rem]"
data-price-calendar-target="message"></div>
{# Reset link — revealed once a start date is selected #}
<button type="button"
class="text-sm text-gray-400 underline mb-4"
data-price-calendar-target="resetButton"
data-action="price-calendar#reset">
Auswahl zurücksetzen
</button>
</div>
{# Navigation — prev/next trigger HTMX month swap; no Stimulus involvement #}
<div class="flex items-center justify-between">
<button type="button"
class="button button--secondary"
{% if offset == 0 %}disabled{% endif %}
hx-get="{{ path('app_groups_booking_calendar_grid', {'offset': offset - 1}) }}"
hx-target="#calendar-mount"
hx-swap="innerHTML">
&larr; früher
</button>
<button type="button"
class="button button--secondary"
{% if offset >= totalMonths - 2 %}disabled{% endif %}
hx-get="{{ path('app_groups_booking_calendar_grid', {'offset': offset + 1}) }}"
hx-target="#calendar-mount"
hx-swap="innerHTML">
später &rarr;
</button>
</div>