From 6cb006cc136f1fc5c83537cc30c64d223d1755e4 Mon Sep 17 00:00:00 2001 From: Solstice Date: Tue, 9 Jun 2026 00:22:18 -0700 Subject: feat: frontend view, state management, and user interface --- src/hooks/useTimerEvents.ts | 78 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/hooks/useTimerEvents.ts (limited to 'src/hooks') diff --git a/src/hooks/useTimerEvents.ts b/src/hooks/useTimerEvents.ts new file mode 100644 index 0000000..2bc502d --- /dev/null +++ b/src/hooks/useTimerEvents.ts @@ -0,0 +1,78 @@ +import { useEffect } from 'react'; +import { listen } from '@tauri-apps/api/event'; +import { invoke } from '@tauri-apps/api/core'; +import { useTimerStore, TimerTickPayload } from '../store/timerStore'; +import { useTaskStore } from '../store/taskStore'; + +interface PhaseChangedPayload { + phase: TimerTickPayload['phase']; + session_count: number; +} + +interface CompletedPayload { + task_id: string | null; +} + +export function useTimerEvents( + onCompleted: (taskId: string | null) => void, +) { + const setTimerTick = useTimerStore((s) => s.setTimerTick); + const setRunning = useTimerStore((s) => s.setRunning); + const fetchTasks = useTaskStore((s) => s.fetchTasks); + + useEffect(() => { + // Bootstrap initial state from backend + invoke<{ + phase: TimerTickPayload['phase']; + remaining_secs: number; + total_secs: number; + running: boolean; + session_count: number; + current_task_id: string | null; + }>('get_timer_status') + .then((status) => { + setTimerTick({ + phase: status.phase, + remaining_secs: status.remaining_secs, + total_secs: status.total_secs, + session_count: status.session_count, + current_task_id: status.current_task_id, + }); + setRunning(status.running); + }) + .catch((e) => console.error('get_timer_status error:', e)); + + let unlistenTick: (() => void) | null = null; + let unlistenCompleted: (() => void) | null = null; + let unlistenPhaseChanged: (() => void) | null = null; + + listen('timer-tick', (event) => { + setTimerTick(event.payload); + setRunning(true); + }).then((fn) => { unlistenTick = fn; }); + + listen('timer-completed', (event) => { + setRunning(false); + onCompleted(event.payload.task_id); + // Refresh tasks since remaining_sessions may have changed + fetchTasks(); + }).then((fn) => { unlistenCompleted = fn; }); + + listen('timer-phase-changed', (event) => { + setRunning(false); + setTimerTick({ + phase: event.payload.phase, + remaining_secs: useTimerStore.getState().remainingSecs, + total_secs: useTimerStore.getState().totalSecs, + session_count: event.payload.session_count, + current_task_id: useTimerStore.getState().currentTaskId, + }); + }).then((fn) => { unlistenPhaseChanged = fn; }); + + return () => { + unlistenTick?.(); + unlistenCompleted?.(); + unlistenPhaseChanged?.(); + }; + }, [setTimerTick, setRunning, fetchTasks, onCompleted]); +} -- cgit v1.3-2-g0d8e