summaryrefslogtreecommitdiff
path: root/src/hooks
diff options
context:
space:
mode:
authorSolstice <solstice@local>2026-06-09 00:22:18 -0700
committerSolstice <solstice@local>2026-06-09 00:22:18 -0700
commit6cb006cc136f1fc5c83537cc30c64d223d1755e4 (patch)
treeb12dfb4a8345c980dc8747657ce381016cdf3b34 /src/hooks
parent25e1dcf205cd14feafdd9b4cf6b7a66f253ba6d2 (diff)
feat: frontend view, state management, and user interface
Diffstat (limited to 'src/hooks')
-rw-r--r--src/hooks/useTimerEvents.ts78
1 files changed, 78 insertions, 0 deletions
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<TimerTickPayload>('timer-tick', (event) => {
+ setTimerTick(event.payload);
+ setRunning(true);
+ }).then((fn) => { unlistenTick = fn; });
+
+ listen<CompletedPayload>('timer-completed', (event) => {
+ setRunning(false);
+ onCompleted(event.payload.task_id);
+ // Refresh tasks since remaining_sessions may have changed
+ fetchTasks();
+ }).then((fn) => { unlistenCompleted = fn; });
+
+ listen<PhaseChangedPayload>('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]);
+}