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'; import 'help_panel.dart'; import 'monitor_model.dart'; import 'programmer_monitor_card.dart'; /// Summary row + programmer grid + help panel for the Monitor tab. class MonitorTab extends ConsumerWidget { const MonitorTab({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { // Tick every 30 s to keep durations fresh. final now = ref.watch(clockTickerProvider).valueOrNull ?? AppTime.now(); final todayKey = ref.watch(todayKeyProvider); final profilesAsync = ref.watch(profilesProvider); final dayDataAsync = ref.watch(programmerDayDataProvider(todayKey)); 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 = profiles.where((p) => p.role == 'programmer').toList(); final profileNames = { for (final p in profiles) p.id: p.fullName, }; final leaves = leavesAsync.valueOrNull ?? []; final passSlips = passSlipsAsync.valueOrNull ?? []; final activeLeaves = activeLeaveByUser(leaves, now); final activePassSlips = activePassSlipByUser(passSlips); // Build sheetStatusByUser for today: programmerId → status. final allSheets = allSheetsAsync.valueOrNull ?? const []; final sheetStatusByUser = {}; 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()); } final dayData = dayDataAsync.valueOrNull; List entries = []; if (dayData != null) { entries = buildMonitorEntries( programmers: programmerProfiles, today: dayData, runStates: runStates, leaves: activeLeaves, passSlips: activePassSlips, sheetStatusByUser: sheetStatusByUser, projectNames: const {}, profileNames: profileNames, now: now, ); } // Compute summary counts. var working = 0; var paused = 0; var idle = 0; var away = 0; for (final e in entries) { switch (e.state) { case MonitorState.working: working++; case MonitorState.paused: paused++; case MonitorState.idle: idle++; case MonitorState.onLeave: case MonitorState.passSlip: away++; } } final summaryItems = [ AppStatusSummaryItem( label: 'Working', count: working, kind: StatusKind.success, ), AppStatusSummaryItem( label: 'Paused', count: paused, kind: StatusKind.warning, ), AppStatusSummaryItem( label: 'Idle', count: idle, kind: StatusKind.neutral, ), AppStatusSummaryItem( label: 'Away', count: away, kind: StatusKind.info, ), AppStatusSummaryItem( label: 'Sheets pending', count: sheetsPending, kind: StatusKind.warning, ), ]; return LayoutBuilder( builder: (context, constraints) { final width = constraints.maxWidth; // Help panel breakpoint: show side-by-side at >= 900. final sideBySide = width >= 900; final grid = _ProgrammerGrid( entries: entries, profileNames: profileNames, width: sideBySide ? width - 320 : width, ); final body = sideBySide ? Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded(child: grid), const SizedBox(width: 12), SizedBox( width: 300, child: HelpPanel(profileNames: profileNames), ), ], ) : Column( children: [ grid, const SizedBox(height: 16), SizedBox( height: 340, child: HelpPanel(profileNames: profileNames), ), ], ); return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ AppStatusSummaryRow( items: summaryItems, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), ), Expanded( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: body, ), ), ], ); }, ); } } class _ProgrammerGrid extends StatelessWidget { const _ProgrammerGrid({ required this.entries, required this.profileNames, required this.width, }); final List entries; final Map profileNames; final double width; @override Widget build(BuildContext context) { final crossAxisCount = width < 700 ? 1 : width < 1100 ? 2 : 3; if (entries.isEmpty) { return const Center( child: Padding( padding: EdgeInsets.all(24), child: Text('No programmers found.'), ), ); } return GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: crossAxisCount, mainAxisSpacing: 10, crossAxisSpacing: 10, childAspectRatio: 2.4, ), itemCount: entries.length, itemBuilder: (context, i) { final entry = entries[i]; return ProgrammerMonitorCard( entry: entry, profileNames: profileNames, onTap: () => context.go('/programmer-tasks/programmers/${entry.programmer.id}'), ); }, ); } }