diff --git a/frontend/src/components/StatCard.tsx b/frontend/src/components/StatCard.tsx index b719705..3627e7b 100644 --- a/frontend/src/components/StatCard.tsx +++ b/frontend/src/components/StatCard.tsx @@ -3,25 +3,35 @@ interface StatCardProps { label: string; value: string; color: 'blue' | 'green' | 'purple' | 'orange'; + /** When true, renders a pulsing green dot to signal a live/active state. */ + indicator?: boolean; } -const colorClasses: Record = { +const colorClasses: Record, string> = { blue: 'bg-blue-50 text-blue-600', green: 'bg-green-50 text-green-600', purple: 'bg-purple-50 text-purple-600', orange: 'bg-orange-50 text-orange-600', }; -export function StatCard({ icon: Icon, label, value, color }: StatCardProps) { +export function StatCard({ icon: Icon, label, value, color, indicator }: StatCardProps) { return (
-
+

{label}

-

{value}

+
+

{value}

+ {indicator && ( + + )} +
diff --git a/frontend/src/pages/DashboardPage.tsx b/frontend/src/pages/DashboardPage.tsx index 96d2c83..94de5e3 100644 --- a/frontend/src/pages/DashboardPage.tsx +++ b/frontend/src/pages/DashboardPage.tsx @@ -3,6 +3,7 @@ import { Link } from "react-router-dom"; import { Clock, Calendar, Briefcase, TrendingUp, Target, Edit2, Trash2 } from "lucide-react"; import { useTimeEntries } from "@/hooks/useTimeEntries"; import { useClientTargets } from "@/hooks/useClientTargets"; +import { useTimer } from "@/contexts/TimerContext"; import { ProjectColorDot } from "@/components/ProjectColorDot"; import { StatCard } from "@/components/StatCard"; import { TimeEntryFormModal } from "@/components/TimeEntryFormModal"; @@ -30,6 +31,7 @@ export function DashboardPage() { }); const { targets } = useClientTargets(); + const { ongoingTimer, elapsedSeconds } = useTimer(); const [isModalOpen, setIsModalOpen] = useState(false); const [editingEntry, setEditingEntry] = useState(null); @@ -54,10 +56,17 @@ export function DashboardPage() { } }; - const totalTodaySeconds = + const completedTodaySeconds = todayEntries?.entries.reduce((total, entry) => { return total + calculateDuration(entry.startTime, entry.endTime, entry.breakMinutes); - }, 0) || 0; + }, 0) ?? 0; + + // Only add the running timer if it started today (not a timer left running from yesterday) + const timerStartedToday = + ongoingTimer !== null && + new Date(ongoingTimer.startTime) >= startOfDay(today); + + const totalTodaySeconds = completedTodaySeconds + (timerStartedToday ? elapsedSeconds : 0); const targetsWithData = targets?.filter(t => t.periods.length > 0) ?? []; @@ -78,6 +87,7 @@ export function DashboardPage() { label="Today" value={formatDurationHoursMinutes(totalTodaySeconds)} color="blue" + indicator={timerStartedToday} />