feat: redesign wallet login and favorites, fix desktop/mobile bugs

- Remove forced BNB chain switch on injected login (signature is chain-agnostic)
- Refine isMobileDevice so touch Macs stay on desktop flow
- Wire RainbowKit/WalletConnect as a real MetaMask/imToken QR fallback,
  gated on a valid VITE_WALLETCONNECT_PROJECT_ID
- Rebuild login modal: single desktop primary action, collapsible other
  methods, mobile open-app fallback feedback, brand icons
- Add My Favorites entry points (header, mobile menu, wallet dropdown)
- Favorites page: error retry, mobile filter drawer
- Auto sign-out and re-login prompt on favorites 401
- Full native translations for all wallet strings across 7 locales

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
TerryM
2026-06-02 03:43:13 +08:00
parent f935f122f9
commit 7abe4a868c
17 changed files with 715 additions and 155 deletions

View File

@@ -2,8 +2,6 @@ import { requestWalletNonce, verifyWalletSignature } from "./api";
export type WalletKind = "tokenPocket" | "metaMask" | "imToken";
const bnbChainIdHex = "0x38";
export type EthereumProvider = {
isMetaMask?: boolean;
isTokenPocket?: boolean;
@@ -36,30 +34,6 @@ export function getInjectedWallet(kind?: WalletKind): EthereumProvider | null {
return match ?? null;
}
async function ensureBnbChain(ethereum: EthereumProvider): Promise<void> {
try {
await ethereum.request({
method: "wallet_switchEthereumChain",
params: [{ chainId: bnbChainIdHex }],
});
} catch (error) {
const code = (error as { code?: number | string }).code;
if (code !== 4902 && code !== "4902") throw error;
await ethereum.request({
method: "wallet_addEthereumChain",
params: [
{
blockExplorerUrls: ["https://bscscan.com"],
chainId: bnbChainIdHex,
chainName: "BNB Smart Chain",
nativeCurrency: { decimals: 18, name: "BNB", symbol: "BNB" },
rpcUrls: ["https://bsc-dataseed.binance.org"],
},
],
});
}
}
export async function signInWithInjectedWallet(kind?: WalletKind): Promise<{
token: string;
wallet: string;
@@ -67,8 +41,9 @@ export async function signInWithInjectedWallet(kind?: WalletKind): Promise<{
const ethereum = getInjectedWallet(kind);
if (!ethereum) throw new Error("No injected wallet found");
await ensureBnbChain(ethereum);
// Login is signature-only (EIP-191 personal_sign). The backend verifies the
// recovered address and never inspects chainId, so we deliberately do NOT
// switch or add any chain — that only adds a failure-prone wallet popup.
const accounts = await ethereum.request<string[]>({
method: "eth_requestAccounts",
});