'use client'; import { useQueryClient } from '@tanstack/react-query'; import { Suspense, useCallback, useEffect, useMemo, useState } from 'react'; import { useSearchParams } from 'next/navigation'; import { AppShell } from '@/components/shell/app-shell'; import { CompanyAnalysisSkeleton } from '@/components/analysis/company-analysis-skeleton'; import { AnalysisToolbar } from '@/components/analysis/analysis-toolbar'; import { BullBearPanel } from '@/components/analysis/bull-bear-panel'; import { CompanyOverviewCard } from '@/components/analysis/company-overview-card'; import { CompanyProfileFactsTable } from '@/components/analysis/company-profile-facts-table'; import { PriceHistoryCard } from '@/components/analysis/price-history-card'; import { RecentDevelopmentsSection } from '@/components/analysis/recent-developments-section'; import { ValuationFactsTable } from '@/components/analysis/valuation-facts-table'; import { Panel } from '@/components/ui/panel'; import { useAuthGuard } from '@/hooks/use-auth-guard'; import { useLinkPrefetch } from '@/hooks/use-link-prefetch'; import { ensureTickerAutomation } from '@/lib/api'; import { buildGraphingHref } from '@/lib/graphing/catalog'; import { queryKeys } from '@/lib/query/keys'; import { companyAnalysisQueryOptions } from '@/lib/query/options'; import type { CompanyAnalysis } from '@/lib/types'; function normalizeTickerInput(value: string | null) { const normalized = value?.trim().toUpperCase() ?? ''; return normalized || null; } export default function AnalysisPage() { return ( Loading overview...}> ); } function AnalysisPageContent() { const { isPending, isAuthenticated } = useAuthGuard(); const searchParams = useSearchParams(); const queryClient = useQueryClient(); const { prefetchResearchTicker } = useLinkPrefetch(); const initialTicker = normalizeTickerInput(searchParams.get('ticker')) ?? 'MSFT'; const [tickerInput, setTickerInput] = useState(initialTicker); const [ticker, setTicker] = useState(initialTicker); const [analysis, setAnalysis] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const normalized = normalizeTickerInput(searchParams.get('ticker')); if (!normalized) { return; } setTickerInput(normalized); setTicker(normalized); }, [searchParams]); const loadAnalysis = useCallback(async (symbol: string, options?: { refresh?: boolean }) => { const queryOptions = companyAnalysisQueryOptions(symbol, options); if (!queryClient.getQueryData(queryOptions.queryKey)) { setLoading(true); } setError(null); try { const response = await queryClient.fetchQuery(queryOptions); setAnalysis(response.analysis); } catch (err) { setError(err instanceof Error ? err.message : 'Unable to load company overview'); setAnalysis((current) => { const normalizedTicker = symbol.trim().toUpperCase(); if (options?.refresh && current?.company.ticker === normalizedTicker) { return current; } return null; }); } finally { setLoading(false); } }, [queryClient]); useEffect(() => { if (!isPending && isAuthenticated) { void loadAnalysis(ticker); } }, [isPending, isAuthenticated, loadAnalysis, ticker]); const activeTicker = analysis?.company.ticker ?? ticker; const quickLinks = useMemo(() => ({ research: `/research?ticker=${encodeURIComponent(activeTicker)}`, filings: `/filings?ticker=${encodeURIComponent(activeTicker)}`, financials: `/financials?ticker=${encodeURIComponent(activeTicker)}`, graphing: buildGraphingHref(activeTicker) }), [activeTicker]); if (isPending || !isAuthenticated) { return Loading overview...; } return ( { event.preventDefault(); const normalized = tickerInput.trim().toUpperCase(); if (!normalized) { return; } void ensureTickerAutomation({ ticker: normalized, source: 'analysis' }); setTicker(normalized); }} onRefresh={() => { const normalizedTicker = activeTicker.trim().toUpperCase(); void queryClient.invalidateQueries({ queryKey: queryKeys.companyAnalysis(normalizedTicker) }); void loadAnalysis(normalizedTicker, { refresh: true }); }} quickLinks={quickLinks} onLinkPrefetch={() => prefetchResearchTicker(activeTicker)} /> {error ? ( {error} ) : null} {!analysis && loading ? ( ) : analysis ? ( <> prefetchResearchTicker(activeTicker)} /> > ) : ( No overview is available for the selected ticker. )} ); }
{error}
No overview is available for the selected ticker.