// ============================================================ // Zustand store — داده‌ها + state UI // داده‌ها از React Query می‌آیند (api client) و اینجا mirror می‌شوند؛ // mutationها اول خوش‌بینانه اینجا آپدیت می‌کنند، بعد API را صدا // می‌زنند و آخر cache را invalidate می‌کنند تا با حقیقت همگرا شود. // ============================================================ import { create } from "zustand"; import type { CategoryUnit, Material, Project, Quote, StandardConversion, Store, Supplier, Topic, UnitConversion, } from "../lib/types"; interface AppStore { // داده‌ها (همگام با API) suppliers: Supplier[]; materials: Material[]; projects: Project[]; quotes: Quote[]; categoryUnits: CategoryUnit[]; unitConversions: UnitConversion[]; standardConversions: StandardConversion[]; topics: Topic[]; // دسته‌بندی‌های ۸گانه — از /material-categories // UI state expandedQuoteIds: Set; // wizard wizardStep: number; wizardHighestVisited: number; // actions — data setData: (store: Store) => void; addQuote: (q: Quote) => void; updateQuote: (id: string, patch: Partial) => void; deleteQuote: (id: string) => void; addSupplier: (s: Supplier) => void; updateSupplier: (id: string, patch: Partial) => void; deleteSupplier: (id: string) => void; addMaterial: (m: Material) => void; addProject: (p: Project) => void; setCategoryUnit: (cu: CategoryUnit) => void; setConversion: (c: UnitConversion) => void; deleteConversion: (id: string) => void; setStandardConversion: (sc: StandardConversion) => void; deleteStandardConversion: (id: string) => void; // actions — UI toggleExpand: (id: string) => void; setWizardStep: (step: number) => void; setWizardHighestVisited: (n: number) => void; } export const useAppStore = create()((set) => ({ suppliers: [], materials: [], projects: [], quotes: [], categoryUnits: [], unitConversions: [], standardConversions: [], topics: [], expandedQuoteIds: new Set(), wizardStep: 1, wizardHighestVisited: 1, setData: (store) => set({ suppliers: store.suppliers, materials: store.materials, projects: store.projects, quotes: store.quotes, categoryUnits: store.categoryUnits, unitConversions: store.unitConversions, standardConversions: store.standardConversions, topics: store.topics, }), addQuote: (q) => set((s) => ({ quotes: [...s.quotes, q] })), updateQuote: (id, patch) => set((s) => ({ quotes: s.quotes.map((q) => (q.id === id ? { ...q, ...patch } : q)), })), deleteQuote: (id) => set((s) => ({ quotes: s.quotes.filter((q) => q.id !== id) })), addSupplier: (sup) => set((s) => ({ suppliers: [...s.suppliers, sup] })), updateSupplier: (id, patch) => set((s) => ({ suppliers: s.suppliers.map((x) => (x.id === id ? { ...x, ...patch } : x)), })), deleteSupplier: (id) => set((s) => ({ suppliers: s.suppliers.filter((x) => x.id !== id) })), addMaterial: (m) => set((s) => ({ materials: [...s.materials, m] })), addProject: (p) => set((s) => ({ projects: [...s.projects, p] })), setCategoryUnit: (cu) => set((s) => { const idx = s.categoryUnits.findIndex((x) => x.id === cu.id); const categoryUnits = [...s.categoryUnits]; if (idx >= 0) categoryUnits[idx] = cu; else categoryUnits.push(cu); return { categoryUnits }; }), setConversion: (c) => set((s) => { const idx = s.unitConversions.findIndex((x) => x.id === c.id); const unitConversions = [...s.unitConversions]; if (idx >= 0) unitConversions[idx] = c; else unitConversions.push(c); return { unitConversions }; }), deleteConversion: (id) => set((s) => ({ unitConversions: s.unitConversions.filter((x) => x.id !== id) })), setStandardConversion: (sc) => set((s) => { const idx = s.standardConversions.findIndex((x) => x.id === sc.id); const standardConversions = [...s.standardConversions]; if (idx >= 0) standardConversions[idx] = sc; else standardConversions.push(sc); return { standardConversions }; }), deleteStandardConversion: (id) => set((s) => ({ standardConversions: s.standardConversions.filter((x) => x.id !== id) })), toggleExpand: (id) => set((s) => { const next = new Set(s.expandedQuoteIds); if (next.has(id)) next.delete(id); else next.add(id); return { expandedQuoteIds: next }; }), setWizardStep: (step) => set({ wizardStep: step }), setWizardHighestVisited: (n) => set({ wizardHighestVisited: n }), }));