import React, { useState, useEffect } from 'react' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { api } from '../lib/api' import { Loader2, Play, Square, ExternalLink } from 'lucide-react' export const ActiveTimer = () => { const queryClient = useQueryClient() const [description, setDescription] = useState('') const [isInputVisible, setIsInputVisible] = useState(false) const [elapsed, setElapsed] = useState(0) const { data: runningEntry, isLoading } = useQuery({ queryKey: ['running-entry'], queryFn: () => api.getRunningTimeEntry(), refetchInterval: 30000, }) const startMutation = useMutation({ mutationFn: (desc: string) => api.createTimeEntry({ description, startTime: new Date().toISOString() }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['running-entry'] }) setIsInputVisible(false) setDescription('') }, }) const stopMutation = useMutation({ mutationFn: (id: string) => api.stopTimeEntry(id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['running-entry'] }) }, }) useEffect(() => { let interval: NodeJS.Timeout if (runningEntry?.startTime) { const update = () => { const start = new Date(runningEntry.startTime).getTime() const now = Date.now() setElapsed(Math.floor((now - start) / 1000)) } update() interval = setInterval(update, 1000) } else { setElapsed(0) } return () => clearInterval(interval) }, [runningEntry]) const formatTime = (seconds: number) => { const h = Math.floor(seconds / 3600) const m = Math.floor((seconds % 3600) / 60) const s = seconds % 60 return h > 0 ? `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}` : `${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}` } const handlePopout = () => { window.open('/tracker-popout', 'tracker', 'width=320,height=220') } if (isLoading) return
if (runningEntry) { return (
{runningEntry.description || 'No description'} {formatTime(elapsed)}
) } return (
{isInputVisible && ( setDescription(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && startMutation.mutate(description)} /> )}
) } export const PopoutTrackerView = () => { const queryClient = useQueryClient() const [description, setDescription] = useState('') const [isInputVisible, setIsInputVisible] = useState(false) const [elapsed, setElapsed] = useState(0) const { data: runningEntry, isLoading } = useQuery({ queryKey: ['running-entry'], queryFn: () => api.getRunningTimeEntry(), refetchInterval: 10000, }) const startMutation = useMutation({ mutationFn: (desc: string) => api.createTimeEntry({ description, startTime: new Date().toISOString() }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['running-entry'] }) setIsInputVisible(false) setDescription('') }, }) const stopMutation = useMutation({ mutationFn: (id: string) => api.stopTimeEntry(id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['running-entry'] }) }, }) useEffect(() => { let interval: NodeJS.Timeout if (runningEntry?.startTime) { const update = () => { const start = new Date(runningEntry.startTime).getTime() const now = Date.now() setElapsed(Math.floor((now - start) / 1000)) } update() interval = setInterval(update, 1000) } else { setElapsed(0) } return () => clearInterval(interval) }, [runningEntry]) const formatTime = (seconds: number) => { const h = Math.floor(seconds / 3600) const m = Math.floor((seconds % 3600) / 60) const s = seconds % 60 return h > 0 ? `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}` : `${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}` } if (isLoading) return
return (
{runningEntry ? ( <>
{runningEntry.description || 'No description'}
{formatTime(elapsed)}
) : ( <>
No active timer
{isInputVisible ? (
setDescription(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && startMutation.mutate(description)} />
) : ( )} )}
) }