fix: race condition causing wrong symbol data in chart and evaluation

- Add cancelled flags to evaluation and scorecard effects so stale
  responses from a previous symbol cannot overwrite current data
- Clear evaluation and scorecard state immediately in pickSymbol so
  old data never flashes when switching symbols
- Add key={symbol} to ConfluenceChart to force clean remount on
  symbol change
This commit is contained in:
Investor Flow Build
2026-08-11 23:43:56 -04:00
parent be4c59d3f4
commit e5a7ff9f33
+17 -5
View File
@@ -55,6 +55,9 @@ export function ConfluencePanel() {
setSymbol(sym);
setSearchQuery(sym);
setActiveSymbol(sym);
// Clear stale data immediately so old symbol never flashes
setEvaluation(null);
setScorecard(null);
}, [setActiveSymbol]);
// Sync searchQuery when activeSymbol changes externally (e.g., from another panel)
@@ -62,6 +65,11 @@ export function ConfluencePanel() {
setSearchQuery(activeSymbol);
}, [activeSymbol]);
// Sync symbol state when activeSymbol changes externally
useEffect(() => {
setSymbol(activeSymbol);
}, [activeSymbol]);
// Racks
const [racks, setRacks] = useState<{ system: Array<{ id: string; name: string }>; user: Array<{ id: string; name: string }> }>({ system: [], user: [] });
useEffect(() => {
@@ -73,18 +81,22 @@ export function ConfluencePanel() {
const rackId = selectedRackId ?? racks.system[0]?.id ?? null;
useEffect(() => {
if (!symbol) return;
let cancelled = false;
api.confluence.evaluation(symbol, { rackId: rackId ?? undefined, limit: 6 })
.then((r) => setEvaluation(r as Record<string, unknown>))
.catch(() => setEvaluation(null));
.then((r) => { if (!cancelled) setEvaluation(r as Record<string, unknown>); })
.catch(() => { if (!cancelled) setEvaluation(null); });
return () => { cancelled = true; };
}, [symbol, rackId]);
// Scorecard
const [scorecard, setScorecard] = useState<{ slots: Array<Record<string, unknown>>; note: string } | null>(null);
useEffect(() => {
if (!symbol) return;
let cancelled = false;
api.confluence.scorecard(symbol)
.then((r) => setScorecard(r as { slots: Array<Record<string, unknown>>; note: string }))
.catch(() => setScorecard(null));
.then((r) => { if (!cancelled) setScorecard(r as { slots: Array<Record<string, unknown>>; note: string }); })
.catch(() => { if (!cancelled) setScorecard(null); });
return () => { cancelled = true; };
}, [symbol]);
// Slots
@@ -194,7 +206,7 @@ export function ConfluencePanel() {
{/* Signal Timeline chart */}
{symbol && (
<CollapsibleSection title="Signal Timeline" defaultOpen>
<ConfluenceChart symbol={symbol} />
<ConfluenceChart key={symbol} symbol={symbol} />
</CollapsibleSection>
)}