UNPKG

@daimo/pay

Version:

Seamless crypto payments. Onboard users from any chain, any coin into your app with one click.

316 lines (313 loc) 12.4 kB
import { jsxs, jsx } from 'react/jsx-runtime'; import { ROUTES } from '../../../constants/routes.js'; import { usePayContext } from '../../../hooks/usePayContext.js'; import { PageContent } from '../../Common/Modal/styles.js'; import { DepositAddressPaymentOptions, getAddressContraction } from '@daimo/pay-common'; import { useWallet } from '@solana/wallet-adapter-react'; import { useAccount, useDisconnect, useConnections } from 'wagmi'; import { Ethereum, Solana, Polygon, Base, Tron } from '../../../assets/chains.js'; import { MetaMask, Trust, Rainbow, Phantom, Rabby, WalletIcon } from '../../../assets/logos.js'; import useIsMobile from '../../../hooks/useIsMobile.js'; import useLocales from '../../../hooks/useLocales.js'; import { flattenChildren } from '../../../utils/index.js'; import { walletConfigs } from '../../../wallets/walletConfigs.js'; import { OptionsList } from '../../Common/OptionsList/index.js'; import { OrderHeader } from '../../Common/OrderHeader/index.js'; import PoweredByFooter from '../../Common/PoweredByFooter/index.js'; import WalletChainLogo from '../../Common/WalletChainLogo/index.js'; function SelectMethod() { const locales = useLocales(); const payWithString = flattenChildren(locales.payWith).join(""); const { isMobile } = useIsMobile(); const { address, chain, isConnected: isEthConnected, connector } = useAccount(); const { connected: isSolanaConnected, wallet: solanaWallet, disconnect: disconnectSolana, publicKey } = useWallet(); const { setRoute, paymentState, log, disableMobileInjector } = usePayContext(); const { disconnectAsync } = useDisconnect(); const connections = useConnections(); const { externalPaymentOptions, senderEnsName, topOptionsOrder } = paymentState; const showConnectedEth = isEthConnected && (!isMobile || !disableMobileInjector); const showConnectedSolana = isSolanaConnected && (!isMobile || !disableMobileInjector); const getConnectedWalletOptions = () => { const showChainLogo = isEthConnected && isSolanaConnected; const connectedOptions = []; if (showConnectedEth) { const ethWalletDisplayName = senderEnsName ?? (address ? getAddressContraction(address) : "wallet"); let walletIcon; const matchedConfig = Object.values(walletConfigs).find((cfg) => { if (!cfg.name || !connector?.name) return false; const cfgName = cfg.name.toLowerCase(); const connName = connector.name.toLowerCase(); return cfgName.includes(connName) || connName.includes(cfgName); }); if (matchedConfig?.icon) { walletIcon = typeof matchedConfig.icon === "string" ? /* @__PURE__ */ jsx("img", { src: matchedConfig.icon, alt: matchedConfig.name }) : matchedConfig.icon; } else if (connector?.icon) { walletIcon = /* @__PURE__ */ jsx("div", { style: { borderRadius: "22.5%", overflow: "hidden" }, children: /* @__PURE__ */ jsx("img", { src: connector.icon, alt: connector.name }) }); } else { walletIcon = /* @__PURE__ */ jsx(WalletIcon, {}); } const connectedEthWalletOption = { id: "connectedWallet", title: `${payWithString} ${ethWalletDisplayName}`, icons: [ /* @__PURE__ */ jsx( WalletChainLogo, { walletIcon, walletName: connector?.name || "Wallet", chainLogo: showChainLogo ? /* @__PURE__ */ jsx(Ethereum, {}) : null }, "eth" ) ], onClick: () => { paymentState.setTokenMode("evm"); setRoute(ROUTES.SELECT_TOKEN, { event: "click-wallet", walletId: connector?.id, chainId: chain?.id, address }); } }; connectedOptions.push(connectedEthWalletOption); } if (showConnectedSolana) { const solWalletDisplayName = getAddressContraction( publicKey?.toBase58() ?? "" ); let solWalletIcon; const solMatchedConfig = Object.values(walletConfigs).find((cfg) => { if (!cfg.name) return false; const cfgName = cfg.name.toLowerCase(); const solName = solanaWallet?.adapter.name.toLowerCase() || ""; return cfgName.includes(solName) || solName.includes(cfgName); }); if (solMatchedConfig?.icon) { solWalletIcon = typeof solMatchedConfig.icon === "string" ? /* @__PURE__ */ jsx("img", { src: solMatchedConfig.icon, alt: solMatchedConfig.name }) : solMatchedConfig.icon; } else if (solanaWallet?.adapter.icon) { solWalletIcon = solanaWallet.adapter.icon; } else { solWalletIcon = /* @__PURE__ */ jsx(Solana, {}); } const connectedSolWalletOption = { id: "connectedSolanaWallet", title: `${payWithString} ${solWalletDisplayName}`, icons: [ /* @__PURE__ */ jsx( WalletChainLogo, { walletIcon: solWalletIcon, walletName: solanaWallet?.adapter.name || "Wallet", chainLogo: showChainLogo && /* @__PURE__ */ jsx(Solana, {}) }, "sol-wallet" ) ], onClick: () => { paymentState.setTokenMode("solana"); setRoute(ROUTES.SELECT_TOKEN, { event: "click-wallet", walletId: solanaWallet?.adapter.name, chainId: "solana", address: publicKey?.toBase58() }); } }; connectedOptions.push(connectedSolWalletOption); } return connectedOptions; }; const connectedWalletOptions = getConnectedWalletOptions(); const walletOrder = paymentState.externalPaymentOptions.parsedConfig.walletOrder; const unconnectedWalletOption = { id: "unconnectedWallet", title: isEthConnected || isSolanaConnected ? locales.payWithAnotherWallet : locales.payWithWallet, icons: getBestUnconnectedWalletIcons(connector, isMobile, walletOrder), onClick: async () => { await Promise.allSettled( connections.map( (connection) => disconnectAsync({ connector: connection.connector }) ) ); await disconnectSolana(); setRoute(ROUTES.CONNECTORS); } }; log( `[SELECT_METHOD] loading: ${externalPaymentOptions.loading}, options: ${JSON.stringify( externalPaymentOptions.options )}` ); const categorizedOptions = []; connectedWalletOptions.forEach( (opt) => categorizedOptions.push({ ...opt, category: "connected" }) ); if (topOptionsOrder.includes("AllWallets")) { categorizedOptions.push({ ...unconnectedWalletOption, category: "AllWallets" }); } const exchangeOptions = externalPaymentOptions.options.get("exchange") ?? []; const showExchangePaymentMethod = exchangeOptions.length > 0 && topOptionsOrder.includes("AllExchanges"); if (showExchangePaymentMethod) { categorizedOptions.push({ id: "exchange", title: locales.payWithExchange, icons: exchangeOptions.slice(0, 3).map((option) => option.logoURI), onClick: () => { setRoute(ROUTES.SELECT_EXCHANGE, { event: "click-option", option: "exchange" }); }, category: "AllExchanges" }); } if (topOptionsOrder.includes("Tron")) { const tronOption = paymentState.depositAddressOptions.options?.find( (option) => option.id === DepositAddressPaymentOptions.TRON_USDT ); if (tronOption) { categorizedOptions.push({ id: "tron", title: tronOption.id, // Use the actual title like "USDT on Tron" icons: [tronOption.logoURI], onClick: () => { paymentState.setSelectedDepositAddressOption(tronOption); setRoute( paymentState.isDepositFlow ? ROUTES.SELECT_DEPOSIT_ADDRESS_AMOUNT : ROUTES.WAITING_DEPOSIT_ADDRESS, { event: "select_tron" } ); }, category: "Tron" }); } } if (topOptionsOrder.includes("AllAddresses")) { const depositAddressOption = getDepositAddressOption( setRoute, locales, topOptionsOrder.includes("Tron") // exclude Tron if shown separately ); categorizedOptions.push({ ...depositAddressOption, category: "AllAddresses" }); } const zkp2pOptions = externalPaymentOptions.options.get("zkp2p") ?? []; const showZkp2pPaymentMethod = !isMobile && zkp2pOptions.length > 0 && topOptionsOrder.includes("AllPaymentApps"); if (showZkp2pPaymentMethod) { categorizedOptions.push({ id: "ZKP2P", title: locales.payViaPaymentApp, icons: zkp2pOptions.slice(0, 2).map((option) => option.logoURI), onClick: () => { setRoute(ROUTES.SELECT_ZKP2P); }, category: "AllPaymentApps" }); } const sortedOptions = categorizedOptions.sort((a, b) => { if (a.category === "connected") return -1; if (b.category === "connected") return 1; const aIndex = topOptionsOrder.indexOf(a.category); const bIndex = topOptionsOrder.indexOf(b.category); if (aIndex === -1 && bIndex === -1) return 0; if (aIndex === -1) return 1; if (bIndex === -1) return -1; return aIndex - bIndex; }); const options = sortedOptions.map(({ category, ...opt }) => opt); options.sort((a, b) => (a.disabled ? 1 : 0) - (b.disabled ? 1 : 0)); return /* @__PURE__ */ jsxs(PageContent, { children: [ /* @__PURE__ */ jsx(OrderHeader, {}), /* @__PURE__ */ jsx( OptionsList, { requiredSkeletons: 3, isLoading: externalPaymentOptions.loading, options: externalPaymentOptions.loading ? [] : options } ), /* @__PURE__ */ jsx(PoweredByFooter, {}) ] }); } function getBestUnconnectedWalletIcons(connector, isMobile, walletOrder) { const icons = []; const strippedId = connector?.id.toLowerCase(); if (walletOrder && walletOrder.length > 0 && isMobile) { const maxIcons = 3; for (const walletName of walletOrder) { if (icons.length >= maxIcons) break; if (strippedId?.includes(walletName.toLowerCase())) continue; const walletId = Object.keys(walletConfigs).find((id) => { const wallet = walletConfigs[id]; const nameLower = walletName.toLowerCase(); return wallet.name?.toLowerCase().includes(nameLower) || wallet.shortName?.toLowerCase().includes(nameLower) || id.toLowerCase().includes(nameLower); }); if (walletId) { const wallet = walletConfigs[walletId]; const icon = wallet.iconConnector || wallet.icon; if (icon) { icons.push( /* @__PURE__ */ jsx( "div", { style: { borderRadius: "22.5%", overflow: "hidden" }, children: icon }, walletId ) ); } } } if (icons.length > 0) return icons; } const [isRainbow, isTrust, isPhantom, isMetaMask, isRabby] = [ strippedId?.includes("rainbow"), strippedId?.includes("trust"), strippedId?.includes("phantom"), strippedId?.includes("coinbase"), strippedId?.includes("metamask"), strippedId?.includes("rabby") ]; if (isMobile) { if (!isMetaMask) icons.push(/* @__PURE__ */ jsx(MetaMask, {})); if (!isTrust) icons.push(/* @__PURE__ */ jsx(Trust, { background: true })); if (!isRainbow && icons.length < 3) icons.push(/* @__PURE__ */ jsx(Rainbow, {})); } else { if (!isMetaMask) icons.push(/* @__PURE__ */ jsx(MetaMask, {})); if (!isRainbow) icons.push(/* @__PURE__ */ jsx(Rainbow, {})); if (!isPhantom) icons.push(/* @__PURE__ */ jsx(Phantom, {})); if (!isRabby && icons.length < 3) icons.push(/* @__PURE__ */ jsx(Rabby, {})); } return icons; } function getDepositAddressOption(setRoute, locales, excludeTron = false) { const icons = excludeTron ? [/* @__PURE__ */ jsx(Ethereum, {}, "eth"), /* @__PURE__ */ jsx(Polygon, {}, "polygon"), /* @__PURE__ */ jsx(Base, {}, "base")] : [/* @__PURE__ */ jsx(Ethereum, {}, "eth"), /* @__PURE__ */ jsx(Tron, {}, "tron"), /* @__PURE__ */ jsx(Base, {}, "base")]; return { id: "depositAddress", title: locales.payToAddress, icons, onClick: () => { setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN); } }; } export { SelectMethod as default }; //# sourceMappingURL=index.js.map