high priority low complexity frontend pending frontend specialist Tier 3

Acceptance Criteria

ExportPreviewMetadataHeader is a widget rendered above the category table inside ExportPreviewPanel
When ExportPreviewLoaded, the header displays: organisation name, unit name (if present, shown as a sub-label), period label, formatted start and end dates (dd.MM.yyyy), and total record count
Organisation and unit names are rendered as read-only chips using the project's AppChip widget or equivalent design-token-styled chip
Period start and end dates are formatted using the locale-aware DateFormat from intl package (Norwegian locale: 'dd.MM.yyyy')
Total record count is displayed as: 'X records' with X bold and 'records' in body text style
The metadata section widget has autofocus: true (or equivalent FocusNode request) so it is the first screen reader focus when the panel becomes visible
A Semantics widget wraps the entire header with a combined descriptive label, e.g. 'Export preview for <orgName>, <unitName>, period <label> (<start> to <end>), <count> records'
When state is ExportPreviewLoading or ExportPreviewInitial, the header shows a single-line skeleton placeholder
All visual values (chip border radius, padding, typography) come from design tokens

Technical Requirements

frameworks
Flutter
flutter_bloc
BLoC
data models
bufdir_column_schema
performance requirements
Header renders in a single frame — no async operations within the widget
security requirements
Organisation and unit names displayed as plain text only — no HTML rendering
ui components
ExportPreviewMetadataHeader
AppChip (read-only variant)
ExportPreviewMetadataSkeleton

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

Place ExportPreviewMetadataHeader as the first sliver (SliverToBoxAdapter) in the CustomScrollView established in task-003. For autofocus, request focus on the header's FocusNode in the widget's initState (if StatefulWidget) or via a post-frame callback in a StatefulBuilder. Avoid using AutofocusWidget if it conflicts with existing focus management in the parent modal or sheet. Date formatting: use DateFormat('dd.MM.yyyy', 'nb') from the intl package to match Norwegian locale conventions used across the app.

Chips should not be tappable — set onPressed: null and ensure InkWell is not present to avoid accessibility confusion about interactivity.

Testing Requirements

Widget tests: render with a full ScopeMetadata (org + unit) and PeriodMetadata and verify all fields are present; render with null unitId and verify unit chip is absent; verify Semantics label contains all expected substrings; verify autofocus behaviour using FocusNode in test environment. Snapshot/golden test at default font scale. Test date formatting for a period spanning year boundaries (e.g. 01.12.2024 to 31.03.2025).

Component
Export Preview Panel
ui medium
Epic Risks (2)
medium impact medium prob technical

The preview panel requires a round-trip to the edge function to compute aggregated counts. If this call takes 5–15 seconds for large scopes, users may assume the app has frozen and navigate away, potentially triggering duplicate preview requests or leaving the export in an undefined state.

Mitigation & Contingency

Mitigation: Show an immediate skeleton loading state on the preview panel as soon as the period and scope are confirmed, with named stage labels (e.g. 'Querying activities…', 'Computing totals…') streamed from the edge function's progress events. Set a clear user-visible timeout with a retry option. Pre-warm the edge function with a lightweight ping when the scope selector is opened.

Contingency: If preview latency consistently exceeds 10 seconds for large scopes, cache the preview payload in local BLoC state and allow the coordinator to proceed to confirmation without re-fetching if scope and period have not changed since the last preview.

high impact medium prob scope

The export preview panel contains dynamic content (warning badges, loading skeletons, aggregated counts) that must be announced correctly by VoiceOver and TalkBack. Incorrect semantics annotations could make the preview unreadable for blind coordinators, violating the project's WCAG 2.2 AA accessibility mandate.

Mitigation & Contingency

Mitigation: Implement semantic annotations using Flutter's Semantics widget with explicit labels for all dynamic content. Use live region announcements for loading state transitions. Schedule a dedicated accessibility review session with a screen reader user (Blindeforbundet has relevant expertise) before marking the epic complete.

Contingency: If the preview panel cannot be made fully screen-reader-accessible in time for launch, ship a simplified text-only summary mode activated by a toggle at the top of the preview panel, which renders all data as a single readable paragraph with no interactive badges.