From 7b357884f2bdecc6854367d2b7120dc448effea5 Mon Sep 17 00:00:00 2001 From: Archit Date: Wed, 16 Jul 2025 23:24:15 +0400 Subject: [PATCH 01/10] fixes metamask autoconnect in mobile --- packages/modal/src/modalManager.ts | 53 +++++++++---------- .../modal/src/ui/components/Login/Login.tsx | 18 ++++--- .../modal/src/ui/components/Widget/Widget.tsx | 10 ++-- 3 files changed, 42 insertions(+), 39 deletions(-) diff --git a/packages/modal/src/modalManager.ts b/packages/modal/src/modalManager.ts index 1c4d1cadd..03589f462 100644 --- a/packages/modal/src/modalManager.ts +++ b/packages/modal/src/modalManager.ts @@ -603,9 +603,8 @@ export class Web3Auth extends Web3AuthNoModal implements IWeb3AuthModal { }): Promise => { try { const connector = this.getConnector(params.connector as WALLET_CONNECTOR_TYPE, params.loginParams?.chainNamespace); - // auto-connect WalletConnect and non-injected MetaMask in background to generate QR code URI without interfering with user's selected connection - const shouldStartConnectionInBackground = - connector.name === WALLET_CONNECTORS.WALLET_CONNECT_V2 || (connector.name === WALLET_CONNECTORS.METAMASK && !connector.isInjected); + // auto-connect WalletConnect in background to generate QR code URI without interfering with user's selected connection + const shouldStartConnectionInBackground = connector.name === WALLET_CONNECTORS.WALLET_CONNECT_V2; if (shouldStartConnectionInBackground) { const initialChain = this.getInitialChainIdForConnector(connector); await connector.connect({ chainId: initialChain.chainId }); @@ -648,30 +647,30 @@ export class Web3Auth extends Web3AuthNoModal implements IWeb3AuthModal { } // handle MM session refresh if MM is not injected - const metamaskConnector = this.getConnector(WALLET_CONNECTORS.METAMASK); - if (metamaskConnector && !metamaskConnector.isInjected) { - const status = metamaskConnector?.status; - log.debug("trying refreshing MM session", visibility, status); - if (visibility && (status === CONNECTOR_STATUS.READY || status === CONNECTOR_STATUS.CONNECTING)) { - log.debug("refreshing MM session"); - - // refreshing session for MM whenever modal is opened. - try { - const initialChain = this.getInitialChainIdForConnector(metamaskConnector); - metamaskConnector.connect({ chainId: initialChain.chainId }); - } catch (error) { - log.error(`Error while connecting to MM`, error); - } - } - if ( - !visibility && - this.status === CONNECTOR_STATUS.CONNECTED && - (status === CONNECTOR_STATUS.READY || status === CONNECTOR_STATUS.CONNECTING) - ) { - log.debug("this stops MM connector from trying to reconnect once proposal expires"); - metamaskConnector.status = CONNECTOR_STATUS.READY; - } - } + // const metamaskConnector = this.getConnector(WALLET_CONNECTORS.METAMASK); + // if (metamaskConnector && !metamaskConnector.isInjected) { + // const status = metamaskConnector?.status; + // log.debug("trying refreshing MM session", visibility, status); + // if (visibility && (status === CONNECTOR_STATUS.READY || status === CONNECTOR_STATUS.CONNECTING)) { + // log.debug("refreshing MM session"); + + // // refreshing session for MM whenever modal is opened. + // try { + // const initialChain = this.getInitialChainIdForConnector(metamaskConnector); + // metamaskConnector.connect({ chainId: initialChain.chainId }); + // } catch (error) { + // log.error(`Error while connecting to MM`, error); + // } + // } + // if ( + // !visibility && + // this.status === CONNECTOR_STATUS.CONNECTED && + // (status === CONNECTOR_STATUS.READY || status === CONNECTOR_STATUS.CONNECTING) + // ) { + // log.debug("this stops MM connector from trying to reconnect once proposal expires"); + // metamaskConnector.status = CONNECTOR_STATUS.READY; + // } + // } }; private getChainNamespaces = (): ChainNamespaceType[] => { diff --git a/packages/modal/src/ui/components/Login/Login.tsx b/packages/modal/src/ui/components/Login/Login.tsx index 5dec19f1f..90c515a6c 100644 --- a/packages/modal/src/ui/components/Login/Login.tsx +++ b/packages/modal/src/ui/components/Login/Login.tsx @@ -356,13 +356,17 @@ function Login(props: LoginProps) { }); // for non-injected Metamask, show QR code to connect if (wallet.name === WALLET_CONNECTORS.METAMASK && !wallet.hasInjectedWallet) { - setBodyState({ - ...bodyState, - metamaskQrCode: { - show: true, - wallet: wallet, - }, - }); + handleExternalWalletClick({ connector: wallet.name }); + // We should show QR code only if the wallet is not installed. + if (!wallet.isInstalled) { + setBodyState({ + ...bodyState, + metamaskQrCode: { + show: true, + wallet: wallet, + }, + }); + } return; } diff --git a/packages/modal/src/ui/components/Widget/Widget.tsx b/packages/modal/src/ui/components/Widget/Widget.tsx index df618d9af..56344f438 100644 --- a/packages/modal/src/ui/components/Widget/Widget.tsx +++ b/packages/modal/src/ui/components/Widget/Widget.tsx @@ -185,11 +185,11 @@ function Widget(props: WidgetProps) { } // auto connect to MetaMask if not injected to generate QR code URI for mobile connection - const mmAvailable = - modalState.externalWalletsConfig[WALLET_CONNECTORS.METAMASK] && !modalState.externalWalletsConfig[WALLET_CONNECTORS.METAMASK]?.isInjected; - if (mmAvailable && !modalState.metamaskConnectUri && typeof handleExternalWalletClick === "function") { - handleExternalWalletClick({ connector: WALLET_CONNECTORS.METAMASK }); - } + // const mmAvailable = + // modalState.externalWalletsConfig[WALLET_CONNECTORS.METAMASK] && !modalState.externalWalletsConfig[WALLET_CONNECTORS.METAMASK]?.isInjected; + // if (mmAvailable && !modalState.metamaskConnectUri && typeof handleExternalWalletClick === "function") { + // handleExternalWalletClick({ connector: WALLET_CONNECTORS.METAMASK }); + // } } }, [modalState, handleExternalWalletClick]); From 3c3455e20d7bca249d0b032264b11363cc4c9796 Mon Sep 17 00:00:00 2001 From: Archit Date: Fri, 18 Jul 2025 11:25:39 +0400 Subject: [PATCH 02/10] remove isInstalledCheck --- .../modal/src/ui/components/Login/Login.tsx | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/modal/src/ui/components/Login/Login.tsx b/packages/modal/src/ui/components/Login/Login.tsx index 90c515a6c..316385dbf 100644 --- a/packages/modal/src/ui/components/Login/Login.tsx +++ b/packages/modal/src/ui/components/Login/Login.tsx @@ -2,6 +2,7 @@ import HCaptcha from "@hcaptcha/react-hcaptcha"; import { AUTH_CONNECTION, AUTH_CONNECTION_TYPE } from "@web3auth/auth"; import { ANALYTICS_EVENTS, + isBrowser, log, type ModalSignInMethodType, type WALLET_CONNECTOR_TYPE, @@ -358,15 +359,13 @@ function Login(props: LoginProps) { if (wallet.name === WALLET_CONNECTORS.METAMASK && !wallet.hasInjectedWallet) { handleExternalWalletClick({ connector: wallet.name }); // We should show QR code only if the wallet is not installed. - if (!wallet.isInstalled) { - setBodyState({ - ...bodyState, - metamaskQrCode: { - show: true, - wallet: wallet, - }, - }); - } + setBodyState({ + ...bodyState, + metamaskQrCode: { + show: true, + wallet: wallet, + }, + }); return; } From a90ed78a96abaf10708c9797aa6c6c5b69374b04 Mon Sep 17 00:00:00 2001 From: Archit Date: Fri, 18 Jul 2025 11:41:02 +0400 Subject: [PATCH 03/10] fixes build --- packages/modal/src/ui/components/Login/Login.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/modal/src/ui/components/Login/Login.tsx b/packages/modal/src/ui/components/Login/Login.tsx index 316385dbf..21d78d8de 100644 --- a/packages/modal/src/ui/components/Login/Login.tsx +++ b/packages/modal/src/ui/components/Login/Login.tsx @@ -2,7 +2,6 @@ import HCaptcha from "@hcaptcha/react-hcaptcha"; import { AUTH_CONNECTION, AUTH_CONNECTION_TYPE } from "@web3auth/auth"; import { ANALYTICS_EVENTS, - isBrowser, log, type ModalSignInMethodType, type WALLET_CONNECTOR_TYPE, From 675d555d2f10952819eb23d093427d011d2206c2 Mon Sep 17 00:00:00 2001 From: Archit Date: Fri, 18 Jul 2025 12:36:17 +0400 Subject: [PATCH 04/10] fixes modal connected state --- packages/modal/src/ui/components/Root/Root.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/modal/src/ui/components/Root/Root.tsx b/packages/modal/src/ui/components/Root/Root.tsx index 2f59c4763..3fdc52b4e 100644 --- a/packages/modal/src/ui/components/Root/Root.tsx +++ b/packages/modal/src/ui/components/Root/Root.tsx @@ -424,12 +424,8 @@ function Root(props: RootProps) { ); const isShowLoader = useMemo(() => { - // don't show loader if metamask is connecting and there is a connect uri - if (modalState.detailedLoaderConnector === WALLET_CONNECTORS.METAMASK && modalState.metamaskConnectUri) { - return false; - } return modalState.status !== MODAL_STATUS.INITIALIZED; - }, [modalState.detailedLoaderConnector, modalState.metamaskConnectUri, modalState.status]); + }, [modalState.status]); return ( From e73a1cba0f3d3d5c5b434396ec63698f9f625039 Mon Sep 17 00:00:00 2001 From: Tai Nguyen TT Date: Sat, 19 Jul 2025 14:55:23 +0700 Subject: [PATCH 05/10] fix bug that QR code of metamask is not displayed in wallet discovery section --- .../modal/src/ui/components/ConnectWallet/ConnectWallet.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/modal/src/ui/components/ConnectWallet/ConnectWallet.tsx b/packages/modal/src/ui/components/ConnectWallet/ConnectWallet.tsx index 4187da83d..15bea2c2a 100644 --- a/packages/modal/src/ui/components/ConnectWallet/ConnectWallet.tsx +++ b/packages/modal/src/ui/components/ConnectWallet/ConnectWallet.tsx @@ -187,6 +187,10 @@ function ConnectWallet(props: ConnectWalletProps) { // show QR code for wallet connect v2 and MM (non-injected) if (button.hasWalletConnect) { + // connect to MM if not injected + if (button.name === WALLET_CONNECTORS.METAMASK) { + handleExternalWalletClick({ connector: button.name }); + } setSelectedButton(button); setSelectedWallet(true); setCurrentPage(CONNECT_WALLET_PAGES.SELECTED_WALLET); From 5dd0c5c3fea6e4fefefe1d7bf6be2abd09f5b9b0 Mon Sep 17 00:00:00 2001 From: Tai Nguyen TT Date: Sat, 19 Jul 2025 15:29:32 +0700 Subject: [PATCH 06/10] remove unused code --- packages/modal/src/modalManager.ts | 26 ------------------- .../modal/src/ui/components/Widget/Widget.tsx | 7 ----- 2 files changed, 33 deletions(-) diff --git a/packages/modal/src/modalManager.ts b/packages/modal/src/modalManager.ts index 03589f462..ff2ea12a4 100644 --- a/packages/modal/src/modalManager.ts +++ b/packages/modal/src/modalManager.ts @@ -645,32 +645,6 @@ export class Web3Auth extends Web3AuthNoModal implements IWeb3AuthModal { wcConnector.status = CONNECTOR_STATUS.READY; } } - - // handle MM session refresh if MM is not injected - // const metamaskConnector = this.getConnector(WALLET_CONNECTORS.METAMASK); - // if (metamaskConnector && !metamaskConnector.isInjected) { - // const status = metamaskConnector?.status; - // log.debug("trying refreshing MM session", visibility, status); - // if (visibility && (status === CONNECTOR_STATUS.READY || status === CONNECTOR_STATUS.CONNECTING)) { - // log.debug("refreshing MM session"); - - // // refreshing session for MM whenever modal is opened. - // try { - // const initialChain = this.getInitialChainIdForConnector(metamaskConnector); - // metamaskConnector.connect({ chainId: initialChain.chainId }); - // } catch (error) { - // log.error(`Error while connecting to MM`, error); - // } - // } - // if ( - // !visibility && - // this.status === CONNECTOR_STATUS.CONNECTED && - // (status === CONNECTOR_STATUS.READY || status === CONNECTOR_STATUS.CONNECTING) - // ) { - // log.debug("this stops MM connector from trying to reconnect once proposal expires"); - // metamaskConnector.status = CONNECTOR_STATUS.READY; - // } - // } }; private getChainNamespaces = (): ChainNamespaceType[] => { diff --git a/packages/modal/src/ui/components/Widget/Widget.tsx b/packages/modal/src/ui/components/Widget/Widget.tsx index 56344f438..3544c0503 100644 --- a/packages/modal/src/ui/components/Widget/Widget.tsx +++ b/packages/modal/src/ui/components/Widget/Widget.tsx @@ -183,13 +183,6 @@ function Widget(props: WidgetProps) { if (wcAvailable && !modalState.walletConnectUri && typeof handleExternalWalletClick === "function") { handleExternalWalletClick({ connector: WALLET_CONNECTORS.WALLET_CONNECT_V2 }); } - - // auto connect to MetaMask if not injected to generate QR code URI for mobile connection - // const mmAvailable = - // modalState.externalWalletsConfig[WALLET_CONNECTORS.METAMASK] && !modalState.externalWalletsConfig[WALLET_CONNECTORS.METAMASK]?.isInjected; - // if (mmAvailable && !modalState.metamaskConnectUri && typeof handleExternalWalletClick === "function") { - // handleExternalWalletClick({ connector: WALLET_CONNECTORS.METAMASK }); - // } } }, [modalState, handleExternalWalletClick]); From cf4628d5119bc8e5fb6077f87fe3b31d0205ce4c Mon Sep 17 00:00:00 2001 From: Tai Nguyen TT Date: Sun, 20 Jul 2025 14:19:44 +0700 Subject: [PATCH 07/10] do not use deeplink on mobile for installed wallets --- .../src/ui/components/Button/ButtonWallet/ButtonWallet.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/modal/src/ui/components/Button/ButtonWallet/ButtonWallet.tsx b/packages/modal/src/ui/components/Button/ButtonWallet/ButtonWallet.tsx index cd40927d7..622e098f9 100644 --- a/packages/modal/src/ui/components/Button/ButtonWallet/ButtonWallet.tsx +++ b/packages/modal/src/ui/components/Button/ButtonWallet/ButtonWallet.tsx @@ -15,7 +15,7 @@ function ButtonWallet(props: ButtonWalletProps) { const isDark = useContext(ThemedContext); const isLink = useMemo( - () => deviceDetails.platform !== "desktop" && button.href && button.hasWalletConnect && !button.hasInjectedWallet, + () => deviceDetails.platform !== "desktop" && button.href && button.hasWalletConnect && !button.isInstalled, [deviceDetails, button] ); From 6b7f2be84c8b8130e3ad88beeef3941a157118f9 Mon Sep 17 00:00:00 2001 From: Tai Nguyen TT Date: Mon, 21 Jul 2025 11:02:14 +0700 Subject: [PATCH 08/10] refactor wallet click handling --- .../ConnectWallet/ConnectWallet.tsx | 87 +++++++++++-------- .../modal/src/ui/components/Login/Login.tsx | 11 ++- .../src/ui/components/Login/Login.type.ts | 4 + .../modal/src/ui/components/Root/Root.tsx | 5 ++ 4 files changed, 69 insertions(+), 38 deletions(-) diff --git a/packages/modal/src/ui/components/ConnectWallet/ConnectWallet.tsx b/packages/modal/src/ui/components/ConnectWallet/ConnectWallet.tsx index 15bea2c2a..d0e4a5652 100644 --- a/packages/modal/src/ui/components/ConnectWallet/ConnectWallet.tsx +++ b/packages/modal/src/ui/components/ConnectWallet/ConnectWallet.tsx @@ -152,6 +152,16 @@ function ConnectWallet(props: ConnectWalletProps) { return walletDiscoverySupported ? defaultButtons.length : installedWalletButtons.length; }, [walletDiscoverySupported, defaultButtons, installedWalletButtons, isShowAllWallets, totalExternalWalletsCount]); + /** + * Wallet click logic + * - For installed wallets + * - For MetaMask non-injected on desktop, show QR code for connection + * - Ask user to select a chain namespace if it has multiple namespaces + * - Otherwise, use their connectors to connect + * - For wallet-discovery wallets (not installed) + * - On desktop, show QR code for connection if wallet connect v2 is supported, otherwise show install links + * - On mobile, open deeplink with wallet connect uri (won't go into this function as it'll open the deeplink) + */ const handleWalletClick = (button: ExternalButton) => { analytics?.track(ANALYTICS_EVENTS.EXTERNAL_WALLET_SELECTED, { connector: button.isInstalled ? button.name : button.hasWalletConnect ? WALLET_CONNECTORS.WALLET_CONNECT_V2 : "", @@ -165,45 +175,50 @@ function ConnectWallet(props: ConnectWalletProps) { total_external_wallets: allUniqueButtons.length, }); - // show chain namespace selector if the button is an injected connector with multiple chain namespaces - const isChainNamespaceSelectorRequired = button.hasInjectedWallet && button.chainNamespaces?.length > 1; - if (isChainNamespaceSelectorRequired) { - setBodyState({ - ...bodyState, - multiChainSelector: { - show: true, - wallet: button, - }, - }); - return; - } - - // connect with connector if injected and single chain namespace or custom connector (except MetaMask) - const isInjectedConnectorAndSingleChainNamespace = button.hasInjectedWallet && button.chainNamespaces?.length === 1; - const isCustomConnector = !button.hasInjectedWallet && button.isInstalled; - if (isInjectedConnectorAndSingleChainNamespace || (isCustomConnector && button.name !== WALLET_CONNECTORS.METAMASK)) { - return handleExternalWalletClick({ connector: button.name }); - } - - // show QR code for wallet connect v2 and MM (non-injected) - if (button.hasWalletConnect) { - // connect to MM if not injected - if (button.name === WALLET_CONNECTORS.METAMASK) { + // for installed wallets + if (button.isInstalled) { + // for MetaMask non-injected on desktop, show QR code for connection + if (button.name === WALLET_CONNECTORS.METAMASK && !button.hasInjectedWallet && deviceDetails.platform === "desktop") { handleExternalWalletClick({ connector: button.name }); + setSelectedButton(button); + setSelectedWallet(true); + setCurrentPage(CONNECT_WALLET_PAGES.SELECTED_WALLET); + handleWalletDetailsHeight(); + return; } - setSelectedButton(button); - setSelectedWallet(true); - setCurrentPage(CONNECT_WALLET_PAGES.SELECTED_WALLET); - handleWalletDetailsHeight(); + + // show chain namespace selector if the button has multiple chain namespaces + if (button.chainNamespaces?.length > 1) { + setBodyState({ + ...bodyState, + multiChainSelector: { + show: true, + wallet: button, + }, + }); + return; + } + + // otherwise, use their connectors to connect + handleExternalWalletClick({ connector: button.name }); + return; } else { - // show install links - setBodyState({ - ...bodyState, - installLinks: { - show: true, - wallet: button, - }, - }); + // show QR code if wallet connect v2 is supported + if (button.hasWalletConnect) { + setSelectedButton(button); + setSelectedWallet(true); + setCurrentPage(CONNECT_WALLET_PAGES.SELECTED_WALLET); + handleWalletDetailsHeight(); + } else { + // otherwise, show install links + setBodyState({ + ...bodyState, + installLinks: { + show: true, + wallet: button, + }, + }); + } } }; diff --git a/packages/modal/src/ui/components/Login/Login.tsx b/packages/modal/src/ui/components/Login/Login.tsx index 21d78d8de..802cff4c2 100644 --- a/packages/modal/src/ui/components/Login/Login.tsx +++ b/packages/modal/src/ui/components/Login/Login.tsx @@ -60,6 +60,7 @@ function Login(props: LoginProps) { showInstalledExternalWallets, logoAlignment = "center", buttonRadius = "pill", + deviceDetails, } = props; const [t] = useTranslation(undefined, { i18n }); @@ -342,6 +343,12 @@ function Login(props: LoginProps) { } }; + /** + * Installed wallet click logic: + * - For MetaMask: If not injected and on desktop, display QR code for connection. + * - If wallet supports multiple chain namespaces, prompt user to select a chain. + * - Otherwise, connect directly using the wallet connector. + */ const handleInstalledWalletClick = (wallet: ExternalButton) => { analytics?.track(ANALYTICS_EVENTS.EXTERNAL_WALLET_SELECTED, { connector: wallet.name, @@ -354,8 +361,8 @@ function Login(props: LoginProps) { has_wallet_registry_item: !!wallet.walletRegistryItem, total_external_wallets: totalExternalWallets, }); - // for non-injected Metamask, show QR code to connect - if (wallet.name === WALLET_CONNECTORS.METAMASK && !wallet.hasInjectedWallet) { + // for non-injected Metamask on desktop, show QR code to connect + if (wallet.name === WALLET_CONNECTORS.METAMASK && !wallet.hasInjectedWallet && deviceDetails.platform === "desktop") { handleExternalWalletClick({ connector: wallet.name }); // We should show QR code only if the wallet is not installed. setBodyState({ diff --git a/packages/modal/src/ui/components/Login/Login.type.ts b/packages/modal/src/ui/components/Login/Login.type.ts index 3f933f3f7..1aeb9b564 100644 --- a/packages/modal/src/ui/components/Login/Login.type.ts +++ b/packages/modal/src/ui/components/Login/Login.type.ts @@ -1,10 +1,13 @@ import { BUILD_ENV_TYPE, WEB3AUTH_NETWORK_TYPE } from "@web3auth/auth"; import type { + browser, ButtonRadiusType, ExternalButton, ExternalWalletEventType, LogoAlignmentType, + os, + platform, SocialLoginEventType, SocialLoginsConfig, } from "../../interfaces"; @@ -31,6 +34,7 @@ export interface LoginProps { totalExternalWallets: number; logoAlignment?: LogoAlignmentType; buttonRadius?: ButtonRadiusType; + deviceDetails: { platform: platform; browser: browser; os: os }; handleExternalWalletBtnClick?: (flag: boolean) => void; handleSocialLoginClick: (params: SocialLoginEventType) => void; handleExternalWalletClick: (params: ExternalWalletEventType) => void; diff --git a/packages/modal/src/ui/components/Root/Root.tsx b/packages/modal/src/ui/components/Root/Root.tsx index 3fdc52b4e..1f8c0f0a2 100644 --- a/packages/modal/src/ui/components/Root/Root.tsx +++ b/packages/modal/src/ui/components/Root/Root.tsx @@ -490,6 +490,11 @@ function Root(props: RootProps) { totalExternalWallets={totalExternalWallets} logoAlignment={logoAlignment} buttonRadius={buttonRadiusType} + deviceDetails={{ + platform: deviceDetails.platform, + browser: deviceDetails.browser, + os: deviceDetails.os as os, + }} handleSocialLoginClick={handleSocialLoginClick} handleExternalWalletBtnClick={onExternalWalletBtnClick} handleSocialLoginHeight={handleSocialLoginHeight} From bcc92c4930b864d20b09e419a20f672d0933ecf8 Mon Sep 17 00:00:00 2001 From: Tai Nguyen TT Date: Mon, 21 Jul 2025 11:07:17 +0700 Subject: [PATCH 09/10] fix incosistent order of chain namespaces in selector --- .../ConnectWalletChainNamespaceSelect.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/modal/src/ui/components/ConnectWallet/ConnectWalletChainNamespaceSelect/ConnectWalletChainNamespaceSelect.tsx b/packages/modal/src/ui/components/ConnectWallet/ConnectWalletChainNamespaceSelect/ConnectWalletChainNamespaceSelect.tsx index 101e11cb2..7869d1cfd 100644 --- a/packages/modal/src/ui/components/ConnectWallet/ConnectWalletChainNamespaceSelect/ConnectWalletChainNamespaceSelect.tsx +++ b/packages/modal/src/ui/components/ConnectWallet/ConnectWalletChainNamespaceSelect/ConnectWalletChainNamespaceSelect.tsx @@ -9,7 +9,7 @@ const ConnectWalletChainNamespaceSelect = (props: ConnectWalletChainNamespaceSel const { isDark, wallet, handleExternalWalletClick } = props; const [t] = useTranslation(undefined, { i18n }); - const chainNamespaces = wallet.chainNamespaces!.map((chainNamespace) => { + const chainNamespaces = wallet.chainNamespaces!.sort().map((chainNamespace) => { const imageId = chainNamespace === "eip155" ? "evm" : chainNamespace; const displayName = chainNamespace === "eip155" ? "EVM" : chainNamespace; return { From 3fd74308b3c53983ae8bfeaaf077d6eb0bc582b6 Mon Sep 17 00:00:00 2001 From: Tai Nguyen TT Date: Mon, 21 Jul 2025 13:02:09 +0700 Subject: [PATCH 10/10] show loader when connecting to Metamask on mobile --- .../modal/src/ui/components/Root/Root.tsx | 26 +++---------------- .../modal/src/ui/components/Root/Root.type.ts | 3 ++- .../modal/src/ui/components/Widget/Widget.tsx | 3 +++ .../src/ui/components/Widget/Widget.type.ts | 5 ++-- packages/modal/src/ui/loginModal.tsx | 17 +++++++++++- 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/packages/modal/src/ui/components/Root/Root.tsx b/packages/modal/src/ui/components/Root/Root.tsx index 1f8c0f0a2..9d7c8477c 100644 --- a/packages/modal/src/ui/components/Root/Root.tsx +++ b/packages/modal/src/ui/components/Root/Root.tsx @@ -1,12 +1,11 @@ import { WALLET_CONNECTORS, type WalletRegistryItem } from "@web3auth/no-modal"; -import Bowser from "bowser"; import { JSX, useCallback, useContext, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { CONNECT_WALLET_PAGES, DEFAULT_METAMASK_WALLET_REGISTRY_ITEM, PAGES } from "../../constants"; import { BodyState, RootContext } from "../../context/RootContext"; import { ThemedContext } from "../../context/ThemeContext"; -import { browser, ExternalButton, mobileOs, MODAL_STATUS, os, platform, TOAST_TYPE, ToastType } from "../../interfaces"; +import { ExternalButton, mobileOs, MODAL_STATUS, TOAST_TYPE, ToastType } from "../../interfaces"; import i18n from "../../localeImport"; import { cn, getBrowserExtensionUrl, getBrowserName, getIcons, getMobileInstallLink, getOsName } from "../../utils"; import BottomSheet from "../BottomSheet"; @@ -42,6 +41,7 @@ function Root(props: RootProps) { isSmsPasswordLessLoginVisible, preHandleExternalWalletClick, uiConfig, + deviceDetails, } = props; const { @@ -99,16 +99,6 @@ function Root(props: RootProps) { }; // Wallet Details - const deviceDetails = useMemo<{ platform: platform; browser: browser; os: mobileOs }>(() => { - if (typeof window === "undefined") return { platform: "mobile", browser: "chrome", os: "ios" }; - const browserData = Bowser.getParser(window.navigator.userAgent); - return { - platform: browserData.getPlatformType() as platform, - browser: browserData.getBrowserName().toLowerCase() as browser, - os: browserData.getOSName() as mobileOs, - }; - }, []); - const mobileInstallLinks = useMemo(() => { if (deviceDetails.platform === "desktop") return []; const installConfig = bodyState.installLinks?.wallet?.walletRegistryItem?.app || {}; @@ -490,11 +480,7 @@ function Root(props: RootProps) { totalExternalWallets={totalExternalWallets} logoAlignment={logoAlignment} buttonRadius={buttonRadiusType} - deviceDetails={{ - platform: deviceDetails.platform, - browser: deviceDetails.browser, - os: deviceDetails.os as os, - }} + deviceDetails={deviceDetails} handleSocialLoginClick={handleSocialLoginClick} handleExternalWalletBtnClick={onExternalWalletBtnClick} handleSocialLoginHeight={handleSocialLoginHeight} @@ -512,11 +498,7 @@ function Root(props: RootProps) { allExternalButtons={allButtons} connectorVisibilityMap={connectorVisibilityMap} customConnectorButtons={customConnectorButtons} - deviceDetails={{ - platform: deviceDetails.platform, - browser: deviceDetails.browser, - os: deviceDetails.os as os, - }} + deviceDetails={deviceDetails} chainNamespace={chainNamespaces} buttonRadius={buttonRadiusType} handleWalletDetailsHeight={handleWalletDetailsHeight} diff --git a/packages/modal/src/ui/components/Root/Root.type.ts b/packages/modal/src/ui/components/Root/Root.type.ts index 6ab13139a..fcd969196 100644 --- a/packages/modal/src/ui/components/Root/Root.type.ts +++ b/packages/modal/src/ui/components/Root/Root.type.ts @@ -1,6 +1,6 @@ import type { ChainNamespaceType, WalletRegistry } from "@web3auth/no-modal"; -import { ModalState, SocialLoginEventType, SocialLoginsConfig, UIConfig } from "../../interfaces"; +import { browser, ModalState, os, platform, SocialLoginEventType, SocialLoginsConfig, UIConfig } from "../../interfaces"; export interface RootProps { appLogo?: string; @@ -18,6 +18,7 @@ export interface RootProps { isEmailPasswordLessLoginVisible: boolean; isSmsPasswordLessLoginVisible: boolean; uiConfig: UIConfig; + deviceDetails: { platform: platform; browser: browser; os: os }; handleSocialLoginClick: (params: SocialLoginEventType) => void; handleExternalWalletBtnClick?: (flag: boolean) => void; preHandleExternalWalletClick: (params: { connector: string; chainNamespace?: ChainNamespaceType }) => void; diff --git a/packages/modal/src/ui/components/Widget/Widget.tsx b/packages/modal/src/ui/components/Widget/Widget.tsx index 3544c0503..99875dfb0 100644 --- a/packages/modal/src/ui/components/Widget/Widget.tsx +++ b/packages/modal/src/ui/components/Widget/Widget.tsx @@ -22,6 +22,7 @@ function Widget(props: WidgetProps) { chainNamespaces, walletRegistry, uiConfig, + deviceDetails, } = props; const { widgetType } = uiConfig; @@ -219,6 +220,7 @@ function Widget(props: WidgetProps) { isEmailPasswordLessLoginVisible={isEmailPasswordLessLoginVisible} isSmsPasswordLessLoginVisible={isSmsPasswordLessLoginVisible} uiConfig={uiConfig} + deviceDetails={deviceDetails} /> )} @@ -250,6 +252,7 @@ function Widget(props: WidgetProps) { isEmailPasswordLessLoginVisible={isEmailPasswordLessLoginVisible} isSmsPasswordLessLoginVisible={isSmsPasswordLessLoginVisible} uiConfig={uiConfig} + deviceDetails={deviceDetails} /> )} diff --git a/packages/modal/src/ui/components/Widget/Widget.type.ts b/packages/modal/src/ui/components/Widget/Widget.type.ts index 84ad72032..5a57636fd 100644 --- a/packages/modal/src/ui/components/Widget/Widget.type.ts +++ b/packages/modal/src/ui/components/Widget/Widget.type.ts @@ -1,7 +1,7 @@ import { SafeEventEmitter } from "@web3auth/auth"; import { ChainNamespaceType, WalletRegistry } from "@web3auth/no-modal"; -import { ExternalWalletEventType, SocialLoginEventType, StateEmitterEvents, UIConfig } from "../../interfaces"; +import { browser, ExternalWalletEventType, os, platform, SocialLoginEventType, StateEmitterEvents, UIConfig } from "../../interfaces"; export interface WidgetProps { stateListener: SafeEventEmitter; @@ -9,9 +9,10 @@ export interface WidgetProps { appName?: string; chainNamespaces: ChainNamespaceType[]; walletRegistry?: WalletRegistry; + uiConfig: UIConfig; + deviceDetails: { platform: platform; browser: browser; os: os }; handleSocialLoginClick: (params: SocialLoginEventType) => void; handleExternalWalletClick: (params: ExternalWalletEventType) => void; handleShowExternalWallets: (externalWalletsInitialized: boolean) => void; closeModal: () => void; - uiConfig: UIConfig; } diff --git a/packages/modal/src/ui/loginModal.tsx b/packages/modal/src/ui/loginModal.tsx index 7568ff142..f3664a7f2 100644 --- a/packages/modal/src/ui/loginModal.tsx +++ b/packages/modal/src/ui/loginModal.tsx @@ -26,6 +26,7 @@ import { type Web3AuthNoModalEvents, WIDGET_TYPE, } from "@web3auth/no-modal"; +import Bowser from "bowser"; import { createRoot } from "react-dom/client"; import { getLoginModalAnalyticsProperties } from "../utils"; @@ -34,11 +35,14 @@ import { DEFAULT_LOGO_DARK, DEFAULT_LOGO_LIGHT, DEFAULT_ON_PRIMARY_COLOR, DEFAUL import { AnalyticsContext } from "./context/AnalyticsContext"; import { ThemedContext } from "./context/ThemeContext"; import { + browser, ExternalWalletEventType, LoginModalCallbacks, LoginModalProps, MODAL_STATUS, ModalState, + os, + platform, SocialLoginEventType, StateEmitterEvents, UIConfig, @@ -112,6 +116,16 @@ export class LoginModal { return this.uiConfig.mode === "dark" || (this.uiConfig.mode === "auto" && window.matchMedia("(prefers-color-scheme: dark)").matches); } + get deviceDetails() { + if (typeof window === "undefined") return { platform: "mobile" as platform, browser: "chrome" as browser, os: "ios" as os }; + const browserData = Bowser.getParser(window.navigator.userAgent); + return { + platform: browserData.getPlatformType() as platform, + browser: browserData.getBrowserName().toLowerCase() as browser, + os: browserData.getOSName() as os, + }; + } + initModal = async (): Promise => { const darkState = { isDark: this.isDark }; @@ -249,6 +263,7 @@ export class LoginModal { appName={this.uiConfig.appName} chainNamespaces={this.chainNamespaces} walletRegistry={this.walletRegistry} + deviceDetails={this.deviceDetails} handleShowExternalWallets={this.handleShowExternalWallets} handleExternalWalletClick={this.handleExternalWalletClick} handleSocialLoginClick={this.handleSocialLoginClick} @@ -394,7 +409,7 @@ export class LoginModal { // don't show loader in case of metamask qr code, because currently it listens for incoming connections without any user interaction const isMetamaskInjected = this.externalWalletsConfig?.[WALLET_CONNECTORS.METAMASK]?.isInjected; - if (data?.connector === WALLET_CONNECTORS.METAMASK && !isMetamaskInjected) return; + if (data?.connector === WALLET_CONNECTORS.METAMASK && !isMetamaskInjected && this.deviceDetails.platform === "desktop") return; this.setState({ status: MODAL_STATUS.CONNECTING }); });