diff options
Merge branch 'i3725-refactor-send-component-' into i3725-refactor-send-component-2
Diffstat (limited to 'ui/app/components/send_/send-footer')
4 files changed, 295 insertions, 0 deletions
diff --git a/ui/app/components/send_/send-footer/send-footer.component.js b/ui/app/components/send_/send-footer/send-footer.component.js index e69de29bb..fc7a78a94 100644 --- a/ui/app/components/send_/send-footer/send-footer.component.js +++ b/ui/app/components/send_/send-footer/send-footer.component.js @@ -0,0 +1,93 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import PageContainerFooter from '../../page-container/page-container-footer' +import { CONFIRM_TRANSACTION_ROUTE, DEFAULT_ROUTE } from '../../../routes' + +export default class SendFooter extends Component { + + static propTypes = { + addToAddressBookIfNew: PropTypes.func, + amount: PropTypes.string, + clearSend: PropTypes.func, + disabled: PropTypes.bool, + editingTransactionId: PropTypes.string, + errors: PropTypes.object, + from: PropTypes.object, + gasLimit: PropTypes.string, + gasPrice: PropTypes.string, + gasTotal: PropTypes.string, + history: PropTypes.object, + selectedToken: PropTypes.object, + sign: PropTypes.func, + to: PropTypes.string, + toAccounts: PropTypes.array, + tokenBalance: PropTypes.string, + unapprovedTxs: PropTypes.object, + update: PropTypes.func, + }; + + onSubmit (event) { + event.preventDefault() + const { + addToAddressBookIfNew, + amount, + editingTransactionId, + from: {address: from}, + gasLimit: gas, + gasPrice, + selectedToken, + sign, + to, + unapprovedTxs, + // updateTx, + update, + toAccounts, + } = this.props + + // Should not be needed because submit should be disabled if there are no errors. + // const noErrors = !amountError && toError === null + + // if (!noErrors) { + // return + // } + + // TODO: add nickname functionality + addToAddressBookIfNew(to, toAccounts) + + editingTransactionId + ? update({ + amount, + editingTransactionId, + from, + gas, + gasPrice, + selectedToken, + to, + unapprovedTxs, + }) + : sign({ selectedToken, to, amount, from, gas, gasPrice }) + + this.props.history.push(CONFIRM_TRANSACTION_ROUTE) + } + + + render () { + const { clearSend, disabled, history } = this.props + + return ( + <PageContainerFooter + onCancel={() => { + clearSend() + history.push(DEFAULT_ROUTE) + }} + onSubmit={e => this.onSubmit(e)} + disabled={disabled} + /> + ) + } + +} + +SendFooter.contextTypes = { + t: PropTypes.func, +} diff --git a/ui/app/components/send_/send-footer/send-footer.container.js b/ui/app/components/send_/send-footer/send-footer.container.js index e69de29bb..022b2db08 100644 --- a/ui/app/components/send_/send-footer/send-footer.container.js +++ b/ui/app/components/send_/send-footer/send-footer.container.js @@ -0,0 +1,106 @@ +import { connect } from 'react-redux' +import ethUtil from 'ethereumjs-util' +import { + addToAddressBook, + clearSend, + signTokenTx, + signTx, + updateTransaction, +} from '../../../actions' +import SendFooter from './send-footer.component' +import { + getGasLimit, + getGasPrice, + getGasTotal, + getSelectedToken, + getSendAmount, + getSendEditingTransactionId, + getSendFromObject, + getSendTo, + getSendToAccounts, + getTokenBalance, + getUnapprovedTxs, +} from '../send.selectors' +import { + isSendFormInError, +} from './send-footer.selectors' +import { + addressIsNew, + constructTxParams, + constructUpdatedTx, + formShouldBeDisabled, +} from './send-footer.utils' + +export default connect(mapStateToProps, mapDispatchToProps)(SendFooter) + +function mapStateToProps (state) { + return { + amount: getSendAmount(state), + disabled: formShouldBeDisabled({ + inError: isSendFormInError(state), + selectedToken: getSelectedToken(state), + tokenBalance: getTokenBalance(state), + gasTotal: getGasTotal(state), + }), + editingTransactionId: getSendEditingTransactionId(state), + from: getSendFromObject(state), + gasLimit: getGasLimit(state), + gasPrice: getGasPrice(state), + inError: isSendFormInError(state), + isToken: Boolean(getSelectedToken(state)), + selectedToken: getSelectedToken(state), + to: getSendTo(state), + toAccounts: getSendToAccounts(state), + unapprovedTxs: getUnapprovedTxs(state), + } +} + +function mapDispatchToProps (dispatch) { + return { + clearSend: () => dispatch(clearSend()), + sign: ({ selectedToken, to, amount, from, gas, gasPrice }) => { + const txParams = constructTxParams({ + amount, + from, + gas, + gasPrice, + selectedToken, + to, + }) + + selectedToken + ? dispatch(signTokenTx(selectedToken.address, to, amount, txParams)) + : dispatch(signTx(txParams)) + }, + update: ({ + amount, + editingTransactionId, + from, + gas, + gasPrice, + selectedToken, + to, + unapprovedTxs, + }) => { + const editingTx = constructUpdatedTx({ + amount, + editingTransactionId, + from, + gas, + gasPrice, + selectedToken, + to, + unapprovedTxs, + }) + + dispatch(updateTransaction(editingTx)) + }, + addToAddressBookIfNew: (newAddress, toAccounts, nickname = '') => { + const hexPrefixedAddress = ethUtil.addHexPrefix(newAddress) + if (addressIsNew(toAccounts)) { + // TODO: nickname, i.e. addToAddressBook(recipient, nickname) + dispatch(addToAddressBook(hexPrefixedAddress, nickname)) + } + }, + } +} diff --git a/ui/app/components/send_/send-footer/send-footer.selectors.js b/ui/app/components/send_/send-footer/send-footer.selectors.js index e69de29bb..e8fef6be6 100644 --- a/ui/app/components/send_/send-footer/send-footer.selectors.js +++ b/ui/app/components/send_/send-footer/send-footer.selectors.js @@ -0,0 +1,12 @@ +import { getSendErrors } from '../send.selectors' + +const selectors = { + isSendFormInError, +} + +module.exports = selectors + +function isSendFormInError (state) { + const { amount, to } = getSendErrors(state) + return Boolean(amount || to !== null) +} diff --git a/ui/app/components/send_/send-footer/send-footer.utils.js b/ui/app/components/send_/send-footer/send-footer.utils.js index e69de29bb..353c0e347 100644 --- a/ui/app/components/send_/send-footer/send-footer.utils.js +++ b/ui/app/components/send_/send-footer/send-footer.utils.js @@ -0,0 +1,84 @@ +import ethAbi from 'ethereumjs-abi' +import ethUtil from 'ethereumjs-util' +import { TOKEN_TRANSFER_FUNCTION_SIGNATURE } from '../send.constants' + +function formShouldBeDisabled ({ inError, selectedToken, tokenBalance, gasTotal }) { + const missingTokenBalance = selectedToken && !tokenBalance + return inError || !gasTotal || missingTokenBalance +} + +function addHexPrefixToObjectValues (obj) { + return Object.keys(obj).reduce((newObj, key) => { + return { ...newObj, [key]: ethUtil.addHexPrefix(obj[key]) } + }, {}) +} + +function constructTxParams ({ selectedToken, to, amount, from, gas, gasPrice }) { + const txParams = { + from, + value: '0', + gas, + gasPrice, + } + + if (!selectedToken) { + txParams.value = amount + txParams.to = to + } + + const hexPrefixedTxParams = addHexPrefixToObjectValues(txParams) + + return hexPrefixedTxParams +} + +function constructUpdatedTx ({ + amount, + editingTransactionId, + from, + gas, + gasPrice, + selectedToken, + to, + unapprovedTxs, +}) { + const editingTx = { + ...unapprovedTxs[editingTransactionId], + txParams: addHexPrefixToObjectValues({ from, gas, gasPrice }), + } + + if (selectedToken) { + const data = TOKEN_TRANSFER_FUNCTION_SIGNATURE + Array.prototype.map.call( + ethAbi.rawEncode(['address', 'uint256'], [to, ethUtil.addHexPrefix(amount)]), + x => ('00' + x.toString(16)).slice(-2) + ).join('') + + Object.assign(editingTx.txParams, addHexPrefixToObjectValues({ + value: '0', + to: selectedToken.address, + data, + })) + } else { + const { data } = unapprovedTxs[editingTransactionId].txParams + + Object.assign(editingTx.txParams, addHexPrefixToObjectValues({ + value: amount, + to, + data, + })) + + if (typeof editingTx.txParams.data === 'undefined') { + delete editingTx.txParams.data + } + } +} + +function addressIsNew (toAccounts, newAddress) { + return !toAccounts.find(({ address }) => newAddress === address) +} + +module.exports = { + addressIsNew, + formShouldBeDisabled, + constructTxParams, + constructUpdatedTx, +} |