Files
ERP/frontend/src/store/index.ts
T
ZCode 253c922280 revert: restore production to the state before 730d0bd (PM/RBAC work moved to 'pm')
Their three commits (730d0bd, 5a9b543, 387edfb) reached production by push and
auto-deployed. 387edfb expects a users.username column that the live database does
not have, so POST /api/v1/auth/login was returning HTTP 500. Their schema changes
never applied either (projects still has only id, name, description, start_date,
pm_user_id, created_at), so nothing depends on the reverted code.

This commit sets the tree back to exactly a02b3ea — verified with git diff against
it — while keeping history linear: the work itself is preserved on 'pm' at 387edfb.
2026-09-26 17:41:07 +00:00

109 lines
3.7 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;
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] })),
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 }),
}));