From 710f9d284d3ddc9cfe72ad8b2759d7cfa67adff9 Mon Sep 17 00:00:00 2001 From: thisconnect Date: Fri, 20 Dec 2024 08:49:41 +0100 Subject: [PATCH] frontend: improve send result view - show errors in send result view instead of popups - add edit transaction if there was an error - add new transaction on success - add buy ETH if there was gasfeetoolow error --- CHANGELOG.md | 1 + frontends/web/src/locales/en/app.json | 3 + .../routes/account/send/components/result.tsx | 90 +++++++++++++++---- .../src/routes/account/send/send.module.css | 8 +- .../web/src/routes/account/send/send.tsx | 36 ++++++-- 5 files changed, 111 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a2623318e..a642154c16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - Display the hide amount button by default and remove its settings - Linux: add support for Wayland - Fix the copy buttons in the Pocket order confirmation page +- Improve send result view offer proper success/error view and remove the popup with 5s timeout # 4.46.3 - Fix camera access on linux diff --git a/frontends/web/src/locales/en/app.json b/frontends/web/src/locales/en/app.json index 44a4daa5b2..dab8e41913 100644 --- a/frontends/web/src/locales/en/app.json +++ b/frontends/web/src/locales/en/app.json @@ -1601,6 +1601,7 @@ }, "availableBalance": "Available balance", "button": "Review", + "buyEth": "Buy ETH", "coincontrol": { "address": "Address", "addressReused": "Address re-used", @@ -1615,6 +1616,7 @@ "to": "To", "total": "Total" }, + "edit": "Edit transaction", "error": { "erc20InsufficientGasFunds": "It seems like you do not have enough Ether to pay for this ERC20 transaction. Please make sure you hold enough Ether in your wallet", "feeTooLow": "fee too low", @@ -1666,6 +1668,7 @@ }, "maximum": "Send all", "maximumSelectedCoins": "Send selected coins", + "newTransaction": "New transaction", "noFeeTargets": "Fee rate estimations are currently unavailable. Please try again later or enter a custom fee.", "priority": "Priority", "scanQR": "Scan QR code", diff --git a/frontends/web/src/routes/account/send/components/result.tsx b/frontends/web/src/routes/account/send/components/result.tsx index 07af9fba14..ea4af9a160 100644 --- a/frontends/web/src/routes/account/send/components/result.tsx +++ b/frontends/web/src/routes/account/send/components/result.tsx @@ -14,16 +14,18 @@ * limitations under the License. */ +import type { ReactNode } from 'react'; import { useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import type { AccountCode, TSendTx } from '@/api/account'; import { View, ViewButtons, ViewContent, ViewHeader } from '@/components/view/view'; import { Button } from '@/components/forms/button'; -import { alertUser } from '@/components/alert/Alert'; type TProps = { + children?: ReactNode; code: AccountCode; onContinue: () => void; + onRetry: () => void; result: TSendTx | undefined; }; @@ -33,45 +35,99 @@ type TProps = { * @returns view */ export const SendResult = ({ + children, code, result, onContinue, + onRetry, }: TProps) => { - const navigate = useNavigate(); const { t } = useTranslation(); + const navigate = useNavigate(); if (!result) { return null; } - const isAborted = 'aborted' in result; - - if (!result.success && !isAborted) { + if (!result.success) { + if ('aborted' in result) { + return ( + + + +

+ {t('send.abort')} +

+
+ + + + +
+ ); + } switch (result.errorCode) { case 'erc20InsufficientGasFunds': - alertUser(t(`send.error.${result.errorCode}`)); - break; + return ( + + + +

+ {t(`send.error.${result.errorCode}`)} +

+
+ + + + +
+ ); default: const { errorMessage } = result; - if (errorMessage) { - alertUser(t('unknownError', { errorMessage })); - } else { - alertUser(t('unknownError')); - } + return ( + + + +

+ {t('unknownError', { errorMessage })} +

+
+ + + + +
+ ); } - return null; } + return ( - +

- { result.success ? t('send.success') : t('send.abort') } + {t('send.success')}

+ {children}
- - + +
); diff --git a/frontends/web/src/routes/account/send/send.module.css b/frontends/web/src/routes/account/send/send.module.css index dac1c8f679..a783378e58 100644 --- a/frontends/web/src/routes/account/send/send.module.css +++ b/frontends/web/src/routes/account/send/send.module.css @@ -2,8 +2,12 @@ margin-top: calc(var(--space-default) * 1.5); } - .coinControlButtonContainer { height: 58px; margin-bottom: var(--space-quarter); -} \ No newline at end of file +} + +.unit { + color: var(--color-secondary); + font-size: var(--size-default); +} diff --git a/frontends/web/src/routes/account/send/send.tsx b/frontends/web/src/routes/account/send/send.tsx index 13e8315f89..bab1a53ea0 100644 --- a/frontends/web/src/routes/account/send/send.tsx +++ b/frontends/web/src/routes/account/send/send.tsx @@ -27,6 +27,7 @@ import { Button } from '@/components/forms'; import { BackButton } from '@/components/backbutton/backbutton'; import { Column, ColumnButtons, Grid, GuideWrapper, GuidedContent, Header, Main } from '@/components/layout'; import { translate, TranslateProps } from '@/decorators/translate'; +import { Amount } from '@/components/amount/amount'; import { FeeTargets } from './feetargets'; import { isBitcoinBased } from '@/routes/account/utils'; import { ConfirmSend } from './components/confirm/confirm'; @@ -36,6 +37,7 @@ import { ReceiverAddressInput } from './components/inputs/receiver-address-input import { CoinInput } from './components/inputs/coin-input'; import { FiatInput } from './components/inputs/fiat-input'; import { NoteInput } from './components/inputs/note-input'; +import { FiatValue } from './components/fiat-value'; import { TSelectedUTXOs } from './utxos'; import { TProposalError, txProposalErrorHandling } from './services'; import { CoinControl } from './coin-control'; @@ -137,9 +139,6 @@ class Send extends Component { try { const result = await accountApi.sendTx(code, this.state.note); this.setState({ sendResult: result, isConfirming: false }); - if (result.success) { - this.reset(); - } } catch (err) { console.error(err); } finally { @@ -354,6 +353,13 @@ class Send extends Component { }); }; + private handleContinue = () => { + this.setState({ + sendResult: undefined, + }); + this.reset(); + }; + public render() { const { account, @@ -497,11 +503,25 @@ class Send extends Component { coinCode={account.coinCode} transactionDetails={waitDialogTransactionDetails} /> - this.setState({ sendResult: undefined })} - /> + {sendResult && ( + this.setState({ sendResult: undefined })}> +

+ {(proposedAmount && + ) || 'N/A'} + {' '} + + {(proposedAmount && proposedAmount.unit) || 'N/A'} + +

+ {(proposedAmount && proposedAmount.conversions && proposedAmount.conversions[activeCurrency]) ? ( + + ) : null} +
+ )}