'use client'; import { useQueryClient } from '@tanstack/react-query'; import Link from 'next/link'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { Suspense } from 'react'; import { format } from 'date-fns'; import { Bot, Download, ExternalLink, Search, TimerReset } from 'lucide-react'; import { useSearchParams } from 'next/navigation'; import { AppShell } from '@/components/shell/app-shell'; import { Panel } from '@/components/ui/panel'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { useAuthGuard } from '@/hooks/use-auth-guard'; import { useLinkPrefetch } from '@/hooks/use-link-prefetch'; import { queueFilingAnalysis, queueFilingSync } from '@/lib/api'; import type { Filing } from '@/lib/types'; import { formatCurrencyByScale, type NumberScaleUnit } from '@/lib/format'; import { queryKeys } from '@/lib/query/keys'; import { filingsQueryOptions } from '@/lib/query/options'; const FINANCIAL_VALUE_SCALE_OPTIONS: Array<{ value: NumberScaleUnit; label: string }> = [ { value: 'thousands', label: 'Thousands (K)' }, { value: 'millions', label: 'Millions (M)' }, { value: 'billions', label: 'Billions (B)' } ]; export default function FilingsPage() { return ( Opening filings stream...}> ); } function formatFilingDate(value: string) { const date = new Date(value); if (Number.isNaN(date.getTime())) { return 'Unknown'; } return format(date, 'MMM dd, yyyy'); } function hasFinancialSnapshot(filing: Filing) { return filing.filing_type === '10-K' || filing.filing_type === '10-Q'; } function asScaledFinancialSnapshot( value: number | null | undefined, scale: NumberScaleUnit ) { if (value === null || value === undefined) { return 'n/a'; } return formatCurrencyByScale(value, scale); } function resolveOriginalFilingUrl(filing: Filing) { if (filing.filing_url) { return filing.filing_url; } if (!filing.primary_document) { return null; } const cikDigits = filing.cik.replace(/\D/g, ''); const cikValue = Number.parseInt(cikDigits, 10); if (!cikDigits || Number.isNaN(cikValue)) { return null; } const compactAccession = filing.accession_number.replace(/-/g, ''); if (!compactAccession) { return null; } return `https://www.sec.gov/Archives/edgar/data/${cikValue}/${compactAccession}/${filing.primary_document}`; } type FilingExternalLinkProps = { href: string; label: string; }; function FilingExternalLink({ href, label }: FilingExternalLinkProps) { return ( {label} ); } function FilingsPageContent() { const { isPending, isAuthenticated } = useAuthGuard(); const searchParams = useSearchParams(); const queryClient = useQueryClient(); const { prefetchReport } = useLinkPrefetch(); const [filings, setFilings] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [syncTickerInput, setSyncTickerInput] = useState(''); const [filterTickerInput, setFilterTickerInput] = useState(''); const [searchTicker, setSearchTicker] = useState(''); const [financialValueScale, setFinancialValueScale] = useState('millions'); useEffect(() => { const ticker = searchParams.get('ticker'); if (ticker) { const normalized = ticker.toUpperCase(); setSyncTickerInput(normalized); setFilterTickerInput(normalized); setSearchTicker(normalized); } }, [searchParams]); const loadFilings = useCallback(async (ticker?: string) => { const options = filingsQueryOptions({ ticker, limit: 120 }); if (!queryClient.getQueryData(options.queryKey)) { setLoading(true); } setError(null); try { const response = await queryClient.ensureQueryData(options); setFilings(response.filings); } catch (err) { setError(err instanceof Error ? err.message : 'Unable to fetch filings'); } finally { setLoading(false); } }, [queryClient]); useEffect(() => { if (!isPending && isAuthenticated) { void loadFilings(searchTicker || undefined); } }, [isPending, isAuthenticated, searchTicker, loadFilings]); const triggerSync = async () => { if (!syncTickerInput.trim()) { return; } try { await queueFilingSync({ ticker: syncTickerInput.trim().toUpperCase(), limit: 20 }); void queryClient.invalidateQueries({ queryKey: queryKeys.recentTasks(20) }); void queryClient.invalidateQueries({ queryKey: ['filings'] }); await loadFilings(searchTicker || undefined); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to queue filing sync'); } }; const triggerAnalysis = async (accessionNumber: string) => { try { await queueFilingAnalysis(accessionNumber); void queryClient.invalidateQueries({ queryKey: queryKeys.recentTasks(20) }); void queryClient.invalidateQueries({ queryKey: ['report'] }); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to queue filing analysis'); } }; const groupedByTicker = useMemo(() => { const counts = new Map(); for (const filing of filings) { counts.set(filing.ticker, (counts.get(filing.ticker) ?? 0) + 1); } return counts; }, [filings]); const selectedFinancialScaleLabel = useMemo(() => { return FINANCIAL_VALUE_SCALE_OPTIONS.find((option) => option.value === financialValueScale)?.label ?? 'Millions (M)'; }, [financialValueScale]); if (isPending || !isAuthenticated) { return
Opening filings stream...
; } return ( { void queryClient.invalidateQueries({ queryKey: queryKeys.filings(searchTicker || null, 120) }); void loadFilings(searchTicker || undefined); }} > Refresh table )} >
{ event.preventDefault(); void triggerSync(); }} > setSyncTickerInput(event.target.value.toUpperCase())} placeholder="Ticker (AAPL)" className="w-full sm:max-w-xs" />
{ event.preventDefault(); setSearchTicker(filterTickerInput.trim().toUpperCase()); }} > setFilterTickerInput(event.target.value.toUpperCase())} placeholder="Ticker filter" className="w-full sm:max-w-xs" />
{FINANCIAL_VALUE_SCALE_OPTIONS.map((option) => ( ))} )} > {error ?

{error}

: null} {loading ? (

Fetching filings...

) : filings.length === 0 ? (

No filings available. Queue a sync job to ingest fresh SEC data.

) : (
{filings.map((filing) => { const financialForm = hasFinancialSnapshot(filing); const revenue = filing.metrics?.revenue; const hasAnalysis = Boolean(filing.analysis?.text || filing.analysis?.legacyInsights); const originalFilingUrl = resolveOriginalFilingUrl(filing); return (

{filing.ticker} ยท {filing.filing_type}

{formatFilingDate(filing.filing_date)}

{hasAnalysis ? 'AI ready' : 'AI pending'}

{filing.company_name}

Financial Snapshot
{financialForm ? asScaledFinancialSnapshot(revenue, financialValueScale) : 'Qualitative filing'}
Accession
{filing.accession_number}
{originalFilingUrl ? ( ) : ( Original filing unavailable )} {filing.submission_url ? ( ) : null} {hasAnalysis ? ( prefetchReport(filing.ticker, filing.accession_number)} onFocus={() => prefetchReport(filing.ticker, filing.accession_number)} className="inline-flex items-center rounded-md border border-[color:var(--line-weak)] px-2 py-1 text-xs text-[color:var(--accent)] transition hover:border-[color:var(--line-strong)] hover:text-[color:var(--accent-strong)]" > Open summary ) : null}
); })}
{filings.map((filing) => { const financialForm = hasFinancialSnapshot(filing); const revenue = filing.metrics?.revenue; const hasAnalysis = Boolean(filing.analysis?.text || filing.analysis?.legacyInsights); const originalFilingUrl = resolveOriginalFilingUrl(filing); return ( ); })}
Ticker Type Filed Revenue Snapshot Company AI Links Action
{filing.ticker}
{groupedByTicker.get(filing.ticker)} filings
{filing.filing_type} {formatFilingDate(filing.filing_date)} {financialForm ? asScaledFinancialSnapshot(revenue, financialValueScale) : 'Qualitative filing'} {filing.company_name} {hasAnalysis ? 'Ready' : 'Not generated'}
{originalFilingUrl ? ( ) : ( Unavailable )} {filing.submission_url ? ( ) : null}
{hasAnalysis ? ( prefetchReport(filing.ticker, filing.accession_number)} onFocus={() => prefetchReport(filing.ticker, filing.accession_number)} className="inline-flex items-center rounded-md border border-[color:var(--line-weak)] px-2 py-1 text-xs text-[color:var(--accent)] transition hover:border-[color:var(--line-strong)] hover:text-[color:var(--accent-strong)]" > Summary ) : null}
)}
); }