/* FinPulse — Markets (India default + Global US toggle) */ function MoverRow({ stock, onOpen }) { const C = stock.live ? curSym(stock.cur) : '$'; return (
onOpen(stock)} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '10px 0', borderBottom: '1px solid var(--border)', cursor: 'pointer' }}>
{stock.name}
{stock.ticker}
= 0} width={72} height={28} />
{C}{fmt.price(stock.price)}
); } const MARKETS_STOCK_PAGE = 15; function MarketsScreen({ onOpenStock, onOpenArticle, onOpenIndices, initialRegion, onRegionChange }) { const L = useLive(); const MD = useMarketData(); const [region, setRegion] = useState(initialRegion || 'IN'); function setMarketRegion(next) { setRegion(next); if (onRegionChange) onRegionChange(next); } useEffect(() => { if (initialRegion && initialRegion !== region) setRegion(initialRegion); }, [initialRegion]); const [selIndex, setSelIndex] = useState(null); const [stockPage, setStockPage] = useState(1); const isUS = region === 'US'; const indiaIndices = MD.indices || []; const globalIndices = MD.globalIndices || []; const indices = isUS ? globalIndices : indiaIndices; const stocks = isUS ? (MD.globalStocks || []) : MD.stocks; const news = MD.news; const status = MD.status; useEffect(() => { if (isUS && L.hasKey && !globalIndices.length && !MD.globalLoading) { MD.loadGlobal(); } }, [isUS, L.hasKey, globalIndices.length, MD.globalLoading, MD.loadGlobal]); useEffect(() => { setSelIndex(null); setStockPage(1); }, [region]); useEffect(() => { if (indices.length && selIndex && !indices.find((i) => i.label === selIndex)) { setSelIndex(null); } }, [indices, selIndex]); if (!isUS && MD.loading && !MD.ready) return ; if (!isUS && MD.error) return Retry} />; if (!isUS && !MD.stocks.length) return Retry} />; if (isUS && !L.hasKey) { return (
Connect API} />
); } if (isUS && MD.globalLoading && !indices.length) return ; if (isUS && !indices.length) { return (
Retry} />
); } const lead = indices.find((i) => i.label === selIndex) || indices[0]; const cur = lead.cur === 'INR' ? '₹' : '$'; const sorted = [...stocks].sort((a, b) => b.chg - a.chg); const gainers = sorted.filter((s) => s.chg > 0).slice(0, 5); const losers = sorted.filter((s) => s.chg < 0).slice(-5).reverse(); const upCount = stocks.filter((s) => s.chg > 0).length; const downCount = stocks.filter((s) => s.chg < 0).length; const flatCount = stocks.length - upCount - downCount; const breadth = [ { k: 'Advances', v: String(upCount), c: 'var(--up)' }, { k: 'Declines', v: String(downCount), c: 'var(--down)' }, { k: 'Unchanged', v: String(flatCount), c: 'var(--text-muted)' }, { k: 'Tracked', v: String(stocks.length), c: 'var(--accent)' }, ]; const sessionLabel = isUS ? 'US Markets · Live' : (status ? (status.isOpen ? 'NSE Open' : (status.session === 'pre-market' ? 'Pre-market' : 'Closed')) : 'NSE'); const dateStr = new Date().toLocaleDateString('en-IN', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric', timeZone: isUS ? 'America/New_York' : 'Asia/Kolkata', }); const updated = MD.lastUpdated ? new Date(MD.lastUpdated).toLocaleTimeString('en-IN', { hour: '2-digit', minute: '2-digit', timeZone: isUS ? 'America/New_York' : 'Asia/Kolkata', }) : null; const stockPages = Math.max(1, Math.ceil(stocks.length / MARKETS_STOCK_PAGE)); const stockSlice = stocks.slice((stockPage - 1) * MARKETS_STOCK_PAGE, stockPage * MARKETS_STOCK_PAGE); function openIndicesDetail() { if (onOpenIndices) onOpenIndices(region, lead.label); } return (
{indices.map((ix) => ( setSelIndex(ix.label)} /> ))}
{ if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); openIndicesDetail(); } }}>
{lead.label} · Intraday
{cur}{fmt.price(lead.value)}
{onOpenIndices && ( )}
= 0 ? 'var(--up)' : 'var(--down)'} height={220} />
{isUS ? 'US Watchlist Breadth' : 'Watchlist Breadth'}
{breadth.map((b, i) => (
{b.k} {b.v}
))} {stocks.length > 0 && (
Adv / Dec ratio
)}

Top Gainers

{gainers.length ? gainers.map((s) => ) :
No gainers today.
}

Top Losers

{losers.length ? losers.map((s) => ) :
No losers today.
}

{isUS ? 'US Watchlist' : 'Nifty 50 Watchlist'}

{stocks.length}{!isUS && MD.stocksTotal ? '/' + MD.stocksTotal : ''} stocks · {isUS ? 'Finnhub live' : 'live NSE quotes'} {!isUS && MD.stocksLoadingMore ? ' · loading…' : ''}
{stockSlice.map((s) => )}
{stocks.length > MARKETS_STOCK_PAGE && (
Page {stockPage} of {stockPages} · showing {(stockPage - 1) * MARKETS_STOCK_PAGE + 1}–{(stockPage - 1) * MARKETS_STOCK_PAGE + stockSlice.length}
)}
{!isUS && news.length > 0 && (

Top Stories

{news.slice(1, 5).map((n) => )}
)}
); } function MarketsHeader({ region, onRegionChange, isUS, live, sessionLabel, dateStr, updated, timezoneLabel }) { return (

Markets

{dateStr ? dateStr + ' · ' : ''}{isUS ? 'US benchmarks & large caps' : 'NSE/BSE'}{updated ? ' · updated ' + updated + ' ' + timezoneLabel : ''}
{sessionLabel}
); } Object.assign(window, { MarketsScreen });