Skip to content

Commit

Permalink
fix: send asset number input allows for decimals (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
kieranroneill authored Dec 23, 2023
1 parent 548364c commit 59131c4
Show file tree
Hide file tree
Showing 10 changed files with 64 additions and 53 deletions.
1 change: 1 addition & 0 deletions src/common/utils/formatCurrencyUnit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import numbro from 'numbro';
/**
* Formats a given unit to display on the frontend.
* @param {BigNumber} input - the unit as a BigNumber.
* @param {decimals} decimals - the number of decimals for the currency.
* @returns {string} the formatted unit.
*/
export default function formatCurrencyUnit(
Expand Down
63 changes: 30 additions & 33 deletions src/extension/components/SendAssetModal/SendAmountInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@ import {
VStack,
} from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React, { FC, ReactElement } from 'react';
import numbro from 'numbro';
import React, { FC, FocusEvent, ReactElement } from 'react';
import { useTranslation } from 'react-i18next';
import { IoInformationCircleOutline } from 'react-icons/io5';

// constants
import { DEFAULT_GAP } from '@extension/constants';

// hooks
import useButtonHoverBackgroundColor from '@extension/hooks/useButtonHoverBackgroundColor';
import useDefaultTextColor from '@extension/hooks/useDefaultTextColor';
Expand All @@ -33,11 +37,7 @@ import {
} from '@extension/types';

// utils
import {
convertToAtomicUnit,
convertToStandardUnit,
formatCurrencyUnit,
} from '@common/utils';
import { convertToStandardUnit, formatCurrencyUnit } from '@common/utils';
import { convertGenesisHashToHex } from '@extension/utils';

interface IProps {
Expand Down Expand Up @@ -86,18 +86,28 @@ const SendAmountInput: FC<IProps> = ({
assetDecimals
);
// handlers
const handleMaximumAmountClick = () =>
onValueChange(maximumTransactionAmount);
const handleValueChange = (valueInStandardUnit: string) => {
const handleOnBlur = (event: FocusEvent<HTMLInputElement>) => {
const blurValue: BigNumber = new BigNumber(event.target.value || '0');

// if the entered value is greater than the maximum allowed, use the max
if (blurValue.gt(maximumTransactionAmountInStandardUnit)) {
onValueChange(maximumTransactionAmountInStandardUnit.toString());

return;
}

// format the number to use an absolute value (no negatives), the maximum decimals for the asset and trim any zeroes
onValueChange(
valueInStandardUnit?.length > 1
? convertToAtomicUnit(
new BigNumber(valueInStandardUnit),
assetDecimals
).toString()
: '0'
numbro(blurValue.absoluteValue().toString()).format({
mantissa: assetDecimals,
trimMantissa: true,
})
);
};
const handleMaximumAmountClick = () =>
onValueChange(maximumTransactionAmountInStandardUnit.toString());
const handleOnChange = (valueAsString: string | undefined) =>
onValueChange(valueAsString || '0');
// renders
const renderMaximumTransactionAmountLabel = () => {
const maximumTransactionAmountLabel: ReactElement = (
Expand All @@ -108,7 +118,7 @@ const SendAmountInput: FC<IProps> = ({
<HStack
backgroundColor={textBackgroundColor}
borderRadius={theme.radii['3xl']}
px={2}
px={DEFAULT_GAP / 3}
py={1}
spacing={1}
>
Expand Down Expand Up @@ -191,25 +201,12 @@ const SendAmountInput: FC<IProps> = ({
{/*input*/}
<NumberInput
colorScheme={primaryColorScheme}
defaultValue={0}
clampValueOnBlur={false}
focusBorderColor={primaryColor}
max={maximumTransactionAmountInStandardUnit.toNumber()}
min={0}
onChange={handleValueChange}
precision={assetDecimals}
onBlur={handleOnBlur}
onChange={handleOnChange}
size="md"
step={convertToStandardUnit(
new BigNumber(1),
assetDecimals
).toNumber()}
value={
value
? convertToStandardUnit(
new BigNumber(value),
assetDecimals
).toString()
: undefined
}
value={value || undefined}
w="full"
>
<NumberInputField textAlign="right" />
Expand Down
14 changes: 9 additions & 5 deletions src/extension/components/SendAssetModal/SendAssetModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ import usePrimaryColor from '@extension/hooks/usePrimaryColor';
import {
useSelectAccounts,
useSelectSelectedNetwork,
useSelectSendingAssetAmount,
useSelectSendingAssetAmountInStandardUnits,
useSelectSendingAssetConfirming,
useSelectSendingAssetError,
useSelectSendingAssetFromAccount,
Expand Down Expand Up @@ -100,7 +100,8 @@ const SendAssetModal: FC<IProps> = ({ onClose }: IProps) => {
const dispatch: IAppThunkDispatch = useDispatch<IAppThunkDispatch>();
// selectors
const accounts: IAccount[] = useSelectAccounts();
const amount: string = useSelectSendingAssetAmount();
const amountInStandardUnits: string =
useSelectSendingAssetAmountInStandardUnits();
const assets: IStandardAsset[] = useSelectStandardAssetsBySelectedNetwork();
const confirming: boolean = useSelectSendingAssetConfirming();
const error: BaseExtensionError | null = useSelectSendingAssetError();
Expand Down Expand Up @@ -209,7 +210,7 @@ const SendAssetModal: FC<IProps> = ({ onClose }: IProps) => {
if (showSummary) {
return (
<SendAssetModalSummaryContent
amount={amount || '0'}
amountInStandardUnits={amountInStandardUnits}
asset={selectedAsset}
fromAccount={fromAccount}
network={network}
Expand All @@ -228,7 +229,7 @@ const SendAssetModal: FC<IProps> = ({ onClose }: IProps) => {
maximumTransactionAmount={maximumTransactionAmount}
onValueChange={handleAmountChange}
selectedAsset={selectedAsset}
value={amount}
value={amountInStandardUnits}
/>

{/*select asset*/}
Expand Down Expand Up @@ -377,7 +378,10 @@ const SendAssetModal: FC<IProps> = ({ onClose }: IProps) => {
setMaximumTransactionAmount(newMaximumTransactionAmount.toString());

// if the amount exceeds the new maximum transaction amount, set the amount to the maximum transaction amount
if (amount && new BigNumber(amount).gt(newMaximumTransactionAmount)) {
if (
amountInStandardUnits &&
new BigNumber(amountInStandardUnits).gt(newMaximumTransactionAmount)
) {
dispatch(setAmount(newMaximumTransactionAmount.toString()));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ import {

// utils
import { createIconFromDataUri } from '@extension/utils';
import { convertToAtomicUnit } from '@common/utils';

interface IProps {
amount: string;
amountInStandardUnits: string;
asset: IStandardAsset;
fromAccount: IAccount;
network: INetworkWithTransactionParams;
Expand All @@ -40,7 +41,7 @@ interface IProps {
}

const SendAssetModalSummaryContent: FC<IProps> = ({
amount,
amountInStandardUnits,
asset,
fromAccount,
network,
Expand All @@ -64,7 +65,10 @@ const SendAssetModalSummaryContent: FC<IProps> = ({
fontSize="sm"
item={
<AssetDisplay
atomicUnitAmount={new BigNumber(amount)}
atomicUnitAmount={convertToAtomicUnit(
new BigNumber(amountInStandardUnits),
asset.decimals
)}
amountColor={subTextColor}
decimals={asset.decimals}
displayUnit={asset.id !== '0'}
Expand Down
4 changes: 2 additions & 2 deletions src/extension/features/send-assets/slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const slice = createSlice({
state.selectedAsset = action.payload.selectedAsset;
},
reset: (state: Draft<ISendAssetsState>) => {
state.amount = '0';
state.amountInStandardUnits = '0';
state.confirming = false;
state.error = null;
state.fromAddress = null;
Expand All @@ -78,7 +78,7 @@ const slice = createSlice({
state: Draft<ISendAssetsState>,
action: PayloadAction<string>
) => {
state.amount = action.payload;
state.amountInStandardUnits = action.payload;
},
setError: (
state: Draft<ISendAssetsState>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ import {
} from '@extension/types';

// utils
import { getAlgodClient } from '@common/utils';
import { convertToAtomicUnit, getAlgodClient } from '@common/utils';
import { selectNetworkFromSettings } from '@extension/utils';
import { createSendAssetTransaction } from '../utils';
import BigNumber from 'bignumber.js';

interface AsyncThunkConfig {
state: IMainRootState;
Expand All @@ -53,7 +54,8 @@ const submitTransactionThunk: AsyncThunk<
> = createAsyncThunk<string, string, AsyncThunkConfig>(
SendAssetsThunkEnum.SubmitTransaction,
async (password, { getState, rejectWithValue }) => {
const amount: string | null = getState().sendAssets.amount;
const amountInStandardUnits: string | null =
getState().sendAssets.amountInStandardUnits;
const asset: IStandardAsset | null = getState().sendAssets.selectedAsset;
const fromAddress: string | null = getState().sendAssets.fromAddress;
const logger: ILogger = getState().system.logger;
Expand All @@ -74,7 +76,7 @@ const submitTransactionThunk: AsyncThunk<
let transactionResponse: IAlgorandPendingTransactionResponse;
let unsignedTransaction: Transaction;

if (!amount || !asset || !fromAddress || !toAddress) {
if (!amountInStandardUnits || !asset || !fromAddress || !toAddress) {
logger.debug(
`${SendAssetsThunkEnum.SubmitTransaction}: required fields not completed`
);
Expand Down Expand Up @@ -157,7 +159,10 @@ const submitTransactionThunk: AsyncThunk<
try {
suggestedParams = await algodClient.getTransactionParams().do();
unsignedTransaction = createSendAssetTransaction({
amount,
amount: convertToAtomicUnit(
new BigNumber(amountInStandardUnits),
asset.decimals
).toString(), // convert to atomic units
asset,
fromAddress,
note,
Expand Down
4 changes: 2 additions & 2 deletions src/extension/features/send-assets/types/ISendAssetsState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { BaseExtensionError } from '@extension/errors';
import { IStandardAsset } from '@extension/types';

/**
* @property {string} amount - the amount to send. Default is "0".
* @property {string} amountInStandardUnits - the amount, in standard units, to send. Defaults to "0".
* @property {boolean} confirming - confirming the transaction to the network.
* @property {BaseExtensionError | null} error - if an error occurred.
* @property {string | null} fromAddress - the address to send from.
Expand All @@ -15,7 +15,7 @@ import { IStandardAsset } from '@extension/types';
* @property {string | null} transactionId - the ID of the confirmed transaction.
*/
interface ISendAssetsState {
amount: string;
amountInStandardUnits: string;
confirming: boolean;
error: BaseExtensionError | null;
fromAddress: string | null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ISendAssetsState } from '../types';

export default function getInitialState(): ISendAssetsState {
return {
amount: '0',
amountInStandardUnits: '0',
confirming: false,
error: null,
fromAddress: null,
Expand Down
2 changes: 1 addition & 1 deletion src/extension/selectors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export { default as useSelectSavingRegistration } from './useSelectSavingRegistr
export { default as useSelectSavingSessions } from './useSelectSavingSessions';
export { default as useSelectSavingSettings } from './useSelectSavingSettings';
export { default as useSelectSelectedNetwork } from './useSelectSelectedNetwork';
export { default as useSelectSendingAssetAmount } from './useSelectSendingAssetAmount';
export { default as useSelectSendingAssetAmountInStandardUnits } from './useSelectSendingAssetAmountInStandardUnits';
export { default as useSelectSendingAssetConfirming } from './useSelectSendingAssetConfirming';
export { default as useSelectSendingAssetError } from './useSelectSendingAssetError';
export { default as useSelectSendingAssetFromAccount } from './useSelectSendingAssetFromAccount';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { useSelector } from 'react-redux';
// types
import { IMainRootState } from '@extension/types';

export default function useSelectSendingAssetAmount(): string {
export default function useSelectSendingAssetAmountInStandardUnits(): string {
return useSelector<IMainRootState, string>(
(state) => state.sendAssets.amount
(state) => state.sendAssets.amountInStandardUnits
);
}

0 comments on commit 59131c4

Please sign in to comment.