import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../models/profile.model.dart'; import '../../../models/programmer_task.model.dart'; import '../../../providers/profile_provider.dart'; import '../../../providers/programmer_day_data_provider.dart'; import '../../../providers/programmer_tasks_provider.dart'; import '../../../utils/programmer_daily_time.dart'; import 'now_working_card.dart'; import 'task_sections.dart'; /// The programmer's own work dashboard — hero card, stat tiles (Task 8), and /// task sections. Drop it into the Mine tab with `userId: me`. class ProgrammerDashboard extends ConsumerWidget { const ProgrammerDashboard({ super.key, required this.userId, this.readOnly = false, }); final String userId; final bool readOnly; @override Widget build(BuildContext context, WidgetRef ref) { // Drive 30-second rebuilds so duration values stay fresh. ref.watch(clockTickerProvider); final tasksAsync = ref.watch(programmerTasksProvider); final runStates = ref.watch(programmerRunStatesProvider); final todayKey = ref.watch(todayKeyProvider); final dayDataAsync = ref.watch(programmerDayDataProvider(todayKey)); final profilesAsync = ref.watch(profilesProvider); final tasks = tasksAsync.valueOrNull ?? const []; final profileById = { for (final p in profilesAsync.valueOrNull ?? []) p.id: p, }; final groups = groupTasksForDashboard(tasks, runStates, userId); final runningTask = groups.running.isNotEmpty ? groups.running.first : null; final nextUp = groups.notStarted.isNotEmpty ? groups.notStarted.first : null; final todayOnTask = _computeTodayDuration( runningTask: runningTask, dayDataAsync: dayDataAsync, userId: userId, todayKey: todayKey, ); final totalOnTask = _computeTotalDuration( runningTask: runningTask, dayDataAsync: dayDataAsync, userId: userId, ); return ListView( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), children: [ NowWorkingCard( running: runningTask, nextUp: nextUp, todayOnTask: todayOnTask, totalOnTask: totalOnTask, readOnly: readOnly, ), const SizedBox(height: 16), // TODO: Task 8 inserts StatTiles + BadgesStrip here TaskSections( groups: groups, profileById: profileById, readOnly: readOnly, ), ], ); } Duration _computeTodayDuration({ required ProgrammerTask? runningTask, required AsyncValue dayDataAsync, required String userId, required DateTime todayKey, }) { if (runningTask == null) return Duration.zero; final dayData = dayDataAsync.valueOrNull; if (dayData == null) return Duration.zero; final logs = dayData.logsByTask[runningTask.id] ?? const []; final dailyByAssignee = dailySecondsByAssignee( task: runningTask, logs: logs, now: DateTime.now().toUtc(), ); final secs = dailyByAssignee[userId]?[todayKey] ?? 0; return Duration(seconds: secs); } Duration _computeTotalDuration({ required ProgrammerTask? runningTask, required AsyncValue dayDataAsync, required String userId, }) { if (runningTask == null) return Duration.zero; final dayData = dayDataAsync.valueOrNull; if (dayData == null) return Duration.zero; final logs = dayData.logsByTask[runningTask.id] ?? const []; final dailyByAssignee = dailySecondsByAssignee( task: runningTask, logs: logs, now: DateTime.now().toUtc(), ); final totalSecs = (dailyByAssignee[userId] ?? const {}).values.fold(0, (s, v) => s + v); return Duration(seconds: totalSecs); } }