Module-specific components built from shared App* primitives (00-shared/03 ).
Props, states, animation, a11y, tokens, Flutter mapping. Reuse over new — only
components missing from the shared library are defined here. All data fields map
exactly to parent.schema.ts, student-parent-link.schema.ts, and user.schema.ts.
Field Spec
Purpose One guardian in /parents list
Props parentId, displayName, photoUrl?, occupation?, company?, linkedChildrenCount, onTap, menu?
Rendering AppListTile 56+: AppAvatar 40 leading; title = displayName titleMedium (from joined User); subtitle = "occupation · company" bodyMedium onSurfaceVariant (omit empties); trailing = AppBadge "N children" primaryContainer + AppMenu (Open, Edit)
Data source GET /parents + GET /parents/:id/students count (client join, OQ-10); children count can be lazy-fetched on demand
a11y Semantics(button, label: "Guardian <name>, <N> linked children")
Tokens surface, e-0; avatar initials primaryContainer
Flutter ListTile in Card(elevation: 0) with MenuAnchor
Field Spec
Purpose One parent–student link with relationship metadata
Props link (link doc: relationship, isPrimaryGuardian, financialResponsibility, pickupAllowed, emergencyPriority, student-parent-link.schema.ts:18-40), student (joined or loading), onTap (→ student detail), onUnlink, onSetPrimary, isPrimaryWarning
Rendering AppCard e-1: leading AppAvatar (student), title student name + mono admissionNumber, subtitle line: RelationshipChip + PrimaryGuardianBadge; meta line bodySmall: "Pickup ✓/✗ · Financial ✓/✗ · Priority N" (icon+label, never color-only — 09 §9 ); trailing AppMenu: "Set as primary" (when not primary), "Unlink"
States student == null → inline AppSkeleton; student 404 → "Student no longer active" (bodySmall warning) with unlink still available
a11y card button + menu; badge text "Primary guardian"
Flutter Card + ListTile + Row of Icon+Text; MenuAnchor
Field Spec
Purpose Display the relationship enum value
Props relationship (one of `mother
Mapping label = i18n key parent.relationship.<value>; icon map: mother → female, father → male, guardian → verified_user, grandparent → elderly, relative → family_restroom, foster_parent → home_work
Tokens AppChips read-only: surfaceVariant fill, labelMedium
a11y chip label + tooltip; Semantics(label: "Relationship: <value>")
Flutter Chip (disabled) with Icon
Field Spec
Purpose Mark isPrimaryGuardian === true per link
Props active (bool), compact?
Rendering active → AppBadge tonal primaryContainer, icon star + "Primary"; inactive → nothing (or outline "Secondary" only in edit contexts)
a11y announced "Primary guardian" when active
Flutter Badge/custom Container with Icon + Text
Field Spec
Purpose Compact per-link flags line: pickup, financial responsibility, priority
Props pickupAllowed, financialResponsibility, emergencyPriority
Rendering Row of icon+label pairs bodySmall: directions_walk ✓/✗ "Pickup", payments "Billing" (only when true), priority_high "N" (when > 0)
a11y each pair Semantics(label); never color-only (icon + text) — 09 §9
Flutter Wrap of Icon+Text
Field Spec
Purpose Choose the User a new parent profile belongs to
Props selectedUser?, onPicked(UserSummary), enabled
Behavior read-only AppTextField + Icons.search → opens AppBottomSheet with AppSearchBar over GET /users?q= (users.service.ts:90-115); results = displayName + email; picking pops sheet with the user; clear button available
a11y field label "User account"; results list live region
Flutter InkWell field + showModalBottomSheet
Field Spec
Purpose Multi-child context switcher (parent zone, (forward-looking))
Props children[{id, name, avatarUrl?}], selectedId, onChanged(id), loading?
Rendering horizontal scrollable row of avatar chips (40 dp, initials fallback); selected = primaryContainer fill + primary border; AppSkeleton when loading
Behavior tap → ChildSwitcherCubit.switchChild(id); announce "Switched to "; persist last child in memory (per session)
a11y chips Semantics(button, toggled: selected)
Flutter SingleChildScrollView + custom FilterChip-style widgets
Field Spec
Purpose Guardian list inside student detail (reverse direction)
Props links, parents (joined), onOpenParent(id), onAdd
Rendering AppCard section: per link — RelationshipChip + name + PrimaryGuardianBadge; TextButton "Add guardian" → link sheet; empty → "No guardians linked"
Source GET /parents/link/student/:studentId (parent.controller.ts:53-57) + parent join
Flutter Card + ListTile rows
Component Flutter widgets
ParentListTile ListTile + CircleAvatar + Badge + MenuAnchor
LinkedChildCard Card + ListTile + Chip + MenuAnchor
RelationshipChip Chip (disabled)
PrimaryGuardianBadge custom Container + Icon
EmergencyFlagsRow Wrap of Icon + Text
UserPickerField InkWell + TextField(readOnly) + bottom sheet
ChildSwitcherBar ListView horizontal of chips
GuardianSummaryCard Card + ListTile
Every module component: golden at phone/tablet/desktop + dark mode; state permutations
for LinkedChildCard (primary/not, pickup on/off, student-missing) and
ChildSwitcherBar (1 child, 4 children, loading).