high priority medium complexity frontend pending frontend specialist Tier 2

Acceptance Criteria

DriverFeeRegistrationForm is a StatelessWidget (or ConsumerWidget if Riverpod is used for form state) that renders inside DriverFeatureFlagGuard
When DriverFeatureFlagGuard evaluates the driver feature flag as disabled, the form is not rendered and a suitable blocked-access UI is shown instead
The contact selector reuses the existing contact picker widget without duplication; it is pre-focused when the form opens if no contact is pre-filled
The fee amount field accepts only numeric input with up to two decimal places; it displays the NOK currency symbol as a leading decoration using design tokens
The fee type dropdown renders all fee type options supplied by the parent/BLoC; selecting an option updates the form field without page navigation
A 'Declaration required' entry point (button or inline prompt) is visible in the form and navigates to DeclarationSendScreen when tapped
All colors, typography, spacing, border radii, and icon sizes use design tokens exclusively — zero hardcoded hex values or raw pixel values
The form layout is responsive: it renders correctly on screen widths from 320px (compact phones) to tablet widths
The submit button is present in the shell but may be in a disabled/placeholder state pending BLoC wiring in task-011
No validation logic is implemented in this shell task — fields accept any input without error display (validation added in task-011)
The form is scrollable when the keyboard is open; it does not overflow or clip fields behind the system keyboard

Technical Requirements

frameworks
Flutter
BLoC (flutter_bloc)
Dart
apis
ContactPickerService (reused existing picker)
FeeTypeRepository (dropdown options)
data models
DriverFee
FeeType
Contact
performance requirements
Form renders in a single frame on open — no async gaps before initial layout
Currency input formatter must run synchronously with no perceptible lag on each keystroke
security requirements
Fee amount input must be sanitized to reject non-numeric characters at the formatter level, not just at validation time
Contact picker must only surface contacts within the authenticated coordinator's accessible scope
ui components
DriverFeeRegistrationForm
DriverFeatureFlagGuard
ContactPickerField (reused)
CurrencyTextField
FeeTypeDropdown
DeclarationEntryPointButton
AppButton (submit)
AppTextField

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Define the form using Flutter's Form widget with a GlobalKey so validation (added in task-011) can be triggered externally from the BLoC layer. Use TextEditingController for the fee amount field and attach a CurrencyInputFormatter using the flutter TextInputFormatter interface — format on every change to display '1 234,50 NOK' style Norwegian locale formatting. Source all fee type options from the BLoC/Riverpod provider, not from a hardcoded list in the widget. For the declaration entry point, make it conditional: the widget accepts a bool showDeclarationPrompt parameter that the BLoC will control in task-011.

Keep this shell task focused on layout and wiring of visual elements only — resist the urge to add any business logic here.

Testing Requirements

Write Flutter widget tests for: (1) form renders when feature flag is enabled; (2) DriverFeatureFlagGuard blocks render when flag is disabled; (3) contact picker field is present and tappable; (4) fee amount field accepts numeric input and displays NOK prefix; (5) fee type dropdown renders all provided options; (6) declaration entry point button navigates to DeclarationSendScreen; (7) form scrolls without overflow when keyboard is simulated open. No validation tests in this task — those belong to task-011. Use WidgetTester.pumpWidget with a mock feature flag provider returning enabled/disabled values.

Component
Driver Fee Registration Form
ui medium
Epic Risks (3)
high impact medium prob technical

The declaration acknowledgement screen has the most complex accessibility requirements of any screen in this feature: scrollable long-form legal text, a conditional checkbox that is only enabled after reading, and a timestamp capture. Incorrect focus management or missing semantics annotations could fail VoiceOver navigation or cause the screen reader to announce the checkbox as available before the driver has scrolled, undermining the legal validity of the acknowledgement.

Mitigation & Contingency

Mitigation: Build the acknowledgement screen against the WCAG 2.2 AA checklist from the start, not as a post-hoc audit. Use semantics-wrapper-widget and live-region-announcer from the platform's accessibility toolkit. Include a VoiceOver test session in the acceptance criteria with a tester using the screen reader.

Contingency: If WCAG compliance cannot be fully achieved within the sprint, ship the screen with a documented list of accessibility gaps and a follow-up sprint commitment. Do not block the declaration workflow launch if the core interaction works but a non-critical semantics annotation is missing.

medium impact medium prob integration

Drivers receive a push notification with a deep link to the declaration acknowledgement screen for a specific assignment. If the deep link handler does not correctly route to the right screen and assignment context — particularly when the app is launched cold from the notification — the driver may see a blank screen or the wrong declaration.

Mitigation & Contingency

Mitigation: Implement and test all three notification scenarios: app foregrounded, app backgrounded, and cold start. Use the platform's existing deep-link-handler infrastructure. Add integration tests that simulate notification tap events and assert correct screen and data loading.

Contingency: If cold-start deep link routing proves unreliable, implement a notification-centre fallback where the driver can find the pending declaration from the notification centre screen, ensuring the workflow can always complete even if the direct deep link fails.

medium impact low prob technical

If the driver-feature-flag-guard has any rendering edge case — such as a brief flash of driver UI before the flag value is loaded, or a guard that fails open on a flag service error — driver-specific UI elements could be momentarily visible to coordinators in organizations that have not opted in, causing confusion and potentially a support escalation.

Mitigation & Contingency

Mitigation: Default the guard to rendering nothing (not a loading indicator) until the flag value is definitively resolved. Treat flag service errors as flag-disabled to fail closed. Write widget tests covering the loading, disabled, and enabled states including the error case.

Contingency: If fail-closed cannot be guaranteed within the sprint, add a server-side RLS check on the driver assignment endpoints so that even if the UI guard leaks, the data layer refuses to return driver data for organizations without the flag enabled.