New event: auto-link the active team, opponent/competition, quick-add popups, recurring series
- teams is now hard-locked to the active team (a hidden field, not a picker) -- there's no "which team" question on a screen already scoped to one. groups/club_wide are dropped for the same reason (both widen the audience past a single team). invited_members/excluded_members stay, re-scoped to sensible pools (add someone off the roster; exclude someone on it) instead of "every club member", with a note that a genuinely multi-team event still needs the desktop. - Opponent and competition are now rendered (game-only) -- opponent via a standalone picker with its own "+ New" popup, competition via EventForm's existing club-agnostic Competition list. - "+ New location"/"+ New opponent" popups create a Location/Opponent scoped to the club without leaving the screen: the modal's own htmx request creates the row and hands back the picker pre-selected via an out-of-band swap, so the rest of the in-progress form is never touched. - A "This repeats" toggle switches the same screen to build an EventSeries instead of a single Event (frequency/interval/weekdays/duration/until), reusing EventSeriesForm and generate_occurrences the same way management.views.EventSeriesCreateView does -- including that view's own behaviour of not sending a per-occurrence notification (the bulk send_deadline_reminders sweep covers it instead, same as a rolling- horizon extension). - Confirmed (and covered with a test) that a single event created this way still fires notify_new_event, notifying whoever's freshly invited. Along the way, found and fixed a real, previously-undetected rendering bug this surfaced: swapping a multi-choice field's widget to CheckboxSelectMultiple *after* setting its queryset/choices silently drops what the queryset/choices setter had already pushed onto the old widget, rendering an empty checkbox list. Hit this for invited_members/excluded_members and weekdays here, and found the same pre-existing bug in CoachCreateNewsView's own team checkboxes (the New Post screen's team picker has been rendering empty) -- fixed all of them (widget swapped in before queryset/choices, not after), with rendering (not just queryset) regression tests for each. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
{% include "mobile/coach/_location_modal_fields.html" with location_form=location_form %}
|
||||
{% include "mobile/coach/_location_picker.html" with location_picker=location_picker oob=True %}
|
||||
31
mobile/templates/mobile/coach/_location_modal_fields.html
Normal file
31
mobile/templates/mobile/coach/_location_modal_fields.html
Normal file
@@ -0,0 +1,31 @@
|
||||
{% load i18n %}
|
||||
<div class="flex flex-col gap-3">
|
||||
{% for error in location_form.non_field_errors %}<p class="text-xs text-club-dark">{{ error }}</p>{% endfor %}
|
||||
<div>
|
||||
<label class="mb-1 block text-xs font-semibold text-muted" for="{{ location_form.name.id_for_label }}">{% trans "Name" %}</label>
|
||||
{{ location_form.name }}
|
||||
{% for error in location_form.name.errors %}<p class="mt-1 text-xs text-club-dark">{{ error }}</p>{% endfor %}
|
||||
</div>
|
||||
<div>
|
||||
<label class="mb-1 block text-xs font-semibold text-muted" for="{{ location_form.address.id_for_label }}">{% trans "Address" %}</label>
|
||||
{{ location_form.address }}
|
||||
{% for error in location_form.address.errors %}<p class="mt-1 text-xs text-club-dark">{{ error }}</p>{% endfor %}
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label class="mb-1 block text-xs font-semibold text-muted" for="{{ location_form.city.id_for_label }}">{% trans "City" %}</label>
|
||||
{{ location_form.city }}
|
||||
{% for error in location_form.city.errors %}<p class="mt-1 text-xs text-club-dark">{{ error }}</p>{% endfor %}
|
||||
</div>
|
||||
<div>
|
||||
<label class="mb-1 block text-xs font-semibold text-muted" for="{{ location_form.zip_code.id_for_label }}">{% trans "Zip code" %}</label>
|
||||
{{ location_form.zip_code }}
|
||||
{% for error in location_form.zip_code.errors %}<p class="mt-1 text-xs text-club-dark">{{ error }}</p>{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="mb-1 block text-xs font-semibold text-muted" for="{{ location_form.country.id_for_label }}">{% trans "Country" %}</label>
|
||||
{{ location_form.country }}
|
||||
{% for error in location_form.country.errors %}<p class="mt-1 text-xs text-club-dark">{{ error }}</p>{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
8
mobile/templates/mobile/coach/_location_picker.html
Normal file
8
mobile/templates/mobile/coach/_location_picker.html
Normal file
@@ -0,0 +1,8 @@
|
||||
{% load i18n %}
|
||||
<div id="location-picker" {% if oob %}hx-swap-oob="true"{% endif %}>
|
||||
<div class="mb-1 flex items-center justify-between">
|
||||
<label class="text-xs font-semibold text-muted" for="{{ location_picker.location.id_for_label }}">{% trans "Location" %}</label>
|
||||
<button type="button" class="font-display text-[11px] font-extrabold tracking-wide text-club uppercase" @click="showLocationModal = true">{% trans "+ New" %}</button>
|
||||
</div>
|
||||
{{ location_picker.location }}
|
||||
</div>
|
||||
@@ -0,0 +1,2 @@
|
||||
{% include "mobile/coach/_opponent_modal_fields.html" with opponent_form=opponent_form %}
|
||||
{% include "mobile/coach/_opponent_picker.html" with opponent_picker=opponent_picker oob=True %}
|
||||
@@ -0,0 +1,9 @@
|
||||
{% load i18n %}
|
||||
<div class="flex flex-col gap-3">
|
||||
{% for error in opponent_form.non_field_errors %}<p class="text-xs text-club-dark">{{ error }}</p>{% endfor %}
|
||||
<div>
|
||||
<label class="mb-1 block text-xs font-semibold text-muted" for="{{ opponent_form.name.id_for_label }}">{% trans "Name" %}</label>
|
||||
{{ opponent_form.name }}
|
||||
{% for error in opponent_form.name.errors %}<p class="mt-1 text-xs text-club-dark">{{ error }}</p>{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
8
mobile/templates/mobile/coach/_opponent_picker.html
Normal file
8
mobile/templates/mobile/coach/_opponent_picker.html
Normal file
@@ -0,0 +1,8 @@
|
||||
{% load i18n %}
|
||||
<div id="opponent-picker" {% if oob %}hx-swap-oob="true"{% endif %}>
|
||||
<div class="mb-1 flex items-center justify-between">
|
||||
<label class="text-xs font-semibold text-muted" for="{{ opponent_picker.opponent.id_for_label }}">{% trans "Opponent" %}</label>
|
||||
<button type="button" class="font-display text-[11px] font-extrabold tracking-wide text-club uppercase" @click="showOpponentModal = true">{% trans "+ New" %}</button>
|
||||
</div>
|
||||
{{ opponent_picker.opponent }}
|
||||
</div>
|
||||
@@ -1,12 +1,14 @@
|
||||
{% extends "mobile/coach/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load i18n lucide %}
|
||||
|
||||
{% comment %}
|
||||
C4 -- design_handoff_rosterchief_platform/README.md's C4 section: three
|
||||
event-type tiles, title/date/location, "who" (teams), and an answers-
|
||||
close row. See CoachCreateEventView's own docstring for what's scoped
|
||||
down from the mock and why (no group/opponent/competition fields, no
|
||||
"Repeat weekly" yet). The white sticky Cancel/title/Create bar breaks out
|
||||
C4 -- design_handoff_rosterchief_platform/README.md's C4 section, grown
|
||||
past the mock: a kind picker, title/location/date, opponent+competition
|
||||
for a game, "who" (invited/excluded members on top of the auto-linked
|
||||
active team), a "this repeats" toggle building an EventSeries instead of
|
||||
a single Event, and "+ New" popups for location/opponent. See
|
||||
CoachCreateEventView's own docstring for the shared-fields/two-forms
|
||||
design this renders. The white sticky Cancel/title/Create bar breaks out
|
||||
of the sheet's own padding (-mx-4 -mt-5), same trick calendar_feed_
|
||||
settings.html/payments.html use for their own back-button bars.
|
||||
{% endcomment %}
|
||||
@@ -18,71 +20,191 @@
|
||||
<button class="font-display text-sm font-extrabold tracking-wide text-club uppercase" type="submit" form="coach-event-form">{% trans "Create" %}</button>
|
||||
</div>
|
||||
|
||||
{% if form.non_field_errors %}
|
||||
<div class="m-card border border-danger-border bg-danger-bg p-3 text-sm text-club-dark">
|
||||
{% for error in form.non_field_errors %}<p>{{ error }}</p>{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% for error in form.non_field_errors %}
|
||||
<div class="m-card border border-danger-border bg-danger-bg p-3 text-sm text-club-dark"><p>{{ error }}</p></div>
|
||||
{% endfor %}
|
||||
{% for error in series_form.non_field_errors %}
|
||||
<div class="m-card border border-danger-border bg-danger-bg p-3 text-sm text-club-dark"><p>{{ error }}</p></div>
|
||||
{% endfor %}
|
||||
|
||||
<form id="coach-event-form" class="flex flex-col gap-4" method="post" action="{% url "mobile:coach_create_event" %}" hx-boost="false">
|
||||
{% csrf_token %}
|
||||
<div x-data="{ kind: '{{ shared_form.kind.value|default:"training" }}', isRecurring: {% if is_recurring %}true{% else %}false{% endif %}, showLocationModal: false, showOpponentModal: false }">
|
||||
<form id="coach-event-form" class="flex flex-col gap-4" method="post" action="{% url "mobile:coach_create_event" %}" hx-boost="false">
|
||||
{% csrf_token %}
|
||||
{{ shared_form.teams }}
|
||||
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<label class="flex h-12 items-center justify-center rounded-lg border border-line bg-white font-display text-xs font-extrabold tracking-wide text-muted uppercase has-checked:border-ink has-checked:bg-ink has-checked:text-white">
|
||||
<input class="sr-only" type="radio" name="kind" value="training" checked>
|
||||
{% trans "Practice" %}
|
||||
</label>
|
||||
<label class="flex h-12 items-center justify-center rounded-lg border border-line bg-white font-display text-xs font-extrabold tracking-wide text-muted uppercase has-checked:border-ink has-checked:bg-ink has-checked:text-white">
|
||||
<input class="sr-only" type="radio" name="kind" value="game">
|
||||
{% trans "Game" %}
|
||||
</label>
|
||||
<label class="flex h-12 items-center justify-center rounded-lg border border-line bg-white font-display text-xs font-extrabold tracking-wide text-muted uppercase has-checked:border-ink has-checked:bg-ink has-checked:text-white">
|
||||
<input class="sr-only" type="radio" name="kind" value="tournament">
|
||||
{% trans "Tournament" %}
|
||||
</label>
|
||||
<label class="flex h-12 items-center justify-center rounded-lg border border-line bg-white font-display text-xs font-extrabold tracking-wide text-muted uppercase has-checked:border-ink has-checked:bg-ink has-checked:text-white">
|
||||
<input class="sr-only" type="radio" name="kind" value="meeting">
|
||||
{% trans "Meeting" %}
|
||||
</label>
|
||||
</div>
|
||||
{% for error in form.kind.errors %}<p class="text-xs text-club-dark">{{ error }}</p>{% endfor %}
|
||||
|
||||
<div class="m-card flex flex-col p-4">
|
||||
<div>
|
||||
<label class="mb-1 block text-xs font-semibold text-muted" for="{{ form.title.id_for_label }}">{% trans "Title" %}</label>
|
||||
{{ form.title }}
|
||||
{% for error in form.title.errors %}<p class="mt-1 text-xs text-club-dark">{{ error }}</p>{% endfor %}
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<label class="flex h-12 items-center justify-center rounded-lg border border-line bg-white font-display text-xs font-extrabold tracking-wide text-muted uppercase has-checked:border-ink has-checked:bg-ink has-checked:text-white">
|
||||
<input class="sr-only" type="radio" name="kind" value="training" x-model="kind">
|
||||
{% trans "Practice" %}
|
||||
</label>
|
||||
<label class="flex h-12 items-center justify-center rounded-lg border border-line bg-white font-display text-xs font-extrabold tracking-wide text-muted uppercase has-checked:border-ink has-checked:bg-ink has-checked:text-white">
|
||||
<input class="sr-only" type="radio" name="kind" value="game" x-model="kind">
|
||||
{% trans "Game" %}
|
||||
</label>
|
||||
<label class="flex h-12 items-center justify-center rounded-lg border border-line bg-white font-display text-xs font-extrabold tracking-wide text-muted uppercase has-checked:border-ink has-checked:bg-ink has-checked:text-white">
|
||||
<input class="sr-only" type="radio" name="kind" value="tournament" x-model="kind">
|
||||
{% trans "Tournament" %}
|
||||
</label>
|
||||
<label class="flex h-12 items-center justify-center rounded-lg border border-line bg-white font-display text-xs font-extrabold tracking-wide text-muted uppercase has-checked:border-ink has-checked:bg-ink has-checked:text-white">
|
||||
<input class="sr-only" type="radio" name="kind" value="meeting" x-model="kind">
|
||||
{% trans "Meeting" %}
|
||||
</label>
|
||||
</div>
|
||||
<div class="my-3 h-px bg-rule"></div>
|
||||
<div>
|
||||
<label class="mb-1 block text-xs font-semibold text-muted" for="{{ form.start.id_for_label }}">{% trans "Date & time" %}</label>
|
||||
{{ form.start }}
|
||||
{% for error in form.start.errors %}<p class="mt-1 text-xs text-club-dark">{{ error }}</p>{% endfor %}
|
||||
{% for error in form.kind.errors %}<p class="text-xs text-club-dark">{{ error }}</p>{% endfor %}
|
||||
{% for error in series_form.kind.errors %}<p class="text-xs text-club-dark">{{ error }}</p>{% endfor %}
|
||||
|
||||
<div class="m-card flex items-center justify-between p-4">
|
||||
<span class="text-sm font-semibold text-ink">{% trans "This repeats" %}</span>
|
||||
<input class="h-5 w-5 shrink-0 accent-ink" type="checkbox" name="is_recurring" x-model="isRecurring">
|
||||
</div>
|
||||
<div class="my-3 h-px bg-rule"></div>
|
||||
<div>
|
||||
<label class="mb-1 block text-xs font-semibold text-muted" for="{{ form.location.id_for_label }}">{% trans "Location" %}</label>
|
||||
{{ form.location }}
|
||||
|
||||
<div class="m-card flex flex-col p-4">
|
||||
<div>
|
||||
<label class="mb-1 block text-xs font-semibold text-muted" for="{{ shared_form.title.id_for_label }}">{% trans "Title" %}</label>
|
||||
{{ shared_form.title }}
|
||||
{% for error in shared_form.title.errors %}<p class="mt-1 text-xs text-club-dark">{{ error }}</p>{% endfor %}
|
||||
</div>
|
||||
|
||||
<div x-show="!isRecurring">
|
||||
<div class="my-3 h-px bg-rule"></div>
|
||||
<label class="mb-1 block text-xs font-semibold text-muted" for="{{ form.start.id_for_label }}">{% trans "Date & time" %}</label>
|
||||
{{ form.start }}
|
||||
{% for error in form.start.errors %}<p class="mt-1 text-xs text-club-dark">{{ error }}</p>{% endfor %}
|
||||
</div>
|
||||
|
||||
<div x-show="isRecurring" x-cloak>
|
||||
<div class="my-3 h-px bg-rule"></div>
|
||||
<label class="mb-1 block text-xs font-semibold text-muted" for="{{ series_form.dtstart.id_for_label }}">{% trans "First occurrence" %}</label>
|
||||
{{ series_form.dtstart }}
|
||||
{% for error in series_form.dtstart.errors %}<p class="mt-1 text-xs text-club-dark">{{ error }}</p>{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="my-3 h-px bg-rule"></div>
|
||||
<div>
|
||||
{% include "mobile/coach/_location_picker.html" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div x-show="kind === 'game'" x-cloak class="flex flex-col gap-4">
|
||||
<div class="m-card p-4">
|
||||
{% include "mobile/coach/_opponent_picker.html" %}
|
||||
</div>
|
||||
<div x-show="!isRecurring" class="m-card p-4">
|
||||
<label class="mb-1 block text-xs font-semibold text-muted" for="{{ form.competition.id_for_label }}">{% trans "Competition" %}</label>
|
||||
{{ form.competition }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div x-show="isRecurring" x-cloak class="m-card flex flex-col p-4">
|
||||
<div class="mb-2 font-display text-xs font-extrabold tracking-wide text-muted uppercase">{% trans "Repeats" %}</div>
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label class="mb-1 block text-xs font-semibold text-muted" for="{{ series_form.frequency.id_for_label }}">{% trans "Frequency" %}</label>
|
||||
{{ series_form.frequency }}
|
||||
</div>
|
||||
<div>
|
||||
<label class="mb-1 block text-xs font-semibold text-muted" for="{{ series_form.interval.id_for_label }}">{% trans "Every" %}</label>
|
||||
{{ series_form.interval }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<label class="mb-1 block text-xs font-semibold text-muted">{% trans "On (weekly only)" %}</label>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
{% for checkbox in series_form.weekdays %}
|
||||
<label class="flex h-9 items-center rounded-lg border border-line bg-white px-3 text-xs font-semibold text-ink has-checked:border-ink has-checked:bg-ink has-checked:text-white">
|
||||
{{ checkbox.tag }} {{ checkbox.choice_label }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% for error in series_form.weekdays.errors %}<p class="mt-1 text-xs text-club-dark">{{ error }}</p>{% endfor %}
|
||||
</div>
|
||||
<div class="my-3 h-px bg-rule"></div>
|
||||
<label class="mb-1 block text-xs font-semibold text-muted" for="{{ series_form.until.id_for_label }}">{% trans "Repeats until" %}</label>
|
||||
{{ series_form.until }}
|
||||
<p class="mt-1 text-xs text-dim">{% trans "Leave blank to keep repeating with no end date." %}</p>
|
||||
<div class="my-3 h-px bg-rule"></div>
|
||||
<label class="mb-1 block text-xs font-semibold text-muted">{% trans "Length of each occurrence" %}</label>
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
{{ series_form.duration_hours }}
|
||||
<p class="mt-1 text-xs text-dim">{% trans "Hours" %}</p>
|
||||
</div>
|
||||
<div>
|
||||
{{ series_form.duration_minutes }}
|
||||
<p class="mt-1 text-xs text-dim">{% trans "Minutes" %}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="m-card p-4">
|
||||
<div class="mb-2 font-display text-xs font-extrabold tracking-wide text-muted uppercase">{% trans "Who" %}</div>
|
||||
<p class="mb-3 text-xs text-dim">{% blocktrans with team=active_team.name %}Automatically for {{ team }}. Need more than one team? Create it from the management panel instead.{% endblocktrans %}</p>
|
||||
|
||||
{% if shared_form.excluded_members.field.queryset.exists %}
|
||||
<div class="mb-3">
|
||||
<div class="mb-1 text-xs font-semibold text-muted">{% trans "Exclude from the roster" %}</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
{% for checkbox in shared_form.excluded_members %}
|
||||
<label class="flex items-center gap-2 text-sm text-ink">{{ checkbox.tag }} {{ checkbox.choice_label }}</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if shared_form.invited_members.field.queryset.exists %}
|
||||
<details>
|
||||
<summary class="cursor-pointer text-xs font-semibold text-muted">{% trans "Add someone not on the roster" %}</summary>
|
||||
<div class="mt-2 flex flex-col gap-2">
|
||||
{% for checkbox in shared_form.invited_members %}
|
||||
<label class="flex items-center gap-2 text-sm text-ink">{{ checkbox.tag }} {{ checkbox.choice_label }}</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</details>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div x-show="!isRecurring" class="m-card p-4">
|
||||
<label class="mb-1 block text-xs font-semibold text-muted" for="{{ form.deadline.id_for_label }}">{% trans "Answers close" %}</label>
|
||||
{{ form.deadline }}
|
||||
<p class="mt-1 text-xs text-dim">{% trans "Leave blank to keep answers open until the event starts." %}</p>
|
||||
</div>
|
||||
<div x-show="isRecurring" x-cloak class="m-card p-4">
|
||||
<label class="mb-1 block text-xs font-semibold text-muted" for="{{ series_form.deadline_minutes_before.id_for_label }}">{% trans "Answers close (minutes before each occurrence)" %}</label>
|
||||
{{ series_form.deadline_minutes_before }}
|
||||
<p class="mt-1 text-xs text-dim">{% trans "Leave blank to keep answers open until each occurrence starts." %}</p>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="fixed inset-0 z-30 flex items-end bg-black/60" x-show="showLocationModal" x-cloak @click.self="showLocationModal = false" @location-created.window="showLocationModal = false">
|
||||
<div class="w-full rounded-t-2xl bg-white p-4" @click.stop>
|
||||
<div class="mb-3 flex items-center justify-between">
|
||||
<span class="font-display text-sm font-extrabold tracking-wide text-ink uppercase">{% trans "New location" %}</span>
|
||||
<button type="button" class="text-dim" @click="showLocationModal = false" aria-label="{% trans "Close" %}">{% lucide "x" size=18 %}</button>
|
||||
</div>
|
||||
<form hx-post="{% url "mobile:coach_location_create" %}" hx-target="#location-modal-body" hx-swap="innerHTML" hx-boost="false">
|
||||
{% csrf_token %}
|
||||
<div id="location-modal-body">
|
||||
{% include "mobile/coach/_location_modal_fields.html" %}
|
||||
</div>
|
||||
<button class="btn btn-dark mt-3 w-full" type="submit">{% trans "Add location" %}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="m-card p-4">
|
||||
<div class="mb-2 font-display text-xs font-extrabold tracking-wide text-muted uppercase">{% trans "Who" %}</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
{% for checkbox in form.teams %}
|
||||
<label class="flex items-center gap-2 text-sm text-ink">
|
||||
{{ checkbox.tag }}
|
||||
{{ checkbox.choice_label }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
<div class="fixed inset-0 z-30 flex items-end bg-black/60" x-show="showOpponentModal" x-cloak @click.self="showOpponentModal = false" @opponent-created.window="showOpponentModal = false">
|
||||
<div class="w-full rounded-t-2xl bg-white p-4" @click.stop>
|
||||
<div class="mb-3 flex items-center justify-between">
|
||||
<span class="font-display text-sm font-extrabold tracking-wide text-ink uppercase">{% trans "New opponent" %}</span>
|
||||
<button type="button" class="text-dim" @click="showOpponentModal = false" aria-label="{% trans "Close" %}">{% lucide "x" size=18 %}</button>
|
||||
</div>
|
||||
<form hx-post="{% url "mobile:coach_opponent_create" %}" hx-target="#opponent-modal-body" hx-swap="innerHTML" hx-boost="false">
|
||||
{% csrf_token %}
|
||||
<div id="opponent-modal-body">
|
||||
{% include "mobile/coach/_opponent_modal_fields.html" %}
|
||||
</div>
|
||||
<button class="btn btn-dark mt-3 w-full" type="submit">{% trans "Add opponent" %}</button>
|
||||
</form>
|
||||
</div>
|
||||
{% for error in form.teams.errors %}<p class="mt-1 text-xs text-club-dark">{{ error }}</p>{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="m-card p-4">
|
||||
<label class="mb-1 block text-xs font-semibold text-muted" for="{{ form.deadline.id_for_label }}">{% trans "Answers close" %}</label>
|
||||
{{ form.deadline }}
|
||||
<p class="mt-1 text-xs text-dim">{% trans "Leave blank to keep answers open until the event starts." %}</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
Reference in New Issue
Block a user