@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
JavaScript
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