feat(programmer): sheet-driven stats, monitor status, drill-down history
- 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>
This commit is contained in:
@@ -2,11 +2,14 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../../models/programmer_day_sheet.model.dart';
|
||||
import '../../../providers/leave_provider.dart';
|
||||
import '../../../providers/pass_slip_provider.dart';
|
||||
import '../../../providers/profile_provider.dart';
|
||||
import '../../../providers/programmer_day_data_provider.dart';
|
||||
import '../../../providers/programmer_day_sheets_provider.dart';
|
||||
import '../../../utils/app_time.dart';
|
||||
import '../../../utils/programmer_daily_time.dart';
|
||||
import '../../../utils/staff_presence.dart';
|
||||
import '../../../widgets/app_status_summary.dart';
|
||||
import '../../../theme/app_status_colors.dart';
|
||||
@@ -28,6 +31,7 @@ class MonitorTab extends ConsumerWidget {
|
||||
final runStates = ref.watch(programmerRunStatesProvider);
|
||||
final leavesAsync = ref.watch(leavesProvider);
|
||||
final passSlipsAsync = ref.watch(passSlipsProvider);
|
||||
final allSheetsAsync = ref.watch(allDaySheetsProvider);
|
||||
|
||||
final profiles = profilesAsync.valueOrNull ?? [];
|
||||
final programmerProfiles =
|
||||
@@ -41,6 +45,20 @@ class MonitorTab extends ConsumerWidget {
|
||||
final activeLeaves = activeLeaveByUser(leaves, now);
|
||||
final activePassSlips = activePassSlipByUser(passSlips);
|
||||
|
||||
// Build sheetStatusByUser for today: programmerId → status.
|
||||
final allSheets = allSheetsAsync.valueOrNull ?? const <ProgrammerDaySheet>[];
|
||||
final sheetStatusByUser = <String, String>{};
|
||||
var sheetsPending = 0;
|
||||
for (final sheet in allSheets) {
|
||||
if (sheet.workDate == manilaDay(now)) {
|
||||
sheetStatusByUser[sheet.programmerId] = sheet.status;
|
||||
if (sheet.status == DaySheetStatus.pending ||
|
||||
sheet.status == DaySheetStatus.disapproved) {
|
||||
sheetsPending++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dayDataAsync.isLoading && !dayDataAsync.hasValue) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
@@ -55,7 +73,7 @@ class MonitorTab extends ConsumerWidget {
|
||||
runStates: runStates,
|
||||
leaves: activeLeaves,
|
||||
passSlips: activePassSlips,
|
||||
sheetStatusByUser: const {},
|
||||
sheetStatusByUser: sheetStatusByUser,
|
||||
projectNames: const {},
|
||||
profileNames: profileNames,
|
||||
now: now,
|
||||
@@ -102,6 +120,11 @@ class MonitorTab extends ConsumerWidget {
|
||||
count: away,
|
||||
kind: StatusKind.info,
|
||||
),
|
||||
AppStatusSummaryItem(
|
||||
label: 'Sheets pending',
|
||||
count: sheetsPending,
|
||||
kind: StatusKind.warning,
|
||||
),
|
||||
];
|
||||
|
||||
return LayoutBuilder(
|
||||
|
||||
Reference in New Issue
Block a user