From 0c8a28508b118120032f3b4c4cff0f1de5780f1a Mon Sep 17 00:00:00 2001 From: krokerdile Date: Thu, 5 Dec 2024 21:46:52 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20webWorker=20=EC=9D=B4=EC=8A=88?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B8=ED=95=B4=20=EA=B8=B0=EC=A1=B4=20useTimer?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=B5=EA=B5=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/frontend/src/hook/useTimer.ts | 105 ++++++++++++----------------- 1 file changed, 43 insertions(+), 62 deletions(-) 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, }; }; From 073105f7ecef89c7334a2363dc0f652258b7f27b Mon Sep 17 00:00:00 2001 From: krokerdile Date: Thu, 5 Dec 2024 21:47:19 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20progress=20=EB=B0=94=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=20=EC=8B=9C=20=EC=B4=88=EA=B8=B0=ED=99=94=20=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/frontend/src/blocks/QuizZone/QuizInProgress.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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: () => {}, });