diff --git a/apps/dashboard/src/components/tracker-timer.tsx b/apps/dashboard/src/components/tracker-timer.tsx index 88e2a25c69..d25e2eb5e0 100644 --- a/apps/dashboard/src/components/tracker-timer.tsx +++ b/apps/dashboard/src/components/tracker-timer.tsx @@ -10,7 +10,7 @@ import { import { useToast } from "@midday/ui/use-toast"; import NumberFlow from "@number-flow/react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { useCallback, useMemo, useRef } from "react"; import { useGlobalTimerStatus } from "@/hooks/use-global-timer-status"; import { useTimerStore } from "@/store/timer"; import { useTRPC } from "@/trpc/client"; @@ -39,12 +39,8 @@ export function TrackerTimer({ const { isRunning: globalIsRunning, elapsedTime: globalElapsedTime } = useGlobalTimerStatus(); - // Hold-to-stop state - const [isHolding, setIsHolding] = useState(false); - const [holdProgress, setHoldProgress] = useState(0); - const holdTimerRef = useRef(null); - const holdProgressRef = useRef(null); - const holdInitialStateRef = useRef(false); // Store initial isThisProjectRunning state when hold starts + // Prevents accidental restart if a stale refetch briefly flips isThisProjectRunning back to true + const justStoppedRef = useRef(false); // Get current timer status - reduced refetch frequency const { data: timerStatus } = useQuery({ @@ -197,58 +193,6 @@ export function TrackerTimer({ }), ); - // Hold-to-stop handlers - const startHolding = useCallback(() => { - // Capture the initial state to prevent issues if refetch occurs during hold - const initialIsRunning = isThisProjectRunning; - if (!initialIsRunning) return; - - // Store the initial state for use throughout the hold operation - holdInitialStateRef.current = initialIsRunning; - - setIsHolding(true); - setHoldProgress(0); - - // Start progress animation - let progress = 0; - holdProgressRef.current = setInterval(() => { - progress += 100 / 15; // 15 steps over 1.5 seconds = 100ms intervals - setHoldProgress(Math.min(progress, 100)); - }, 100); - - // Execute stop after 1.5 seconds - use stored initial state - holdTimerRef.current = setTimeout(() => { - // Only stop if the initial state was running (prevent stop if state changed during hold) - if (holdInitialStateRef.current) { - stopTimerMutation.mutate({}); - } - resetHold(); - }, 1500); - }, [isThisProjectRunning, stopTimerMutation]); - - const resetHold = useCallback(() => { - setIsHolding(false); - setHoldProgress(0); - holdInitialStateRef.current = false; // Reset initial state - - if (holdTimerRef.current) { - clearTimeout(holdTimerRef.current); - holdTimerRef.current = null; - } - - if (holdProgressRef.current) { - clearInterval(holdProgressRef.current); - holdProgressRef.current = null; - } - }, []); - - // Cleanup hold timers on unmount - useEffect(() => { - return () => { - resetHold(); - }; - }, [resetHold]); - const formatTime = useCallback((seconds: number) => { const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); @@ -263,28 +207,35 @@ export function TrackerTimer({ }, []); const handleButtonClick = useCallback(() => { - if (!isThisProjectRunning) { - // Check if there's a different timer running - if (isDifferentTimerRunning) { - const currentProjectName = - timerStatus?.currentEntry?.trackerProject?.name || "Unknown Project"; - toast({ - title: "Timer already running", - description: `You have a timer running for "${currentProjectName}". Please stop it first before starting a new timer.`, - }); - return; - } + if (isThisProjectRunning) { + justStoppedRef.current = true; + stopTimerMutation.mutate({}); + setTimeout(() => { + justStoppedRef.current = false; + }, 500); + return; + } - // Start timer for this project - startTimerMutation.mutate({ - projectId, + if (justStoppedRef.current) return; + + if (isDifferentTimerRunning) { + const currentProjectName = + timerStatus?.currentEntry?.trackerProject?.name || "Unknown Project"; + toast({ + title: "Timer already running", + description: `You have a timer running for "${currentProjectName}". Please stop it first before starting a new timer.`, }); + return; } - // For stop, we only use hold-to-stop, so no immediate action + + startTimerMutation.mutate({ + projectId, + }); }, [ isThisProjectRunning, isDifferentTimerRunning, startTimerMutation, + stopTimerMutation, projectId, timerStatus?.currentEntry?.trackerProject?.name, toast, @@ -315,30 +266,6 @@ export function TrackerTimer({ e.stopPropagation(); handleButtonClick(); }} - onMouseDown={(e) => { - e.stopPropagation(); - if (isThisProjectRunning) { - startHolding(); - } - }} - onMouseUp={(e) => { - e.stopPropagation(); - resetHold(); - }} - onMouseLeave={(e) => { - e.stopPropagation(); - resetHold(); - }} - onTouchStart={(e) => { - e.stopPropagation(); - if (isThisProjectRunning) { - startHolding(); - } - }} - onTouchEnd={(e) => { - e.stopPropagation(); - resetHold(); - }} > {isThisProjectRunning ? ( @@ -353,44 +280,11 @@ export function TrackerTimer({ sideOffset={5} className="text-xs px-2 py-1 text-[#878787]" > -

Hold down to stop

+

Stop timer

)} - - {/* Circular Progress Bar */} - {isHolding && isThisProjectRunning && ( - - - - - )}