UNPKG

@daimo/pay

Version:

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

463 lines (460 loc) 20.5 kB
import { jsx } from 'react/jsx-runtime'; import { useWallet } from '@solana/wallet-adapter-react'; import { useEffect } from 'react'; import { useAccount } from 'wagmi'; import { ExternalPaymentOptions, DepositAddressPaymentOptions } from '@daimo/pay-common'; 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); const closeable = !(context.options?.enforceSupportedChains && isEthConnected && !chainIsSupported); const showBackButton = closeable && context.route !== context.uniquePaymentMethodPage && 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(void 0); context.setRoute(ROUTES.SELECT_TOKEN, meta); } else if (context.route === ROUTES.SELECT_EXTERNAL_AMOUNT) { setSelectedExternalOption(void 0); context.setRoute(context.uniquePaymentMethodPage, meta); } else if (context.route === ROUTES.SELECT_DEPOSIT_ADDRESS_AMOUNT) { setSelectedDepositAddressOption(void 0); context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN, meta); } else if (context.route === ROUTES.WAITING_EXTERNAL) { setPaymentWaitingMessage(void 0); if (isDepositFlow) { generatePreviewOrder(); context.setRoute(ROUTES.SELECT_EXTERNAL_AMOUNT, meta); } else { setSelectedExternalOption(void 0); context.setRoute(context.uniquePaymentMethodPage, meta); } } else if (context.route === ROUTES.PAY_WITH_TOKEN) { if (isDepositFlow) { generatePreviewOrder(); context.setRoute(ROUTES.SELECT_AMOUNT, meta); } else { setSelectedTokenOption(void 0); 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 === void 0) { context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN, meta); } else { generatePreviewOrder(); context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_AMOUNT, meta); } } else { setSelectedDepositAddressOption(void 0); 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(void 0); context.setRoute(ROUTES.CONNECTORS, meta); } } else if (context.route === ROUTES.SOLANA_SELECT_AMOUNT) { setSelectedSolanaTokenOption(void 0); 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(void 0); context.setRoute(ROUTES.SELECT_TOKEN, meta); } } else { context.setRoute(context.uniquePaymentMethodPage, meta); } }; const pages = { [ROUTES.SELECT_METHOD]: /* @__PURE__ */ jsx(SelectMethod, {}), [ROUTES.SELECT_TOKEN]: /* @__PURE__ */ jsx(SelectToken, {}), [ROUTES.SELECT_AMOUNT]: /* @__PURE__ */ jsx(SelectAmount, {}), [ROUTES.SELECT_EXTERNAL_AMOUNT]: /* @__PURE__ */ jsx(SelectExternalAmount, {}), [ROUTES.SELECT_EXCHANGE]: /* @__PURE__ */ jsx(SelectExchange, {}), [ROUTES.SELECT_DEPOSIT_ADDRESS_AMOUNT]: /* @__PURE__ */ jsx(SelectDepositAddressAmount, {}), [ROUTES.SELECT_WALLET_AMOUNT]: /* @__PURE__ */ jsx(SelectWalletAmount, {}), [ROUTES.SELECT_WALLET_CHAIN]: /* @__PURE__ */ jsx(SelectWalletChain, {}), [ROUTES.WAITING_EXTERNAL]: /* @__PURE__ */ jsx(WaitingExternal, {}), [ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN]: /* @__PURE__ */ jsx(SelectDepositAddressChain, {}), [ROUTES.WAITING_DEPOSIT_ADDRESS]: /* @__PURE__ */ jsx(WaitingDepositAddress, {}), [ROUTES.SELECT_ZKP2P]: /* @__PURE__ */ jsx(SelectZKP, {}), [ROUTES.WAITING_WALLET]: /* @__PURE__ */ jsx(WaitingWallet, {}), [ROUTES.CONFIRMATION]: /* @__PURE__ */ jsx(Confirmation, {}), [ROUTES.ERROR]: /* @__PURE__ */ jsx(ErrorPage, {}), [ROUTES.PAY_WITH_TOKEN]: /* @__PURE__ */ jsx(PayWithToken, {}), [ROUTES.SOLANA_CONNECTOR]: /* @__PURE__ */ jsx(ConnectSolana, {}), [ROUTES.SOLANA_SELECT_AMOUNT]: /* @__PURE__ */ jsx(SelectSolanaAmount, {}), [ROUTES.SOLANA_PAY_WITH_TOKEN]: /* @__PURE__ */ jsx(PayWithSolanaToken, {}), // Unused routes. Kept to minimize connectkit merge conflicts. [ROUTES.ONBOARDING]: /* @__PURE__ */ jsx(Introduction, {}), [ROUTES.ABOUT]: /* @__PURE__ */ jsx(About, {}), [ROUTES.DOWNLOAD]: /* @__PURE__ */ jsx(DownloadApp, {}), [ROUTES.CONNECTORS]: /* @__PURE__ */ jsx(Wallets, {}), [ROUTES.MOBILECONNECTORS]: /* @__PURE__ */ jsx(MobileConnectors, {}), [ROUTES.CONNECT]: /* @__PURE__ */ jsx(ConnectUsing, {}), [ROUTES.SWITCHNETWORKS]: /* @__PURE__ */ jsx(SwitchNetworks, {}) }; function hide() { if (isDepositFlow) { generatePreviewOrder(); } context.setOpen(false, { event: "click-close" }); } const goToManualAddressScreen = (eventSuffix) => { if (paymentState.isDepositFlow) { context.setUniquePaymentMethodPage(ROUTES.SELECT_DEPOSIT_ADDRESS_AMOUNT); context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_AMOUNT, { event: `unique_payment_option_deposit_${eventSuffix}` }); } else { context.setUniquePaymentMethodPage(ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN); context.setRoute(ROUTES.WAITING_DEPOSIT_ADDRESS, { event: `unique_payment_option_${eventSuffix}` }); } }; const { isMobile } = useIsMobile(); useEffect(() => { if (!context.open) return; if (context.route !== ROUTES.SELECT_METHOD) return; if (paymentState.buttonProps && "uniquePaymentOption" in paymentState.buttonProps && paymentState.buttonProps.uniquePaymentOption) { switch (paymentState.buttonProps.uniquePaymentOption) { case "Tron": const tronOption = paymentState.depositAddressOptions.options?.find( (option) => option.id === DepositAddressPaymentOptions.TRON_USDT ); if (tronOption) { setSelectedDepositAddressOption(tronOption); goToManualAddressScreen("tron"); } else if (!paymentState.depositAddressOptions.loading) { context.setUniquePaymentMethodPage( ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN ); context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN, { event: "unique_payment_option_tron_fallback" }); } break; case "AllExchanges": context.setUniquePaymentMethodPage(ROUTES.SELECT_EXCHANGE); context.setRoute(ROUTES.SELECT_EXCHANGE, { event: "unique_payment_option_all_exchanges" }); break; case "ManualAddress": context.setUniquePaymentMethodPage( ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN ); context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN, { event: "unique_payment_option_manual_address" }); break; case "Base": const baseOption = paymentState.depositAddressOptions.options?.find( (option) => option.id === DepositAddressPaymentOptions.BASE ); if (baseOption) { setSelectedDepositAddressOption(baseOption); goToManualAddressScreen("base"); } else if (!paymentState.depositAddressOptions.loading) { context.setUniquePaymentMethodPage( ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN ); context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN, { event: "unique_payment_option_base_fallback" }); } break; case "Arbitrum": const arbitrumOption = paymentState.depositAddressOptions.options?.find( (option) => option.id === DepositAddressPaymentOptions.ARBITRUM ); if (arbitrumOption) { setSelectedDepositAddressOption(arbitrumOption); goToManualAddressScreen("arbitrum"); } else if (!paymentState.depositAddressOptions.loading) { context.setUniquePaymentMethodPage( ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN ); context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN, { event: "unique_payment_option_arbitrum_fallback" }); } break; case "Optimism": const optimismOption = paymentState.depositAddressOptions.options?.find( (option) => option.id === DepositAddressPaymentOptions.OP_MAINNET ); if (optimismOption) { setSelectedDepositAddressOption(optimismOption); goToManualAddressScreen("optimism"); } else if (!paymentState.depositAddressOptions.loading) { context.setUniquePaymentMethodPage( ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN ); context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN, { event: "unique_payment_option_optimism_fallback" }); } break; case "Polygon": const polygonOption = paymentState.depositAddressOptions.options?.find( (option) => option.id === DepositAddressPaymentOptions.POLYGON ); if (polygonOption) { setSelectedDepositAddressOption(polygonOption); goToManualAddressScreen("polygon"); } else if (!paymentState.depositAddressOptions.loading) { context.setUniquePaymentMethodPage( ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN ); context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN, { event: "unique_payment_option_polygon_fallback" }); } break; case "Ethereum": const ethereumOption = paymentState.depositAddressOptions.options?.find( (option) => option.id === DepositAddressPaymentOptions.ETH_L1 ); if (ethereumOption) { setSelectedDepositAddressOption(ethereumOption); goToManualAddressScreen("ethereum"); } else if (!paymentState.depositAddressOptions.loading) { context.setUniquePaymentMethodPage( ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN ); context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN, { event: "unique_payment_option_ethereum_fallback" }); } break; case "Binance": const exchangeOptions = paymentState.externalPaymentOptions.options.get("exchange"); const binanceOption = exchangeOptions?.find( (option) => option.id === ExternalPaymentOptions.Binance ); if (binanceOption) { setSelectedExternalOption(binanceOption); context.setUniquePaymentMethodPage(ROUTES.WAITING_EXTERNAL); context.setRoute(ROUTES.WAITING_EXTERNAL, { event: "unique_payment_option_binance" }); } else if (!paymentState.externalPaymentOptions.loading) { context.setUniquePaymentMethodPage(ROUTES.SELECT_EXCHANGE); context.setRoute(ROUTES.SELECT_EXCHANGE, { event: "unique_payment_option_binance_fallback" }); } break; case "Coinbase": const coinbaseExchangeOptions = paymentState.externalPaymentOptions.options.get("exchange"); const coinbaseOption = coinbaseExchangeOptions?.find( (option) => option.id === ExternalPaymentOptions.Coinbase ); if (coinbaseOption) { setSelectedExternalOption(coinbaseOption); context.setUniquePaymentMethodPage(ROUTES.WAITING_EXTERNAL); context.setRoute(ROUTES.WAITING_EXTERNAL, { event: "unique_payment_option_coinbase" }); } else if (!paymentState.externalPaymentOptions.loading) { context.setUniquePaymentMethodPage(ROUTES.SELECT_EXCHANGE); context.setRoute(ROUTES.SELECT_EXCHANGE, { event: "unique_payment_option_coinbase_fallback" }); } break; case "Lemon": const lemonExternalOptions = paymentState.externalPaymentOptions.options.get("external"); const lemonOption = lemonExternalOptions?.find( (option) => option.id === ExternalPaymentOptions.Lemon ); if (lemonOption) { setSelectedExternalOption(lemonOption); context.setUniquePaymentMethodPage(ROUTES.WAITING_EXTERNAL); context.setRoute(ROUTES.WAITING_EXTERNAL, { event: "unique_payment_option_lemon" }); } else if (!paymentState.externalPaymentOptions.loading) { context.setUniquePaymentMethodPage(ROUTES.SELECT_METHOD); context.setRoute(ROUTES.SELECT_METHOD, { event: "unique_payment_option_lemon_fallback" }); } break; case "Wallets": context.setUniquePaymentMethodPage(ROUTES.CONNECTORS); context.setRoute(ROUTES.CONNECTORS, { event: "unique_payment_option_wallets" }); break; default: context.setUniquePaymentMethodPage(ROUTES.SELECT_METHOD); break; } } const hasUniquePaymentOption = paymentState.buttonProps && "uniquePaymentOption" in paymentState.buttonProps && paymentState.buttonProps.uniquePaymentOption; const isWalletsUniquePaymentOption = paymentState.buttonProps?.uniquePaymentOption === "Wallets"; const evmOptionsCount = paymentState.walletPaymentOptions.options?.length ?? 0; const isEvmLoading = paymentState.walletPaymentOptions.isLoading; const solanaOptionsCount = paymentState.solanaPaymentOptions.options?.length ?? 0; const isSolanaLoading = paymentState.solanaPaymentOptions.isLoading; if ((!hasUniquePaymentOption || isWalletsUniquePaymentOption) && isEthConnected && !isSolanaConnected && (!isMobile || !disableMobileInjector) && !isEvmLoading && evmOptionsCount > 0) { paymentState.setTokenMode("evm"); context.setRoute(ROUTES.SELECT_TOKEN, { event: "eth_connected_on_open", walletId: connector?.id, chainId: chain?.id, address }); } else if ((!hasUniquePaymentOption || isWalletsUniquePaymentOption) && isSolanaConnected && !isEthConnected && showSolanaPaymentMethod && !disableMobileInjector && !isSolanaLoading && solanaOptionsCount > 0) { paymentState.setTokenMode("solana"); context.setRoute(ROUTES.SELECT_TOKEN, { event: "solana_connected_on_open" }); } }, [ context.open, paymentState.walletPaymentOptions.options, paymentState.walletPaymentOptions.isLoading, paymentState.solanaPaymentOptions.options, paymentState.solanaPaymentOptions.isLoading, paymentState.externalPaymentOptions.options, paymentState.externalPaymentOptions.loading, paymentState.depositAddressOptions.options, paymentState.depositAddressOptions.loading, showSolanaPaymentMethod, address, chain?.id, connector?.id, context.uniquePaymentMethodPage ]); 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 }); } } }, [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 { } }; }, [context.open]); return /* @__PURE__ */ jsx(DaimoPayThemeProvider, { theme, customTheme, mode, children: /* @__PURE__ */ jsx( Modal, { open: context.open, pages, pageId: context.route, onClose: closeable ? hide : void 0, onInfo: void 0, onBack: showBackButton ? onBack : void 0 } ) }); }; export { DaimoPayModal }; //# sourceMappingURL=index.js.map