import { useMemo, useState } from 'react'; import { formatPercent, formatLargeNumber } from '../../lib/format'; import { fundamentalScore, metricStatus, overallFundamentalStatus, } from '../../lib/fundamentals'; import type { FundamentalResponse } from '../../lib/types'; interface FundamentalsPanelProps { data: FundamentalResponse; } const FIELD_LABELS: Record = { pe_ratio: 'P/E Ratio', revenue_growth: 'Revenue Growth', earnings_surprise: 'Earnings Surprise', market_cap: 'Market Cap', }; type MetricKey = 'pe_ratio' | 'revenue_growth' | 'earnings_surprise' | 'market_cap'; export function FundamentalsPanel({ data }: FundamentalsPanelProps) { const [expanded, setExpanded] = useState(false); const score = useMemo( () => fundamentalScore({ pe_ratio: data.pe_ratio, revenue_growth: data.revenue_growth, earnings_surprise: data.earnings_surprise, }), [data.pe_ratio, data.revenue_growth, data.earnings_surprise], ); const overall = overallFundamentalStatus(score); const items: { key: MetricKey; label: string; value: number | null; format: (v: number) => string; }[] = [ { key: 'pe_ratio', label: 'P/E Ratio', value: data.pe_ratio, format: (v) => v.toFixed(2) }, { key: 'revenue_growth', label: 'Revenue Growth', value: data.revenue_growth, format: formatPercent }, { key: 'earnings_surprise', label: 'Earnings Surprise', value: data.earnings_surprise, format: formatPercent }, { key: 'market_cap', label: 'Market Cap', value: data.market_cap, format: formatLargeNumber }, ]; const unavailableEntries = Object.entries(data.unavailable_fields ?? {}); return (

Fundamentals

{score != null && ( score {score.toFixed(0)} )}

{overall.text}

{items.map((item) => { const reason = data.unavailable_fields?.[item.key]; const status = item.value !== null ? metricStatus(item.key, item.value) : null; let display: React.ReactNode; let valueClass = 'text-gray-200'; if (item.value !== null) { display = item.format(item.value); } else if (reason) { display = reason; valueClass = 'text-amber-400'; } else { display = '—'; } return (
{item.label}
{display}
{status && (
{status.text}
)}
); })}

Score = average of available P/E, revenue growth, and earnings surprise (need 2+). {' '}P/E: lower scores higher (≈15 best, ≈45 worst). {' '}Growth / surprise: 0% is neutral; stronger positives lift the score. {' '}Market cap is size context only — not scored.

{expanded && (
Data Source FMP
{data.fetched_at && (
Fetched {new Date(data.fetched_at).toLocaleString()}
)}
{unavailableEntries.length > 0 && (
Unavailable Fields
    {unavailableEntries.map(([field, reason]) => (
  • {FIELD_LABELS[field] ?? field} {reason}
  • ))}
)}
)} {!expanded && data.fetched_at && (

Updated {new Date(data.fetched_at).toLocaleDateString()}

)}
); }