[M04] Member Person Detail
Summary
A rework of the existing person detail screen (/person/:id/view) so it presents a concise identity summary and, below it, the person’s membership history. Today the screen is a flat demographic dump (name, identity, contact, emergency, parent, doctor, medical, address) and never shows memberships. This use case narrows the identity block to the essentials and adds the membership history that operators actually come here for — it is the landing target of M03.
Actor & Context
Actor: membership administrator / desk operator (authenticated staff user).
Frequency: routine — every time a member is opened from the lookup screen or a link.
Precondition: user is authenticated with access to the person (org + person security dimensions apply). Person id is in the route.
Entry point: /person/:id/view — reached by clicking a result on M03, or any existing link to a person record.
Main Flow
-
Operator arrives at
/person/:id/view. Thepersonis resolved by the existing route resolver. -
The screen renders an identity summary: a responsive two-column grid showing only first name, last name, ID number + identity type, DOB, gender.
-
The screen loads the person’s memberships via
GET /api/membershipsfiltered bypersonIdand sorted byvalidTodescending (newest first). -
Below the identity summary, a membership history list renders each membership newest→oldest with: Membership Type, Period, Criteria, and Status (as a coloured tag).
-
Operator reads the record; existing Back / Edit actions are retained.
Alternative Flows
-
AF-1 — No memberships. Person has no membership records. Show an empty state under the history heading ("No memberships on record.") — the identity summary still renders.
-
AF-2 — Memberships still loading. Show a spinner / skeleton in the history section while the identity summary is already visible (the two loads are independent).
-
AF-3 — Membership load error. Show a dismissible error in the history section without blocking the identity summary.
Acceptance Criteria
-
The identity summary is a responsive two-column grid showing ONLY: first name, last name, ID number + identity type, DOB, gender. The former medical / emergency / parent / doctor / address blocks are removed from this screen.
-
Membership history lists every membership for the person, newest→oldest (by
validTodesc). -
Each membership row shows Membership Type, Period, Criteria, and Status; status renders as a coloured tag (reusing the membership-list status→severity mapping).
-
The history uses
GET /api/memberships?personId.equals=<id>&sort=validTo,desc— no new backend endpoint is introduced. -
Empty / loading / error states are handled per AF-1 / AF-2 / AF-3.
-
The screen remains responsive (desktop table / mobile cards) and retains Back / Edit actions.
API Surface
| Call | Purpose |
|---|---|
|
(existing, via resolver) fetch the person for the identity summary. |
|
(existing) list the person’s memberships newest-first; already org+person secured via |
No new backend work: MembershipCriteria already exposes a personId filter and the standard membership list endpoint applies security. MembershipService.queryPerson() (GET /api/memberships/person) is a dead frontend method with no backend mapping and MUST NOT be used.
Out of Scope
-
Editing memberships or person details from this screen (Edit still routes to the existing update screens).
-
Restoring the removed demographic blocks — they remain available on the edit screen; this view is deliberately narrowed.
-
Any change to membership data shape or the membership list endpoint.
Design Anchors
-
M03 Member Person Lookup (the entry point)
Notes
-
Reuse targets:
IMembershipmodel (already carries the four display fields); theMembershipStatus→p-tagseverity mapping and the responsive table/card markup from the membership list; the existing person resolver and Back/Edit chrome inperson-detail.component. -
Implementation injects
MembershipServiceintoPersonDetailComponent(currently only takesActivatedRoute) and loads memberships inngOnInit. Pick a sane page-size cap for history.