diff --git a/src/components/PomodoroTimer.tsx b/src/components/PomodoroTimer.tsx index 9f829f5..7d4ec9e 100644 --- a/src/components/PomodoroTimer.tsx +++ b/src/components/PomodoroTimer.tsx @@ -37,6 +37,10 @@ export function PomodoroTimer({ onStateChange }: PomodoroTimerProps = {}) { const saved = localStorage.getItem('pomodoroSessionsCompleted'); return saved ? parseInt(saved) : 0; }); + const [endTime, setEndTime] = useState(() => { + const saved = localStorage.getItem('pomodoroEndTime'); + return saved ? parseInt(saved) : null; + }); const intervalRef = useRef(null); // Save state to localStorage whenever it changes and dispatch custom event @@ -60,6 +64,15 @@ export function PomodoroTimer({ onStateChange }: PomodoroTimerProps = {}) { window.dispatchEvent(new CustomEvent('pomodoroStateChange')); }, [sessionsCompleted]); + useEffect(() => { + if (endTime !== null) { + localStorage.setItem('pomodoroEndTime', endTime.toString()); + } else { + localStorage.removeItem('pomodoroEndTime'); + } + window.dispatchEvent(new CustomEvent('pomodoroStateChange')); + }, [endTime]); + // Listen for localStorage changes from other instances useEffect(() => { const handleStorageChange = () => { @@ -67,6 +80,7 @@ export function PomodoroTimer({ onStateChange }: PomodoroTimerProps = {}) { const savedTimeLeft = localStorage.getItem('pomodoroTimeLeft'); const savedIsRunning = localStorage.getItem('pomodoroIsRunning'); const savedSessions = localStorage.getItem('pomodoroSessionsCompleted'); + const savedEndTime = localStorage.getItem('pomodoroEndTime'); if (savedMode && savedMode !== mode) { setMode(savedMode); @@ -80,11 +94,15 @@ export function PomodoroTimer({ onStateChange }: PomodoroTimerProps = {}) { if (savedSessions && parseInt(savedSessions) !== sessionsCompleted) { setSessionsCompleted(parseInt(savedSessions)); } + const newEndTime = savedEndTime ? parseInt(savedEndTime) : null; + if (newEndTime !== endTime) { + setEndTime(newEndTime); + } }; window.addEventListener('pomodoroStateChange', handleStorageChange); return () => window.removeEventListener('pomodoroStateChange', handleStorageChange); - }, [mode, timeLeft, isRunning, sessionsCompleted]); + }, [mode, timeLeft, isRunning, sessionsCompleted, endTime]); // Function to play notification sound using Web Audio API const playNotificationSound = () => { @@ -137,6 +155,7 @@ export function PomodoroTimer({ onStateChange }: PomodoroTimerProps = {}) { const handleTimerComplete = useCallback(() => { setIsRunning(false); + setEndTime(null); // Play notification sound playNotificationSound(); @@ -163,18 +182,19 @@ export function PomodoroTimer({ onStateChange }: PomodoroTimerProps = {}) { } }, [mode, sessionsCompleted]); - // Manage timer interval + // Manage timer interval - using timestamps for accuracy across tab switches useEffect(() => { - if (isRunning) { + if (isRunning && endTime) { intervalRef.current = setInterval(() => { - setTimeLeft(prev => { - if (prev <= 1) { - handleTimerComplete(); - return 0; - } - return prev - 1; - }); - }, 1000); + const now = Date.now(); + const remaining = Math.max(0, Math.ceil((endTime - now) / 1000)); + + setTimeLeft(remaining); + + if (remaining <= 0) { + handleTimerComplete(); + } + }, 100); // Check every 100ms for better accuracy } else { if (intervalRef.current) { clearInterval(intervalRef.current); @@ -188,18 +208,24 @@ export function PomodoroTimer({ onStateChange }: PomodoroTimerProps = {}) { intervalRef.current = null; } }; - }, [isRunning, handleTimerComplete]); + }, [isRunning, endTime, handleTimerComplete]); const handleStart = () => { + const now = Date.now(); + const newEndTime = now + (timeLeft * 1000); + setEndTime(newEndTime); setIsRunning(true); }; const handlePause = () => { setIsRunning(false); + setEndTime(null); + // timeLeft is already updated by the interval }; const handleReset = () => { setIsRunning(false); + setEndTime(null); setTimeLeft(TIMER_DURATIONS[mode]); }; @@ -207,6 +233,7 @@ export function PomodoroTimer({ onStateChange }: PomodoroTimerProps = {}) { setMode(newMode); setTimeLeft(TIMER_DURATIONS[newMode]); setIsRunning(false); + setEndTime(null); }; const formatTime = (seconds: number): string => {