Paginated user list UI with status indicators
epic-admin-portal-user-management-task-005 — Build the paginated user list Flutter widget showing all users within the admin's org scope. Each user row must display name, role badge, account status, chapter affiliation(s), and certification state indicator. Implement infinite scroll pagination and pull-to-refresh. Handle multi-chapter display (up to 5 chapters) without duplicating user rows.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 4 - 323 tasks
Can start after Tier 3 completes
Implementation Notes
Extract UserRowWidget as a StatelessWidget accepting a UserSummary and callback functions — this keeps it testable in isolation and prevents the entire list from rebuilding when one row changes. For infinite scroll, add a ScrollController to the ListView and listen for scroll position; dispatch LoadNextPage when `position.pixels >= position.maxScrollExtent - (3 * rowHeight)`. Use shimmer package or a custom shimmer implementation for the loading skeleton — avoid a single circular progress indicator as it is poor UX for list loading. For chapter chips, measure available width using LayoutBuilder and calculate how many chips fit before collapsing to '+N more'.
Use design token constants for all colours and typography — never reference Color(0xff...) directly in widget files. For WCAG compliance, test against the dark and light themes if both are supported. The certification state icon must include both an icon and a tooltip/semantics label so it is accessible to screen readers (critical for Blindeforbundet users).
Testing Requirements
Widget tests (flutter_test): render list with 10 mock users and assert all fields visible; render empty state when users list is empty; render skeleton when state is loading; render error card with retry button on error state; assert infinite scroll triggers LoadNextPage when scrolled to bottom; assert pull-to-refresh triggers PullToRefresh. Golden tests for UserRowWidget covering all role/status/certification combinations. Accessibility audit: run flutter_test semantics checks to confirm all interactive elements have semantic labels. Performance test: render 200 rows in a test and assert no jank (frame time < 16ms).
WCAG contrast check: assert text colours meet 4.5:1 minimum using colour contrast utility in tests.
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.
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.
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.