Add person detail page and link people tiles to it

GET /api/people/:id returns a published person's profile, public
roles (current and past), published events they were billed at or
hosted, and public awards, each under the same visibility rules its
own page applies. public_phone is never sent.

PersonDetail renders it at /people/:id, the route personHref already
pointed at. PeopleTiles links a tile with a people id to that page;
an expandable tile keeps its details panel and the panel carries a
"View full profile" link instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Zaldimmar 2026-09-25 05:05:45 -05:00
parent 300c9b74f0
commit 6ec2fb240a
6 changed files with 643 additions and 6 deletions

View file

@ -276,3 +276,63 @@ export type AwardRecord = {
export const useAward = (id?: string): Resource<AwardRecord> =>
useRecord<AwardRecord>(detailPath('/awards', id), 'award')
/* ── People ──────────────────────────────────────────────────── */
/** One public affiliation. ended_on null means current. */
export type PersonRole = {
title?: string | null
role: 'lead' | 'board' | 'staff' | 'volunteer' | 'member'
is_owner: boolean
started_on?: string | null
ended_on?: string | null
org: OrgRef
/** Null when there's no team, or the team is unpublished. */
team: { id: string; name: string } | null
}
/** A published event this person was billed at or hosted, with
* every capacity they appeared in. 'host' comes from event_hosts. */
export type PersonEvent = {
id: string
title: string
event_type: EventType
date_label?: string | null
starts_on?: string | null
status: 'upcoming' | 'past' | 'cancelled'
roles: { role: string; title?: string | null }[]
}
export type PersonAward = {
award: { id: string; name: string; logo?: string | null }
awarded_on?: string | null
citation?: string | null
event: { id: string; title: string } | null
}
export type PersonRecord = {
id: string
name: string
pronouns?: string | null
tagline?: string | null
photo?: string | null
location_label?: string | null
public_email?: string | null
/** The primary organization, when it's published. */
org: OrgRef | null
/** people.bio split on blank lines. */
bio: string[]
description: string[]
blocks: ContentBlock[]
links: Link[]
socials: Link[]
website?: string | null
instagram?: string | null
/** Current first, then most recently ended. */
roles: PersonRole[]
events: PersonEvent[]
awards: PersonAward[]
}
export const usePerson = (id?: string): Resource<PersonRecord> =>
useRecord<PersonRecord>(detailPath('/people', id), 'person')