{# The shared shape a plan is drawn from. Imported by each board/plan/_.html.twig, so the per-type partials carry geometry only and the states look identical everywhere. The state comes from App\Booking\Spot, not from counting bookings here. That distinction is the fix for a real bug: a desk booked 09:00-13:00 used to render exactly like one booked all day on an all-day board, and carried no hx-get either -- so a second person could not book the afternoon at all unless they happened to narrow the span by hand first. Clicking always opens a modal: the create modal when anything is still free, the edit modal when it is yours (which is where changing the times and releasing live). Nothing else is clickable, so the SVG carries no confirm dialogs or inline CSRF tokens. #} {% macro spot(spot, geometry, width, height, selected_date, is_past, time_params) %} {% set state = spot.state.name %} {% if state == 'MINE' %} {% set fill = 'fill-primary' %}{% set stroke = 'stroke-primary-dark' %}{% set text = 'fill-white' %} {% elseif state == 'TAKEN' %} {% set fill = 'fill-gray-200' %}{% set stroke = 'stroke-gray-400' %}{% set text = 'fill-gray-600' %} {% elseif state == 'PARTLY' %} {% set fill = 'fill-amber-50' %}{% set stroke = 'stroke-amber-500' %}{% set text = 'fill-amber-900' %} {% else %} {% set fill = 'fill-emerald-50' %}{% set stroke = 'stroke-emerald-500' %}{% set text = 'fill-emerald-900' %} {% endif %} {% set interactive = not is_past and spot.actionable %} {# The second line: what you would be told at a glance. For a partly-free spot that is the window still available, because that is the reason to click it. #} {% if state == 'MINE' %} {% set caption = spot.own.timeRange.allDay ? 'du' : 'du ' ~ spot.own.timeRange %} {% elseif state == 'PARTLY' %} {% set caption = 'frei ' ~ spot.suggested %} {% elseif spot.bookings|length > 1 %} {% set caption = spot.bookings|length ~ ' Buchungen' %} {% elseif spot.bookings is not empty %} {% set caption = spot.bookings|first.user.name %} {% else %} {% set caption = null %} {% endif %} ; closing it is Stimulus, not htmx. It prefills the free window itself -- see BookingController::create. #} hx-get="{{ path('app_booking_new', { id: spot.resource.id, date: selected_date|date('Y-m-d') }|merge(time_params)) }}" hx-target="body" hx-swap="beforeend" {%- endif %}> {{- spot.resource.label }} {%- if spot.bookings is empty %} — frei {%- else %} {%- for booking in spot.bookings %} — {{ booking.user.id == app.user.id ? 'du' : booking.user.name }} {{ booking.timeRange }}{% endfor %} {%- for window in spot.free %} — frei {{ window }}{% endfor %} {%- endif -%} {{ spot.resource.label }} {% if caption %} {{ caption }} {% endif %} {% endmacro %}