import { useEffect, useRef } from 'react'; import { listen } from '@tauri-apps/api/event'; 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 syncFromBackend = useTimerStore((s) => s.syncFromBackend); const setRunning = useTimerStore((s) => s.setRunning); const fetchTasks = useTaskStore((s) => s.fetchTasks); const onCompletedRef = useRef(onCompleted); useEffect(() => { onCompletedRef.current = onCompleted; }, [onCompleted]); useEffect(() => { let cancelled = false; let unlisteners: Array<() => void> = []; async function setup() { // Register all listeners atomically try { const [unlistenTick, unlistenCompleted, unlistenPhaseChanged] = await Promise.all([ listen('timer-tick', (event) => { useTimerStore.setState({ phase: event.payload.phase, remainingSecs: event.payload.remaining_secs, totalSecs: event.payload.total_secs, running: true, sessionCount: event.payload.session_count, currentTaskId: event.payload.current_task_id, }); }), listen('timer-completed', async (event) => { setRunning(false); onCompletedRef.current(event.payload.task_id ?? null); await fetchTasks(); await syncFromBackend(); }), listen('timer-phase-changed', async (_event) => { try { await syncFromBackend(); } catch (e) { console.error('Failed to re-sync timer status:', e); } }), ]); if (cancelled) { unlistenTick(); unlistenCompleted(); unlistenPhaseChanged(); return; } unlisteners = [unlistenTick, unlistenCompleted, unlistenPhaseChanged]; try { await syncFromBackend(); } catch (e) { console.error('Failed to get timer status:', e); } } catch (e) { console.error('Failed to register timer listeners:', e); } } setup(); return () => { cancelled = true; unlisteners.forEach((fn) => fn()); }; }, [syncFromBackend, setRunning, fetchTasks]); // onCompleted excluded — updated via ref }