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 <noreply@anthropic.com>
This commit is contained in:
@@ -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<FocusState>((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<FocusState>()(
|
||||
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 }),
|
||||
}));
|
||||
)
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user