Implement ReportHistoryListItem widget
epic-bufdir-report-history-ui-task-002 — Build the ReportHistoryListItem Flutter widget that renders a single past Bufdir report entry. It must display period range, generation timestamp, generating user name, and action buttons for re-download and re-export. Embed ReportSummaryMetricsWidget to show snapshot metrics inline. Apply design token system for all visual properties and ensure all interactive controls meet WCAG 2.2 AA touch target and label requirements.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Implementation Notes
Accept the full ReportHistoryRecord via constructor along with named `onRedownload` and `onReexport` VoidCallback parameters. Wrap action buttons in a Row aligned to the trailing edge. Use `intl` package for date formatting with the 'nb_NO' locale β import the locale data in main.dart if not already done. For the re-export loading state, accept an `isReexporting` bool parameter rather than managing state internally, so the parent BLoC/Riverpod layer controls the loading indicator.
Apply `Semantics(label: '...', button: true)` to each action button with the period range baked into the label for screen reader context. Ensure the entire list item is not itself tappable β only the discrete action buttons are interactive.
Testing Requirements
Widget tests: render with a complete ReportHistoryRecord and assert period range text, timestamp, user name, and both action buttons are visible. Tap re-download button and assert `onRedownload` callback is called once. Tap re-export button and assert `onReexport` callback is called once. Render with null generatedByName and assert fallback text appears.
Render with re-export loading state active and assert button is disabled and spinner is visible. Verify Semantics labels on both buttons using `tester.getSemantics()`.
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.