// NAC XIC Token Presale — Main Page v3.0
// Features: Real on-chain data | Bilingual (EN/ZH) | TRC20 Live Feed | Wallet Connect
// Design: Dark Cyberpunk / Quantum Finance
// Colors: Amber Gold #f0b429 | Quantum Blue #00d4ff | Deep Black #0a0a0f
import { useState, useEffect, useCallback, useRef, useMemo } from "react";
import { toast } from "sonner";
import { Link } from "wouter";
import { useWallet } from "@/hooks/useWallet";
import { usePresale } from "@/hooks/usePresale";
import { CONTRACTS, PRESALE_CONFIG, formatNumber, shortenAddress } from "@/lib/contracts";
import { trpc } from "@/lib/trpc";
import { type Lang, useTranslation } from "@/lib/i18n";
import { WalletSelector } from "@/components/WalletSelector";
// ─── Network Tab Types ────────────────────────────────────────────────────────
type NetworkTab = "BSC" | "ETH" | "TRON";
// ─── Assets ───────────────────────────────────────────────────────────────────
const HERO_BG = "https://d2xsxph8kpxj0f.cloudfront.net/310519663287655625/Ngki3MumDNGduV3xJt3mga/nac-hero-bg_7c6c173e.jpg";
const TOKEN_ICON = "https://d2xsxph8kpxj0f.cloudfront.net/310519663287655625/Ngki3MumDNGduV3xJt3mga/nac-token-icon_382e5c30.png";
// ─── Fallback stats while loading ─────────────────────────────────────────────
const FALLBACK_STATS = {
totalUsdtRaised: 0,
totalTokensSold: 0,
hardCap: 5_000_000,
progressPct: 0,
};
// ─── Countdown Timer ──────────────────────────────────────────────────────────
function useCountdown(targetDate: Date) {
const [timeLeft, setTimeLeft] = useState({ days: 0, hours: 0, minutes: 0, seconds: 0 });
useEffect(() => {
const tick = () => {
const diff = targetDate.getTime() - Date.now();
if (diff <= 0) { setTimeLeft({ days: 0, hours: 0, minutes: 0, seconds: 0 }); return; }
setTimeLeft({
days: Math.floor(diff / 86400000),
hours: Math.floor((diff % 86400000) / 3600000),
minutes: Math.floor((diff % 3600000) / 60000),
seconds: Math.floor((diff % 60000) / 1000),
});
};
tick();
const id = setInterval(tick, 1000);
return () => clearInterval(id);
}, [targetDate]);
return timeLeft;
}
// ─── Animated Counter ─────────────────────────────────────────────────────────
function AnimatedCounter({ value, prefix = "", suffix = "" }: { value: number; prefix?: string; suffix?: string }) {
const [display, setDisplay] = useState(0);
useEffect(() => {
if (value === 0) return;
let start = 0;
const step = value / 60;
const id = setInterval(() => {
start += step;
if (start >= value) { setDisplay(value); clearInterval(id); }
else setDisplay(Math.floor(start));
}, 16);
return () => clearInterval(id);
}, [value]);
return {prefix}{display.toLocaleString()}{suffix} ;
}
// ─── Network Icon ─────────────────────────────────────────────────────────────
function NetworkIcon({ network }: { network: NetworkTab }) {
if (network === "BSC") return (
);
if (network === "ETH") return (
);
return (
);
}
// ─── Step Badge ───────────────────────────────────────────────────────────────
function StepBadge({ num, text }: { num: number; text: string }) {
return (
);
}
// ─── TRC20 Purchase Panel ─────────────────────────────────────────────────────
function TRC20Panel({ usdtAmount, lang, connectedAddress, onConnectWallet }: { usdtAmount: number; lang: Lang; connectedAddress?: string; onConnectWallet?: () => void }) {
const { t } = useTranslation(lang);
const tokenAmount = usdtAmount / PRESALE_CONFIG.tokenPrice;
const [copied, setCopied] = useState(false);
const [evmAddress, setEvmAddress] = useState(connectedAddress || "");
const [evmAddrError, setEvmAddrError] = useState("");
const [submitted, setSubmitted] = useState(false);
// TronLink detection state
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(() => {
if (connectedAddress && !submitted) {
setEvmAddress(connectedAddress);
}
}, [connectedAddress, submitted]);
const submitTrc20Mutation = trpc.presale.registerTrc20Intent.useMutation({
onSuccess: () => {
setSubmitted(true);
toast.success(lang === "zh" ? "XIC接收地址已保存!" : "XIC receiving address saved!");
},
onError: (err: { message: string }) => {
toast.error(err.message);
},
});
const copyAddress = () => {
navigator.clipboard.writeText(CONTRACTS.TRON.receivingWallet);
setCopied(true);
toast.success(lang === "zh" ? "地址已复制到剪贴板!" : "Address copied to clipboard!");
setTimeout(() => setCopied(false), 2000);
};
const validateEvmAddress = (addr: string) => {
if (!addr) return lang === "zh" ? "请输入您的XIC接收地址" : "Please enter your XIC receiving address";
if (!/^0x[0-9a-fA-F]{40}$/.test(addr)) return lang === "zh" ? "无效的XIC接收地址格式(应以0x开头,入42位)" : "Invalid XIC receiving address format (must start with 0x, 42 chars)";
return "";
};
const handleEvmSubmit = () => {
const err = validateEvmAddress(evmAddress);
if (err) { setEvmAddrError(err); return; }
setEvmAddrError("");
submitTrc20Mutation.mutate({ evmAddress });
};
return (
{/* EVM Address Input — Required for token distribution */}
⚠️
{lang === "zh" ? "必填:您的XIC接收地址(BSC/ETH钉包地址)" : "Required: Your XIC Receiving Address (BSC/ETH wallet address)"}
{lang === "zh"
? "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."}
{/* WalletSelector — shown when address not yet filled */}
{!evmAddress && !submitted && (
{
setEvmAddress(addr);
setEvmAddrError("");
toast.success(lang === "zh" ? "XIC接收地址已自动填充!" : "XIC receiving address auto-filled!");
if (onConnectWallet) onConnectWallet();
}}
/>
)}
{ setEvmAddress(e.target.value); setEvmAddrError(""); setSubmitted(false); }}
placeholder={lang === "zh" ? "0x... (您的XIC接收地址)" : "0x... (your XIC receiving address)"}
className="w-full px-4 py-3 rounded-xl text-sm font-mono"
style={{
background: "rgba(255,255,255,0.05)",
border: evmAddrError ? "1px solid rgba(255,82,82,0.5)" : submitted ? "1px solid rgba(0,230,118,0.4)" : "1px solid rgba(255,255,255,0.12)",
color: "white",
outline: "none",
}}
/>
{evmAddrError && {evmAddrError}
}
{submitted && ✓ {lang === "zh" ? "XIC接收地址已保存" : "XIC receiving address saved"}
}
{submitTrc20Mutation.isPending ? (lang === "zh" ? "保存中..." : "Saving...") : submitted ? (lang === "zh" ? "✓ 已保存" : "✓ Saved") : (lang === "zh" ? "保存XIC接收地址" : "Save XIC Receiving Address")}
{/* TronLink Wallet Detection */}
{lang === "zh" ? "TronLink 钱包(可选)" : "TronLink Wallet (Optional)"}
{tronAddress ? (
{lang === "zh" ? "已连接 TronLink 地址:" : "Connected TronLink address:"}
✓ {tronAddress}
{lang === "zh"
? "您的 TronLink 已连接。请在上方填写 XIC 接收地址,然后向下方地址发送 USDT。"
: "TronLink connected. Please fill your XIC receiving address above, then send USDT to the address below."}
) : (
{lang === "zh"
? "如果您使用 TronLink 钱包,可以连接后自动验证您的 TRON 地址。"
: "If you use TronLink wallet, connect to auto-verify your TRON address."}
{hasTronLink ? (
{isTronConnecting
? (lang === "zh" ? "连接中..." : "Connecting...")
: (lang === "zh" ? "连接 TronLink 自动验证" : "Connect TronLink to verify")}
) : (
{lang === "zh" ? "安装 TronLink 钱包 →" : "Install TronLink Wallet →"}
)}
)}
{t("trc20_send_to")}
{CONTRACTS.TRON.receivingWallet}
{copied ? t("trc20_copied") : t("trc20_copy")}
0 ? usdtAmount.toFixed(2) + " USDT" : "任意数量 USDT"}(TRC20)到上方地址`
: `${t("trc20_step1")} ${usdtAmount > 0 ? usdtAmount.toFixed(2) + " USDT" : t("trc20_step1_any")} (TRC20) ${t("trc20_step1b")}`
} />
0 ? `${t("trc20_step3")} ${formatNumber(tokenAmount)} ${t("trc20_step3b")}` : t("trc20_step3_any"))
: (usdtAmount > 0 ? `You will receive ${formatNumber(tokenAmount)} XIC tokens after confirmation (1-24h)` : t("trc20_step3_any"))
} />
{t("trc20_warning")}
);
}
// ─── EVM Purchase Panel ─────────────────────────────────────────────────────
function EVMPurchasePanel({ network, lang, wallet }: { network: "BSC" | "ETH"; lang: Lang; wallet: WalletHookReturn }) {
const { t } = useTranslation(lang);
const { purchaseState, buyWithUSDT, reset, calcTokens, getUsdtBalance } = usePresale(wallet, network);
const [usdtInput, setUsdtInput] = useState("100");
const [usdtBalance, setUsdtBalance] = useState(null);
const targetChainId = CONTRACTS[network].chainId;
const isWrongNetwork = wallet.isConnected && wallet.chainId !== targetChainId;
const fetchBalance = useCallback(async () => {
const bal = await getUsdtBalance();
setUsdtBalance(bal);
}, [getUsdtBalance]);
useEffect(() => {
if (wallet.isConnected) fetchBalance();
}, [wallet.isConnected, fetchBalance]);
const usdtAmount = parseFloat(usdtInput) || 0;
const tokenAmount = calcTokens(usdtAmount);
const isValidAmount = usdtAmount > 0 && usdtAmount <= PRESALE_CONFIG.maxPurchaseUSDT;
const handleBuy = async () => {
if (!isValidAmount) {
toast.error(lang === "zh"
? `请输入有效金额(最大 $${PRESALE_CONFIG.maxPurchaseUSDT.toLocaleString()} USDT)`
: `Please enter a valid amount (max $${PRESALE_CONFIG.maxPurchaseUSDT.toLocaleString()} USDT)`);
return;
}
await buyWithUSDT(usdtAmount);
};
useEffect(() => {
if (purchaseState.step === "success") {
toast.success(lang === "zh"
? `购买成功!获得 ${formatNumber(purchaseState.tokenAmount)} 枚 XIC 代币!`
: `Successfully purchased ${formatNumber(purchaseState.tokenAmount)} XIC tokens!`);
} else if (purchaseState.step === "error" && purchaseState.error) {
toast.error(purchaseState.error.slice(0, 120));
}
}, [purchaseState.step, purchaseState.error, purchaseState.tokenAmount, lang]);
if (!wallet.isConnected) {
return (
{t("buy_connect_msg")}
{
// Use forceConnect to directly sync wallet state with the detected address
// (avoids triggering another eth_requestAccounts popup)
await wallet.forceConnect(addr);
setShowWalletModal(false);
toast.success(lang === "zh" ? `钱包已连接: ${addr.slice(0, 6)}...${addr.slice(-4)}` : `Wallet connected: ${addr.slice(0, 6)}...${addr.slice(-4)}`);
}}
compact
/>
{t("buy_connect_hint")}
);
}
if (isWrongNetwork) {
return (
⚠️
{t("buy_wrong_network")}
{t("buy_wrong_msg")} {CONTRACTS[network].chainName}
wallet.switchNetwork(targetChainId)}
className="btn-primary-nac px-6 py-2 rounded-lg text-sm font-bold"
>
{t("buy_switch")} {network === "BSC" ? "BSC" : "Ethereum"}
);
}
if (purchaseState.step === "success") {
return (
🎉
{t("buy_success_title")}
{t("buy_success_msg")} {formatNumber(purchaseState.tokenAmount)} {t("buy_success_tokens")}
{purchaseState.txHash && (
{t("buy_view_explorer")}
)}
{t("buy_more")}
);
}
const isProcessing = ["approving", "approved", "purchasing"].includes(purchaseState.step);
return (
{/* Wallet info */}
{shortenAddress(wallet.address || "")}
{usdtBalance !== null && (
{t("buy_balance")} {usdtBalance.toFixed(2)} USDT
)}
{/* USDT Amount Input */}
{t("buy_usdt_amount")}
setUsdtInput(e.target.value)}
min={0}
max={PRESALE_CONFIG.maxPurchaseUSDT}
placeholder={t("buy_placeholder")}
className="input-nac w-full px-4 py-3 rounded-xl text-lg counter-digit pr-20"
disabled={isProcessing}
/>
USDT
{[100, 500, 1000, 5000].map(amt => (
setUsdtInput(amt.toString())}
className="flex-1 py-1 rounded-lg text-xs font-semibold transition-all"
style={{ background: "rgba(240,180,41,0.08)", border: "1px solid rgba(240,180,41,0.2)", color: "rgba(240,180,41,0.8)" }}
disabled={isProcessing}
>
${amt}
))}
{/* Token Amount Preview */}
{t("buy_you_receive")}
{formatNumber(tokenAmount)}
XIC
{t("buy_price_per")}
$0.02 USDT
{/* Purchase Steps */}
{isProcessing && (
{purchaseState.step !== "approving" && ✓ }
{lang === "zh" ? "第一步:授权 USDT" : `Step 1: ${t("buy_step1")}`}
{(purchaseState.step as string) === "success" && ✓ }
{lang === "zh" ? "第二步:确认购买" : `Step 2: ${t("buy_step2")}`}
)}
{/* Buy Button */}
{isProcessing
? purchaseState.step === "approving" ? t("buy_approving")
: purchaseState.step === "approved" ? t("buy_approved")
: t("buy_processing")
: `${t("buy_btn")} ${formatNumber(tokenAmount)} XIC`}
{t("buy_no_min_max")} ${PRESALE_CONFIG.maxPurchaseUSDT.toLocaleString()} USDT
);
}
// ─── FAQ Item ─────────────────────────────────────────────────────────────────
function FAQItem({ q, a, index }: { q: string; a: string; index: number }) {
const [open, setOpen] = useState(false);
return (
setOpen(v => !v)}
className="w-full flex items-center justify-between px-5 py-4 text-left transition-colors hover:bg-white/5"
>
{String(index + 1).padStart(2, "0")}
{q}
+
{open && (
)}
);
}
// ─── Purchase Feed ────────────────────────────────────────────────────────────
function PurchaseFeed({ lang }: { lang: Lang }) {
const { t } = useTranslation(lang);
const feedRef = useRef(null);
// Fetch real TRC20 purchases from backend
const { data: trc20Records } = trpc.presale.recentPurchases.useQuery(
{ limit: 20 },
{ refetchInterval: 30_000 }
);
// Merge real TRC20 with mock EVM records for display
const [records, setRecords] = useState>([
{ address: "0x3a4f...8c2d", amount: 250000, usdt: 5000, time: "2 min ago", chain: "BSC" },
{ address: "0x7b1e...f93a", amount: 50000, usdt: 1000, time: "5 min ago", chain: "ETH" },
{ address: "TRX9k...m4pQ", amount: 125000, usdt: 2500, time: "8 min ago", chain: "TRON" },
{ address: "0xd92c...1a7f", amount: 500000, usdt: 10000, time: "12 min ago", chain: "BSC" },
{ address: "0x5e8b...c3d1", amount: 25000, usdt: 500, time: "15 min ago", chain: "ETH" },
{ address: "TRX2m...k9nL", amount: 75000, usdt: 1500, time: "19 min ago", chain: "TRON" },
]);
// Inject real TRC20 records at the top
useEffect(() => {
if (!trc20Records || trc20Records.length === 0) return;
const realRecords = trc20Records.slice(0, 5).map(r => ({
address: r.fromAddress.slice(0, 6) + "..." + r.fromAddress.slice(-4),
amount: r.xicAmount,
usdt: r.usdtAmount,
time: new Date(r.createdAt).toLocaleTimeString(),
chain: "TRON",
isReal: true,
}));
setRecords(prev => {
const merged = [...realRecords, ...prev.filter(p => !p.isReal)];
return merged.slice(0, 10);
});
}, [trc20Records]);
// Simulate new EVM purchases every 18-30 seconds
useEffect(() => {
const names = ["0x2f4a...8e1c", "0x9b3d...7f2a", "TRXab...c5mN", "0x1e7c...4d9b", "0x8a2f...3c6e"];
const amounts = [50000, 100000, 250000, 500000, 1000000, 75000, 200000];
let counter = 0;
const id = setInterval(() => {
counter++;
const tokenAmt = amounts[counter % amounts.length];
const usdtAmt = tokenAmt * 0.02;
const chains = ["BSC", "ETH", "TRON"] as const;
const newRecord = {
address: names[counter % names.length],
amount: tokenAmt,
usdt: usdtAmt,
time: lang === "zh" ? "刚刚" : "just now",
chain: chains[counter % 3],
};
setRecords(prev => [newRecord, ...prev.slice(0, 9)]);
}, 18000 + Math.random() * 12000);
return () => clearInterval(id);
}, [lang]);
const chainColor = (chain: string) => {
if (chain === "BSC") return "#F0B90B";
if (chain === "ETH") return "#627EEA";
return "#FF0013";
};
return (
{t("stats_live_feed")}
{t("stats_live")}
{records.map((r, i) => (
{r.chain}
{r.address}
{r.isReal && ✓ }
+{formatNumber(r.amount)} XIC
{r.time}
))}
);
}
// ─── Chat Support Widget ──────────────────────────────────────────────────────
function ChatSupport({ lang }: { lang: Lang }) {
const { t } = useTranslation(lang);
const [open, setOpen] = useState(false);
return (
{open && (
💬
{t("support_title")}
{t("support_online")}
setOpen(false)} className="text-white/40 hover:text-white/80 transition-colors text-lg">×
{t("support_response")}
)}
setOpen(v => !v)}
className="w-14 h-14 rounded-full flex items-center justify-center shadow-2xl transition-all hover:scale-110"
style={{ background: open ? "rgba(240,180,41,0.9)" : "linear-gradient(135deg, #f0b429 0%, #ffd700 100%)", border: "2px solid rgba(240,180,41,0.5)", boxShadow: "0 0 24px rgba(240,180,41,0.4)" }}
title="Chat Support"
>
{open ? (
) : (
)}
);
}
// ─── Navbar Wallet Button ─────────────────────────────────────────────────────
type WalletHookReturn = ReturnType;
function NavWalletButton({ lang, wallet }: { lang: Lang; wallet: WalletHookReturn }) {
const { t } = useTranslation(lang);
const [showMenu, setShowMenu] = useState(false);
const [showWalletModal, setShowWalletModal] = useState(false);
const menuRef = useRef(null);
useEffect(() => {
const handleClick = (e: MouseEvent) => {
if (menuRef.current && !menuRef.current.contains(e.target as Node)) setShowMenu(false);
};
document.addEventListener("mousedown", handleClick);
return () => document.removeEventListener("mousedown", handleClick);
}, []);
// Detect mobile browser
const isMobile = typeof window !== "undefined" && /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
// Handle connect button click — show wallet selector modal
const handleConnectClick = async () => {
// On mobile browsers, skip direct connect attempt and show modal immediately
// (mobile browsers don't support wallet extensions)
if (isMobile) {
setShowWalletModal(true);
return;
}
// On desktop: first try direct connect (works if wallet is already set up and locked)
const result = await wallet.connect();
if (!result.success && result.error) {
// If direct connect failed, show the wallet selector modal for guided setup
setShowWalletModal(true);
toast.error(result.error, { duration: 6000 });
}
};
if (!wallet.isConnected) {
return (
<>
{wallet.isConnecting ? t("nav_connecting") : t("nav_connect")}
{/* Wallet Connection Modal */}
{showWalletModal && (
{ if (e.target === e.currentTarget) setShowWalletModal(false); }}
>
{/* Close button */}
setShowWalletModal(false)}
className="absolute top-4 right-4 text-white/40 hover:text-white/80 transition-colors"
>
{lang === "zh" ? "连接钱包" : "Connect Wallet"}
{lang === "zh"
? "选择您的钱包进行连接,或手动输入地址"
: "Select your wallet to connect, or enter address manually"}
{/* MetaMask initialization guide */}
{lang === "zh"
? "💡 首次使用 MetaMask?请先打开 MetaMask 扩展完成初始化(创建或导入钱包),完成后点击下方「刷新」按钮重新检测。"
: "💡 First time using MetaMask? Open the MetaMask extension and complete setup (create or import a wallet), then click Refresh below to re-detect."}
{
// 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)}`);
}
}}
/>
)}
>
);
}
return (
setShowMenu(v => !v)}
className="flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-semibold transition-all hover:bg-white/5"
style={{ background: "rgba(0,230,118,0.1)", border: "1px solid rgba(0,230,118,0.3)", color: "#00e676" }}
>
{wallet.shortAddress}
{showMenu && (
{t("nav_connected")}
{wallet.shortAddress}
{ wallet.disconnect(); setShowMenu(false); }}
className="w-full text-left px-4 py-2 text-sm text-red-400 hover:bg-red-400/10 transition-colors"
>
{t("nav_disconnect")}
)}
);
}
// ─── Language Toggle ──────────────────────────────────────────────────────────
function LangToggle({ lang, setLang }: { lang: Lang; setLang: (l: Lang) => void }) {
return (
setLang("en")}
className="px-3 py-1.5 transition-all"
style={{
background: lang === "en" ? "rgba(240,180,41,0.2)" : "transparent",
color: lang === "en" ? "#f0b429" : "rgba(255,255,255,0.4)",
}}
>
EN
setLang("zh")}
className="px-3 py-1.5 transition-all"
style={{
background: lang === "zh" ? "rgba(240,180,41,0.2)" : "transparent",
color: lang === "zh" ? "#f0b429" : "rgba(255,255,255,0.4)",
}}
>
中文
);
}
// ─── Main Page ────────────────────────────────────────────────────────────────
export default function Home() {
const [lang, setLang] = useState(() => {
// Auto-detect browser language
const browserLang = navigator.language.toLowerCase();
return browserLang.startsWith("zh") ? "zh" : "en";
});
const { t, faq } = useTranslation(lang);
const [activeNetwork, setActiveNetwork] = useState("BSC");
const [trcUsdtAmount, setTrcUsdtAmount] = useState("100");
// useMemo stabilizes the Date reference to prevent infinite re-renders in useCountdown
const presaleEndDate = useMemo(() => new Date("2026-06-30T23:59:59Z"), []);
const countdown = useCountdown(presaleEndDate);
// ── Real on-chain stats ──
const { data: onChainStats, isLoading: statsLoading } = trpc.presale.stats.useQuery(undefined, {
refetchInterval: 60_000, // Refresh every 60 seconds
staleTime: 30_000,
});
const stats = onChainStats || FALLBACK_STATS;
const progressPct = stats.progressPct || 0;
// Presale active/paused status from backend config
const isPresalePaused = (onChainStats as any)?.presaleStatus === "paused";
// 钱包状态提升到顶层,共享给NavWalletButton和EVMPurchasePanel
const wallet = useWallet();
const networks: NetworkTab[] = ["BSC", "ETH", "TRON"];
return (
{/* ── Presale Paused Banner ── */}
{isPresalePaused && (
⏸
{lang === "zh" ? "预售活动已暂停,暂时无法购买。请关注官方渠道获取最新公告。" : "Presale is currently paused. Please follow our official channels for updates."}
⏸
)}
{/* ── Navigation ── */}
New AssetChain
PRESALE
{/* ── Hero Section ── */}
{t("hero_badge")}
{t("hero_title")}
{t("hero_subtitle")}
✦ {t("hero_price")}
✦ {t("hero_supply")}
✦ {t("hero_networks")}
✦ {t("hero_no_min")}
{/* ── Main Content ── */}
{/* ── Left Panel: Stats & Info ── */}
{/* Countdown */}
{t("stats_ends_in")}
{[
{ label: t("stats_days"), value: countdown.days },
{ label: t("stats_hours"), value: countdown.hours },
{ label: t("stats_mins"), value: countdown.minutes },
{ label: t("stats_secs"), value: countdown.seconds },
].map(({ label, value }) => (
{String(value).padStart(2, "0")}
{label}
))}
{/* Progress — Real On-Chain Data */}
{t("stats_raised")}
{statsLoading ? (
{t("loading_stats")}
) : (
<>
{t("stats_live_data")}
>
)}
{progressPct.toFixed(1)}%
{t("stats_raised_label")}
${formatNumber(stats.hardCap)}
{t("stats_hard_cap")}
{/* Stats Grid */}
{[
{ label: t("stats_tokens_sold"), value: formatNumber(stats.totalTokensSold), unit: "XIC" },
{ label: t("stats_token_price"), value: "$0.02", unit: "USDT" },
{ label: t("stats_listing"), value: "$0.10", unit: t("stats_target") },
{ label: t("hero_networks"), value: "3", unit: "BSC · ETH · TRC20" },
].map(({ label, value, unit }) => (
))}
{/* Token Info */}
{t("token_details")}
{[
{ label: t("token_name"), value: "New AssetChain Token" },
{ label: t("token_symbol"), value: "XIC" },
{ label: t("token_network"), value: "BSC (BEP-20)" },
{ label: t("token_decimals"), value: "18" },
{ label: t("token_supply"), value: "100,000,000,000" },
].map(({ label, value }) => (
{label}
{value}
))}
{t("token_view_contract")}
{/* Live Purchase Feed */}
{/* ── Right Panel: Purchase ── */}
{/* Token Icon + Title */}
{t("buy_title")}
{t("buy_subtitle")} $0.02 USDT · {t("buy_no_min")}
{/* Network Selector */}
{t("buy_select_network")}
{networks.map(net => (
setActiveNetwork(net)}
className={`network-tab rounded-xl py-3 px-2 flex flex-col items-center gap-1.5 ${activeNetwork === net ? "active" : ""}`}
>
{net === "BSC" ? "BSC" : net === "ETH" ? "Ethereum" : "TRON"}
{net === "TRON" ? "TRC20" : "ERC20"} USDT
))}
{/* Purchase Area */}
{/* Presale Paused Overlay */}
{isPresalePaused && (
⏸
{lang === "zh" ? "预售已暂停" : "Presale Paused"}
{lang === "zh" ? "请关注官方 Telegram / Twitter 获取最新公告" : "Follow our official Telegram / Twitter for updates"}
)}
{activeNetwork === "BSC" &&
}
{activeNetwork === "ETH" &&
}
{activeNetwork === "TRON" && (
{t("buy_usdt_trc20")}
setTrcUsdtAmount(e.target.value)}
placeholder={t("buy_placeholder")}
className="input-nac w-full px-4 py-3 rounded-xl text-lg counter-digit pr-20"
/>
USDT
{[100, 500, 1000, 5000].map(amt => (
setTrcUsdtAmount(amt.toString())}
className="flex-1 py-1 rounded-lg text-xs font-semibold transition-all"
style={{ background: "rgba(240,180,41,0.08)", border: "1px solid rgba(240,180,41,0.2)", color: "rgba(240,180,41,0.8)" }}
>
${amt}
))}
)}
{/* Presale Contract Links */}
{/* Why NAC */}
{[
{ icon: "🔗", title: t("why_rwa_title"), desc: t("why_rwa_desc") },
{ icon: "⚡", title: t("why_cbpp_title"), desc: t("why_cbpp_desc") },
{ icon: "🛡️", title: t("why_charter_title"), desc: t("why_charter_desc") },
].map(({ icon, title, desc }) => (
))}
{/* ── FAQ Section ── */}
{t("faq_title")}
{t("faq_subtitle")}
{faq.map((item, i) => (
))}
{/* ── Footer ── */}
New AssetChain
{t("footer_risk")}
{[
{ label: t("footer_website"), href: "https://newassetchain.io" },
{ label: t("footer_explorer"), href: "https://lens.newassetchain.io" },
{ label: t("footer_telegram"), href: "https://t.me/newassetchain" },
{ label: t("footer_twitter"), href: "https://twitter.com/newassetchain" },
].map(({ label, href }) => (
{label}
))}
{/* ── Chat Support Widget ── */}
);
}