high priority medium complexity frontend pending frontend specialist Tier 5

Acceptance Criteria

Each user row in the list has a toggle (switch or icon button) representing the account's active/inactive status
Tapping the toggle to deactivate an active account triggers a confirmation dialog before proceeding
Confirmation dialog clearly states the user's name and the consequence of deactivation (e.g. 'user will no longer be able to log in')
Tapping to activate an inactive account does NOT require a confirmation dialog — activation is lower risk
After confirmation (or direct activation), an optimistic UI update flips the status chip and toggle immediately
ActivationToggled event is dispatched to UserManagementBloc with userId and new desired status
If the server call succeeds, the optimistic state is confirmed and a brief success indicator is shown
If the server call fails, the toggle and status chip revert to the previous value and an error snackbar appears with the failure reason
Toggle is disabled (non-interactive, visually dimmed) while an operation for that specific user is in progress
An admin cannot toggle their own account status from this screen — own-user row toggle is hidden or disabled with tooltip explanation
Toggle is accessible: has semantic label describing current state ('Activate user', 'Deactivate user') and announces state change to screen reader
Status chip updates in sync with the toggle — the two UI elements never show contradictory states

Technical Requirements

frameworks
Flutter
flutter_bloc
Design token system
apis
UserManagementBloc (ActivationToggled event, operationStatus state)
UserManagementService (account status update endpoint)
data models
UserSummary
AccountStatus enum (active, inactive, pending)
UserManagementOperationStatus
performance requirements
Optimistic update must apply within one frame — no async delay before visual state change
Confirmation dialog must not block the rest of the list (rendered as a modal overlay, not a navigation push)
security requirements
Account status change must be authorised server-side via RLS — client cannot deactivate users outside their org
Self-deactivation must be blocked both client-side (disabled toggle) and server-side (service layer guard)
Deactivation of another admin must be restricted — service layer must enforce role hierarchy constraints
ui components
ActivationToggleWidget
DeactivationConfirmationDialog
StatusChip (updated state)
OperationFeedbackSnackbar

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

Implement ActivationToggleWidget as a StatelessWidget that accepts the current AccountStatus and an onToggle callback — keep it decoupled from the BLoC so it is independently testable. The BLoC integration lives in the parent UserRowWidget which dispatches ActivationToggled on the callback. For the confirmation dialog, use `showDialog` with a simple AlertDialog — do not navigate to a new route, as that would disrupt the list scroll position. The own-user guard: compare the row's userId against the authenticated admin's userId from the auth state (available via Supabase auth or a separate BLoC); if they match, render the toggle as disabled with a Tooltip.

For the optimistic update and revert pattern, ensure the BLoC's operationStatus carries the previous status so revert is deterministic — do not rely on re-fetching from the server to revert, as that introduces latency and a potential second error. Use design token colours for the toggle states: active = `AppColors.success` / `AppColors.primary`, inactive = `AppColors.surfaceVariant`.

Testing Requirements

Widget tests: render active user row and tap toggle — assert confirmation dialog appears; dismiss dialog — assert no event dispatched and toggle reverts; confirm dialog — assert ActivationToggled event dispatched; render inactive user row and tap toggle — assert NO confirmation dialog; assert toggle disabled when operationStatus is InProgress for that userId; assert own-user toggle is disabled. BLoC integration: toggle active user → optimistic inactive → server error → reverts to active with error snackbar. Accessibility: assert semantic label changes from 'Deactivate user' to 'Activate user' after toggle. Golden test for toggle in active, inactive, and in-progress states.

Component
User Account Management Screen
ui high
Epic Risks (3)
medium impact medium prob technical

Displaying NHF users with membership in up to 5 local chapters in a flat list view without duplicating entries requires a non-trivial aggregation query. Incorrect query design could result in duplicated user rows or missing chapter affiliations, confusing admins and causing incorrect role assignments.

Mitigation & Contingency

Mitigation: Design the user list query to GROUP BY user_id and aggregate chapter affiliations as an array field. Use AdminRepository's typed models to surface this aggregated structure to the UI. Validate with a test dataset containing users in 5 chapters.

Contingency: If aggregation query complexity proves too high for real-time filtering, implement a separate multi-chapter affiliation fetch triggered only when a specific user row is expanded, reducing query complexity for the base list.

medium impact medium prob technical

Composable multi-dimensional filters (role + chapter + status + certification state) applied server-side against an org with 2,000+ users may produce slow queries, particularly when filtering by certification state requires joining an additional table.

Mitigation & Contingency

Mitigation: Ensure the relevant filter columns (role, status, chapter_id, certification_expiry) are indexed in Supabase. Use cursor-based pagination rather than OFFSET to maintain consistent performance at high page numbers. Profile filter query combinations against a large dataset during development.

Contingency: If multi-filter performance degrades in production, introduce a denormalised search index table updated on user status changes, allowing the list query to filter from a single table.

medium impact medium prob integration

Deactivating a user account that has ongoing activity assignments, open expense claims, or active chapter affiliations may leave orphaned records or break downstream workflows if the deactivation does not trigger correct cascade handling.

Mitigation & Contingency

Mitigation: Define and document the expected state of each dependent record type on user deactivation before implementing the toggle. Implement deactivation as a UserManagementService operation that checks for and warns about open dependencies before persisting. Write integration tests covering each dependency type.

Contingency: If orphaned record issues are discovered post-launch, provide an admin-accessible reconciliation view that surfaces users with inconsistent dependency states and allows manual resolution without requiring a code deploy.