diff --git a/browser/ui/webui/brave_wallet/wallet_page_ui.cc b/browser/ui/webui/brave_wallet/wallet_page_ui.cc
index f7333985acb5..a4dabb6307ee 100644
--- a/browser/ui/webui/brave_wallet/wallet_page_ui.cc
+++ b/browser/ui/webui/brave_wallet/wallet_page_ui.cc
@@ -60,6 +60,8 @@ WalletPageUI::WalletPageUI(content::WebUI* web_ui)
plural_string_handler->AddLocalizedString(
"braveWalletExchangeNamePlusSteps",
IDS_BRAVE_WALLET_EXCHANGE_NAME_PLUS_STEPS);
+ plural_string_handler->AddLocalizedString(
+ "braveWalletPendingTransactions", IDS_BRAVE_WALLET_PENDING_TRANSACTIONS);
web_ui->AddMessageHandler(std::move(plural_string_handler));
NavigationBarDataProvider::Initialize(source, profile);
webui::SetupWebUIDataSource(
diff --git a/browser/ui/webui/brave_wallet/wallet_panel_ui.cc b/browser/ui/webui/brave_wallet/wallet_panel_ui.cc
index 4090e9e5763f..ceddcaf163b9 100644
--- a/browser/ui/webui/brave_wallet/wallet_panel_ui.cc
+++ b/browser/ui/webui/brave_wallet/wallet_panel_ui.cc
@@ -63,6 +63,8 @@ WalletPanelUI::WalletPanelUI(content::WebUI* web_ui)
plural_string_handler->AddLocalizedString(
"braveWalletExchangeNamePlusSteps",
IDS_BRAVE_WALLET_EXCHANGE_NAME_PLUS_STEPS);
+ plural_string_handler->AddLocalizedString(
+ "braveWalletPendingTransactions", IDS_BRAVE_WALLET_PENDING_TRANSACTIONS);
web_ui->AddMessageHandler(std::move(plural_string_handler));
webui::SetupWebUIDataSource(source,
base::make_span(kBraveWalletPanelGenerated,
diff --git a/components/brave_wallet/browser/brave_wallet_constants.h b/components/brave_wallet/browser/brave_wallet_constants.h
index ab3911470240..c6dfba64b66e 100644
--- a/components/brave_wallet/browser/brave_wallet_constants.h
+++ b/components/brave_wallet/browser/brave_wallet_constants.h
@@ -1124,14 +1124,32 @@ inline constexpr webui::LocalizedString kLocalizedStrings[] = {
{"braveWalletPortfolioSettings", IDS_BRAVE_WALLET_PORTFOLIO_SETTINGS},
{"braveWalletAccountFilterAllAccounts",
IDS_BRAVE_WALLET_ACCOUNT_FILTER_ALL_ACCOUNTS},
+ {"braveWalletGetHelp", IDS_BRAVE_WALLET_GET_HELP},
+ {"braveWalletTransactionTakingLongTime",
+ IDS_BRAVE_WALLET_TRANSACTION_TAKING_LONG_TIME},
+ {"braveWalletViewInActivity", IDS_BRAVE_WALLET_VIEW_IN_ACTIVITY},
+ {"braveWalletSafelyDismissWindow", IDS_BRAVE_WALLET_SAFELY_DISMISS_WINDOW},
+ {"braveWalletSendingAmountToAccount",
+ IDS_BRAVE_WALLET_SENDING_AMOUNT_TO_ACCOUNT},
+ {"braveWalletAmountSentToAccount", IDS_BRAVE_WALLET_AMOUNT_SENT_TO_ACCOUNT},
+ {"braveWalletSwappingAmountToAmountOnNetwork",
+ IDS_BRAVE_WALLET_SWAPPING_AMOUNT_TO_ACCOUNT_ON_NETWORK},
+ {"braveWalletAmountAddedToAccount",
+ IDS_BRAVE_WALLET_AMOUNT_ADDED_TO_ACCOUNT},
+ {"braveWalletBridgingAmountToNetwork",
+ IDS_BRAVE_WALLET_BRIDGING_AMOUNT_TO_NETWORK},
+ {"braveWalletUnableToSendSwapOrBridge",
+ IDS_BRAVE_WALLET_UNABLE_TO_SEND_SWAP_OR_BRIDGE},
+ {"braveWalletErrorAttemptingToTransact",
+ IDS_BRAVE_WALLET_ERROR_ATTEMPTING_TO_TRANSACT},
+ {"braveWalletApprovingAmountOnExchange",
+ IDS_BRAVE_WALLET_APPROVING_AMOUNT_ON_EXCHANGE},
+ {"braveWalletCancelTransactionDescription",
+ IDS_BRAVE_WALLET_CANCEL_TRANSACTION_DESCRIPTION},
{"braveWalletTransactionSubmittedTitle",
IDS_BRAVE_WALLET_TRANSACTION_SUBMITTED_TITLE},
- {"braveWalletTransactionSubmittedDescription",
- IDS_BRAVE_WALLET_TRANSACTION_SUBMITTED_DESCRIPTION},
{"braveWalletTransactionSignedTitle",
IDS_BRAVE_WALLET_TRANSACTION_SIGNED_TITLE},
- {"braveWalletTransactionSignedDescription",
- IDS_BRAVE_WALLET_TRANSACTION_SIGNED_DESCRIPTION},
{"braveWalletTransactionFailedHeaderTitle",
IDS_BRAVE_WALLET_TRANSACTION_FAILED_HEADER_TITLE},
{"braveWalletTransactionFailedTitle",
diff --git a/components/brave_wallet_ui/assets/svg-icons/error-circle-icon.svg b/components/brave_wallet_ui/assets/svg-icons/error-circle-icon.svg
deleted file mode 100644
index 6116f0553598..000000000000
--- a/components/brave_wallet_ui/assets/svg-icons/error-circle-icon.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/cancel_transaction/cancel_transaction.stories.tsx b/components/brave_wallet_ui/components/extension/post-confirmation/cancel_transaction/cancel_transaction.stories.tsx
new file mode 100644
index 000000000000..db59c6873078
--- /dev/null
+++ b/components/brave_wallet_ui/components/extension/post-confirmation/cancel_transaction/cancel_transaction.stories.tsx
@@ -0,0 +1,42 @@
+// Copyright (c) 2024 The Brave Authors. All rights reserved.
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at https://mozilla.org/MPL/2.0/.
+import * as React from 'react'
+
+// Mocks
+import {
+ mockTransactionInfo //
+} from '../../../../stories/mock-data/mock-transaction-info'
+
+// Components
+import {
+ WalletPanelStory //
+} from '../../../../stories/wrappers/wallet-panel-story-wrapper'
+import { CancelTransaction } from './cancel_transaction'
+
+// Styled Components
+import { LongWrapper } from '../../../../stories/style'
+import { PanelWrapper } from '../../../../panel/style'
+
+export const _CancelTransaction = {
+ render: () => {
+ return (
+
+
+
+ alert('Back clicked')}
+ transaction={mockTransactionInfo}
+ />
+
+
+
+ )
+ }
+}
+
+export default { component: CancelTransaction }
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/cancel_transaction/cancel_transaction.style.ts b/components/brave_wallet_ui/components/extension/post-confirmation/cancel_transaction/cancel_transaction.style.ts
new file mode 100644
index 000000000000..a3aa65c724d2
--- /dev/null
+++ b/components/brave_wallet_ui/components/extension/post-confirmation/cancel_transaction/cancel_transaction.style.ts
@@ -0,0 +1,11 @@
+// Copyright (c) 2024 The Brave Authors. All rights reserved.
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at https://mozilla.org/MPL/2.0/.
+import styled from 'styled-components'
+import Button from '@brave/leo/react/button'
+import * as leo from '@brave/leo/tokens/css/variables'
+
+export const CancelButton = styled(Button)`
+ --leo-button-color: ${leo.color.button.errorBackground};
+`
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/cancel_transaction/cancel_transaction.tsx b/components/brave_wallet_ui/components/extension/post-confirmation/cancel_transaction/cancel_transaction.tsx
new file mode 100644
index 000000000000..63b995558eb6
--- /dev/null
+++ b/components/brave_wallet_ui/components/extension/post-confirmation/cancel_transaction/cancel_transaction.tsx
@@ -0,0 +1,79 @@
+// Copyright (c) 2024 The Brave Authors. All rights reserved.
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at https://mozilla.org/MPL/2.0/.
+import * as React from 'react'
+
+// Types
+import { SerializableTransactionInfo } from '../../../../constants/types'
+
+// Utils
+import { getLocale } from '$web-common/locale'
+import { getCoinFromTxDataUnion } from '../../../../utils/network-utils'
+
+// Hooks
+import {
+ useCancelTransactionMutation //
+} from '../../../../common/slices/api.slice'
+
+// Components
+import { PostConfirmationHeader } from '../common/post_confirmation_header'
+
+// Styled components
+import { CancelButton } from './cancel_transaction.style'
+import { Wrapper, Title } from '../common/common.style'
+import { Column, Row, Text } from '../../../shared/style'
+
+interface Props {
+ transaction: SerializableTransactionInfo
+ onBack: () => void
+}
+
+export const CancelTransaction = (props: Props) => {
+ const { transaction, onBack } = props
+
+ // Computed
+ const txCoinType = getCoinFromTxDataUnion(transaction.txDataUnion)
+
+ // Hooks
+ const [cancelTx] = useCancelTransactionMutation()
+
+ // Methods
+ const onClickCancelTransaction = () => {
+ cancelTx({
+ coinType: txCoinType,
+ chainId: transaction.chainId,
+ transactionId: transaction.id
+ })
+ }
+
+ return (
+
+
+
+ {getLocale('braveWalletTransactionCancel')}
+
+ {getLocale('braveWalletCancelTransactionDescription')}
+
+
+
+
+ {getLocale('braveWalletTransactionCancel')}
+
+
+
+ )
+}
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/common/common.style.ts b/components/brave_wallet_ui/components/extension/post-confirmation/common/common.style.ts
index 1edde1c73e5c..c3109d5393f5 100644
--- a/components/brave_wallet_ui/components/extension/post-confirmation/common/common.style.ts
+++ b/components/brave_wallet_ui/components/extension/post-confirmation/common/common.style.ts
@@ -3,26 +3,21 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at https://mozilla.org/MPL/2.0/.
import styled from 'styled-components'
-
+import ProgressRing from '@brave/leo/react/progressRing'
+import LeoIcon from '@brave/leo/react/icon'
+import LeoAlert from '@brave/leo/react/alert'
+import * as leo from '@brave/leo/tokens/css/variables'
import LinkSvg from '../../../../assets/svg-icons/link-icon.svg'
import LoadingIcon from '../../../../assets/svg-icons/loading-slow.svg'
-import { WalletButton } from '../../../shared/style'
+import { WalletButton, Column, Text } from '../../../shared/style'
-export const TransactionStatusIcon = styled.div`
- width: 112px;
- height: 112px;
- margin: 24px 0;
+export const Wrapper = styled(Column)`
+ background-color: ${leo.color.container.highlight};
`
-export const TransactionStatusText = styled.div`
- font-family: 'Poppins';
- font-style: normal;
- font-weight: 600;
- font-size: 18px;
- line-height: 27px;
-
- text-align: center;
- letter-spacing: 0.02em;
+export const Title = styled(Text)`
+ font: ${leo.font.heading.h3};
+ margin-bottom: 8px;
`
export const TransactionStatusDescription = styled.div`
@@ -33,31 +28,7 @@ export const TransactionStatusDescription = styled.div`
line-height: 20px;
text-align: center;
color: ${(p) => p.theme.color.text02};
-
padding: 8px 16px;
- flex-grow: 1;
-`
-
-export const PendingTransactionsRow = styled.div`
- font-family: 'Poppins';
- font-style: normal;
- font-weight: 400;
- font-size: 12px;
- line-height: 20px;
- text-align: center;
- color: ${(p) => p.theme.color.text03};
- padding: 8px 16px;
- flex-grow: 1;
-`
-
-export const ButtonRow = styled.div`
- display: flex;
- align-items: center;
- justify-content: center;
- flex-direction: row;
- width: 100%;
- padding-bottom: 22px;
- gap: 8px;
`
export const LinkIcon = styled.div`
@@ -90,3 +61,68 @@ export const Loader = styled.div`
margin: 36px 0;
opacity: 0.4;
`
+
+export const LoadingRing = styled(ProgressRing)`
+ --leo-progressring-size: 110px;
+ --leo-progressring-color: ${leo.color.icon.interactive};
+ margin-bottom: 46px;
+`
+
+export const StatusIcon = styled(LeoIcon)`
+ --leo-icon-size: 34px;
+ color: ${leo.color.icon.interactive};
+`
+
+export const Button = styled(WalletButton)`
+ cursor: pointer;
+ background-color: none;
+ background: none;
+ outline: none;
+ border: none;
+ padding: 0px;
+ margin: 0px;
+`
+
+export const HeaderButton = styled(Button)`
+ margin: 2px 0px;
+`
+
+export const HeaderIcon = styled(LeoIcon)`
+ --leo-icon-size: 24px;
+ color: ${leo.color.icon.default};
+`
+
+export const ExplorerIcon = styled(LeoIcon).attrs({
+ name: 'arrow-diagonal-up-right'
+})`
+ --leo-icon-size: 20px;
+ color: ${leo.color.icon.interactive};
+`
+
+export const Alert = styled(LeoAlert)`
+ width: 100%;
+ --leo-alert-padding: 12px;
+ margin-bottom: 46px;
+`
+
+export const ErrorOrSuccessIconWrapper = styled.div<{
+ kind: 'error' | 'success'
+}>`
+ padding: 20px;
+ border-radius: 100%;
+ background-color: ${(p) =>
+ p.kind === 'error'
+ ? leo.color.systemfeedback.errorBackground
+ : leo.color.systemfeedback.successBackground};
+ margin-bottom: 40px;
+`
+
+export const ErrorOrSuccessIcon = styled(LeoIcon)<{
+ kind: 'error' | 'success'
+}>`
+ --leo-icon-size: 60px;
+ color: ${(p) =>
+ p.kind === 'error'
+ ? leo.color.systemfeedback.errorIcon
+ : leo.color.systemfeedback.successIcon};
+`
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/common/post_confirmation_header.tsx b/components/brave_wallet_ui/components/extension/post-confirmation/common/post_confirmation_header.tsx
new file mode 100644
index 000000000000..ae5485cdacf1
--- /dev/null
+++ b/components/brave_wallet_ui/components/extension/post-confirmation/common/post_confirmation_header.tsx
@@ -0,0 +1,56 @@
+// Copyright (c) 2024 The Brave Authors. All rights reserved.
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at https://mozilla.org/MPL/2.0/.
+import * as React from 'react'
+import Icon from '@brave/leo/react/icon'
+import LeoButton from '@brave/leo/react/button'
+
+// Utils
+import { getLocale } from '$web-common/locale'
+
+// Styled Components
+import { HeaderButton, HeaderIcon } from './common.style'
+import { Row } from '../../../shared/style'
+
+interface Props {
+ onClose?: () => void
+ onBack?: () => void
+ showHelp?: boolean
+}
+
+export const PostConfirmationHeader = (props: Props) => {
+ const { onClose, onBack, showHelp } = props
+
+ return (
+
+ {showHelp && (
+
+
+
+ {getLocale('braveWalletGetHelp')}
+
+
+ )}
+ {onBack && (
+
+
+
+ )}
+ {onClose && (
+
+
+
+ )}
+
+ )
+}
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/common/speed_up_alert.tsx b/components/brave_wallet_ui/components/extension/post-confirmation/common/speed_up_alert.tsx
new file mode 100644
index 000000000000..d6ad9cec74d7
--- /dev/null
+++ b/components/brave_wallet_ui/components/extension/post-confirmation/common/speed_up_alert.tsx
@@ -0,0 +1,38 @@
+// Copyright (c) 2024 The Brave Authors. All rights reserved.
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at https://mozilla.org/MPL/2.0/.
+import * as React from 'react'
+import Button from '@brave/leo/react/button'
+
+// Utils
+import { getLocale } from '$web-common/locale'
+
+// Styled Components
+import { Alert } from './common.style'
+
+interface Props {
+ onSpeedUp?: () => void
+}
+
+export const SpeedUpAlert = (props: Props) => {
+ const { onSpeedUp } = props
+
+ return (
+
+ {getLocale('braveWalletTransactionTakingLongTime')}
+
+
+
+
+ )
+}
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/common/transaction_intent.tsx b/components/brave_wallet_ui/components/extension/post-confirmation/common/transaction_intent.tsx
new file mode 100644
index 000000000000..d4acae7f4cb5
--- /dev/null
+++ b/components/brave_wallet_ui/components/extension/post-confirmation/common/transaction_intent.tsx
@@ -0,0 +1,329 @@
+// Copyright (c) 2024 The Brave Authors. All rights reserved.
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at https://mozilla.org/MPL/2.0/.
+import * as React from 'react'
+import { skipToken } from '@reduxjs/toolkit/query/react'
+
+// Types
+import {
+ BraveWallet,
+ SerializableTransactionInfo //
+} from '../../../../constants/types'
+
+// Utils
+import { getLocale, splitStringForTag } from '$web-common/locale'
+import {
+ findTransactionToken,
+ getFormattedTransactionTransferredValue,
+ getIsTxApprovalUnlimited,
+ getTransactionApprovalTargetAddress,
+ getTransactionToAddress,
+ isBridgeTransaction,
+ isSwapTransaction
+} from '../../../../utils/tx-utils'
+import { getCoinFromTxDataUnion } from '../../../../utils/network-utils'
+import { getAddressLabel } from '../../../../utils/account-utils'
+import Amount from '../../../../utils/amount'
+
+// Queries
+import {
+ useAccountQuery,
+ useGetCombinedTokensListQuery
+} from '../../../../common/slices/api.slice.extra'
+import {
+ useGetAccountInfosRegistryQuery,
+ useGetNetworkQuery
+} from '../../../../common/slices/api.slice'
+import {
+ accountInfoEntityAdaptorInitialState //
+} from '../../../../common/slices/entities/account-info.entity'
+
+// Hooks
+import {
+ useTransactionsNetwork //
+} from '../../../../common/hooks/use-transactions-network'
+import {
+ useSwapTransactionParser //
+} from '../../../../common/hooks/use-swap-tx-parser'
+import { useExplorer } from '../../../../common/hooks/explorer'
+
+// Styled Components
+import { Button, ExplorerIcon } from './common.style'
+import { Row, Text } from '../../../shared/style'
+
+interface Props {
+ transaction: SerializableTransactionInfo
+}
+
+export const TransactionIntent = (props: Props) => {
+ const { transaction } = props
+
+ // Computed
+ const isBridge = isBridgeTransaction(transaction)
+ const isSwap = isSwapTransaction(transaction)
+ const isSwapOrBridge = isBridge || isSwap
+ const isERC20Approval =
+ transaction.txType === BraveWallet.TransactionType.ERC20Approve
+ const isTxApprovalUnlimited = getIsTxApprovalUnlimited(transaction)
+ const txApprovalTarget = getTransactionApprovalTargetAddress(transaction)
+ const txCoinType = getCoinFromTxDataUnion(transaction.txDataUnion)
+ const txToAddress = getTransactionToAddress(transaction)
+
+ // Queries
+ const { account: txAccount } = useAccountQuery(transaction.fromAccountId)
+
+ // Custom Hooks
+ const transactionNetwork = useTransactionsNetwork(transaction)
+ const onClickViewOnBlockExplorer = useExplorer(transactionNetwork)
+
+ const { normalizedTransferredValue } =
+ getFormattedTransactionTransferredValue({
+ tx: transaction,
+ txAccount,
+ txNetwork: transactionNetwork
+ })
+
+ const { data: txNetwork } = useGetNetworkQuery({
+ chainId: transaction.chainId,
+ coin: txCoinType
+ })
+
+ const { data: bridgeToNetwork } = useGetNetworkQuery(
+ isBridge &&
+ transaction.swapInfo?.toChainId &&
+ transaction.swapInfo.toCoin !== undefined
+ ? {
+ chainId: transaction.swapInfo.toChainId,
+ coin: transaction.swapInfo.toCoin
+ }
+ : skipToken
+ )
+
+ const { data: accountInfosRegistry = accountInfoEntityAdaptorInitialState } =
+ useGetAccountInfosRegistryQuery(undefined)
+
+ const { buyToken, sellToken, buyAmountWei, sellAmountWei } =
+ useSwapTransactionParser(transaction)
+
+ const { data: combinedTokensList } = useGetCombinedTokensListQuery()
+
+ const formattedSellAmount = sellToken
+ ? sellAmountWei
+ .divideByDecimals(sellToken.decimals)
+ .formatAsAsset(6, sellToken.symbol)
+ : ''
+ const formattedBuyAmount = buyToken
+ ? buyAmountWei
+ .divideByDecimals(buyToken.decimals)
+ .formatAsAsset(6, buyToken.symbol)
+ : ''
+
+ const recipientLabel = getAddressLabel(
+ isERC20Approval ? txApprovalTarget : txToAddress,
+ accountInfosRegistry
+ )
+
+ const transactionsToken = findTransactionToken(
+ transaction,
+ combinedTokensList
+ )
+
+ const formattedSendAmount = React.useMemo(() => {
+ if (!transactionsToken) {
+ return ''
+ }
+ if (
+ transactionsToken.isErc721 ||
+ transactionsToken.isErc1155 ||
+ transactionsToken.isNft
+ ) {
+ return `${transactionsToken.name} ${transactionsToken.symbol}`
+ }
+ return new Amount(normalizedTransferredValue).formatAsAsset(
+ 6,
+ transactionsToken.symbol
+ )
+ }, [transactionsToken, normalizedTransferredValue])
+
+ const formattedApprovalAmount = isTxApprovalUnlimited
+ ? `${getLocale('braveWalletTransactionApproveUnlimited')} ${
+ transactionsToken?.symbol ?? ''
+ }`
+ : formattedSendAmount
+
+ const transactionFailed =
+ transaction.txStatus === BraveWallet.TransactionStatus.Dropped ||
+ transaction.txStatus === BraveWallet.TransactionStatus.Error
+
+ const transactionConfirmed =
+ transaction.txStatus === BraveWallet.TransactionStatus.Confirmed
+
+ const firstDuringValue = React.useMemo(() => {
+ if (isERC20Approval) {
+ return formattedApprovalAmount
+ }
+ if (isSwapOrBridge && transactionConfirmed) {
+ return formattedBuyAmount
+ }
+ if (isSwapOrBridge) {
+ return formattedSellAmount
+ }
+ return formattedSendAmount
+ }, [
+ isERC20Approval,
+ formattedApprovalAmount,
+ isSwapOrBridge,
+ transactionConfirmed,
+ formattedBuyAmount,
+ formattedSellAmount,
+ formattedSendAmount
+ ])
+
+ const secondDuringValue = React.useMemo(() => {
+ if (isSwapOrBridge && transactionConfirmed) {
+ return recipientLabel
+ }
+ if (isBridge) {
+ return bridgeToNetwork?.chainName ?? ''
+ }
+ if (isSwap) {
+ return formattedBuyAmount
+ }
+ return recipientLabel
+ }, [
+ isSwapOrBridge,
+ transactionConfirmed,
+ recipientLabel,
+ isBridge,
+ bridgeToNetwork,
+ isSwap,
+ formattedBuyAmount
+ ])
+
+ const sendSwapOrBridgeLocale = React.useMemo(() => {
+ if (isBridge) {
+ return getLocale('braveWalletBridge').toLocaleLowerCase()
+ }
+ if (isSwap) {
+ return getLocale('braveWalletSwap').toLocaleLowerCase()
+ }
+ return getLocale('braveWalletSend').toLocaleLowerCase()
+ }, [isBridge, isSwap])
+
+ const descriptionLocale = React.useMemo(() => {
+ if (transactionFailed) {
+ return 'braveWalletErrorAttemptingToTransact'
+ }
+ if (isSwapOrBridge && transactionConfirmed) {
+ return 'braveWalletAmountAddedToAccount'
+ }
+ if (isBridge) {
+ return 'braveWalletBridgingAmountToNetwork'
+ }
+ if (isSwap) {
+ return 'braveWalletSwappingAmountToAmountOnNetwork'
+ }
+ if (isERC20Approval) {
+ return 'braveWalletApprovingAmountOnExchange'
+ }
+ if (transactionConfirmed) {
+ return 'braveWalletAmountSentToAccount'
+ }
+ return 'braveWalletSendingAmountToAccount'
+ }, [
+ transactionFailed,
+ isSwapOrBridge,
+ transactionConfirmed,
+ isBridge,
+ isSwap,
+ isERC20Approval
+ ])
+
+ const descriptionString = getLocale(descriptionLocale)
+ .replace('$5', firstDuringValue)
+ .replace('$6', secondDuringValue)
+ .replace(
+ '$7',
+ transactionFailed ? sendSwapOrBridgeLocale : txNetwork?.chainName ?? ''
+ )
+
+ const {
+ beforeTag: firstBefore,
+ duringTag: firstDuring,
+ afterTag: firstAfter
+ } = splitStringForTag(descriptionString, 1)
+ const {
+ beforeTag: secondBefore,
+ duringTag: secondDuring,
+ afterTag: secondAfter
+ } = splitStringForTag(firstAfter ?? '', 3)
+
+ return (
+
+ {firstBefore && (
+
+ {firstBefore}
+
+ )}
+ {firstDuring && (
+
+ {firstDuring}
+
+ )}
+ {secondBefore && (
+
+ {secondBefore}
+
+ )}
+ {secondDuring && (
+
+
+ {secondDuring}
+
+
+
+ )}
+ {secondAfter && (
+
+ {secondAfter}
+
+ )}
+
+ )
+}
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/complete/complete.stories.tsx b/components/brave_wallet_ui/components/extension/post-confirmation/complete/complete.stories.tsx
index 17db35272cad..68cad02df89e 100644
--- a/components/brave_wallet_ui/components/extension/post-confirmation/complete/complete.stories.tsx
+++ b/components/brave_wallet_ui/components/extension/post-confirmation/complete/complete.stories.tsx
@@ -2,40 +2,66 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at https://mozilla.org/MPL/2.0/.
-
import * as React from 'react'
-// Utils
-import { getLocale } from '$web-common/locale'
+// Types
+import {
+ BraveWallet,
+ StorybookTransactionArgs,
+ StorybookTransactionOptions
+} from '../../../../constants/types'
+
+// Mocks
+import {
+ getPostConfirmationStatusMockTransaction //
+} from '../../../../stories/mock-data/mock-transaction-info'
// Components
-import WalletPanelStory from '../../../../stories/wrappers/wallet-panel-story-wrapper'
-import { StyledExtensionWrapper } from '../../../../stories/style'
-import { PanelWrapper } from '../../../../panel/style'
+import {
+ WalletPanelStory //
+} from '../../../../stories/wrappers/wallet-panel-story-wrapper'
import { TransactionComplete } from './complete'
+// Styled Components
+import { LongWrapper } from '../../../../stories/style'
+import { PanelWrapper } from '../../../../panel/style'
+
export const _TransactionComplete = {
- render: () => {
- const onClose = () => alert('Close panel screen')
+ render: (args: StorybookTransactionArgs) => {
+ // Props
+ const { transactionType } = args
+
+ // Computed
+ const transaction = getPostConfirmationStatusMockTransaction(
+ transactionType,
+ BraveWallet.TransactionStatus.Confirmed
+ )
return (
-
-
+
+ alert('Clicked primary CTA')}
- onClickSecondaryCTA={() => alert('Clicked secondary CTA')}
+ transaction={transaction}
+ onClose={() => alert('Close panel screen clicked.')}
+ onClickViewInActivity={() => alert('View in activity clicked.')}
/>
-
+
)
}
}
-export default { component: TransactionComplete }
+export default {
+ component: TransactionComplete,
+ argTypes: {
+ transactionType: {
+ options: StorybookTransactionOptions,
+ control: { type: 'select' }
+ }
+ }
+}
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/complete/complete.style.ts b/components/brave_wallet_ui/components/extension/post-confirmation/complete/complete.style.ts
deleted file mode 100644
index 480c4ed92935..000000000000
--- a/components/brave_wallet_ui/components/extension/post-confirmation/complete/complete.style.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2022 The Brave Authors. All rights reserved.
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this file,
-// you can obtain one at https://mozilla.org/MPL/2.0/.
-import styled from 'styled-components'
-
-import SuccessSvg from '../../../../assets/svg-icons/success-circle-icon.svg'
-import {
- TransactionStatusIcon,
- TransactionStatusText
-} from '../common/common.style'
-
-export const SuccessIcon = styled(TransactionStatusIcon)`
- background: url(${SuccessSvg});
-`
-
-export const Title = styled(TransactionStatusText)`
- color: ${(p) => p.theme.color.text01};
-`
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/complete/complete.tsx b/components/brave_wallet_ui/components/extension/post-confirmation/complete/complete.tsx
index 159afb1b663c..013c89b12643 100644
--- a/components/brave_wallet_ui/components/extension/post-confirmation/complete/complete.tsx
+++ b/components/brave_wallet_ui/components/extension/post-confirmation/complete/complete.tsx
@@ -3,75 +3,106 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at https://mozilla.org/MPL/2.0/.
import * as React from 'react'
+import LeoButton from '@brave/leo/react/button'
+import {
+ PluralStringProxyImpl //
+} from 'chrome://resources/js/plural_string_proxy.js'
+import usePromise from '$web-common/usePromise'
// Utils
import { getLocale } from '$web-common/locale'
// Hooks
-import { usePendingTransactions } from '../../../../common/hooks/use-pending-transaction'
+import {
+ usePendingTransactions //
+} from '../../../../common/hooks/use-pending-transaction'
// Components
-import { NavButton } from '../../buttons/nav-button/index'
-import { Panel } from '../../panel/index'
-import { SuccessIcon, Title } from './complete.style'
import {
- ButtonRow,
- PendingTransactionsRow,
- TransactionStatusDescription
+ PostConfirmationHeader //
+} from '../common/post_confirmation_header'
+
+// Styled Components
+import {
+ // TransactionStatusDescription,
+ Title,
+ Wrapper,
+ ErrorOrSuccessIconWrapper,
+ ErrorOrSuccessIcon
} from '../common/common.style'
+import { Column, Row, Text } from '../../../shared/style'
+import { SerializableTransactionInfo } from '../../../../constants/types'
+import { TransactionIntent } from '../common/transaction_intent'
interface Props {
- headerTitle: string
- description: string
- isPrimaryCTADisabled: boolean
- primaryCTAText: string
+ transaction: SerializableTransactionInfo
onClose: () => void
- onClickSecondaryCTA: () => void
- onClickPrimaryCTA: () => void
+ onClickViewInActivity: () => void
}
export const TransactionComplete = (props: Props) => {
- const {
- headerTitle,
- description,
- isPrimaryCTADisabled,
- primaryCTAText,
- onClose,
- onClickPrimaryCTA,
- onClickSecondaryCTA
- } = props
+ const { transaction, onClose, onClickViewInActivity } = props
+ // Hooks
const { transactionsQueueLength } = usePendingTransactions()
+ // Computed
+ const { result: pendingTransactionsLocale } = usePromise(
+ async () =>
+ PluralStringProxyImpl.getInstance().getPluralString(
+ 'braveWalletPendingTransactions',
+ transactionsQueueLength
+ ),
+ [transactionsQueueLength]
+ )
+ const hasMoreTransactions = transactionsQueueLength >= 1
+
return (
-
-
- {getLocale('braveWalletTransactionCompleteTitle')}
- {description}
-
- {transactionsQueueLength >= 1 && (
-
- {transactionsQueueLength} more transactions pending.
-
- )}
-
-
-
-
-
-
+
+
+
+
+
+ {getLocale('braveWalletTransactionCompleteTitle')}
+
+
+
+ {hasMoreTransactions && (
+
+ {pendingTransactionsLocale}
+
+ )}
+
+
+ {getLocale('braveWalletViewInActivity')}
+
+ {hasMoreTransactions && (
+
+ {getLocale('braveWalletButtonNext')}
+
+ )}
+
+
+
)
}
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/complete/index.tsx b/components/brave_wallet_ui/components/extension/post-confirmation/complete/index.tsx
deleted file mode 100644
index 8ec6f9f99477..000000000000
--- a/components/brave_wallet_ui/components/extension/post-confirmation/complete/index.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright (c) 2022 The Brave Authors. All rights reserved.
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this file,
-// you can obtain one at https://mozilla.org/MPL/2.0/.
-import { TransactionComplete } from './complete'
-
-export { TransactionComplete }
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/failed/failed.stories.tsx b/components/brave_wallet_ui/components/extension/post-confirmation/failed/failed.stories.tsx
deleted file mode 100644
index e8a366b97749..000000000000
--- a/components/brave_wallet_ui/components/extension/post-confirmation/failed/failed.stories.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2022 The Brave Authors. All rights reserved.
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this file,
-// you can obtain one at https://mozilla.org/MPL/2.0/.
-
-import * as React from 'react'
-
-// Utils
-import { getLocale } from '$web-common/locale'
-
-// Components
-import WalletPanelStory from '../../../../stories/wrappers/wallet-panel-story-wrapper'
-import { StyledExtensionWrapper } from '../../../../stories/style'
-import { PanelWrapper } from '../../../../panel/style'
-import { TransactionFailed } from './failed'
-
-export const _TransactionFailed = {
- render: () => {
- const onClose = () => alert('Close panel screen')
-
- return (
-
-
-
- alert('Clicked primary CTA')}
- />
-
-
-
- )
- }
-}
-
-export default { component: TransactionFailed }
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/failed/failed.style.ts b/components/brave_wallet_ui/components/extension/post-confirmation/failed/failed.style.ts
deleted file mode 100644
index 5751eba4d1aa..000000000000
--- a/components/brave_wallet_ui/components/extension/post-confirmation/failed/failed.style.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2022 The Brave Authors. All rights reserved.
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this file,
-// you can obtain one at https://mozilla.org/MPL/2.0/.
-import styled from 'styled-components'
-
-import ErrorSvg from '../../../../assets/svg-icons/error-circle-icon.svg'
-import {
- TransactionStatusIcon,
- TransactionStatusText
-} from '../common/common.style'
-
-export const ErrorIcon = styled(TransactionStatusIcon)`
- background: url(${ErrorSvg});
-`
-
-export const Title = styled(TransactionStatusText)`
- color: ${(p) => p.theme.color.errorBorder};
-`
-
-export const ErrorDetailTitle = styled.div`
- font-family: 'Poppins';
- font-style: normal;
- font-weight: 500;
- font-size: 12px;
- line-height: 18px;
- color: ${(p) => p.theme.color.errorBorder};
- margin: 0 16px;
-`
-
-export const ErrorDetailContentContainer = styled.div`
- background: ${(p) => p.theme.color.errorBackground};
- border-radius: 8px;
- margin: 16px;
-`
-
-export const ErrorDetailContent = styled.div`
- font-family: 'Poppins';
- font-style: normal;
- font-weight: 400;
- font-size: 12px;
- line-height: 18px;
- color: ${(p) => p.theme.color.text01};
- opacity: 0.9;
- margin: 8px;
-`
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/failed/failed.tsx b/components/brave_wallet_ui/components/extension/post-confirmation/failed/failed.tsx
deleted file mode 100644
index 88a8c7fae5c4..000000000000
--- a/components/brave_wallet_ui/components/extension/post-confirmation/failed/failed.tsx
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2022 The Brave Authors. All rights reserved.
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this file,
-// you can obtain one at https://mozilla.org/MPL/2.0/.
-import * as React from 'react'
-
-import { getLocale } from '$web-common/locale'
-
-import { Panel } from '../../panel/index'
-import { NavButton } from '../../buttons/nav-button/index'
-import {
- ErrorIcon,
- Title,
- ErrorDetailTitle,
- ErrorDetailContent,
- ErrorDetailContentContainer
-} from './failed.style'
-import { ButtonRow, TransactionStatusDescription } from '../common/common.style'
-import { PopupModal } from '../../popup-modals'
-
-interface Props {
- headerTitle: string
- isPrimaryCTADisabled: boolean
- customDescription: string | undefined
- errorDetailTitle: string
- errorDetailContent?: string | undefined
- onClose: () => void
- onClickPrimaryCTA: () => void
-}
-
-export const TransactionFailed = (props: Props) => {
- const {
- headerTitle,
- errorDetailTitle,
- errorDetailContent,
- isPrimaryCTADisabled,
- customDescription,
- onClose,
- onClickPrimaryCTA
- } = props
-
- const [showErrorCodeModal, setShowErrorCodeModal] =
- React.useState(false)
-
- const description = customDescription ||
- getLocale('braveWalletTransactionFailedDescription')
-
- return (
-
-
- {getLocale('braveWalletTransactionFailedTitle')}
-
- {description}
-
-
- {errorDetailContent && (
- setShowErrorCodeModal(true)}
- />
- )}
-
-
-
- {showErrorCodeModal && errorDetailContent && (
- setShowErrorCodeModal(false)}
- />
- )}
-
- )
-}
-
-interface ModalProps {
- title: string
- content: string
- onClose: () => void
-}
-
-const ErrorDetail = (props: ModalProps) => {
- const { content, title, onClose } = props
-
- return (
-
- {title}
-
-
- {content}
-
-
-
-
-
-
- )
-}
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/failed/index.tsx b/components/brave_wallet_ui/components/extension/post-confirmation/failed/index.tsx
deleted file mode 100644
index 3d68c9055646..000000000000
--- a/components/brave_wallet_ui/components/extension/post-confirmation/failed/index.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright (c) 2022 The Brave Authors. All rights reserved.
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this file,
-// you can obtain one at https://mozilla.org/MPL/2.0/.
-import { TransactionFailed } from './failed'
-
-export { TransactionFailed }
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/failed_or_canceled/failed_or_canceled.stories.tsx b/components/brave_wallet_ui/components/extension/post-confirmation/failed_or_canceled/failed_or_canceled.stories.tsx
new file mode 100644
index 000000000000..10e030e052e9
--- /dev/null
+++ b/components/brave_wallet_ui/components/extension/post-confirmation/failed_or_canceled/failed_or_canceled.stories.tsx
@@ -0,0 +1,66 @@
+// Copyright (c) 2024 The Brave Authors. All rights reserved.
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at https://mozilla.org/MPL/2.0/.
+import * as React from 'react'
+
+// Types
+import {
+ BraveWallet,
+ StorybookTransactionArgs,
+ StorybookTransactionOptions
+} from '../../../../constants/types'
+
+// Mocks
+import {
+ getPostConfirmationStatusMockTransaction //
+} from '../../../../stories/mock-data/mock-transaction-info'
+
+// Components
+import {
+ WalletPanelStory //
+} from '../../../../stories/wrappers/wallet-panel-story-wrapper'
+import { TransactionFailedOrCanceled } from './failed_or_canceled'
+
+// Styled Components
+import { LongWrapper } from '../../../../stories/style'
+import { PanelWrapper } from '../../../../panel/style'
+
+export const _TransactionFailedOrCanceled = {
+ render: (args: StorybookTransactionArgs) => {
+ // Props
+ const { transactionType } = args
+
+ // Computed
+ const transaction = getPostConfirmationStatusMockTransaction(
+ transactionType,
+ BraveWallet.TransactionStatus.Error
+ )
+
+ return (
+
+
+
+ alert('Close panel screen clicked.')}
+ />
+
+
+
+ )
+ }
+}
+
+export default {
+ component: TransactionFailedOrCanceled,
+ argTypes: {
+ transactionType: {
+ options: StorybookTransactionOptions,
+ control: { type: 'select' }
+ }
+ }
+}
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/failed_or_canceled/failed_or_canceled.tsx b/components/brave_wallet_ui/components/extension/post-confirmation/failed_or_canceled/failed_or_canceled.tsx
new file mode 100644
index 000000000000..cb7020bb3d0a
--- /dev/null
+++ b/components/brave_wallet_ui/components/extension/post-confirmation/failed_or_canceled/failed_or_canceled.tsx
@@ -0,0 +1,153 @@
+// Copyright (c) 2024 The Brave Authors. All rights reserved.
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at https://mozilla.org/MPL/2.0/.
+import * as React from 'react'
+import LeoButton from '@brave/leo/react/button'
+
+// Hooks
+import {
+ useRetryTransactionMutation //
+} from '../../../../common/slices/api.slice'
+
+// Selectors
+import {
+ useUnsafeUISelector //
+} from '../../../../common/hooks/use-safe-selector'
+import { UISelectors } from '../../../../common/selectors'
+
+// Types
+import {
+ BraveWallet,
+ SerializableTransactionInfo //
+} from '../../../../constants/types'
+
+// Utils
+import { getLocale } from '$web-common/locale'
+import {
+ isBridgeTransaction,
+ isSwapTransaction
+} from '../../../../utils/tx-utils'
+import { getCoinFromTxDataUnion } from '../../../../utils/network-utils'
+
+// Components
+import {
+ PostConfirmationHeader //
+} from '../common/post_confirmation_header'
+import { TransactionIntent } from '../common/transaction_intent'
+
+// Styled Components
+import {
+ // TransactionStatusDescription,
+ Title,
+ Wrapper,
+ ErrorOrSuccessIconWrapper,
+ ErrorOrSuccessIcon
+} from '../common/common.style'
+import { Column, Row, Text } from '../../../shared/style'
+
+interface Props {
+ transaction: SerializableTransactionInfo
+ onClose: () => void
+}
+
+export const TransactionFailedOrCanceled = (props: Props) => {
+ const { transaction, onClose } = props
+
+ // redux
+ const transactionProviderErrorRegistry = useUnsafeUISelector(
+ UISelectors.transactionProviderErrorRegistry
+ )
+
+ // Hooks
+ const [retryTx] = useRetryTransactionMutation()
+
+ // Computed
+ const txCoinType = getCoinFromTxDataUnion(transaction.txDataUnion)
+ const isBridge = isBridgeTransaction(transaction)
+ const isSwap = isSwapTransaction(transaction)
+
+ const providerError = transactionProviderErrorRegistry[transaction.id]
+ const errorCode =
+ providerError?.code.providerError ??
+ providerError?.code.zcashProviderError ??
+ providerError?.code.bitcoinProviderError ??
+ providerError?.code.solanaProviderError ??
+ providerError?.code.filecoinProviderError ??
+ BraveWallet.ProviderError.kUnknown
+
+ const errorDetails = providerError && `${errorCode}: ${providerError.message}`
+
+ // Memos
+ const sendSwapOrBridgeLocale = React.useMemo(() => {
+ if (isBridge) {
+ return 'braveWalletBridge'
+ }
+ if (isSwap) {
+ return 'braveWalletSwap'
+ }
+ return 'braveWalletSend'
+ }, [isBridge, isSwap])
+
+ // Methods
+ const onClickRetryTransaction = () => {
+ retryTx({
+ coinType: txCoinType,
+ chainId: transaction.chainId,
+ transactionId: transaction.id
+ })
+ }
+
+ return (
+
+
+
+
+
+
+
+ {getLocale('braveWalletUnableToSendSwapOrBridge').replace(
+ '$1',
+ getLocale(sendSwapOrBridgeLocale).toLocaleLowerCase()
+ )}
+
+
+
+ {errorDetails}
+
+
+
+
+ {getLocale('braveWalletButtonClose')}
+
+
+ {getLocale('braveWalletButtonRetry')}
+
+
+
+ )
+}
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/index.tsx b/components/brave_wallet_ui/components/extension/post-confirmation/index.tsx
index b8d21d65b185..7cdd8120ea71 100644
--- a/components/brave_wallet_ui/components/extension/post-confirmation/index.tsx
+++ b/components/brave_wallet_ui/components/extension/post-confirmation/index.tsx
@@ -11,38 +11,31 @@ import { useHistory } from 'react-router'
import { BraveWallet, TransactionInfoLookup } from '../../../constants/types'
// Utils
-import { getLocale } from '$web-common/locale'
-import {
- findTransactionToken,
- getFormattedTransactionTransferredValue,
- getTransactionErc721TokenId,
- getTransactionIntent
-} from '../../../utils/tx-utils'
import { getCoinFromTxDataUnion } from '../../../utils/network-utils'
import { makeTransactionDetailsRoute } from '../../../utils/routes-utils'
// Hooks
-import { useTransactionsNetwork } from '../../../common/hooks/use-transactions-network'
-import { usePendingTransactions } from '../../../common/hooks/use-pending-transaction'
import { useGetTransactionQuery } from '../../../common/slices/api.slice'
-import { useUnsafeUISelector } from '../../../common/hooks/use-safe-selector'
-import {
- useAccountQuery,
- useGetCombinedTokensListQuery
-} from '../../../common/slices/api.slice.extra'
-import { useSwapTransactionParser } from '../../../common/hooks/use-swap-tx-parser'
// Actions
import * as WalletPanelActions from '../../../panel/actions/wallet_panel_actions'
// Components
-import { Panel } from '../panel/index'
-import { TransactionSubmittedOrSigned } from './submitted_or_signed'
-import { TransactionComplete } from './complete'
-import { TransactionFailed } from './failed'
+import {
+ TransactionSubmittedOrSigned //
+} from './submitted_or_signed/submitted_or_signed'
+import { TransactionComplete } from './complete/complete'
+import {
+ TransactionFailedOrCanceled //
+} from './failed_or_canceled/failed_or_canceled'
+import {
+ CancelTransaction //
+} from './cancel_transaction/cancel_transaction'
+
+// Styled Components
import { Loader } from './common/common.style'
import { Skeleton } from '../../shared/loading-skeleton/styles'
-import { UISelectors } from '../../../common/selectors'
+import { Column } from '../../shared/style'
interface Props {
transactionLookup: TransactionInfoLookup
@@ -52,72 +45,18 @@ export function TransactionStatus({ transactionLookup }: Props) {
// history
const history = useHistory()
- // redux
- const transactionProviderErrorRegistry = useUnsafeUISelector(
- UISelectors.transactionProviderErrorRegistry
- )
-
// queries
const { data: tx } = useGetTransactionQuery(transactionLookup ?? skipToken)
- const { account: txAccount } = useAccountQuery(tx?.fromAccountId)
- const { data: combinedTokensList } = useGetCombinedTokensListQuery()
+ // State
+ const [showCancelTransaction, setShowCancelTransaction] =
+ React.useState(false)
// hooks
const dispatch = useDispatch()
- const transactionNetwork = useTransactionsNetwork(tx || undefined)
- const { transactionsQueueLength } = usePendingTransactions()
-
- const { buyToken, sellToken, buyAmountWei, sellAmountWei } =
- useSwapTransactionParser(tx ?? undefined)
-
- const transactionIntent = React.useMemo(() => {
- if (!tx) {
- return ''
- }
-
- const token = findTransactionToken(tx, combinedTokensList)
-
- const { normalizedTransferredValue } =
- getFormattedTransactionTransferredValue({
- tx,
- txAccount,
- txNetwork: transactionNetwork,
- token,
- sellToken
- })
-
- const buyAmount = buyToken
- ? buyAmountWei.divideByDecimals(buyToken.decimals)
- : undefined
- const sellAmount = sellToken
- ? sellAmountWei.divideByDecimals(sellToken.decimals)
- : undefined
-
- return getTransactionIntent({
- tx,
- normalizedTransferredValue,
- buyAmount,
- buyToken,
- erc721TokenId: getTransactionErc721TokenId(tx),
- sellAmount,
- sellToken,
- token,
- transactionNetwork
- })
- }, [
- tx,
- combinedTokensList,
- txAccount,
- transactionNetwork,
- buyToken,
- sellToken,
- buyAmountWei,
- sellAmountWei
- ])
// methods
- const viewTransactionDetail = React.useCallback(() => {
+ const onClickViewInActivity = React.useCallback(() => {
if (!tx?.id) {
return
}
@@ -134,25 +73,31 @@ export function TransactionStatus({ transactionLookup }: Props) {
const onClose = () =>
dispatch(WalletPanelActions.setSelectedTransactionId(undefined))
- const completePrimaryCTAText =
- transactionsQueueLength === 0
- ? getLocale('braveWalletButtonClose')
- : getLocale('braveWalletButtonNext')
// render
if (!tx) {
return
}
+ if (showCancelTransaction) {
+ return (
+ setShowCancelTransaction(false)}
+ transaction={tx}
+ />
+ )
+ }
+
if (
tx.txStatus === BraveWallet.TransactionStatus.Submitted ||
tx.txStatus === BraveWallet.TransactionStatus.Signed
) {
return (
setShowCancelTransaction(true)}
+ onClickViewInActivity={onClickViewInActivity}
/>
)
}
@@ -160,57 +105,28 @@ export function TransactionStatus({ transactionLookup }: Props) {
if (tx.txStatus === BraveWallet.TransactionStatus.Confirmed) {
return (
)
}
if (tx.txStatus === BraveWallet.TransactionStatus.Error) {
- const providerError = transactionProviderErrorRegistry[tx.id]
- const errorCode =
- providerError?.code.providerError ??
- providerError?.code.zcashProviderError ??
- providerError?.code.bitcoinProviderError ??
- providerError?.code.solanaProviderError ??
- providerError?.code.filecoinProviderError ??
- BraveWallet.ProviderError.kUnknown
-
- const errorDetailContent =
- providerError && `${errorCode}: ${providerError.message}`
- const customDescription =
- errorCode ===
- BraveWallet.ZCashProviderError.kMultipleTransactionsNotSupported
- ? providerError.message
- : undefined
-
return (
-
)
}
return (
-
-
+
)
}
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/submitted_or_signed/index.tsx b/components/brave_wallet_ui/components/extension/post-confirmation/submitted_or_signed/index.tsx
deleted file mode 100644
index 217a1361317d..000000000000
--- a/components/brave_wallet_ui/components/extension/post-confirmation/submitted_or_signed/index.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright (c) 2022 The Brave Authors. All rights reserved.
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this file,
-// you can obtain one at https://mozilla.org/MPL/2.0/.
-import { TransactionSubmittedOrSigned } from './submitted_or_signed'
-
-export { TransactionSubmittedOrSigned }
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/submitted_or_signed/submitted_or_signed.stories.tsx b/components/brave_wallet_ui/components/extension/post-confirmation/submitted_or_signed/submitted_or_signed.stories.tsx
index 4cddf361459d..3b4826a6a4db 100644
--- a/components/brave_wallet_ui/components/extension/post-confirmation/submitted_or_signed/submitted_or_signed.stories.tsx
+++ b/components/brave_wallet_ui/components/extension/post-confirmation/submitted_or_signed/submitted_or_signed.stories.tsx
@@ -2,36 +2,69 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at https://mozilla.org/MPL/2.0/.
-
import * as React from 'react'
+// Types
+import {
+ BraveWallet,
+ StorybookTransactionArgs,
+ StorybookTransactionOptions
+} from '../../../../constants/types'
+
// Mocks
-import { mockTransactionInfo } from '../../../../stories/mock-data/mock-transaction-info'
+import {
+ getPostConfirmationStatusMockTransaction //
+} from '../../../../stories/mock-data/mock-transaction-info'
// Components
-import WalletPanelStory from '../../../../stories/wrappers/wallet-panel-story-wrapper'
-import { StyledExtensionWrapper } from '../../../../stories/style'
-import { PanelWrapper } from '../../../../panel/style'
+import {
+ WalletPanelStory //
+} from '../../../../stories/wrappers/wallet-panel-story-wrapper'
import { TransactionSubmittedOrSigned } from './submitted_or_signed'
+// Styled Components
+import { LongWrapper } from '../../../../stories/style'
+import { PanelWrapper } from '../../../../panel/style'
+
export const _TransactionSubmittedOrSigned = {
- render: () => {
- const onClose = () => alert('Close panel screen')
+ render: (args: StorybookTransactionArgs) => {
+ // Props
+ const { transactionType } = args
+
+ // Computed
+ const transaction = getPostConfirmationStatusMockTransaction(
+ transactionType,
+ BraveWallet.TransactionStatus.Submitted
+ )
return (
-
-
+
+ alert('Close panel screen clicked.')}
+ onShowCancelTransaction={() =>
+ alert('Show cancel transaction clicked.')
+ }
+ transaction={transaction}
+ onClickViewInActivity={() => alert('View in activity clicked.')}
/>
-
+
)
}
}
-export default { component: TransactionSubmittedOrSigned }
+export default {
+ component: TransactionSubmittedOrSigned,
+ argTypes: {
+ transactionType: {
+ options: StorybookTransactionOptions,
+ control: { type: 'select' }
+ }
+ }
+}
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/submitted_or_signed/submitted_or_signed.style.ts b/components/brave_wallet_ui/components/extension/post-confirmation/submitted_or_signed/submitted_or_signed.style.ts
deleted file mode 100644
index 6c1f709ada52..000000000000
--- a/components/brave_wallet_ui/components/extension/post-confirmation/submitted_or_signed/submitted_or_signed.style.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2022 The Brave Authors. All rights reserved.
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this file,
-// You can obtain one at https://mozilla.org/MPL/2.0/.
-
-import styled from 'styled-components'
-
-import SubmittedOrSignedSvg from '../../../../assets/svg-icons/submitted-circle-icon.svg'
-import { WalletButton } from '../../../shared/style'
-import {
- TransactionStatusIcon,
- TransactionStatusText
-} from '../common/common.style'
-
-export const SubmittedOrSignedIcon = styled(TransactionStatusIcon)`
- background: url(${SubmittedOrSignedSvg});
- background-size: contain;
-`
-
-export const Title = styled(TransactionStatusText)`
- color: ${(p) => p.theme.color.text01};
-`
-
-export const DetailButton = styled(WalletButton)`
- font-family: 'Poppins';
- font-style: normal;
- font-weight: 600;
- font-size: 12px;
- line-height: 20px;
- text-align: center;
- color: ${(p) => p.theme.color.interactive05};
- background: none;
- cursor: pointer;
- outline: none;
- border: none;
- margin: 0;
- padding: 0;
-`
diff --git a/components/brave_wallet_ui/components/extension/post-confirmation/submitted_or_signed/submitted_or_signed.tsx b/components/brave_wallet_ui/components/extension/post-confirmation/submitted_or_signed/submitted_or_signed.tsx
index 2da85b62e2a8..26ca9516c948 100644
--- a/components/brave_wallet_ui/components/extension/post-confirmation/submitted_or_signed/submitted_or_signed.tsx
+++ b/components/brave_wallet_ui/components/extension/post-confirmation/submitted_or_signed/submitted_or_signed.tsx
@@ -3,6 +3,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at https://mozilla.org/MPL/2.0/.
import * as React from 'react'
+import LeoButton from '@brave/leo/react/button'
// Constants
import {
@@ -10,65 +11,124 @@ import {
SerializableTransactionInfo
} from '../../../../constants/types'
-// Hooks
-import { useExplorer } from '../../../../common/hooks/explorer'
-import { useTransactionsNetwork } from '../../../../common/hooks/use-transactions-network'
-
// Utils
import { getLocale } from '$web-common/locale'
+// Components
+import {
+ PostConfirmationHeader //
+} from '../common/post_confirmation_header'
+import { SpeedUpAlert } from '../common/speed_up_alert'
+import { TransactionIntent } from '../common/transaction_intent'
+
// Styled components
-import { Panel } from '../../panel/index'
-import { SubmittedOrSignedIcon, Title } from './submitted_or_signed.style'
+import { LoadingRing, StatusIcon, Wrapper, Title } from '../common/common.style'
+import { Column, Row, Text, VerticalSpace } from '../../../shared/style'
import {
- ButtonRow,
- DetailButton,
- LinkIcon,
- TransactionStatusDescription
-} from '../common/common.style'
+ isBridgeTransaction,
+ isSwapTransaction
+} from '../../../../utils/tx-utils'
interface Props {
- headerTitle: string
transaction: SerializableTransactionInfo
onClose: () => void
+ onShowCancelTransaction: () => void
+ onClickViewInActivity: () => void
}
export const TransactionSubmittedOrSigned = (props: Props) => {
- const { headerTitle, transaction, onClose } = props
+ const {
+ transaction,
+ onClose,
+ onShowCancelTransaction,
+ onClickViewInActivity
+ } = props
- // custom hooks
- const transactionNetwork = useTransactionsNetwork(transaction)
- const onClickViewOnBlockExplorer = useExplorer(transactionNetwork)
+ // State
+ const [showSpeedUpAlert, setShowSpeedupAlert] = React.useState(false)
- const title =
- transaction.txStatus === BraveWallet.TransactionStatus.Submitted
- ? getLocale('braveWalletTransactionSubmittedTitle')
- : getLocale('braveWalletTransactionSignedTitle')
- const description =
- transaction.txStatus === BraveWallet.TransactionStatus.Submitted
- ? getLocale('braveWalletTransactionSubmittedDescription')
- : getLocale('braveWalletTransactionSignedDescription')
+ // Computed
+ const isBridge = isBridgeTransaction(transaction)
+ const isSwap = isSwapTransaction(transaction)
+ const isERC20Approval =
+ transaction.txType === BraveWallet.TransactionType.ERC20Approve
+
+ // Memos
+ const statusIconName = React.useMemo(() => {
+ if (isERC20Approval) {
+ return 'lock-open'
+ }
+ if (isBridge) {
+ return 'web3-bridge'
+ }
+ if (isSwap) {
+ return 'swap-horizontal'
+ }
+ return 'send-filled'
+ }, [isERC20Approval, isBridge, isSwap])
+
+ React.useEffect(() => {
+ const timeId = setTimeout(() => {
+ setShowSpeedupAlert(true)
+ }, 5000)
+ return () => {
+ clearTimeout(timeId)
+ }
+ }, [])
return (
-
-
- {title}
- {description}
-
-
+
+
+ {showSpeedUpAlert ? (
+
+ ) : (
+
)}
+
+
+
+
+ {transaction.txStatus === BraveWallet.TransactionStatus.Submitted
+ ? getLocale('braveWalletTransactionSubmittedTitle')
+ : getLocale('braveWalletTransactionSignedTitle')}
+
+
+
+
+
+
- {getLocale('braveWalletTransactionExplorer')}
-
-
-
-
+ {getLocale('braveWalletSafelyDismissWindow')}
+
+
+
+ {getLocale('braveWalletTransactionCancel')}
+
+
+ {getLocale('braveWalletViewInActivity')}
+
+
+
+
)
}
diff --git a/components/brave_wallet_ui/constants/types.ts b/components/brave_wallet_ui/constants/types.ts
index a3b4074ac517..0b99578659fa 100644
--- a/components/brave_wallet_ui/constants/types.ts
+++ b/components/brave_wallet_ui/constants/types.ts
@@ -1080,3 +1080,14 @@ export const SupportedSwapProviders = [
BraveWallet.SwapProvider.kZeroEx,
BraveWallet.SwapProvider.kLiFi
]
+
+export type StorybookTransactionTypes = 'Send' | 'Swap' | 'Bridge' | 'Approve'
+export const StorybookTransactionOptions: StorybookTransactionTypes[] = [
+ 'Send',
+ 'Swap',
+ 'Bridge',
+ 'Approve'
+]
+export type StorybookTransactionArgs = {
+ transactionType: StorybookTransactionTypes
+}
diff --git a/components/brave_wallet_ui/panel/container.tsx b/components/brave_wallet_ui/panel/container.tsx
index 90d5039de5d1..81dcb84c05c2 100644
--- a/components/brave_wallet_ui/panel/container.tsx
+++ b/components/brave_wallet_ui/panel/container.tsx
@@ -288,10 +288,13 @@ function Container() {
if (selectedPanel === 'transactionStatus' && selectedTransactionId) {
return (
-
-
+
+
-
+
)
}
diff --git a/components/brave_wallet_ui/stories/locale.ts b/components/brave_wallet_ui/stories/locale.ts
index bf9eed9484e7..1418d9bc3e81 100644
--- a/components/brave_wallet_ui/stories/locale.ts
+++ b/components/brave_wallet_ui/stories/locale.ts
@@ -1186,12 +1186,26 @@ provideStrings({
braveWalletAccountFilterAllAccounts: 'All accounts',
// Transaction post-confirmation
-
+ braveWalletGetHelp: 'Get help',
+ braveWalletTransactionTakingLongTime: 'Taking longer than expected?',
+ braveWalletViewInActivity: 'View in activity',
+ braveWalletSafelyDismissWindow: 'You can safely dismiss this window.',
+ braveWalletSendingAmountToAccount: 'Sending $1$5$2 to $3$6$4',
+ braveWalletAmountSentToAccount: '$1$5$2 has been sent to account $3$6$4',
+ braveWalletSwappingAmountToAmountOnNetwork: 'Swapping $1$5$2 to $3$6$4 on $7',
+ braveWalletAmountAddedToAccount:
+ 'The amount of $1$5$2 has been added to your account $3$6$4',
+ braveWalletBridgingAmountToNetwork: 'Bridging $1$5$2 to $3$6$4',
+ braveWalletUnableToSendSwapOrBridge: 'Unable to $1',
+ braveWalletErrorAttemptingToTransact:
+ 'There was an error attempting to $7 $1$5$2 to $3$6$4',
+ braveWalletApprovingAmountOnExchange: 'Approving $1$5$2 to $3$6$4',
+ braveWalletCancelTransactionDescription:
+ 'A new transaction will be created to cancel your existing transaction.',
+ braveWalletPendingTransactions: '$1 more transactions pending.',
// Submitted
braveWalletTransactionSubmittedTitle: 'Transaction submitted',
- braveWalletTransactionSubmittedDescription:
- 'Transaction has been successfully sent ' +
- 'to the network and awaits confirmation.',
+ braveWalletTransactionSignedTitle: 'Transaction signed',
// Failed
braveWalletTransactionFailedHeaderTitle: '$1 was returned to your wallet',
diff --git a/components/brave_wallet_ui/stories/mock-data/mock-transaction-info.ts b/components/brave_wallet_ui/stories/mock-data/mock-transaction-info.ts
index 163abe5d916b..efab049bceb9 100644
--- a/components/brave_wallet_ui/stories/mock-data/mock-transaction-info.ts
+++ b/components/brave_wallet_ui/stories/mock-data/mock-transaction-info.ts
@@ -4,7 +4,11 @@
// you can obtain one at https://mozilla.org/MPL/2.0/.
// Types
-import { BraveWallet, SerializableTransactionInfo } from '../../constants/types'
+import {
+ BraveWallet,
+ SerializableTransactionInfo,
+ StorybookTransactionTypes
+} from '../../constants/types'
import { deserializeTransaction } from '../../utils/model-serialization-utils'
import { FileCoinTransactionInfo } from '../../utils/tx-utils'
@@ -19,11 +23,13 @@ import {
} from '../../common/constants/mocks'
import { mockOriginInfo } from './mock-origin-info'
import { mockEthAccount } from './mock-wallet-accounts'
+import { mockBasicAttentionToken, mockUSDCoin } from './mock-asset-options'
+import { LiFiExchangeProxy } from '../../common/constants/registry'
export const mockTransactionInfo: SerializableTransactionInfo = {
fromAccountId: mockAccount.accountId,
fromAddress: mockAccount.address,
- chainId: BraveWallet.SEPOLIA_CHAIN_ID,
+ chainId: BraveWallet.MAINNET_CHAIN_ID,
id: '465a4d6646-kjlwf665',
txArgs: ['0x0d8775f648430679a709e98d2b0cb6250d2887ef', '0x15ddf09c97b0000'],
txDataUnion: {
@@ -469,3 +475,63 @@ export const createMockTransactionInfo = (arg: {
swapInfo
}
}
+
+const getMockTransactionType = (
+ isSwapOrBridge: boolean,
+ transactionType: StorybookTransactionTypes
+) => {
+ if (isSwapOrBridge) {
+ return BraveWallet.TransactionType.ETHSwap
+ }
+ if (transactionType === 'Approve') {
+ return BraveWallet.TransactionType.ERC20Approve
+ }
+ return BraveWallet.TransactionType.ETHSend
+}
+
+export const getPostConfirmationStatusMockTransaction = (
+ transactionType: StorybookTransactionTypes,
+ transactionStatus: BraveWallet.TransactionStatus
+) => {
+ const isSwapOrBridge =
+ transactionType === 'Swap' || transactionType === 'Bridge'
+
+ return {
+ ...mockTransactionInfo,
+ txArgs: [
+ BraveWallet.TransactionType.ERC20Approve
+ ? LiFiExchangeProxy
+ : '0x0d8775f648430679a709e98d2b0cb6250d2887ef',
+ '0x15ddf09c97b0000'
+ ],
+ txDataUnion: {
+ ...mockTransactionInfo.txDataUnion,
+ ethTxData1559: {
+ ...mockTransactionInfo.txDataUnion.ethTxData1559,
+ baseData: {
+ ...mockTransactionInfo.txDataUnion.ethTxData1559?.baseData,
+ to: mockBasicAttentionToken.contractAddress
+ }
+ }
+ },
+ txStatus: transactionStatus,
+ txType: getMockTransactionType(isSwapOrBridge, transactionType),
+ swapInfo: isSwapOrBridge
+ ? ({
+ fromCoin: BraveWallet.CoinType.ETH,
+ fromChainId: BraveWallet.MAINNET_CHAIN_ID,
+ fromAsset: mockBasicAttentionToken.contractAddress,
+ fromAmount: '9996544123665456564888',
+ toCoin: BraveWallet.CoinType.ETH,
+ toChainId:
+ transactionType === 'Bridge'
+ ? BraveWallet.SEPOLIA_CHAIN_ID
+ : BraveWallet.MAINNET_CHAIN_ID,
+ toAsset: mockUSDCoin.contractAddress,
+ toAmount: '111111111111111',
+ receiver: '0x0d8775f648430679a709e98d2b0cb6250d2887ef',
+ provider: 'lifi'
+ } as BraveWallet.SwapInfo)
+ : undefined
+ } as SerializableTransactionInfo
+}
diff --git a/components/resources/wallet_strings.grdp b/components/resources/wallet_strings.grdp
index ca795c3636b4..9ddcda5fbf95 100644
--- a/components/resources/wallet_strings.grdp
+++ b/components/resources/wallet_strings.grdp
@@ -665,10 +665,27 @@
Show spam NFTsPortfolio settingsAll accounts
+ Get help
+ Taking longer than expected?
+ View in activity
+ You can safely dismiss this window.
+ Sending $120 ETH$5$2 to $3Ethereum Account 2$6$4
+ $120 ETH$5$2 has been sent to account $3Ethereum Account 2$6$4
+ Swapping $120 ETH$5$2 to $3Ethereum Account 2$6$4 on Ethereum Mainnet$7
+ The amount of $120 ETH$5$2 has been added to your account $3Ethereum Account 2$6$4
+ Bridging $120 ETH$5$2 to $3Polygon Mainnet$6$4
+ Unable to Bridge$1
+ There was an error attempting to Bridge$7$120 ETH$5$2 to $3Polygon Mainnet$6$4
+ Approving $120 ETH$5$2 to $3Li.Fi Excahnge$6$4
+ A new transaction will be created to cancel your existing transaction.
+
+ {PENDING_TRANSACTIONS, plural,
+ =1 {{PENDING_TRANSACTIONS} more transaction pending.}
+ other {{PENDING_TRANSACTIONS} more transactions pending.}
+ }
+ Transaction submitted
- Transaction has been successfully sent to the network and awaits confirmation.Transaction signed
- The transaction has been signed and will be sent to network by the DApp$11 ETH was returned to your walletTransaction failedTransaction was failed due to a large price movement. Increase slippage tolerance to succeed at a larger price movement.
diff --git a/ui/webui/resources/BUILD.gn b/ui/webui/resources/BUILD.gn
index b98c9cc1ac8f..b375d8ec6d14 100644
--- a/ui/webui/resources/BUILD.gn
+++ b/ui/webui/resources/BUILD.gn
@@ -346,6 +346,7 @@ leo_icons = [
"search-zoom-in.svg",
"search.svg",
"send.svg",
+ "send-filled.svg",
"settings.svg",
"share-macos.svg",
"shield-done.svg",
@@ -424,6 +425,7 @@ leo_icons = [
"sol-color.svg",
"filecoin-color.svg",
"slash.svg",
+ "xmark-color.svg",
"yahoo-color.svg",
"yandex-color.svg",
]