feat: instrument analysis
This commit is contained in:
@@ -100,7 +100,7 @@ function KeepAlivePage({ path, component: Component }: { path: string; component
|
|||||||
|
|
||||||
// Registers the instrument tab on navigation (renders nothing itself)
|
// Registers the instrument tab on navigation (renders nothing itself)
|
||||||
function InstrumentRoute() {
|
function InstrumentRoute() {
|
||||||
const { id = 'EURUSD' } = useParams<{ id: string }>()
|
const { id = localStorage.getItem('last_instrument') || 'EURUSD' } = useParams<{ id: string }>()
|
||||||
const { openInstrument } = useTabs()
|
const { openInstrument } = useTabs()
|
||||||
useEffect(() => { openInstrument(id.toUpperCase()) }, [id, openInstrument])
|
useEffect(() => { openInstrument(id.toUpperCase()) }, [id, openInstrument])
|
||||||
return null
|
return null
|
||||||
@@ -112,7 +112,7 @@ function InstrumentKeepAlive({ id }: { id: string }) {
|
|||||||
const isActive = location.pathname.toLowerCase() === `/instruments/${id.toLowerCase()}`
|
const isActive = location.pathname.toLowerCase() === `/instruments/${id.toLowerCase()}`
|
||||||
return (
|
return (
|
||||||
<div className={isActive ? 'flex-1 min-h-0 overflow-y-auto' : 'hidden'}>
|
<div className={isActive ? 'flex-1 min-h-0 overflow-y-auto' : 'hidden'}>
|
||||||
<InstrumentDashboard instrumentIdProp={id} />
|
<InstrumentDashboard instrumentIdProp={id} isVisible={isActive} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -129,7 +129,7 @@ function NormalRoutes() {
|
|||||||
return (
|
return (
|
||||||
<div className={isInstrument ? 'hidden' : 'flex-1 overflow-auto'}>
|
<div className={isInstrument ? 'hidden' : 'flex-1 overflow-auto'}>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/instruments" element={<Navigate to="/instruments/EURUSD" replace />} />
|
<Route path="/instruments" element={<Navigate to={`/instruments/${localStorage.getItem('last_instrument') || 'EURUSD'}`} replace />} />
|
||||||
<Route path="/instruments/:id" element={<InstrumentRoute />} />
|
<Route path="/instruments/:id" element={<InstrumentRoute />} />
|
||||||
{/* Legacy redirects */}
|
{/* Legacy redirects */}
|
||||||
<Route path="/impact" element={<Navigate to="/market-events" replace />} />
|
<Route path="/impact" element={<Navigate to="/market-events" replace />} />
|
||||||
|
|||||||
@@ -28,8 +28,10 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||||||
const forgetRoute = useCallback((r: string) =>
|
const forgetRoute = useCallback((r: string) =>
|
||||||
setKept(p => { const n = new Set(p); n.delete(r); return n }), [])
|
setKept(p => { const n = new Set(p); n.delete(r); return n }), [])
|
||||||
|
|
||||||
const openInstrument = useCallback((id: string) =>
|
const openInstrument = useCallback((id: string) => {
|
||||||
setInstrumentIds(p => p.includes(id) ? p : [...p, id]), [])
|
localStorage.setItem('last_instrument', id)
|
||||||
|
setInstrumentIds(p => p.includes(id) ? p : [...p, id])
|
||||||
|
}, [])
|
||||||
|
|
||||||
const closeInstrument = useCallback((id: string) =>
|
const closeInstrument = useCallback((id: string) =>
|
||||||
setInstrumentIds(p => p.filter(x => x !== id)), [])
|
setInstrumentIds(p => p.filter(x => x !== id)), [])
|
||||||
|
|||||||
@@ -1205,8 +1205,8 @@ const PERIODS = [
|
|||||||
{ key: '5y', label: '5Y' },
|
{ key: '5y', label: '5Y' },
|
||||||
]
|
]
|
||||||
|
|
||||||
export default function InstrumentDashboard({ instrumentIdProp }: { instrumentIdProp?: string } = {}) {
|
export default function InstrumentDashboard({ instrumentIdProp, isVisible }: { instrumentIdProp?: string; isVisible?: boolean } = {}) {
|
||||||
const { id: paramId = 'EURUSD' } = useParams<{ id: string }>()
|
const { id: paramId = localStorage.getItem('last_instrument') || 'EURUSD' } = useParams<{ id: string }>()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const [period, setPeriod] = useState('1y')
|
const [period, setPeriod] = useState('1y')
|
||||||
const [chartStyle, setChartStyle] = useState<'candles' | 'line'>('candles')
|
const [chartStyle, setChartStyle] = useState<'candles' | 'line'>('candles')
|
||||||
@@ -1237,6 +1237,14 @@ export default function InstrumentDashboard({ instrumentIdProp }: { instrumentId
|
|||||||
api.get('/causal-lab/templates').then(r => setTemplates(r.data)).catch(() => {})
|
api.get('/causal-lab/templates').then(r => setTemplates(r.data)).catch(() => {})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
// Silent refresh when the tab becomes visible again (e.g. after analysis updated from MarketEvents)
|
||||||
|
const mountedRef = useRef(false)
|
||||||
|
useEffect(() => {
|
||||||
|
if (!mountedRef.current) { mountedRef.current = true; return }
|
||||||
|
if (isVisible) fetchSnapshotSilent()
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [isVisible])
|
||||||
|
|
||||||
const fetchSnapshot = useCallback(() => {
|
const fetchSnapshot = useCallback(() => {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
api.get(`/instruments/${instrumentId}/snapshot?period=${period}`)
|
api.get(`/instruments/${instrumentId}/snapshot?period=${period}`)
|
||||||
|
|||||||
Reference in New Issue
Block a user