import { createSignal, createEffect, onMount } from 'solid-js'; import { IconClock, IconActivity, IconCurrencyDollar } from '@tabler/icons-solidjs'; import { useHaptics } from '@/lib/haptics'; import { Button } from '@/components/ui/Button'; import { Card } from '@/components/ui/Card'; import { Badge } from '@/components/ui/badge'; import { LoadingState } from '@/components/ui/LoadingState'; import { solidtimeApi } from '@/lib/solidtime-api'; export const TimeTracking = () => { const haptics = useHaptics(); const [loading, setLoading] = createSignal(true); const [timeEntries, setTimeEntries] = createSignal([]); const [currentRunningEntry, setCurrentRunningEntry] = createSignal(null); const [elapsedSeconds, setElapsedSeconds] = createSignal(0); const [stats, setStats] = createSignal({ total: 0, billable: 0, nonBillable: 0 }); let timerInterval: ReturnType | null = null; const loadData = async () => { try { setLoading(true); const entries = await solidtimeApi.getTimeEntries(); setTimeEntries(entries); const active = await solidtimeApi.getActiveTimeEntry(); setCurrentRunningEntry(active); if (active) { const start = new Date(active.start).getTime(); const now = Date.now(); setElapsedSeconds(Math.floor((now - start) / 1000)); } else { setElapsedSeconds(0); } const stats = await solidtimeApi.getTimeEntriesStats(); setStats(stats); } catch (err) { console.error('Failed to load time entries:', err); } finally { setLoading(false); } }; const startTimer = async () => { try { const entry = await solidtimeApi.startTimeEntry({ description: 'Working on Trackeep', }); setCurrentRunningEntry(entry); setElapsedSeconds(0); haptics.impact(); loadData(); } catch (err) { console.error('Failed to start timer:', err); } }; const stopTimer = async () => { if (!currentRunningEntry()) return; try { await solidtimeApi.stopTimeEntry(currentRunningEntry().id); setCurrentRunningEntry(null); setElapsedSeconds(0); haptics.selection(); loadData(); } catch (err) { console.error('Failed to stop timer:', err); } }; const formatTime = (seconds: number) => { const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); const secs = seconds % 60; return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; }; const formatDuration = (start: string, end?: string) => { const startTime = new Date(start).getTime(); const endTime = end ? new Date(end).getTime() : Date.now(); const diff = Math.floor((endTime - startTime) / 1000); return formatTime(diff); }; onMount(() => { loadData(); }); createEffect(() => { if (currentRunningEntry()) { timerInterval = setInterval(() => { setElapsedSeconds(s => s + 1); }, 1000); } else { if (timerInterval) { clearInterval(timerInterval); timerInterval = null; } } return () => { if (timerInterval) clearInterval(timerInterval); }; }); return (

Time Tracking

Track your time with solidtime.io integration

{currentRunningEntry() ? 'Timer Running' : 'Ready to Track'}

{currentRunningEntry() ? currentRunningEntry().description || 'No description' : 'Start tracking your time'}

{formatTime(elapsedSeconds())}
{currentRunningEntry() ? 'Running' : 'Stopped'}
{!currentRunningEntry() ? ( ) : ( )}

Total Today

{formatTime(stats().total)}

Billable

{formatTime(stats().billable)}

Non-Billable

{formatTime(stats().nonBillable)}

Recent Time Entries

{loading() ? ( ) : timeEntries().length === 0 ? (

No time entries yet

Start tracking your time to see entries here

) : (
{timeEntries().map((entry) => (

{entry.description || 'Untitled'}

{new Date(entry.start).toLocaleString()}

{entry.billable ? 'Billable' : 'Non-Billable'} {formatDuration(entry.start, entry.end)}
))}
)}
); };