From 40be4636e95ec57e56bb828d2c5d14386daa29ed Mon Sep 17 00:00:00 2001 From: Manus Date: Sun, 8 Mar 2026 03:45:55 -0400 Subject: [PATCH] =?UTF-8?q?Checkpoint:=20v5=20=E5=AE=8C=E6=95=B4=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=8D=87=E7=BA=A7=EF=BC=9A=201.=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E9=92=B1=E5=8C=85=E8=BF=9E=E6=8E=A5=E7=8A=B6=E6=80=81=E5=85=B1?= =?UTF-8?q?=E4=BA=AB=E9=97=AE=E9=A2=98=EF=BC=88useWallet=E6=8F=90=E5=8D=87?= =?UTF-8?q?=E5=88=B0Home=E9=A1=B6=E5=B1=82=EF=BC=89=202.=20=E9=85=8D?= =?UTF-8?q?=E7=BD=AEBSC/ETH=E5=A4=9A=E8=8A=82=E7=82=B9RPC=E6=95=85?= =?UTF-8?q?=E9=9A=9C=E8=BD=AC=E7=A7=BB=E6=B1=A0=EF=BC=889+7=E4=B8=AA?= =?UTF-8?q?=E8=8A=82=E7=82=B9=EF=BC=89=203.=20=E6=B7=BB=E5=8A=A0TRC20?= =?UTF-8?q?=E8=B4=AD=E4=B9=B0Telegram=E9=80=9A=E7=9F=A5=EF=BC=88Bot=20Toke?= =?UTF-8?q?n/Chat=20ID=E9=80=9A=E8=BF=87=E7=AE=A1=E7=90=86=E5=90=8E?= =?UTF-8?q?=E5=8F=B0=E9=85=8D=E7=BD=AE=EF=BC=89=204.=20=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=91=98=E5=90=8E=E5=8F=B0=E6=96=B0=E5=A2=9ESite=20Settings?= =?UTF-8?q?=E6=A0=87=E7=AD=BE=E9=A1=B5=EF=BC=88=E9=A2=84=E5=94=AE=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E3=80=81=E9=A6=96=E9=A1=B5=E5=86=85=E5=AE=B9=E3=80=81?= =?UTF-8?q?Telegram=E9=85=8D=E7=BD=AE=EF=BC=89=205.=20=E4=BF=AE=E5=A4=8DAd?= =?UTF-8?q?min.tsx=E8=AF=AD=E6=B3=95=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/pages/Admin.tsx | 253 ++++++++++++++++++- client/src/pages/Home.tsx | 18 +- drizzle/0004_parallel_unus.sql | 11 + drizzle/meta/0004_snapshot.json | 429 ++++++++++++++++++++++++++++++++ drizzle/meta/_journal.json | 7 + drizzle/schema.ts | 17 +- server/configDb.ts | 225 +++++++++++++++++ server/onchain.ts | 152 ++++++++--- server/routers.ts | 91 +++++++ server/telegram.ts | 169 +++++++++++++ server/trc20Monitor.ts | 14 ++ todo.md | 12 + 12 files changed, 1349 insertions(+), 49 deletions(-) create mode 100644 drizzle/0004_parallel_unus.sql create mode 100644 drizzle/meta/0004_snapshot.json create mode 100644 server/configDb.ts create mode 100644 server/telegram.ts diff --git a/client/src/pages/Admin.tsx b/client/src/pages/Admin.tsx index 8bd5873..5772cd8 100644 --- a/client/src/pages/Admin.tsx +++ b/client/src/pages/Admin.tsx @@ -119,13 +119,244 @@ function LoginForm({ onLogin }: { onLogin: (token: string) => void }) { ); } -// ─── Main Dashboard ─────────────────────────────────────────────────────────── +// ─── Main D// ─── Settings Panel ─────────────────────────────────────────────── +function SettingsPanel({ token }: { token: string }) { + const { data: configData, refetch: refetchConfig, isLoading } = trpc.admin.getConfig.useQuery({ token }); + const [editValues, setEditValues] = useState>({}); + const [savingKey, setSavingKey] = useState(null); + const [savedKeys, setSavedKeys] = useState>(new Set()); + const [telegramBotToken, setTelegramBotToken] = useState(""); + const [telegramChatId, setTelegramChatId] = useState(""); + const [telegramStatus, setTelegramStatus] = useState<"idle" | "testing" | "success" | "error">("idle"); + const [telegramError, setTelegramError] = useState(""); + + const setConfigMutation = trpc.admin.setConfig.useMutation({ + onSuccess: (_, vars) => { + setSavedKeys(prev => { const s = new Set(Array.from(prev)); s.add(vars.key); return s; }); + setSavingKey(null); + refetchConfig(); + setTimeout(() => setSavedKeys(prev => { const n = new Set(Array.from(prev)); n.delete(vars.key); return n; }), 2000); + }, + onError: (err) => { + setSavingKey(null); + alert(`Save failed: ${err.message}`); + }, + }); + + const testTelegramMutation = trpc.admin.testTelegram.useMutation({ + onSuccess: () => { + setTelegramStatus("success"); + refetchConfig(); + }, + onError: (err) => { + setTelegramStatus("error"); + setTelegramError(err.message); + }, + }); + + // Initialize edit values from config + useEffect(() => { + if (configData) { + const vals: Record = {}; + configData.forEach(c => { vals[c.key] = c.value; }); + setEditValues(vals); + // Pre-fill Telegram fields + const botToken = configData.find(c => c.key === "telegramBotToken")?.value || ""; + const chatId = configData.find(c => c.key === "telegramChatId")?.value || ""; + if (botToken) setTelegramBotToken(botToken); + if (chatId) setTelegramChatId(chatId); + } + }, [configData]); + + const handleSave = (key: string) => { + setSavingKey(key); + setConfigMutation.mutate({ token, key, value: editValues[key] || "" }); + }; + + const handleTestTelegram = () => { + if (!telegramBotToken || !telegramChatId) { + setTelegramStatus("error"); + setTelegramError("Please enter both Bot Token and Chat ID"); + return; + } + setTelegramStatus("testing"); + setTelegramError(""); + testTelegramMutation.mutate({ token, botToken: telegramBotToken, chatId: telegramChatId }); + }; + + // Group configs by category + const presaleKeys = ["presaleEndDate", "tokenPrice", "hardCap", "listingPrice", "totalSupply", "maxPurchaseUsdt", "presaleStatus"]; + const contentKeys = ["heroTitle", "heroSubtitle", "tronReceivingAddress"]; + const telegramKeys = ["telegramBotToken", "telegramChatId"]; + + const renderConfigRow = (cfg: { key: string; value: string; label: string; description: string; type: string; updatedAt: Date | null }) => ( +
+
+
+
+ {cfg.label} + {cfg.type} +
+

{cfg.description}

+ {cfg.type === "text" && cfg.key !== "heroSubtitle" ? ( + setEditValues(prev => ({ ...prev, [cfg.key]: e.target.value }))} + className="w-full px-3 py-2 rounded-lg text-sm" + style={{ background: "rgba(255,255,255,0.05)", border: "1px solid rgba(255,255,255,0.1)", color: "white", outline: "none" }} + /> + ) : cfg.key === "heroSubtitle" ? ( +