diff --git a/frontend/src/components/TimerWidget.tsx b/frontend/src/components/TimerWidget.tsx index 3a40bff..1717eda 100644 --- a/frontend/src/components/TimerWidget.tsx +++ b/frontend/src/components/TimerWidget.tsx @@ -1,12 +1,41 @@ -import { useState } from 'react'; -import { Play, Square, ChevronDown } from 'lucide-react'; -import { useTimer } from '@/contexts/TimerContext'; -import { useProjects } from '@/hooks/useProjects'; -import { formatDuration } from '@/utils/dateUtils'; -import { ProjectColorDot } from '@/components/ProjectColorDot'; +import { useState } from "react"; +import { Play, Square, ChevronDown } from "lucide-react"; +import { useTimer } from "@/contexts/TimerContext"; +import { useProjects } from "@/hooks/useProjects"; +import { ProjectColorDot } from "@/components/ProjectColorDot"; + +function TimerDisplay({ totalSeconds }: { totalSeconds: number }) { + const hours = Math.floor(totalSeconds / 3600); + const minutes = Math.floor((totalSeconds % 3600) / 60); + const seconds = totalSeconds % 60; + + const pad = (n: number) => n.toString().padStart(2, "0"); + + return ( + + {hours > 0 && ( + <> + {pad(hours)} + h + + )} + {pad(minutes)} + m + {pad(seconds)} + s + + ); +} export function TimerWidget() { - const { ongoingTimer, isLoading, elapsedSeconds, startTimer, stopTimer, updateTimerProject } = useTimer(); + const { + ongoingTimer, + isLoading, + elapsedSeconds, + startTimer, + stopTimer, + updateTimerProject, + } = useTimer(); const { projects } = useProjects(); const [showProjectSelect, setShowProjectSelect] = useState(false); const [error, setError] = useState(null); @@ -16,7 +45,7 @@ export function TimerWidget() { try { await startTimer(); } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to start timer'); + setError(err instanceof Error ? err.message : "Failed to start timer"); } }; @@ -25,7 +54,7 @@ export function TimerWidget() { try { await stopTimer(); } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to stop timer'); + setError(err instanceof Error ? err.message : "Failed to stop timer"); } }; @@ -35,7 +64,7 @@ export function TimerWidget() { await updateTimerProject(projectId); setShowProjectSelect(false); } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to update project'); + setError(err instanceof Error ? err.message : "Failed to update project"); } }; @@ -45,7 +74,7 @@ export function TimerWidget() { await updateTimerProject(null); setShowProjectSelect(false); } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to clear project'); + setError(err instanceof Error ? err.message : "Failed to clear project"); } }; @@ -68,9 +97,7 @@ export function TimerWidget() {
- - {formatDuration(elapsedSeconds)} - +
{/* Project Selector */} @@ -110,8 +137,12 @@ export function TimerWidget() { >
-
{project.name}
-
{project.client.name}
+
+ {project.name} +
+
+ {project.client.name} +
))} @@ -155,4 +186,4 @@ export function TimerWidget() { )}
); -} \ No newline at end of file +} diff --git a/frontend/src/pages/DashboardPage.tsx b/frontend/src/pages/DashboardPage.tsx index 118189f..88263af 100644 --- a/frontend/src/pages/DashboardPage.tsx +++ b/frontend/src/pages/DashboardPage.tsx @@ -5,7 +5,7 @@ import { ProjectColorDot } from "@/components/ProjectColorDot"; import { StatCard } from "@/components/StatCard"; import { formatDate, - formatDurationFromDates, + formatDurationFromDatesHoursMinutes, formatDurationHoursMinutes, calculateDuration, } from "@/utils/dateUtils"; @@ -123,8 +123,8 @@ export function DashboardPage() { {formatDate(entry.startTime)} - - {formatDurationFromDates(entry.startTime, entry.endTime)} + + {formatDurationFromDatesHoursMinutes(entry.startTime, entry.endTime)} ))} diff --git a/frontend/src/pages/StatisticsPage.tsx b/frontend/src/pages/StatisticsPage.tsx index 577ec68..61528bc 100644 --- a/frontend/src/pages/StatisticsPage.tsx +++ b/frontend/src/pages/StatisticsPage.tsx @@ -10,7 +10,7 @@ import { useStatistics } from "@/hooks/useTimeEntries"; import { useClients } from "@/hooks/useClients"; import { useProjects } from "@/hooks/useProjects"; import { ProjectColorDot } from "@/components/ProjectColorDot"; -import { formatDuration, toISOTimezone } from "@/utils/dateUtils"; +import { formatDurationHoursMinutes, toISOTimezone } from "@/utils/dateUtils"; import type { StatisticsFilters } from "@/types"; export function StatisticsPage() { @@ -166,7 +166,7 @@ export function StatisticsPage() { {isLoading ? ( Loading... ) : ( - formatDuration(statistics?.totalSeconds || 0) + formatDurationHoursMinutes(statistics?.totalSeconds || 0) )}

@@ -202,7 +202,7 @@ export function StatisticsPage() { - {formatDuration(project.totalSeconds)} + {formatDurationHoursMinutes(project.totalSeconds)} ))} @@ -232,7 +232,7 @@ export function StatisticsPage() { - {formatDuration(client.totalSeconds)} + {formatDurationHoursMinutes(client.totalSeconds)} ))} diff --git a/frontend/src/pages/TimeEntriesPage.tsx b/frontend/src/pages/TimeEntriesPage.tsx index 3ecc024..5847ad4 100644 --- a/frontend/src/pages/TimeEntriesPage.tsx +++ b/frontend/src/pages/TimeEntriesPage.tsx @@ -5,7 +5,7 @@ import { useProjects } from '@/hooks/useProjects'; import { Modal } from '@/components/Modal'; import { Spinner } from '@/components/Spinner'; import { ProjectColorDot } from '@/components/ProjectColorDot'; -import { formatDate, formatDurationFromDates, getLocalISOString, toISOTimezone } from '@/utils/dateUtils'; +import { formatDate, formatDurationFromDatesHoursMinutes, getLocalISOString, toISOTimezone } from '@/utils/dateUtils'; import type { TimeEntry, CreateTimeEntryInput, UpdateTimeEntryInput } from '@/types'; export function TimeEntriesPage() { @@ -127,7 +127,7 @@ export function TimeEntriesPage() { - {formatDurationFromDates(entry.startTime, entry.endTime)} + {formatDurationFromDatesHoursMinutes(entry.startTime, entry.endTime)} diff --git a/frontend/src/utils/dateUtils.ts b/frontend/src/utils/dateUtils.ts index 3074c8a..6ba8522 100644 --- a/frontend/src/utils/dateUtils.ts +++ b/frontend/src/utils/dateUtils.ts @@ -57,6 +57,14 @@ export function formatDurationFromDates( return formatDuration(seconds); } +export function formatDurationFromDatesHoursMinutes( + startTime: string, + endTime: string, +): string { + const seconds = calculateDuration(startTime, endTime); + return formatDurationHoursMinutes(seconds); +} + export function getLocalISOString(date: Date = new Date()): string { const timezoneOffset = date.getTimezoneOffset() * 60000; const localISOTime = new Date(date.getTime() - timezoneOffset)