Wire Export Edge Function client into screen BLoC
epic-accounting-system-export-ui-task-005 — Integrate the Export Edge Function Dart client (wrapping Supabase Functions invoke) into the AccountingExportScreenBloc. The client must accept DateTimeRange and orgId, return an ExportResult containing fileUrl and exportRunId, and propagate typed errors (NetworkError, AuthError, DuplicateError). Implement retry logic for transient network failures with exponential back-off up to 3 attempts. Expose progress stream so the UI can show an indeterminate loading indicator during the edge function call.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 3 - 413 tasks
Can start after Tier 2 completes
Implementation Notes
Use the supabase_flutter SDK's client.functions.invoke() method — it automatically injects the current session's JWT as the Authorization header. Define the retry logic in a standalone retryWithBackoff
Parse the Edge Function response body as JSON using dart:convert — validate that required fields (exportRunId, fileUrl) are present before constructing ExportResult. The exponential back-off must use Future.delayed() — verify with fake_async in tests to avoid slow tests.
Testing Requirements
Unit tests: mock supabase.functions.invoke using mockito/mocktail. Test success path returns ExportResult. Test 401 response maps to AuthError. Test 409 response maps to DuplicateError with correct existingRunId extracted from response JSON.
Test NetworkError triggers retry exactly 3 times with correct back-off delays (use fake_async to control time). Test AuthError does NOT trigger retry. Test ParseError on malformed response JSON. Integration test (staging environment only): invoke the actual Edge Function with a test org and verify exportRunId is returned.
BLoC integration test: verify BLoC emits Exporting state when progress stream emits, and ExportSuccess on client success. Target 90%+ unit test coverage on client logic.
Export operations may take several seconds, and the UI must handle all intermediate states (loading, partial success, failure, duplicate warning) without leaving the coordinator on a blank or unresponsive screen. Missing state handling causes confusion and potentially double-submissions.
Mitigation & Contingency
Mitigation: Design the BLoC state machine with explicit states for each transition before writing any widget code: ExportIdle, ExportDuplicateWarning, ExportInProgress, ExportSuccess, ExportPartialSuccess, ExportFailed. Each state maps to a distinct UI. Widget tests cover all states.
Contingency: If a loading state is missed in production, surface a generic error state with a retry action rather than leaving the UI stuck. Add a timeout on the Edge Function call (default 30 seconds) that transitions to ExportFailed with a user-readable message.
The custom Export Date Range Picker may not be fully navigable with VoiceOver if the underlying Flutter date widgets do not expose the correct semantic tree. This is a critical accessibility failure for Blindeforbundet users who rely on screen readers.
Mitigation & Contingency
Mitigation: Use Flutter's built-in DateRangePicker as the base and wrap with explicit Semantics nodes for start and end labels. Test with VoiceOver on a physical iOS device as part of the definition of done for this component. Reference the existing AccessibilityTestHarness pattern used elsewhere in the app.
Contingency: If the custom picker fails accessibility audit, replace it with two independent DatePicker fields (start and end) using Flutter's standard accessible date input, which has broader VoiceOver support than range variants.