buildDayRows can emit both an 'assignee' row and a 'helper' row for the
same taskId when a programmer previously held a task (accumulated clock
time) and later helped on it after reassignment. ValueKey(row.taskId)
collided in that case, crashing Flutter's widget tree with a red screen.
Fixed by keying on taskId:kind, making each row unique.
Caught during targeted QA on the new loading-state / dialog flows.
Co-Authored-By: claude-flow <ruv@ruv.net>
Day sheet dialogs (disapprove, justify): moved the async controller call
inside each dialog so loading state is owned there — button shows a
spinner and is disabled while the RPC is in flight; errors display inline
instead of via a snackbar after dialog close.
Detail screen (approve): added _approvingSheet bool; Approve button shows
CircularProgressIndicator while in flight. On success shows an AlertDialog
"Sheet Approved" with a check icon instead of silently updating state.
Approvals tab (bulk approve): upgraded post-approve feedback from a
snackbar to a success AlertDialog showing the count of approved sheets
and any skipped ones.
Day sheets tab (submit): added confirmation AlertDialog before the
existing submit flow so programmers don't accidentally submit mid-day.
Co-Authored-By: claude-flow <ruv@ruv.net>
approvedSnapshot is only populated at approval time; pending and disapproved
sheets had null snapshot so the card always displayed 0m · 0 tasks.
Now totalSecs/taskCount are passed as nullable params from the parent; the
card renders — when no snapshot is available yet.
Also accept camelCase 'daySheets' URL param in parseProgrammerTasksTab
alongside the existing hyphenated 'day-sheets' spelling.
Co-Authored-By: claude-flow <ruv@ruv.net>
- Wire daySheetsForUserProvider(userId) into ProgrammerDashboard so
computeProgrammerStats/computeBadges receive real sheet data instead of
the placeholder const <ProgrammerDaySheet>[].
- Monitor tab: watch allDaySheetsProvider and build sheetStatusByUser map
for today; pass it to buildMonitorEntries; add "Sheets pending" chip
(pending + disapproved today) to the summary row.
- ProgrammerDrillDownScreen: add _RecentDaySheetsPanel below the dashboard
showing the last 10 sheets (date + status pill) with tap-to-daySheetDetail.
- DaySheetDetailScreen (T17 gaps): replace const [] liveRows with
programmerDayDataProvider(sheet.workDate) built rows for non-approved
sheets; fix _onApprove timer check to filter only the sheet programmer's
own tasks (QN-1).
- Add test/programmer_drill_down_test.dart (3 tests, all passing).
Co-Authored-By: claude-flow <ruv@ruv.net>