Add families list, member kind filter, sidebar counters, pagination
New Families list page (parents/children columns, edit goes to the detail view). Members list gets a member/guardian/both filter so guardians aren't just invisible. Sidebar now shows live counts for pending parent claims and games missing a referee, always numeric. Member, event, team, group, news and family lists are paginated with a shared pager partial that preserves the query string. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,8 +16,14 @@
|
||||
|
||||
<li class="menu-title">{% trans "People" %}</li>
|
||||
<li><a class="{% if nav == 'member_list' %}menu-active{% endif %}" href="{% url 'management:member_list' %}">{% lucide "users" size=16 %} {% trans "Members" %}</a></li>
|
||||
<li><a class="{% if nav == 'family_list' %}menu-active{% endif %}" href="{% url 'management:family_list' %}">{% lucide "home" size=16 %} {% trans "Families" %}</a></li>
|
||||
{% if is_club_admin %}
|
||||
<li><a class="{% if nav == 'parent_claim_list' %}menu-active{% endif %}" href="{% url 'management:parent_claim_list' %}">{% lucide "inbox" size=16 %} {% trans "Parent claims" %}</a></li>
|
||||
<li>
|
||||
<a class="{% if nav == 'parent_claim_list' %}menu-active{% endif %}" href="{% url 'management:parent_claim_list' %}">
|
||||
{% lucide "inbox" size=16 %} {% trans "Parent claims" %}
|
||||
<span class="badge badge-sm ml-auto {% if pending_parent_claims_count %}badge-error{% else %}badge-neutral{% endif %}">{{ pending_parent_claims_count }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if is_club_admin %}
|
||||
<li><a class="{% if nav == 'membership_list' %}menu-active{% endif %}" href="{% url 'management:membership_list' %}">{% lucide "wallet" size=16 %} {% trans "Memberships" %}</a></li>
|
||||
@@ -30,7 +36,12 @@
|
||||
<li><a class="{% if nav == 'position_list' %}menu-active{% endif %}" href="{% url 'management:position_list' %}">{% lucide "tags" size=16 %} {% trans "Positions" %}</a></li>
|
||||
{% if is_club_admin %}
|
||||
<li><a class="{% if nav == 'referee_level_list' %}menu-active{% endif %}" href="{% url 'management:referee_level_list' %}">{% lucide "badge-check" size=16 %} {% trans "Referee levels" %}</a></li>
|
||||
<li><a class="{% if nav == 'referee_management' %}menu-active{% endif %}" href="{% url 'management:referee_management' %}">{% lucide "calendar-check" size=16 %} {% trans "Referee management" %}</a></li>
|
||||
<li>
|
||||
<a class="{% if nav == 'referee_management' %}menu-active{% endif %}" href="{% url 'management:referee_management' %}">
|
||||
{% lucide "calendar-check" size=16 %} {% trans "Referee management" %}
|
||||
<span class="badge badge-sm ml-auto {% if games_missing_referees_count %}badge-error{% else %}badge-neutral{% endif %}">{{ games_missing_referees_count }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li><a class="{% if nav == 'referee_list' %}menu-active{% endif %}" href="{% url 'management:referee_list' %}">{% lucide "flag" size=16 %} {% trans "Referees" %}</a></li>
|
||||
|
||||
|
||||
32
management/templates/management/_pagination.html
Normal file
32
management/templates/management/_pagination.html
Normal file
@@ -0,0 +1,32 @@
|
||||
{% load i18n lucide %}
|
||||
|
||||
{% comment %}
|
||||
Shared pager for every paginated management list (see paginate_by on
|
||||
MemberListView/EventListView/TeamListView/GroupListView/NewsListView/
|
||||
FamilyListView) -- {% include %} this once rather than duplicating prev/next
|
||||
markup per template. Expects the standard ListView pagination context
|
||||
(page_obj/paginator/is_paginated); renders nothing on an unpaginated page.
|
||||
|
||||
{% querystring %} (built-in since Django 5.1) rebuilds the current query
|
||||
string with just `page` overridden, so an active ?q=/?kind=/?season= filter
|
||||
survives a page link instead of being dropped.
|
||||
{% endcomment %}
|
||||
{% if is_paginated %}
|
||||
<div class="mt-4 flex flex-wrap items-center justify-between gap-2">
|
||||
<span class="text-sm opacity-60">
|
||||
{% blocktrans with number=page_obj.number total=paginator.num_pages %}Page {{ number }} of {{ total }}{% endblocktrans %}
|
||||
</span>
|
||||
<div class="join">
|
||||
{% if page_obj.has_previous %}
|
||||
<a href="{% querystring page=page_obj.previous_page_number %}" class="btn btn-sm join-item">{% lucide "chevron-left" size=14 %} {% trans "Previous" %}</a>
|
||||
{% else %}
|
||||
<span class="btn btn-sm join-item btn-disabled">{% lucide "chevron-left" size=14 %} {% trans "Previous" %}</span>
|
||||
{% endif %}
|
||||
{% if page_obj.has_next %}
|
||||
<a href="{% querystring page=page_obj.next_page_number %}" class="btn btn-sm join-item">{% trans "Next" %} {% lucide "chevron-right" size=14 %}</a>
|
||||
{% else %}
|
||||
<span class="btn btn-sm join-item btn-disabled">{% trans "Next" %} {% lucide "chevron-right" size=14 %}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -80,6 +80,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include "management/_pagination.html" %}
|
||||
|
||||
{% comment %} Dialogs live outside the table: <tbody> may only contain <tr> elements. {% endcomment %}
|
||||
{% for event in events %}
|
||||
{% if event.can_manage %}
|
||||
|
||||
61
management/templates/management/family_list.html
Normal file
61
management/templates/management/family_list.html
Normal file
@@ -0,0 +1,61 @@
|
||||
{% extends "management/base.html" %}
|
||||
{% load i18n lucide %}
|
||||
|
||||
{% block heading %}{% trans "Families" %}{% endblock heading %}
|
||||
{% block subheading %}{% trans "Every household on file -- who their parents/guardians and children are." %}{% endblock subheading %}
|
||||
|
||||
{% block actions %}
|
||||
{% if is_club_admin %}
|
||||
<a class="btn btn-outline gap-2" href="{% url 'management:family_create' %}">{% lucide "users" size=16 %} {% trans "Add family" %}</a>
|
||||
{% endif %}
|
||||
{% endblock actions %}
|
||||
|
||||
{% block panel %}
|
||||
<div class="card bg-base-100 shadow">
|
||||
<div class="card-body">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "Family" %}</th>
|
||||
<th>{% trans "Parents / guardians" %}</th>
|
||||
<th>{% trans "Children" %}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for family in families %}
|
||||
<tr>
|
||||
<td><a class="link link-hover font-semibold" href="{% url 'management:family_detail' family.pk %}">{{ family }}</a></td>
|
||||
<td>
|
||||
{% for guardian in family.guardians_display %}
|
||||
<a class="link link-hover" href="{% url 'management:member_detail' guardian.pk %}">{{ guardian }}</a>{% if not forloop.last %}, {% endif %}
|
||||
{% empty %}
|
||||
<span class="opacity-40">-</span>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>
|
||||
{% for child in family.children_display %}
|
||||
<a class="link link-hover" href="{% url 'management:member_detail' child.pk %}">{{ child }}</a>{% if not forloop.last %}, {% endif %}
|
||||
{% empty %}
|
||||
<span class="opacity-40">-</span>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{# Same convention as Groups: "Edit" lands on the overview page, not a standalone rename form -- family_detail is where every family action (add parent/child, change role, remove) actually lives. #}
|
||||
<a class="btn btn-outline btn-sm" href="{% url 'management:family_detail' family.pk %}" aria-label="{% trans 'Edit' %}">{% lucide "pencil" size=14 %} {% trans "Edit" %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="4" class="text-center opacity-60">{% trans "No families yet." %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include "management/_pagination.html" %}
|
||||
{% endblock panel %}
|
||||
@@ -43,6 +43,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include "management/_pagination.html" %}
|
||||
|
||||
{% trans "Delete group" as delete_group_title %}
|
||||
{% trans "Delete" as delete_label %}
|
||||
{% for group in groups %}
|
||||
|
||||
@@ -13,17 +13,35 @@
|
||||
{% endblock actions %}
|
||||
|
||||
{% block panel %}
|
||||
<form method="get" class="mb-4 flex gap-2">
|
||||
<form method="get" class="mb-2 flex flex-wrap items-center gap-2">
|
||||
<label class="input">
|
||||
<span class="opacity-50">{% lucide "search" size=16 %}</span>
|
||||
<input type="search" name="q" value="{{ search }}" placeholder="{% trans 'Search members ...' %}" class="input input-bordered w-full max-w-xs">
|
||||
</label>
|
||||
{% if selected_kind != "member" %}<input type="hidden" name="kind" value="{{ selected_kind }}">{% endif %}
|
||||
<button class="btn btn-outline gap-2" type="submit">{% lucide "search" size=16 %} {% trans "Search" %}</button>
|
||||
{% if search %}
|
||||
<a class="btn gap-2" href="{% url "management:member_list" %}">{% lucide "x" size=16 %} {% trans "Clear filter" %}</a>
|
||||
{% endif %}
|
||||
</form>
|
||||
|
||||
{% comment %}
|
||||
Guardians -- parents attached to the club only through a child -- have no
|
||||
fee and aren't counted as members, so members_visible_to() leaves them out
|
||||
of the default list entirely. Without this filter that's silent: a parent
|
||||
just registered via "Add family"/"Add parent" simply doesn't appear here,
|
||||
with nothing on the page explaining why. ?kind= makes the exclusion an
|
||||
explicit, reversible choice instead.
|
||||
{% endcomment %}
|
||||
<div class="mb-4 flex flex-wrap items-center gap-2">
|
||||
<div class="join">
|
||||
<a href="{% querystring kind=None page=None %}" class="btn btn-sm join-item {% if selected_kind == "member" %}btn-primary{% endif %}">{% trans "Members" %}</a>
|
||||
<a href="{% querystring kind="guardian" page=None %}" class="btn btn-sm join-item {% if selected_kind == "guardian" %}btn-primary{% endif %}">{% trans "Guardians" %}</a>
|
||||
<a href="{% querystring kind="both" page=None %}" class="btn btn-sm join-item {% if selected_kind == "both" %}btn-primary{% endif %}">{% trans "Both" %}</a>
|
||||
</div>
|
||||
<span class="text-xs opacity-60">{% trans "Guardians are parents linked only through a child -- no fee, not counted as a member." %}</span>
|
||||
</div>
|
||||
|
||||
<div class="card bg-base-100 shadow">
|
||||
<div class="card-body">
|
||||
<div class="overflow-x-auto">
|
||||
@@ -90,6 +108,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include "management/_pagination.html" %}
|
||||
|
||||
{% if is_club_admin %}
|
||||
{% trans "Delete member" as delete_member_title %}
|
||||
{% trans "Delete" as delete_label %}
|
||||
|
||||
@@ -64,6 +64,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include "management/_pagination.html" %}
|
||||
|
||||
{% trans "Delete news item" as delete_news_title %}
|
||||
{% trans "Delete" as delete_label %}
|
||||
{% for news_item in news_items %}
|
||||
|
||||
@@ -50,6 +50,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include "management/_pagination.html" %}
|
||||
|
||||
{% if is_club_admin %}
|
||||
{% trans "Delete team" as delete_team_title %}
|
||||
{% trans "Delete" as delete_label %}
|
||||
|
||||
Reference in New Issue
Block a user