1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Refactor confirm approve page (#8757)

The `confirm-approve` page has been converted from a set of container/
component components to a functional component. The `withTokenTracker`
higher-order component has been deleted, as it was replaced by the
`useTokenTracker` hook.
This commit is contained in:
Mark Stacey 2020-06-09 17:10:07 -03:00 committed by GitHub
parent 2873053d45
commit 4706401f4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 142 additions and 331 deletions

View File

@ -1 +0,0 @@
export { default } from './with-token-tracker.component'

View File

@ -1,101 +0,0 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import TokenTracker from '@metamask/eth-token-tracker'
export default function withTokenTracker (WrappedComponent) {
return class TokenTrackerWrappedComponent extends Component {
static propTypes = {
userAddress: PropTypes.string.isRequired,
token: PropTypes.object.isRequired,
}
state = {
string: '',
symbol: '',
balance: '',
error: null,
}
tracker = null
componentDidMount () {
this.createFreshTokenTracker()
}
componentDidUpdate (prevProps) {
const { userAddress: newAddress, token: { address: newTokenAddress } } = this.props
const { userAddress: oldAddress, token: { address: oldTokenAddress } } = prevProps
if ((oldAddress === newAddress) && (oldTokenAddress === newTokenAddress)) {
return
}
if ((!oldAddress || !newAddress) && (!oldTokenAddress || !newTokenAddress)) {
return
}
this.createFreshTokenTracker()
}
componentWillUnmount () {
this.removeListeners()
}
createFreshTokenTracker () {
this.removeListeners()
if (!global.ethereumProvider) {
return
}
const { userAddress, token } = this.props
this.tracker = new TokenTracker({
userAddress,
provider: global.ethereumProvider,
tokens: [token],
pollingInterval: 8000,
})
this.tracker.on('update', this.updateBalance)
this.tracker.on('error', this.setError)
this.tracker.updateBalances()
.then(() => this.updateBalance(this.tracker.serialize()))
.catch((error) => this.setState({ error: error.message }))
}
setError = (error) => {
this.setState({ error })
}
updateBalance = (tokens = []) => {
if (!this.tracker.running) {
return
}
const [{ string, symbol, balance }] = tokens
this.setState({ string, symbol, error: null, balance })
}
removeListeners () {
if (this.tracker) {
this.tracker.stop()
this.tracker.removeListener('update', this.updateBalance)
this.tracker.removeListener('error', this.setError)
}
}
render () {
const { balance, string, symbol, error } = this.state
return (
<WrappedComponent
{ ...this.props }
string={string}
symbol={symbol}
tokenTrackerBalance={balance}
error={error}
/>
)
}
}
}

View File

@ -1,115 +0,0 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import ConfirmTransactionBase from '../confirm-transaction-base'
import ConfirmApproveContent from './confirm-approve-content'
import { getCustomTxParamsData } from './confirm-approve.util'
import {
calcTokenAmount,
} from '../../helpers/utils/token-util'
export default class ConfirmApprove extends Component {
static contextTypes = {
t: PropTypes.func,
}
static propTypes = {
tokenAddress: PropTypes.string,
toAddress: PropTypes.string,
tokenAmount: PropTypes.string,
tokenSymbol: PropTypes.string,
fiatTransactionTotal: PropTypes.string,
ethTransactionTotal: PropTypes.string,
contractExchangeRate: PropTypes.number,
conversionRate: PropTypes.number,
currentCurrency: PropTypes.string,
showCustomizeGasModal: PropTypes.func,
showEditApprovalPermissionModal: PropTypes.func,
origin: PropTypes.string,
siteImage: PropTypes.string,
tokenTrackerBalance: PropTypes.string,
data: PropTypes.string,
decimals: PropTypes.number,
txData: PropTypes.object,
}
static defaultProps = {
tokenAmount: '0',
}
state = {
customPermissionAmount: '',
}
componentDidUpdate (prevProps) {
const { tokenAmount } = this.props
if (tokenAmount !== prevProps.tokenAmount) {
this.setState({ customPermissionAmount: tokenAmount })
}
}
render () {
const {
toAddress,
tokenAddress,
tokenSymbol,
tokenAmount,
showCustomizeGasModal,
showEditApprovalPermissionModal,
origin,
siteImage,
tokenTrackerBalance,
data,
decimals,
txData,
currentCurrency,
ethTransactionTotal,
fiatTransactionTotal,
...restProps
} = this.props
const { customPermissionAmount } = this.state
const tokensText = `${Number(tokenAmount)} ${tokenSymbol}`
const tokenBalance = tokenTrackerBalance
? calcTokenAmount(tokenTrackerBalance, decimals).toString(10)
: ''
const customData = customPermissionAmount
? getCustomTxParamsData(data, { customPermissionAmount, decimals })
: null
return (
<ConfirmTransactionBase
toAddress={toAddress}
identiconAddress={tokenAddress}
showAccountInHeader
title={tokensText}
contentComponent={(
<ConfirmApproveContent
decimals={decimals}
siteImage={siteImage}
setCustomAmount={(newAmount) => {
this.setState({ customPermissionAmount: newAmount })
}}
customTokenAmount={String(customPermissionAmount)}
tokenAmount={tokenAmount}
origin={origin}
tokenSymbol={tokenSymbol}
tokenBalance={tokenBalance}
showCustomizeGasModal={() => showCustomizeGasModal(txData)}
showEditApprovalPermissionModal={showEditApprovalPermissionModal}
data={customData || data}
toAddress={toAddress}
currentCurrency={currentCurrency}
ethTransactionTotal={ethTransactionTotal}
fiatTransactionTotal={fiatTransactionTotal}
/>
)}
hideSenderToRecipient
customTxParamsData={customData}
{...restProps}
/>
)
}
}

View File

@ -1,113 +0,0 @@
import { connect } from 'react-redux'
import { compose } from 'redux'
import { withRouter } from 'react-router-dom'
import {
contractExchangeRateSelector,
transactionFeeSelector,
} from '../../selectors'
import { getTokens } from '../../ducks/metamask/metamask'
import { showModal } from '../../store/actions'
import {
getTokenData,
} from '../../helpers/utils/transactions.util'
import withTokenTracker from '../../helpers/higher-order-components/with-token-tracker'
import {
calcTokenAmount,
getTokenToAddress,
getTokenValue,
} from '../../helpers/utils/token-util'
import ConfirmApprove from './confirm-approve.component'
const mapStateToProps = (state, ownProps) => {
const { match: { params = {} } } = ownProps
const { id: paramsTransactionId } = params
const {
confirmTransaction,
metamask: {
currentCurrency,
conversionRate,
currentNetworkTxList,
domainMetadata = {},
selectedAddress,
},
} = state
const {
txData: { id: transactionId, txParams: { to: tokenAddress, data } = {} } = {},
} = confirmTransaction
const transaction = (
currentNetworkTxList.find(({ id }) => id === (Number(paramsTransactionId) ||
transactionId)) || {}
)
const {
ethTransactionTotal,
fiatTransactionTotal,
} = transactionFeeSelector(state, transaction)
const tokens = getTokens(state)
const currentToken = tokens && tokens.find(({ address }) => tokenAddress === address)
const { decimals, symbol: tokenSymbol } = currentToken || {}
const tokenData = getTokenData(data)
const tokenValue = tokenData && getTokenValue(tokenData.params)
const toAddress = tokenData && getTokenToAddress(tokenData.params)
const tokenAmount = tokenData && calcTokenAmount(tokenValue, decimals).toString(10)
const contractExchangeRate = contractExchangeRateSelector(state)
const { origin } = transaction
const formattedOrigin = origin
? origin[0].toUpperCase() + origin.slice(1)
: ''
const { icon: siteImage = '' } = domainMetadata[origin] || {}
return {
toAddress,
tokenAddress,
tokenAmount,
currentCurrency,
conversionRate,
contractExchangeRate,
fiatTransactionTotal,
ethTransactionTotal,
tokenSymbol,
siteImage,
token: { address: tokenAddress },
userAddress: selectedAddress,
origin: formattedOrigin,
data,
decimals: Number(decimals),
txData: transaction,
}
}
const mapDispatchToProps = (dispatch) => {
return {
showCustomizeGasModal: (txData) => dispatch(showModal({ name: 'CUSTOMIZE_GAS', txData })),
showEditApprovalPermissionModal: ({
customTokenAmount,
decimals,
origin,
setCustomAmount,
tokenAmount,
tokenBalance,
tokenSymbol,
}) => dispatch(showModal({
name: 'EDIT_APPROVAL_PERMISSION',
customTokenAmount,
decimals,
origin,
setCustomAmount,
tokenAmount,
tokenBalance,
tokenSymbol,
})),
}
}
export default compose(
withRouter,
connect(mapStateToProps, mapDispatchToProps),
withTokenTracker,
)(ConfirmApprove)

View File

@ -0,0 +1,141 @@
import React, { useEffect, useRef, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { useParams } from 'react-router-dom'
import ConfirmTransactionBase from '../confirm-transaction-base'
import ConfirmApproveContent from './confirm-approve-content'
import { getCustomTxParamsData } from './confirm-approve.util'
import { showModal } from '../../store/actions'
import {
getTokenData,
} from '../../helpers/utils/transactions.util'
import {
calcTokenAmount,
getTokenToAddress,
getTokenValue,
} from '../../helpers/utils/token-util'
import { useTokenTracker } from '../../hooks/useTokenTracker'
import { getTokens } from '../../ducks/metamask/metamask'
import {
transactionFeeSelector,
txDataSelector,
} from '../../selectors/confirm-transaction'
import { getCurrentCurrency, getDomainMetadata } from '../../selectors/selectors'
import { currentNetworkTxListSelector } from '../../selectors/transactions'
export default function ConfirmApprove () {
const dispatch = useDispatch()
const { id: paramsTransactionId } = useParams()
const {
id: transactionId,
txParams: {
to: tokenAddress,
data,
} = {},
} = useSelector(txDataSelector)
const currentCurrency = useSelector(getCurrentCurrency)
const currentNetworkTxList = useSelector(currentNetworkTxListSelector)
const domainMetadata = useSelector(getDomainMetadata)
const tokens = useSelector(getTokens)
const transaction = (
currentNetworkTxList.find(({ id }) => id === (Number(paramsTransactionId) || transactionId)) || {}
)
const {
ethTransactionTotal,
fiatTransactionTotal,
} = useSelector((state) => transactionFeeSelector(state, transaction))
const currentToken = (tokens && tokens.find(({ address }) => tokenAddress === address)) || { address: tokenAddress }
const { tokensWithBalances } = useTokenTracker([currentToken])
const tokenTrackerBalance = tokensWithBalances[0]?.balance || ''
const tokenSymbol = currentToken?.symbol
const decimals = Number(currentToken?.decimals)
const tokenData = getTokenData(data)
const tokenValue = tokenData && getTokenValue(tokenData.params)
const toAddress = tokenData && getTokenToAddress(tokenData.params)
const tokenAmount = tokenData && calcTokenAmount(tokenValue, decimals).toString(10)
const [customPermissionAmount, setCustomPermissionAmount] = useState('')
const previousTokenAmount = useRef(tokenAmount)
useEffect(
() => {
if (customPermissionAmount && previousTokenAmount.current !== tokenAmount) {
setCustomPermissionAmount(tokenAmount)
}
previousTokenAmount.current = tokenAmount
},
[customPermissionAmount, tokenAmount]
)
const { origin } = transaction
const formattedOrigin = origin
? origin[0].toUpperCase() + origin.slice(1)
: ''
const txData = transaction
const { icon: siteImage = '' } = domainMetadata[origin] || {}
const tokensText = `${Number(tokenAmount)} ${tokenSymbol}`
const tokenBalance = tokenTrackerBalance
? calcTokenAmount(tokenTrackerBalance, decimals).toString(10)
: ''
const customData = customPermissionAmount
? getCustomTxParamsData(data, { customPermissionAmount, decimals })
: null
return (
<ConfirmTransactionBase
toAddress={toAddress}
identiconAddress={tokenAddress}
showAccountInHeader
title={tokensText}
contentComponent={(
<ConfirmApproveContent
decimals={decimals}
siteImage={siteImage}
setCustomAmount={setCustomPermissionAmount}
customTokenAmount={String(customPermissionAmount)}
tokenAmount={tokenAmount}
origin={formattedOrigin}
tokenSymbol={tokenSymbol}
tokenBalance={tokenBalance}
showCustomizeGasModal={() => dispatch(showModal({ name: 'CUSTOMIZE_GAS', txData }))}
showEditApprovalPermissionModal={
({
customTokenAmount,
decimals,
origin,
setCustomAmount,
tokenAmount,
tokenBalance,
tokenSymbol,
}) => dispatch(
showModal({
name: 'EDIT_APPROVAL_PERMISSION',
customTokenAmount,
decimals,
origin,
setCustomAmount,
tokenAmount,
tokenBalance,
tokenSymbol,
})
)
}
data={customData || data}
toAddress={toAddress}
currentCurrency={currentCurrency}
ethTransactionTotal={ethTransactionTotal}
fiatTransactionTotal={fiatTransactionTotal}
/>
)}
hideSenderToRecipient
customTxParamsData={customData}
/>
)
}

View File

@ -1 +1 @@
export { default } from './confirm-approve.container'
export { default } from './confirm-approve'