Files
RosterChief/management/templates/management/_referee_assignment_panel.html
Bernard Siebens 441367362d Build the D5 events calendar, redesign event forms, and polish the events UI
Adds the Week/Month/Season calendar to the Events page (team/group-scoped
visibility, kind-colored blocks, a repeating-series indicator) alongside the
existing table as a List view, and redesigns event/event-series creation
around a kind-first picker with progressive disclosure instead of one long
flat form. Also: an accessible radio-based kind picker (no redundant
select-next-to-cards), a fixed week-grid layout bug, a filterable single-list
redesign of the event detail page's RSVP/responses modal, a tidied-up
recurrence field layout, and assorted button/field height and width fixes
across the referee panel and event forms.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
2026-08-20 01:08:53 +02:00

116 lines
8.0 KiB
HTML

{% load i18n lucide ui %}
{% comment %}
Shared by the event detail page and the referee management dashboard --
context: event, referees (EventReferee rows -- fee/km/km_rate read straight
off the model instance, no separate form object needed), referee_candidates,
referees_full, can_manage_referees, and an optional next_url to return to
after a POST (defaults to the event detail page when blank).
The fee is entered right here, inline, rather than behind a "Fee" button
that opened a second (and on the dashboard, nested-inside-a-dialog) modal
-- that extra click-through was the easiest way for a fee to slip past
everyone's attention until PDF export time. Travel (km/rate) stays behind
a small disclosure since most assignments never need it, but posts in the
same form as the fee so there's still only one Save per referee.
{% endcomment %}
<div class="flex flex-wrap items-center justify-between gap-2">
<h2 class="card-title">
{% lucide "flag" size=18 %} {% trans "Referees" %}
<span class="badge badge-sm {% if referees_full %}badge-neutral{% else %}badge-outline{% endif %}">
{{ referees|length }} / {{ event.max_referees }}
</span>
</h2>
{% if can_manage_referees %}
<a class="btn btn-outline btn-sm gap-1" href="{% url 'management:event_referee_form_pdf' event.pk %}">{% lucide "file-down" size=12 %} {% trans "Referee form (PDF)" %}</a>
{% endif %}
</div>
<ul class="divide-y">
{% for referee in referees %}
<li class="flex flex-wrap items-center justify-between gap-3 py-2.5">
<div class="flex min-w-0 flex-col gap-0.5">
<div class="flex flex-wrap items-center gap-1.5">
<span class="text-sm font-semibold text-ink">{{ referee.display_name }}</span>
{% if referee.is_external %}<span class="badge badge-neutral badge-xs">{% trans "External" %}</span>{% endif %}
{% if can_manage_referees and not referee.fee %}<span class="badge badge-warning badge-xs">{% trans "Fee not set" %}</span>{% endif %}
</div>
{% if referee.assigned_by %}<span class="text-xs text-muted">{% blocktrans with name=referee.assigned_by %}Assigned by {{ name }}{% endblocktrans %}</span>{% endif %}
</div>
{% if can_manage_referees %}
<div class="flex shrink-0 items-center gap-1.5">
{% url 'management:event_referee_fee_update' event.pk referee.pk as fee_action_url %}
<form method="post" action="{{ fee_action_url }}?next={{ next_url|urlencode }}" class="flex items-center gap-1.5">
{% csrf_token %}
<label class="flex items-center gap-1">
<span class="font-mono text-xs text-dim">&euro;</span>
<input type="number" step="0.01" min="0" name="fee" value="{{ referee.fee }}" class="input w-20 text-right" aria-label="{% trans 'Fee' %}">
</label>
<details class="relative">
<summary class="btn btn-square btn-outline btn-xs cursor-pointer list-none" title="{% trans 'Travel reimbursement' %}">{% lucide "car" size=12 %}</summary>
<div class="absolute right-0 z-10 mt-1 flex w-44 flex-col gap-2 rounded-lg border border-line bg-white p-2.5 shadow-lg">
<label class="flex flex-col gap-0.5 text-xs text-muted">{% trans "Km" %}
<input type="number" step="0.1" min="0" name="km" value="{{ referee.km|default_if_none:'' }}" class="input">
</label>
<label class="flex flex-col gap-0.5 text-xs text-muted">{% trans "Rate/km" %}
<input type="number" step="any" min="0" name="km_rate" value="{{ referee.km_rate|default_if_none:'' }}" class="input">
</label>
</div>
</details>
<button class="btn btn-square btn-outline btn-xs" type="submit" title="{% trans 'Save fee' %}" aria-label="{% trans 'Save fee' %}">{% lucide "check" size=12 %}</button>
</form>
{% if referee.km %}
<span class="font-mono text-xs text-muted">{% blocktrans with total=referee.total_payable|floatformat:2 %}{{ total }} due{% endblocktrans %}</span>
{% endif %}
<form method="post" action="{% url 'management:event_referee_remove' event.pk referee.pk %}">
{% csrf_token %}
{% if next_url %}<input type="hidden" name="next" value="{{ next_url }}">{% endif %}
<button class="btn btn-square btn-outline btn-error btn-xs" type="submit" title="{% trans 'Remove' %}" aria-label="{% trans 'Remove' %}">{% lucide "x" size=12 %}</button>
</form>
</div>
{% elif referee.total_payable %}
<span class="shrink-0 font-mono text-xs text-muted">{% blocktrans with total=referee.total_payable|floatformat:2 %}&euro;{{ total }} due{% endblocktrans %}</span>
{% endif %}
</li>
{% empty %}
<li class="py-2.5 text-sm text-muted">{% trans "No referees assigned yet." %}</li>
{% endfor %}
</ul>
{% if can_manage_referees and not referees_full %}
<div class="mt-3 flex flex-col gap-2 border-t border-rule pt-3">
<span class="font-mono text-[11px] tracking-[.08em] text-dim uppercase">{% trans "Add a referee" %}</span>
{% if referee_candidates %}
<form method="post" action="{% url 'management:event_referee_assign' event.pk %}" class="flex flex-wrap items-center gap-2">
{% csrf_token %}
{% if next_url %}<input type="hidden" name="next" value="{{ next_url }}">{% endif %}
<select name="member" class="select w-auto">
{% for candidate in referee_candidates %}
<option value="{{ candidate.pk }}" {% if candidate.has_conflict %}title="{% blocktrans with events=candidate.conflict_titles %}Also expected at: {{ events }}{% endblocktrans %}"{% endif %}>
{{ candidate }}{% if candidate.has_conflict %} ⚠{% endif %}
</option>
{% endfor %}
</select>
{# No btn-sm: .select is height:2.25rem, matching plain .btn -- btn-sm would sit 6px shorter and misalign in the row. #}
<button class="btn btn-outline gap-2" type="submit">{% lucide "user-plus" size=14 %} {% trans "Assign" %}</button>
</form>
{% else %}
<p class="text-sm text-muted">
{% trans "No eligible referees for this team yet." %}
<a class="link link-hover" href="{% url 'management:referee_level_list' %}">{% trans "Link a referee level to this team." %}</a>
</p>
{% endif %}
<form method="post" action="{% url 'management:event_referee_add_external' event.pk %}" class="flex flex-wrap items-center gap-2">
{% csrf_token %}
{% if next_url %}<input type="hidden" name="next" value="{{ next_url }}">{% endif %}
<input type="text" name="name" class="input w-56" placeholder="{% trans 'External referee name' %}">
{# No btn-sm: .input is height:2.25rem, matching plain .btn -- btn-sm would sit 6px shorter and misalign in the row. #}
<button class="btn btn-outline gap-2" type="submit">{% lucide "user-plus" size=14 %} {% trans "Add external" %}</button>
</form>
<p class="text-xs text-muted">{% trans "⚠ = also expected at another event around this time -- shown as a warning, not blocked." %}</p>
</div>
{% elif can_manage_referees and referees_full %}
<p class="mt-2 text-sm text-muted">{% trans "This game already has its maximum number of referees." %}</p>
{% endif %}