UNPKG

@daimo/pay

Version:

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

167 lines (164 loc) 7.13 kB
import { jsxs, jsx } from 'react/jsx-runtime'; import { useState, useEffect } from 'react'; import { usePayContext } from '../../../hooks/usePayContext.js'; import { PageContent, ModalContent, ModalBody } from '../Modal/styles.js'; import { parseUnits } from 'viem'; import styled from '../../../styles/styled/index.js'; import { formatUsd, roundTokenAmount, roundUsd, USD_DECIMALS, tokenAmountToRoundedUsd, usdToRoundedTokenAmount, roundTokenAmountUnits } from '../../../utils/format.js'; import { isValidNumber, sanitizeNumber } from '../../../utils/validateInput.js'; import Button from '../Button/index.js'; import SwitchButton from '../SwitchButton/index.js'; import TokenLogoSpinner from '../../Spinners/TokenLogoSpinner/index.js'; import AmountInputField from './AmountInputField.js'; const MultiCurrencySelectAmount = ({ selectedTokenOption, setSelectedTokenOption, nextPage }) => { const { paymentState, setRoute, triggerResize } = usePayContext(); const maxUsdLimit = paymentState.getOrderUsdLimit(); const balanceToken = selectedTokenOption.balance.token; const isUsdStablecoin = balanceToken.fiatISO === "USD"; const usdBalanceMessage = isUsdStablecoin ? `Balance: ${formatUsd(selectedTokenOption.balance.usd)}` : `Balance: ${formatUsd(selectedTokenOption.balance.usd)} ${balanceToken.symbol}`; const tokenBalanceMessage = `Balance: ${roundTokenAmount(selectedTokenOption.balance.amount, balanceToken)} ${balanceToken.symbol}`; const getBalanceMessage = (editingUsd) => editingUsd ? usdBalanceMessage : tokenBalanceMessage; const [usdStr, setUsdValue] = useState(""); const [tokenStr, setTokenValue] = useState(""); const [isEditingUsd, setIsEditingUsd] = useState(true); const [message, setMessage] = useState(usdBalanceMessage); const [continueDisabled, setContinueDisabled] = useState(true); useEffect(() => { triggerResize(); }, [message]); const updateValues = (newUsdValue, newTokenValue, newIsEditingUsd) => { const sanitizedUsdValue = sanitizeNumber(newUsdValue); const sanitizedTokenValue = sanitizeNumber(newTokenValue); const usdNum = Number(sanitizedUsdValue); const tokenNum = Number(sanitizedTokenValue); const stripTrailingZeros = (val) => val.includes(".") ? val.replace(/\.?0+$/, "") : val; setUsdValue( newIsEditingUsd ? newUsdValue : usdNum > 0 ? roundUsd(usdNum) : "" ); setTokenValue( newIsEditingUsd ? tokenNum > 0 ? stripTrailingZeros(roundTokenAmountUnits(tokenNum, balanceToken)) : "" : newTokenValue ); setIsEditingUsd(newIsEditingUsd); setContinueDisabled( usdNum <= 0 || usdNum < selectedTokenOption.minimumRequired.usd || usdNum > selectedTokenOption.balance.usd || usdNum > maxUsdLimit ); const formatAmount = (usd) => newIsEditingUsd ? formatUsd(usd) : `${usdToRoundedTokenAmount(usd, balanceToken)} ${balanceToken.symbol}`; if (usdNum > selectedTokenOption.balance.usd) { setMessage( `Amount exceeds your balance: ${formatAmount(selectedTokenOption.balance.usd)}` ); } else if (usdNum > maxUsdLimit) { setMessage(`Maximum ${formatAmount(maxUsdLimit)}`); } else if (usdNum > 0 && usdNum < selectedTokenOption.minimumRequired.usd) { setMessage( `Minimum ${formatAmount(selectedTokenOption.minimumRequired.usd)}` ); } else { setMessage(getBalanceMessage(newIsEditingUsd)); } }; const handleAmountChange = (e) => { const value = e.target.value; const maxDecimals = isEditingUsd ? USD_DECIMALS : balanceToken.displayDecimals; if (value !== "" && !isValidNumber(value, maxDecimals)) return; const sanitizedValue = sanitizeNumber(value); const newUsdValue = isEditingUsd ? value : tokenAmountToRoundedUsd( parseUnits(sanitizedValue, balanceToken.decimals), balanceToken ); const newTokenValue = isEditingUsd ? usdToRoundedTokenAmount(Number(sanitizedValue), balanceToken) : value; updateValues(newUsdValue, newTokenValue, isEditingUsd); }; const handleMax = () => { const usdStr2 = roundUsd(Number(selectedTokenOption.balance.usd)); const tokenStr2 = roundTokenAmount( selectedTokenOption.balance.amount, balanceToken ); updateValues(usdStr2, tokenStr2, isEditingUsd); }; const handleKeyDown = (e) => { if (e.key === "Enter" && !continueDisabled) { handleContinue(); } }; const handleSwitchCurrency = () => { updateValues(usdStr, tokenStr, !isEditingUsd); }; const handleContinue = () => { const usd = Number(sanitizeNumber(usdStr)); const amountUnits = usd / balanceToken.usd; const amount = parseUnits(amountUnits.toString(), balanceToken.decimals); setSelectedTokenOption({ ...selectedTokenOption, required: { token: balanceToken, amount: amount.toString(), usd } }); paymentState.setChosenUsd(usd); setRoute(nextPage, { amountUsd: usd, amountUnits, tokenSymbol: balanceToken.symbol }); }; return /* @__PURE__ */ jsxs(PageContent, { children: [ /* @__PURE__ */ jsx(TokenLogoSpinner, { token: balanceToken }), /* @__PURE__ */ jsxs(ModalContent, { $preserveDisplay: true, children: [ /* @__PURE__ */ jsxs(AmountInputContainer, { children: [ /* @__PURE__ */ jsx(MaxButton, { style: { visibility: "hidden" }, children: "Max" }), /* @__PURE__ */ jsx( AmountInputField, { value: isEditingUsd ? usdStr : tokenStr, onChange: handleAmountChange, currency: isEditingUsd ? "$" : balanceToken.symbol, onKeyDown: handleKeyDown } ), /* @__PURE__ */ jsx(MaxButton, { onClick: handleMax, children: "Max" }) ] }), balanceToken.fiatISO !== "USD" && /* @__PURE__ */ jsx(SwitchContainer, { children: /* @__PURE__ */ jsx(SwitchButton, { onClick: handleSwitchCurrency, children: /* @__PURE__ */ jsx(SecondaryAmount, { children: isEditingUsd ? `${tokenStr || "0"} ${balanceToken.symbol}` : `$${usdStr || roundUsd(0)}` }) }) }), message && /* @__PURE__ */ jsx(ModalBody, { children: message }), /* @__PURE__ */ jsx(Button, { onClick: handleContinue, disabled: continueDisabled, children: "Continue" }) ] }) ] }); }; const AmountInputContainer = styled.div` display: flex; align-items: center; justify-content: center; gap: 6px; `; const SecondaryAmount = styled.div` font-size: 16px; font-weight: 400; line-height: 21px; color: var(--ck-body-color-muted); strong { font-weight: 500; color: var(--ck-body-color); } `; const MaxButton = styled.button` display: inline-block; padding: 3px 8px; border-radius: var(--ck-primary-button-border-radius); font-size: 14px; font-weight: 400; background: var( --ck-secondary-button-background, var(--ck-body-background-secondary) ); color: var(--ck-body-color-secondary); cursor: pointer; `; const SwitchContainer = styled.div` display: flex; align-items: center; justify-content: center; `; export { MultiCurrencySelectAmount as default }; //# sourceMappingURL=index.js.map