Build PauseStatusIndicator widget
epic-peer-mentor-pause-management-core-workflows-task-003 — Create a reusable widget that visually displays a peer mentor's current pause status. Support three states: active (green indicator), paused (amber with optional return date label), and expired_cert (red with expiry context). Widget must be screen-reader accessible with proper Semantics labels and support both compact (list) and expanded (detail) display modes.
Acceptance Criteria
Technical Requirements
Implementation Notes
Keep this widget purely presentational — it must not read from any BLoC, Riverpod provider, or Supabase directly. Pass all data as constructor parameters. Use a switch expression on PauseStatus to resolve colors and labels cleanly. For the Semantics label, build a descriptive string in the widget's build method: 'Status: ${_statusLabel(status)}${_returnDateLabel(expectedReturnDate)}'.
Store status label strings in a constants file or use the organisation labels system if localised terminology is needed per organisation. The compact/expanded distinction should be controlled by a DisplayMode enum, not a bool, to allow future addition of a third mode (e.g. 'badge'). Reference the existing AppButton and AppTextField for design token usage patterns.
Testing Requirements
Write widget tests using flutter_test. Test: (1) Compact active renders green dot and 'Active' label. (2) Compact paused renders amber dot and 'Paused' label. (3) Compact expired_cert renders red dot and 'Expired Certificate' label.
(4) Expanded paused with return date shows date string. (5) Expanded paused without return date shows 'Indefinite pause'. (6) Semantics label is correct for each state (use find.bySemanticsLabel). (7) Widget renders correctly when wrapped in a dark theme.
Generate golden test images for all 6 state/mode combinations and commit them as baseline. Verify WCAG contrast ratios using a contrast-checking utility or manual inspection against design tokens.
Concurrent status transitions (e.g., coordinator and automated scheduler both attempting to update the same mentor's status simultaneously) may produce race conditions or inconsistent state in the database, leading to audit log gaps or incorrect notifications.
Mitigation & Contingency
Mitigation: Implement all status transitions as atomic Postgres RPC functions with optimistic locking (version column or updated_at check). Use database-level constraints rather than application-level guards as the final enforcement point.
Contingency: Add a compensation job that reconciles status and log table consistency on each nightly scheduler run, surfacing any discrepancies to coordinator dashboards.
The coordinator-to-mentor assignment relationship may not always be 1:1 or may be stale (coordinator reassigned after a pause was set), causing notifications to be sent to the wrong coordinator or not sent at all.
Mitigation & Contingency
Mitigation: Query the assignment relationship at notification dispatch time rather than caching it at pause creation time. Add a fallback to notify the chapter administrator if no active coordinator assignment exists.
Contingency: Log all undeliverable notification attempts with the originating mentor ID so administrators can manually follow up, and surface undelivered notification counts on the coordinator dashboard.
The CoordinatorPauseRosterScreen may load slowly for coordinators managing large rosters with many concurrent certification expiry queries, degrading usability on low-bandwidth mobile connections.
Mitigation & Contingency
Mitigation: Use a single Supabase RPC that joins mentor status, certification expiry, and assignment data in one query rather than N+1 individual calls. Implement pagination with a configurable page size and skeleton loading states.
Contingency: Add an offline cache of the last-fetched roster state using Riverpod with SharedPreferences, ensuring coordinators can at minimum view stale data when connectivity is poor.