mirror of
https://github.com/R0m1k3/noteflow.git
synced 2026-10-11 17:29:37 +02:00
Merge pull request #150 from R0m1k3/claude/fix-pomodoro-tab-switch-01WFQEsfPro5ynAgg4VAU3EV
fix: permettre au timer Pomodoro de continuer en arrière-plan
This commit is contained in:
1 file changed
+39
-12
@@ -37,6 +37,10 @@ export function PomodoroTimer({ onStateChange }: PomodoroTimerProps = {}) {
|
||||
const saved = localStorage.getItem('pomodoroSessionsCompleted');
|
||||
return saved ? parseInt(saved) : 0;
|
||||
});
|
||||
const [endTime, setEndTime] = useState<number | null>(() => {
|
||||
const saved = localStorage.getItem('pomodoroEndTime');
|
||||
return saved ? parseInt(saved) : null;
|
||||
});
|
||||
const intervalRef = useRef<NodeJS.Timeout | null>(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 => {
|
||||
|
||||
Reference in new issue
Block a user