From ecd362615eff697a1911027ae524d60d8bbe5226 Mon Sep 17 00:00:00 2001 From: Maciek Date: Mon, 10 Apr 2023 13:59:02 +0200 Subject: [PATCH] chore(deposits): impove UX on deposit dialog (#3401) --- .../trading-e2e/src/integration/deposit.cy.ts | 5 +- .../deposits/src/lib/approve-notification.tsx | 29 +++-- libs/deposits/src/lib/deposit-form.spec.tsx | 53 ++++++-- libs/deposits/src/lib/deposit-form.tsx | 115 ++++++++++-------- libs/deposits/src/lib/deposit-limits.tsx | 62 +++++++--- libs/deposits/src/setup-tests.ts | 3 + 6 files changed, 179 insertions(+), 88 deletions(-) diff --git a/apps/trading-e2e/src/integration/deposit.cy.ts b/apps/trading-e2e/src/integration/deposit.cy.ts index dad973e56..0f0fae630 100644 --- a/apps/trading-e2e/src/integration/deposit.cy.ts +++ b/apps/trading-e2e/src/integration/deposit.cy.ts @@ -87,7 +87,10 @@ describe('deposit form validation', { tags: '@smoke' }, () => { .clear() .type('850') .next(`[data-testid="${formFieldError}"]`) - .should('have.text', 'Insufficient amount in Ethereum wallet'); + .should( + 'have.text', + "You can't deposit more than you have in your Ethereum wallet, 800 tEURO" + ); }); }); diff --git a/libs/deposits/src/lib/approve-notification.tsx b/libs/deposits/src/lib/approve-notification.tsx index 9b2d6a62f..9f3a006ce 100644 --- a/libs/deposits/src/lib/approve-notification.tsx +++ b/libs/deposits/src/lib/approve-notification.tsx @@ -51,11 +51,12 @@ export const ApproveNotification = ({ intent={intent} testId="approve-default" message={t( - `Before you can make a deposit of your chosen asset, ${selectedAsset?.symbol}, you need to approve its use in your Ethereum wallet` + 'Before you can make a deposit of your chosen asset, %s, you need to approve its use in your Ethereum wallet', + selectedAsset?.symbol )} buttonProps={{ size: 'sm', - text: `Approve ${selectedAsset?.symbol}`, + text: t('Approve %s', selectedAsset?.symbol), action: onApprove, dataTestId: 'approve-submit', }} @@ -68,13 +69,12 @@ export const ApproveNotification = ({ intent={intent} testId="reapprove-default" message={t( - `Approve again to deposit more than ${formatNumber( - balances.allowance.toString() - )}` + 'Approve again to deposit more than %s', + formatNumber(balances.allowance.toString()) )} buttonProps={{ size: 'sm', - text: `Approve ${selectedAsset?.symbol}`, + text: t('Approve %s', selectedAsset?.symbol), action: onApprove, dataTestId: 'reapprove-submit', }} @@ -157,7 +157,8 @@ const ApprovalTxFeedback = ({ intent={Intent.Warning} testId="approve-requested" message={t( - `Go to your Ethereum wallet and approve the transaction to enable the use of ${selectedAsset?.symbol}` + 'Go to your Ethereum wallet and approve the transaction to enable the use of %s', + selectedAsset?.symbol )} /> @@ -174,7 +175,8 @@ const ApprovalTxFeedback = ({ <>

{t( - `Your ${selectedAsset?.symbol} approval is being confirmed by the Ethereum network. When this is complete, you can continue your deposit` + 'Your %s approval is being confirmed by the Ethereum network. When this is complete, you can continue your deposit', + selectedAsset?.symbol )}{' '}

{txLink &&

{txLink}

} @@ -194,13 +196,10 @@ const ApprovalTxFeedback = ({ message={ <>

- {t( - `You can now make deposits in ${ - selectedAsset?.symbol - }, up to a maximum of ${formatNumber( - allowance?.toString() || 0 - )}` - )} + {t('You approved deposits of up to %s %s.', [ + selectedAsset?.symbol, + formatNumber(allowance?.toString() || 0), + ])}

{txLink &&

{txLink}

} diff --git a/libs/deposits/src/lib/deposit-form.spec.tsx b/libs/deposits/src/lib/deposit-form.spec.tsx index 3ce7565b4..8a3e3fde4 100644 --- a/libs/deposits/src/lib/deposit-form.spec.tsx +++ b/libs/deposits/src/lib/deposit-form.spec.tsx @@ -1,4 +1,11 @@ -import { waitFor, fireEvent, render, screen } from '@testing-library/react'; +import { + waitFor, + fireEvent, + render, + screen, + act, +} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import BigNumber from 'bignumber.js'; import type { DepositFormProps } from './deposit-form'; import { DepositForm } from './deposit-form'; @@ -141,12 +148,14 @@ describe('Deposit form', () => { fireEvent.submit(screen.getByTestId('deposit-form')); expect( - await screen.findByText('Insufficient amount in Ethereum wallet') + await screen.findByText( + "You can't deposit more than you have in your Ethereum wallet, 5" + ) ).toBeInTheDocument(); }); it('fails when submitted amount is more than the maximum limit', async () => { - render(); + render(); const amountMoreThanLimit = '21'; fireEvent.change(screen.getByLabelText('Amount'), { @@ -155,7 +164,9 @@ describe('Deposit form', () => { fireEvent.submit(screen.getByTestId('deposit-form')); expect( - await screen.findByText('Amount is above lifetime deposit limit') + await screen.findByText( + "You can't deposit more than your remaining deposit allowance, 10 asset-symbol" + ) ).toBeInTheDocument(); }); @@ -179,7 +190,9 @@ describe('Deposit form', () => { fireEvent.submit(screen.getByTestId('deposit-form')); expect( - await screen.findByText('Amount is above approved amount') + await screen.findByText( + "You can't deposit more than your approved deposit amount, 30" + ) ).toBeInTheDocument(); }); @@ -283,8 +296,6 @@ describe('Deposit form', () => { expect(screen.getByTestId('BALANCE_AVAILABLE_value')).toHaveTextContent( '50' ); - expect(screen.getByTestId('MAX_LIMIT_value')).toHaveTextContent('20'); - expect(screen.getByTestId('DEPOSITED_value')).toHaveTextContent('10'); expect(screen.getByTestId('REMAINING_value')).toHaveTextContent('10'); fireEvent.change(screen.getByLabelText('Amount'), { @@ -365,4 +376,32 @@ describe('Deposit form', () => { /this app only works on/i ); }); + + it('Remaining deposit allowance tooltip should be rendered', async () => { + render(); + await act(async () => { + await userEvent.hover(screen.getByText('Remaining deposit allowance')); + }); + await waitFor(async () => { + await expect( + screen.getByRole('tooltip', { + name: /VEGA has a lifetime deposit limit of 20 asset-symbol per address/, + }) + ).toBeInTheDocument(); + }); + }); + + it('Ethereum deposit cap tooltip should be rendered', async () => { + render(); + await act(async () => { + await userEvent.hover(screen.getByText('Ethereum deposit cap')); + }); + await waitFor(async () => { + await expect( + screen.getByRole('tooltip', { + name: /The deposit cap is set when you approve an asset for use with this app/, + }) + ).toBeInTheDocument(); + }); + }); }); diff --git a/libs/deposits/src/lib/deposit-form.tsx b/libs/deposits/src/lib/deposit-form.tsx index e403a0bf5..23721f885 100644 --- a/libs/deposits/src/lib/deposit-form.tsx +++ b/libs/deposits/src/lib/deposit-form.tsx @@ -8,6 +8,7 @@ import { maxSafe, addDecimal, isAssetTypeERC20, + formatNumber, } from '@vegaprotocol/utils'; import { t } from '@vegaprotocol/i18n'; import { useLocalStorage } from '@vegaprotocol/react-helpers'; @@ -133,11 +134,8 @@ export const DepositForm = ({ return _pubKeys ? _pubKeys.map((pk) => pk.publicKey) : []; }, [_pubKeys]); - const approved = balances - ? balances.allowance.isGreaterThan(0) - ? true - : false - : false; + const approved = + balances && balances.allowance.isGreaterThan(0) ? true : false; return (
{errors.from.message} )} + + setValue('to', '')} + select={ + + } + input={ + + } + /> + {errors.to?.message && ( + + {errors.to.message} + + )} + - - setValue('to', '')} - select={ - - } - input={ - - } - /> - {errors.to?.message && ( - - {errors.to.message} - - )} - - {selectedAsset && balances && ( + {approved && selectedAsset && balances && (
@@ -305,8 +303,15 @@ export const DepositForm = ({ minSafe: (value) => minSafe(new BigNumber(min))(value), approved: (v) => { const value = new BigNumber(v); - if (value.isGreaterThan(balances?.allowance || 0)) { - return t('Amount is above approved amount'); + const allowance = new BigNumber(balances?.allowance || 0); + if (value.isGreaterThan(allowance)) { + return t( + "You can't deposit more than your approved deposit amount, %s %s", + [ + formatNumber(allowance.toString()), + selectedAsset?.symbol || ' ', + ] + ); } return true; }, @@ -322,14 +327,24 @@ export const DepositForm = ({ } if (value.isGreaterThan(lifetimeLimit)) { - return t('Amount is above lifetime deposit limit'); + return t( + "You can't deposit more than your remaining deposit allowance, %s %s", + [ + formatNumber(lifetimeLimit.toString()), + selectedAsset?.symbol || ' ', + ] + ); } return true; }, balance: (v) => { const value = new BigNumber(v); - if (value.isGreaterThan(balances?.balance || 0)) { - return t('Insufficient amount in Ethereum wallet'); + const balance = new BigNumber(balances?.balance || 0); + if (value.isGreaterThan(balance)) { + return t( + "You can't deposit more than you have in your Ethereum wallet, %s %s", + [formatNumber(balance), selectedAsset?.symbol || ' '] + ); } return true; }, @@ -405,7 +420,7 @@ const FormButton = ({ approved, selectedAsset }: FormButtonProps) => { type="submit" data-testid="deposit-submit" variant={isActive ? 'primary' : 'default'} - fill={true} + fill disabled={invalidChain} > {t('Deposit')} diff --git a/libs/deposits/src/lib/deposit-limits.tsx b/libs/deposits/src/lib/deposit-limits.tsx index dc08b492a..7b69298c4 100644 --- a/libs/deposits/src/lib/deposit-limits.tsx +++ b/libs/deposits/src/lib/deposit-limits.tsx @@ -1,8 +1,13 @@ import type { Asset } from '@vegaprotocol/assets'; import { t } from '@vegaprotocol/i18n'; import { CompactNumber } from '@vegaprotocol/react-helpers'; -import { KeyValueTable, KeyValueTableRow } from '@vegaprotocol/ui-toolkit'; +import { + KeyValueTable, + KeyValueTableRow, + Tooltip, +} from '@vegaprotocol/ui-toolkit'; import type BigNumber from 'bignumber.js'; +import { formatNumber } from '@vegaprotocol/utils'; // Note: all of the values here are with correct asset's decimals // See `libs/deposits/src/lib/use-deposit-balances.ts` @@ -33,21 +38,35 @@ export const DepositLimits = ({ '-' ), }, - { - key: 'MAX_LIMIT', - label: t('Lifetime deposit allowance'), - rawValue: max, - value: , - }, - { - key: 'DEPOSITED', - label: t('Deposited'), - rawValue: deposited, - value: , - }, { key: 'REMAINING', - label: t('Remaining'), + label: ( + +

+ {t( + 'VEGA has a lifetime deposit limit of %s %s per address. This can be changed through governance', + [formatNumber(max.toString()), asset.symbol] + )} +

+

+ {t( + 'To date, %s %s has been deposited from this Ethereum address, so you can deposit up to %s %s more.', + [ + formatNumber(deposited.toString()), + asset.symbol, + formatNumber(max.minus(deposited).toString()), + asset.symbol, + ] + )} +

+ + } + > + +
+ ), rawValue: max.minus(deposited), value: ( + {t( + 'The deposit cap is set when you approve an asset for use with this app. To increase this cap, approve %s again and choose a higher cap. Check the documentation for your Ethereum wallet app for details.', + asset.symbol + )} +

+ } + > + + + ), rawValue: allowance, value: allowance ? ( diff --git a/libs/deposits/src/setup-tests.ts b/libs/deposits/src/setup-tests.ts index 7b0828bfa..68773380a 100644 --- a/libs/deposits/src/setup-tests.ts +++ b/libs/deposits/src/setup-tests.ts @@ -1 +1,4 @@ import '@testing-library/jest-dom'; +import ResizeObserver from 'resize-observer-polyfill'; + +global.ResizeObserver = ResizeObserver;