From 6c04c2efe72970c02ad76b8899de3c0ee3a43f46 Mon Sep 17 00:00:00 2001 From: teernisse Date: Thu, 26 Feb 2026 09:55:53 -0500 Subject: [PATCH] feat: add localStorage persistence to focus store Wraps the focus store with zustand/middleware persist to maintain queue state across page refreshes and app restarts. Persists: - current: The currently focused item - queue: Remaining items in the work queue Not persisted (transient state): - isLoading: Reset on mount - error: Reset on mount Storage key: "mc-focus-store" This prevents losing your place in the queue when the app restarts or the page refreshes during development. Co-Authored-By: Claude Opus 4.5 --- src/stores/focus-store.ts | 128 +++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 58 deletions(-) diff --git a/src/stores/focus-store.ts b/src/stores/focus-store.ts index 1d42352..4e1e0ed 100644 --- a/src/stores/focus-store.ts +++ b/src/stores/focus-store.ts @@ -6,6 +6,7 @@ */ import { create } from "zustand"; +import { persist } from "zustand/middleware"; import type { FocusAction, FocusItem } from "@/lib/types"; export interface FocusState { @@ -34,72 +35,83 @@ export interface FocusState { setError: (error: string | null) => void; } -export const useFocusStore = create((set, get) => ({ - current: null, - queue: [], - isLoading: false, - error: null, - - setItems: (items) => { - const [first, ...rest] = items; - set({ - current: first ?? null, - queue: rest, +export const useFocusStore = create()( + persist( + (set, get) => ({ + current: null, + queue: [], isLoading: false, error: null, - }); - }, - act: (action, _reason) => { - const { current, queue } = get(); - const [next, ...rest] = queue; + setItems: (items) => { + const [first, ...rest] = items; + set({ + current: first ?? null, + queue: rest, + isLoading: false, + error: null, + }); + }, - // Log the decision (will be wired to backend decision log in Phase 7) - console.debug("[focus] act:", action, "on:", current?.id); + act: (action, _reason) => { + const { current, queue } = get(); + const [next, ...rest] = queue; - const nextItem = next ?? null; - set({ - current: nextItem, - queue: rest, - }); + // Log the decision (will be wired to backend decision log in Phase 7) + console.debug("[focus] act:", action, "on:", current?.id); - return nextItem; - }, + const nextItem = next ?? null; + set({ + current: nextItem, + queue: rest, + }); - setFocus: (itemId) => { - const { current, queue } = get(); - const allItems = current ? [current, ...queue] : [...queue]; - const target = allItems.find((item) => item.id === itemId); + return nextItem; + }, - if (!target) return; + setFocus: (itemId) => { + const { current, queue } = get(); + const allItems = current ? [current, ...queue] : [...queue]; + const target = allItems.find((item) => item.id === itemId); - const remaining = allItems.filter((item) => item.id !== itemId); - set({ - current: target, - queue: remaining, - }); - }, + if (!target) return; - reorderQueue: (fromIndex, toIndex) => { - const { queue } = get(); - if ( - fromIndex < 0 || - fromIndex >= queue.length || - toIndex < 0 || - toIndex >= queue.length || - fromIndex === toIndex - ) { - return; + const remaining = allItems.filter((item) => item.id !== itemId); + set({ + current: target, + queue: remaining, + }); + }, + + reorderQueue: (fromIndex, toIndex) => { + const { queue } = get(); + if ( + fromIndex < 0 || + fromIndex >= queue.length || + toIndex < 0 || + toIndex >= queue.length || + fromIndex === toIndex + ) { + return; + } + + const updated = [...queue]; + const [moved] = updated.splice(fromIndex, 1); + updated.splice(toIndex, 0, moved); + + console.debug("[focus] reorder:", moved.id, "from", fromIndex, "to", toIndex); + set({ queue: updated }); + }, + + setLoading: (loading) => set({ isLoading: loading }), + setError: (error) => set({ error }), + }), + { + name: "mc-focus-store", + partialize: (state) => ({ + current: state.current, + queue: state.queue, + }), } - - const updated = [...queue]; - const [moved] = updated.splice(fromIndex, 1); - updated.splice(toIndex, 0, moved); - - console.debug("[focus] reorder:", moved.id, "from", fromIndex, "to", toIndex); - set({ queue: updated }); - }, - - setLoading: (loading) => set({ isLoading: loading }), - setError: (error) => set({ error }), -})); + ) +);