high priority medium complexity frontend pending frontend specialist Tier 5

Acceptance Criteria

Tapping the save button with a valid form triggers contact-edit-service and the button transitions to a loading state (CircularProgressIndicator replaces label text) within one frame
The save button is non-interactive (disabled, no ripple) while the network request is in flight, preventing double-submission
On successful save, the route is popped exactly once, returning to ContactDetailScreen with the updated contact data reflected immediately
A SnackBar with a localised success message appears on the ContactDetailScreen within 300ms of route pop and auto-dismisses after 4 seconds
On service failure, an inline error banner is rendered at the top of the form body (not a dialog) with the error message and a 'Retry' action button; the banner persists until the user retries or navigates away
Retry action re-submits the same validated payload without requiring the user to re-enter any data
If the user navigates back manually while a request is in flight, the in-flight request is cancelled via the BLoC/cubit's close method to prevent state updates on a disposed widget
Save button remains disabled if any field carries an active validation error, regardless of loading state
The error banner is announced via a live region (Semantics.liveRegion) for screen reader users
All state transitions are managed through the existing BLoC/Riverpod state, with no local setState calls for async state

Technical Requirements

frameworks
Flutter
BLoC
Riverpod
apis
contact-edit-service (internal)
Supabase REST (via service layer)
data models
Contact
ContactEditPayload
performance requirements
Loading indicator appears within one frame (~16ms) of tap
Route pop and SnackBar display complete within 300ms of success response
No UI jank during state transition; use const constructors where possible
security requirements
Payload must be validated client-side before dispatch to prevent sending malformed data
No sensitive contact fields (e.g. personal ID numbers) are logged or exposed in error messages shown to users
Authentication token is injected by the service layer, not constructed in the widget
ui components
AppButton (loading variant)
SnackBar (via ScaffoldMessenger)
Inline error banner widget (non-dismissable, with retry action)
CircularProgressIndicator (button-embedded)

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

Use BlocConsumer or BlocListener to separate UI reaction from build logic — place navigation and SnackBar display in the listener callback, never in the build method. For the loading state, add an `isSaving` flag to the form cubit/BLoC state and drive the AppButton's `isLoading` prop from it. For route pop, use `context.pop()` (go_router) or `Navigator.of(context).pop(updatedContact)` passing the updated model so ContactDetailScreen can refresh without a full reload. Cancellation on navigate-away: override `dispose()` in the cubit to cancel any pending Futures.

The inline error banner should be a named widget (e.g. `_SaveErrorBanner`) for testability — avoid anonymous closures in the build tree. Use `ScaffoldMessenger.of(context).showSnackBar()` to ensure the SnackBar appears after the pop on the underlying screen.

Testing Requirements

Write widget tests using flutter_test covering: (1) save button is in loading state after tap and service call is pending, (2) successful save triggers Navigator.pop and SnackBar appears on the previous route, (3) service failure renders inline error banner with correct message and retry CTA, (4) retry action re-dispatches the same event, (5) save button is disabled while loading and re-enabled after failure. Mock contact-edit-service using a Fake/Mock class. Aim for 100% branch coverage on the save action handler. Add a golden test for the error banner appearance.

Component
Edit Contact Screen
ui medium
Epic Risks (3)
medium impact medium prob scope

The encrypted-field-display confirmation dialog adds interaction steps that may frustrate coordinators who access sensitive fields frequently, leading to requests to bypass the flow or skip read-receipt logging, which would violate Blindeforbundet's compliance requirements.

Mitigation & Contingency

Mitigation: Design the confirmation dialog to be as minimal as possible (one clear sentence, single confirm action) and ensure it does not reappear for the same field within a single screen session. Validate the UX with Blindeforbundet coordinators during the TestFlight pilot before finalising.

Contingency: If coordinators raise strong objections, escalate to Blindeforbundet's data protection officer to determine whether a lighter confirmation pattern (e.g., biometric confirmation instead of dialog) satisfies their compliance obligation.

medium impact medium prob technical

The activity-history-list infinite scroll requires paginated Supabase queries. Contacts with hundreds of activities (e.g., an HLF peer mentor with 380 annual registrations) could cause slow page loads or memory pressure on older devices if pagination boundaries are set too large.

Mitigation & Contingency

Mitigation: Use a page size of 20 records with cursor-based pagination. Implement list item recycling using Flutter's ListView.builder. Benchmark memory usage with 400+ item simulation on a low-end test device before TestFlight release.

Contingency: If performance degrades on older devices, reduce page size to 10 and add a time-window filter (last 30 days, last 6 months, all) so the default view loads a manageable record count for most coordinators.

low impact high prob scope

The cognitive load rule engine (from the Cognitive Accessibility feature) mandates no more than 7 fields per screen section. If a contact model has more than 7 editable fields, the edit-contact-screen layout must be split into sections, adding complexity not accounted for in the initial scope.

Mitigation & Contingency

Mitigation: Audit the full contact field list from all four organisations before implementation. Group fields into logical sections (personal info, contact details, affiliation) so no single section exceeds 7 fields. Use the cognitive-load-rule-engine component if it is already delivered by the Cognitive Accessibility feature.

Contingency: If the rule-engine component is not yet available, implement a simple manual section layout with accordion-style expansion for less-frequently edited fields to stay within the 7-field guideline without blocking delivery.