) {
event.preventDefault();
if (results[0]) selectTicker(results[0].symbol);
else if (query.trim()) selectTicker(query);
}
async function toggleWatchlist() {
if (!selectedTicker) return;
try {
const next = isSaved ? await api.removeWatchlist(selectedTicker) : await api.addWatchlist(selectedTicker);
setWatchlist(next);
setWatchlistError(null);
} catch (exc) {
setWatchlistError(exc instanceof Error ? exc.message : "Could not update watchlist");
}
}
const summaryTicker = overview?.profile.symbol || selectedTicker;
const summaryName =
overviewState === "invalid"
? "Ticker not found"
: overview?.profile.name || (selectedTicker ? "Loading ticker..." : "No ticker selected");
return (
{!selectedTicker && }
{selectedTicker && overviewState === "loading" && Loading {selectedTicker}...
}
{selectedTicker && overviewState === "invalid" && }
{selectedTicker && overviewState === "error" && {overviewError || "Ticker data unavailable"}
}
{overview && overviewState === "ready" && (
{overview.profile.exchange || "Ticker"}
{overview.profile.name}
{overview.meta.is_partial && Partial Data}
{identityLine(overview)}
{fmtCurrency(overview.quote.price)}
{fmtPct(overview.quote.change_pct, 2, true)}
Prev close {fmtCurrency(overview.quote.prev_close)}
{overview.meta.is_partial && Some fields are unavailable for this ticker. Available data is still shown below.
}
{overview.signals.map((signal) => (
{signal.key}
{signal.value}
{signal.description}
))}
Price History
{overview.profile.symbol}
{PERIODS.map((option) => (
))}
{chartState === "loading" && Loading {period.toUpperCase()} history...
}
{chartState === "error" && {chartError || "Could not load chart history"}
}
{chartState === "ready" && }
)}
);
}
function MarketBar({ indices }: { indices: MarketIndex[] }) {
if (!indices.length) return Market data unavailable
;
return (
{indices.map((index) => (
{index.name}
{fmtNumber(index.price)}
{fmtPct(index.change_pct, 2, true)}
))}
);
}
function EmptyState({ watchlist, onSelect }: { watchlist: WatchlistResponse; onSelect: (symbol: string) => void }) {
return (
Overview
{watchlist.items.length ? (
<>
Select a saved ticker to load its company profile, quote, stats, and chart.
{watchlist.items.map((item) => (
))}
>
) : (
Search for a ticker to begin.
)}
);
}
function InvalidTickerState({ symbol, onClear }: { symbol: string; onClear: () => void }) {
return (
{symbol}
This ticker could not be resolved to usable market data.
);
}
function Stat({ label, value, missing = false }: { label: string; value: string; missing?: boolean }) {
return (
{label}
{missing ? "Unavailable" : value}
);
}
function RangeCard({ overview }: { overview: TickerOverview }) {
const low = overview.range_52w.low;
const high = overview.range_52w.high;
const price = overview.range_52w.price;
const pct = low != null && high != null && price != null && high > low ? Math.max(0, Math.min(100, ((price - low) / (high - low)) * 100)) : null;
return (
52 Week Range
{pct === null ? (
Range unavailable
) : (
<>
{fmtCurrency(low)}
{fmtCurrency(price)}
{fmtCurrency(high)}
>
)}
);
}
function ShortInterest({ overview }: { overview: TickerOverview }) {
const short = overview.short_interest;
return (
);
}
function ProfileCard({ overview }: { overview: TickerOverview }) {
return (
Company Profile
Sector
{overview.profile.sector || "Unavailable"}
Industry
{overview.profile.industry || "Unavailable"}
{overview.profile.summary || "Business summary unavailable."}
);
}
function SourceCard({ overview }: { overview: TickerOverview }) {
const fields = Object.entries(overview.meta.sources).slice(0, 6);
return (
Data Quality
Status {overview.meta.status}
{fields.length ? (
fields.map(([field, source]) => (
{field}
{source}
))
) : (
Sources
Unavailable
)}
);
}
function identityLine(overview: TickerOverview) {
const parts = [overview.profile.symbol, overview.profile.sector, overview.profile.industry].filter(Boolean);
return parts.length ? parts.join(" ยท ") : overview.profile.symbol;
}