diff --git a/mobile/templates/mobile/me.html b/mobile/templates/mobile/me.html index 3882ee5..7d6a37b 100644 --- a/mobile/templates/mobile/me.html +++ b/mobile/templates/mobile/me.html @@ -7,10 +7,10 @@ calls: no license/eligibility field backing "licence OK", so each row's meta line is real roster data instead; "Household & contacts" has no screen to lead to and is omitted, same for the mockup's "Coach mode" - promo (base.html's own precedent -- no Coach mode screens exist yet, so - it's never rendered, not even as a dead/inert link). "Payments & dues" - does lead somewhere (mobile:payments) and carries its "N OPEN" pill only - once open_dues_count is actually > 0. + promo. "Payments & dues" does lead somewhere (mobile:payments) and + carries its "N OPEN" pill only once open_dues_count is actually > 0. + "Teams I coach" is new, beyond the mockup -- one row per current-season + staff assignment, linking straight into Coach mode for that team. The avatar/name/subtitle row lives in header_extra -- merged into the shared navy app-header (base.html) rather than a separately-coloured block of its own, matching the design canvas's own M5 markup. @@ -66,6 +66,25 @@ + {% if staff_assignments %} +
+
{% trans "Teams I coach" %}
+
+ {% for assignment in staff_assignments %} + {% if not forloop.first %}
{% endif %} + + {{ assignment.team.short_name|slice:":2" }} +
+
{{ assignment.team.name }}
+
{{ assignment.position }}
+
+ +
+ {% endfor %} +
+
+ {% endif %} +
{% trans "Personal details" %} diff --git a/mobile/tests.py b/mobile/tests.py index dc2b834..e49b677 100644 --- a/mobile/tests.py +++ b/mobile/tests.py @@ -1343,6 +1343,26 @@ class MeViewTests(TestCase): self.assertContains(response, "Team manager U16") + def test_no_teams_card_without_a_staff_assignment(self): + self.client.force_login(self.user) + + response = self._get() + + self.assertNotContains(response, "Teams I coach") + + def test_teams_card_lists_each_current_season_staff_assignment(self): + team = Team.objects.create(club=self.club, name="U16", short_name="U16") + position = Position.objects.create(club=self.club, name="Physio", short_name="PHY", staff_position=True, management_position=False) + StaffAssignment.objects.create(team=team, member=self.member, season=self.season, position=position) + self.client.force_login(self.user) + + response = self._get() + + self.assertContains(response, "Teams I coach") + self.assertContains(response, "U16") + self.assertContains(response, "Physio") + self.assertContains(response, reverse("mobile:coach_today") + "?team=" + str(team.pk)) + def test_empty_account_gets_a_graceful_empty_state(self): bare_user = User.objects.create_user(email="new@example.com", password="pw-secret-123") self.client.force_login(bare_user) diff --git a/mobile/views.py b/mobile/views.py index 44345ea..31ca289 100644 --- a/mobile/views.py +++ b/mobile/views.py @@ -33,7 +33,7 @@ from members.models import FamilyMembership, Member from members.views import ClubScopedPublicMixin from news.models import News from notifications.models import Notification -from teams.models import TeamMembership +from teams.models import StaffAssignment, TeamMembership from .forms import MemberProfileForm from .mixins import PersonScopeMixin @@ -530,11 +530,18 @@ class MeView(PersonScopeMixin, LoginRequiredMixin, TemplateView): ``self.me`` and into M7 (notifications). The mockup's "Household & contacts" row and its "Coach mode" promo card - have nowhere to lead in this build (no dedicated screen, no Coach mode - screens at all yet -- see base.html's own comment) and are deliberately - omitted rather than built as dead or inert links. "Payments & dues" does - lead somewhere -- PaymentsView below -- with its "N OPEN" pill only - rendered once there's actually a balance owed. + have nowhere to lead in this build (no dedicated screen) and are + deliberately omitted rather than built as dead or inert links. + "Payments & dues" does lead somewhere -- PaymentsView below -- with its + "N OPEN" pill only rendered once there's actually a balance owed. + + "Teams I coach" is new, beyond the mockup: one row per current-season + StaffAssignment self.me holds (team + position/role), each linking + straight into Coach mode for that team (mobile:coach_today?team=, + which mobile.coach_mixins.CoachScopeMixin's own ?team= handling already + resolves and persists). Shown for any staffed team, not just ones + self.me *manages* -- Coach mode's own screens already render read-only + for a non-management position, so there's nothing to hide here. There's no license/eligibility field on Member or ClubMembership to power the mockup's "licence OK" text, so each managed person's meta line is @@ -586,11 +593,16 @@ class MeView(PersonScopeMixin, LoginRequiredMixin, TemplateView): open_dues_count = len(open_dues_rows(club, self.managed_people, season)) + staff_assignments = [] + if self.me is not None and season is not None: + staff_assignments = list(StaffAssignment.objects.filter(member=self.me, season=season).select_related("team", "position").order_by("team__name")) + return super().get_context_data( member_since=member_since, team_manager_label=team_manager_label, people_rows=people_rows, open_dues_count=open_dues_count, + staff_assignments=staff_assignments, **kwargs, )