diff --git a/apps/frontend/src/blocks/QuizZone/QuizInProgress.tsx b/apps/frontend/src/blocks/QuizZone/QuizInProgress.tsx index 7c5d726a1..0c327c48b 100644 --- a/apps/frontend/src/blocks/QuizZone/QuizInProgress.tsx +++ b/apps/frontend/src/blocks/QuizZone/QuizInProgress.tsx @@ -19,10 +19,11 @@ const QuizInProgress = ({ currentQuiz, submitAnswer }: QuizInProgressProps) => { const MAX_TEXT_LENGTH = 100; const MIN_TEXT_LENGTH = 1; - const playTime = currentQuiz.playTime; + const now = new Date().getTime(); + const { playTime, deadlineTime } = currentQuiz; const { start, time } = useTimer({ - initialTime: playTime / 1000, + initialTime: (deadlineTime - now) / 1000, onComplete: () => {}, }); diff --git a/apps/frontend/src/hook/useTimer.ts b/apps/frontend/src/hook/useTimer.ts index 3b0c41880..13ba22dd7 100644 --- a/apps/frontend/src/hook/useTimer.ts +++ b/apps/frontend/src/hook/useTimer.ts @@ -1,5 +1,4 @@ -import { useCallback, useEffect, useRef, useState } from 'react'; -import TimerWorker from '@/workers/timer.worker?worker'; +import { useState, useEffect, useCallback } from 'react'; interface TimerConfig { initialTime: number; @@ -8,85 +7,67 @@ interface TimerConfig { } /** - * Web Worker를 활용한 정확한 카운트다운 타이머 커스텀 훅 + * 카운트다운 타이머를 관리하는 커스텀 훅입니다. + * + * @description + * 이 훅은 시작 제어 기능을 갖춘 카운트다운 타이머 기능을 제공합니다. + * 초기 시간과 타이머 완료 시 실행될 선택적 콜백을 받습니다. + * + * @example + * ```typescript + * const { time, start } = useTimer({ + * initialTime: 60, + * onComplete: () => console.log('타이머 완료!'), + * }); + * + * // 타이머 시작 + * start(); + * ``` * * @param {TimerConfig} config - 타이머 설정 객체 - * @returns {object} 타이머 상태와 컨트롤 함수들 + * @param {number} config.initialTime - 카운트다운 초기 시간(초 단위) + * @param {() => void} [config.onComplete] - 타이머 완료 시 실행될 선택적 콜백 + * + * @returns {object} 현재 시간과 시작 함수를 포함하는 객체 + * @returns {number} returns.time - 카운트다운의 현재 시간 + * @returns {() => void} returns.start - 타이머를 시작하는 함수 */ + export const useTimer = ({ initialTime, onComplete }: TimerConfig) => { const [time, setTime] = useState(initialTime); const [isRunning, setIsRunning] = useState(false); - const workerRef = useRef(null); useEffect(() => { - // Worker가 이미 존재하면 종료 - if (workerRef.current) { - workerRef.current.terminate(); - } - - // 새 Worker 생성 - workerRef.current = new TimerWorker(); + let timer: NodeJS.Timeout | null = null; - // Worker 메시지 핸들러 - workerRef.current.onmessage = (event) => { - const { type, payload } = event.data; - // console.log('Received from worker:', type, payload); // 디버깅용 - - switch (type) { - case 'TICK': - setTime(payload.time); - break; - case 'COMPLETE': - setTime(0); - setIsRunning(false); - onComplete?.(); - break; - } - }; + if (isRunning) { + timer = setInterval(() => { + setTime((prev) => { + const nextTime = prev - 0.1; + if (nextTime <= 0) { + setIsRunning(false); + onComplete?.(); + return 0; + } + return nextTime; + }); + }, 100); + } - // Clean up return () => { - workerRef.current?.terminate(); + if (timer) { + clearInterval(timer); + } }; - }, []); + }, [isRunning, onComplete]); - // 타이머 시작 const start = useCallback(() => { - if (isRunning || !workerRef.current) return; - - workerRef.current.postMessage({ - type: 'START', - payload: { - duration: initialTime, - serverTime: Date.now(), - }, - }); - + if (isRunning) return; setIsRunning(true); - }, [isRunning, initialTime]); - - // 타이머 정지 - const stop = useCallback(() => { - if (!isRunning || !workerRef.current) return; - - workerRef.current.postMessage({ type: 'STOP' }); - setIsRunning(false); }, [isRunning]); - // 타이머 리셋 - const reset = useCallback(() => { - if (!workerRef.current) return; - - workerRef.current.postMessage({ type: 'RESET' }); - setTime(initialTime); - setIsRunning(false); - }, [initialTime]); - return { time, - isRunning, start, - stop, - reset, }; };