feat(programmer): dashboard stat tiles + badges
Add StatTiles and BadgesStrip widgets wired into ProgrammerDashboard. StatTiles shows 2 tiles (focus + completed) when showSheetStats is false, and 5 tiles (+ streak, first-pass approval, help given) when the viewing user's role is programmer. BadgesStrip renders earned/locked chips in a horizontal Wrap with tap-to-dialog detail. Dashboard feeds todayFocus via buildDayRows/totalSeconds, leaveDays via approvedLeaveDays, and sheets: const [] until Task 20 wires real data. Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -2,12 +2,20 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../../../models/profile.model.dart';
|
||||
import '../../../models/programmer_day_sheet.model.dart';
|
||||
import '../../../models/programmer_task.model.dart';
|
||||
import '../../../providers/leave_provider.dart';
|
||||
import '../../../providers/profile_provider.dart';
|
||||
import '../../../providers/programmer_day_data_provider.dart';
|
||||
import '../../../providers/programmer_tasks_provider.dart';
|
||||
import '../../../utils/app_time.dart';
|
||||
import '../../../utils/programmer_daily_time.dart';
|
||||
import '../../../utils/programmer_day_rows.dart';
|
||||
import '../../../utils/programmer_stats.dart';
|
||||
import '../../../utils/staff_presence.dart';
|
||||
import 'badges_strip.dart';
|
||||
import 'now_working_card.dart';
|
||||
import 'stat_tiles.dart';
|
||||
import 'task_sections.dart';
|
||||
|
||||
/// The programmer's own work dashboard — hero card, stat tiles (Task 8), and
|
||||
@@ -33,10 +41,49 @@ class ProgrammerDashboard extends ConsumerWidget {
|
||||
final dayDataAsync = ref.watch(programmerDayDataProvider(todayKey));
|
||||
final profilesAsync = ref.watch(profilesProvider);
|
||||
|
||||
final now = ref.watch(clockTickerProvider).valueOrNull ?? AppTime.now();
|
||||
|
||||
final tasks = tasksAsync.valueOrNull ?? const [];
|
||||
final profileById = <String, Profile>{
|
||||
for (final p in profilesAsync.valueOrNull ?? <Profile>[]) p.id: p,
|
||||
};
|
||||
final profileNames = <String, String>{
|
||||
for (final p in profilesAsync.valueOrNull ?? <Profile>[]) p.id: p.fullName,
|
||||
};
|
||||
|
||||
final dayData = dayDataAsync.valueOrNull;
|
||||
final leaveDays = approvedLeaveDays(
|
||||
ref.watch(leavesProvider).valueOrNull ?? [],
|
||||
userId,
|
||||
);
|
||||
|
||||
final todayRows = dayData == null
|
||||
? const <DaySheetRow>[]
|
||||
: buildDayRows(
|
||||
userId: userId,
|
||||
day: todayKey,
|
||||
tasks: tasks,
|
||||
logsByTask: dayData.logsByTask,
|
||||
workLogs: dayData.workLogs,
|
||||
projectNames: const {},
|
||||
profileNames: profileNames,
|
||||
now: now,
|
||||
);
|
||||
final todayFocus = Duration(seconds: totalSeconds(todayRows));
|
||||
|
||||
final stats = computeProgrammerStats(
|
||||
userId: userId,
|
||||
now: now,
|
||||
tasks: tasks,
|
||||
sheets: const <ProgrammerDaySheet>[],
|
||||
leaveDays: leaveDays,
|
||||
todayFocus: todayFocus,
|
||||
);
|
||||
|
||||
final showSheetStats =
|
||||
ref.watch(currentProfileProvider).valueOrNull?.role == 'programmer';
|
||||
|
||||
final badges = computeBadges(stats, includeSheetBadges: showSheetStats);
|
||||
|
||||
final groups = groupTasksForDashboard(tasks, runStates, userId);
|
||||
final runningTask =
|
||||
@@ -67,7 +114,10 @@ class ProgrammerDashboard extends ConsumerWidget {
|
||||
readOnly: readOnly,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// TODO: Task 8 inserts StatTiles + BadgesStrip here
|
||||
StatTiles(stats: stats, showSheetStats: showSheetStats),
|
||||
const SizedBox(height: 8),
|
||||
BadgesStrip(badges: badges),
|
||||
const SizedBox(height: 16),
|
||||
TaskSections(
|
||||
groups: groups,
|
||||
profileById: profileById,
|
||||
|
||||
Reference in New Issue
Block a user