Skip to content

Commit

Permalink
feat(wallet): Backed Up Transactions Warning
Browse files Browse the repository at this point in the history
  • Loading branch information
Douglashdaniel committed Feb 28, 2022
1 parent d03c7da commit a2f49f2
Show file tree
Hide file tree
Showing 11 changed files with 301 additions and 22 deletions.
10 changes: 10 additions & 0 deletions components/brave_wallet/browser/brave_wallet_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,16 @@ constexpr webui::LocalizedString kLocalizedStrings[] = {
{"braveWalletConfirmTransactionFrist",
IDS_BRAVE_WALLET_CONFIRM_TRANSACTION_FRIST},
{"braveWalletConfirmTransactions", IDS_BRAVE_WALLET_CONFIRM_TRANSACTIONS},
{"braveWalletBackedUpTransactionsTitle",
IDS_BRAVE_WALLET_BACKED_UP_TRANSACTIONS_TITLE},
{"braveWalletBackedUpTransactionsDescription",
IDS_BRAVE_WALLET_BACKED_UP_TRANSACTIONS_DESCRIPTION},
{"braveWalletBackedUpTransactionsCheckbox",
IDS_BRAVE_WALLET_BACKED_UP_TRANSACTIONS_CHECKBOX},
{"braveWalletBackedUpTransactionsClearButton",
IDS_BRAVE_WALLET_BACKED_UP_TRANSACTIONS_CLEAR_BUTTON},
{"braveWalletBackedUpTransactionsClearingButton",
IDS_BRAVE_WALLET_BACKED_UP_TRANSACTIONS_CLEARING_BUTTON},
{"braveWalletPanelTitle", IDS_BRAVE_WALLET_PANEL_TITLE},
{"braveWalletPanelConnected", IDS_BRAVE_WALLET_PANEL_CONNECTED},
{"braveWalletSitePermissionsAccounts",
Expand Down
1 change: 1 addition & 0 deletions components/brave_wallet_ui/common/async/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,7 @@ handler.on(WalletActions.addSitePermission.getType(), async (store: Store, paylo

handler.on(WalletActions.transactionStatusChanged.getType(), async (store: Store, payload: TransactionStatusChanged) => {
const status = payload.txInfo.txStatus
await store.dispatch(refreshTransactionHistory(payload.txInfo.fromAddress))
if (status === BraveWallet.TransactionStatus.Confirmed || status === BraveWallet.TransactionStatus.Error) {
await refreshBalancesPricesAndHistory(store)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { create } from 'ethereum-blockies'
import {
BraveWallet,
WalletAccountType,
DefaultCurrencies
DefaultCurrencies,
AccountTransactions
} from '../../../constants/types'
import {
UpdateUnapprovedTransactionGasFieldsType,
Expand All @@ -16,15 +17,23 @@ import {
import { reduceAddress } from '../../../utils/reduce-address'
import { reduceNetworkDisplayName } from '../../../utils/network-utils'
import { reduceAccountDisplayName } from '../../../utils/reduce-account-name'
import { sortTransactionByDate } from '../../../utils/tx-utils'
import { mojoTimeDeltaToJSDate, calculatedTimeDiffInMilliseconds } from '../../../utils/datetime-utils'
import Amount from '../../../utils/amount'

// Hooks
import { usePricing, useTransactionParser, useTokenInfo } from '../../../common/hooks'

import { getLocale } from '../../../../common/locale'
import { withPlaceholderIcon } from '../../shared'

import { NavButton, PanelTab, TransactionDetailBox } from '../'
// Components
import { withPlaceholderIcon } from '../../shared'
import {
NavButton,
PanelTab,
TransactionDetailBox,
TransactionsBackedUpWarning
} from '../'
import EditGas, { MaxPriorityPanels } from '../edit-gas'
import EditAllowance from '../edit-allowance'

Expand Down Expand Up @@ -94,6 +103,8 @@ export interface Props {
transactionsQueueLength: number
transactionQueueNumber: number
defaultCurrencies: DefaultCurrencies
transactions: AccountTransactions
selectedAccount: WalletAccountType
onQueueNextTransaction: () => void
onConfirm: () => void
onReject: () => void
Expand All @@ -118,6 +129,8 @@ function ConfirmTransactionPanel (props: Props) {
transactionQueueNumber,
fullTokenList,
defaultCurrencies,
transactions,
selectedAccount,
onQueueNextTransaction,
onConfirm,
onReject,
Expand All @@ -144,11 +157,39 @@ function ConfirmTransactionPanel (props: Props) {
const [currentTokenAllowance, setCurrentTokenAllowance] = React.useState<string>('')
const [isEditingAllowance, setIsEditingAllowance] = React.useState<boolean>(false)
const [showAdvancedTransactionSettings, setShowAdvancedTransactionSettings] = React.useState<boolean>(false)
const [showTransactionsBackedUpWarning, setShowTransactionsBackedUpWarning] = React.useState<boolean>(false)

const { findAssetPrice } = usePricing(transactionSpotPrices)
const parseTransaction = useTransactionParser(selectedNetwork, accounts, transactionSpotPrices, visibleTokens, fullTokenList)
const transactionDetails = parseTransaction(transactionInfo)

const unconfirmedSubmittedTransactions = React.useMemo(() => {
// Gets a the list of transcations for the selected account
const transactionsList =
selectedAccount?.address && transactions[selectedAccount.address]
? sortTransactionByDate(transactions[selectedAccount.address], 'descending')
: []

// Gets a list of all transactions with the status of Submitted
const submittedTransactions = transactionsList.filter((transaction) => transaction.txStatus === BraveWallet.TransactionStatus.Submitted)

// Returns a list of all unconfirmed submited transactions that are over 24 hours old
return submittedTransactions.filter((transaction) =>
Math.floor(
calculatedTimeDiffInMilliseconds(
mojoTimeDeltaToJSDate(transaction.submittedTime)
) / (1000 * 60 * 60)) > 24)
}, [selectedAccount, transactions])

React.useEffect(() => {
if (
unconfirmedSubmittedTransactions.length !== 0 &&
transactionInfo.txDataUnion.ethTxData1559?.baseData.nonce === ''
) {
setShowTransactionsBackedUpWarning(true)
}
}, [unconfirmedSubmittedTransactions])

const {
onFindTokenInfoByContractAddress,
foundTokenInfoByContractAddress
Expand Down Expand Up @@ -261,6 +302,27 @@ function ConfirmTransactionPanel (props: Props) {
)
}, [transactionDetails])

const onContinueTransaction = (clearTransactions: boolean) => {
if (clearTransactions) {
// Finds the nonce of the oldest unconfirmed transaction and
// sets the nonce for the new unapproved transaction.
const newNonce =
unconfirmedSubmittedTransactions[unconfirmedSubmittedTransactions.length - 1]
.txDataUnion.ethTxData1559?.baseData.nonce ?? ''

updateUnapprovedTransactionNonce({ txMetaId: transactionInfo.id, nonce: newNonce })
}
setShowTransactionsBackedUpWarning(false)
}

if (showTransactionsBackedUpWarning) {
return (
<TransactionsBackedUpWarning
onContinue={onContinueTransaction}
/>
)
}

if (isEditing) {
return (
<EditGas
Expand Down Expand Up @@ -337,7 +399,7 @@ function ConfirmTransactionPanel (props: Props) {
{transactionDetails.isApprovalUnlimited &&
<WarningBox>
<WarningTitleRow>
<WarningIcon/>
<WarningIcon />
<WarningTitle>
{getLocale('braveWalletAllowSpendUnlimitedWarningTitle')}
</WarningTitle>
Expand Down Expand Up @@ -394,7 +456,7 @@ function ConfirmTransactionPanel (props: Props) {
/>

<AdvancedTransactionSettingsButton
onSubmit={ onToggleAdvancedTransactionSettings }
onSubmit={onToggleAdvancedTransactionSettings}
/>
</TabRow>
<MessageBox isDetails={selectedTab === 'details'} isApprove={transactionInfo.txType === BraveWallet.TransactionType.ERC20Approve}>
Expand Down Expand Up @@ -439,7 +501,7 @@ function ConfirmTransactionPanel (props: Props) {
transactionDetails.isApprovalUnlimited
? getLocale('braveWalletTransactionApproveUnlimited')
: new Amount(transactionDetails.valueExact)
.formatAsAsset(undefined, transactionDetails.symbol)
.formatAsAsset(undefined, transactionDetails.symbol)
}
</TransactionTypeText>
<TransactionText />
Expand Down
4 changes: 3 additions & 1 deletion components/brave_wallet_ui/components/extension/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import TransactionsListItem from './transaction-list-item'
import TransactionDetailPanel from './transaction-detail-panel'
import AssetsPanel from './assets-panel'
import EncryptionKeyPanel from './encryption-key-panel'
import TransactionsBackedUpWarning from './transactions-backed-up-warning'
import { NavButton } from './buttons'

export {
Expand Down Expand Up @@ -53,5 +54,6 @@ export {
TransactionsListItem,
TransactionDetailPanel,
AssetsPanel,
EncryptionKeyPanel
EncryptionKeyPanel,
TransactionsBackedUpWarning
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import * as React from 'react'

// Components
import { NavButton } from '../'
import { Checkbox } from 'brave-ui'
import { getLocale } from '../../../../common/locale'

// Styled Components
import {
StyledWrapper,
Title,
Description,
LearnMoreButton,
CheckboxRow,
ClearButton,
ClearButtonText,
LoadIcon,
CheckboxText
} from './style'

export interface Props {
onContinue: (clearTransactions: boolean) => void
}

function TransactionsBackedUpWarning (props: Props) {
const { onContinue } = props
const [clearTransactions, setClearTransactions] = React.useState<boolean>(false)
const [isClearing, setIsClearing] = React.useState<boolean>(false)

const onCheckClearTransactions = (key: string, selected: boolean) => {
if (key === 'clearTransactions') {
setClearTransactions(selected)
}
}

const onClickContinue = () => {
if (clearTransactions) {
setIsClearing(true)
}
onContinue(clearTransactions)
}

const onClickLearnMore = () => {
chrome.tabs.create({ url: 'https://support.brave.com/hc/en-us/articles/4537540021389' }, () => {
if (chrome.runtime.lastError) {
console.error('tabs.create failed: ' + chrome.runtime.lastError.message)
}
})
}

return (
<StyledWrapper>
<Title>{getLocale('braveWalletBackedUpTransactionsTitle')}</Title>
<Description>{getLocale('braveWalletBackedUpTransactionsDescription')}</Description>
<LearnMoreButton onClick={onClickLearnMore}>{getLocale('braveWalletWelcomePanelButton')}</LearnMoreButton>
<CheckboxRow>
<Checkbox
children={<CheckboxText data-key='clearTransactions'>{getLocale('braveWalletBackedUpTransactionsCheckbox')}</CheckboxText>}
size='small'
value={{ clearTransactions: clearTransactions }}
onChange={onCheckClearTransactions}
/>
</CheckboxRow>
{
isClearing ? (
<ClearButton>
<ClearButtonText>
{getLocale('braveWalletBackedUpTransactionsClearingButton')}
</ClearButtonText>
<LoadIcon />
</ClearButton>
) : (
<NavButton
disabled={isClearing}
buttonType={
clearTransactions
? 'danger'
: 'primary'
}
text={
clearTransactions
? getLocale('braveWalletBackedUpTransactionsClearButton')
: getLocale('braveWalletButtonContinue')
}
onSubmit={onClickContinue}
/>
)
}
</StyledWrapper >
)
}

export default TransactionsBackedUpWarning
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import styled from 'styled-components'
import { LoaderIcon } from 'brave-ui/components/icons'
import { WalletButton } from '../../shared/style'

export const StyledWrapper = styled.div`
display: flex;
width: 100%;
height: 100%;
flex-direction: column;
align-items: center;
justify-content: center;
`

export const Title = styled.span`
font-family: Poppins;
font-size: 15px;
line-height: 20px;
letter-spacing: 0.01em;
font-weight: 600;
color: ${(p) => p.theme.color.text01};
margin-bottom: 10px;
`

export const Description = styled.span`
font-family: Poppins;
font-size: 14px;
line-height: 18px;
letter-spacing: 0.01em;
color: ${(p) => p.theme.color.text02};
width: 80%;
text-align: center;
margin-bottom: 6px;
`

export const LearnMoreButton = styled(WalletButton)`
cursor: pointer;
outline: none;
background: none;
border: none;
font-family: Poppins;
font-size: 14px;
line-height: 18px;
letter-spacing: 0.01em;
color: ${(p) => p.theme.color.interactive05};
margin: 0px;
padding: 0px;
`

export const CheckboxRow = styled.div`
display: flex;
align-items: center;
justify-content: center;
flex-direction: row;
margin: 20px 0px;
width: 70%;
`

export const CheckboxText = styled.span`
font-size: 8px;
line-height: 20px;
color: ${(p) => p.theme.color.text02};
`

export const ClearButton = styled(WalletButton)`
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 7px 22px;
border: none;
box-sizing: border-box;
border-radius: 40px;
background-color: ${(p) => p.theme.color.errorBorder};
opacity: .4;
`

export const ClearButtonText = styled.span`
font-weight: 600;
font-size: 13px;
line-height: 20px;
color: ${(p) => p.theme.palette.white};
margin-right: 4px;
`

export const LoadIcon = styled(LoaderIcon)`
color: ${p => p.theme.palette.white};
height: 25px;
width: 25px;
`
2 changes: 2 additions & 0 deletions components/brave_wallet_ui/panel/container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,8 @@ function Container (props: Props) {
updateUnapprovedTransactionNonce={props.walletActions.updateUnapprovedTransactionNonce}
gasEstimates={gasEstimates}
fullTokenList={props.wallet.fullTokenList}
transactions={transactions}
selectedAccount={selectedAccount}
/>
</LongWrapper>
</PanelWrapper>
Expand Down
7 changes: 7 additions & 0 deletions components/brave_wallet_ui/stories/locale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,13 @@ provideStrings({
braveWalletConfirmTransactionFrist: 'first',
braveWalletConfirmTransactions: 'transactions',

// Backed up Transactions Warning
braveWalletBackedUpTransactionsTitle: 'Transaction backlog',
braveWalletBackedUpTransactionsDescription: 'Youre attempting to start a new transaction while you have previously submitted transactions that have not been confirmed. This will block any new ones from being submitted.',
braveWalletBackedUpTransactionsCheckbox: 'Clear & replace the incomplete transaction(s)',
braveWalletBackedUpTransactionsClearButton: 'Clear and continue',
braveWalletBackedUpTransactionsClearingButton: 'Clearing transactions',

// Wallet Main Panel
braveWalletPanelTitle: 'Brave Wallet',
braveWalletPanelConnected: 'Connected',
Expand Down
Loading

0 comments on commit a2f49f2

Please sign in to comment.