- 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
55 lines
2.0 KiB
TypeScript
55 lines
2.0 KiB
TypeScript
// ============================================================
|
|
// همگامسازی بین تبها (BroadcastChannel) — بعد از هر mutation که روی
|
|
// دادههای «پیشنهادها» یا «انبار» اثر میگذارد، به تبهای دیگر اعلام میشود
|
|
// تا آنها هم دادههای خود را تازه کنند (بدون نیاز به refresh دستی).
|
|
// BroadcastChannel در خودِ همان تب پیام را نمیدهد — همتبهها همانجا
|
|
// refresh میشوند و این فقط برای تبهای دیگر است.
|
|
// ============================================================
|
|
|
|
import { useEffect } from "react";
|
|
|
|
const CHANNEL = "procurement-data-sync";
|
|
|
|
export type DataScope = "quotes" | "inventory";
|
|
|
|
let _channel: BroadcastChannel | null = null;
|
|
|
|
function channel(): BroadcastChannel | null {
|
|
if (typeof BroadcastChannel === "undefined") return null;
|
|
if (!_channel) {
|
|
try {
|
|
_channel = new BroadcastChannel(CHANNEL);
|
|
} catch {
|
|
_channel = null;
|
|
}
|
|
}
|
|
return _channel;
|
|
}
|
|
|
|
/** بعد از تغییر داده در این تب، به بقیهی تبها اعلام کن. */
|
|
export function notifyDataChanged(scope: DataScope): void {
|
|
const ch = channel();
|
|
if (!ch) return;
|
|
try {
|
|
ch.postMessage({ scope });
|
|
} catch {
|
|
/* نادیده — پیام فقط بهروزرسانی است */
|
|
}
|
|
}
|
|
|
|
/** گوش دادن به تغییرات تبهای دیگر (scope دلخواه یا همه). */
|
|
export function useDataChanged(onEvent: (scope: DataScope) => void, scopes?: DataScope[]): void {
|
|
useEffect(() => {
|
|
const ch = channel();
|
|
if (!ch) return;
|
|
const handler = (ev: MessageEvent) => {
|
|
const scope = (ev.data as { scope?: DataScope } | null)?.scope;
|
|
if (!scope) return;
|
|
if (scopes && !scopes.includes(scope)) return;
|
|
onEvent(scope);
|
|
};
|
|
ch.addEventListener("message", handler);
|
|
return () => ch.removeEventListener("message", handler);
|
|
}, [onEvent, scopes?.join(",")]);
|
|
}
|