feat: member profile pages with clickable links from all member lists
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m51s

- Member detail page (/admin/members/[id]) now shows:
  - Profile details card (nationality, country, institution, bio)
  - Team memberships / projects with links to project pages
  - Jury groups with role (Chair/Member/Observer)
  - All roles including Applicant, Award Master, Audience in role selector
- Project detail page team members now show:
  - Nationality, institution, country inline
  - Names are clickable links to member profile pages
- Members list: names are clickable links to profile pages (all tabs)
- Applicants tab: added nationality and institution columns
- Backend: user.get includes teamMemberships and juryGroupMemberships
- Backend: project.getFullDetail includes nationality/country/institution

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 13:29:56 +01:00
parent c6d0f90038
commit b6ba5d7145
5 changed files with 168 additions and 15 deletions

View File

@@ -354,19 +354,19 @@ export function MembersContent() {
/>
</TableCell>
<TableCell>
<div className="flex items-center gap-3">
<Link href={`/admin/members/${user.id}`} className="flex items-center gap-3 hover:opacity-80">
<UserAvatar
user={user}
avatarUrl={(user as Record<string, unknown>).avatarUrl as string | undefined}
size="sm"
/>
<div>
<p className="font-medium">{user.name || 'Unnamed'}</p>
<p className="font-medium hover:underline">{user.name || 'Unnamed'}</p>
<p className="text-sm text-muted-foreground">
{user.email}
</p>
</div>
</div>
</Link>
</TableCell>
<TableCell>
<div className="flex flex-wrap gap-1">
@@ -460,14 +460,14 @@ export function MembersContent() {
avatarUrl={(user as Record<string, unknown>).avatarUrl as string | undefined}
size="md"
/>
<div>
<CardTitle className="text-base">
<Link href={`/admin/members/${user.id}`}>
<CardTitle className="text-base hover:underline">
{user.name || 'Unnamed'}
</CardTitle>
<CardDescription className="text-xs">
{user.email}
</CardDescription>
</div>
</Link>
</div>
<div className="flex flex-col items-end gap-1.5">
<Badge variant={statusColors[user.status] || 'secondary'}>
@@ -695,6 +695,8 @@ function ApplicantsTabContent({ search, searchInput, setSearchInput }: { search:
</TableHead>
<TableHead>Applicant</TableHead>
<TableHead>Project</TableHead>
<TableHead>Nationality</TableHead>
<TableHead>Institution</TableHead>
<TableHead>Status</TableHead>
<TableHead>Last Login</TableHead>
</TableRow>
@@ -709,10 +711,10 @@ function ApplicantsTabContent({ search, searchInput, setSearchInput }: { search:
/>
</TableCell>
<TableCell>
<div>
<p className="font-medium">{user.name || 'Unnamed'}</p>
<Link href={`/admin/members/${user.id}`} className="block">
<p className="font-medium hover:underline">{user.name || 'Unnamed'}</p>
<p className="text-sm text-muted-foreground">{user.email}</p>
</div>
</Link>
</TableCell>
<TableCell>
{user.projectName ? (
@@ -721,6 +723,12 @@ function ApplicantsTabContent({ search, searchInput, setSearchInput }: { search:
<span className="text-sm text-muted-foreground">-</span>
)}
</TableCell>
<TableCell>
<span className="text-sm">{user.nationality || <span className="text-muted-foreground">-</span>}</span>
</TableCell>
<TableCell>
<span className="text-sm">{user.institution || <span className="text-muted-foreground">-</span>}</span>
</TableCell>
<TableCell>
<div className="flex items-center gap-2">
<Badge variant={statusColors[user.status] || 'secondary'}>