Build ExpectedReturnDatePicker widget
epic-peer-mentor-pause-management-core-workflows-task-004 — Implement a date picker widget scoped to future dates for optional return date selection during pause activation. Use Flutter's CupertinoDatePicker or Material DatePickerDialog with minimum date = tomorrow. Widget must emit nullable DateTime (nil = indefinite pause) and be accessible with full VoiceOver/TalkBack semantics. Integrate with design token system for consistent styling.
Acceptance Criteria
Technical Requirements
Implementation Notes
Decouple the platform-specific picker invocation into a private _showPicker(BuildContext) method that calls showDatePicker (Material) or shows a CupertinoDatePicker in a showModalBottomSheet (iOS). Use Platform.isIOS or Theme.of(context).platform to choose the path. Since the widget is stateless, the parent (the pause activation form BLoC/Cubit or form widget) holds the selected date in its state. The widget's onChanged is the only communication channel — do not use a TextEditingController or FormField here.
Format dates using intl package's DateFormat.yMMMMd() for locale-aware display. The 'indefinite pause' path is the default and must be the most prominent option — the date picker is optional, matching the product spec that 60–70% of pauses will be indefinite.
Testing Requirements
Write widget tests using flutter_test. Test: (1) Widget renders 'No return date' label when value is null. (2) Widget renders formatted date when value is set. (3) Clear button is hidden when value is null, visible when value is set.
(4) Clear button tap emits null via onChanged. (5) Semantics labels are correct for both null and set states. (6) Validation rejects a today's date if somehow passed programmatically. Use Platform.isIOS check in tests or abstract the picker selection for testability.
Golden tests for null state and set state. Do not test the native date picker UI itself — test the host widget's behaviour before and after dialog interaction.
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.