UNPKG

@web3auth/modal

Version:

Multi chain wallet aggregator for web3Auth

280 lines (276 loc) 12.8 kB
'use strict'; var _objectSpread = require('@babel/runtime/helpers/objectSpread2'); var jsxRuntime = require('react/jsx-runtime'); var noModal = require('@web3auth/no-modal'); var react = require('react'); var constants = require('../../constants.js'); var AnalyticsContext = require('../../context/AnalyticsContext.js'); var RootContext = require('../../context/RootContext.js'); var ConnectWalletChainFilter = require('./ConnectWalletChainFilter/ConnectWalletChainFilter.js'); var ConnectWalletHeader = require('./ConnectWalletHeader/ConnectWalletHeader.js'); var ConnectWalletList = require('./ConnectWalletList/ConnectWalletList.js'); var ConnectWalletQrCode = require('./ConnectWalletQrCode/ConnectWalletQrCode.js'); var ConnectWalletSearch = require('./ConnectWalletSearch/ConnectWalletSearch.js'); function ConnectWallet(props) { var _selectedButton$walle; const { isDark, config, walletConnectUri, metamaskConnectUri, walletRegistry, allRegistryButtons, customConnectorButtons, connectorVisibilityMap, deviceDetails, buttonRadius = "pill", chainNamespace, isExternalWalletModeOnly, onBackClick, handleExternalWalletClick, handleWalletDetailsHeight } = props; const { bodyState, setBodyState } = react.useContext(RootContext.RootContext); const { analytics } = react.useContext(AnalyticsContext.AnalyticsContext); const [currentPage, setCurrentPage] = react.useState(constants.CONNECT_WALLET_PAGES.CONNECT_WALLET); const [selectedWallet, setSelectedWallet] = react.useState(false); const [isLoading] = react.useState(false); const [selectedButton, setSelectedButton] = react.useState(null); const [walletSearch, setWalletSearch] = react.useState(""); const [selectedChain, setSelectedChain] = react.useState("all"); const [isShowAllWallets, setIsShowAllWallets] = react.useState(false); const handleBack = () => { if (!selectedWallet && currentPage === constants.CONNECT_WALLET_PAGES.CONNECT_WALLET && onBackClick) { onBackClick(false); return; } if (selectedWallet) { setCurrentPage(constants.CONNECT_WALLET_PAGES.CONNECT_WALLET); setSelectedWallet(false); handleWalletDetailsHeight(); } }; const walletDiscoverySupported = react.useMemo(() => { const supported = walletRegistry && (Object.keys(walletRegistry.default || {}).length > 0 || Object.keys(walletRegistry.others || {}).length > 0); return supported; }, [walletRegistry]); const allUniqueButtons = react.useMemo(() => { const uniqueButtonSet = new Set(); return customConnectorButtons.concat(allRegistryButtons).filter(button => { if (uniqueButtonSet.has(button.name)) return false; uniqueButtonSet.add(button.name); return true; }); }, [allRegistryButtons, customConnectorButtons]); const defaultButtonKeys = react.useMemo(() => new Set(Object.keys(walletRegistry.default)), [walletRegistry]); const defaultButtons = react.useMemo(() => { // display order: default injected buttons > custom adapter buttons > default non-injected buttons const buttons = [...allRegistryButtons.filter(button => button.hasInjectedWallet && defaultButtonKeys.has(button.name)), ...customConnectorButtons, ...allRegistryButtons.filter(button => !button.hasInjectedWallet && defaultButtonKeys.has(button.name))].sort((a, b) => { // favor MetaMask over other wallets if (a.name === noModal.WALLET_CONNECTORS.METAMASK && b.name === noModal.WALLET_CONNECTORS.METAMASK) { // favor installed MetaMask over non-installed MetaMask if (a.isInstalled) return -1; if (b.isInstalled) return 1; // favor injected MetaMask over non-injected MetaMask if (a.hasInjectedWallet) return -1; if (b.hasInjectedWallet) return 1; return 0; } if (a.name === noModal.WALLET_CONNECTORS.METAMASK) return -1; if (b.name === noModal.WALLET_CONNECTORS.METAMASK) return 1; return 0; }); const buttonSet = new Set(); return buttons.filter(button => { if (buttonSet.has(button.name)) return false; buttonSet.add(button.name); return true; }).filter(button => { var _button$chainNamespac; return selectedChain === "all" || ((_button$chainNamespac = button.chainNamespaces) === null || _button$chainNamespac === void 0 ? void 0 : _button$chainNamespac.includes(selectedChain)); }); }, [allRegistryButtons, customConnectorButtons, defaultButtonKeys, selectedChain]); const installedWalletButtons = react.useMemo(() => { const visibilityMap = connectorVisibilityMap; return Object.keys(config).reduce((acc, localConnector) => { if (localConnector !== noModal.WALLET_CONNECTORS.WALLET_CONNECT_V2 && visibilityMap[localConnector]) { acc.push({ name: localConnector, displayName: config[localConnector].label || localConnector, hasInjectedWallet: config[localConnector].isInjected, hasWalletConnect: false, hasInstallLinks: false }); } return acc; }, []); }, [connectorVisibilityMap, config]); const handleWalletSearch = e => { const searchValue = e.target.value; setWalletSearch(searchValue); }; const handleChainFilterChange = chain => { setSelectedChain(chain); }; const filteredButtons = react.useMemo(() => { if (walletDiscoverySupported) { return [...allUniqueButtons.filter(button => button.hasInjectedWallet), ...allUniqueButtons.filter(button => !button.hasInjectedWallet)].sort((a, _) => a.name === noModal.WALLET_CONNECTORS.METAMASK ? -1 : 1).filter(button => selectedChain === "all" || button.chainNamespaces.includes(selectedChain)).filter(button => button.name.toLowerCase().includes(walletSearch.toLowerCase())); } return installedWalletButtons; }, [walletDiscoverySupported, installedWalletButtons, walletSearch, allUniqueButtons, selectedChain]); const externalButtons = react.useMemo(() => { if (walletDiscoverySupported && !walletSearch && !isShowAllWallets) { return defaultButtons; } return filteredButtons; }, [walletDiscoverySupported, walletSearch, filteredButtons, defaultButtons, isShowAllWallets]); const totalExternalWalletsCount = react.useMemo(() => filteredButtons.length, [filteredButtons]); const initialWalletCount = react.useMemo(() => { if (isShowAllWallets) return totalExternalWalletsCount; return walletDiscoverySupported ? defaultButtons.length : installedWalletButtons.length; }, [walletDiscoverySupported, defaultButtons, installedWalletButtons, isShowAllWallets, totalExternalWalletsCount]); // Automatically show all wallets if there are less than or equal to 15 wallets // also resets everytime we search causing no. of wallets to change or select different chain react.useEffect(() => { if (walletDiscoverySupported && totalExternalWalletsCount <= 15) { setIsShowAllWallets(true); } else { setIsShowAllWallets(false); } }, [walletDiscoverySupported, selectedChain, 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 => { analytics === null || analytics === void 0 || analytics.track(noModal.ANALYTICS_EVENTS.EXTERNAL_WALLET_SELECTED, { connector: button.isInstalled ? button.name : button.hasWalletConnect ? noModal.WALLET_CONNECTORS.WALLET_CONNECT_V2 : "", wallet_name: button.displayName, is_installed: button.isInstalled, is_injected: button.hasInjectedWallet, chain_namespaces: button.chainNamespaces, has_wallet_connect: button.hasWalletConnect, has_install_links: button.hasInstallLinks, has_wallet_registry_item: !!button.walletRegistryItem, total_external_wallets: allUniqueButtons.length }); noModal.log.info("handleWalletClick", button); // for installed wallets if (button.isInstalled) { var _button$chainNamespac2; // for MetaMask non-injected on desktop, show QR code for connection if (button.name === noModal.WALLET_CONNECTORS.METAMASK && !button.hasInjectedWallet && deviceDetails.platform === "desktop") { handleExternalWalletClick({ connector: button.name }); setSelectedButton(button); setSelectedWallet(true); setCurrentPage(constants.CONNECT_WALLET_PAGES.SELECTED_WALLET); handleWalletDetailsHeight(); return; } // show chain namespace selector if the button has multiple chain namespaces if (((_button$chainNamespac2 = button.chainNamespaces) === null || _button$chainNamespac2 === void 0 ? void 0 : _button$chainNamespac2.length) > 1) { setBodyState(_objectSpread(_objectSpread({}, bodyState), {}, { multiChainSelector: { show: true, wallet: button } })); return; } // otherwise, use their connectors to connect handleExternalWalletClick({ connector: button.name }); return; } else { // show QR code if wallet connect v2 is supported if (button.hasWalletConnect) { setSelectedButton(button); setSelectedWallet(true); setCurrentPage(constants.CONNECT_WALLET_PAGES.SELECTED_WALLET); handleWalletDetailsHeight(); } else { // otherwise, show install links setBodyState(_objectSpread(_objectSpread({}, bodyState), {}, { installLinks: { show: true, wallet: button } })); } } }; const handleMoreWallets = () => { setIsShowAllWallets(true); }; const qrCodeValue = react.useMemo(() => { if (!selectedWallet) return null; if (selectedButton.name === noModal.WALLET_CONNECTORS.METAMASK && !selectedButton.hasInjectedWallet) { return metamaskConnectUri; } return walletConnectUri; }, [metamaskConnectUri, selectedButton, selectedWallet, walletConnectUri]); const disableBackButton = react.useMemo(() => { // If wallet is selected, show the back button if (selectedWallet) return false; // Otherwise, if external wallet mode only, login screen is skipped so back button is not needed if (isExternalWalletModeOnly) return true; return false; }, [selectedWallet, isExternalWalletModeOnly]); return jsxRuntime.jsxs("div", { className: "w3a--relative w3a--flex w3a--flex-1 w3a--flex-col w3a--gap-y-4", children: [jsxRuntime.jsx(ConnectWalletHeader, { disableBackButton: disableBackButton, onBackClick: handleBack, currentPage: currentPage, selectedButton: selectedButton }), selectedWallet ? jsxRuntime.jsx(ConnectWalletQrCode, { qrCodeValue: qrCodeValue, isDark: isDark, selectedButton: selectedButton, primaryColor: (_selectedButton$walle = selectedButton.walletRegistryItem) === null || _selectedButton$walle === void 0 ? void 0 : _selectedButton$walle.primaryColor, logoImage: `https://images.web3auth.io/login-${selectedButton.name}.${selectedButton.imgExtension}` }) : jsxRuntime.jsxs("div", { className: "w3a--flex w3a--flex-col w3a--gap-y-2", children: [chainNamespace.length > 1 && jsxRuntime.jsx(ConnectWalletChainFilter, { isDark: isDark, isLoading: isLoading, selectedChain: selectedChain, setSelectedChain: handleChainFilterChange, chainNamespace: chainNamespace }), jsxRuntime.jsx(ConnectWalletSearch, { totalExternalWalletCount: totalExternalWalletsCount, isLoading: isLoading, walletSearch: walletSearch, handleWalletSearch: handleWalletSearch, buttonRadius: buttonRadius }), jsxRuntime.jsx(ConnectWalletList, { externalButtons: externalButtons, isLoading: isLoading, totalExternalWalletsCount: totalExternalWalletsCount, initialWalletCount: initialWalletCount, handleWalletClick: handleWalletClick, handleMoreWallets: handleMoreWallets, isDark: isDark, deviceDetails: deviceDetails, walletConnectUri: walletConnectUri, buttonRadius: buttonRadius, isShowAllWallets: isShowAllWallets })] })] }); } module.exports = ConnectWallet;