Files
ERP/frontend/src/store/index.ts
T
MMD 0ea0322967 Revert 253c922: restore the PM/RBAC work to the integration
Reverting the production revert so the pm branch can merge cleanly on
top of the restored RBAC base. Conflicts against newer integration work
resolved by combining:
- App.tsx: v7's bot-draft wizard bypass + login returnUrl kept alongside
  the supervisor gating (no-project block screen, panel scoping)
- LoginPage: returnUrl navigation kept, supervisor routing added
- migration.sql: bot_drafts table kept, unified-projects ALTERs restored
2026-10-01 15:24:56 +03:30

111 lines
3.8 KiB
TypeScript

// ============================================================
// Zustand store — داده‌ها + state UI
// داده‌ها از React Query می‌آیند (api client) و اینجا mirror می‌شوند؛
// mutationها اول خوش‌بینانه اینجا آپدیت می‌کنند، بعد API را صدا
// می‌زنند و آخر cache را invalidate می‌کنند تا با حقیقت همگرا شود.
// ============================================================
import { create } from "zustand";
import type {
Material,
Project,
Quote,
StandardConversion,
Store,
Supplier,
Topic,
} from "../lib/types";
interface AppStore {
// داده‌ها (همگام با API)
suppliers: Supplier[];
materials: Material[];
projects: Project[];
quotes: Quote[];
standardConversions: StandardConversion[];
topics: Topic[]; // دسته‌بندی‌های ۸گانه — از /material-categories
// UI state
expandedQuoteIds: Set<string>;
// wizard
wizardStep: number;
wizardHighestVisited: number;
// actions — data
setData: (store: Store) => void;
addQuote: (q: Quote) => void;
updateQuote: (id: string, patch: Partial<Quote>) => void;
deleteQuote: (id: string) => void;
addSupplier: (s: Supplier) => void;
updateSupplier: (id: string, patch: Partial<Supplier>) => void;
deleteSupplier: (id: string) => void;
addMaterial: (m: Material) => void;
addProject: (p: Project) => void;
deleteProject: (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<AppStore>()((set) => ({
suppliers: [],
materials: [],
projects: [],
quotes: [],
standardConversions: [],
topics: [],
expandedQuoteIds: new Set<string>(),
wizardStep: 1,
wizardHighestVisited: 1,
setData: (store) =>
set({
suppliers: store.suppliers,
materials: store.materials,
projects: store.projects,
quotes: store.quotes,
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] })),
deleteProject: (id) => set((s) => ({ projects: s.projects.filter((p) => p.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 }),
}));