diff --git a/frontend/components/dashboard/ScanTerminalDashboard.tsx b/frontend/components/dashboard/ScanTerminalDashboard.tsx index 36dc5408..64a47bd9 100644 --- a/frontend/components/dashboard/ScanTerminalDashboard.tsx +++ b/frontend/components/dashboard/ScanTerminalDashboard.tsx @@ -99,6 +99,66 @@ function edgeClass(value: unknown) { return n > 0 ? "text-emerald-700" : "text-red-600"; } +const TERM = { + cityContract: { en: "City / Contract", zh: "城市 / 合约" }, + live: { en: "Live", zh: "实测" }, + deb: { en: "DEB", zh: "DEB" }, + mkt: { en: "Mkt", zh: "市场" }, + edge: { en: "Edge", zh: "优势" }, + liq: { en: "Liq", zh: "流动性" }, + signal: { en: "Signal", zh: "信号" }, + searchPlaceholder: { en: "Search city, contract, station, or signal", zh: "搜索城市、合约、站点或信号" }, + weatherContracts: { en: "Weather Contracts", zh: "天气合约" }, + approvedSignals: { en: "Approved Signals", zh: "已确认信号" }, + selectedContractMonitor: { en: "Selected Contract Monitor", zh: "选中合约监控" }, + probabilityDistribution: { en: "Probability Distribution", zh: "概率分布" }, + marketList: { en: "Market List", zh: "市场列表" }, + watchlist: { en: "Watchlist", zh: "观察列表" }, + rows: { en: "Rows", zh: "行数" }, + avgEdge: { en: "Avg Edge", zh: "平均优势" }, + liquidity: { en: "Liquidity", zh: "流动性" }, + intradayPerformance: { en: "Intraday Performance", zh: "日内表现" }, + spread: { en: "Spread", zh: "价差" }, + model: { en: "Model", zh: "模型" }, + noData: { en: "No data", zh: "无数据" }, + noDistributionData: { en: "No distribution data", zh: "无分布数据" }, + selectContract: { + en: "Select a weather contract to inspect model edge, market price, and live evidence.", + zh: "选择天气合约以查看模型优势、市场价格和实况证据。", + }, + signInToContinue: { en: "Sign in to continue", zh: "请先登录" }, + signInHint: { + en: "The terminal is only available to registered users. Please sign in or create an account.", + zh: "决策台仅对注册用户开放。请登录或创建账号。", + }, + logIn: { en: "Log in", zh: "登录" }, + createAccount: { en: "Create an account", zh: "注册账号" }, + learnAbout: { en: "Learn about PolyWeather", zh: "了解 PolyWeather" }, + proAccessRequired: { en: "Pro Access Required", zh: "需要付费订阅" }, + proDesc: { + en: "The PolyWeather terminal is a paid product. Subscribe to unlock real-time weather-market intelligence.", + zh: "PolyWeather 决策台为付费产品。订阅以解锁实时天气市场情报。", + }, + subscriptionTerms: { + en: "Billed monthly. Cancel anytime. Payment via USDC on Polygon.", + zh: "按月计费,随时可取消。通过 Polygon 链 USDC 支付。", + }, + month: { en: "/ month", zh: "/ 月" }, + subscribeNow: { en: "Subscribe Now — $10/mo", zh: "立即订阅 — $10/月" }, + subscribePrompt: { + en: "You need an active subscription to access the terminal.", + zh: "你需要开通有效订阅才能访问决策台。", + }, + backToProduct: { en: "Back to product overview", zh: "返回产品介绍页" }, + dashboard: { en: "Weather Market Dashboard", zh: "天气市场数据仪表盘" }, + refresh: { en: "Refresh", zh: "刷新" }, + switchLang: { en: "Switch to Chinese", zh: "切换到英文" }, +} as const; + +function t(key: keyof typeof TERM, isEn: boolean) { + return isEn ? TERM[key].en : TERM[key].zh; +} + function decisionLabel(row?: ScanOpportunityRow | null) { const raw = row?.ai_decision || @@ -128,14 +188,16 @@ function decisionClass(label: string) { function SparkArea({ color = "#2563eb", data, + isEn = true, }: { color?: string; data: { v: number }[]; + isEn?: boolean; }) { if (!data.length) { return (
- No data + {t("noData", isEn)}
); } @@ -164,13 +226,15 @@ function SparkArea({ function ProbabilityDistributionChart({ points, + isEn = true, }: { points?: ScanOpportunityRow["distribution_preview"]; + isEn?: boolean; }) { if (!points?.length) { return (
- No distribution data + {t("noDistributionData", isEn)}
); } @@ -206,8 +270,8 @@ function ProbabilityDistributionChart({ `${Number(value).toFixed(1)}%` } /> - - + + ); @@ -246,23 +310,25 @@ function MarketTable({ onSelect, rows, selectedId, + isEn = true, }: { onSelect: (row: ScanOpportunityRow) => void; rows: ScanOpportunityRow[]; selectedId?: string | null; + isEn?: boolean; }) { return (
- - - - - - - + + + + + + + @@ -395,7 +461,7 @@ function KoyfinWeatherTerminal({
- Search city, contract, station, or signal + {t("searchPlaceholder", isEn)} / @@ -403,7 +469,7 @@ function KoyfinWeatherTerminal({
- {isEn ? "Weather Market Dashboard" : "天气市场数据仪表盘"} + {t("dashboard", isEn)}
@@ -411,8 +477,8 @@ function KoyfinWeatherTerminal({ {/* Language toggle — matches landing page style */}
- +
- Rows + {t("rows", isEn)}
{rows.length}
- Avg Edge + {t("avgEdge", isEn)}
{pct(avgEdge)} @@ -476,7 +542,7 @@ function KoyfinWeatherTerminal({
- Liquidity + {t("liquidity", isEn)}
{money(totalLiquidity)} @@ -487,10 +553,11 @@ function KoyfinWeatherTerminal({ rows={topRows} selectedId={selectedRow?.id} onSelect={setSelectedRow} + isEn={isEn} /> - +
{(approveRows.length ? approveRows : topRows.slice(0, 5)).map((row) => (
@@ -726,7 +796,7 @@ function SubscriptionGate({ isEn }: { isEn: boolean }) {
$10 - {isEn ? "/ month" : "/ 月"} + {t("month", isEn)}
@@ -750,7 +820,7 @@ function SubscriptionGate({ isEn }: { isEn: boolean }) { className="flex w-full items-center justify-center gap-2 rounded-xl bg-blue-600 py-3.5 text-sm font-black text-white shadow-sm transition hover:bg-blue-700" > - {isEn ? "Subscribe Now — $10/mo" : "立即订阅 — $10/月"} + {t("subscribeNow", isEn)}

@@ -767,7 +837,7 @@ function SubscriptionGate({ isEn }: { isEn: boolean }) { href="/" className="text-xs text-slate-500 hover:text-slate-800 transition-colors" > - ← {isEn ? "Back to product overview" : "返回产品介绍页"} + ← {t("backToProduct", isEn)}

@@ -801,7 +871,7 @@ function UnauthenticatedGate({

- {isEn ? "Sign in to continue" : "请先登录"} + {t("signInToContinue", isEn)}

{isEn

City / ContractLiveDEBMktEdgeLiqSignal{t("cityContract", isEn)}{t("live", isEn)}{t("deb", isEn)}{t("mkt", isEn)}{t("edge", isEn)}{t("liq", isEn)}{t("signal", isEn)}