high priority low complexity frontend pending frontend specialist Tier 0

Acceptance Criteria

ExpenseCalculationPreview renders the zero-state placeholder when it receives a null or empty selection state
Placeholder contains: an illustrative icon (sourced from design tokens or app icon set), a primary instructional heading, and a secondary descriptive sentence
All text and icon colors use design tokens exclusively — zero hardcoded values
Placeholder container has sufficient height to occupy the space the calculation preview will eventually fill (prevents layout shift on selection)
When the placeholder appears (transition from preview→zero-state), a live-region Semantics announcement is made so screen readers inform the user that no type is selected
The live-region announcement fires at most once per appearance (not on every frame)
Placeholder is visually differentiated from the loaded state — uses a muted/secondary color palette to avoid appearing interactive
Widget test confirms placeholder renders when state is null and does not render when a valid selection is provided

Technical Requirements

frameworks
Flutter
flutter_test
data models
ExpenseCalculationPreviewState (null = zero state)
performance requirements
Placeholder must be a const widget or near-const to avoid rebuild overhead
ui components
ExpenseCalculationPreview (new widget with conditional rendering)
Semantics with liveRegion: true
Design token icon and typography constants

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Use a simple conditional in the build method: if (state == null) return _ZeroStatePlaceholder(); else return _PreviewContent(state: state!). Extract _ZeroStatePlaceholder as a private StatelessWidget so it can be made const. For the live-region announcement, wrap the placeholder in a Semantics widget with liveRegion: true and a meaningful label (e.g., 'No expense type selected. Choose a type above to see the calculation.').

To ensure the announcement fires only on appearance rather than every rebuild, consider using a StatefulWidget with a didUpdateWidget check, or manage the announcement at the parent screen level when transitioning into the zero state. Keep the placeholder height consistent with the expected preview content height by using a SizedBox with a design-token-defined minimum height constant. The instructional copy should be localized via the app's l10n system — no hardcoded strings.

Testing Requirements

Widget tests: (1) render widget with null state, confirm placeholder is present and the preview content is absent, (2) render widget with a valid state, confirm placeholder is absent and preview content is present, (3) use tester.getSemantics() to confirm the live-region Semantics node is present when placeholder is shown, (4) transition from a valid state to null and confirm the live-region fires (use SemanticsController or a semantic update listener in test), (5) golden test the zero-state placeholder at standard and 1.5Ă— text scale. Coverage target: 100% of conditional branches.

Component
Expense Calculation Preview
ui low
Epic Risks (2)
medium impact medium prob technical

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.

medium impact low prob integration

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.