diff --git a/management/context_processors.py b/management/context_processors.py index bed78d4..05d4dd0 100644 --- a/management/context_processors.py +++ b/management/context_processors.py @@ -298,3 +298,30 @@ def sidebar_counters(request): "pending_parent_claims_count": ParentClaim.objects.filter(club=club, status=ParentClaim.Status.PENDING).count(), "games_missing_referees_count": games_missing_referees_count(club, limit=int(RefereeManagementDashboardView.DEFAULT_RANGE)), } + + +def notification_bell(request): + """The topbar bell's badge count and dropdown contents -- every signed-in + staff member can have notifications (not just admins, unlike + sidebar_counters' admin-only queues above), since notifications.Notification + is keyed to whichever Member they are, not to a role. + + None (not 0) when there's no club/signed-in user/Member row to key off -- + same "hidden means not applicable, 0 means an empty inbox" distinction + sidebar_counters draws.""" + club = getattr(request, "club", None) + if club is None or not request.user.is_authenticated: + return {"unread_notification_count": None, "recent_notifications": None} + + from members.models import Member + from notifications.models import Notification + + member = Member.objects.filter(user=request.user).first() + if member is None: + return {"unread_notification_count": None, "recent_notifications": None} + + notifications = Notification.objects.filter(club=club, member=member).order_by("-created")[:8] + return { + "unread_notification_count": Notification.objects.filter(club=club, member=member, read_at__isnull=True).count(), + "recent_notifications": notifications, + } diff --git a/management/templates/management/_news_preview.html b/management/templates/management/_news_preview.html index f98982a..75cf817 100644 --- a/management/templates/management/_news_preview.html +++ b/management/templates/management/_news_preview.html @@ -16,6 +16,8 @@
{% if news_item.status == "draft" %} {% trans "Draft" %} + {% elif news_item.status == "pending_review" %} + {% trans "Pending review" %} {% elif news_item.is_scheduled %} {% blocktrans with date=news_item.published_at %}Scheduled for {{ date }}{% endblocktrans %} {% else %} @@ -29,11 +31,17 @@ {% endif %} {% if can_publish %} - {% if news_item.status == "draft" %} - - {% else %} + {% if news_item.status == "published" %} + {% else %} + {% endif %} + {% elif can_edit and news_item.status == "draft" %} + {# Whoever can edit but not publish (a coach_manager, not an editor/admin -- see club.services.access.can_add_news vs can_publish_news) hands it off instead. #} +
+ {% csrf_token %} + +
{% endif %}
diff --git a/management/templates/management/base.html b/management/templates/management/base.html index 7291f32..66aab67 100644 --- a/management/templates/management/base.html +++ b/management/templates/management/base.html @@ -79,7 +79,7 @@ Opens upward (bottom-full): the trigger sits at the very bottom of the sidebar, so a menu opening down would run off the viewport. {% endcomment %} -
+
{% if user.member %}{{ user.member.first_name|slice:":1" }}{{ user.member.last_name|slice:":1" }}{% else %}?{% endif %} @@ -103,6 +103,40 @@ {% block heading %}{% block topbar_title %}Management{% endblock topbar_title %}{% endblock heading %} {% block topbar_context %}{% endblock topbar_context %}
+ {% if unread_notification_count is not None %} + {# Same
/ convention as the sidebar's own user-menu below -- no JS needed to open it, only the shared outside-click/Escape listener to close it. #} +
+ + {% lucide "bell" size=16 %} + {% if unread_notification_count %} + {{ unread_notification_count }} + {% endif %} + +
+
+ {% trans "Notifications" %} + {% if unread_notification_count %} +
+ {% csrf_token %} + + +
+ {% endif %} +
+
+ {% for notification in recent_notifications %} +
+ {{ notification.title }} + {{ notification.body|truncatechars:100 }} + {{ notification.created|timesince }} {% trans "ago" %} +
+ {% empty %} +

{% trans "Nothing yet." %}

+ {% endfor %} +
+
+
+ {% endif %}
{% block actions %}{% endblock actions %}
@@ -140,13 +174,19 @@