feat: complete pragativeer v2 frontend and backend, docker setup, and cbt engine
This commit is contained in:
49
src/hooks/useExamTimer.ts
Normal file
49
src/hooks/useExamTimer.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { useEffect, useState, useRef } from 'react';
|
||||
import { useCBTStore } from '@/store/cbtStore';
|
||||
|
||||
export function useExamTimer() {
|
||||
const { startTime, totalDuration, status, submitExam } = useCBTStore();
|
||||
const [timeRemaining, setTimeRemaining] = useState<number>(totalDuration);
|
||||
const frameRef = useRef<number | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (status !== 'IN_PROGRESS' || !startTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
const calculateTime = () => {
|
||||
const now = Date.now();
|
||||
const elapsedSeconds = Math.floor((now - startTime) / 1000);
|
||||
const remaining = Math.max(0, totalDuration - elapsedSeconds);
|
||||
|
||||
setTimeRemaining(remaining);
|
||||
|
||||
if (remaining === 0) {
|
||||
submitExam('TIMED_OUT');
|
||||
} else {
|
||||
// Use requestAnimationFrame for a high-performance loop instead of setInterval
|
||||
// We throttle updates to when the second actually changes
|
||||
frameRef.current = requestAnimationFrame(calculateTime);
|
||||
}
|
||||
};
|
||||
|
||||
frameRef.current = requestAnimationFrame(calculateTime);
|
||||
|
||||
return () => {
|
||||
if (frameRef.current) cancelAnimationFrame(frameRef.current);
|
||||
};
|
||||
}, [startTime, totalDuration, status, submitExam]);
|
||||
|
||||
// Format HH:MM:SS
|
||||
const hours = Math.floor(timeRemaining / 3600);
|
||||
const minutes = Math.floor((timeRemaining % 3600) / 60);
|
||||
const seconds = timeRemaining % 60;
|
||||
|
||||
const formattedTime = [
|
||||
hours.toString().padStart(2, '0'),
|
||||
minutes.toString().padStart(2, '0'),
|
||||
seconds.toString().padStart(2, '0'),
|
||||
].join(':');
|
||||
|
||||
return { timeRemaining, formattedTime, isTimedOut: timeRemaining === 0 };
|
||||
}
|
||||
Reference in New Issue
Block a user