'use client'; import { useQueryClient } from '@tanstack/react-query'; import Link from 'next/link'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { format } from 'date-fns'; import { ArrowLeft, BrainCircuit, NotebookPen, RefreshCcw } from 'lucide-react'; import { useParams } from 'next/navigation'; import { AppShell } from '@/components/shell/app-shell'; import { useAuthGuard } from '@/hooks/use-auth-guard'; import { useLinkPrefetch } from '@/hooks/use-link-prefetch'; import { queryKeys } from '@/lib/query/keys'; import { aiReportQueryOptions } from '@/lib/query/options'; import type { CompanyAiReportDetail } from '@/lib/types'; import { Button } from '@/components/ui/button'; import { Panel } from '@/components/ui/panel'; import { createResearchJournalEntry } from '@/lib/api'; function formatFilingDate(value: string) { const date = new Date(value); if (Number.isNaN(date.getTime())) { return 'Unknown'; } return format(date, 'MMM dd, yyyy'); } export default function AnalysisReportPage() { const { isPending, isAuthenticated } = useAuthGuard(); const params = useParams<{ ticker: string; accessionNumber: string }>(); const queryClient = useQueryClient(); const { prefetchResearchTicker } = useLinkPrefetch(); const tickerFromRoute = useMemo(() => { const value = typeof params.ticker === 'string' ? params.ticker : ''; return value.toUpperCase(); }, [params.ticker]); const accessionNumber = useMemo(() => { const value = typeof params.accessionNumber === 'string' ? params.accessionNumber : ''; return decodeURIComponent(value); }, [params.accessionNumber]); const [report, setReport] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [savingToJournal, setSavingToJournal] = useState(false); const [journalNotice, setJournalNotice] = useState(null); const loadReport = useCallback(async () => { if (!accessionNumber) { setError('Invalid accession number.'); setReport(null); setLoading(false); return; } const options = aiReportQueryOptions(accessionNumber); if (!queryClient.getQueryData(options.queryKey)) { setLoading(true); } setError(null); try { const response = await queryClient.ensureQueryData(options); setReport(response.report); } catch (err) { setReport(null); setError(err instanceof Error ? err.message : 'Unable to load AI summary'); } finally { setLoading(false); } }, [accessionNumber, queryClient]); useEffect(() => { if (!isPending && isAuthenticated) { void loadReport(); } }, [isPending, isAuthenticated, loadReport]); if (isPending || !isAuthenticated) { return
Loading summary detail...
; } const resolvedTicker = report?.ticker ?? tickerFromRoute; const analysisHref = resolvedTicker ? `/analysis?ticker=${encodeURIComponent(resolvedTicker)}` : '/analysis'; const filingsHref = resolvedTicker ? `/filings?ticker=${encodeURIComponent(resolvedTicker)}` : '/filings'; return ( { if (accessionNumber) { void queryClient.invalidateQueries({ queryKey: queryKeys.report(accessionNumber) }); } void loadReport(); }} disabled={loading} > Refresh )} >
prefetchResearchTicker(resolvedTicker)} onFocus={() => prefetchResearchTicker(resolvedTicker)} className="inline-flex items-center gap-1 text-xs uppercase tracking-[0.12em] text-[color:var(--accent)] hover:text-[color:var(--accent-strong)]" > Back to analysis prefetchResearchTicker(resolvedTicker)} onFocus={() => prefetchResearchTicker(resolvedTicker)} className="inline-flex items-center gap-1 text-xs uppercase tracking-[0.12em] text-[color:var(--accent)] hover:text-[color:var(--accent-strong)]" > Back to filings
{loading ? (

Loading AI summary...

) : null} {!loading && error ? (

{error}

) : null} {!loading && !error && report ? ( <>

Accession

{report.accessionNumber}

Provider

{report.provider}

Model

{report.model}

Full text view
{journalNotice ? (

{journalNotice}

) : null}

{report.summary}

) : null}
); }