import { QRCodeSVG } from "qrcode.react"; import { ChevronLeft, ChevronRight, LoaderCircle, X } from "lucide-react"; import { useEffect, useState } from "react"; import { useI18n } from "../i18n"; import { getInjectedWallet, type WalletKind } from "./injected"; import { useWallet } from "./WalletProvider"; import { useWalletConnectLogin } from "./useWalletConnectLogin"; import { WalletBrandIcon } from "./WalletBrandIcon"; type ModalState = "idle" | "signing"; type Step = "wallet" | "method"; const wallets: WalletKind[] = ["tokenPocket", "metaMask", "imToken"]; function isMobileDevice(): boolean { if (typeof navigator === "undefined") return false; const ua = navigator.userAgent || ""; if ( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile/i.test( ua, ) ) { return true; } // iPadOS 13+ reports a desktop "Macintosh" UA. A genuine touch-primary iPad // exposes a coarse pointer; a Mac (even with a touch peripheral) keeps a fine // pointer, so it stays on the desktop flow instead of the wallet-app jump. const coarsePointer = typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(pointer: coarse)").matches; return /Macintosh/i.test(ua) && navigator.maxTouchPoints > 1 && coarsePointer; } export function WalletLoginModal() { const { t } = useI18n(); const { closeLoginModal, loginModalOpen, signInInjected } = useWallet(); const wc = useWalletConnectLogin(); const [step, setStep] = useState("wallet"); const [selected, setSelected] = useState(null); const [state, setState] = useState("idle"); const [error, setError] = useState(""); const [mobileDevice, setMobileDevice] = useState(false); const resetWalletConnect = wc.reset; useEffect(() => { if (!loginModalOpen) return; setMobileDevice(isMobileDevice()); setStep("wallet"); setSelected(null); setState("idle"); setError(""); resetWalletConnect(); }, [loginModalOpen, resetWalletConnect]); const busy = state === "signing"; const close = () => { if (busy) return; closeLoginModal(); setError(""); }; if (!loginModalOpen) return null; const walletName = (kind: WalletKind) => t(walletNameKey(kind)); // A wallet's browser flow only works if THAT wallet is injected right now // (its desktop extension, or its in-app browser on mobile). const injectedAvailable = (kind: WalletKind) => Boolean(getInjectedWallet(kind)); // All scan/app login paths use RainbowKit/WalletConnect on BNB Chain. const qrAvailable = () => wc.available; const resetFlow = () => { setError(""); setState("idle"); wc.reset(); }; const pickWallet = (kind: WalletKind) => { resetFlow(); setSelected(kind); setStep("method"); }; const back = () => { if (busy) return; resetFlow(); setSelected(null); setStep("wallet"); }; const signInjectedFor = async (kind: WalletKind) => { setError(""); if (!getInjectedWallet(kind)) { setError( t("walletInstallSelected").replace("{wallet}", walletName(kind)), ); return; } setState("signing"); await signInInjected(kind) .catch((err) => { setError(err instanceof Error ? err.message : t("walletLoginFailed")); }) .finally(() => setState("idle")); }; const chooseQr = (kind: WalletKind) => { setError(""); void wc.start(kind); }; const iconButtonClass = "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-full border border-white/10 text-neutral-300 transition hover:border-ark-gold/50 hover:text-ark-gold"; return (
{step === "method" ? ( ) : null}

{t("walletLoginTitle")}

{step === "wallet" ? t("walletLoginDesc") : t("walletChooseMethod")}

{/* Step 1 — choose a wallet. */} {step === "wallet" ? (
{wallets.map((kind) => ( ))}
) : selected ? (
{/* Selected wallet header. */}
{walletName(selected)}
{!mobileDevice && !injectedAvailable(selected) ? (

{t("walletInstallSelected").replace( "{wallet}", walletName(selected), )}

) : null} {/* Method: browser wallet (injected). */} {(() => { const ok = injectedAvailable(selected); return ( ); })()} {/* Method: scan to log in. */} {(() => { const ok = qrAvailable(); const isTp = selected === "tokenPocket"; const qrBusy = wc.state !== "idle"; const qrLabel = wc.state === "connecting" ? t("walletConnecting") : wc.state === "signing" ? t("walletSigning") : isTp && mobileDevice ? t("walletTpLoginBtn") : t("walletQrLogin"); return (
{ok ? (

{t("walletNetworkWarning")}

) : null} {wc.qrUri ? (

{mobileDevice ? t("walletTpWaiting") : t("walletQrUseAnotherDevice")}

) : null}
); })()}
) : null} {error || wc.error ? (

{error || wc.error}

) : null}
); } function walletNameKey(kind: WalletKind): string { if (kind === "tokenPocket") return "walletTokenPocket"; if (kind === "metaMask") return "walletMetaMask"; return "walletImToken"; }