Add loading indicators and empty state UI to ContactListScreen
epic-contact-list-management-ui-components-task-009 — Implement loading and empty state handling in ContactListScreen. Display a centered CircularProgressIndicator when the contact list is in a loading state. Render a contextual empty-state widget (illustration + message) when the list is empty due to no contacts existing, or when the search query returns zero results. Empty state messaging must be role-aware and use org-label terminology. Handle network error states with a retry action button.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 3 - 413 tasks
Can start after Tier 2 completes
Implementation Notes
Use a BLoC/Riverpod state sealed class or enum with distinct variants for Loading, Loaded, EmptyNoContacts, EmptySearchResults, and Error. Avoid overloading a single 'empty' state — the empty-due-to-search vs empty-due-to-no-data distinction requires separate UI copy. Build EmptyStateWidget and NetworkErrorWidget as generic, reusable widgets in the shared widgets library so they can be used across other screens. Resolve org-label strings via the existing OrgLabels system rather than hardcoding — pass the resolved string into EmptyStateWidget.
Keep illustration assets lightweight SVGs or simple Lottie animations; avoid large PNGs. The retry callback should re-dispatch the same event that triggered the initial load, keeping the BLoC as the single source of truth.
Testing Requirements
Unit-test each BLoC/Riverpod state mapping in isolation. Widget-test ContactListScreen with mock states: (1) ContactListLoading → verify CircularProgressIndicator present, (2) ContactListEmpty (no-contacts) → verify correct illustration and role-aware org-label message, (3) ContactListEmpty (search-no-results) → verify search-specific message, (4) ContactListError → verify error widget and retry button present, (5) tap retry → verify reload event dispatched. Test org-label substitution by providing alternate label fixtures. Run all tests with flutter_test; no golden tests required for this task.
Design token color values used in role badges, certification status indicators, and availability chips may not meet the WCAG 2.2 AA contrast ratio of 4.5:1 when rendered against card backgrounds, requiring rework after accessibility review and potentially blocking acceptance sign-off.
Mitigation & Contingency
Mitigation: Run the contrast-ratio-validator on every new token combination during widget development. Enforce the CI accessibility lint runner on all PRs touching visualization components, and validate against the contrast-safe-color-palette before finalizing card designs.
Contingency: If contrast failures are found late, adjust token values in the design token theme centrally — since all widgets consume design tokens rather than hardcoded colors, all affected widgets will be corrected by a single token update without per-widget changes.
The ContactViewSwitcher is required for Barnekreftforeningen but must not appear for other organizations. If the organization labels provider does not yet expose a reliable feature flag for this widget, it may render universally or be conditionally hidden in an inconsistent way, breaking the role-specific layout contract.
Mitigation & Contingency
Mitigation: Implement view switcher visibility as a constructor parameter on ContactListScreen injected from a provider, defaulting to hidden. Document the integration point for the org labels provider so the flag can be wired without changing the widget's API.
Contingency: If org labels integration is delayed beyond this epic, use a feature flag constant keyed to the Barnekreftforeningen organization ID as a temporary gate, with a tracked issue to replace it with the runtime labels provider before general release.