mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
second commit
This commit is contained in:
parent
f4d8da9277
commit
59c887301a
@ -0,0 +1,54 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
export default class AmountMaxButton extends Component {
|
||||
|
||||
static propTypes = {
|
||||
tokenBalance: PropTypes.string,
|
||||
gasTotal: PropTypes.string,
|
||||
balance: PropTypes.string,
|
||||
selectedToken: PropTypes.object,
|
||||
setAmountToMax: PropTypes.func,
|
||||
setMaxModeTo: PropTypes.func,
|
||||
maxModeOn: PropTypes.bool,
|
||||
};
|
||||
|
||||
setAmountToMax = function () {
|
||||
const {
|
||||
balance,
|
||||
tokenBalance,
|
||||
selectedToken,
|
||||
gasTotal,
|
||||
setAmountToMax,
|
||||
} = this.props
|
||||
|
||||
setAmountToMax({
|
||||
tokenBalance,
|
||||
selectedToken,
|
||||
gasTotal,
|
||||
setAmountToMax,
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
const { setMaxModeTo } = this.props
|
||||
|
||||
return (
|
||||
<div
|
||||
className='send-v2__amount-max'
|
||||
onClick={(event) => {
|
||||
event.preventDefault()
|
||||
setMaxModeTo(true)
|
||||
this.setAmountToMax()
|
||||
}}
|
||||
>
|
||||
{!maxModeOn ? this.context.t('max') : '' ])}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
AmountMaxButton.contextTypes = {
|
||||
t: PropTypes.func,
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
import {
|
||||
getSelectedToken,
|
||||
getGasTotal,
|
||||
getTokenBalance,
|
||||
getSendFromBalance,
|
||||
} from '../../../send.selectors.js'
|
||||
import { getMaxModeOn } from '../send-amount-row.selectors.js'
|
||||
import { calcMaxAmount } from './amount-max-button.utils.js'
|
||||
import {
|
||||
updateSendAmount,
|
||||
setMaxModeTo,
|
||||
} from '../../../actions'
|
||||
import AmountMaxButton from './amount-max-button.component'
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SendToRow)
|
||||
|
||||
function mapStateToProps (state) {
|
||||
|
||||
return {
|
||||
selectedToken: getSelectedToken(state),
|
||||
maxModeOn: getMaxModeOn(state),
|
||||
gasTotal: getGasTotal(state),
|
||||
tokenBalance: getTokenBalance(state),
|
||||
balance: getSendFromBalance(state),
|
||||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps (dispatch) {
|
||||
return {
|
||||
setAmountToMax: maxAmountDataObject => {
|
||||
updateSendErrors({ amount: null })
|
||||
updateSendAmount(calcMaxAmount(maxAmountDataObject))
|
||||
}
|
||||
setMaxModeTo: bool => dispatch(setMaxModeTo(bool)),
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
const {
|
||||
multiplyCurrencies,
|
||||
subtractCurrencies,
|
||||
} = require('../../../../conversion-util')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
|
||||
function calcMaxAmount ({ balance, gasTotal, selectedToken, tokenBalance }) {
|
||||
const { decimals } = selectedToken || {}
|
||||
const multiplier = Math.pow(10, Number(decimals || 0))
|
||||
|
||||
return selectedToken
|
||||
? multiplyCurrencies(tokenBalance, multiplier, {toNumericBase: 'hex'})
|
||||
: subtractCurrencies(
|
||||
ethUtil.addHexPrefix(balance),
|
||||
ethUtil.addHexPrefix(gasTotal),
|
||||
{ toNumericBase: 'hex' }
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
calcMaxAmount
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import SendRowWrapper from '../send-row-wrapper/send-row-wrapper.component'
|
||||
import AmountMaxButton from '../amount-max-button/amount-max-button.component'
|
||||
import CurrencyDisplay from '../../../send/currency-display'
|
||||
|
||||
export default class SendAmountRow extends Component {
|
||||
|
||||
static propTypes = {
|
||||
amountConversionRate: PropTypes.string,
|
||||
conversionRate: PropTypes.string,
|
||||
from: PropTypes.object,
|
||||
gasTotal: PropTypes.string,
|
||||
primaryCurrency: PropTypes.string,
|
||||
selectedToken: PropTypes.object,
|
||||
tokenBalance: PropTypes.string,
|
||||
updateSendAmountError: PropTypes.func,
|
||||
updateSendAmount: PropTypes.func,
|
||||
setMaxModeTo: PropTypes.func
|
||||
}
|
||||
|
||||
validateAmount (amount) {
|
||||
const {
|
||||
amountConversionRate,
|
||||
conversionRate,
|
||||
from: { balance },
|
||||
gasTotal,
|
||||
primaryCurrency,
|
||||
selectedToken,
|
||||
tokenBalance,
|
||||
updateSendAmountError,
|
||||
} = this.props
|
||||
|
||||
updateSendAmountError({
|
||||
amount,
|
||||
amountConversionRate,
|
||||
balance,
|
||||
conversionRate,
|
||||
gasTotal,
|
||||
primaryCurrency,
|
||||
selectedToken,
|
||||
tokenBalance,
|
||||
})
|
||||
}
|
||||
|
||||
handleAmountChange (amount) {
|
||||
const { updateSendAmount, setMaxModeTo } = this.props
|
||||
|
||||
setMaxModeTo(false)
|
||||
this.validateAmount(amount)
|
||||
updateSendAmount(amount)
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
amount,
|
||||
amountConversionRate,
|
||||
convertedCurrency,
|
||||
inError,
|
||||
gasTotal,
|
||||
maxModeOn,
|
||||
primaryCurrency = 'ETH',
|
||||
selectedToken,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<SendRowWrapper
|
||||
label={`${this.context.t('amount')}:`}
|
||||
showError={inError}
|
||||
errorType={'amount'}
|
||||
>
|
||||
!inError && gasTotal && <AmountMaxButton />
|
||||
<CurrencyDisplay
|
||||
inError={inError},
|
||||
primaryCurrency={primaryCurrency},
|
||||
convertedCurrency={convertedCurrency},
|
||||
selectedToken={selectedToken},
|
||||
value={amount || '0x0'},
|
||||
conversionRate={amountConversionRate},
|
||||
handleChange={this.handleAmountChange},
|
||||
>
|
||||
</SendRowWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SendAmountRow.contextTypes = {
|
||||
t: PropTypes.func,
|
||||
}
|
||||
|
@ -7,42 +7,43 @@ import {
|
||||
getGasTotal,
|
||||
getSelectedBalance,
|
||||
getTokenBalance,
|
||||
getSendFromBalance,
|
||||
} from '../../send.selectors.js'
|
||||
import {
|
||||
getMaxModeOn,
|
||||
getSendAmountError,
|
||||
sendAmountIsInError,
|
||||
} from './send-amount-row.selectors.js'
|
||||
import { getAmountErrorObject } from './send-to-row.utils.js'
|
||||
import { getAmountErrorObject } from './send-amount-row.utils.js'
|
||||
import {
|
||||
updateSendErrors,
|
||||
updateSendTo,
|
||||
updateSendAmount,
|
||||
setMaxModeTo,
|
||||
} from '../../../actions'
|
||||
import {
|
||||
openToDropdown,
|
||||
closeToDropdown,
|
||||
} from '../../../ducks/send'
|
||||
import SendToRow from './send-to-row.component'
|
||||
import SendAmountRow from './send-amount-row.component'
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SendToRow)
|
||||
|
||||
function mapStateToProps (state) {
|
||||
updateSendTo
|
||||
return {
|
||||
to: getSendTo(state),
|
||||
toAccounts: getSendToAccounts(state),
|
||||
toDropdownOpen: getToDropdownOpen(state),
|
||||
inError: sendToIsInError(state),
|
||||
network: getCurrentNetwork(state),
|
||||
selectedToken: getSelectedToken(state),
|
||||
primaryCurrency: getPrimaryCurrency(state),
|
||||
convertedCurrency: getConvertedCurrency(state),
|
||||
amountConversionRate: getAmountConversionRate(state),
|
||||
inError: sendAmountIsInError(state),
|
||||
amount: getSendAmount(state),
|
||||
maxModeOn: getMaxModeOn(state),
|
||||
gasTotal: getGasTotal(state),
|
||||
tokenBalance: getTokenBalance(state),
|
||||
balance: getSendFromBalance(state),
|
||||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps (dispatch) {
|
||||
return {
|
||||
updateSendToError: (to) => {
|
||||
dispatch(updateSendErrors(getToErrorObject(to)))
|
||||
},
|
||||
updateSendTo: (to, nickname) => dispatch(updateSendTo(to, nickname)),
|
||||
openToDropdown: () => dispatch(()),
|
||||
closeToDropdown: () => dispatch(()),
|
||||
}
|
||||
return {
|
||||
updateSendAmountError: (amountDataObject) => {
|
||||
dispatch(updateSendErrors(getAmountErrorObject(amountDataObject)))
|
||||
},
|
||||
updateSendAmount: newAmount => dispatch(updateSendAmount(newAmount)),
|
||||
setMaxModeTo: bool => dispatch(setMaxModeTo(bool)),
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
const selectors = {
|
||||
getMaxModeOn,
|
||||
sendAmountIsInError,
|
||||
}
|
||||
|
||||
module.exports = selectors
|
||||
|
||||
function getMaxModeOn (state) {
|
||||
return state.metamask.send.maxModeOn
|
||||
}
|
||||
|
||||
function sendAmountIsInError (state) {
|
||||
return Boolean(state.metamask.send.errors.amount)
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
const { isValidAddress } = require('../../../../util')
|
||||
|
||||
function getAmountErrorObject ({
|
||||
amount,
|
||||
balance,
|
||||
amountConversionRate,
|
||||
conversionRate,
|
||||
primaryCurrency,
|
||||
selectedToken,
|
||||
gasTotal,
|
||||
tokenBalance,
|
||||
}) {
|
||||
let insufficientFunds = false
|
||||
if (gasTotal && conversionRate) {
|
||||
insufficientFunds = !isBalanceSufficient({
|
||||
amount: selectedToken ? '0x0' : amount,
|
||||
gasTotal,
|
||||
balance,
|
||||
primaryCurrency,
|
||||
amountConversionRate,
|
||||
conversionRate,
|
||||
})
|
||||
}
|
||||
|
||||
let inSufficientTokens = false
|
||||
if (selectedToken && tokenBalance !== null) {
|
||||
const { decimals } = selectedToken
|
||||
inSufficientTokens = !isTokenBalanceSufficient({
|
||||
tokenBalance,
|
||||
amount,
|
||||
decimals,
|
||||
})
|
||||
}
|
||||
|
||||
const amountLessThanZero = conversionGreaterThan(
|
||||
{ value: 0, fromNumericBase: 'dec' },
|
||||
{ value: amount, fromNumericBase: 'hex' },
|
||||
)
|
||||
|
||||
let amountError = null
|
||||
|
||||
if (insufficientFunds) {
|
||||
amountError = this.context.t('insufficientFunds')
|
||||
} else if (insufficientTokens) {
|
||||
amountError = this.context.t('insufficientTokens')
|
||||
} else if (amountLessThanZero) {
|
||||
amountError = this.context.t('negativeETH')
|
||||
}
|
||||
|
||||
return { amount: amountError }
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getAmountErrorObject
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
import React, { Component } from 'react'
|
||||
import PageContainerContent from '../../page-container/page-container-header.component'
|
||||
import SendFromRow from './send-from-row/send-from-row.component'
|
||||
import SendToRow from './send-to-row/send-to-row.component'
|
||||
import SendAmountRow from './send-amount-row/send-amount-row.component'
|
||||
import SendGasRow from './send-gas-row/send-gas-row.component'
|
||||
|
||||
export default class SendContent extends Component {
|
||||
|
||||
render () {
|
||||
return (
|
||||
<PageContainerContent>
|
||||
<div className='.send-v2__form'>
|
||||
<SendFromRow />
|
||||
<SendToRow />
|
||||
<SendAmountRow />
|
||||
<SendGasRow />
|
||||
</div>
|
||||
</PageContainerContent>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import SendRowWrapper from '../../../send/from-dropdown'
|
||||
import FromDropdown from ''
|
||||
import SendRowWrapper from '../send-row-wrapper/send-row-wrapper.component'
|
||||
import FromDropdown from '../../../send/from-dropdown'
|
||||
|
||||
export default class SendFromRow extends Component {
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {
|
||||
getSendFrom,
|
||||
conversionRateSelector,
|
||||
getConversionRate,
|
||||
getSelectedTokenContract,
|
||||
getCurrentAccountWithSendEtherInfo,
|
||||
accountsWithSendEtherInfoSelector,
|
||||
@ -23,7 +23,7 @@ function mapStateToProps (state) {
|
||||
return {
|
||||
from: getSendFrom(state) || getCurrentAccountWithSendEtherInfo(state),
|
||||
fromAccounts: accountsWithSendEtherInfoSelector(state),
|
||||
conversionRate: conversionRateSelector(state),
|
||||
conversionRate: getConversionRate(state),
|
||||
fromDropdownOpen: getFromDropdownOpen(state),
|
||||
tokenContract: getSelectedTokenContract(state),
|
||||
}
|
||||
|
@ -0,0 +1,60 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import SendRowWrapper from '../send-row-wrapper/send-row-wrapper.component'
|
||||
import GasFeeDisplay from '../../../send/gas-fee-display-v2'
|
||||
|
||||
export default class SendGasRow extends Component {
|
||||
|
||||
static propTypes = {
|
||||
closeFromDropdown: PropTypes.func,
|
||||
conversionRate: PropTypes.string,
|
||||
from: PropTypes.string,
|
||||
fromAccounts: PropTypes.array,
|
||||
fromDropdownOpen: PropTypes.bool,
|
||||
openFromDropdown: PropTypes.func,
|
||||
tokenContract: PropTypes.object,
|
||||
updateSendFrom: PropTypes.func,
|
||||
updateSendTokenBalance: PropTypes.func,
|
||||
};
|
||||
|
||||
async handleFromChange (newFrom) {
|
||||
const {
|
||||
updateSendFrom,
|
||||
tokenContract,
|
||||
updateSendTokenBalance,
|
||||
} = this.props
|
||||
|
||||
if (tokenContract) {
|
||||
const usersToken = await tokenContract.balanceOf(newFrom.address)
|
||||
updateSendTokenBalance(usersToken)
|
||||
}
|
||||
updateSendFrom(newFrom)
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
conversionRate,
|
||||
convertedCurrency,
|
||||
showCustomizeGasModal,
|
||||
gasTotal,
|
||||
gasLoadingError,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<SendRowWrapper label={`${this.context.t('gasFee')}:`}>
|
||||
<GasFeeDisplay
|
||||
gasTotal={gasTotal},
|
||||
conversionRate={conversionRate},
|
||||
convertedCurrency={convertedCurrency},
|
||||
onClick={() => showCustomizeGasModal()},
|
||||
gasLoadingError={gasLoadingError},
|
||||
/>
|
||||
</SendRowWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SendGasRow.contextTypes = {
|
||||
t: PropTypes.func,
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
import {
|
||||
getConversionRate,
|
||||
getConvertedCurrency,
|
||||
getGasTotal,
|
||||
} from '../../send.selectors.js'
|
||||
import { getGasLoadingError } from './send-gas-row.selectors.js'
|
||||
import { calcTokenUpdateAmount } from './send-gas-row.utils.js'
|
||||
import { showModal } from '../../../actions'
|
||||
import SendGasRow from './send-from-row.component'
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SendGasRow)
|
||||
|
||||
function mapStateToProps (state) {
|
||||
return {
|
||||
conversionRate: getConversionRate(state),
|
||||
convertedCurrency: getConvertedCurrency(state),
|
||||
gasTotal: getGasTotal(state),
|
||||
gasLoadingError: getGasLoadingError(state),
|
||||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps (dispatch) {
|
||||
return {
|
||||
showCustomizeGasModal: () => dispatch(showModal({ name: 'CUSTOMIZE_GAS' })),
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
const selectors = {
|
||||
sendGasIsInError,
|
||||
}
|
||||
|
||||
module.exports = selectors
|
||||
|
||||
function sendGasIsInError (state) {
|
||||
return state.send.errors.gasLoading
|
||||
}
|
@ -19,14 +19,23 @@ export default class SendRowWrapper extends Component {
|
||||
children,
|
||||
} = this.props
|
||||
|
||||
let formField = children[0]
|
||||
let customLabelContent = null
|
||||
|
||||
if (children.length === 2) {
|
||||
formField = children[1]
|
||||
customLabelContent = children[0]
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="send-v2__form-row">
|
||||
<div className="send-v2__form-label">
|
||||
{label}
|
||||
(showError && <SendRowErrorMessage errorType={errorType}/>)
|
||||
{customLabelContent}
|
||||
</div>
|
||||
<div className="send-v2__form-field">
|
||||
{children}
|
||||
{formField}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import SendRowWrapper from '../../../send/from-dropdown'
|
||||
import SendRowWrapper from '../send-row-wrapper/send-row-wrapper.component'
|
||||
import ToDropdown from '../../../ens-input'
|
||||
|
||||
export default class SendToRow extends Component {
|
||||
@ -37,7 +37,11 @@ export default class SendToRow extends Component {
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<SendRowWrapper label={`${this.context.t('to')}:`}>
|
||||
<SendRowWrapper
|
||||
label={`${this.context.t('to')}:`}
|
||||
showError={inError}
|
||||
errorType={'to'}
|
||||
>
|
||||
<EnsInput
|
||||
name={'address'}
|
||||
placeholder={this.context.t('recipient Address')}
|
||||
|
@ -10,5 +10,5 @@ function getToDropdownOpen (state) {
|
||||
}
|
||||
|
||||
function sendToIsInError (state) {
|
||||
return Boolean(state.metamask.send.to)
|
||||
return Boolean(state.metamask.send.errors.to)
|
||||
}
|
||||
|
@ -5,31 +5,33 @@ import {
|
||||
} from './conversion-util'
|
||||
|
||||
const selectors = {
|
||||
accountsWithSendEtherInfoSelector,
|
||||
autoAddToBetaUI,
|
||||
getConversionRate,
|
||||
getAddressBook,
|
||||
getConversionRate,
|
||||
getCurrentAccountWithSendEtherInfo,
|
||||
getCurrentCurrency,
|
||||
getCurrentNetwork,
|
||||
getCurrentViewContext,
|
||||
getForceGasMin,
|
||||
getGasLimit,
|
||||
getGasPrice,
|
||||
getSelectedAccount,
|
||||
getSelectedAddress,
|
||||
getSelectedIdentity,
|
||||
getSelectedAccount,
|
||||
getSelectedToken,
|
||||
getSelectedTokenExchangeRate,
|
||||
getTokenExchangeRate,
|
||||
conversionRateSelector,
|
||||
transactionsSelector,
|
||||
accountsWithSendEtherInfoSelector,
|
||||
getCurrentAccountWithSendEtherInfo,
|
||||
getGasPrice,
|
||||
getGasLimit,
|
||||
getForceGasMin,
|
||||
getAddressBook,
|
||||
getSendFrom,
|
||||
getCurrentCurrency,
|
||||
getSendAmount,
|
||||
getSelectedTokenToFiatRate,
|
||||
getSelectedTokenContract,
|
||||
autoAddToBetaUI,
|
||||
getSendMaxModeState,
|
||||
getCurrentViewContext,
|
||||
getSelectedTokenExchangeRate,
|
||||
getSelectedTokenToFiatRate,
|
||||
getSendAmount,
|
||||
getSendErrors,
|
||||
getSendFrom,
|
||||
getSendFromBalance,
|
||||
getSendMaxModeState,
|
||||
getSendTo,
|
||||
getCurrentNetwork,
|
||||
getTokenExchangeRate,
|
||||
transactionsSelector,
|
||||
}
|
||||
|
||||
module.exports = selectors
|
||||
@ -82,7 +84,7 @@ function getTokenExchangeRate (state, tokenSymbol) {
|
||||
return tokenExchangeRate
|
||||
}
|
||||
|
||||
function conversionRateSelector (state) {
|
||||
function getConversionRate (state) {
|
||||
return state.metamask.conversionRate
|
||||
}
|
||||
|
||||
@ -142,6 +144,11 @@ function getSendFrom (state) {
|
||||
return state.metamask.send.from
|
||||
}
|
||||
|
||||
function getSendFromBalance (state) {
|
||||
const from = state.metamask.send.from || {}
|
||||
return from.balance
|
||||
}
|
||||
|
||||
function getSendAmount (state) {
|
||||
return state.metamask.send.amount
|
||||
}
|
||||
@ -156,7 +163,7 @@ function getCurrentCurrency (state) {
|
||||
|
||||
function getSelectedTokenToFiatRate (state) {
|
||||
const selectedTokenExchangeRate = getSelectedTokenExchangeRate(state)
|
||||
const conversionRate = conversionRateSelector(state)
|
||||
const conversionRate = getConversionRate(state)
|
||||
|
||||
const tokenToFiatRate = multiplyCurrencies(
|
||||
conversionRate,
|
||||
|
Loading…
Reference in New Issue
Block a user