summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Hoang <tyler@tylerhoang.xyz>2026-05-19 00:35:20 -0700
committerTyler Hoang <tyler@tylerhoang.xyz>2026-05-19 00:35:20 -0700
commitf024c46e874b3cacb7af5bf96aec376b88b86156 (patch)
tree9c1f28d5a78d1545b224f31c80beaa2640ef6286
parentf66caf34f8cb9aaff878432aa3c18b9cceb01e65 (diff)
feat: replace StatsCard with QualityCard (margins, returns, leverage)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
-rw-r--r--frontend/app/page.tsx62
-rw-r--r--frontend/components/prism/QualityCard.tsx39
2 files changed, 42 insertions, 59 deletions
diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx
index d6bde2a..6253221 100644
--- a/frontend/app/page.tsx
+++ b/frontend/app/page.tsx
@@ -11,9 +11,10 @@ import { KPIStrip } from "@/components/prism/KPIStrip";
import { Sidebar } from "@/components/prism/Sidebar";
import { TickerHeader } from "@/components/prism/TickerHeader";
import { TopBar } from "@/components/prism/TopBar";
+import { QualityCard } from "@/components/prism/QualityCard";
import { VolumeCard } from "@/components/prism/VolumeCard";
import { ApiError, api } from "@/lib/api";
-import { deltaClass, fmtCurrency, fmtLarge, fmtNumber, fmtPct } from "@/lib/format";
+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";
@@ -316,7 +317,7 @@ function OverviewClient() {
<div className="psm-column">
<ProfileCard overview={overview} />
<ShortInterestCard overview={overview} />
- <StatsCard overview={overview} />
+ <QualityCard overview={overview} />
</div>
</div>
</>
@@ -496,54 +497,6 @@ function ShortInterestCard({ overview }: { overview: TickerOverview }) {
);
}
-function StatsCard({ overview }: { overview: TickerOverview }) {
- const referenceRows = [
- { label: "Market Cap", value: fmtLarge(overview.stats.market_cap), missing: overview.stats.market_cap == null },
- { label: "P/E TTM", value: overview.stats.trailing_pe == null ? "-" : `${fmtNumber(overview.stats.trailing_pe)}x`, missing: overview.stats.trailing_pe == null },
- { label: "EPS TTM", value: fmtCurrency(overview.stats.trailing_eps), missing: overview.stats.trailing_eps == null },
- { label: "P/B", value: overview.ratios.price_to_book == null ? "-" : `${fmtNumber(overview.ratios.price_to_book)}x`, missing: overview.ratios.price_to_book == null },
- { label: "P/S", value: overview.ratios.price_to_sales == null ? "-" : `${fmtNumber(overview.ratios.price_to_sales)}x`, missing: overview.ratios.price_to_sales == null },
- { label: "EV/Sales", value: overview.ratios.ev_to_sales == null ? "-" : `${fmtNumber(overview.ratios.ev_to_sales)}x`, missing: overview.ratios.ev_to_sales == null },
- { label: "EV/EBITDA", value: overview.ratios.ev_to_ebitda == null ? "-" : `${fmtNumber(overview.ratios.ev_to_ebitda)}x`, missing: overview.ratios.ev_to_ebitda == null },
- { label: "Gross Margin", value: fmtPct(overview.ratios.gross_margin_ttm), missing: overview.ratios.gross_margin_ttm == null },
- { label: "Op Margin", value: fmtPct(overview.ratios.operating_margin_ttm), missing: overview.ratios.operating_margin_ttm == null },
- { label: "Net Margin", value: fmtPct(overview.ratios.net_margin_ttm), missing: overview.ratios.net_margin_ttm == null },
- { label: "ROE", value: fmtPct(overview.ratios.roe_ttm), missing: overview.ratios.roe_ttm == null },
- { label: "ROA", value: fmtPct(overview.ratios.roa_ttm), missing: overview.ratios.roa_ttm == null },
- { label: "ROIC", value: fmtPct(overview.ratios.roic_ttm), missing: overview.ratios.roic_ttm == null },
- { label: "D/E", value: overview.ratios.debt_to_equity == null ? "-" : `${fmtNumber(overview.ratios.debt_to_equity)}x`, missing: overview.ratios.debt_to_equity == null },
- { label: "Current Ratio", value: overview.ratios.current_ratio == null ? "-" : `${fmtNumber(overview.ratios.current_ratio)}x`, missing: overview.ratios.current_ratio == null },
- { label: "Dividend Yield", value: fmtPct(overview.ratios.dividend_yield_ttm), missing: overview.ratios.dividend_yield_ttm == null },
- { label: "Payout Ratio", value: fmtPct(overview.ratios.dividend_payout_ratio_ttm), missing: overview.ratios.dividend_payout_ratio_ttm == null }
- ];
-
- const visibleRows = referenceRows.filter((r) => !r.missing);
- const suppressedCount = referenceRows.length - visibleRows.length;
-
- return (
- <section className="psm-card">
- <div className="psm-card-head">
- <div>
- <div className="psm-eyebrow">Reference</div>
- <h2 className="psm-card-title">Reference</h2>
- </div>
- </div>
- {visibleRows.length > 0 && (
- <div className="psm-stat-list">
- {visibleRows.map((row) => (
- <StatRow key={row.label} label={row.label} value={row.value} missing={false} />
- ))}
- </div>
- )}
- {suppressedCount > 0 && (
- <p className="psm-muted-copy" style={{ marginTop: visibleRows.length > 0 ? "var(--sp-4)" : 0 }}>
- ยท Statement data incomplete
- </p>
- )}
- </section>
- );
-}
-
function DetailItem({ label, value, missing = false }: { label: string; value: string; missing?: boolean }) {
return (
<article className="psm-detail-item">
@@ -553,15 +506,6 @@ function DetailItem({ label, value, missing = false }: { label: string; value: s
);
}
-function StatRow({ label, value, missing = false }: { label: string; value: string; missing?: boolean }) {
- return (
- <div className="psm-stat-row">
- <span className="psm-stat-label">{label}</span>
- <span className={`psm-stat-value${missing ? " missing" : ""}`}>{missing ? "Unavailable" : value}</span>
- </div>
- );
-}
-
function LoadingShell() {
return (
<AppShell
diff --git a/frontend/components/prism/QualityCard.tsx b/frontend/components/prism/QualityCard.tsx
new file mode 100644
index 0000000..e220fce
--- /dev/null
+++ b/frontend/components/prism/QualityCard.tsx
@@ -0,0 +1,39 @@
+import type { TickerOverview } from "@/types/api";
+import { fmtNumber, fmtPct } from "@/lib/format";
+
+export function QualityCard({ overview }: { overview: TickerOverview }) {
+ const rows = [
+ { label: "Gross Margin", value: fmtPct(overview.ratios.gross_margin_ttm), missing: overview.ratios.gross_margin_ttm == null },
+ { label: "Op Margin", value: fmtPct(overview.ratios.operating_margin_ttm), missing: overview.ratios.operating_margin_ttm == null },
+ { label: "Net Margin", value: fmtPct(overview.ratios.net_margin_ttm), missing: overview.ratios.net_margin_ttm == null },
+ { label: "ROE", value: fmtPct(overview.ratios.roe_ttm), missing: overview.ratios.roe_ttm == null },
+ { label: "ROA", value: fmtPct(overview.ratios.roa_ttm), missing: overview.ratios.roa_ttm == null },
+ { label: "ROIC", value: fmtPct(overview.ratios.roic_ttm), missing: overview.ratios.roic_ttm == null },
+ { label: "D/E", value: overview.ratios.debt_to_equity == null ? "-" : `${fmtNumber(overview.ratios.debt_to_equity)}x`, missing: overview.ratios.debt_to_equity == null },
+ { label: "Current Ratio", value: overview.ratios.current_ratio == null ? "-" : `${fmtNumber(overview.ratios.current_ratio)}x`, missing: overview.ratios.current_ratio == null },
+ { label: "Dividend Yield", value: fmtPct(overview.ratios.dividend_yield_ttm), missing: overview.ratios.dividend_yield_ttm == null },
+ { label: "Payout Ratio", value: fmtPct(overview.ratios.dividend_payout_ratio_ttm), missing: overview.ratios.dividend_payout_ratio_ttm == null },
+ ];
+
+ const visible = rows.filter((r) => !r.missing);
+ if (!visible.length) return null;
+
+ return (
+ <section className="psm-card">
+ <div className="psm-card-head">
+ <div>
+ <div className="psm-eyebrow">Quality</div>
+ <h2 className="psm-card-title">Quality</h2>
+ </div>
+ </div>
+ <div className="psm-stat-list">
+ {visible.map((row) => (
+ <div key={row.label} className="psm-stat-row">
+ <span className="psm-stat-label">{row.label}</span>
+ <span className="psm-stat-value">{row.value}</span>
+ </div>
+ ))}
+ </div>
+ </section>
+ );
+}