From 08be1173cb46d76949cf8fa9669cad2006fa1bee Mon Sep 17 00:00:00 2001 From: NAC Admin Date: Fri, 20 Mar 2026 08:30:04 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=B4=AD=E4=B9=B0?= =?UTF-8?q?=E6=8C=89=E9=92=AE=E7=BC=BA=E5=A4=B1=E9=97=AE=E9=A2=98=20-=20?= =?UTF-8?q?=E5=BD=93=E9=92=B1=E5=8C=85=E8=BF=9E=E6=8E=A5=E4=BD=86=E7=BD=91?= =?UTF-8?q?=E7=BB=9C=E4=B8=8D=E5=AF=B9=E6=97=B6=E6=98=BE=E7=A4=BA=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E7=BD=91=E7=BB=9C=E6=8C=89=E9=92=AE=E8=80=8C=E9=9D=9E?= =?UTF-8?q?=20null?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题原因: EVMPurchasePanel 中 isWrongNetwork ? null 导致购买按钮完全不渲染 修复方案: 将 null 替换为切换网络按钮,引导用户切换到正确网络 修复时间: 2026-03-20 修复文件: client/src/pages/Home.tsx (第498行) --- client/src/pages/Home.tsx | 489 +++++++++++++------------------------- 1 file changed, 159 insertions(+), 330 deletions(-) diff --git a/client/src/pages/Home.tsx b/client/src/pages/Home.tsx index 83ebe99..4d9d971 100644 --- a/client/src/pages/Home.tsx +++ b/client/src/pages/Home.tsx @@ -112,48 +112,8 @@ function TRC20Panel({ usdtAmount, lang, connectedAddress, onConnectWallet }: { u const [evmAddress, setEvmAddress] = useState(connectedAddress || ""); const [evmAddrError, setEvmAddrError] = useState(""); const [submitted, setSubmitted] = useState(false); - // TronLink detection state + // TronLink detection state — now handled by WalletSelector(showTron=true) const [tronAddress, setTronAddress] = useState(null); - const [isTronConnecting, setIsTronConnecting] = useState(false); - const hasTronLink = typeof window !== "undefined" && (!!(window as unknown as Record).tronWeb || !!(window as unknown as Record).tronLink); - - // Auto-detect TronLink on mount - useEffect(() => { - const detectTron = async () => { - // Wait briefly for TronLink to inject - await new Promise(resolve => setTimeout(resolve, 500)); - const tronWeb = (window as unknown as Record).tronWeb as { defaultAddress?: { base58?: string }; ready?: boolean } | undefined; - if (tronWeb && tronWeb.ready && tronWeb.defaultAddress?.base58) { - setTronAddress(tronWeb.defaultAddress.base58); - } - }; - detectTron(); - }, []); - - // Connect TronLink wallet - const handleConnectTronLink = async () => { - setIsTronConnecting(true); - try { - const tronLink = (window as unknown as Record).tronLink as { request?: (args: { method: string }) => Promise<{ code: number }> } | undefined; - const tronWeb = (window as unknown as Record).tronWeb as { defaultAddress?: { base58?: string }; ready?: boolean } | undefined; - if (tronLink?.request) { - const result = await tronLink.request({ method: 'tron_requestAccounts' }); - if (result?.code === 200 && tronWeb?.defaultAddress?.base58) { - setTronAddress(tronWeb.defaultAddress.base58); - toast.success(lang === "zh" ? "TronLink已连接!" : "TronLink connected!"); - } - } else if (tronWeb?.ready && tronWeb.defaultAddress?.base58) { - setTronAddress(tronWeb.defaultAddress.base58); - toast.success(lang === "zh" ? "TronLink已检测到!" : "TronLink detected!"); - } else { - toast.error(lang === "zh" ? "请安装TronLink钱包扩展" : "Please install TronLink wallet extension"); - } - } catch { - toast.error(lang === "zh" ? "连接TronLink失败" : "Failed to connect TronLink"); - } finally { - setIsTronConnecting(false); - } - }; // Auto-fill EVM address whenever wallet connects or address changes (unless user already submitted) useEffect(() => { @@ -199,12 +159,12 @@ function TRC20Panel({ usdtAmount, lang, connectedAddress, onConnectWallet }: { u
⚠️

- {lang === "zh" ? "必填:您的XIC接收地址(BSC/ETH钱包地址)" : "Required: Your XIC Receiving Address (BSC/ETH wallet address)"} + {lang === "zh" ? "必填:您的XIC接收地址(BSC/ETH钉包地址)" : "Required: Your XIC Receiving Address (BSC/ETH wallet address)"}

{lang === "zh" - ? "XIC代币将发放到您的BSC/ETH钱包地址(0x开头)。请确保填写正确的地址,否则无法收到代币。" + ? "XIC代币将发放到您的BSC/ETH钉包地址(0x开头)。请确保填写正确的地址,否则无法收到代币。" : "XIC tokens will be sent to your BSC/ETH wallet address (starts with 0x). Please make sure to enter the correct address."}

@@ -213,7 +173,7 @@ function TRC20Panel({ usdtAmount, lang, connectedAddress, onConnectWallet }: { u { + onAddressDetected={(addr) => { setEvmAddress(addr); setEvmAddrError(""); toast.success(lang === "zh" ? "XIC接收地址已自动填充!" : "XIC receiving address auto-filled!"); @@ -252,7 +212,7 @@ function TRC20Panel({ usdtAmount, lang, connectedAddress, onConnectWallet }: { u
- {/* TronLink Wallet Detection */} + {/* TronLink Wallet Detection — using unified WalletSelector with showTron=true */}
@@ -261,7 +221,7 @@ function TRC20Panel({ usdtAmount, lang, connectedAddress, onConnectWallet }: { u

- {lang === "zh" ? "TronLink 钱包(可选)" : "TronLink Wallet (Optional)"} + {lang === "zh" ? "连接 TronLink 钱包(可选)" : "Connect TronLink Wallet (Optional)"}

{tronAddress ? ( @@ -283,45 +243,28 @@ function TRC20Panel({ usdtAmount, lang, connectedAddress, onConnectWallet }: { u
) : (
-

+

{lang === "zh" - ? "如果您使用 TronLink 钱包,可以连接后自动验证您的 TRON 地址。" - : "If you use TronLink wallet, connect to auto-verify your TRON address."} + ? "连接 TronLink 可自动验证您的 TRON 地址。手机用户可通过 TronLink App 内置浏览器打开本页面。" + : "Connect TronLink to auto-verify your TRON address. Mobile users can open this page in TronLink App's built-in browser."}

- {hasTronLink ? ( - - ) : ( - - {lang === "zh" ? "安装 TronLink 钱包 →" : "Install TronLink Wallet →"} - - )} + { + if (network === "tron") { + setTronAddress(addr); + toast.success(lang === "zh" ? "TronLink 已连接!" : "TronLink connected!"); + } else { + // EVM address detected in TRC20 panel — use as XIC receiving address + setEvmAddress(addr); + setEvmAddrError(""); + toast.success(lang === "zh" ? "XIC接收地址已自动填充!" : "XIC receiving address auto-filled!"); + if (onConnectWallet) onConnectWallet(); + } + }} + />
)} @@ -391,7 +334,8 @@ function EVMPurchasePanel({ network, lang, wallet }: { network: "BSC" | "ETH"; l const usdtAmount = parseFloat(usdtInput) || 0; const tokenAmount = calcTokens(usdtAmount); - const isValidAmount = usdtAmount > 0 && usdtAmount <= PRESALE_CONFIG.maxPurchaseUSDT; + // maxPurchaseUSDT=0 means no limit; otherwise check against the limit + const isValidAmount = usdtAmount > 0 && (PRESALE_CONFIG.maxPurchaseUSDT === 0 || usdtAmount <= PRESALE_CONFIG.maxPurchaseUSDT); const handleBuy = async () => { if (!isValidAmount) { @@ -413,74 +357,7 @@ function EVMPurchasePanel({ network, lang, wallet }: { network: "BSC" | "ETH"; l } }, [purchaseState.step, purchaseState.error, purchaseState.tokenAmount, lang]); - if (!wallet.isConnected) { - return ( -
-

{t("buy_connect_msg")}

- { - await wallet.forceConnect(addr, provider); - toast.success(lang === "zh" ? `钱包已连接: ${addr.slice(0, 6)}...${addr.slice(-4)}` : `Wallet connected: ${addr.slice(0, 6)}...${addr.slice(-4)}`); - // Auto-trigger wallet_watchAsset directly via provider — makes wallet pop open so user sees it's connected - setTimeout(async () => { - try { - await (provider as { request: (a: { method: string; params?: unknown[] }) => Promise }).request({ - method: "wallet_watchAsset", - params: [{ - type: "ERC20", - options: { - address: CONTRACTS.BSC.token, - symbol: "XIC", - decimals: 18, - image: "https://d2xsxph8kpxj0f.cloudfront.net/310519663287655625/Ngki3MumDNGduV3xJt3mga/nac-token-icon_382e5c30.png", - }, - }], - }); - } catch { /* ignore */ } - }, 800); - }} - compact - /> -
{t("buy_connect_hint")}
-
- ); - } - - if (isWrongNetwork) { - return ( -
-
-
⚠️
-

{t("buy_wrong_network")}

-

{t("buy_wrong_msg")} {CONTRACTS[network].chainName}

- -
-
- ); - } - - if (purchaseState.step === "success") { - const handleAddToken = async () => { - try { - // Use wallet.watchAsset() which uses the user's connected wallet provider (not window.ethereum) - const success = await wallet.watchAsset(network); - if (success) { - toast.success(t("add_token_success")); - } else { - toast.error(t("add_token_fail")); - } - } catch { - toast.error(t("add_token_fail")); - } - }; - + if (purchaseState.step === "success") { return (
🎉
@@ -500,35 +377,6 @@ function EVMPurchasePanel({ network, lang, wallet }: { network: "BSC" | "ETH"; l {t("buy_view_explorer")} )} - {/* Add XIC to Wallet Button */} - - {/* WhatsApp Support */} -
-

{t("support_whatsapp_msg")}

- - - - - {t("support_whatsapp_btn")} - -
@@ -540,16 +388,32 @@ function EVMPurchasePanel({ network, lang, wallet }: { network: "BSC" | "ETH"; l return (
- {/* Wallet info */} -
-
-
- {shortenAddress(wallet.address || "")} + {/* Wallet info — only shown when connected */} + {wallet.isConnected && !isWrongNetwork && ( +
+
+
+ {shortenAddress(wallet.address || "")} +
+ {usdtBalance !== null && ( + {t("buy_balance")} {usdtBalance.toFixed(2)} USDT + )}
- {usdtBalance !== null && ( - {t("buy_balance")} {usdtBalance.toFixed(2)} USDT - )} -
+ )} + {/* Wrong network banner */} + {isWrongNetwork && ( +
+
⚠️
+

{t("buy_wrong_network")}

+

{t("buy_wrong_msg")} {CONTRACTS[network].chainName}

+ +
+ )} {/* USDT Amount Input */}
@@ -617,23 +481,99 @@ function EVMPurchasePanel({ network, lang, wallet }: { network: "BSC" | "ETH"; l
)} - {/* Buy Button */} - + {/* Buy Button — or Connect Wallet if not connected */} + {!wallet.isConnected ? ( +
+

{t("buy_connect_msg")}

+ { + toast.success(lang === "zh" ? `已连接: ${addr.slice(0, 6)}...${addr.slice(-4)}` : `Connected: ${addr.slice(0, 6)}...${addr.slice(-4)}`); + }} + compact + /> +
{t("buy_connect_hint")}
+
+ ) : isWrongNetwork ? ( + + ) : ( + + )}

- {t("buy_no_min_max")} ${PRESALE_CONFIG.maxPurchaseUSDT.toLocaleString()} USDT + {PRESALE_CONFIG.maxPurchaseUSDT > 0 + ? `${t("buy_no_min_max")} $${PRESALE_CONFIG.maxPurchaseUSDT.toLocaleString()} USDT` + : (lang === "zh" ? "无最低/最高购买限制" : "No minimum or maximum purchase limit")}

+ + {/* Add XIC to Wallet button — only show on BSC where token address is known */} + {network === "BSC" && CONTRACTS.BSC.token && ( + + )}
); } @@ -870,7 +810,7 @@ function ChatSupport({ lang }: { lang: Lang }) { // ─── Navbar Wallet Button ───────────────────────────────────────────────────── type WalletHookReturn = ReturnType; -function NavWalletButton({ lang, wallet, onNetworkDetected }: { lang: Lang; wallet: WalletHookReturn; onNetworkDetected?: (chainId: number) => void }) { +function NavWalletButton({ lang, wallet }: { lang: Lang; wallet: WalletHookReturn }) { const { t } = useTranslation(lang); const [showMenu, setShowMenu] = useState(false); const [showWalletModal, setShowWalletModal] = useState(false); @@ -924,12 +864,12 @@ function NavWalletButton({ lang, wallet, onNetworkDetected }: { lang: Lang; wall {/* Wallet Connection Modal */} {showWalletModal && (
{ if (e.target === e.currentTarget) setShowWalletModal(false); }} >
{/* Close button */} @@ -966,35 +906,17 @@ function NavWalletButton({ lang, wallet, onNetworkDetected }: { lang: Lang; wall { - // Use the specific provider from WalletSelector (OKX/MetaMask/TP etc.) - await wallet.forceConnect(addr, provider); - setShowWalletModal(false); - toast.success(lang === "zh" ? `钱包已连接: ${addr.slice(0, 6)}...${addr.slice(-4)}` : `Wallet connected: ${addr.slice(0, 6)}...${addr.slice(-4)}`); - // Auto-switch to the network matching the wallet's current chain - // Get chainId directly from provider (not from wallet state which may not be updated yet) - try { - const chainHex = await (provider as { request: (a: { method: string }) => Promise }).request({ method: "eth_chainId" }); - const chainId = parseInt(chainHex, 16); - if (onNetworkDetected) onNetworkDetected(chainId); - } catch { /* ignore */ } - // Auto-trigger wallet_watchAsset directly via provider — makes wallet pop open so user sees it's connected - setTimeout(async () => { - try { - await (provider as { request: (a: { method: string; params?: unknown[] }) => Promise }).request({ - method: "wallet_watchAsset", - params: [{ - type: "ERC20", - options: { - address: CONTRACTS.BSC.token, - symbol: "XIC", - decimals: 18, - image: "https://d2xsxph8kpxj0f.cloudfront.net/310519663287655625/Ngki3MumDNGduV3xJt3mga/nac-token-icon_382e5c30.png", - }, - }], - }); - } catch { /* ignore */ } - }, 800); + onAddressDetected={async (addr) => { + // After address detected from WalletSelector, sync wallet state + const result = await wallet.connect(); + if (result.success) { + setShowWalletModal(false); + toast.success(lang === "zh" ? `钱包已连接: ${addr.slice(0, 6)}...${addr.slice(-4)}` : `Wallet connected: ${addr.slice(0, 6)}...${addr.slice(-4)}`); + } else { + // Even if connect() failed, we have the address — close modal + setShowWalletModal(false); + toast.success(lang === "zh" ? `地址已确认: ${addr.slice(0, 6)}...${addr.slice(-4)}` : `Address confirmed: ${addr.slice(0, 6)}...${addr.slice(-4)}`); + } }} />
@@ -1137,10 +1059,7 @@ export default function Home() { - { - if (chainId === 1) setActiveNetwork("ETH"); - else if (chainId === 56) setActiveNetwork("BSC"); - }} /> +
@@ -1259,57 +1178,6 @@ export default function Home() { {value}
))} - {/* Contract Address Row with Copy Button */} -
- {t("token_contract_addr")} -
- - {CONTRACTS.BSC.token.slice(0, 6)}...{CONTRACTS.BSC.token.slice(-4)} - - -
-
- {/* Add XIC to Wallet — uses wallet.watchAsset() which correctly handles OKX/MetaMask/TP etc. */} -
- {/* How to Buy Guide — 3 Text Paragraphs */} -
-

{t("guide_title")}

- {/* Step 1 */} -
-
- {t("guide_step1_title")}: - {t("guide_step1_1")},{t("guide_step1_3")}。 -
- {/* Contract address with copy button */} -
- {lang === "zh" ? "XIC合约" : "XIC Contract"}: - - {CONTRACTS.BSC.token.slice(0, 10)}...{CONTRACTS.BSC.token.slice(-6)} - - -
-
- {/* Step 2 */} -
- {t("guide_step2_title")}: - {t("guide_step2_1")},{t("guide_step2_2")},{t("guide_step2_3")},{t("guide_step2_4")}。 -
- {/* Step 3 */} -
- {t("guide_step3_title")}: - {t("guide_step3_1")},{t("guide_step3_2")},{t("guide_step3_3")},{t("guide_step3_4")}。 -
-
- {/* Network Selector */}

{t("buy_select_network")}