import { useCallback, useEffect, useRef, useState } from 'react'; import { useReducedMotion } from '@/shared/lib/useReducedMotion'; import { cn } from '@/shared/lib/cn'; import { useToast } from '@/shared/ui'; import { SpaceTimerHudWidget } from '@/widgets/space-timer-hud'; import { GoalCompleteSheet } from './GoalCompleteSheet'; import { GoalFlashOverlay } from './GoalFlashOverlay'; interface SpaceFocusHudWidgetProps { goal: string; timerLabel: string; visible: boolean; onGoalUpdate: (nextGoal: string) => void; } export const SpaceFocusHudWidget = ({ goal, timerLabel, visible, onGoalUpdate, }: SpaceFocusHudWidgetProps) => { const { pushToast } = useToast(); const reducedMotion = useReducedMotion(); const [flashVisible, setFlashVisible] = useState(false); const [sheetOpen, setSheetOpen] = useState(false); const [completePulseVisible, setCompletePulseVisible] = useState(false); const playbackStateRef = useRef<'running' | 'paused'>('running'); const flashTimerRef = useRef(null); const completePulseTimerRef = useRef(null); const triggerFlash = useCallback((durationMs: number) => { if (reducedMotion || !visible) { return; } setFlashVisible(true); if (flashTimerRef.current) { window.clearTimeout(flashTimerRef.current); } flashTimerRef.current = window.setTimeout(() => { setFlashVisible(false); flashTimerRef.current = null; }, durationMs); }, [reducedMotion, visible]); useEffect(() => { return () => { if (flashTimerRef.current) { window.clearTimeout(flashTimerRef.current); flashTimerRef.current = null; } if (completePulseTimerRef.current) { window.clearTimeout(completePulseTimerRef.current); completePulseTimerRef.current = null; } }; }, []); useEffect(() => { if (!visible || reducedMotion) { setFlashVisible(false); return; } triggerFlash(2000); }, [visible, reducedMotion, triggerFlash]); useEffect(() => { const ENABLE_PERIODIC_FLASH = false; if (!visible || reducedMotion || !ENABLE_PERIODIC_FLASH) { return; } const intervalId = window.setInterval(() => { triggerFlash(800); }, 10 * 60 * 1000); return () => { window.clearInterval(intervalId); }; }, [visible, reducedMotion, triggerFlash]); if (!visible) { return null; } const handleOpenCompleteSheet = () => { setCompletePulseVisible(true); if (completePulseTimerRef.current) { window.clearTimeout(completePulseTimerRef.current); } completePulseTimerRef.current = window.setTimeout(() => { setCompletePulseVisible(false); setSheetOpen(true); completePulseTimerRef.current = null; }, 700); }; return ( <>
완료!
{ if (reducedMotion) { playbackStateRef.current = state; return; } if (playbackStateRef.current === 'paused' && state === 'running') { triggerFlash(1000); } playbackStateRef.current = state; }} /> setSheetOpen(false)} onRest={() => { setSheetOpen(false); pushToast({ title: '좋아요, 잠깐 쉬고 다시 이어가요.' }); }} onConfirm={(nextGoal) => { onGoalUpdate(nextGoal); setSheetOpen(false); pushToast({ title: '다음 한 조각으로 이어갑니다.' }); triggerFlash(1200); }} /> ); };