Build reimbursement line-item row widget
epic-expense-type-selection-user-interface-task-007 — Create a ReimbursementLineItem widget that displays a single expense type's name and calculated reimbursement amount in a two-column row. The row must handle currency formatting, support zero amounts, and be individually accessible with a descriptive Semantics label combining type name and formatted amount.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Implementation Notes
Use intl package's NumberFormat.currency(locale: 'nb_NO', symbol: 'kr') — instantiate once as a static final to avoid per-build allocation. Keep the widget a pure StatelessWidget with no BLoC dependency; data flows in from the parent panel. Apply design token TextStyle for both name and amount (e.g., AppTypography.bodyMedium and AppTypography.bodyMediumMono or equivalent). The Semantics label must be a single merged string so VoiceOver/TalkBack reads it as one unit rather than two separate elements — use Semantics(label: '$name: $formattedAmount', child: ExcludeSemantics(child: Row(...))).
Testing Requirements
Unit/widget tests using flutter_test. Cover: (1) name renders in left slot, (2) amount renders formatted NOK in right slot, (3) zero amount renders 'kr 0,00' not empty, (4) Semantics label matches '{name}: {formatted amount}' exactly, (5) long names truncate with ellipsis. No golden tests required at this granularity — golden tests are handled at the panel level in task-008.
If the expense calculation preview subscribes to the full BLoC state stream, every unrelated state property change (e.g. a loading flag toggle) triggers a widget rebuild. With complex card animations for the disabled-state transition, this could cause frame drops on low-end Android devices used by some peer mentors.
Mitigation & Contingency
Mitigation: Use select() on the Riverpod provider to subscribe only to the specific state slice each widget needs; write a performance test asserting rebuild count on a rapid sequence of toggle events.
Contingency: If jank is detected in device testing, replace animated disabled-state transitions with instant opacity changes and defer animation polish to a follow-up sprint.
The disabled card state requires a specific contrast-safe colour combination that communicates unavailability without relying solely on colour (WCAG 1.4.1). If the current design token palette does not include a disabled-state token with sufficient contrast for text on the disabled background, the widget will either fail WCAG AA or require a last-minute design token addition that could break other components.
Mitigation & Contingency
Mitigation: Audit the existing design token manifest for disabled-state tokens at the start of the epic; if missing, raise with the design lead and add a contrast-validated token before widget implementation begins.
Contingency: If no design review is available, use the established --color-text-disabled and --color-surface-disabled tokens with an added strikethrough or lock icon to satisfy WCAG 1.4.1 non-colour requirement, and document the deviation for design review.