Files
RosterChief/mobile/templates/mobile/edit_profile.html
Bernard Siebens 366239e60b Fix RSVP buttons broken by hx-boost; require a real Out reason; add optional Maybe reason
The In/Out hero buttons (and Out's reason confirm) stopped working: Alpine
owns the toggle between a row's two sibling forms (buttons vs. the reason
prompt), and hx-boost="true" on <body> had htmx *also* intercepting the
same submit -- both ended up fighting over it. Fixed by marking every
write-action <form> across the mobile app hx-boost="false" (link
navigation, where the smooth-navigation feature actually matters, is
untouched). The one exception worth calling out: coach/lineup.html's form
uses three submit buttons sharing one <form> via formaction overrides --
htmx's boost reads the form's own action rather than the submitter's
formaction override, so a boosted click there would always have posted to
the wrong endpoint regardless of the Alpine conflict.

Also:
- A reason for Out is now mandatory, not just captured -- empty and
  punctuation-only "answers" (a bare ".", "-", "??") are rejected
  server-side (the authoritative check) with textarea required/minlength
  as a client-side nudge on top.
- Maybe can now carry an optional reason too, visible to the same audience
  as Out's (this member/family, and Coach mode's bench attendance) -- one
  shared reason form in event_detail.html's per-person row, its hidden
  status input following whichever of Maybe/Out was tapped.
- The 3-way In/Maybe/Out row (and the 2-way hero In/Out) now use min-w-0 on
  every button so flex-1 actually splits the row evenly -- a longer
  label's own intrinsic width was winning it a bigger share otherwise.
- HomeView's "Needs your answer" list now excludes events whose
  registration deadline has already passed -- replying is no longer
  possible there (same rule EventDetailView.post already enforces), so it
  doesn't belong in a "still needs a reply" list. hero_attendance is
  unaffected -- it always shows the true next event, falling back to a
  read-only pill once its own deadline closes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
2026-08-22 14:59:23 +02:00

91 lines
5.1 KiB
HTML

{% extends "mobile/base.html" %}
{% load i18n lucide %}
{% comment %}
M6 -- design_handoff_rosterchief_platform/README.md's M6 section, "Edit
personal info". See EditProfileView's own docstring (mobile/views.py) for
the judgment calls: the design mock's "National register no.", "Address",
"Allergies / notes" and the two "Consent" toggles have no backing field on
Member and are omitted entirely; the guardian ("Contact 1") and open
onboarding-requirements ("Medical form... missing") rows are real data,
shown read-only.
{% endcomment %}
{% block content %}
<form method="post" class="flex flex-col gap-4" hx-boost="false">
{% csrf_token %}
<div class="-mx-4 -mt-4 flex items-center gap-1 border-b border-line bg-white px-4 py-3">
<a class="-ml-2.5 flex h-11 w-11 shrink-0 items-center justify-center" href="{% url "mobile:me" %}" aria-label="{% trans "Back" %}">
{% lucide "chevron-left" size=20 stroke_width=2.4 class="text-ink" %}
</a>
<span class="min-w-0 flex-1 truncate font-display text-xl leading-none font-extrabold text-ink uppercase">{{ member.get_full_name }}</span>
<button type="submit" class="btn btn-primary h-9 px-3.5 text-sm">{% trans "Save" %}</button>
</div>
{% if open_requirement_names %}
<div class="rounded-box border border-warn-border bg-warn-bg p-3.5 text-sm text-warn-deep">
{% blocktrans count counter=open_requirement_names|length with names=open_requirement_summary %}{{ counter }} requirement still open: {{ names }}{% plural %}{{ counter }} requirements still open: {{ names }}{% endblocktrans %}
</div>
{% endif %}
<div>
<div class="mb-2 font-display text-xs font-extrabold tracking-wide text-muted uppercase">{% trans "Identity" %}</div>
<div class="m-card overflow-hidden">
<div class="p-3.5">
<label class="mb-1 block text-xs text-muted" for="{{ form.first_name.id_for_label }}">{{ form.first_name.label }}</label>
{{ form.first_name }}
{% for error in form.first_name.errors %}<p class="mt-1 text-xs text-club">{{ error }}</p>{% endfor %}
</div>
<div class="h-px bg-rule"></div>
<div class="p-3.5">
<label class="mb-1 block text-xs text-muted" for="{{ form.last_name.id_for_label }}">{{ form.last_name.label }}</label>
{{ form.last_name }}
{% for error in form.last_name.errors %}<p class="mt-1 text-xs text-club">{{ error }}</p>{% endfor %}
</div>
<div class="h-px bg-rule"></div>
<div class="p-3.5">
<label class="mb-1 block text-xs text-muted" for="{{ form.date_of_birth.id_for_label }}">{{ form.date_of_birth.label }}</label>
{{ form.date_of_birth }}
{% for error in form.date_of_birth.errors %}<p class="mt-1 text-xs text-club">{{ error }}</p>{% endfor %}
</div>
</div>
</div>
<div>
<div class="mb-2 font-display text-xs font-extrabold tracking-wide text-muted uppercase">{% trans "Contact" %}</div>
<div class="m-card overflow-hidden">
<div class="p-3.5">
<label class="mb-1 block text-xs text-muted" for="{{ form.email.id_for_label }}">{{ form.email.label }}</label>
{{ form.email }}
{% for error in form.email.errors %}<p class="mt-1 text-xs text-club">{{ error }}</p>{% endfor %}
</div>
<div class="h-px bg-rule"></div>
<div class="p-3.5">
<label class="mb-1 block text-xs text-muted" for="{{ form.phone.id_for_label }}">{{ form.phone.label }}</label>
{{ form.phone }}
{% for error in form.phone.errors %}<p class="mt-1 text-xs text-club">{{ error }}</p>{% endfor %}
</div>
</div>
</div>
<div>
<div class="mb-2 font-display text-xs font-extrabold tracking-wide text-muted uppercase">{% trans "Emergency" %}</div>
<div class="m-card overflow-hidden">
<div class="p-3.5">
<label class="mb-1 block text-xs text-muted" for="{{ form.emergency_phone.id_for_label }}">{{ form.emergency_phone.label }}</label>
{{ form.emergency_phone }}
{% for error in form.emergency_phone.errors %}<p class="mt-1 text-xs text-club">{{ error }}</p>{% endfor %}
</div>
{% for row in guardian_rows %}
<div class="h-px bg-rule"></div>
<div class="p-3.5">
<div class="text-xs text-muted">{% trans "Emergency contact" %}</div>
<div class="text-[15px] font-medium text-ink">{{ row.member.get_full_name }} &middot; {{ row.role }}</div>
</div>
{% endfor %}
</div>
</div>
</form>
{% endblock content %}