'use client'; import Link from 'next/link'; import { Suspense, useCallback, useEffect, useMemo, useState } from 'react'; import { format } from 'date-fns'; import { Bar, BarChart, CartesianGrid, Legend, Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts'; import { BrainCircuit, ChartNoAxesCombined, RefreshCcw, Search } from 'lucide-react'; import { useSearchParams } from 'next/navigation'; import { AppShell } from '@/components/shell/app-shell'; 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 { asNumber, formatCompactCurrency, formatCurrency, formatPercent } from '@/lib/format'; import type { CompanyAnalysis } from '@/lib/types'; function formatShortDate(value: string) { return format(new Date(value), 'MMM yyyy'); } function hasFinancialSnapshot(filingType: CompanyAnalysis['filings'][number]['filing_type']) { return filingType === '10-K' || filingType === '10-Q'; } export default function AnalysisPage() { return ( Loading analysis desk...}> ); } function AnalysisPageContent() { 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); useEffect(() => { const fromQuery = searchParams.get('ticker'); if (!fromQuery) { return; } const normalized = fromQuery.trim().toUpperCase(); if (!normalized) { return; } setTickerInput(normalized); setTicker(normalized); }, [searchParams]); const loadAnalysis = 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 company analysis'); setAnalysis(null); } finally { setLoading(false); } }, []); useEffect(() => { if (!isPending && isAuthenticated) { void loadAnalysis(ticker); } }, [isPending, isAuthenticated, ticker, loadAnalysis]); const priceSeries = useMemo(() => { return (analysis?.priceHistory ?? []).map((point) => ({ ...point, label: formatShortDate(point.date) })); }, [analysis?.priceHistory]); const financialSeries = useMemo(() => { return (analysis?.financials ?? []) .slice() .reverse() .map((item) => ({ label: formatShortDate(item.filingDate), revenue: item.revenue, netIncome: item.netIncome, assets: item.totalAssets })); }, [analysis?.financials]); if (isPending || !isAuthenticated) { return
Loading analysis desk...
; } return ( void loadAnalysis(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 filing stream ) : null}
{error ? (

{error}

) : null}

{analysis?.company.companyName ?? ticker}

{analysis?.company.ticker ?? ticker}

{analysis?.company.sector ?? 'Sector unavailable'}

{formatCurrency(analysis?.quote ?? 0)}

CIK {analysis?.company.cik ?? 'n/a'}

{formatCurrency(analysis?.position?.market_value)}

{analysis?.position ? `${asNumber(analysis.position.shares).toLocaleString()} shares` : 'Not held in portfolio'}

= 0 ? 'text-[#96f5bf]' : 'text-[#ff9f9f]'}`}> {formatCurrency(analysis?.position?.gain_loss)}

{formatPercent(analysis?.position?.gain_loss_pct)}

{loading ? (

Loading price history...

) : priceSeries.length === 0 ? (

No price history available.

) : (
`$${value.toFixed(0)}`} /> formatCurrency(value)} />
)}
{loading ? (

Loading financials...

) : financialSeries.length === 0 ? (

No parsed filing metrics yet.

) : (
`$${Math.round(value / 1_000_000_000)}B`} /> formatCompactCurrency(value)} />
)}
{loading ? (

Loading filings...

) : !analysis || analysis.filings.length === 0 ? (

No filings available for this ticker.

) : (
{analysis.filings.map((filing) => ( ))}
Filed Type Revenue Net Income Assets Document
{format(new Date(filing.filing_date), 'MMM dd, yyyy')} {filing.filing_type}{hasFinancialSnapshot(filing.filing_type) ? '' : ' (Qualitative)'} {hasFinancialSnapshot(filing.filing_type) ? (filing.metrics?.revenue ? formatCompactCurrency(filing.metrics.revenue) : 'n/a') : 'qualitative only'} {hasFinancialSnapshot(filing.filing_type) ? (filing.metrics?.netIncome ? formatCompactCurrency(filing.metrics.netIncome) : 'n/a') : 'qualitative only'} {hasFinancialSnapshot(filing.filing_type) ? (filing.metrics?.totalAssets ? formatCompactCurrency(filing.metrics.totalAssets) : 'n/a') : 'qualitative only'} {filing.filing_url ? ( SEC filing ) : ( 'n/a' )}
)}
{loading ? (

Loading AI reports...

) : !analysis || analysis.aiReports.length === 0 ? (

No AI reports generated yet. Run filing analysis from the filings stream.

) : (
{analysis.aiReports.map((report) => (

{report.filingType} ยท {format(new Date(report.filingDate), 'MMM dd, yyyy')}

{report.provider} / {report.model}

{report.summary}

{report.accessionNumber}

Open summary
))}
)}
Analysis scope: price + filings + ai synthesis
); }