Build ExportScopeSelector widget with reactive state
epic-bufdir-report-export-orchestration-task-003 — Implement the ExportScopeSelector Flutter widget that consumes the Riverpod provider from task-001 and the permitted-scopes list from task-002. Render scope options as selectable cards (local chapter, region, national) with disabled styling for options the user cannot access. Ensure WCAG 2.2 AA contrast and correct semantics labels for screen readers.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Follow the existing card widget patterns in the project (AppButton, contact cards) for structural consistency. Use the design token system for all colours — no hardcoded hex values. Norwegian display names for scope cards: 'Lokalt lokallag' (localChapter), 'Region' (region), 'Nasjonalt' (national). For accessibility, pay particular attention to the Blindeforbundet requirement: screen reader support is critical for this app.
Test with VoiceOver on a physical iOS device or simulator during development, not just automated checks. The widget should be placed at lib/features/bufdir_export/widgets/export_scope_selector.dart. Consider extracting ExportScopeCard as a separate file for testability.
Testing Requirements
Write widget tests using flutter_test WidgetTester. Tests must cover: (1) all three scope cards render with correct titles, (2) disabled card does not fire selectScope when tapped, (3) tapping an enabled card updates the Riverpod provider state, (4) isLoading=true shows skeleton, not cards, (5) empty permittedScopes shows the no-access message, (6) selected card has correct visual state (use findsOneWidget with semantic label check). Use ProviderScope with override in tests to inject pre-set ExportScopeState values. Run flutter_test with accessibility checks using AccessibilityGuidelines if available in the project.
Aim for ≥80% widget code coverage.
The scope selector must accurately reflect each coordinator's access rights within the org hierarchy. If a coordinator can select a scope broader than their authorised access, the edge function's RLS enforcement must catch the attempt — but a permissive RLS policy or a bug in the scope resolver could allow unauthorised data to be exported.
Mitigation & Contingency
Mitigation: Implement permission enforcement at two independent layers: (1) the scope selector only renders options permitted by the user's role record, and (2) the edge function re-validates the requested scope against the user's JWT claims before executing any queries. Write integration tests that attempt to invoke the edge function with a scope beyond the user's permissions and assert rejection.
Contingency: If a permission bypass is discovered post-launch, immediately disable the export feature via the org-level feature flag while the fix is deployed. Review all audit records for exports that may have included out-of-scope data and notify affected organisations.
The export workflow has 7+ discrete states (idle, scope selected, period selected, preview loading, preview ready, confirming, exporting, complete, failed) and several conditional transitions. An incomplete BLoC state machine could allow duplicate submissions, stale preview data to be confirmed, or error states to be unrecoverable without a restart.
Mitigation & Contingency
Mitigation: Model the state machine explicitly as a sealed class hierarchy before coding. Review the state diagram against all user story acceptance criteria. Write bloc unit tests for every valid and invalid state transition, including the happy path and all documented error states.
Contingency: If the BLoC grows too complex to test reliably, decompose it into two cooperating blocs: one for configuration (scope + period selection) and one for execution (preview + confirm + export), linked by a coordinator object.