critical priority low complexity frontend pending frontend specialist Tier 1

Acceptance Criteria

Tapping the Reject action button automatically focuses the comment TextField and scrolls it into view
The comment field is visually highlighted (border color change using error color token) when the reject flow is active
Attempting to confirm a rejection with an empty comment field displays an inline error message directly below the comment field — not a snackbar or dialog
The inline error message reads 'A rejection reason is required' (or equivalent localized string)
The inline error message is announced by screen readers (VoiceOver/TalkBack) via Semantics widget with liveRegion: true
Confirm Rejection button remains in a visually disabled or non-submittable state until comment field contains at least 1 non-whitespace character
Clearing the comment field after it had content re-disables the Confirm Rejection button
Comment field accepts multi-line input (maxLines: null or minLines: 3) to accommodate longer rejection reasons
Validation state is managed in local widget state (StatefulWidget or BLoC) and does not persist after sheet is dismissed
Approve flow is completely unaffected by comment validation — approve path requires no comment

Technical Requirements

frameworks
Flutter
BLoC
data models
claim_event
performance requirements
Focus transition to comment field must complete within one frame (no visible delay after Reject button tap)
security requirements
Rejection comment must be trimmed of leading/trailing whitespace before submission to prevent empty-string bypass
ui components
AppTextField with error state variant
FocusNode for programmatic focus management
Semantics widget with liveRegion for error announcement
ValueNotifier or BLoC state for comment validation state

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Create a FocusNode for the comment TextField and call FocusScope.of(context).requestFocus(commentFocusNode) in the Reject button's onPressed handler. Use a local StatefulWidget bool _showCommentError and String _commentText (via TextEditingController.addListener) to drive the validation UI. Avoid form validation packages — the logic is simple enough for direct state management. The error text widget should use the design token error color (errorContainer or equivalent) and be wrapped in an AnimatedSwitcher for a subtle fade-in.

Whitespace-trim validation: commentController.text.trim().isEmpty. Keep approve and reject as enum-based action state (ApprovalAction.approve / ApprovalAction.reject) to clearly separate the two paths.

Testing Requirements

Widget tests must cover: (1) tapping Reject button moves focus to comment field — verify FocusNode.hasFocus; (2) tapping Confirm Rejection with empty comment renders inline error text widget; (3) tapping Confirm Rejection with whitespace-only comment also renders error; (4) entering valid comment removes error widget; (5) Confirm button widget is disabled (onPressed == null) when comment is empty; (6) Approve path does not trigger comment validation. Use flutter_test WidgetTester with enterText and pump.

Component
Approval Action Bottom Sheet
ui medium
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.