feat: simplify wallet login options
Some checks failed
Deploy Staging (terry-wallet-login) / deploy (push) Failing after 29s
Some checks failed
Deploy Staging (terry-wallet-login) / deploy (push) Failing after 29s
This commit is contained in:
@@ -7,7 +7,6 @@ import {
|
||||
} from "@rainbow-me/rainbowkit";
|
||||
import {
|
||||
imTokenWallet,
|
||||
metaMaskWallet,
|
||||
tokenPocketWallet,
|
||||
} from "@rainbow-me/rainbowkit/wallets";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
@@ -22,7 +21,7 @@ const connectors = connectorsForWallets(
|
||||
[
|
||||
{
|
||||
groupName: "ARK Library",
|
||||
wallets: [metaMaskWallet, imTokenWallet, tokenPocketWallet],
|
||||
wallets: [imTokenWallet, tokenPocketWallet],
|
||||
},
|
||||
],
|
||||
{
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import type { WalletKind } from "./injected";
|
||||
|
||||
type Brand = { bg: string; label: string };
|
||||
|
||||
const brands: Record<WalletKind, Brand> = {
|
||||
tokenPocket: { bg: "#2980FE", label: "TP" },
|
||||
metaMask: { bg: "#F6851B", label: "M" },
|
||||
imToken: { bg: "#11C4D1", label: "im" },
|
||||
const logos: Partial<Record<WalletKind, string>> = {
|
||||
tokenPocket: "/assets/ark-library/wallets/tokenpocket.svg",
|
||||
imToken: "/assets/ark-library/wallets/imtoken.svg",
|
||||
};
|
||||
|
||||
export function WalletBrandIcon({
|
||||
@@ -15,14 +12,17 @@ export function WalletBrandIcon({
|
||||
kind: WalletKind;
|
||||
size?: number;
|
||||
}) {
|
||||
const brand = brands[kind];
|
||||
const logo = logos[kind];
|
||||
if (!logo) return null;
|
||||
|
||||
return (
|
||||
<span
|
||||
<img
|
||||
src={logo}
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
style={{ width: size, height: size, backgroundColor: brand.bg }}
|
||||
className="inline-flex shrink-0 items-center justify-center rounded-lg text-[11px] font-bold leading-none text-white"
|
||||
>
|
||||
{brand.label}
|
||||
</span>
|
||||
width={size}
|
||||
height={size}
|
||||
className="inline-flex shrink-0 rounded-lg"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { QRCodeSVG } from "qrcode.react";
|
||||
import { LoaderCircle, X } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useI18n } from "../i18n";
|
||||
import { walletDeepLink } from "./deepLinks";
|
||||
import { getInjectedWallet, type WalletKind } from "./injected";
|
||||
import { useWallet } from "./WalletProvider";
|
||||
import { useWalletConnectLogin } from "./useWalletConnectLogin";
|
||||
import {
|
||||
connectInjectedWallet,
|
||||
getInjectedWallet,
|
||||
type WalletKind,
|
||||
} from "./injected";
|
||||
import { localWalletToken, useWallet } from "./WalletProvider";
|
||||
import { WalletBrandIcon } from "./WalletBrandIcon";
|
||||
|
||||
const AUTO_LOGIN_PARAM = "autoLogin";
|
||||
@@ -20,7 +22,9 @@ function buildAutoLoginDappUrl(kind: WalletKind): string {
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
const wallets: WalletKind[] = ["tokenPocket", "metaMask", "imToken"];
|
||||
const wallets: WalletKind[] = ["tokenPocket", "imToken"];
|
||||
|
||||
type LoginState = "idle" | "connecting";
|
||||
|
||||
function isMobileDevice(): boolean {
|
||||
if (typeof navigator === "undefined") return false;
|
||||
@@ -31,60 +35,66 @@ function isMobileDevice(): boolean {
|
||||
|
||||
export function WalletLoginModal() {
|
||||
const { t } = useI18n();
|
||||
const { closeLoginModal, loginModalOpen } = useWallet();
|
||||
const wc = useWalletConnectLogin();
|
||||
const { closeLoginModal, completeLogin, loginModalOpen } = useWallet();
|
||||
const [selected, setSelected] = useState<WalletKind | null>(null);
|
||||
const [mobileDevice, setMobileDevice] = useState(false);
|
||||
|
||||
const resetWalletConnect = wc.reset;
|
||||
const [state, setState] = useState<LoginState>("idle");
|
||||
const [error, setError] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
if (!loginModalOpen) return;
|
||||
setMobileDevice(isMobileDevice());
|
||||
setSelected(null);
|
||||
resetWalletConnect();
|
||||
}, [loginModalOpen, resetWalletConnect]);
|
||||
setState("idle");
|
||||
setError("");
|
||||
}, [loginModalOpen]);
|
||||
|
||||
if (!loginModalOpen) return null;
|
||||
|
||||
const walletName = (kind: WalletKind) => t(walletNameKey(kind));
|
||||
const walletHint = (kind: WalletKind) => {
|
||||
if (kind === "tokenPocket") {
|
||||
return mobileDevice
|
||||
? t("walletTpMobileDesc")
|
||||
: t("walletTokenPocketQrDesc");
|
||||
}
|
||||
return t("walletRainbowFallbackDesc");
|
||||
};
|
||||
const busy = wc.state !== "idle";
|
||||
const walletHint = () =>
|
||||
mobileDevice ? t("walletChooseMobile") : t("walletDesktopHint");
|
||||
const busy = state !== "idle";
|
||||
|
||||
const close = () => {
|
||||
closeLoginModal();
|
||||
setSelected(null);
|
||||
wc.reset();
|
||||
setState("idle");
|
||||
setError("");
|
||||
};
|
||||
|
||||
const selectWallet = (kind: WalletKind) => {
|
||||
setSelected(kind);
|
||||
wc.reset();
|
||||
setError("");
|
||||
};
|
||||
|
||||
const startWalletLogin = (kind: WalletKind, mode: "deeplink" | "qr") => {
|
||||
const loginInjected = async (kind: WalletKind) => {
|
||||
setSelected(kind);
|
||||
void wc.start(kind, mode);
|
||||
setState("connecting");
|
||||
setError("");
|
||||
try {
|
||||
const address = await connectInjectedWallet(kind);
|
||||
completeLogin(localWalletToken(address), address);
|
||||
} catch (err) {
|
||||
setState("idle");
|
||||
setError(err instanceof Error ? err.message : t("walletLoginFailed"));
|
||||
}
|
||||
};
|
||||
|
||||
const openWalletAppDirect = (kind: WalletKind) => {
|
||||
if (getInjectedWallet(kind)) {
|
||||
startWalletLogin(kind, "deeplink");
|
||||
void loginInjected(kind);
|
||||
return;
|
||||
}
|
||||
if (mobileDevice && supportsDirectPull(kind)) {
|
||||
setSelected(kind);
|
||||
setError("");
|
||||
const deeplink = walletDeepLink(kind, buildAutoLoginDappUrl(kind));
|
||||
window.location.href = deeplink;
|
||||
return;
|
||||
}
|
||||
startWalletLogin(kind, "deeplink");
|
||||
setSelected(kind);
|
||||
setError(t("walletInstallSelected").replace("{wallet}", walletName(kind)));
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -120,8 +130,7 @@ export function WalletLoginModal() {
|
||||
<div className="mt-5 grid gap-2">
|
||||
{wallets.map((kind) => {
|
||||
const active = selected === kind;
|
||||
const connecting = active && wc.state === "connecting";
|
||||
const signing = active && wc.state === "signing";
|
||||
const connecting = active && state === "connecting";
|
||||
return (
|
||||
<div
|
||||
key={kind}
|
||||
@@ -136,9 +145,9 @@ export function WalletLoginModal() {
|
||||
onClick={() =>
|
||||
mobileDevice
|
||||
? selectWallet(kind)
|
||||
: startWalletLogin(kind, "qr")
|
||||
: openWalletAppDirect(kind)
|
||||
}
|
||||
disabled={!wc.available || busy}
|
||||
disabled={busy}
|
||||
className="flex w-full items-center gap-3 text-left disabled:cursor-wait disabled:opacity-70"
|
||||
>
|
||||
<WalletBrandIcon kind={kind} size={32} />
|
||||
@@ -147,38 +156,24 @@ export function WalletLoginModal() {
|
||||
{walletName(kind)}
|
||||
</span>
|
||||
<span className="mt-1 block text-xs leading-5 text-neutral-400">
|
||||
{connecting
|
||||
? t("walletConnecting")
|
||||
: signing
|
||||
? t("walletSigning")
|
||||
: walletHint(kind)}
|
||||
{connecting ? t("walletConnecting") : walletHint()}
|
||||
</span>
|
||||
</span>
|
||||
{connecting || signing ? (
|
||||
{connecting ? (
|
||||
<LoaderCircle className="h-4 w-4 animate-spin text-ark-gold" />
|
||||
) : null}
|
||||
</button>
|
||||
|
||||
{mobileDevice && active ? (
|
||||
<div className="mt-3 grid grid-cols-2 gap-2">
|
||||
<div className="mt-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => openWalletAppDirect(kind)}
|
||||
disabled={
|
||||
supportsDirectPull(kind) ? busy : !wc.available || busy
|
||||
}
|
||||
className="rounded-full bg-ark-gold px-3 py-2 text-sm font-bold text-black transition hover:bg-ark-gold2 disabled:cursor-wait disabled:opacity-70"
|
||||
disabled={busy}
|
||||
className="w-full rounded-full bg-ark-gold px-3 py-2 text-sm font-bold text-black transition hover:bg-ark-gold2 disabled:cursor-wait disabled:opacity-70"
|
||||
>
|
||||
{t("walletOpenWalletApp")}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => startWalletLogin(kind, "qr")}
|
||||
disabled={!wc.available || busy}
|
||||
className="rounded-full border border-ark-gold/50 px-3 py-2 text-sm font-semibold text-ark-gold transition hover:bg-ark-gold/10 disabled:cursor-wait disabled:opacity-70"
|
||||
>
|
||||
{t("walletQrLogin")}
|
||||
</button>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
@@ -186,37 +181,9 @@ export function WalletLoginModal() {
|
||||
})}
|
||||
</div>
|
||||
|
||||
{!wc.available ? (
|
||||
<p className="mt-4 rounded-2xl border border-white/10 bg-white/[0.03] px-4 py-3 text-sm text-neutral-400">
|
||||
{t("walletRainbowUnavailable")}
|
||||
</p>
|
||||
) : null}
|
||||
|
||||
{selected && wc.qrUri ? (
|
||||
<div className="mt-4 grid place-items-center rounded-2xl bg-white p-4 text-center">
|
||||
<QRCodeSVG value={wc.qrUri} size={180} level="M" />
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{wc.error ? (
|
||||
{error ? (
|
||||
<p className="mt-4 rounded-2xl border border-red-500/30 bg-red-500/10 px-4 py-3 text-sm text-red-200">
|
||||
{wc.error}
|
||||
</p>
|
||||
) : null}
|
||||
|
||||
{selected ? (
|
||||
<div className="mt-4 rounded-2xl border border-white/10 bg-white/[0.03] px-4 py-3 text-xs leading-5 text-neutral-400">
|
||||
<p className="font-semibold text-neutral-200">Wallet debug</p>
|
||||
<p>state: {wc.state}</p>
|
||||
<p>connected: {wc.isConnected ? "yes" : "no"}</p>
|
||||
<p className="break-all">address: {wc.address || "-"}</p>
|
||||
<p>qr: {wc.qrUri ? "received" : "-"}</p>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{selected ? (
|
||||
<p className="mt-4 text-xs leading-5 text-amber-300/80">
|
||||
{t("walletNetworkWarning")}
|
||||
{error}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
@@ -225,7 +192,5 @@ export function WalletLoginModal() {
|
||||
}
|
||||
|
||||
function walletNameKey(kind: WalletKind): string {
|
||||
if (kind === "tokenPocket") return "walletTokenPocket";
|
||||
if (kind === "metaMask") return "walletMetaMask";
|
||||
return "walletImToken";
|
||||
return kind === "tokenPocket" ? "walletTokenPocket" : "walletImToken";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user