sozsoft-platform/ui/src/utils/hooks/useExamTimer.ts

94 lines
2.2 KiB
TypeScript
Raw Normal View History

2026-02-24 20:44:16 +00:00
import { useState, useEffect, useCallback } from 'react';
interface UseExamTimerProps {
initialTime: number; // in seconds
onTimeUp?: () => void;
onTick?: (timeRemaining: number) => void;
autoStart?: boolean;
}
export const useExamTimer = ({
initialTime,
onTimeUp,
onTick,
autoStart = false
}: UseExamTimerProps) => {
const [timeRemaining, setTimeRemaining] = useState(initialTime);
const [isRunning, setIsRunning] = useState(autoStart);
const [isPaused, setIsPaused] = useState(false);
const start = useCallback(() => {
setIsRunning(true);
setIsPaused(false);
}, []);
const pause = useCallback(() => {
setIsPaused(true);
}, []);
const resume = useCallback(() => {
setIsPaused(false);
}, []);
const reset = useCallback(() => {
setTimeRemaining(initialTime);
setIsRunning(false);
setIsPaused(false);
}, [initialTime]);
const stop = useCallback(() => {
setIsRunning(false);
setIsPaused(false);
}, []);
useEffect(() => {
let interval: ReturnType<typeof setInterval>;
2026-02-24 20:44:16 +00:00
if (isRunning && !isPaused && timeRemaining > 0) {
interval = setInterval(() => {
setTimeRemaining((prev) => {
const newTime = prev - 1;
onTick?.(newTime);
if (newTime <= 0) {
setIsRunning(false);
onTimeUp?.();
return 0;
}
return newTime;
});
}, 1000);
}
return () => {
if (interval) {
clearInterval(interval);
}
};
}, [isRunning, isPaused, timeRemaining, onTimeUp, onTick]);
const formatTime = useCallback((seconds: number) => {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const secs = seconds % 60;
if (hours > 0) {
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
}
return `${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
}, []);
return {
timeRemaining,
formattedTime: formatTime(timeRemaining),
isRunning,
isPaused,
start,
pause,
resume,
reset,
stop,
progress: ((initialTime - timeRemaining) / initialTime) * 100
};
};