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/store/settingsStore.ts | 33 +++++++++++++++++++ src/store/taskStore.ts | 80 ++++++++++++++++++++++++++++++++++++++++++++++ src/store/timerStore.ts | 42 ++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 src/store/settingsStore.ts create mode 100644 src/store/taskStore.ts create mode 100644 src/store/timerStore.ts (limited to 'src/store') diff --git a/src/store/settingsStore.ts b/src/store/settingsStore.ts new file mode 100644 index 0000000..ea7be34 --- /dev/null +++ b/src/store/settingsStore.ts @@ -0,0 +1,33 @@ +import { create } from 'zustand'; +import { invoke } from '@tauri-apps/api/core'; + +export interface Settings { + work_duration_secs: number; + short_break_secs: number; + long_break_secs: number; + sessions_before_long_break: number; +} + +interface SettingsStore { + settings: Settings | null; + fetchSettings: () => Promise; + updateSettings: (s: Settings) => Promise; +} + +export const useSettingsStore = create((set) => ({ + settings: null, + + fetchSettings: async () => { + try { + const settings = await invoke('get_settings'); + set({ settings }); + } catch (e) { + console.error('fetchSettings error:', e); + } + }, + + updateSettings: async (s) => { + await invoke('update_settings', { settings: s }); + set({ settings: s }); + }, +})); diff --git a/src/store/taskStore.ts b/src/store/taskStore.ts new file mode 100644 index 0000000..dccd17d --- /dev/null +++ b/src/store/taskStore.ts @@ -0,0 +1,80 @@ +import { create } from 'zustand'; +import { invoke } from '@tauri-apps/api/core'; + +export interface Task { + id: string; + name: string; + total_sessions: number; + remaining_sessions: number; + completed: boolean; + created_at: string; +} + +interface TaskStore { + tasks: Task[]; + loading: boolean; + fetchTasks: () => Promise; + addTask: (name: string, totalSessions: number) => Promise; + updateTask: (id: string, remainingSessions?: number, completed?: boolean) => Promise; + deleteTask: (id: string) => Promise; + setCurrentTask: (id: string | null) => Promise; + refreshTask: (task: Task) => void; +} + +export const useTaskStore = create((set) => ({ + tasks: [], + loading: false, + + fetchTasks: async () => { + set({ loading: true }); + try { + const tasks = await invoke('get_tasks'); + set({ tasks, loading: false }); + } catch (e) { + console.error('fetchTasks error:', e); + set({ loading: false }); + } + }, + + addTask: async (name, totalSessions) => { + const task = await invoke('add_task', { + name, + totalSessions, + }); + set((state) => ({ tasks: [...state.tasks, task] })); + }, + + updateTask: async (id, remainingSessions, completed) => { + await invoke('update_task', { + id, + remainingSessions: remainingSessions ?? null, + completed: completed ?? null, + }); + set((state) => ({ + tasks: state.tasks.map((t) => + t.id === id + ? { + ...t, + remaining_sessions: remainingSessions ?? t.remaining_sessions, + completed: completed ?? t.completed, + } + : t, + ), + })); + }, + + deleteTask: async (id) => { + await invoke('delete_task', { id }); + set((state) => ({ tasks: state.tasks.filter((t) => t.id !== id) })); + }, + + setCurrentTask: async (id) => { + await invoke('set_current_task', { taskId: id }); + }, + + refreshTask: (updatedTask) => { + set((state) => ({ + tasks: state.tasks.map((t) => (t.id === updatedTask.id ? updatedTask : t)), + })); + }, +})); diff --git a/src/store/timerStore.ts b/src/store/timerStore.ts new file mode 100644 index 0000000..6a81e20 --- /dev/null +++ b/src/store/timerStore.ts @@ -0,0 +1,42 @@ +import { create } from 'zustand'; + +export type TimerPhase = 'work' | 'short_break' | 'long_break'; + +export interface TimerTickPayload { + phase: TimerPhase; + remaining_secs: number; + total_secs: number; + session_count: number; + current_task_id: string | null; +} + +interface TimerState { + phase: TimerPhase; + remainingSecs: number; + totalSecs: number; + running: boolean; + sessionCount: number; + currentTaskId: string | null; + setTimerTick: (payload: TimerTickPayload) => void; + setRunning: (running: boolean) => void; +} + +export const useTimerStore = create((set) => ({ + phase: 'work', + remainingSecs: 25 * 60, + totalSecs: 25 * 60, + running: false, + sessionCount: 0, + currentTaskId: null, + + setTimerTick: (payload) => + set({ + phase: payload.phase, + remainingSecs: payload.remaining_secs, + totalSecs: payload.total_secs, + sessionCount: payload.session_count, + currentTaskId: payload.current_task_id, + }), + + setRunning: (running) => set({ running }), +})); -- cgit v1.3-2-g0d8e