import { copy } from "@/shared/i18n"; import { cn } from "@/shared/lib/cn"; import type { HudStatusLinePayload } from "@/shared/lib/useHudStatusLine"; import { useEffect, useRef, useState } from "react"; import { EndSessionConfirmModal } from "./EndSessionConfirmModal"; import { GoalCompleteSheet } from "./GoalCompleteSheet"; import { InlineMicrostep } from "./InlineMicrostep"; import { ThoughtOrb } from "./ThoughtOrb"; interface SpaceFocusHudWidgetProps { sessionId?: string | null; goal: string; microStep?: string | null; remainingSeconds?: number | null; phaseStartedAt?: string | null; timeDisplay?: string; hasActiveSession?: boolean; playbackState?: "running" | "paused"; sessionPhase?: "focus" | "break" | null; onIntentUpdate: (payload: { goal?: string; microStep?: string | null; }) => boolean | Promise; onGoalUpdate: (nextGoal: string) => boolean | Promise; onGoalCompleteFinish: () => boolean | Promise; onTimerFinish: () => boolean | Promise; onAddTenMinutes: () => boolean | Promise; onStatusMessage: (payload: HudStatusLinePayload) => void; onCaptureThought: (note: string) => void; onExitRequested: () => boolean | Promise; } export const SpaceFocusHudWidget = ({ sessionId = null, goal, microStep, remainingSeconds = null, phaseStartedAt = null, timeDisplay, hasActiveSession = false, playbackState = "paused", sessionPhase = "focus", onIntentUpdate, onGoalUpdate, onGoalCompleteFinish, onTimerFinish, onAddTenMinutes, onStatusMessage, onCaptureThought, onExitRequested, }: SpaceFocusHudWidgetProps) => { const [overlay, setOverlay] = useState<"none" | "end-session" | "timer-complete">("none"); const [isSavingIntent, setSavingIntent] = useState(false); const visibleRef = useRef(false); const timerPromptSignatureRef = useRef(null); const normalizedGoal = goal.trim().length > 0 ? goal.trim() : copy.space.focusHud.goalFallback; const isTimerCompleteOpen = overlay === "timer-complete"; const timerCompletionSignature = hasActiveSession && sessionPhase === "focus" && remainingSeconds === 0 && phaseStartedAt ? `${sessionId ?? "session"}:${phaseStartedAt}` : null; useEffect(() => { if (!hasActiveSession) { setOverlay("none"); setSavingIntent(false); timerPromptSignatureRef.current = null; } }, [hasActiveSession]); useEffect(() => { if (!visibleRef.current && playbackState === "running") { onStatusMessage({ message: copy.space.focusHud.goalToast(normalizedGoal), }); } visibleRef.current = true; }, [normalizedGoal, onStatusMessage, playbackState]); useEffect(() => { if (overlay !== "timer-complete" || timerCompletionSignature) { return; } setOverlay("none"); }, [overlay, timerCompletionSignature]); useEffect(() => { if (!timerCompletionSignature) { return; } if (timerPromptSignatureRef.current === timerCompletionSignature) { return; } timerPromptSignatureRef.current = timerCompletionSignature; setOverlay("timer-complete"); }, [timerCompletionSignature]); const handleInlineMicrostepUpdate = async (nextStep: string | null) => { if (isSavingIntent) return false; setSavingIntent(true); try { const didUpdate = await onIntentUpdate({ microStep: nextStep }); if (didUpdate) { if (nextStep) { onStatusMessage({ message: copy.space.focusHud.refocusSaved }); } else { onStatusMessage({ message: copy.space.focusHud.microStepCleared }); } } return didUpdate; } finally { setSavingIntent(false); } }; return ( <>
{/* The Monolith (Central Hub) */}
{/* Massive Unstoppable Timer */}

{timeDisplay}

{/* Core Intent */}
{/* Immutable Goal */}

{normalizedGoal}

{/* Kinetic Inline Microstep */}
{hasActiveSession && (sessionPhase === "focus" || sessionPhase === "break") && (
)}
setOverlay("none")} onFinish={() => Promise.resolve(onTimerFinish())} onExtendTenMinutes={() => Promise.resolve(onAddTenMinutes())} />
setOverlay("none")} onAdvanceGoal={(nextGoal) => Promise.resolve(onGoalUpdate(nextGoal))} onFinishHere={() => Promise.resolve(onGoalCompleteFinish())} onEndSession={() => Promise.resolve(onExitRequested())} /> ); };