high priority medium complexity frontend pending frontend specialist Tier 2

Acceptance Criteria

A DeclarationSendCubit (or BLoC) is implemented with sealed state classes: DeclarationSendInitial, DeclarationSendLoading, DeclarationSendTemplateLoaded, DeclarationSendSending, DeclarationSendSent, DeclarationSendResending, DeclarationSendError
On screen mount, the cubit automatically triggers template and declaration status loading from DeclarationManagementService
In DeclarationSendLoading state, a loading indicator replaces the template preview section
In DeclarationSendTemplateLoaded state, the template preview section renders the actual declaration template content (HTML or formatted text)
In DeclarationSendSending state, the Send button shows a loading spinner and is disabled; Re-send is also disabled
In DeclarationSendSent state, the Send button changes to a success state (checkmark or 'Sent' label), a success SnackBar or inline message is shown
In DeclarationSendResending state, the Re-send button shows a loading spinner and is disabled
In DeclarationSendError state, an accessible error message is displayed with a retry option
DeclarationStatusBadge is rendered and reflects the current declaration status (not sent, sent, acknowledged, expired)
Send and Re-send buttons call the correct DeclarationManagementService methods with the loaded assignment ID
Unit tests cover all state transitions with mocked DeclarationManagementService
Widget tests verify UI reflects each BLoC state correctly

Technical Requirements

frameworks
Flutter
BLoC
Riverpod
apis
DeclarationManagementService (send)
DeclarationManagementService (resend)
DeclarationManagementService (getTemplate)
Supabase Edge Functions (Deno)
data models
confidentiality_declaration
assignment
contact
performance requirements
Template loading must not block the UI thread — use async/await with proper state transitions
Send operation must provide immediate feedback (loading state) within 100ms of button tap
security requirements
Declaration template content must not be cached in widget state beyond the current screen lifecycle
Send/Re-send operations must include the authenticated user's JWT from Supabase Auth — never send unauthenticated requests
Assignment ID must be validated server-side — do not rely solely on client-side route parameter validation
Error messages must not expose internal server details or PII in the UI error state
ui components
DeclarationSendCubit
DeclarationStatusBadge
CircularProgressIndicator (loading states)
SnackBar (success feedback)
AppButton (send/resend with loading states)
ErrorMessageWidget

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Use flutter_bloc Cubit (not full BLoC with events) since the state transitions are linear and do not require complex event streams. Define the state hierarchy using sealed classes for exhaustive pattern matching in the UI. The cubit's loadTemplate() method should call DeclarationManagementService.getDeclarationTemplate(assignmentId) and DeclarationManagementService.getDeclarationStatus(assignmentId) in parallel using Future.wait(). For the template preview, if the template is HTML, use a Flutter WebView or a simple HTML-to-widget parser — confirm with the team which format templates use before implementing.

The DeclarationStatusBadge should be a separate stateless widget accepting a DeclarationStatus enum, not coupled to the cubit. Ensure the cubit is provided via BlocProvider at the screen level (not globally) so it is disposed when the screen is popped.

Testing Requirements

Unit tests for DeclarationSendCubit using bloc_test package. Test all state transitions: initial → loading → templateLoaded, templateLoaded → sending → sent, templateLoaded → sending → error, sent → resending → sent, error → loading (retry). Mock DeclarationManagementService using Mockito or Mocktail. Widget tests for DeclarationSendScreen verifying each BLoC state produces the correct UI (loading spinner, template content visible, success message, error message).

Minimum 90% branch coverage on the cubit. Integration test verifying the full send flow against a mocked Supabase Edge Function is recommended but not required for this task.

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.