diff --git a/src/locales/en.ts b/src/locales/en.ts index 7d5c2db..c1eaf7d 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -215,6 +215,14 @@ export const enDict: Dict = { walletDesktopHelpRetry: "Come back here and click “Reconnect {wallet}”.", walletReconnectWallet: "Reconnect {wallet}", walletInstallWallet: "Install {wallet} extension", + walletConfirmAddressTitle: "Log in with this {wallet} address?", + walletConfirmAddressDesc: + "Confirm this is the {wallet} address you want to use.", + walletConfirmLogin: "Confirm login", + walletCancelLogin: "Cancel", + walletDesktopImTokenTitle: "Open this site in the mobile {wallet} app", + walletDesktopImTokenDesc: + "{wallet} does not provide a desktop browser extension. Open https://arkie-library-stag.com inside the mobile {wallet} app to log in.", walletOpen: "Open", walletQrLogin: "QR login", walletMobileQrDesc: diff --git a/src/locales/id.ts b/src/locales/id.ts index 1c3a3b1..de412d9 100644 --- a/src/locales/id.ts +++ b/src/locales/id.ts @@ -217,6 +217,14 @@ export const idDict: Dict = { "Kembali ke sini dan klik “Hubungkan ulang {wallet}”.", walletReconnectWallet: "Hubungkan ulang {wallet}", walletInstallWallet: "Pasang ekstensi {wallet}", + walletConfirmAddressTitle: "Masuk dengan alamat {wallet} ini?", + walletConfirmAddressDesc: + "Pastikan ini adalah alamat dompet {wallet} yang ingin Anda gunakan.", + walletConfirmLogin: "Konfirmasi masuk", + walletCancelLogin: "Batal", + walletDesktopImTokenTitle: "Buka situs ini di aplikasi {wallet} seluler", + walletDesktopImTokenDesc: + "{wallet} tidak menyediakan ekstensi browser desktop. Buka https://arkie-library-stag.com di dalam aplikasi {wallet} seluler untuk masuk.", walletOpen: "Buka", walletQrLogin: "Login QR", walletMobileQrDesc: diff --git a/src/locales/ja.ts b/src/locales/ja.ts index 1a3c01d..c2eea0b 100644 --- a/src/locales/ja.ts +++ b/src/locales/ja.ts @@ -240,6 +240,15 @@ export const jaDict: Dict = { walletDesktopHelpRetry: "ここに戻って「{wallet} に再接続」をクリックします。", walletReconnectWallet: "{wallet} に再接続", walletInstallWallet: "{wallet} 拡張機能をインストール", + walletConfirmAddressTitle: "この {wallet} アドレスでログインしますか?", + walletConfirmAddressDesc: + "使用する {wallet} ウォレットアドレスであることを確認してください。", + walletConfirmLogin: "ログインを確認", + walletCancelLogin: "キャンセル", + walletDesktopImTokenTitle: + "モバイル {wallet} アプリでこのサイトを開いてください", + walletDesktopImTokenDesc: + "{wallet} にはデスクトップ用ブラウザ拡張機能がありません。モバイル {wallet} アプリ内で https://arkie-library-stag.com を開いてログインしてください。", walletOpen: "開く", walletQrLogin: "QR ログイン", walletMobileQrDesc: diff --git a/src/locales/ko.ts b/src/locales/ko.ts index 39625e0..1c97aa5 100644 --- a/src/locales/ko.ts +++ b/src/locales/ko.ts @@ -214,6 +214,14 @@ export const koDict: Dict = { walletDesktopHelpRetry: "여기로 돌아와 ‘{wallet} 다시 연결’을 클릭하세요.", walletReconnectWallet: "{wallet} 다시 연결", walletInstallWallet: "{wallet} 확장 프로그램 설치", + walletConfirmAddressTitle: "이 {wallet} 주소로 로그인할까요?", + walletConfirmAddressDesc: + "사용하려는 {wallet} 지갑 주소가 맞는지 확인하세요.", + walletConfirmLogin: "로그인 확인", + walletCancelLogin: "취소", + walletDesktopImTokenTitle: "모바일 {wallet} 앱에서 이 사이트를 여세요", + walletDesktopImTokenDesc: + "{wallet}은 데스크톱 브라우저 확장 프로그램을 제공하지 않습니다. 모바일 {wallet} 앱 안에서 https://arkie-library-stag.com 을 열어 로그인하세요.", walletOpen: "열기", walletQrLogin: "QR 로그인", walletMobileQrDesc: diff --git a/src/locales/ms.ts b/src/locales/ms.ts index df64b8f..4aad10b 100644 --- a/src/locales/ms.ts +++ b/src/locales/ms.ts @@ -215,6 +215,15 @@ export const msDict: Dict = { walletDesktopHelpRetry: "Kembali ke sini dan klik “Sambung semula {wallet}”.", walletReconnectWallet: "Sambung semula {wallet}", walletInstallWallet: "Pasang sambungan {wallet}", + walletConfirmAddressTitle: "Log masuk dengan alamat {wallet} ini?", + walletConfirmAddressDesc: + "Sahkan ini ialah alamat dompet {wallet} yang ingin anda gunakan.", + walletConfirmLogin: "Sahkan log masuk", + walletCancelLogin: "Batal", + walletDesktopImTokenTitle: + "Buka laman ini dalam aplikasi mudah alih {wallet}", + walletDesktopImTokenDesc: + "{wallet} tidak menyediakan sambungan pelayar desktop. Buka https://arkie-library-stag.com dalam aplikasi mudah alih {wallet} untuk log masuk.", walletOpen: "Buka", walletQrLogin: "Log masuk QR", walletMobileQrDesc: diff --git a/src/locales/vi.ts b/src/locales/vi.ts index d22a954..bdf6bf8 100644 --- a/src/locales/vi.ts +++ b/src/locales/vi.ts @@ -211,6 +211,15 @@ export const viDict: Dict = { walletDesktopHelpRetry: "Quay lại đây và nhấn “Kết nối lại {wallet}”.", walletReconnectWallet: "Kết nối lại {wallet}", walletInstallWallet: "Cài tiện ích {wallet}", + walletConfirmAddressTitle: "Đăng nhập bằng địa chỉ {wallet} này?", + walletConfirmAddressDesc: + "Vui lòng xác nhận đây là địa chỉ ví {wallet} bạn muốn dùng.", + walletConfirmLogin: "Xác nhận đăng nhập", + walletCancelLogin: "Hủy", + walletDesktopImTokenTitle: + "Mở trang này trong ứng dụng {wallet} trên điện thoại", + walletDesktopImTokenDesc: + "{wallet} không có tiện ích mở rộng trình duyệt cho máy tính. Hãy mở https://arkie-library-stag.com trong ứng dụng {wallet} trên điện thoại để đăng nhập.", walletOpen: "Mở", walletQrLogin: "Đăng nhập QR", walletMobileQrDesc: diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 5a235e0..c54ba02 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -200,6 +200,13 @@ export const zhDict: Dict = { walletDesktopHelpRetry: "回到这里点击“重新连接 {wallet}”。", walletReconnectWallet: "重新连接 {wallet}", walletInstallWallet: "安装 {wallet} 插件", + walletConfirmAddressTitle: "确认使用这个 {wallet} 地址登录?", + walletConfirmAddressDesc: "请确认这是你要使用的 {wallet} 钱包地址。", + walletConfirmLogin: "确认登录", + walletCancelLogin: "取消", + walletDesktopImTokenTitle: "请用手机 {wallet} App 打开本站", + walletDesktopImTokenDesc: + "{wallet} 没有电脑浏览器插件。请在手机 {wallet} App 内打开 https://arkie-library-stag.com 后登录。", walletOpen: "打开", walletQrLogin: "扫码登录", walletMobileQrDesc: "适合用另一台设备扫描二维码登录当前浏览器。", diff --git a/src/wallet/WalletLoginModal.tsx b/src/wallet/WalletLoginModal.tsx index 6601775..bc269e2 100644 --- a/src/wallet/WalletLoginModal.tsx +++ b/src/wallet/WalletLoginModal.tsx @@ -16,6 +16,10 @@ function supportsDirectPull(kind: WalletKind): boolean { return kind === "tokenPocket" || kind === "imToken"; } +function supportsDesktopExtension(kind: WalletKind): boolean { + return kind === "tokenPocket"; +} + function buildAutoLoginDappUrl(kind: WalletKind): string { const url = new URL(window.location.href); url.searchParams.set(AUTO_LOGIN_PARAM, kind); @@ -26,6 +30,11 @@ const wallets: WalletKind[] = ["tokenPocket", "imToken"]; type LoginState = "idle" | "connecting"; +type PendingLogin = { + kind: WalletKind; + address: string; +}; + type Translate = (key: string) => string; function walletErrorMessage(error: unknown, t: Translate): string { @@ -47,6 +56,7 @@ export function WalletLoginModal() { const [mobileDevice, setMobileDevice] = useState(false); const [state, setState] = useState("idle"); const [error, setError] = useState(""); + const [pendingLogin, setPendingLogin] = useState(null); useEffect(() => { if (!loginModalOpen) return; @@ -54,13 +64,14 @@ export function WalletLoginModal() { setSelected(null); setState("idle"); setError(""); + setPendingLogin(null); }, [loginModalOpen]); if (!loginModalOpen) return null; const walletName = (kind: WalletKind) => t(walletNameKey(kind)); const walletText = (key: string, kind: WalletKind) => - t(key).replace("{wallet}", walletName(kind)); + t(key).replaceAll("{wallet}", walletName(kind)); const walletHint = () => mobileDevice ? t("walletChooseMobile") : t("walletDesktopHint"); const busy = state !== "idle"; @@ -70,27 +81,49 @@ export function WalletLoginModal() { setSelected(null); setState("idle"); setError(""); + setPendingLogin(null); }; const selectWallet = (kind: WalletKind) => { setSelected(kind); setError(""); + setPendingLogin(null); }; const loginInjected = async (kind: WalletKind) => { setSelected(kind); setState("connecting"); setError(""); + setPendingLogin(null); try { const address = await connectInjectedWallet(kind); - completeLogin(localWalletToken(address), address); + setPendingLogin({ kind, address }); + setState("idle"); } catch (err) { setState("idle"); setError(walletErrorMessage(err, t)); } }; + const confirmPendingLogin = () => { + if (!pendingLogin) return; + completeLogin(localWalletToken(pendingLogin.address), pendingLogin.address); + }; + + const cancelPendingLogin = () => { + setPendingLogin(null); + setSelected(null); + setState("idle"); + setError(""); + }; + const openWalletAppDirect = (kind: WalletKind) => { + if (!mobileDevice && !supportsDesktopExtension(kind)) { + setSelected(kind); + setPendingLogin(null); + setError(""); + return; + } if (getInjectedWallet(kind)) { void loginInjected(kind); return; @@ -103,6 +136,7 @@ export function WalletLoginModal() { return; } setSelected(kind); + setPendingLogin(null); setError(walletText("walletInstallSelected", kind)); }; @@ -192,31 +226,82 @@ export function WalletLoginModal() { {!mobileDevice && active ? (
-

- {walletText("walletDesktopHelpTitle", kind)} -

-
    -
  1. {t("walletDesktopHelpUnlock")}
  2. -
  3. {t("walletDesktopHelpSelect")}
  4. -
  5. {walletText("walletDesktopHelpRetry", kind)}
  6. -
-
- - -
+ {pendingLogin?.kind === kind ? ( + <> +

+ {walletText("walletConfirmAddressTitle", kind)} +

+

+ {walletText("walletConfirmAddressDesc", kind)} +

+

+ {pendingLogin.address} +

+
+ + +
+ + ) : supportsDesktopExtension(kind) ? ( + <> +

+ {walletText("walletDesktopHelpTitle", kind)} +

+
    +
  1. {t("walletDesktopHelpUnlock")}
  2. +
  3. {t("walletDesktopHelpSelect")}
  4. +
  5. {walletText("walletDesktopHelpRetry", kind)}
  6. +
+
+ + +
+ + ) : ( + <> +

+ {walletText("walletDesktopImTokenTitle", kind)} +

+

+ {walletText("walletDesktopImTokenDesc", kind)} +

+ + + )}
) : null} diff --git a/src/wallet/deepLinks.ts b/src/wallet/deepLinks.ts index 08bdc35..215f208 100644 --- a/src/wallet/deepLinks.ts +++ b/src/wallet/deepLinks.ts @@ -31,7 +31,7 @@ export function openWalletDeepLink(kind: WalletKind): void { } const downloadUrls: Record = { - tokenPocket: "https://www.tokenpocket.pro/en/download/app", + tokenPocket: "https://extension.tokenpocket.pro/", metaMask: "https://metamask.io/download/", imToken: "https://token.im/download", };