diff --git a/frontend/src/components/windows/InventoryWindow.tsx b/frontend/src/components/windows/InventoryWindow.tsx index fda806e4..51454847 100644 --- a/frontend/src/components/windows/InventoryWindow.tsx +++ b/frontend/src/components/windows/InventoryWindow.tsx @@ -163,19 +163,33 @@ export const InventoryWindow: React.FC = ({ id, charName, zIndex, invento const [activePack, setActivePack] = useState(null); const [tooltip, setTooltip] = useState<{ item: any; x: number; y: number } | null>(null); const [charStats, setCharStats] = useState(null); - const [cantripState, setCantripState] = useState(null); + const debounceRef = useRef(0); + const initialLoadDone = useRef(false); + // Initial fetch useEffect(() => { setLoading(true); Promise.all([ apiFetch(`/inventory/${encodeURIComponent(charName)}?limit=1000`).catch(() => ({ items: [] })), apiFetch(`/character-stats/${encodeURIComponent(charName)}`).catch(() => null), ]).then(([inv, stats]) => { - const rawItems = inv.items ?? []; - setItems(rawItems.map(normalizeItem)); + setItems((inv.items ?? []).map(normalizeItem)); setCharStats(stats); + initialLoadDone.current = true; }).finally(() => setLoading(false)); - }, [charName, inventoryVersion]); // re-fetch when inventory_delta arrives + }, [charName]); + + // Debounced re-fetch on inventory_delta (no loading flash) + useEffect(() => { + if (!initialLoadDone.current || !inventoryVersion) return; + clearTimeout(debounceRef.current); + debounceRef.current = window.setTimeout(() => { + apiFetch(`/inventory/${encodeURIComponent(charName)}?limit=1000`) + .then(inv => setItems((inv.items ?? []).map(normalizeItem))) + .catch(() => {}); + }, 2000); // 2s debounce — batch rapid deltas + return () => clearTimeout(debounceRef.current); + }, [charName, inventoryVersion]); const handleHover = useCallback((item: any | null, e?: React.MouseEvent) => { if (item && e) setTooltip({ item, x: e.clientX, y: e.clientY });