'use client' import { useState, useEffect, useCallback } from 'react' import { useLocale } from 'next-intl' import { useAccount, useSignMessage } from 'wagmi' import { getTelegramStatus, tgInit, tgUnbind, type TelegramStatus, } from '@/lib/api' import { signRequest } from '@/lib/signedRequest' import { walletErrorLabel } from '@/lib/walletError' import { confirmSign } from '@/components/wallet/SignConfirmSheet' /** * Settings → Telegram alerts card. * * Three states: * 1. Server not configured → show "ask the admin to set up the bot" * 2. Not bound → deep-link to bot + optional wallet-link code * 3. Bound → status line + link to bot for preferences * * Preferences are managed entirely inside the bot (/trump /btc /funding /kol * /conf /quiet). This card is just discovery + wallet-linking for Pro users. */ export default function TelegramCard() { const locale = useLocale() const isZh = false // i18n shelved — Chinese branches kept as dead code for future revival; see messages/zh.json const { address, isConnected } = useAccount() const { signMessageAsync } = useSignMessage() const [mounted, setMounted] = useState(false) const [status, setStatus] = useState(null) const [loading, setLoading] = useState(true) const [err, setErr] = useState('') const [busy, setBusy] = useState(false) const [code, setCode] = useState<{ code: string; deep_link: string } | null>(null) useEffect(() => { setMounted(true) }, []) const refresh = useCallback(async () => { if (!address) return setLoading(true) try { const s = await getTelegramStatus(address.toLowerCase()) setStatus(s); setErr('') } catch (e) { setErr(e instanceof Error ? e.message : 'load failed') } finally { setLoading(false) } }, [address]) useEffect(() => { refresh() }, [refresh]) // Poll while waiting for wallet-link to complete. useEffect(() => { if (!code || status?.bound) return const id = setInterval(refresh, 3000) return () => clearInterval(id) }, [code, status?.bound, refresh]) const botUsername = status?.bot_username ?? 'TrumpAlpha_bot' const botLink = `https://t.me/${botUsername}` async function handleLinkWallet() { if (!address) return setBusy(true); setErr('') try { const confirmed = await confirmSign({ label: 'Generate Telegram link code', description: 'A one-time 6-char code valid for 10 min. Paste it into the bot to link your wallet for Pro features.', }) if (!confirmed) { setBusy(false); return } const env = await signRequest({ action: 'telegram_init', wallet: address, body: null, signMessageAsync, }) const r = await tgInit(address.toLowerCase(), env) setCode({ code: r.code, deep_link: r.deep_link }) } catch (e) { setErr(walletErrorLabel(e, 'Cancelled')) } finally { setBusy(false) } } async function handleUnbind() { if (!address) return setBusy(true); setErr('') try { const confirmed = await confirmSign({ label: 'Disconnect Telegram', description: 'Unlinks this wallet from Telegram. Your free subscription stays active in the bot.', }) if (!confirmed) { setBusy(false); return } const env = await signRequest({ action: 'telegram_unbind', wallet: address, body: null, signMessageAsync, }) await tgUnbind(address.toLowerCase(), env) setCode(null) await refresh() } catch (e) { setErr(walletErrorLabel(e, 'Cancelled')) } finally { setBusy(false) } } // ── Render ─────────────────────────────────────────────────────────────── if (!mounted) return null if (!isConnected) return null return (
{/* Header */}
{isZh ? 'Telegram 提醒' : 'Telegram alerts'}
{isZh ? '高置信度信号触发时发送推送提醒' : 'Push notifications when high-conviction signals fire'}
{status?.bound && status.alerts_enabled && ( ● {isZh ? '已开启' : 'Active'} )} {status?.bound && !status.alerts_enabled && ( ○ {isZh ? '已暂停' : 'Paused'} )}
{loading && (
)} {/* Server not configured */} {!loading && status && !status.configured && (
⚠️ {isZh ? '当前服务器还没有配置 Telegram 提醒。请让管理员设置' : 'Telegram alerts are not configured on this server. Ask the operator to set'} TELEGRAM_BOT_TOKEN and TELEGRAM_BOT_USERNAME.
)} {/* Configured — main body */} {!loading && status?.configured && (
{/* Bot link row — always visible */}
✈️
{status.bound ? (isZh ? '打开机器人调整偏好(/trump /btc /funding /kol /conf /quiet)' : 'Open the bot to adjust preferences (/trump /btc /funding /kol /conf /quiet)') : (isZh ? '打开机器人并发送 /start,无需额外账号' : 'Open the bot and send /start — no account needed')}
{/* Bound: wallet status + disconnect */} {status.bound && (
{status.tg_username ? <>{isZh ? '已绑定账号' : 'Linked as'} @{status.tg_username} : <>{isZh ? '聊天 ID' : 'Chat'} #{status.chat_id}} {status.wallet_address ? ( <> · Pro · {isZh ? `已发送 ${status.total_alerts_sent ?? 0} 条提醒` : `${status.total_alerts_sent ?? 0} alerts sent`} · ) : ( <> · {isZh ? `已发送 ${status.total_alerts_sent ?? 0} 条提醒` : `${status.total_alerts_sent ?? 0} alerts sent`} )}
)} {/* Not bound: optional wallet-link for Pro */} {!status.bound && !code && (
{isZh ? '已经在机器人里了?' : 'Already in the bot?'}{' '}
)} {/* Wallet-link code flow */} {!status.bound && code && ( setCode(null)} isZh={isZh} /> )}
)} {err && (
● {err}
)}
) } // ── Subcomponents ──────────────────────────────────────────────────────────── function WalletLinkPanel({ code, link, onCancel, isZh }: { code: string; link: string; onCancel: () => void; isZh: boolean }) { const [copied, setCopied] = useState(false) function copy() { navigator.clipboard.writeText(code).then(() => { setCopied(true); setTimeout(() => setCopied(false), 1500) }).catch(() => {}) } return (
{isZh ? '绑定钱包(Pro):' : 'Link wallet (Pro):'}
  1. {isZh ? '打开机器人:' : 'Open the bot:'}  {link.replace('https://', '')} ↗
  2. {isZh ? '发送' : 'Send'} /start {code}
{isZh ? '验证码 10 分钟内有效,绑定成功后这里会自动刷新。' : 'Code expires in 10 min. This panel updates automatically once linked.'}
) }