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,15 +1,13 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { Warehouse as WarehouseIcon } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { Header, PageLayout } from "../../components/layout/Header";
|
||||
import { EmptyState } from "../../components/EmptyState";
|
||||
import { Badge } from "../../components/ui/badge";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { useAuthStore } from "../../store/auth";
|
||||
import { PanelMenu } from "../../components/PanelMenu";
|
||||
import { accountMenuItems, inventorySubheader, panelMenuItems, pmMenuItems, useLogout } from "./panelMenu";
|
||||
import { inventorySubheader } from "./panelMenu";
|
||||
import { apiV26 } from "../../lib/api";
|
||||
import { refreshProcurementStore } from "../../hooks";
|
||||
import type { PendingArrival, Warehouse } from "../../lib/types";
|
||||
import { faNum, fmtDate } from "../../lib/formatters";
|
||||
|
||||
@@ -22,8 +20,6 @@ interface AllocRow { key: number; qty: string; whId: string; }
|
||||
interface ItemDraft { received: string; allocs: AllocRow[]; }
|
||||
|
||||
export function ArrivalsPage() {
|
||||
const location = useLocation();
|
||||
const logout = useLogout();
|
||||
const user = useAuthStore((s) => s.user);
|
||||
const isAdmin = user?.role === "admin" || user?.role === "procurement_manager";
|
||||
const isPM = user?.role === "pm";
|
||||
@@ -193,6 +189,9 @@ export function ArrivalsPage() {
|
||||
});
|
||||
}
|
||||
toast.success("رسید (کامل یا جزیی) ثبت شد و به انبارها وارد شد ✓ — اقلام باقیمانده همچنان در راه هستند");
|
||||
// همگامسازی با دفتر تدارکات: store پیشنهادها را تازه کن تا کارتهای
|
||||
// پیشنهاد (بدون refresh دستی) رسید را نشان دهند.
|
||||
refreshProcurementStore();
|
||||
setDrafts((d) => {
|
||||
const next = { ...d };
|
||||
submittable.forEach((it) => delete next[it.item_decision_id]);
|
||||
@@ -214,7 +213,7 @@ export function ArrivalsPage() {
|
||||
if (!isAdmin && !isPM) {
|
||||
return (
|
||||
<div className="min-h-screen">
|
||||
<Header title="کالاهای در راه" menu={<PanelMenu title="پنل مدیریت انبار" items={panelMenuItems(location.pathname, user?.role, logout)} />} />
|
||||
<Header title="کالاهای در راه" backTo="/inventory" backLabel="بازگشت به داشبورد" />
|
||||
<PageLayout>
|
||||
<EmptyState emoji="🔒" text="این بخش فقط برای مدیر پروژه و مدیر تدارکات است." />
|
||||
</PageLayout>
|
||||
@@ -229,8 +228,6 @@ export function ArrivalsPage() {
|
||||
sub={inventorySubheader(user)}
|
||||
backTo="/inventory"
|
||||
backLabel="بازگشت به داشبورد"
|
||||
icon={<WarehouseIcon className="h-4.5 w-4.5" strokeWidth={2} />}
|
||||
menu={<PanelMenu title="پنل مدیریت انبار" items={isAdmin ? accountMenuItems(logout) : pmMenuItems(logout)} />}
|
||||
/>
|
||||
<PageLayout className="flex flex-col gap-4">
|
||||
<div className="rounded-lg border border-blue/20 bg-blue/5 px-3 py-2 text-[12px] leading-6 text-muted">
|
||||
|
||||
Reference in New Issue
Block a user