diff --git a/frontend/components/dashboard/ScanTerminalDashboard.tsx b/frontend/components/dashboard/ScanTerminalDashboard.tsx index 063830ce..79cdc9ee 100644 --- a/frontend/components/dashboard/ScanTerminalDashboard.tsx +++ b/frontend/components/dashboard/ScanTerminalDashboard.tsx @@ -19,6 +19,17 @@ import { UserRound, } from "lucide-react"; import { useEffect, useMemo, useState } from "react"; +import { + Area, + AreaChart, + Bar, + BarChart as ReBarChart, + CartesianGrid, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from "recharts"; import type { ProAccessState, ScanOpportunityRow } from "@/lib/dashboard-types"; import { getInitialLocaleFromNavigator } from "@/lib/i18n"; import { isBrowserLocalFullAccess } from "@/lib/local-dev-access"; @@ -114,23 +125,91 @@ function decisionClass(label: string) { return "border-amber-200 bg-amber-50 text-amber-700"; } -function MiniSparkline({ tone = "blue" }: { tone?: "blue" | "emerald" | "red" }) { - const stroke = - tone === "emerald" ? "#059669" : tone === "red" ? "#dc2626" : "#2563eb"; +function SparkArea({ + color = "#2563eb", + data, +}: { + color?: string; + data: { v: number }[]; +}) { + if (!data.length) { + return ( +
+ No data +
+ ); + } return ( - + + + + + + + + + + + + ); +} + +function ProbabilityDistributionChart({ + points, +}: { + points?: ScanOpportunityRow["distribution_preview"]; +}) { + if (!points?.length) { + return ( +
+ No distribution data +
+ ); + } + const chartData = points.map((p) => ({ + label: p.label || "", + model: Number((p.model_probability ?? 0) * 100), + market: Number((p.market_probability ?? 0) * 100), + })); + return ( + + + + + `${v}%`} + /> + + `${Number(value).toFixed(1)}%` + } + /> + + + + ); } @@ -445,9 +524,23 @@ function KoyfinWeatherTerminal({
Intraday Performance
- = 0 ? "emerald" : "red"} - /> +
+ = 0 + ? "#059669" + : "#dc2626" + } + data={ + selectedRow?.distribution_preview?.map((p) => ({ + v: + typeof p === "number" + ? p + : p.model_probability ?? 0, + })) || [] + } + /> +
Edge {pct(selectedRow?.edge_percent)} @@ -460,21 +553,14 @@ function KoyfinWeatherTerminal({
- -
- {[ - ["Model Probability", selectedRow?.model_probability ?? selectedRow?.model_event_probability, "blue"], - ["Market Probability", selectedRow?.market_probability ?? selectedRow?.market_event_probability, "emerald"], - ["Peak Probability", selectedRow?.peak_probability, "red"], - ].map(([label, value, tone]) => ( -
-
- {label} - {pct(value)} -
- -
- ))} + +
+
diff --git a/frontend/public/logo.png b/frontend/public/logo.png new file mode 100644 index 00000000..db665596 Binary files /dev/null and b/frontend/public/logo.png differ