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:
parent
2873053d45
commit
4706401f4f
@ -1 +0,0 @@
|
||||
export { default } from './with-token-tracker.component'
|
@ -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}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -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}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
141
ui/app/pages/confirm-approve/confirm-approve.js
Normal file
141
ui/app/pages/confirm-approve/confirm-approve.js
Normal 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}
|
||||
/>
|
||||
)
|
||||
}
|
@ -1 +1 @@
|
||||
export { default } from './confirm-approve.container'
|
||||
export { default } from './confirm-approve'
|
||||
|
Loading…
Reference in New Issue
Block a user