terry-wallet-login #15
30
.unipi/docs/fix/2026-06-04-wallet-no-account-message-fix.md
Normal file
30
.unipi/docs/fix/2026-06-04-wallet-no-account-message-fix.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
title: "Wallet No Account Message — Quick Fix"
|
||||||
|
type: quick-fix
|
||||||
|
date: 2026-06-04
|
||||||
|
---
|
||||||
|
|
||||||
|
# Wallet No Account Message — Quick Fix
|
||||||
|
|
||||||
|
## Bug
|
||||||
|
When a wallet provider was detected but returned no account, the wallet login UI displayed the raw internal error key `walletNoAccount`.
|
||||||
|
|
||||||
|
## Root Cause
|
||||||
|
`connectInjectedWallet` throws `Error("walletNoAccount")`, but the modal and toast paths rendered `error.message` directly. The locale dictionaries also did not define a friendly `walletNoAccount` message.
|
||||||
|
|
||||||
|
## Fix
|
||||||
|
Translate wallet error keys before rendering them, and add user-facing English and Simplified Chinese text for `walletNoAccount`.
|
||||||
|
|
||||||
|
### Files Modified
|
||||||
|
- `src/wallet/WalletLoginModal.tsx` — translate wallet error messages before showing modal errors.
|
||||||
|
- `src/wallet/WalletProvider.tsx` — translate wallet error messages before showing toast errors.
|
||||||
|
- `src/locales/en.ts` — added English `walletNoAccount` copy.
|
||||||
|
- `src/locales/zh-CN.ts` — added Simplified Chinese `walletNoAccount` copy.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
- `npx tsc --noEmit`
|
||||||
|
- `npm run format:check`
|
||||||
|
- `npm test`
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
The underlying login behavior is unchanged. This only replaces the raw internal key with a user-friendly explanation to unlock/select a wallet account and retry.
|
||||||
@@ -231,6 +231,8 @@ export const enDict: Dict = {
|
|||||||
walletRainbowUnavailable: "QR login is not available yet.",
|
walletRainbowUnavailable: "QR login is not available yet.",
|
||||||
walletLoginSuccess: "Wallet connected",
|
walletLoginSuccess: "Wallet connected",
|
||||||
walletLoginFailed: "Wallet login failed",
|
walletLoginFailed: "Wallet login failed",
|
||||||
|
walletNoAccount:
|
||||||
|
"No wallet account was returned. Unlock your wallet and select an account, then try again.",
|
||||||
walletDisconnected: "Wallet disconnected",
|
walletDisconnected: "Wallet disconnected",
|
||||||
walletOtherMethods: "Other login methods",
|
walletOtherMethods: "Other login methods",
|
||||||
walletUseCurrent: "Use current wallet",
|
walletUseCurrent: "Use current wallet",
|
||||||
|
|||||||
@@ -217,6 +217,7 @@ export const zhDict: Dict = {
|
|||||||
walletRainbowUnavailable: "扫码登录暂不可用。",
|
walletRainbowUnavailable: "扫码登录暂不可用。",
|
||||||
walletLoginSuccess: "钱包已连接",
|
walletLoginSuccess: "钱包已连接",
|
||||||
walletLoginFailed: "钱包登录失败",
|
walletLoginFailed: "钱包登录失败",
|
||||||
|
walletNoAccount: "钱包没有返回账号。请先解锁钱包并选择一个账号后重试。",
|
||||||
walletDisconnected: "钱包已断开",
|
walletDisconnected: "钱包已断开",
|
||||||
walletOtherMethods: "其他登录方式",
|
walletOtherMethods: "其他登录方式",
|
||||||
walletUseCurrent: "使用当前钱包登录",
|
walletUseCurrent: "使用当前钱包登录",
|
||||||
|
|||||||
@@ -26,6 +26,13 @@ const wallets: WalletKind[] = ["tokenPocket", "imToken"];
|
|||||||
|
|
||||||
type LoginState = "idle" | "connecting";
|
type LoginState = "idle" | "connecting";
|
||||||
|
|
||||||
|
type Translate = (key: string) => string;
|
||||||
|
|
||||||
|
function walletErrorMessage(error: unknown, t: Translate): string {
|
||||||
|
if (!(error instanceof Error)) return t("walletLoginFailed");
|
||||||
|
return t(error.message) || t("walletLoginFailed");
|
||||||
|
}
|
||||||
|
|
||||||
function isMobileDevice(): boolean {
|
function isMobileDevice(): boolean {
|
||||||
if (typeof navigator === "undefined") return false;
|
if (typeof navigator === "undefined") return false;
|
||||||
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile/i.test(
|
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile/i.test(
|
||||||
@@ -77,7 +84,7 @@ export function WalletLoginModal() {
|
|||||||
completeLogin(localWalletToken(address), address);
|
completeLogin(localWalletToken(address), address);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setState("idle");
|
setState("idle");
|
||||||
setError(err instanceof Error ? err.message : t("walletLoginFailed"));
|
setError(walletErrorMessage(err, t));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,13 @@ import { clearWalletToken, readWalletToken, writeWalletToken } from "./token";
|
|||||||
|
|
||||||
type WalletStatus = "loading" | "loggedOut" | "loggedIn";
|
type WalletStatus = "loading" | "loggedOut" | "loggedIn";
|
||||||
|
|
||||||
|
type Translate = (key: string) => string;
|
||||||
|
|
||||||
|
function walletErrorMessage(error: unknown, t: Translate): string {
|
||||||
|
if (!(error instanceof Error)) return t("walletLoginFailed");
|
||||||
|
return t(error.message) || t("walletLoginFailed");
|
||||||
|
}
|
||||||
|
|
||||||
const localWalletTokenPrefix = "local-wallet:";
|
const localWalletTokenPrefix = "local-wallet:";
|
||||||
|
|
||||||
export function localWalletToken(wallet: string): string {
|
export function localWalletToken(wallet: string): string {
|
||||||
@@ -106,9 +113,7 @@ export function WalletProvider({ children }: { children: ReactNode }) {
|
|||||||
completeLogin(res.token, res.wallet);
|
completeLogin(res.token, res.wallet);
|
||||||
showToast(t("walletLoginSuccess"));
|
showToast(t("walletLoginSuccess"));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message =
|
showToast(walletErrorMessage(error, t), "error");
|
||||||
error instanceof Error ? error.message : t("walletLoginFailed");
|
|
||||||
showToast(message || t("walletLoginFailed"), "error");
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user