high priority low complexity frontend pending frontend specialist Tier 1

Acceptance Criteria

Widget renders an 'Active' badge (design token success colour) when mentor is active, and a 'Paused' badge (design token warning colour) when paused
Action button label reads 'Pause' when mentor is active and 'Reactivate' when paused — label updates without widget rebuild from parent
Tapping the button while active opens PauseConfirmationDialog (not dispatching immediately)
Tapping the button while paused dispatches ReactivateMentorEvent directly without a confirmation dialog
Touch target for the action button is at minimum 44×44 dp (verified with Flutter DevTools hit-test overlay)
All colours (badge background, badge text, button background, button text) use design token variables — no hardcoded hex values
Widget is self-contained and accepts a MentorStatus enum parameter; BLoC wiring is added in task-009
Widget is exported from the component barrel file and can be rendered in isolation via flutter_test

Technical Requirements

frameworks
Flutter
BLoC
flutter_test
data models
MentorStatus (enum: active, paused)
PauseDetails
performance requirements
Widget rebuild must be limited to PauseReactivateToggle subtree only — no full-page repaint on state change
security requirements
Reactivation action must only be dispatched when current state is confirmed paused — guard against double-tap race condition
ui components
PauseReactivateToggle (new widget)
StatusBadge (design system badge)
AppButton (design system button)
PauseConfirmationDialog
InkWell / GestureDetector with MaterialTapTargetSize.padded

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Keep PauseReactivateToggle as a pure presentational widget in this task — pass MentorStatus as a constructor parameter and callbacks for onPauseConfirmed/onReactivate. BLoC wiring belongs in task-009. Use a ternary on MentorStatus to switch badge colour token and button label; avoid duplicating layout logic. For the 44 dp touch target, wrap AppButton with a SizedBox(width: 44, height: 44) minimum and set minimumSize in ButtonStyle if AppButton accepts styleOverride.

Design tokens should be accessed via Theme.of(context).extension() or equivalent token accessor — do not import token constants directly into this widget file. PauseConfirmationDialog should be opened via Navigator.of(context).push() with a modal route so it is accessible from the widget test.

Testing Requirements

Widget tests: render with MentorStatus.active — assert badge text 'Active', button label 'Pause'. Widget tests: render with MentorStatus.paused — assert badge text 'Paused', button label 'Reactivate'. Widget tests: tap pause button, assert PauseConfirmationDialog is pushed. Widget tests: tap reactivate button, assert ReactivateMentorEvent is dispatched (mock BLoC).

Widget tests: verify touch target >= 44dp using tester.getSize(). Golden tests: snapshot both active and paused states for visual regression.

Component
Pause / Reactivate Toggle
ui low
Epic Risks (3)
medium impact medium prob technical

PauseConfirmationDialog must meet WCAG 2.2 AA focus trap requirements: when the dialog opens, focus must move to the first interactive element; when it closes, focus must return to the triggering toggle. Flutter's default showDialog does not always guarantee correct focus restoration on Android, which could trap screen-reader users.

Mitigation & Contingency

Mitigation: Use a custom modal implementation wrapping Flutter's Dialog with explicit FocusScope management and test with TalkBack on Android and VoiceOver on iOS during development, not just in final QA. Reference the accessible-modal-sheet pattern already used elsewhere in the codebase.

Contingency: If full WCAG focus management cannot be achieved within the sprint, ship the feature with a documented accessibility defect and schedule a dedicated accessibility remediation task. Communicate the known gap to the accessibility stakeholder at HLF/NHF.

low impact medium prob technical

If the user taps the PauseReactivateToggle rapidly before the BLoC emits a loading state, multiple PauseMentorEvents could be added to the BLoC stream, resulting in duplicate service calls and inconsistent UI state (toggle flickering between states).

Mitigation & Contingency

Mitigation: Disable the toggle widget immediately on first tap by emitting MentorStatusLoading synchronously before the async service call begins. Use BLoC's event transformer with droppable() to discard subsequent events while a transition is in progress.

Contingency: If BLoC event deduplication is not sufficient, add a debounce at the widget level (300 ms) and a server-side idempotency check in MentorStatusService that no-ops if the requested transition is already in progress.

low impact low prob security

PauseStatusBanner must conditionally render the reactivate shortcut only for users with coordinator permission. If the permission check relies on a stale role state in the Riverpod provider, a peer mentor could briefly see a reactivate action they are not authorised to use, which could cause a confusing permission-denied error if tapped.

Mitigation & Contingency

Mitigation: Source the permission check directly from the role-resolution Riverpod provider (which is kept in sync with Supabase auth) rather than from local component state. Add a widget test asserting the shortcut is absent when the user role is peer_mentor.

Contingency: If the shortcut is accidentally shown to an unauthorised user, the underlying MentorStatusService enforces role validation server-side, so the worst outcome is a visible error message rather than an actual unauthorised state change.