From f1b1e85b53db87a04442181a40c530aca4791a14 Mon Sep 17 00:00:00 2001
From: Tyler Hoang <tyler@tylerhoang.xyz>
Date: Mon, 29 Jun 2026 01:41:20 -0700
Subject: feat: add DCF panel components

---
 frontend/components/prism/DcfResults.tsx | 81 ++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)
 create mode 100644 frontend/components/prism/DcfResults.tsx

(limited to 'frontend/components/prism/DcfResults.tsx')

diff --git a/frontend/components/prism/DcfResults.tsx b/frontend/components/prism/DcfResults.tsx
new file mode 100644
index 0000000..062f041
--- /dev/null
+++ b/frontend/components/prism/DcfResults.tsx
@@ -0,0 +1,81 @@
+"use client";
+
+import { fmtCurrency, fmtLarge, fmtPct } from "@/lib/format";
+import type { DcfComputed } from "@/lib/dcf";
+import type { DcfResult } from "@/types/api";
+
+type Props = {
+  dcf: DcfResult;
+  computed: DcfComputed | { error: string } | null;
+  livePrice: number | null;
+  sharesOutstanding: number | null;
+  currency: string;
+};
+
+export function DcfResults({ dcf, computed, livePrice, sharesOutstanding, currency }: Props) {
+  return (
+    <div className="psm-val-dcf-results">
+      <div className="psm-val-dcf-col-label">Results</div>
+
+      {computed && "error" in computed ? (
+        <p className="psm-val-dcf-error">{computed.error}</p>
+      ) : (
+        <>
+          <div className="psm-val-kv-list">
+            <div className="psm-val-kv-row">
+              <span className="psm-val-kv-label">Base FCF (TTM)</span>
+              <span className="psm-val-kv-val">
+                {dcf.base_fcf != null ? fmtLarge(dcf.base_fcf, currency) : "—"}
+              </span>
+            </div>
+            <div className="psm-val-kv-row">
+              <span className="psm-val-kv-label">Historical growth</span>
+              <span className="psm-val-kv-val">
+                {dcf.growth_rate_used != null ? fmtPct(dcf.growth_rate_used) : "—"}
+              </span>
+            </div>
+            <div className="psm-val-kv-row is-divider">
+              <span className="psm-val-kv-label">FCF PV Sum</span>
+              <span className="psm-val-kv-val">
+                {computed ? fmtLarge(computed.fcfPvSum, currency) : "—"}
+              </span>
+            </div>
+            <div className="psm-val-kv-row">
+              <span className="psm-val-kv-label">Terminal Value PV</span>
+              <span className="psm-val-kv-val">
+                {computed ? fmtLarge(computed.terminalValuePv, currency) : "—"}
+              </span>
+            </div>
+            <div className="psm-val-kv-row">
+              <span className="psm-val-kv-label">Enterprise Value</span>
+              <span className="psm-val-kv-val">
+                {computed ? fmtLarge(computed.enterpriseValue, currency) : "—"}
+              </span>
+            </div>
+            <div className="psm-val-kv-row is-total">
+              <span className="psm-val-kv-label">Net Debt</span>
+              <span className="psm-val-kv-val">
+                {dcf.net_debt != null ? fmtLarge(dcf.net_debt, currency) : "—"}
+              </span>
+            </div>
+          </div>
+          <div className="psm-val-intrinsic">
+            <span className="psm-val-intrinsic-label">Intrinsic Value</span>
+            <span className={`psm-val-intrinsic-price${livePrice != null && livePrice < 0 ? " invalid" : ""}`}>
+              {livePrice != null && livePrice < 0
+                ? "Invalid assumptions"
+                : livePrice != null
+                  ? fmtCurrency(livePrice, 2, currency)
+                  : "—"}
+            </span>
+            {sharesOutstanding != null && (
+              <span className="psm-val-intrinsic-shares">
+                {fmtLarge(sharesOutstanding, currency)} shares
+              </span>
+            )}
+          </div>
+        </>
+      )}
+    </div>
+  );
+}
-- 
cgit v1.3-2-g0d8e

