UNPKG

@daimo/pay

Version:

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

272 lines (269 loc) 12.7 kB
import { jsx } from 'react/jsx-runtime'; import { useWallet } from '@solana/wallet-adapter-react'; import { useEffect } from 'react'; import { useAccount } from 'wagmi'; import { ROUTES } from '../../constants/routes.js'; import { getAppName } from '../../defaultConfig.js'; import { useChainIsSupported } from '../../hooks/useChainIsSupported.js'; import { useDaimoPay } from '../../hooks/useDaimoPay.js'; import useIsMobile from '../../hooks/useIsMobile.js'; import { usePayContext } from '../../hooks/usePayContext.js'; import Modal from '../Common/Modal/index.js'; import { DaimoPayThemeProvider } from '../DaimoPayThemeProvider/DaimoPayThemeProvider.js'; import About from '../Pages/About/index.js'; import Confirmation from '../Pages/Confirmation/index.js'; import Wallets from '../Pages/Connectors/index.js'; import DownloadApp from '../Pages/DownloadApp/index.js'; import ErrorPage from '../Pages/Error/index.js'; import MobileConnectors from '../Pages/MobileConnectors/index.js'; import Introduction from '../Pages/Onboarding/index.js'; import PayWithToken from '../Pages/PayWithToken/index.js'; import SelectAmount from '../Pages/SelectAmount/index.js'; import SelectDepositAddressAmount from '../Pages/SelectDepositAddressAmount/index.js'; import SelectDepositAddressChain from '../Pages/SelectDepositAddressChain/index.js'; import SelectExchange from '../Pages/SelectExchange/index.js'; import SelectExternalAmount from '../Pages/SelectExternalAmount/index.js'; import SelectMethod from '../Pages/SelectMethod/index.js'; import SelectToken from '../Pages/SelectToken/index.js'; import SelectWalletAmount from '../Pages/SelectWalletAmount/index.js'; import SelectWalletChain from '../Pages/SelectWalletChain/index.js'; import SelectZKP from '../Pages/SelectZKP/index.js'; import ConnectSolana from '../Pages/Solana/ConnectorSolana/index.js'; import PayWithSolanaToken from '../Pages/Solana/PayWithSolanaToken/index.js'; import SelectSolanaAmount from '../Pages/Solana/SelectSolanaAmount/index.js'; import SwitchNetworks from '../Pages/SwitchNetworks/index.js'; import WaitingDepositAddress from '../Pages/WaitingDepositAddress/index.js'; import WaitingExternal from '../Pages/WaitingExternal/index.js'; import WaitingWallet from '../Pages/WaitingWallet/index.js'; import ConnectUsing from './ConnectUsing.js'; const DaimoPayModal = ({ mode, theme, customTheme, lang, disableMobileInjector, }) => { const context = usePayContext(); const { setMode, setTheme, setCustomTheme, setLang, setDisableMobileInjector, } = context; const paymentState = context.paymentState; const { generatePreviewOrder, isDepositFlow, showSolanaPaymentMethod, setPaymentWaitingMessage, setSelectedExternalOption, setSelectedTokenOption, setSelectedSolanaTokenOption, setSelectedDepositAddressOption, setSelectedWallet, } = paymentState; const { paymentState: paymentFsmState } = useDaimoPay(); const { isConnected: isEthConnected, connector, chain, address, } = useAccount(); const { connected: isSolanaConnected } = useWallet(); const chainIsSupported = useChainIsSupported(chain?.id); //if chain is unsupported we enforce a "switch chain" prompt const closeable = !(context.options?.enforceSupportedChains && isEthConnected && !chainIsSupported); const showBackButton = closeable && context.route !== ROUTES.SELECT_METHOD && context.route !== ROUTES.CONFIRMATION && context.route !== ROUTES.SELECT_TOKEN && context.route !== ROUTES.ERROR && paymentFsmState !== "error"; const onBack = () => { const meta = { event: "click-back" }; if (context.route === ROUTES.DOWNLOAD) { context.setRoute(ROUTES.CONNECT, meta); } else if (context.route === ROUTES.CONNECTORS) { context.setRoute(ROUTES.SELECT_METHOD, meta); } else if (context.route === ROUTES.SELECT_AMOUNT) { setSelectedTokenOption(undefined); context.setRoute(ROUTES.SELECT_TOKEN, meta); } else if (context.route === ROUTES.SELECT_EXTERNAL_AMOUNT) { setSelectedExternalOption(undefined); context.setRoute(ROUTES.SELECT_METHOD, meta); } else if (context.route === ROUTES.SELECT_DEPOSIT_ADDRESS_AMOUNT) { setSelectedDepositAddressOption(undefined); context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN, meta); } else if (context.route === ROUTES.SELECT_ZKP2P) { context.setRoute(ROUTES.SELECT_METHOD, meta); } else if (context.route === ROUTES.WAITING_EXTERNAL) { setPaymentWaitingMessage(undefined); if (isDepositFlow) { generatePreviewOrder(); context.setRoute(ROUTES.SELECT_EXTERNAL_AMOUNT, meta); } else { setSelectedExternalOption(undefined); context.setRoute(ROUTES.SELECT_METHOD, meta); } } else if (context.route === ROUTES.PAY_WITH_TOKEN) { if (isDepositFlow) { generatePreviewOrder(); context.setRoute(ROUTES.SELECT_AMOUNT, meta); } else { setSelectedTokenOption(undefined); context.setRoute(ROUTES.SELECT_TOKEN, meta); } } else if (context.route === ROUTES.ONBOARDING) { context.setRoute(ROUTES.CONNECTORS, meta); } else if (context.route === ROUTES.WAITING_DEPOSIT_ADDRESS) { if (isDepositFlow) { if (paymentState.selectedDepositAddressOption === undefined) { context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN, meta); } else { generatePreviewOrder(); context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_AMOUNT, meta); } } else { setSelectedDepositAddressOption(undefined); context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN, meta); } } else if (context.route === ROUTES.WAITING_WALLET) { if (isDepositFlow) { generatePreviewOrder(); context.setRoute(ROUTES.SELECT_WALLET_AMOUNT, meta); } else { setSelectedWallet(undefined); context.setRoute(ROUTES.SELECT_METHOD, meta); } } else if (context.route === ROUTES.SOLANA_SELECT_AMOUNT) { setSelectedSolanaTokenOption(undefined); context.setRoute(ROUTES.SELECT_TOKEN, meta); } else if (context.route === ROUTES.SOLANA_PAY_WITH_TOKEN) { if (isDepositFlow) { generatePreviewOrder(); context.setRoute(ROUTES.SOLANA_SELECT_AMOUNT, meta); } else { setSelectedSolanaTokenOption(undefined); context.setRoute(ROUTES.SELECT_TOKEN, meta); } } else { context.setRoute(ROUTES.SELECT_METHOD, meta); } }; const pages = { [ROUTES.SELECT_METHOD]: jsx(SelectMethod, {}), [ROUTES.SELECT_TOKEN]: jsx(SelectToken, {}), [ROUTES.SELECT_AMOUNT]: jsx(SelectAmount, {}), [ROUTES.SELECT_EXTERNAL_AMOUNT]: jsx(SelectExternalAmount, {}), [ROUTES.SELECT_EXCHANGE]: jsx(SelectExchange, {}), [ROUTES.SELECT_DEPOSIT_ADDRESS_AMOUNT]: jsx(SelectDepositAddressAmount, {}), [ROUTES.SELECT_WALLET_AMOUNT]: jsx(SelectWalletAmount, {}), [ROUTES.SELECT_WALLET_CHAIN]: jsx(SelectWalletChain, {}), [ROUTES.WAITING_EXTERNAL]: jsx(WaitingExternal, {}), [ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN]: jsx(SelectDepositAddressChain, {}), [ROUTES.WAITING_DEPOSIT_ADDRESS]: jsx(WaitingDepositAddress, {}), [ROUTES.SELECT_ZKP2P]: jsx(SelectZKP, {}), [ROUTES.WAITING_WALLET]: jsx(WaitingWallet, {}), [ROUTES.CONFIRMATION]: jsx(Confirmation, {}), [ROUTES.ERROR]: jsx(ErrorPage, {}), [ROUTES.PAY_WITH_TOKEN]: jsx(PayWithToken, {}), [ROUTES.SOLANA_CONNECTOR]: jsx(ConnectSolana, {}), [ROUTES.SOLANA_SELECT_AMOUNT]: jsx(SelectSolanaAmount, {}), [ROUTES.SOLANA_PAY_WITH_TOKEN]: jsx(PayWithSolanaToken, {}), // Unused routes. Kept to minimize connectkit merge conflicts. [ROUTES.ONBOARDING]: jsx(Introduction, {}), [ROUTES.ABOUT]: jsx(About, {}), [ROUTES.DOWNLOAD]: jsx(DownloadApp, {}), [ROUTES.CONNECTORS]: jsx(Wallets, {}), [ROUTES.MOBILECONNECTORS]: jsx(MobileConnectors, {}), [ROUTES.CONNECT]: jsx(ConnectUsing, {}), [ROUTES.SWITCHNETWORKS]: jsx(SwitchNetworks, {}), }; function hide() { if (isDepositFlow) { generatePreviewOrder(); } context.setOpen(false, { event: "click-close" }); } const { isMobile } = useIsMobile(); // If the user has a wallet already connected upon opening the modal, go // straight to the select token screen useEffect(() => { if (!context.open) return; if (context.route !== ROUTES.SELECT_METHOD) return; // Skip to token selection if exactly one wallet is connected. If both // wallets are connected, stay on the SELECT_METHOD screen to allow the // user to select which wallet to use // If mobile injector is disabled, don't show the connected wallets. if (isEthConnected && !isSolanaConnected && (!isMobile || !disableMobileInjector)) { paymentState.setTokenMode("evm"); context.setRoute(ROUTES.SELECT_TOKEN, { event: "eth_connected_on_open", walletId: connector?.id, chainId: chain?.id, address, }); } else if (isSolanaConnected && !isEthConnected && showSolanaPaymentMethod && !disableMobileInjector) { paymentState.setTokenMode("solana"); context.setRoute(ROUTES.SELECT_TOKEN, { event: "solana_connected_on_open", }); } // Don't include context.route in the dependency array otherwise the user // can't go back from the select token screen to the select method screen // eslint-disable-next-line react-hooks/exhaustive-deps }, [ context.open, paymentState.walletPaymentOptions.options, paymentState.solanaPaymentOptions.options, showSolanaPaymentMethod, address, chain?.id, connector?.id, ]); // If we're on the connect page and the user successfully connects their // wallet, go to the select token page useEffect(() => { if (context.route === ROUTES.CONNECT || context.route === ROUTES.CONNECTORS || context.route === ROUTES.MOBILECONNECTORS) { if (isEthConnected) { paymentState.setTokenMode("evm"); context.setRoute(ROUTES.SELECT_TOKEN, { event: "connected", walletId: connector?.id, chainId: chain?.id, address, }); } } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isEthConnected, context.route, connector?.id, chain?.id, address]); useEffect(() => setMode(mode), [mode, setMode]); useEffect(() => setTheme(theme), [theme, setTheme]); useEffect(() => setCustomTheme(customTheme), [customTheme, setCustomTheme]); useEffect(() => setLang(lang), [lang, setLang]); useEffect(() => setDisableMobileInjector(disableMobileInjector), [disableMobileInjector, setDisableMobileInjector]); useEffect(() => { const appName = getAppName(); if (!appName || !context.open) return; const title = document.createElement("meta"); title.setAttribute("property", "og:title"); title.setAttribute("content", appName); document.head.prepend(title); return () => { try { document.head.removeChild(title); } catch { } //if (appIcon) document.head.removeChild(icon); }; }, [context.open]); return (jsx(DaimoPayThemeProvider, { theme: theme, customTheme: customTheme, mode: mode, children: jsx(Modal, { open: context.open, pages: pages, pageId: context.route, onClose: closeable ? hide : undefined, onInfo: undefined, onBack: showBackButton ? onBack : undefined }) })); }; export { DaimoPayModal }; //# sourceMappingURL=index.js.map