Build M2 Event detail ("answer for several") for the mobile app
Full event-detail screen: hero header, Face-off/Meet/Where facts (the design mock's Kit/dressing-room details have no backing Event field, so they're simply omitted), a per-managed-person RSVP card so a parent with several kids on the same event can answer for each independently, and a club-visible squad-response aggregate (counts only, never who answered what). Extends the existing quick-RSVP POST (built for M1's Home hero) to also accept "maybe" for M2's three-way buttons, and adds an optional next=event_detail redirect target so answering here doesn't bounce back to Home -- M1's and M3's existing forms are unaffected. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
This commit is contained in:
126
mobile/templates/mobile/event_detail.html
Normal file
126
mobile/templates/mobile/event_detail.html
Normal file
@@ -0,0 +1,126 @@
|
||||
{% extends "mobile/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% comment %}
|
||||
M2 -- design_handoff_rosterchief_platform/README.md's M2 section, "answer
|
||||
for several". See EventDetailView's own docstring (mobile/views.py) for
|
||||
the judgment calls: no event photos, no Kit/dressing-room fields (the
|
||||
Event model has none), squad response is counts-only (never who answered
|
||||
what).
|
||||
{% endcomment %}
|
||||
|
||||
{% block content %}
|
||||
<div class="-mx-4 -mt-4 flex h-[220px] flex-col justify-end bg-ink p-4 text-white" style="background: linear-gradient(180deg, rgba(11,18,32,.35) 0%, rgba(11,18,32,.55) 60%, rgba(11,18,32,.92) 100%), var(--color-navy)">
|
||||
<a class="mb-auto flex h-11 w-11 items-center justify-center rounded-full bg-white/15" href="{% url "mobile:home" %}" aria-label="{% trans "Back" %}">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M15 5l-7 7 7 7"/></svg>
|
||||
</a>
|
||||
<span class="mb-2 inline-block w-fit rounded bg-club px-2 py-1 font-display text-xs font-extrabold tracking-wide text-white uppercase">
|
||||
{% if event.kind == "game" %}{% if event.is_home_game %}{% trans "Home game" %}{% else %}{% trans "Away game" %}{% endif %}{% else %}{{ event.get_kind_display }}{% endif %}
|
||||
</span>
|
||||
<h1 class="font-display text-4xl leading-[.98] font-extrabold uppercase">{{ event.title }}</h1>
|
||||
</div>
|
||||
|
||||
<div class="m-card flex flex-col gap-2.5 p-4">
|
||||
<div class="flex gap-3.5">
|
||||
<span class="w-20 shrink-0 font-display text-xs font-extrabold tracking-wide text-muted uppercase">{% trans "Face-off" %}</span>
|
||||
<span class="text-[15px] font-semibold text-ink">{{ event.start|date:"D d M \a\t H:i" }}</span>
|
||||
</div>
|
||||
{% if event.gathering %}
|
||||
<div class="flex gap-3.5">
|
||||
<span class="w-20 shrink-0 font-display text-xs font-extrabold tracking-wide text-muted uppercase">{% trans "Meet" %}</span>
|
||||
<span class="text-[15px] font-semibold text-ink">{{ event.gathering|date:"H:i" }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if event.location %}
|
||||
<div class="flex gap-3.5">
|
||||
<span class="w-20 shrink-0 font-display text-xs font-extrabold tracking-wide text-muted uppercase">{% trans "Where" %}</span>
|
||||
<span class="text-[15px] font-semibold text-ink">
|
||||
{{ event.location.name }}<br>
|
||||
<span class="text-[13px] font-normal text-muted">{{ event.location.address }}, {{ event.location.zip_code }} {{ event.location.city }}</span>
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if your_answers %}
|
||||
<div class="m-card p-4">
|
||||
<span class="font-display text-xs font-extrabold tracking-wide text-muted uppercase">{% trans "Your answers" %}</span>
|
||||
<div class="mt-3 flex flex-col gap-3">
|
||||
{% for answer in your_answers %}
|
||||
{% if not forloop.first %}<div class="h-px bg-rule"></div>{% endif %}
|
||||
<div>
|
||||
<div class="mb-2 flex items-center gap-2.5">
|
||||
<span class="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-steel font-display text-sm font-extrabold text-white">{{ answer.member.first_name|slice:":1" }}{{ answer.member.last_name|slice:":1" }}</span>
|
||||
<div class="min-w-0 flex-1">
|
||||
<div class="text-[15px] font-semibold text-ink">{{ answer.member.get_full_name }}</div>
|
||||
{% if answer.membership %}
|
||||
<div class="text-xs text-muted">
|
||||
{{ answer.membership.team.short_name }}
|
||||
{% if answer.membership.jersey_number %}· #{{ answer.membership.jersey_number }}{% endif %}
|
||||
{% if answer.membership.position %}· {{ answer.membership.position.name }}{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if answer.attendance.status == "no_response" %}
|
||||
<span class="pill pill-warn shrink-0">{% trans "No reply" %}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="flex gap-1.5">
|
||||
{% trans "In" as label_in %}
|
||||
{% trans "Maybe" as label_maybe %}
|
||||
{% trans "Out" as label_out %}
|
||||
{% with status=answer.attendance.status %}
|
||||
<form class="flex-1" method="post" action="{% url "mobile:event_detail" event.pk %}">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="member_id" value="{{ answer.member.pk }}">
|
||||
<input type="hidden" name="status" value="present">
|
||||
<input type="hidden" name="next" value="event_detail">
|
||||
<button type="submit" class="btn h-11 w-full text-[15px] {% if status == "present" %}btn-positive{% else %}bg-paper border border-stroke text-muted{% endif %}">{{ label_in }}</button>
|
||||
</form>
|
||||
<form class="flex-1" method="post" action="{% url "mobile:event_detail" event.pk %}">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="member_id" value="{{ answer.member.pk }}">
|
||||
<input type="hidden" name="status" value="maybe">
|
||||
<input type="hidden" name="next" value="event_detail">
|
||||
<button type="submit" class="btn h-11 w-full text-[15px] {% if status == "maybe" %}bg-steel text-white{% else %}bg-paper border border-stroke text-muted{% endif %}">{{ label_maybe }}</button>
|
||||
</form>
|
||||
<form class="flex-1" method="post" action="{% url "mobile:event_detail" event.pk %}">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="member_id" value="{{ answer.member.pk }}">
|
||||
<input type="hidden" name="status" value="absent">
|
||||
<input type="hidden" name="next" value="event_detail">
|
||||
<button type="submit" class="btn h-11 w-full text-[15px] {% if status == "absent" %}bg-club text-white{% else %}bg-paper border border-stroke text-muted{% endif %}">{{ label_out }}</button>
|
||||
</form>
|
||||
{% endwith %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if squad_summary %}
|
||||
<div class="m-card p-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="font-display text-xs font-extrabold tracking-wide text-muted uppercase">{% trans "Squad response" %}</span>
|
||||
<span class="text-[13px] text-muted">{% blocktrans with responded=squad_summary.responded total=squad_summary.total %}{{ responded }} of {{ total }}{% endblocktrans %}</span>
|
||||
</div>
|
||||
<div class="mt-2.5 flex h-2 overflow-hidden rounded-full bg-rule">
|
||||
<div class="bg-ok" style="width: {{ squad_summary.in_pct }}%"></div>
|
||||
<div class="bg-club" style="width: {{ squad_summary.out_pct }}%"></div>
|
||||
<div class="bg-line" style="width: {{ squad_summary.no_reply_pct }}%"></div>
|
||||
</div>
|
||||
<div class="mt-2 flex gap-3.5 text-[13px] text-muted">
|
||||
<span><strong class="text-ink">{{ squad_summary.in_count }}</strong> {% trans "in" %}</span>
|
||||
<span><strong class="text-ink">{{ squad_summary.out_count }}</strong> {% trans "out" %}</span>
|
||||
<span><strong class="text-ink">{{ squad_summary.no_reply_count }}</strong> {% trans "no reply" %}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if not your_answers and not squad_summary %}
|
||||
<div class="m-card p-6 text-center">
|
||||
<p class="text-sm text-muted">{% trans "No one you manage is invited to this event." %}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock content %}
|
||||
Reference in New Issue
Block a user