@daimo/pay
Version:
Seamless crypto payments. Onboard users from any chain, any coin into your app with one click.
212 lines (209 loc) • 10.1 kB
JavaScript
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 { getAddressContraction } from '@daimo/pay-common';
import { useWallet } from '@solana/wallet-adapter-react';
import { useAccount, useDisconnect } from 'wagmi';
import { Ethereum, Solana, Tron, Base } from '../../../assets/chains.js';
import { WalletIcon, Trust, Rainbow, Phantom, Rabby, MetaMask } from '../../../assets/logos.js';
import useIsMobile from '../../../hooks/useIsMobile.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 { isMobile, isIOS, isAndroid } = useIsMobile();
const { address, chain, isConnected: isEthConnected, connector, } = useAccount();
const { connected: isSolanaConnected, wallet: solanaWallet, wallets: solanaWallets, disconnect: disconnectSolana, publicKey, } = useWallet();
const { setRoute, paymentState, log, disableMobileInjector } = usePayContext();
const { showSolanaPaymentMethod } = paymentState;
const { disconnectAsync } = useDisconnect();
const { externalPaymentOptions, senderEnsName } = paymentState;
// Decide whether to show the connected eth account, solana account, or both.
// Desktop: Always show connected wallets when available
// Mobile: Only show connected wallets when mobile injector is enabled (!disableMobileInjector)
const showConnectedEth = isEthConnected && (!isMobile || !disableMobileInjector);
const showConnectedSolana = isSolanaConnected && (!isMobile || !disableMobileInjector);
const getConnectedWalletOptions = () => {
const showChainLogo = isEthConnected && isSolanaConnected && showSolanaPaymentMethod;
const connectedOptions = [];
if (showConnectedEth) {
const ethWalletDisplayName = senderEnsName ?? (address ? getAddressContraction(address) : "wallet");
// Prefer icon from walletConfigs if there's a name match, otherwise fall back
// to the connector-provided icon, and finally to the generic WalletIcon.
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" ? (jsx("img", { src: matchedConfig.icon, alt: matchedConfig.name })) : matchedConfig.icon;
}
else if (connector?.icon) {
walletIcon = (jsx("div", { style: { borderRadius: "22.5%", overflow: "hidden" }, children: jsx("img", { src: connector.icon, alt: connector.name }) }));
}
else {
walletIcon = jsx(WalletIcon, {});
}
const connectedEthWalletOption = {
id: "connectedWallet",
title: `Pay with ${ethWalletDisplayName}`,
icons: [
jsx(WalletChainLogo, { walletIcon: walletIcon, walletName: connector?.name || "Wallet", chainLogo: showChainLogo ? jsx(Ethereum, {}) : null }, "eth"),
],
onClick: () => {
paymentState.setTokenMode("evm");
setRoute(ROUTES.SELECT_TOKEN, {
event: "click-wallet",
walletId: connector?.id,
chainId: chain?.id,
address: address,
});
},
};
connectedOptions.push(connectedEthWalletOption);
}
if (showConnectedSolana && showSolanaPaymentMethod) {
const solWalletDisplayName = getAddressContraction(publicKey?.toBase58() ?? "");
// Prefer icon from walletConfigs if available
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" ? (jsx("img", { src: solMatchedConfig.icon, alt: solMatchedConfig.name })) : solMatchedConfig.icon;
}
else if (solanaWallet?.adapter.icon) {
solWalletIcon = solanaWallet.adapter.icon;
}
else {
solWalletIcon = jsx(Solana, {});
}
const connectedSolWalletOption = {
id: "connectedSolanaWallet",
title: `Pay with ${solWalletDisplayName}`,
icons: [
jsx(WalletChainLogo, { walletIcon: solWalletIcon, walletName: solanaWallet?.adapter.name || "Wallet", chainLogo: showChainLogo && 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 unconnectedWalletOption = {
id: "unconnectedWallet",
title: isEthConnected || isSolanaConnected
? `Pay with another wallet`
: `Pay with wallet`,
icons: getBestUnconnectedWalletIcons(connector, isMobile),
onClick: async () => {
await disconnectAsync();
await disconnectSolana();
setRoute(ROUTES.CONNECTORS);
},
};
const options = [];
options.push(...connectedWalletOptions);
options.push(unconnectedWalletOption);
log(`[SELECT_METHOD] loading: ${externalPaymentOptions.loading}, options: ${JSON.stringify(externalPaymentOptions.options)}`);
// Pay with Exchange
const exchangeOptions = externalPaymentOptions.options.get("exchange") ?? [];
const showExchangePaymentMethod = exchangeOptions.length > 0;
if (showExchangePaymentMethod) {
options.push({
id: "exchange",
title: "Pay with exchange",
icons: exchangeOptions.slice(0, 3).map((option) => option.logoURI),
onClick: () => {
setRoute(ROUTES.SELECT_EXCHANGE, {
event: "click-option",
option: "exchange",
});
},
});
}
const depositAddressOption = getDepositAddressOption(setRoute);
options.push(depositAddressOption);
// ZKP2P is currently only available on desktop. Check if the user is on
// desktop and if any ZKP2P options are available.
const zkp2pOptions = externalPaymentOptions.options.get("zkp2p") ?? [];
const showZkp2pPaymentMethod = !isMobile && zkp2pOptions.length > 0;
if (showZkp2pPaymentMethod) {
options.push({
id: "ZKP2P",
title: "Pay via payment app",
icons: zkp2pOptions.slice(0, 2).map((option) => option.logoURI),
onClick: () => {
setRoute(ROUTES.SELECT_ZKP2P);
},
});
}
// Order disabled to bottom
options.sort((a, b) => (a.disabled ? 1 : 0) - (b.disabled ? 1 : 0));
return (jsxs(PageContent, { children: [jsx(OrderHeader, {}), jsx(OptionsList, { requiredSkeletons: isMobile ? 4 : 3, isLoading: externalPaymentOptions.loading, options: externalPaymentOptions.loading ? [] : options }), jsx(PoweredByFooter, {})] }));
}
// Get 3 icons, skipping the one that is already connected
function getBestUnconnectedWalletIcons(connector, isMobile) {
const icons = [];
const strippedId = connector?.id.toLowerCase(); // some connector ids can have weird casing and or suffixes and prefixes
const [isRainbow, isTrust, isPhantom, isCoinbase, isMetamask, isRabby] = [
strippedId?.includes("rainbow"),
strippedId?.includes("trust"),
strippedId?.includes("phantom"),
strippedId?.includes("coinbase"),
strippedId?.includes("metamask"),
strippedId?.includes("rabby"),
];
if (isMobile) {
if (!isTrust)
icons.push(jsx(Trust, { background: true }));
if (!isRainbow)
icons.push(jsx(Rainbow, {}));
if (!isPhantom)
icons.push(jsx(Phantom, {}));
}
else {
if (!isRainbow)
icons.push(jsx(Rainbow, {}));
if (!isPhantom)
icons.push(jsx(Phantom, {}));
if (!isRabby)
icons.push(jsx(Rabby, {}));
if (!isMetamask && icons.length < 3)
icons.push(jsx(MetaMask, {}));
}
return icons;
}
function getDepositAddressOption(setRoute) {
return {
id: "depositAddress",
title: "Pay to address",
icons: [jsx(Ethereum, {}, "eth"), jsx(Tron, {}, "tron"), jsx(Base, {}, "base")],
onClick: () => {
setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN);
},
};
}
export { SelectMethod as default };
//# sourceMappingURL=index.js.map