mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-23 02:10:12 +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