diff --git a/components/frontend/src/lib/components/hackathon/ParticipantCard.svelte b/components/frontend/src/lib/components/hackathon/ParticipantCard.svelte index d9bdd303..a704baa9 100644 --- a/components/frontend/src/lib/components/hackathon/ParticipantCard.svelte +++ b/components/frontend/src/lib/components/hackathon/ParticipantCard.svelte @@ -9,7 +9,7 @@ role: roleProp, skills = [], linkedinUrl, - profileDetailsHref = '#', + profileDetailsHref, actions, }: { name: string; @@ -26,6 +26,8 @@ role?: string; skills?: string[]; linkedinUrl?: string; + /** When unset, no "View" link is rendered — the caller has decided this + * viewer has nowhere to go (e.g. a member who can't read others). */ profileDetailsHref?: string; /** * Extra controls rendered beside "View" — e.g. an owner's Approve/Remove @@ -112,8 +114,10 @@
- - View + {#if profileDetailsHref} + + View + {/if} {#if actions} {@render actions()} {/if} 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 f9c5050f..cd8f2c30 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 @@ -33,6 +33,7 @@ export const load: PageServerLoad = async (event) => { return { participants, ownerCount, + hackathonId: event.params.id, // 0 means unlimited — the page renders the fullness gauge and the // over-capacity warning only when a cap is set. maxParticipants: hackathon.maxParticipants ?? 0, diff --git a/components/frontend/src/routes/(app)/my/hackathon/[id]/participants/+page.svelte b/components/frontend/src/routes/(app)/my/hackathon/[id]/participants/+page.svelte index 032cdc3d..7fa6023c 100644 --- a/components/frontend/src/routes/(app)/my/hackathon/[id]/participants/+page.svelte +++ b/components/frontend/src/routes/(app)/my/hackathon/[id]/participants/+page.svelte @@ -76,6 +76,17 @@ function mayDemote(p: Participant): boolean { return data.mayManage && p.isOwner && !p.isSelf && data.ownerCount > 1; } + + // "View" opens this person's registration answers. Your own row goes to + // your editable form; another person's needs organizer rights, so it is a + // read-only ?userId= view offered only to managers — a plain member would + // deterministically 403, matching how every organizer-only action here is + // hidden rather than left to fail. + function viewHref(p: Participant): string | undefined { + if (p.isSelf) return `/register/${data.hackathonId}`; + if (data.mayManage) return `/register/${data.hackathonId}?userId=${p.id}`; + return undefined; + } + {#if !data.alreadySubmitted} +

No response yet.

+ {:else} +
+ {#each data.fields as f (f.key)} +
+
{f.label}
+
+ {data.answers[f.key] || '—'} +
+
+ {/each} + {#each data.consents as c (c.key)} +
+ + {c.label} +
+ {/each} +
+ {/if} + {:else if form?.submitted}

Thanks — your answers are in.