diff --git a/components/frontend/src/routes/(app)/my/hackathon/[id]/+layout.svelte b/components/frontend/src/routes/(app)/my/hackathon/[id]/+layout.svelte index 411adf00..515622c9 100644 --- a/components/frontend/src/routes/(app)/my/hackathon/[id]/+layout.svelte +++ b/components/frontend/src/routes/(app)/my/hackathon/[id]/+layout.svelte @@ -37,7 +37,12 @@ const hackathon = $derived(data.hackathon); const title = $derived(hackathon.name); const dates = $derived(formatDates(hackathon.startsAt, hackathon.endsAt)); - const participantCount = $derived(hackathon.members.length); + // Counted the way the Participants list counts its rows — which drops + // waitlisted members, for everyone — so the hero and that page never + // disagree. How many are waiting is the Manage hub's badge, not this number. + const participantCount = $derived( + hackathon.members.filter((m) => !m.isWaiting).length, + ); // Same resolution the timeline page uses, so the header bar and the page never // disagree about which phase is the live one. const phases = $derived( diff --git a/components/frontend/src/routes/(app)/my/hackathon/[id]/participants/+page.server.ts b/components/frontend/src/routes/(app)/my/hackathon/[id]/participants/+page.server.ts index 80635c96..0f5d57ff 100644 --- a/components/frontend/src/routes/(app)/my/hackathon/[id]/participants/+page.server.ts +++ b/components/frontend/src/routes/(app)/my/hackathon/[id]/participants/+page.server.ts @@ -4,17 +4,23 @@ import { membershipBadgeLabel } from "$lib/utils/hackathonRole" // No owner/admin check here: the way into participant management is the // sidebar's Manage section, which gates itself on the same subjects (see // $lib/navigation's manageNav) and owns the Approve/Remove actions. This page is -// the participant view and reads the same for everyone. +// the participant view and reads the same for everyone — an organizer included, +// which is what lets them see exactly what a participant sees. export const load: PageServerLoad = async (event) => { // No RPC of its own: the layout's `hackathon.get` already returns every // participant with their casbin role and waitlist flag. const { hackathon } = await event.parent() - // Waitlisted members are listed too, carrying a "Waitlisted" label. They are - // real rows in the hackathon's membership, and the label says which is which - // — hiding them would make the page disagree with the count in the header. + // Waitlisted members are dropped: who has applied and not been accepted is + // between the applicant and the organizer, and the "Waitlisted" chip + // otherwise told every participant which of their peers was still pending. + // They are not hidden from the people who act on them — Manage Participants + // lists them, with Approve, and the Manage hub badges how many are waiting. + // + // Filtered in the load rather than the component, so this page's payload never + // carries the waitlisted names at all. const participants = hackathon.members - .filter((m) => m.user !== undefined) + .filter((m) => m.user !== undefined && !m.isWaiting) .map((m) => ({ id: m.user!.id, name: m.user!.displayName || m.user!.username,