From 927a77d68b138778690d380fe7931cc37ce06c9e Mon Sep 17 00:00:00 2001
From: Tyler Hoang <tyler@tylerhoang.xyz>
Date: Tue, 19 May 2026 00:41:35 -0700
Subject: feat: fetch valuation on overview tab, add DCF block to
 ValuationOverviewCard

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---
 frontend/app/page.tsx | 35 +++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

(limited to 'frontend/app/page.tsx')

diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx
index 150aaff..07bdfa4 100644
--- a/frontend/app/page.tsx
+++ b/frontend/app/page.tsx
@@ -17,10 +17,11 @@ import { VolumeCard } from "@/components/prism/VolumeCard";
 import { ApiError, api } from "@/lib/api";
 import { deltaClass, fmtNumber, fmtPct } from "@/lib/format";
 import { buildKpis, limitIndices, marketClock, OVERVIEW_NAV_ITEMS, signalTone } from "@/lib/overview";
-import type { HistoryPoint, MarketIndex, SearchResult, TickerOverview, WatchlistResponse } from "@/types/api";
+import type { HistoryPoint, MarketIndex, SearchResult, TickerOverview, ValuationResponse, WatchlistResponse } from "@/types/api";
 
 type LoadState = "idle" | "loading" | "ready" | "invalid" | "error";
 type ChartState = "idle" | "loading" | "ready" | "error";
+type ValState = "idle" | "loading" | "ready" | "error";
 
 export default function OverviewPage() {
   return (
@@ -49,6 +50,8 @@ function OverviewClient() {
   const [overviewError, setOverviewError] = useState<string | null>(null);
   const [chartState, setChartState] = useState<ChartState>("idle");
   const [chartError, setChartError] = useState<string | null>(null);
+  const [valuation, setValuation] = useState<ValuationResponse | null>(null);
+  const [valState, setValState] = useState<ValState>("idle");
   const [watchlistError, setWatchlistError] = useState<string | null>(null);
   const [clockSnapshot, setClockSnapshot] = useState(() => marketClock());
 
@@ -229,6 +232,34 @@ function OverviewClient() {
     };
   }, [selectedTicker, period]);
 
+  useEffect(() => {
+    if (!selectedTicker) {
+      setValuation(null);
+      setValState("idle");
+      return;
+    }
+
+    let cancelled = false;
+    setValState("loading");
+    setValuation(null);
+
+    api
+      .valuation(selectedTicker)
+      .then((res) => {
+        if (!cancelled) {
+          setValuation(res);
+          setValState("ready");
+        }
+      })
+      .catch(() => {
+        if (!cancelled) setValState("error");
+      });
+
+    return () => {
+      cancelled = true;
+    };
+  }, [selectedTicker]);
+
   async function onSearchSubmit(event: FormEvent<HTMLFormElement>) {
     event.preventDefault();
     if (results[0]) {
@@ -318,7 +349,7 @@ function OverviewClient() {
               <div className="psm-column">
                 <ProfileCard overview={overview} />
                 <ShortInterestCard overview={overview} />
-                <ValuationOverviewCard overview={overview} />
+                <ValuationOverviewCard overview={overview} valuation={valuation} valState={valState} />
                 <QualityCard overview={overview} />
               </div>
             </div>
-- 
cgit v1.3-2-g0d8e

