high priority low complexity frontend pending frontend specialist Tier 0

Acceptance Criteria

Widget renders three preset buttons: Q1–Q4 quarter shortcuts, H1/H2 half-year shortcuts, and full-year shortcut — each visually distinct and labeled in plain Norwegian/English
Tapping a preset button updates internal selection state and immediately invokes the onPeriodSelected(DateTimeRange period) callback with the correct start and end dates computed relative to the current calendar year
All tap targets are at minimum 48Ă—48 dp to satisfy WCAG 2.2 AA Success Criterion 2.5.8 (Target Size Minimum)
Selected preset button renders with a visually distinct active state using design token colors (no inline styles)
Widget is stateless externally — accepts an optional initialPeriod parameter and selectedPeriod for controlled usage
All preset labels have Semantics wrappers with descriptive labels readable by VoiceOver and TalkBack (e.g., 'Select Q1 2025, January 1 to March 31')
Widget renders correctly on both iOS and Android at font scale 1.0Ă—, 1.5Ă—, and 2.0Ă— without overflow or clipped text
Unit tests confirm correct DateTimeRange values for every preset button across year boundaries (e.g., Q4 spanning October–December)
No hardcoded colors or spacing — all values sourced from the app's design token system

Technical Requirements

frameworks
Flutter
BLoC
Riverpod
data models
DateTimeRange
BufdirReportingPeriod
performance requirements
Widget rebuild cost must be negligible — use const constructors wherever possible
No async operations in build(); all date arithmetic is synchronous
security requirements
No PII stored or transmitted by this widget
Date values must be validated before passed upstream to prevent negative-range exports
ui components
BufdirPeriodSelectorWidget (stateful)
PresetPeriodButton (reusable chip-style button with active/inactive states)
Semantics wrapper for each button

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Model each preset as a BufdirPresetPeriod enum (q1, q2, q3, q4, h1, h2, fullYear) with a toPeriodRange(int year) extension method that returns DateTimeRange. This isolates date logic from UI and makes unit testing trivial. Use design token spacing (AppSpacing.sm, AppSpacing.md) for padding so the widget adapts to accessibility text-scale changes. Wrap each ElevatedButton or OutlinedButton in a Semantics node — set label to a human-readable string including computed dates so screen-reader users hear the actual date range, not just 'Q1'.

Avoid Row with Expanded children that overflow at large text scale; prefer Wrap with runSpacing from design tokens. Export the widget from a barrel file so downstream screens import a single path.

Testing Requirements

Write flutter_test widget tests covering: (1) correct DateTimeRange emitted for each of the 7 presets (Q1–Q4, H1, H2, full year), (2) callback not invoked on render — only on tap, (3) active-state visual indicator changes on selection, (4) widget accepts controlled selectedPeriod prop and highlights correct button, (5) no overflow at text scale 2.0×. All tests must pass on both Material (Android) and Cupertino (iOS) themes. Target 100% branch coverage for date arithmetic helpers.

Epic Risks (2)
medium impact medium prob technical

For large exports that run for 10–30 seconds, a static loading spinner will feel broken to users on slow mobile connections. If the UI cannot display meaningful progress during the export pipeline, coordinators may abandon the flow or trigger duplicate exports by pressing the button multiple times.

Mitigation & Contingency

Mitigation: Implement streaming progress events from the orchestrator BLoC through named pipeline stages (querying, mapping, generating, uploading). Display each stage label with a progress indicator on the trigger screen. Disable the generate button immediately on first tap to prevent duplicates.

Contingency: If streaming pipeline progress is not feasible in the first release, implement a deterministic stage-based progress animation (10% querying, 50% generating, 90% uploading) that gives users feedback without requiring real server events.

high impact medium prob technical

Custom date range pickers are among the most common accessibility failures in mobile apps. Blindeforbundet users rely on VoiceOver, and NHF users include people with cognitive impairments. A non-accessible period picker could make the entire export workflow unusable for a significant portion of the intended user base.

Mitigation & Contingency

Mitigation: Build the period picker using Flutter's native date picker semantics as the foundation, with preset shortcuts as primary navigation (reducing the need to interact with the custom range picker at all). Test with VoiceOver on iOS and TalkBack on Android before UI epic sign-off. Engage Blindeforbundet's test contact for accessibility validation.

Contingency: If the custom date range picker cannot be made fully accessible before release, ship only the preset period shortcuts (covering the majority of use cases) and add the custom range picker in a follow-up sprint after dedicated accessibility remediation.