'use client'; import Link from 'next/link'; import { Suspense, useCallback, useEffect, useMemo, useState } from 'react'; import { format } from 'date-fns'; import { useSearchParams } from 'next/navigation'; import { Area, AreaChart, Bar, BarChart, CartesianGrid, Legend, Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts'; import { ChartNoAxesCombined, RefreshCcw, Search } from 'lucide-react'; import { AppShell } from '@/components/shell/app-shell'; import { MetricCard } from '@/components/dashboard/metric-card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Panel } from '@/components/ui/panel'; import { useAuthGuard } from '@/hooks/use-auth-guard'; import { getCompanyAnalysis } from '@/lib/api'; import { formatCompactCurrency, formatCurrency, formatPercent } from '@/lib/format'; import type { CompanyAnalysis } from '@/lib/types'; type FinancialSeriesPoint = { filingDate: string; filingType: '10-K' | '10-Q'; periodKind: 'quarterly' | 'fiscalYearEnd'; periodLabel: 'Quarter End' | 'Fiscal Year End'; label: string; revenue: number | null; netIncome: number | null; totalAssets: number | null; cash: number | null; debt: number | null; netMargin: number | null; debtToAssets: number | null; }; type ChartPeriodFilter = 'quarterlyAndFiscalYearEnd' | 'quarterlyOnly' | 'fiscalYearEndOnly'; const AXIS_CURRENCY = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', notation: 'compact', maximumFractionDigits: 1 }); const CHART_PERIOD_FILTER_OPTIONS: Array<{ value: ChartPeriodFilter; label: string }> = [ { value: 'quarterlyAndFiscalYearEnd', label: 'Quarterly + Fiscal Year End' }, { value: 'quarterlyOnly', label: 'Quarterly only' }, { value: 'fiscalYearEndOnly', label: 'Fiscal Year End only' } ]; function formatShortDate(value: string) { const parsed = new Date(value); if (Number.isNaN(parsed.getTime())) { return 'Unknown'; } return format(parsed, 'MMM yyyy'); } function formatLongDate(value: string) { const parsed = new Date(value); if (Number.isNaN(parsed.getTime())) { return 'Unknown'; } return format(parsed, 'MMM dd, yyyy'); } function ratioPercent(numerator: number | null, denominator: number | null) { if (numerator === null || denominator === null || denominator === 0) { return null; } return (numerator / denominator) * 100; } function asDisplayCurrency(value: number | null) { return value === null ? 'n/a' : formatCurrency(value); } function asDisplayPercent(value: number | null) { return value === null ? 'n/a' : formatPercent(value); } function normalizeTooltipValue(value: unknown) { if (Array.isArray(value)) { const [first] = value; return typeof first === 'number' || typeof first === 'string' ? first : null; } if (typeof value === 'number' || typeof value === 'string') { return value; } return null; } function asTooltipCurrency(value: unknown) { const normalized = normalizeTooltipValue(value); if (normalized === null) { return 'n/a'; } const numeric = Number(normalized); if (!Number.isFinite(numeric)) { return 'n/a'; } return formatCompactCurrency(numeric); } function includesChartPeriod(point: FinancialSeriesPoint, filter: ChartPeriodFilter) { if (filter === 'quarterlyOnly') { return point.periodKind === 'quarterly'; } if (filter === 'fiscalYearEndOnly') { return point.periodKind === 'fiscalYearEnd'; } return true; } function isFinancialPeriodForm(filingType: CompanyAnalysis['financials'][number]['filingType']): filingType is '10-K' | '10-Q' { return filingType === '10-K' || filingType === '10-Q'; } export default function FinancialsPage() { return ( Loading financial terminal...}> ); } function FinancialsPageContent() { const { isPending, isAuthenticated } = useAuthGuard(); const searchParams = useSearchParams(); const [tickerInput, setTickerInput] = useState('MSFT'); const [ticker, setTicker] = useState('MSFT'); const [analysis, setAnalysis] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [chartPeriodFilter, setChartPeriodFilter] = useState('quarterlyAndFiscalYearEnd'); useEffect(() => { const fromQuery = searchParams.get('ticker'); if (!fromQuery) { return; } const normalized = fromQuery.trim().toUpperCase(); if (!normalized) { return; } setTickerInput(normalized); setTicker(normalized); }, [searchParams]); const loadFinancials = useCallback(async (symbol: string) => { setLoading(true); setError(null); try { const response = await getCompanyAnalysis(symbol); setAnalysis(response.analysis); } catch (err) { setError(err instanceof Error ? err.message : 'Unable to load financial history'); setAnalysis(null); } finally { setLoading(false); } }, []); useEffect(() => { if (!isPending && isAuthenticated) { void loadFinancials(ticker); } }, [isPending, isAuthenticated, ticker, loadFinancials]); const financialSeries = useMemo(() => { return (analysis?.financials ?? []) .filter((entry): entry is CompanyAnalysis['financials'][number] & { filingType: '10-K' | '10-Q' } => { return isFinancialPeriodForm(entry.filingType); }) .slice() .sort((a, b) => Date.parse(a.filingDate) - Date.parse(b.filingDate)) .map((entry) => ({ filingDate: entry.filingDate, filingType: entry.filingType, periodKind: entry.filingType === '10-Q' ? 'quarterly' : 'fiscalYearEnd', periodLabel: entry.filingType === '10-Q' ? 'Quarter End' : 'Fiscal Year End', label: formatShortDate(entry.filingDate), revenue: entry.revenue ?? null, netIncome: entry.netIncome ?? null, totalAssets: entry.totalAssets ?? null, cash: entry.cash ?? null, debt: entry.debt ?? null, netMargin: ratioPercent(entry.netIncome ?? null, entry.revenue ?? null), debtToAssets: ratioPercent(entry.debt ?? null, entry.totalAssets ?? null) })); }, [analysis?.financials]); const chartSeries = useMemo(() => { return financialSeries.filter((point) => includesChartPeriod(point, chartPeriodFilter)); }, [financialSeries, chartPeriodFilter]); const selectedChartFilterLabel = useMemo(() => { return CHART_PERIOD_FILTER_OPTIONS.find((option) => option.value === chartPeriodFilter)?.label ?? 'Quarterly + Fiscal Year End'; }, [chartPeriodFilter]); const latestSnapshot = financialSeries[financialSeries.length - 1] ?? null; const liquidityRatio = useMemo(() => { if (!latestSnapshot || latestSnapshot.cash === null || latestSnapshot.debt === null || latestSnapshot.debt === 0) { return null; } return latestSnapshot.cash / latestSnapshot.debt; }, [latestSnapshot]); const coverage = useMemo(() => { const total = chartSeries.length; const asCoverage = (entries: number) => { if (total === 0) { return '0%'; } return `${Math.round((entries / total) * 100)}%`; }; return { total, revenue: asCoverage(chartSeries.filter((point) => point.revenue !== null).length), netIncome: asCoverage(chartSeries.filter((point) => point.netIncome !== null).length), assets: asCoverage(chartSeries.filter((point) => point.totalAssets !== null).length), cash: asCoverage(chartSeries.filter((point) => point.cash !== null).length), debt: asCoverage(chartSeries.filter((point) => point.debt !== null).length) }; }, [chartSeries]); if (isPending || !isAuthenticated) { return
Loading financial terminal...
; } return ( void loadFinancials(ticker)}> Refresh )} >
{ event.preventDefault(); const normalized = tickerInput.trim().toUpperCase(); if (!normalized) { return; } setTicker(normalized); }} > setTickerInput(event.target.value.toUpperCase())} placeholder="Ticker (AAPL)" className="max-w-xs" /> {analysis ? ( <> Open full analysis Open filings stream ) : null}
{error ? (

{error}

) : null}
= 0} />
{CHART_PERIOD_FILTER_OPTIONS.map((option) => ( ))}
{loading ? (

Loading statement data...

) : chartSeries.length === 0 ? (

No filing metrics match the current chart period filter.

) : (
AXIS_CURRENCY.format(value)} /> asTooltipCurrency(value)} />
)}
{loading ? (

Loading balance sheet data...

) : chartSeries.length === 0 ? (

No balance sheet metrics match the current chart period filter.

) : (
AXIS_CURRENCY.format(value)} /> asTooltipCurrency(value)} />
)}
{loading ? (

Loading ratio trends...

) : chartSeries.length === 0 ? (

No ratio points match the current chart period filter.

) : (
`${value.toFixed(0)}%`} /> { const normalized = normalizeTooltipValue(value); if (normalized === null) { return 'n/a'; } const numeric = Number(normalized); return Number.isFinite(numeric) ? `${numeric.toFixed(2)}%` : 'n/a'; }} />
)}
Revenue coverage
{coverage.revenue}
Net income coverage
{coverage.netIncome}
Asset coverage
{coverage.assets}
Cash coverage
{coverage.cash}
Debt coverage
{coverage.debt}
{loading ? (

Loading table...

) : financialSeries.length === 0 ? (

No financial rows are available for this ticker yet.

) : (
{financialSeries.map((point, index) => ( ))}
Filed Period Form Revenue Net Income Total Assets Cash Debt Net Margin
{formatLongDate(point.filingDate)} {point.periodLabel} {point.filingType} {asDisplayCurrency(point.revenue)} = 0 ? 'text-[#96f5bf]' : 'text-[#ff9f9f]'}>{asDisplayCurrency(point.netIncome)} {asDisplayCurrency(point.totalAssets)} {asDisplayCurrency(point.cash)} {asDisplayCurrency(point.debt)} {asDisplayPercent(point.netMargin)}
)}
Financial lens: revenue + margin + balance sheet strength
); }