high priority medium complexity frontend pending frontend specialist Tier 5

Acceptance Criteria

Bottom sheet slides up smoothly from the bottom of the screen using a standard DraggableScrollableSheet or showModalBottomSheet with animation duration between 200–300ms
All chapters available to the authenticated user are displayed in a scrollable list within the sheet
The currently active chapter is visually highlighted with a distinct active indicator (e.g., checkmark, filled circle, or accent border) using design token colors
Each chapter list item displays the chapter avatar/icon and chapter name with sufficient contrast (WCAG 2.2 AA: minimum 4.5:1 for text, 3:1 for UI components)
All interactive touch targets are at least 48x48dp per WCAG 2.2 AA guidelines
Tapping a non-active chapter dispatches a SwitchChapterEvent to the ActiveChapterState BLoC and closes the sheet
Tapping the already-active chapter closes the sheet without dispatching any event
Sheet closes on tap outside or drag-down gesture
Screen reader (VoiceOver/TalkBack) can navigate and interact with all list items; active state is announced correctly via Semantics widgets
Sheet renders correctly on both small (320dp) and large (428dp+) screen widths
No jank or frame drops during open/close animation (60fps minimum)
BLoC state changes are reflected immediately — the newly selected chapter becomes highlighted before sheet closes

Technical Requirements

frameworks
Flutter
BLoC (flutter_bloc)
data models
Chapter
ActiveChapterState
performance requirements
Bottom sheet open animation completes within 300ms
Chapter list renders without jank for up to 50 chapters
No unnecessary BLoC rebuilds — use BlocSelector or buildWhen to scope rebuilds
security requirements
Only display chapters the authenticated user has access to — never expose chapter IDs or names for unauthorized chapters
Do not cache chapter list in widget state beyond the sheet lifetime; re-read from BLoC on each open
ui components
DraggableScrollableSheet or ModalBottomSheet wrapper
ListView.builder for chapter list
ChapterListTile (avatar, name, active indicator)
Semantics wrappers on list items for accessibility
Design token colors and spacing throughout

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

Use showModalBottomSheet with isScrollControlled: true and a DraggableScrollableSheet for flexible sizing. Keep the widget stateless — all state comes from BlocBuilder. Use BlocSelector to listen only to the chapter list and active chapter ID fields to minimize rebuilds. For the active indicator, use a design token accent color with an AnimatedContainer for a subtle highlight transition.

Wrap each ListTile with Semantics(label: '${chapter.name}, ${isActive ? 'active' : ''}', button: true) for screen reader support. Avoid using GestureDetector inside InkWell to prevent touch conflict — use ListTile's onTap. For NHF with up to 1,400 local chapters, ensure the list uses ListView.builder (not ListView with full children array).

Testing Requirements

Write widget tests using flutter_test covering: (1) sheet renders with correct chapter list from mocked BLoC state, (2) active chapter has correct visual indicator, (3) tapping a chapter dispatches the correct BLoC event, (4) tapping active chapter does not dispatch event, (5) sheet closes after selection. Write golden tests for the sheet in active and default states. Manually verify screen reader announcement order and touch target sizes on a physical device or Xcode Simulator with VoiceOver enabled. Aim for 90%+ widget-level coverage on ChapterSwitcherSheet and ChapterListTile.

Component
Chapter Switcher
ui medium
Epic Risks (3)
high impact medium prob security

If the AccessScopeService and the Supabase RLS policies use different logic to determine accessible units, a coordinator could see data in the client that RLS blocks server-side, causing confusing empty states, or worse, RLS could block data the scope service declares accessible.

Mitigation & Contingency

Mitigation: Define the canonical scope computation in a single Supabase Postgres function shared by both the RLS policies and the RPC endpoint called by AccessScopeService. The client-side service calls this RPC rather than reimplementing the logic, ensuring a single source of truth.

Contingency: Add integration tests that execute the same access decision through both the RLS policy path and the AccessScopeService path and assert identical results. Use these as regression guards in the CI pipeline.

medium impact medium prob integration

When a user switches active chapter via the ChapterSwitcher, widgets that are already built may not receive the context-change event if they subscribe incorrectly to the ActiveChapterState BLoC, leading to stale data being displayed under the new chapter context.

Mitigation & Contingency

Mitigation: Use Riverpod's ref.watch on the active chapter provider at the root of each scoped data subtree rather than at individual leaf widgets. Trigger a global data refresh by invalidating all scoped providers when the chapter changes.

Contingency: Add an app-level chapter-change listener that forces a full navigation stack reset to the home screen on chapter switch, guaranteeing all widgets rebuild from scratch with the new context. Accept the UX cost of navigation reset for correctness.

medium impact medium prob scope

Non-technical organization administrators may find the hierarchy management interface too complex for the structural changes they need to make frequently (e.g., chapter renaming, coordinator reassignment), leading to low adoption and continued reliance on manual processes.

Mitigation & Contingency

Mitigation: Conduct usability testing with at least one NHF administrator before finalizing the admin portal screen layout. Prioritize the most common operations (rename, reparent, add child) as primary actions in the UI. Include inline help text and confirmation dialogs with plain-language descriptions of consequences.

Contingency: Provide a simplified 'quick edit' mode that exposes only the three most common operations (rename, deactivate, add child) and hides advanced structural operations behind an 'Advanced' toggle.