high priority low complexity frontend pending frontend specialist Tier 2

Acceptance Criteria

PauseStatusBanner is visible on both coordinator mentor detail screen and mentor list item when MentorStatusBLoC emits a state with isPaused == true
PauseStatusBanner is completely absent from the widget tree (not just hidden) when the BLoC state is not paused
Tapping the reactivate shortcut inside the banner dispatches exactly one ReactivateMentorEvent to the BLoC
A loading indicator replaces the reactivate button text immediately upon dispatch and persists until BLoC emits MentorStatusSuccess or MentorStatusError
On MentorStatusSuccess the banner disappears and the parent view reflects the active mentor state without requiring a full page reload
On MentorStatusError the loading indicator is replaced with the reactivate shortcut again and a SnackBar or inline error message is shown
BLoC is provided via BlocProvider.value or context.read — never instantiated directly inside PauseStatusBanner
No business logic (status checks, API calls) lives inside PauseStatusBanner; all logic is delegated to the BLoC
The banner correctly displays the pause timestamp and reason pulled from BLoC state
Integration works identically on both mentor detail screen and mentor list view without duplication of BLoC wiring code

Technical Requirements

frameworks
Flutter
BLoC
flutter_bloc
data models
MentorStatus
MentorStatusState
ReactivateMentorEvent
performance requirements
BlocBuilder rebuilds only the banner subtree, not the full page — use BlocBuilder with buildWhen to limit rebuilds
Banner widget renders in under 16ms (single frame) on mid-range Android devices
security requirements
ReactivateMentorEvent must only be dispatchable by users with coordinator or admin role; validate role in BLoC before processing
ui components
PauseStatusBanner
BlocBuilder<MentorStatusBLoC, MentorStatusState>
CircularProgressIndicator (loading state)
TextButton or InkWell (reactivate shortcut)
SnackBar or inline error widget

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Use BlocBuilder with a buildWhen condition checking only the isPaused and isLoading flags to minimise rebuilds. Wrap the BlocBuilder in a conditional — return SizedBox.shrink() when not paused so the banner is fully removed from the tree. Dispatch ReactivateMentorEvent via context.read().add(...) inside the shortcut's onTap to avoid holding a BLoC reference in state. Pull pausedAt and pauseReason from the BLoC state object, not from a separate provider, to maintain a single source of truth.

Ensure the BLoC is already provided by an ancestor — do not create a new BlocProvider inside the banner itself.

Testing Requirements

Widget tests (covered by task-012) should verify: (1) banner renders when BLoC emits paused state, (2) banner is absent for non-paused states, (3) tapping shortcut dispatches ReactivateMentorEvent, (4) loading indicator appears during in-flight state, (5) error state restores shortcut. Manual smoke test on both mentor detail and list views in a coordinator session before PR merge.

Component
Pause Status Banner
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.