high priority low complexity frontend pending frontend specialist Tier 0

Acceptance Criteria

BulkApprovalBar is a StatelessWidget accepting: selectedCount (int), onApproveAll (VoidCallback?), onRejectAll (VoidCallback?), isProcessing (bool)
Widget is invisible (zero height, no render) when selectedCount == 0
Widget animates in with a slide-up transition when selectedCount transitions from 0 to 1
Widget animates out with a slide-down transition when selectedCount returns to 0
Displayed label reads: '{N} claim(s) selected' with correct singular/plural form
Approve All button uses design token accent color (success/confirm), Reject All uses destructive color token
Both buttons are disabled and show a CircularProgressIndicator inside the bar when isProcessing == true
Widget uses Stack or a Column with the bar above a BottomNavigationBar — does not overlap the nav bar
Widget is anchored using MediaQuery.of(context).padding.bottom to respect device safe area
All interactive elements meet WCAG 2.2 AA minimum tap target size (48x48dp)
Approve All and Reject All buttons have Semantics labels for screen reader accessibility
Widget uses only design tokens (colors, typography, spacing, border radii) — no hardcoded style values

Technical Requirements

frameworks
Flutter
Dart
performance requirements
Slide animation must run at 60fps — use AnimatedSlide or AnimatedContainer, not custom animation controller unless necessary
Widget rebuild triggered only when selectedCount or isProcessing changes — no unnecessary repaints
security requirements
onApproveAll and onRejectAll callbacks accept null — when null, buttons are disabled (prevents accidental invocation before wiring)
ui components
AnimatedSlide or AnimatedContainer for entry/exit animation
ElevatedButton or AppButton (project design system) for action buttons
CircularProgressIndicator for loading state
SafeArea or manual bottom padding via MediaQuery

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Position BulkApprovalBar above the bottom nav by placing it in the page Scaffold's body using a Column with Expanded(child: content) + BulkApprovalBar(), not inside the bottomNavigationBar slot (which would cause it to sit behind the nav). Alternatively use a Stack with Positioned if the nav bar is managed by a shell route. Use AnimatedCrossFade or Visibility(maintainState: false) for the show/hide to avoid layout jank. The widget should NOT hold any state itself — all state (selectedCount, isProcessing) is passed as constructor parameters, keeping it purely presentational.

This makes it trivially testable and reusable.

Testing Requirements

Widget tests: (1) widget renders nothing when selectedCount=0, (2) widget visible with correct label when selectedCount=3, (3) singular label 'claim' for selectedCount=1 vs plural 'claims' for selectedCount=2, (4) both buttons disabled when isProcessing=true, (5) onApproveAll callback fires on Approve All tap, (6) onRejectAll callback fires on Reject All tap, (7) buttons disabled (not just hidden) when callbacks are null, (8) Semantics label present on both action buttons. Golden tests optional but recommended for visual regression. Run with flutter_test.

Component
Bulk Approval Action Bar
ui low
Epic Risks (2)
medium impact medium prob scope

If a bulk approval batch partially fails (some claims approved, some failed), the UI must communicate which specific claims failed without overwhelming the coordinator. A poorly designed error display could cause coordinators to re-approve already-approved claims or miss claims that still need attention.

Mitigation & Contingency

Mitigation: Design the BulkApprovalResult display to show a clear summary (e.g., '14 approved, 2 failed') with a collapsible list of failed claims including their IDs and submitter names. Failed claims should remain selected in the queue so the coordinator can retry them individually.

Contingency: If the summary UI proves insufficient, add a dedicated 'bulk action history' sheet showing the last bulk operation result, accessible from the queue screen header.

medium impact low prob technical

If the app is backgrounded or the network drops while the coordinator has the ApprovalActionSheet open mid-decision, the typed comment could be lost and the transition state could be ambiguous, potentially causing a coordinator to believe they approved a claim that was never submitted.

Mitigation & Contingency

Mitigation: Persist the in-progress action sheet state (selected action + comment text) to a local draft store keyed on claim ID. On sheet re-open for the same claim, restore the draft. After confirmed submission, verify the resulting claim status from the server before dismissing the sheet.

Contingency: On network error during submission, display a persistent retry banner within the sheet rather than dismissing it, so the coordinator can resubmit without re-entering their comment.