From 91b352de18ea3faf43ddd095b1ba7c388c92758c Mon Sep 17 00:00:00 2001 From: joshua Date: Thu, 23 Jul 2026 16:56:32 +0200 Subject: [PATCH] Add closed/past/inactive status badges to user dashboard event titles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds an EventStatusBadge component shown next to every event title on the dashboard (registrations list, upcoming events, tickets, and the registration modal), with precedence Closed > Past > Inactive when more than one applies — reusing the badge styling already established in the supervisor events list. Co-Authored-By: Claude Sonnet 5 --- CHANGELOG.md | 4 +++ frontend/src/app/dashboard/user/page.tsx | 33 +++++++++++++++++++++--- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d0496e..4ef51d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ and this project follows [Semantic Versioning](https://semver.org/). - User dashboard: registration-edit errors now show inside the edit popup instead of being hidden behind it. - User dashboard: closed events are now hidden by default alongside past events (revealed via "Show past events"), and the Edit, Make payment, and Cancel registration actions no longer appear for closed or past registrations (also enforced server-side). +### Added + +- User dashboard: event titles now show a status badge (Closed / Past / Inactive, in that precedence) wherever they're listed. + ## [1.0.0] - 2026-07-23 ### Added diff --git a/frontend/src/app/dashboard/user/page.tsx b/frontend/src/app/dashboard/user/page.tsx index b97b271..f243369 100644 --- a/frontend/src/app/dashboard/user/page.tsx +++ b/frontend/src/app/dashboard/user/page.tsx @@ -12,6 +12,23 @@ const isFuture = (d: string | Date) => new Date(d).getTime() > Date.now(); const isEventOver = (ev: any) => !!ev && ((ev.endDate && new Date(ev.endDate).getTime() < Date.now()) || ev.cashupStatus === 'closed'); +// Status badge for an event, shown wherever an event title is displayed on this page. +// Precedence when more than one applies: Closed > Past > Inactive. +function EventStatusBadge({ event }: { event: any }) { + if (!event) return null; + let label: string | null = null; + let className = ''; + if (event.cashupStatus === 'closed') { + label = 'Closed'; className = 'bg-rose-50 text-rose-700'; + } else if (event.endDate && new Date(event.endDate).getTime() < Date.now()) { + label = 'Past'; className = 'bg-amber-50 text-amber-700'; + } else if (event.isActive === false) { + label = 'Inactive'; className = 'bg-gray-100 text-gray-500'; + } + if (!label) return null; + return {label}; +} + // Effective unit price for an event option (or one of its variants), early-bird aware. // Used by the registration editor, which works off raw /api/events/:id data rather than // a registration's priceSnapshot — mirrors the pricing logic in register/[eventId]/RegisterForm.tsx. @@ -655,7 +672,10 @@ export default function UserDashboardPage() { >
-
{r.event?.title || r.eventId}
+
+ {r.event?.title || r.eventId} + +
Status: {r.status}{isCancelled && cancelled}
@@ -728,7 +748,10 @@ export default function UserDashboardPage() {
    {upcomingEvents.map(ev => (
  • -
    {ev.title}
    +
    + {ev.title} + +
    {new Date(ev.startDate).toLocaleString()} - {new Date(ev.endDate).toLocaleString()}
    {type}
    @@ -832,7 +856,10 @@ export default function UserDashboardPage() {
    { setEditMode(false); setEditError(null); setShowCancelConfirm(false); setActiveRegId(null); }}>
    e.stopPropagation()}>
    -

    {activeReg.event?.title || activeReg.eventId}

    +

    + {activeReg.event?.title || activeReg.eventId} + +