Implement ReportHistoryScreen scaffold and pagination
epic-bufdir-report-history-ui-task-004 — Build the ReportHistoryScreen Flutter widget as the main entry point for the report history feature. Implement a paginated, scrollable list using ListView.builder or equivalent. Integrate the filter controls from task-003 at the top of the screen. Wire the list to the BLoC or Riverpod provider that delegates to ReportHistoryService. Handle loading, empty, and error states with appropriate accessible feedback widgets using design token classes.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Use a `NotificationListener
The route guard checking role access should be in the GoRouter or Navigator 2.0 redirect logic, not inside the screen widget itself — keep the screen focused on presentation.
Testing Requirements
Widget tests: pump screen with a mock state providing a list of 3 records and assert 3 ReportHistoryListItem widgets are present. Pump with loading state and assert shimmer/spinner is shown and list is absent. Pump with empty state and assert empty state widget and 'Clear filters' button are present. Pump with error state and assert error message and retry button are present; tap retry and assert state layer fetch is called.
Integration test: use a fake service returning 2 pages of 5 records each; scroll to bottom and assert second page is loaded and list shows 10 items total.
The ReportSummaryMetricsWidget must display metrics as they were at time of submission, not recalculated from current data. If the metrics are not stored as a JSON snapshot in the history record at export time, the widget will either show wrong data or require a full re-aggregation on every list load.
Mitigation & Contingency
Mitigation: Ensure the Bufdir export pipeline (bufdir-report-export feature) writes a summary_metrics JSONB column in the history record at export time, containing total_activities, total_hours, and participants_reached. The UI widget reads only from this snapshot field — never from live aggregation queries.
Contingency: If snapshot data is missing for historical records (e.g., older exports before the column existed), display a 'Metrics not available for this report' placeholder in the widget rather than showing zeros or triggering a live aggregation that could return different figures.
Re-export can take several seconds (it runs the full generation pipeline). Without adequate progress feedback, coordinators may tap the button multiple times, triggering duplicate exports and duplicate history records.
Mitigation & Contingency
Mitigation: Disable the re-export button immediately on first tap and show an inline progress indicator on the list item. Guard against duplicate invocations at the service layer using an in-progress flag keyed by report ID. Display a loading state on the list item throughout the operation.
Contingency: If duplicate re-export records are created (e.g., due to a race condition), the history table will show multiple entries for the same original report — which is harmless but confusing. Add a deduplication UI hint ('Re-exported N times') and a backend guard that prevents more than one in-flight re-export for the same source record ID simultaneously.