From 3742d78fa2bd871c54d8a98585d2ad5cf6803133 Mon Sep 17 00:00:00 2001 From: JCNoguera <88061365+VmMad@users.noreply.github.com> Date: Mon, 25 Nov 2024 17:47:53 +0100 Subject: [PATCH] refactor(wallet, dashboard): remove `isPayAllIota` from FormValues (#4184) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor(wallet, dashboard): remove isPayAllIota from FormValues * fix: use supporting label to show correct gas label * fix: add missing isPayALlIota indicator * fix: avoid parsing an unformatted value * fix: format gas --------- Co-authored-by: Begoña Álvarez de la Cruz --- .../components/Inputs/SendTokenFormInput.tsx | 10 +++-- apps/core/src/forms/token.ts | 1 - .../Dialogs/SendToken/SendTokenDialog.tsx | 7 +++- .../Dialogs/SendToken/constants/index.ts | 1 - .../Dialogs/SendToken/interfaces/index.ts | 1 - .../SendToken/views/EnterValuesFormView.tsx | 30 +++---------- .../SendToken/views/ReviewValuesFormView.tsx | 13 +++--- .../home/transfer-coin/PreviewTransfer.tsx | 6 ++- .../home/transfer-coin/SendTokenForm.tsx | 25 +++-------- .../ui/app/pages/home/transfer-coin/index.tsx | 42 +++++++++++++------ 10 files changed, 65 insertions(+), 71 deletions(-) diff --git a/apps/core/src/components/Inputs/SendTokenFormInput.tsx b/apps/core/src/components/Inputs/SendTokenFormInput.tsx index 5c49038945b..3e97b41c707 100644 --- a/apps/core/src/components/Inputs/SendTokenFormInput.tsx +++ b/apps/core/src/components/Inputs/SendTokenFormInput.tsx @@ -19,6 +19,7 @@ export interface SendTokenInputProps { onActionClick: () => Promise; isMaxActionDisabled?: boolean; name: string; + isPayAllIota: boolean; } export function SendTokenFormInput({ @@ -30,6 +31,7 @@ export function SendTokenFormInput({ onActionClick, isMaxActionDisabled, name, + isPayAllIota, }: SendTokenInputProps) { const { values, setFieldValue, isSubmitting, validateField } = useFormikContext(); const { data: gasBudgetEstimation } = useGasBudgetEstimation({ @@ -38,7 +40,7 @@ export function SendTokenFormInput({ activeAddress, to: to, amount: values.amount, - isPayAllIota: values.isPayAllIota, + isPayAllIota, }); const [formattedGasBudgetEstimation, gasToken] = useFormatCoin( gasBudgetEstimation, @@ -61,8 +63,8 @@ export function SendTokenFormInput({ // gasBudgetEstimation should change when the amount above changes useEffect(() => { - setFieldValue('gasBudgetEst', formattedGasBudgetEstimation, false); - }, [formattedGasBudgetEstimation, setFieldValue, values.amount]); + setFieldValue('gasBudgetEst', gasBudgetEstimation, false); + }, [gasBudgetEstimation, setFieldValue, values.amount]); return ( )} diff --git a/apps/wallet-dashboard/components/Dialogs/SendToken/constants/index.ts b/apps/wallet-dashboard/components/Dialogs/SendToken/constants/index.ts index 58f1e99acca..f4f51359080 100644 --- a/apps/wallet-dashboard/components/Dialogs/SendToken/constants/index.ts +++ b/apps/wallet-dashboard/components/Dialogs/SendToken/constants/index.ts @@ -7,6 +7,5 @@ export const INITIAL_VALUES: FormDataValues = { to: '', amount: '', formattedAmount: '', - isPayAllIota: false, gasBudgetEst: '', }; diff --git a/apps/wallet-dashboard/components/Dialogs/SendToken/interfaces/index.ts b/apps/wallet-dashboard/components/Dialogs/SendToken/interfaces/index.ts index 983b77712a3..e6eb00f8094 100644 --- a/apps/wallet-dashboard/components/Dialogs/SendToken/interfaces/index.ts +++ b/apps/wallet-dashboard/components/Dialogs/SendToken/interfaces/index.ts @@ -4,6 +4,5 @@ export interface FormDataValues { amount: string; formattedAmount: string; to: string; - isPayAllIota: boolean; gasBudgetEst: string; } diff --git a/apps/wallet-dashboard/components/Dialogs/SendToken/views/EnterValuesFormView.tsx b/apps/wallet-dashboard/components/Dialogs/SendToken/views/EnterValuesFormView.tsx index 2f9598c29ef..24b1855cd1d 100644 --- a/apps/wallet-dashboard/components/Dialogs/SendToken/views/EnterValuesFormView.tsx +++ b/apps/wallet-dashboard/components/Dialogs/SendToken/views/EnterValuesFormView.tsx @@ -30,7 +30,6 @@ import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; import { Form, Formik, FormikProps } from 'formik'; import { Exclamation } from '@iota/ui-icons'; import { UseQueryResult } from '@tanstack/react-query'; -import { useEffect } from 'react'; import { FormDataValues } from '../interfaces'; import { INITIAL_VALUES } from '../constants'; @@ -78,13 +77,13 @@ function FormInputs({ coins, queryResult, }: FormInputsProps): React.JSX.Element { - const newPayIotaAll = + const isPayAllIota = parseAmount(values.amount, coinDecimals) === coinBalance && coinType === IOTA_TYPE_ARG; const hasEnoughBalance = - values.isPayAllIota || + isPayAllIota || iotaBalance > - parseAmount(values.gasBudgetEst, coinDecimals) + + BigInt(values.gasBudgetEst ?? '0') + parseAmount(coinType === IOTA_TYPE_ARG ? values.amount : '0', coinDecimals); async function onMaxTokenButtonClick() { @@ -96,12 +95,6 @@ function FormInputs({ queryResult.isPending || !coinBalance; - useEffect(() => { - if (values.isPayAllIota !== newPayIotaAll) { - setFieldValue('isPayAllIota', newPayIotaAll); - } - }, [values.isPayAllIota, newPayIotaAll, setFieldValue]); - return (
@@ -124,6 +117,7 @@ function FormInputs({ activeAddress={activeAddress} onActionClick={onMaxTokenButtonClick} isMaxActionDisabled={isMaxActionDisabled} + isPayAllIota={isPayAllIota} />
@@ -195,7 +189,6 @@ export function EnterValuesFormView({ ); const formattedTokenBalance = tokenBalance.replace(/,/g, ''); - const initAmountBig = parseAmount('', coinDecimals); if (coinsBalanceIsPending || coinsIsPending || iotaCoinsIsPending) { return ( @@ -205,7 +198,7 @@ export function EnterValuesFormView({ ); } - async function handleFormSubmit({ to, amount, isPayAllIota, gasBudgetEst }: FormDataValues) { + async function handleFormSubmit({ to, amount, gasBudgetEst }: FormDataValues) { if (!coins || !iotaCoins) return; const coinsIDs = [...coins] .sort((a, b) => Number(b.balance) - Number(a.balance)) @@ -217,7 +210,6 @@ export function EnterValuesFormView({ to, amount, formattedAmount, - isPayAllIota, coins, coinIds: coinsIDs, gasBudgetEst, @@ -239,17 +231,7 @@ export function EnterValuesFormView({ /> void; coinType: string; + isPayAllIota?: boolean; } export function ReviewValuesFormView({ - formData: { amount, to, formattedAmount, isPayAllIota, gasBudgetEst }, + formData: { amount, to, formattedAmount, gasBudgetEst }, senderAddress, isPending, executeTransfer, coinType, + isPayAllIota, }: ReviewValuesFormProps): JSX.Element { const [formatAmount, symbol] = useFormatCoin(formattedAmount, coinType); + const [gasEstimated, gasSymbol] = useFormatCoin(gasBudgetEst, IOTA_TYPE_ARG); return (
@@ -89,8 +92,8 @@ export function ReviewValuesFormView({
diff --git a/apps/wallet/src/ui/app/pages/home/transfer-coin/PreviewTransfer.tsx b/apps/wallet/src/ui/app/pages/home/transfer-coin/PreviewTransfer.tsx index 4dc96f4e070..c2288f7a4eb 100644 --- a/apps/wallet/src/ui/app/pages/home/transfer-coin/PreviewTransfer.tsx +++ b/apps/wallet/src/ui/app/pages/home/transfer-coin/PreviewTransfer.tsx @@ -4,7 +4,7 @@ import { ExplorerLink, ExplorerLinkType, TxnAmount } from '_components'; import { useActiveAddress } from '_src/ui/app/hooks/useActiveAddress'; -import { GAS_SYMBOL, parseAmount, useCoinMetadata } from '@iota/core'; +import { parseAmount, useCoinMetadata, useFormatCoin } from '@iota/core'; import { Divider, KeyValueInfo } from '@iota/apps-ui-kit'; import { formatAddress } from '@iota/iota-sdk/utils'; @@ -26,6 +26,7 @@ export function PreviewTransfer({ const accountAddress = useActiveAddress(); const { data: metadata } = useCoinMetadata(coinType); const amountWithoutDecimals = parseAmount(amount, metadata?.decimals ?? 0); + const [formattedGasBudgetEstimation, gasToken] = useFormatCoin(gasBudget, coinType); return (
@@ -63,7 +64,8 @@ export function PreviewTransfer({
diff --git a/apps/wallet/src/ui/app/pages/home/transfer-coin/SendTokenForm.tsx b/apps/wallet/src/ui/app/pages/home/transfer-coin/SendTokenForm.tsx index a9b263403f3..32e8be11c52 100644 --- a/apps/wallet/src/ui/app/pages/home/transfer-coin/SendTokenForm.tsx +++ b/apps/wallet/src/ui/app/pages/home/transfer-coin/SendTokenForm.tsx @@ -17,7 +17,7 @@ import { import { type CoinStruct } from '@iota/iota-sdk/client'; import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; import { Form, Formik } from 'formik'; -import { useEffect, useMemo } from 'react'; +import { useMemo } from 'react'; import { InfoBox, @@ -32,7 +32,6 @@ import { Exclamation } from '@iota/ui-icons'; const INITIAL_VALUES = { to: '', amount: '', - isPayAllIota: false, gasBudgetEst: '', }; @@ -41,7 +40,6 @@ export type FormValues = typeof INITIAL_VALUES; export type SubmitProps = { to: string; amount: string; - isPayAllIota: boolean; coinIds: string[]; coins: CoinStruct[]; gasBudgetEst: string; @@ -100,9 +98,8 @@ export function SendTokenForm({ // remove the comma from the token balance const formattedTokenBalance = tokenBalance.replace(/,/g, ''); - const initAmountBig = parseAmount(initialAmount, coinDecimals); - async function handleFormSubmit({ to, amount, isPayAllIota, gasBudgetEst }: FormValues) { + async function handleFormSubmit({ to, amount, gasBudgetEst }: FormValues) { if (!coins || !iotaCoins) return; const coinsIDs = [...coins] .sort((a, b) => Number(b.balance) - Number(a.balance)) @@ -111,7 +108,6 @@ export function SendTokenForm({ const data = { to, amount, - isPayAllIota, coins, coinIds: coinsIDs, gasBudgetEst, @@ -132,10 +128,6 @@ export function SendTokenForm({ initialValues={{ amount: initialAmount, to: initialTo, - isPayAllIota: - !!initAmountBig && - initAmountBig === coinBalance && - coinType === IOTA_TYPE_ARG, gasBudgetEst: '', }} validationSchema={validationSchemaStepOne} @@ -145,14 +137,14 @@ export function SendTokenForm({ onSubmit={handleFormSubmit} > {({ isValid, isSubmitting, setFieldValue, values, submitForm }) => { - const newPayIotaAll = + const isPayAllIota = parseAmount(values.amount, coinDecimals) === coinBalance && coinType === IOTA_TYPE_ARG; const hasEnoughBalance = - values.isPayAllIota || + isPayAllIota || iotaBalance > - parseAmount(values.gasBudgetEst, coinDecimals) + + BigInt(values.gasBudgetEst ?? '0') + parseAmount( coinType === IOTA_TYPE_ARG ? values.amount : '0', coinDecimals, @@ -167,12 +159,6 @@ export function SendTokenForm({ queryResult.isPending || !coinBalance; - useEffect(() => { - if (values.isPayAllIota !== newPayIotaAll) { - setFieldValue('isPayAllIota', newPayIotaAll); - } - }, [values.isPayAllIota, newPayIotaAll, setFieldValue]); - return (
@@ -194,6 +180,7 @@ export function SendTokenForm({ coins={coins ?? []} onActionClick={onMaxTokenButtonClick} isMaxActionDisabled={isMaxActionDisabled} + isPayAllIota={isPayAllIota} />
diff --git a/apps/wallet/src/ui/app/pages/home/transfer-coin/index.tsx b/apps/wallet/src/ui/app/pages/home/transfer-coin/index.tsx index b743f0e20a6..f4e3a2555c1 100644 --- a/apps/wallet/src/ui/app/pages/home/transfer-coin/index.tsx +++ b/apps/wallet/src/ui/app/pages/home/transfer-coin/index.tsx @@ -14,6 +14,7 @@ import { CoinSelector, createTokenTransferTransaction, filterAndSortTokenBalances, + parseAmount, useCoinMetadata, } from '@iota/core'; import * as Sentry from '@sentry/react'; @@ -26,14 +27,15 @@ import { SendTokenForm, type SubmitProps } from './SendTokenForm'; import { Button, ButtonType, LoadingIndicator } from '@iota/apps-ui-kit'; import { Loader } from '@iota/ui-icons'; import { useIotaClientQuery } from '@iota/dapp-kit'; +import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; function TransferCoinPage() { const [searchParams] = useSearchParams(); - const coinType = searchParams.get('type'); + const selectedCoinType = searchParams.get('type'); const [showTransactionPreview, setShowTransactionPreview] = useState(false); const [formData, setFormData] = useState(); const navigate = useNavigate(); - const { data: coinMetadata } = useCoinMetadata(coinType); + const { data: coinMetadata } = useCoinMetadata(selectedCoinType); const activeAccount = useActiveAccount(); const signer = useSigner(activeAccount); const address = activeAccount?.address; @@ -49,6 +51,16 @@ function TransferCoinPage() { select: filterAndSortTokenBalances, }, ); + const coinBalance = coinsBalance?.find( + (coin) => coin.coinType === selectedCoinType, + )?.totalBalance; + + const selectedAmount = formData?.amount; + const selectedCoinDecimals = coinMetadata?.decimals; + const hasSelectedMaxCoinBalance = + selectedAmount && selectedCoinDecimals && coinBalance + ? parseAmount(selectedAmount, coinMetadata.decimals) === BigInt(coinBalance) + : false; if (coinsBalanceIsPending) { return ( @@ -58,15 +70,19 @@ function TransferCoinPage() { ); } + const isPayAllIota: boolean = + (hasSelectedMaxCoinBalance && selectedCoinType === IOTA_TYPE_ARG) ?? false; + const transaction = useMemo(() => { - if (!coinType || !signer || !formData || !address) return null; + if (!selectedCoinType || !signer || !formData || !address) return null; return createTokenTransferTransaction({ - coinType, + coinType: selectedCoinType, coinDecimals: coinMetadata?.decimals ?? 0, + isPayAllIota, ...formData, }); - }, [formData, signer, coinType, address, coinMetadata?.decimals]); + }, [formData, signer, selectedCoinType, address, coinMetadata?.decimals]); const executeTransfer = useMutation({ mutationFn: async () => { @@ -95,7 +111,7 @@ function TransferCoinPage() { queryClient.invalidateQueries({ queryKey: ['coin-balance'] }); ampli.sentCoins({ - coinType: coinType!, + coinType: selectedCoinType!, }); const receiptUrl = `/receipt?txdigest=${encodeURIComponent( @@ -121,7 +137,7 @@ function TransferCoinPage() { return null; } - if (!coinType || !coinsBalance) { + if (!selectedCoinType || !coinsBalance) { return ; } @@ -138,10 +154,10 @@ function TransferCoinPage() {
@@ -152,7 +168,7 @@ function TransferCoinPage() { executeTransfer.mutateAsync(); }} text="Send Now" - disabled={coinType === null || executeTransfer.isPending} + disabled={selectedCoinType === null || executeTransfer.isPending} icon={ executeTransfer.isPending ? ( @@ -164,7 +180,7 @@ function TransferCoinPage() { ) : ( <> { setFormData(undefined); @@ -179,8 +195,8 @@ function TransferCoinPage() { setFormData(formData); setShowTransactionPreview(true); }} - key={coinType} - coinType={coinType} + key={selectedCoinType} + coinType={selectedCoinType} initialAmount={formData?.amount || ''} initialTo={formData?.to || ''} />