Skip to content

Commit

Permalink
fix: limit decimals for swap input amount
Browse files Browse the repository at this point in the history
  • Loading branch information
chybisov committed May 25, 2023
1 parent d5f5750 commit 93973d8
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 57 deletions.
27 changes: 0 additions & 27 deletions packages/widget/src/components/SwapInput/FitInputText.ts

This file was deleted.

27 changes: 24 additions & 3 deletions packages/widget/src/components/SwapInput/FormPriceHelperText.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { TokenAmount } from '@lifi/sdk';
import { FormHelperText, Skeleton, Typography } from '@mui/material';
import { useWatch } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
Expand All @@ -9,17 +10,37 @@ import { formatTokenAmount, formatTokenPrice } from '../../utils';
export const FormPriceHelperText: React.FC<SwapFormTypeProps> = ({
formType,
}) => {
const { t } = useTranslation();
const [amount, chainId, tokenAddress] = useWatch({
const [chainId, tokenAddress] = useWatch({
name: [
SwapFormKeyHelper.getAmountKey(formType),
SwapFormKeyHelper.getChainKey(formType),
SwapFormKeyHelper.getTokenKey(formType),
],
});

const { token, isLoading } = useTokenAddressBalance(chainId, tokenAddress);

return (
<FormPriceHelperTextBase
formType={formType}
isLoading={isLoading}
tokenAddress={tokenAddress}
token={token}
/>
);
};

export const FormPriceHelperTextBase: React.FC<
SwapFormTypeProps & {
isLoading?: boolean;
tokenAddress?: string;
token?: TokenAmount;
}
> = ({ formType, isLoading, tokenAddress, token }) => {
const { t } = useTranslation();
const amount = useWatch({
name: SwapFormKeyHelper.getAmountKey(formType),
});

const fromAmountTokenPrice = formatTokenPrice(amount, token?.priceUSD);

return (
Expand Down
82 changes: 64 additions & 18 deletions packages/widget/src/components/SwapInput/SwapInput.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,70 @@
import type { Token } from '@lifi/sdk';
import type { BoxProps } from '@mui/material';
import type { ChangeEvent } from 'react';
import { useRef } from 'react';
import { useController } from 'react-hook-form';
import type { ChangeEvent, ReactNode } from 'react';
import { useLayoutEffect, useRef } from 'react';
import { useController, useWatch } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { useToken } from '../../hooks';
import type { SwapFormTypeProps } from '../../providers';
import { SwapFormKeyHelper, useWidgetConfig } from '../../providers';
import { DisabledUI } from '../../types';
import { formatInputAmount } from '../../utils';
import { fitInputText, formatInputAmount } from '../../utils';
import { Card, CardTitle } from '../Card';
import { FitInputText } from './FitInputText';
import { FormPriceHelperText } from './FormPriceHelperText';
import { FormControl, Input } from './SwapInput.style';
import {
FormControl,
Input,
maxInputFontSize,
minInputFontSize,
} from './SwapInput.style';
import { SwapInputEndAdornment } from './SwapInputEndAdornment';
import { SwapInputStartAdornment } from './SwapInputStartAdornment';

export const SwapInput: React.FC<SwapFormTypeProps & BoxProps> = ({
formType,
...props
}) => {
const { disabledUI } = useWidgetConfig();
const [chainId, tokenAddress] = useWatch({
name: [
SwapFormKeyHelper.getChainKey(formType),
SwapFormKeyHelper.getTokenKey(formType),
],
});
const { token } = useToken(chainId, tokenAddress);
const disabled = disabledUI?.includes(DisabledUI.FromAmount);
return (
<SwapInputBase
formType={formType}
token={token}
startAdornment={<SwapInputStartAdornment formType={formType} />}
endAdornment={
!disabled ? <SwapInputEndAdornment formType={formType} /> : undefined
}
bottomAdornment={<FormPriceHelperText formType={formType} />}
disabled={disabled}
{...props}
/>
);
};

export const SwapInputBase: React.FC<
SwapFormTypeProps &
BoxProps & {
token?: Token;
startAdornment?: ReactNode;
endAdornment?: ReactNode;
bottomAdornment?: ReactNode;
disabled?: boolean;
}
> = ({
formType,
token,
startAdornment,
endAdornment,
bottomAdornment,
disabled,
...props
}) => {
const { t } = useTranslation();
const amountKey = SwapFormKeyHelper.getAmountKey(formType);
Expand All @@ -25,27 +73,30 @@ export const SwapInput: React.FC<SwapFormTypeProps & BoxProps> = ({
} = useController({
name: amountKey,
});
const { disabledUI } = useWidgetConfig();
const ref = useRef<HTMLInputElement>(null);

const handleChange = (
event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => {
const { value } = event.target;
const formattedAmount = formatInputAmount(value, true);
const formattedAmount = formatInputAmount(value, token?.decimals, true);
onChange(formattedAmount);
};

const handleBlur = (
event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => {
const { value } = event.target;
const formattedAmount = formatInputAmount(value);
const formattedAmount = formatInputAmount(value, token?.decimals);
onChange(formattedAmount);
onBlur();
};

const disabled = disabledUI?.includes(DisabledUI.FromAmount);
useLayoutEffect(() => {
if (ref.current) {
fitInputText(maxInputFontSize, minInputFontSize, ref.current);
}
}, [value, ref]);

return (
<Card {...props}>
Expand All @@ -56,12 +107,8 @@ export const SwapInput: React.FC<SwapFormTypeProps & BoxProps> = ({
size="small"
autoComplete="off"
placeholder="0"
startAdornment={<SwapInputStartAdornment formType={formType} />}
endAdornment={
!disabled ? (
<SwapInputEndAdornment formType={formType} />
) : undefined
}
startAdornment={startAdornment}
endAdornment={endAdornment}
inputProps={{
inputMode: 'decimal',
}}
Expand All @@ -72,9 +119,8 @@ export const SwapInput: React.FC<SwapFormTypeProps & BoxProps> = ({
disabled={disabled}
required
/>
<FormPriceHelperText formType={formType} />
{bottomAdornment}
</FormControl>
<FitInputText ref={ref} formType={formType} />
</Card>
);
};
6 changes: 5 additions & 1 deletion packages/widget/src/hooks/useTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import { useFeaturedTokens } from './useFeaturedTokens';

export const useTokens = (selectedChainId?: number) => {
const lifi = useLiFi();
const { data, isLoading } = useQuery(['tokens'], () => lifi.getTokens());
const { data, isLoading } = useQuery(['tokens'], () => lifi.getTokens(), {
refetchInterval: 3_600_000,
});
const { getChainById, isLoading: isSupportedChainsLoading } = useChains();
const featuredTokens = useFeaturedTokens(selectedChainId);
const { tokens: configTokens, chains: configChains } = useWidgetConfig();
Expand Down Expand Up @@ -62,12 +64,14 @@ export const useTokens = (selectedChainId?: number) => {
] as TokenAmount[];

return tokens;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
configChains,
configTokens?.allow,
configTokens?.deny,
configTokens?.include,
data?.tokens,
data,
featuredTokens,
getChainById,
isSupportedChainsLoading,
Expand Down
21 changes: 13 additions & 8 deletions packages/widget/src/utils/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const formatTokenAmount = (
decimalPlaces++;
}

return Big(parsedAmount).toFixed(decimalPlaces + 1, 0);
return parsedAmount.toFixed(decimalPlaces + 1);
};

export const formatSlippage = (
Expand Down Expand Up @@ -61,6 +61,7 @@ export const formatSlippage = (

export const formatInputAmount = (
amount: string,
decimals: number = 0,
returnInitial: boolean = false,
) => {
if (!amount) {
Expand All @@ -74,15 +75,19 @@ export const formatInputAmount = (
if (isNaN(Number(formattedAmount)) && !isNaN(parsedAmount)) {
return parsedAmount.toString();
}
try {
const absFormattedAmount = Big(formattedAmount).abs();
if (returnInitial) {
return formattedAmount;
}
return absFormattedAmount.toString();
} catch {
if (isNaN(Math.abs(Number(formattedAmount)))) {
return '';
}
if (returnInitial) {
return formattedAmount;
}
let [integer, fraction = ''] = formattedAmount.split('.');
if (fraction.length > decimals) {
fraction = fraction.slice(0, decimals);
}
integer = integer.replace(/^0+|-/, '');
fraction = fraction.replace(/(0+)$/, '');
return `${integer || (fraction ? '0' : '')}${fraction ? `.${fraction}` : ''}`;
};

export const formatTokenPrice = (amount?: string, price?: string) => {
Expand Down

0 comments on commit 93973d8

Please sign in to comment.