feat(sync): live cross-module cache invalidation (no manual refresh)
- procurement store refreshes right after a warehouse receipt (arrivals) and after role/project changes (organization/admin), so the ledger reflects warehouse actions immediately - refetchOnWindowFocus enabled on the shared query client - BroadcastChannel (lib/crossTab.ts): mutations broadcast 'quotes' / 'inventory'; all warehouse pages + the store hook resync open tabs automatically (receipt in one tab updates the ledger in another) - warehouse mutations (stock changes) notify other tabs; same-page refresh behavior unchanged
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
export { useStoreData, useInvalidateStore } from "./useStoreData";
|
||||
export { useStoreData, useInvalidateStore, refreshProcurementStore } from "./useStoreData";
|
||||
export { useQuotes, useCreateQuote, useUpdateQuote, useDeleteQuote } from "./useQuotes";
|
||||
export { useSuppliers, useAddSupplier, useUpdateSupplier, useRemoveSupplier } from "./useSuppliers";
|
||||
export { useMaterials, useAddMaterial } from "./useMaterials";
|
||||
|
||||
@@ -4,12 +4,16 @@
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useCallback } from "react";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { api } from "../lib/api";
|
||||
import { useAppStore } from "../store";
|
||||
import { notifyDataChanged, useDataChanged } from "../lib/crossTab";
|
||||
import { queryClient } from "../lib/queryClient";
|
||||
|
||||
export const STORE_KEY = ["store"] as const;
|
||||
|
||||
export { queryClient };
|
||||
|
||||
// یک بار در ریشهی برنامه صدا زده میشود: لود + mirror در Zustand
|
||||
export function useStoreData(): void {
|
||||
const setData = useAppStore((s) => s.setData);
|
||||
@@ -21,12 +25,25 @@ export function useStoreData(): void {
|
||||
useEffect(() => {
|
||||
if (data) setData(data);
|
||||
}, [data, setData]);
|
||||
|
||||
// تبهای دیگر (رسید انبار / تغییر نقش و...) → بازخوانی خودکار store
|
||||
useDataChanged(
|
||||
useCallback(() => {
|
||||
void queryClient.invalidateQueries({ queryKey: STORE_KEY });
|
||||
}, []),
|
||||
["quotes"],
|
||||
);
|
||||
}
|
||||
|
||||
// بعد از هر mutation برای همگرایی با حقیقت
|
||||
// بعد از هر mutation برای همگرایی با حقیقت (+ اعلام به تبهای دیگر)
|
||||
export function useInvalidateStore(): () => void {
|
||||
const qc = useQueryClient();
|
||||
return useCallback(() => {
|
||||
void qc.invalidateQueries({ queryKey: STORE_KEY });
|
||||
}, [qc]);
|
||||
return useCallback(refreshProcurementStore, []);
|
||||
}
|
||||
|
||||
// نسخهی تابعی (خارج از کامپوننت هم قابل صدا زدن) — بعد از تغییر دادههای
|
||||
// مرتبط با پیشنهادها (مثلاً رسید انبار) خودِ store را تازه میکند تا دفتر
|
||||
// بدون refresh دستی بهروز شود؛ و به تبهای دیگر هم اعلام میکند.
|
||||
export function refreshProcurementStore(): void {
|
||||
void queryClient.invalidateQueries({ queryKey: STORE_KEY });
|
||||
notifyDataChanged("quotes");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user