summaryrefslogtreecommitdiff
path: root/frontend/components/prism
diff options
context:
space:
mode:
authorTyler Hoang <tyler@tylerhoang.xyz>2026-05-18 22:18:20 -0700
committerTyler Hoang <tyler@tylerhoang.xyz>2026-05-18 22:18:20 -0700
commit16d9eb4f864fe8c29a9dee57ec47f77b34ae0df4 (patch)
tree36d56f7ed8bc5d893fafce807f7846e6c320b1cc /frontend/components/prism
parent566f59cb00958caa073279a7bb698e1ede48c0d4 (diff)
feat: wire Ratios subtab into FinancialsPage, move tab strip up from FinancialsCard
Diffstat (limited to 'frontend/components/prism')
-rw-r--r--frontend/components/prism/FinancialsCard.tsx20
-rw-r--r--frontend/components/prism/FinancialsPage.tsx68
2 files changed, 50 insertions, 38 deletions
diff --git a/frontend/components/prism/FinancialsCard.tsx b/frontend/components/prism/FinancialsCard.tsx
index 94a6618..43a2dc2 100644
--- a/frontend/components/prism/FinancialsCard.tsx
+++ b/frontend/components/prism/FinancialsCard.tsx
@@ -9,16 +9,9 @@ type Props = {
data: FinancialsResponse;
statement: StatementKey;
period: PeriodKey;
- onChangeStatement: (s: StatementKey) => void;
onChangePeriod: (p: PeriodKey) => void;
};
-const STMT_LABELS: Record<StatementKey, string> = {
- income: "INCOME",
- balance: "BALANCE",
- cash_flow: "CASH FLOW",
-};
-
function fmtFinVal(val: number | null | undefined, isMargin: boolean): string {
if (val === null || val === undefined) return "—";
if (isMargin) return `${(val * 100).toFixed(1)}%`;
@@ -70,7 +63,6 @@ export function FinancialsCard({
data,
statement,
period,
- onChangeStatement,
onChangePeriod,
}: Props) {
const stmt = data[statement];
@@ -79,18 +71,6 @@ export function FinancialsCard({
return (
<section className="psm-card psm-financials-card">
<div className="psm-fin-header">
- <div className="psm-fin-tabs">
- {(["income", "balance", "cash_flow"] as StatementKey[]).map((key) => (
- <button
- key={key}
- type="button"
- className={`psm-fin-tab${statement === key ? " active" : ""}`}
- onClick={() => onChangeStatement(key)}
- >
- {STMT_LABELS[key]}
- </button>
- ))}
- </div>
<div className="psm-fin-period">
{(["annual", "quarterly"] as PeriodKey[]).map((p) => (
<button
diff --git a/frontend/components/prism/FinancialsPage.tsx b/frontend/components/prism/FinancialsPage.tsx
index fcd2763..9a56f2c 100644
--- a/frontend/components/prism/FinancialsPage.tsx
+++ b/frontend/components/prism/FinancialsPage.tsx
@@ -4,10 +4,12 @@ import { api } from "@/lib/api";
import { buildKpis } from "@/lib/overview";
import { FinancialsCard } from "@/components/prism/FinancialsCard";
import { KPIStrip } from "@/components/prism/KPIStrip";
+import { RatiosPage } from "@/components/prism/RatiosPage";
import { TickerHeader } from "@/components/prism/TickerHeader";
import type { FinancialsResponse, TickerOverview } from "@/types/api";
-type StatementKey = "income" | "balance" | "cash_flow";
+type StatementKey = "income" | "balance" | "cash_flow" | "ratios";
+type FinancialStatementKey = Exclude<StatementKey, "ratios">;
type PeriodKey = "annual" | "quarterly";
type FinState = "loading" | "ready" | "error";
@@ -18,6 +20,13 @@ type Props = {
onToggleWatchlist: () => void;
};
+const STATEMENT_LABELS: Record<StatementKey, string> = {
+ income: "INCOME",
+ balance: "BALANCE",
+ cash_flow: "CASH FLOW",
+ ratios: "RATIOS",
+};
+
export function FinancialsPage({ ticker, overview, isSaved, onToggleWatchlist }: Props) {
const [statement, setStatement] = useState<StatementKey>("income");
const [period, setPeriod] = useState<PeriodKey>("annual");
@@ -26,6 +35,10 @@ export function FinancialsPage({ ticker, overview, isSaved, onToggleWatchlist }:
const kpis = buildKpis(overview);
useEffect(() => {
+ if (statement === "ratios") {
+ return;
+ }
+
let cancelled = false;
setFinState("loading");
setData(null);
@@ -45,28 +58,47 @@ export function FinancialsPage({ ticker, overview, isSaved, onToggleWatchlist }:
return () => {
cancelled = true;
};
- }, [ticker, period]);
+ }, [ticker, period, statement]);
return (
<>
<TickerHeader overview={overview} isSaved={isSaved} onToggleWatchlist={onToggleWatchlist} />
<KPIStrip items={kpis} />
- {finState === "loading" && (
- <section className="psm-card psm-skeleton" style={{ minHeight: 320 }} />
- )}
- {finState === "error" && (
- <section className="psm-card">
- <p className="psm-muted-copy">Financial statements unavailable for {ticker}.</p>
- </section>
- )}
- {finState === "ready" && data && (
- <FinancialsCard
- data={data}
- statement={statement}
- period={period}
- onChangeStatement={setStatement}
- onChangePeriod={setPeriod}
- />
+ <section className="psm-fin-tab-bar">
+ <div className="psm-fin-tabs">
+ {(["income", "balance", "cash_flow", "ratios"] as StatementKey[]).map((key) => (
+ <button
+ key={key}
+ type="button"
+ className={`psm-fin-tab${statement === key ? " active" : ""}`}
+ onClick={() => setStatement(key)}
+ >
+ {STATEMENT_LABELS[key]}
+ </button>
+ ))}
+ </div>
+ </section>
+ {statement === "ratios" ? (
+ <RatiosPage ticker={ticker} />
+ ) : (
+ <>
+ {finState === "loading" && (
+ <section className="psm-card psm-skeleton" style={{ minHeight: 320 }} />
+ )}
+ {finState === "error" && (
+ <section className="psm-card">
+ <p className="psm-muted-copy">Financial statements unavailable for {ticker}.</p>
+ </section>
+ )}
+ {finState === "ready" && data && (
+ <FinancialsCard
+ data={data}
+ statement={statement as FinancialStatementKey}
+ period={period}
+ onChangePeriod={setPeriod}
+ />
+ )}
+ </>
)}
</>
);