Build BulkApprovalBar sticky UI widget
epic-expense-approval-workflow-bulk-and-action-task-004 — Implement the BulkApprovalBar as a sticky bottom widget that becomes visible when one or more claims are selected in the coordinator review queue. Display selected claim count, provide Approve All and Reject All action buttons, and emit events to trigger BulkApprovalProcessor. Widget must remain anchored above the bottom navigation bar.
Acceptance Criteria
Technical Requirements
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.
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.
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.