1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00
metamask-extension/ui/app/pages/send/send.component.js
Mark Stacey 0d61f78379
Remove unused PersistentForm (#7770)
This component used to persist form contents to LocalStorage. This was
especially useful for the popup UI, as each time the mouse left the
popup, the UI was completely torn down and state was lost.

This component was only being referenced by one form, and it wasn't
even being used there (e.g. no fields were labelled appropriately to
be persisted).

This was a useful component, and it seems this feature was lost
somewhere in the past couple of years. It was tempting to re-instate it
rather than delete it, but I decided not to because I'd likely approach
the problem differently if we wanted to reinstate it again today (maybe
by using a React Hook, or storing the state in Redux and persisting a
subset of the Redux store instead).
2020-01-10 11:55:27 -04:00

363 lines
8.9 KiB
JavaScript

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import {
getAmountErrorObject,
getGasFeeErrorObject,
getToAddressForGasUpdate,
doesAmountErrorRequireUpdate,
} from './send.utils'
import debounce from 'lodash.debounce'
import { getToWarningObject, getToErrorObject } from './send-content/add-recipient/add-recipient'
import SendHeader from './send-header'
import AddRecipient from './send-content/add-recipient'
import SendContent from './send-content'
import SendFooter from './send-footer'
import EnsInput from './send-content/add-recipient/ens-input'
export default class SendTransactionScreen extends Component {
static propTypes = {
addressBook: PropTypes.arrayOf(PropTypes.object),
amount: PropTypes.string,
amountConversionRate: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
blockGasLimit: PropTypes.string,
conversionRate: PropTypes.number,
editingTransactionId: PropTypes.string,
fetchBasicGasEstimates: PropTypes.func.isRequired,
from: PropTypes.object,
gasLimit: PropTypes.string,
gasPrice: PropTypes.string,
gasTotal: PropTypes.string,
hasHexData: PropTypes.bool,
history: PropTypes.object,
network: PropTypes.string,
primaryCurrency: PropTypes.string,
recentBlocks: PropTypes.array,
resetSendState: PropTypes.func.isRequired,
selectedAddress: PropTypes.string,
selectedToken: PropTypes.object,
showHexData: PropTypes.bool,
to: PropTypes.string,
toNickname: PropTypes.string,
tokens: PropTypes.array,
tokenBalance: PropTypes.string,
tokenContract: PropTypes.object,
updateAndSetGasLimit: PropTypes.func.isRequired,
updateSendEnsResolution: PropTypes.func.isRequired,
updateSendEnsResolutionError: PropTypes.func.isRequired,
updateSendErrors: PropTypes.func.isRequired,
updateSendTo: PropTypes.func.isRequired,
updateSendTokenBalance: PropTypes.func.isRequired,
updateToNicknameIfNecessary: PropTypes.func.isRequired,
scanQrCode: PropTypes.func.isRequired,
qrCodeDetected: PropTypes.func.isRequired,
qrCodeData: PropTypes.object,
}
static contextTypes = {
t: PropTypes.func,
metricsEvent: PropTypes.func,
}
state = {
query: '',
toError: null,
toWarning: null,
}
constructor (props) {
super(props)
this.dValidate = debounce(this.validate, 1000)
}
componentDidUpdate (prevProps) {
const {
amount,
amountConversionRate,
conversionRate,
from: { address, balance },
gasTotal,
network,
primaryCurrency,
selectedToken,
tokenBalance,
updateSendErrors,
updateSendTo,
updateSendTokenBalance,
tokenContract,
to,
toNickname,
addressBook,
updateToNicknameIfNecessary,
qrCodeData,
qrCodeDetected,
} = this.props
let updateGas = false
const {
from: { balance: prevBalance },
gasTotal: prevGasTotal,
tokenBalance: prevTokenBalance,
network: prevNetwork,
selectedToken: prevSelectedToken,
to: prevTo,
} = prevProps
const uninitialized = [prevBalance, prevGasTotal].every(n => n === null)
const amountErrorRequiresUpdate = doesAmountErrorRequireUpdate({
balance,
gasTotal,
prevBalance,
prevGasTotal,
prevTokenBalance,
selectedToken,
tokenBalance,
})
if (amountErrorRequiresUpdate) {
const amountErrorObject = getAmountErrorObject({
amount,
amountConversionRate,
balance,
conversionRate,
gasTotal,
primaryCurrency,
selectedToken,
tokenBalance,
})
const gasFeeErrorObject = selectedToken
? getGasFeeErrorObject({
amountConversionRate,
balance,
conversionRate,
gasTotal,
primaryCurrency,
selectedToken,
})
: { gasFee: null }
updateSendErrors(Object.assign(amountErrorObject, gasFeeErrorObject))
}
if (!uninitialized) {
if (network !== prevNetwork && network !== 'loading') {
updateSendTokenBalance({
selectedToken,
tokenContract,
address,
})
updateToNicknameIfNecessary(to, toNickname, addressBook)
updateGas = true
}
}
const prevTokenAddress = prevSelectedToken && prevSelectedToken.address
const selectedTokenAddress = selectedToken && selectedToken.address
if (selectedTokenAddress && prevTokenAddress !== selectedTokenAddress) {
this.updateSendToken()
updateGas = true
}
let scannedAddress
if (qrCodeData) {
if (qrCodeData.type === 'address') {
scannedAddress = qrCodeData.values.address.toLowerCase()
const currentAddress = prevTo && prevTo.toLowerCase()
if (currentAddress !== scannedAddress) {
updateSendTo(scannedAddress)
updateGas = true
// Clean up QR code data after handling
qrCodeDetected(null)
}
}
}
if (updateGas) {
if (scannedAddress) {
this.updateGas({ to: scannedAddress })
} else {
this.updateGas()
}
}
}
componentDidMount () {
this.props.fetchBasicGasEstimates()
.then(() => {
this.updateGas()
})
}
UNSAFE_componentWillMount () {
this.updateSendToken()
// Show QR Scanner modal if ?scan=true
if (window.location.search === '?scan=true') {
this.props.scanQrCode()
// Clear the queryString param after showing the modal
const cleanUrl = location.href.split('?')[0]
history.pushState({}, null, `${cleanUrl}`)
window.location.hash = '#send'
}
}
componentWillUnmount () {
this.props.resetSendState()
}
onRecipientInputChange = query => {
if (query) {
this.dValidate(query)
} else {
this.validate(query)
}
this.setState({
query,
})
}
validate (query) {
const {
hasHexData,
tokens,
selectedToken,
network,
} = this.props
if (!query) {
return this.setState({ toError: '', toWarning: '' })
}
const toErrorObject = getToErrorObject(query, null, hasHexData, tokens, selectedToken, network)
const toWarningObject = getToWarningObject(query, null, tokens, selectedToken)
this.setState({
toError: toErrorObject.to,
toWarning: toWarningObject.to,
})
}
updateSendToken () {
const {
from: { address },
selectedToken,
tokenContract,
updateSendTokenBalance,
} = this.props
updateSendTokenBalance({
selectedToken,
tokenContract,
address,
})
}
updateGas ({ to: updatedToAddress, amount: value, data } = {}) {
const {
amount,
blockGasLimit,
editingTransactionId,
gasLimit,
gasPrice,
recentBlocks,
selectedAddress,
selectedToken = {},
to: currentToAddress,
updateAndSetGasLimit,
} = this.props
updateAndSetGasLimit({
blockGasLimit,
editingTransactionId,
gasLimit,
gasPrice,
recentBlocks,
selectedAddress,
selectedToken,
to: getToAddressForGasUpdate(updatedToAddress, currentToAddress),
value: value || amount,
data,
})
}
render () {
const { history, to } = this.props
let content
if (to) {
content = this.renderSendContent()
} else {
content = this.renderAddRecipient()
}
return (
<div className="page-container">
<SendHeader history={history} />
{ this.renderInput() }
{ content }
</div>
)
}
renderInput () {
return (
<EnsInput
className="send__to-row"
scanQrCode={_ => {
this.context.metricsEvent({
eventOpts: {
category: 'Transactions',
action: 'Edit Screen',
name: 'Used QR scanner',
},
})
this.props.scanQrCode()
}}
onChange={this.onRecipientInputChange}
onValidAddressTyped={(address) => this.props.updateSendTo(address, '')}
onPaste={text => {
this.props.updateSendTo(text) && this.updateGas()
}}
onReset={() => this.props.updateSendTo('', '')}
updateEnsResolution={this.props.updateSendEnsResolution}
updateEnsResolutionError={this.props.updateSendEnsResolutionError}
/>
)
}
renderAddRecipient () {
const { toError, toWarning } = this.state
return (
<AddRecipient
updateGas={({ to, amount, data } = {}) => this.updateGas({ to, amount, data })}
query={this.state.query}
toError={toError}
toWarning={toWarning}
/>
)
}
renderSendContent () {
const { history, showHexData } = this.props
return [
<SendContent
key="send-content"
updateGas={({ to, amount, data } = {}) => this.updateGas({ to, amount, data })}
showHexData={showHexData}
/>,
<SendFooter key="send-footer" history={history} />,
]
}
}