Coach Schedule: same This week/Next week/month-divider agenda grouping
Extracted the grouping algorithm (previously duplicated between mobile.views. CalendarView and management.views.EventListView's own "List" mode) into a shared events.services.calendar.agenda_groups, and wired it into both -- plus mobile.coach_views.CoachScheduleView, the coach app's own upcoming- events screen, which had no grouping at all before (one flat card). All three now read identically and can't drift apart. Also: give each management event-list row's kind badge a fixed width, so titles start at the same horizontal position regardless of whether the row says "Game" or "Tournament". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{% load i18n lucide ui %}
|
||||
<div class="flex items-center gap-3 px-4 py-3 {% if not forloop.last %}border-b border-line{% endif %}">
|
||||
<span class="badge badge-sm shrink-0 {% if event.kind == "game" %}badge-error{% elif event.kind == "training" %}badge-info{% elif event.kind == "tournament" %}badge-warning{% elif event.kind == "meeting" %}badge-neutral{% elif event.kind == "social" %}border-violet/30 bg-violet/10 text-violet{% else %}badge-outline{% endif %}">
|
||||
<span class="badge badge-sm w-24 shrink-0 justify-center {% if event.kind == "game" %}badge-error{% elif event.kind == "training" %}badge-info{% elif event.kind == "tournament" %}badge-warning{% elif event.kind == "meeting" %}badge-neutral{% elif event.kind == "social" %}border-violet/30 bg-violet/10 text-violet{% else %}badge-outline{% endif %}">
|
||||
{{ event.get_kind_display }}
|
||||
</span>
|
||||
<div class="min-w-0 flex-1">
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
{% for month in list_months %}
|
||||
<div class="card overflow-hidden">
|
||||
<div class="border-b border-line bg-subhead px-4 py-2 font-display text-xs font-extrabold tracking-[.08em] text-ink uppercase">{{ month.month_start|date:"F Y" }}</div>
|
||||
{% for event in month.events %}{% include "management/_event_list_row.html" %}{% endfor %}
|
||||
{% for event in month.items %}{% include "management/_event_list_row.html" %}{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
@@ -5625,7 +5625,7 @@ class EventManagementTests(ManagementTestBase):
|
||||
self.assertEqual([event.title for event in response.context["list_next_week"]], ["Next week event"])
|
||||
later_months = response.context["list_months"]
|
||||
self.assertEqual(len(later_months), 1)
|
||||
self.assertEqual([event.title for event in later_months[0]["events"]], ["Later event"])
|
||||
self.assertEqual([event.title for event in later_months[0]["items"]], ["Later event"])
|
||||
self.assertContains(response, "This week")
|
||||
self.assertContains(response, "Next week")
|
||||
self.assertContains(response, later_event.start.strftime("%B %Y"))
|
||||
@@ -5640,7 +5640,7 @@ class EventManagementTests(ManagementTestBase):
|
||||
self.assertEqual(response.context["list_this_week"], [])
|
||||
self.assertEqual(response.context["list_next_week"], [])
|
||||
self.assertEqual(len(response.context["list_months"]), 1)
|
||||
self.assertEqual([event.title for event in response.context["list_months"][0]["events"]], ["Past event"])
|
||||
self.assertEqual([event.title for event in response.context["list_months"][0]["items"]], ["Past event"])
|
||||
self.assertNotContains(response, "This week")
|
||||
|
||||
def test_the_dashboard_only_shows_upcoming_events_for_managed_teams(self):
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import itertools
|
||||
from datetime import date, timedelta
|
||||
from decimal import Decimal
|
||||
|
||||
@@ -38,7 +37,7 @@ from controlpanel.mixins import RedirectOnInvalidMixin
|
||||
from controlpanel.services.statistics import club_attention, club_charts, club_statistics, unrostered_members
|
||||
from events.models import Attendance, Event, EventReferee, EventSeries, Location, Opponent, RefereeSignup
|
||||
from events.services.attendance import member_attendance_counts, member_attendance_sparkline, player_attendance_rankings, players_who_missed_recent_practices, team_attendance_rate, team_no_shows
|
||||
from events.services.calendar import add_months, month_bounds, month_grid, season_grid, week_bounds, week_grid
|
||||
from events.services.calendar import add_months, agenda_groups, month_bounds, month_grid, season_grid, week_bounds, week_grid
|
||||
from events.services.competitions import CompetitionFetchError, fetch_game_info
|
||||
from events.services.rbihf_import import RBIHFImportError, apply_plan, build_plan, extract_team_id, fetch_html
|
||||
from events.services.recurrence import cancel_occurrence, detach_occurrence, generate_occurrences, propagate_series
|
||||
@@ -2473,36 +2472,15 @@ class EventListView(ClubStaffRequiredMixin, ListView):
|
||||
return grid, calendar_nav
|
||||
|
||||
def _list_groups(self, events, show_past):
|
||||
"""The same This week/Next week/by-month agenda grouping mobile.views.
|
||||
CalendarView uses (see that view's own docstring for the algorithm) --
|
||||
applied to whichever page of `events` is actually being shown, so
|
||||
pagination and grouping don't fight each other. Past mode (show_past=1,
|
||||
already descending) skips the this/next-week special-casing -- those
|
||||
labels only make sense for what's ahead -- and just groups straight
|
||||
into months, most recent first."""
|
||||
if not events:
|
||||
return [], [], []
|
||||
|
||||
if show_past:
|
||||
months = [{"month_start": month_start, "events": list(month_events)} for month_start, month_events in itertools.groupby(events, key=lambda event: timezone.localtime(event.start).date().replace(day=1))]
|
||||
return [], [], months
|
||||
|
||||
today = timezone.localdate()
|
||||
_this_week_start, this_week_end = week_bounds(today)
|
||||
next_week_end = this_week_end + timedelta(days=7)
|
||||
|
||||
this_week, next_week, later = [], [], []
|
||||
for event in events:
|
||||
event_date = timezone.localtime(event.start).date()
|
||||
if event_date <= this_week_end:
|
||||
this_week.append(event)
|
||||
elif event_date <= next_week_end:
|
||||
next_week.append(event)
|
||||
else:
|
||||
later.append(event)
|
||||
|
||||
later_months = [{"month_start": month_start, "events": list(month_events)} for month_start, month_events in itertools.groupby(later, key=lambda event: timezone.localtime(event.start).date().replace(day=1))]
|
||||
return this_week, next_week, later_months
|
||||
"""The shared This week/Next week/by-month agenda grouping (events.
|
||||
services.calendar.agenda_groups, also behind mobile.views.CalendarView
|
||||
and mobile.coach_views.CoachScheduleView) -- applied to whichever page
|
||||
of `events` is actually being shown, so pagination and grouping don't
|
||||
fight each other. Past mode (show_past=1, already descending) skips
|
||||
the this/next-week special-casing -- those labels only make sense for
|
||||
what's ahead -- and just groups straight into months, most recent
|
||||
first."""
|
||||
return agenda_groups(events, show_past=show_past)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
club, user = self.request.club, self.request.user
|
||||
|
||||
Reference in New Issue
Block a user