aboutsummaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorDan J Miller <danjm.com@gmail.com>2018-05-01 10:46:17 +0800
committerGitHub <noreply@github.com>2018-05-01 10:46:17 +0800
commit6def76e294d813c4f5a6c11fed3faf19580cc04b (patch)
tree24d68a267304d085ee1b7c705ce5ade53c9439c3 /ui
parent954394f81090b1a6a4afe55243caa3671b88addc (diff)
parent2f78fffbdbb0e41d73bcde2c15c88fff095614b7 (diff)
downloadtangerine-wallet-browser-6def76e294d813c4f5a6c11fed3faf19580cc04b.tar.gz
tangerine-wallet-browser-6def76e294d813c4f5a6c11fed3faf19580cc04b.tar.zst
tangerine-wallet-browser-6def76e294d813c4f5a6c11fed3faf19580cc04b.zip
Merge pull request #4157 from danjm/i3725-refactor-send-component-2
I3725 refactor send component
Diffstat (limited to 'ui')
-rw-r--r--ui/app/components/page-container/index.js1
-rw-r--r--ui/app/components/page-container/page-container-footer/index.js1
-rw-r--r--ui/app/components/page-container/page-container-footer/page-container-footer.component.js (renamed from ui/app/components/page-container/page-container-footer.component.js)26
-rw-r--r--ui/app/components/page-container/page-container-footer/tests/page-container-footer.component.test.js (renamed from ui/app/components/page-container/tests/page-container-content-component.test.js)0
-rw-r--r--ui/app/components/page-container/page-container-header/index.js1
-rw-r--r--ui/app/components/page-container/page-container-header/page-container-header.component.js57
-rw-r--r--ui/app/components/page-container/page-container-header/tests/page-container-header.component.test.js (renamed from ui/app/components/page-container/tests/page-container-footer-component.test.js)0
-rw-r--r--ui/app/components/page-container/page-container.component.js58
-rw-r--r--ui/app/components/page-container/tests/page-container.component.test.js (renamed from ui/app/components/page-container/tests/page-container-header-component.test.js)0
-rw-r--r--ui/app/components/send/send-v2-container.js1
-rw-r--r--ui/app/components/send_/send-footer/send-footer.component.js2
-rw-r--r--ui/app/components/send_/send-header/send-header.component.js2
-rw-r--r--ui/app/components/send_/send.component.js5
-rw-r--r--ui/app/send-v2.js456
14 files changed, 578 insertions, 32 deletions
diff --git a/ui/app/components/page-container/index.js b/ui/app/components/page-container/index.js
new file mode 100644
index 000000000..415870b37
--- /dev/null
+++ b/ui/app/components/page-container/index.js
@@ -0,0 +1 @@
+export { default } from './page-container.component'
diff --git a/ui/app/components/page-container/page-container-footer/index.js b/ui/app/components/page-container/page-container-footer/index.js
new file mode 100644
index 000000000..7825c4520
--- /dev/null
+++ b/ui/app/components/page-container/page-container-footer/index.js
@@ -0,0 +1 @@
+export { default } from './page-container-footer.component'
diff --git a/ui/app/components/page-container/page-container-footer.component.js b/ui/app/components/page-container/page-container-footer/page-container-footer.component.js
index 475ce6b1c..fafe1c19e 100644
--- a/ui/app/components/page-container/page-container-footer.component.js
+++ b/ui/app/components/page-container/page-container-footer/page-container-footer.component.js
@@ -5,12 +5,24 @@ export default class PageContainerFooter extends Component {
static propTypes = {
onCancel: PropTypes.func,
+ cancelText: PropTypes.string,
onSubmit: PropTypes.func,
+ submitText: PropTypes.string,
disabled: PropTypes.bool,
- };
+ }
+
+ static contextTypes = {
+ t: PropTypes.func,
+ }
render () {
- const { onCancel, onSubmit, disabled } = this.props
+ const {
+ onCancel,
+ cancelText,
+ onSubmit,
+ submitText,
+ disabled,
+ } = this.props
return (
<div className="page-container__footer">
@@ -19,15 +31,15 @@ export default class PageContainerFooter extends Component {
className="btn-secondary--lg page-container__footer-button"
onClick={() => onCancel()}
>
- {this.context.t('cancel')}
+ { this.context.t('cancel') || cancelText }
</button>
<button
className="btn-primary--lg page-container__footer-button"
disabled={disabled}
- onClick={(e) => onSubmit(e)}
+ onClick={e => onSubmit(e)}
>
- {this.context.t('next')}
+ { this.context.t('next') || submitText }
</button>
</div>
@@ -35,7 +47,3 @@ export default class PageContainerFooter extends Component {
}
}
-
-PageContainerFooter.contextTypes = {
- t: PropTypes.func,
-}
diff --git a/ui/app/components/page-container/tests/page-container-content-component.test.js b/ui/app/components/page-container/page-container-footer/tests/page-container-footer.component.test.js
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/page-container/tests/page-container-content-component.test.js
+++ b/ui/app/components/page-container/page-container-footer/tests/page-container-footer.component.test.js
diff --git a/ui/app/components/page-container/page-container-header/index.js b/ui/app/components/page-container/page-container-header/index.js
new file mode 100644
index 000000000..b194af057
--- /dev/null
+++ b/ui/app/components/page-container/page-container-header/index.js
@@ -0,0 +1 @@
+export { default } from './page-container-header.component'
diff --git a/ui/app/components/page-container/page-container-header/page-container-header.component.js b/ui/app/components/page-container/page-container-header/page-container-header.component.js
new file mode 100644
index 000000000..28882edce
--- /dev/null
+++ b/ui/app/components/page-container/page-container-header/page-container-header.component.js
@@ -0,0 +1,57 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+
+export default class PageContainerHeader extends Component {
+
+ static propTypes = {
+ title: PropTypes.string.isRequired,
+ subtitle: PropTypes.string,
+ onClose: PropTypes.func,
+ showBackButton: PropTypes.bool,
+ onBackButtonClick: PropTypes.func,
+ backButtonStyles: PropTypes.object,
+ backButtonString: PropTypes.string,
+ };
+
+ renderHeaderRow () {
+ const { showBackButton, onBackButtonClick, backButtonStyles, backButtonString } = this.props
+
+ return showBackButton && (
+ <div className="page-container__header-row">
+ <span
+ className="page-container__back-button"
+ onClick={onBackButtonClick}
+ style={backButtonStyles}
+ >
+ { backButtonString || 'Back' }
+ </span>
+ </div>
+ )
+ }
+
+ render () {
+ const { title, subtitle, onClose } = this.props
+
+ return (
+ <div className="page-container__header">
+
+ { this.renderHeaderRow() }
+
+ <div className="page-container__title">
+ {title}
+ </div>
+
+ <div className="page-container__subtitle">
+ {subtitle}
+ </div>
+
+ <div
+ className="page-container__header-close"
+ onClick={() => onClose()}
+ />
+
+ </div>
+ )
+ }
+
+}
diff --git a/ui/app/components/page-container/tests/page-container-footer-component.test.js b/ui/app/components/page-container/page-container-header/tests/page-container-header.component.test.js
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/page-container/tests/page-container-footer-component.test.js
+++ b/ui/app/components/page-container/page-container-header/tests/page-container-header.component.test.js
diff --git a/ui/app/components/page-container/page-container.component.js b/ui/app/components/page-container/page-container.component.js
index dc3745d4a..9bfb99ade 100644
--- a/ui/app/components/page-container/page-container.component.js
+++ b/ui/app/components/page-container/page-container.component.js
@@ -1,16 +1,70 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
+import PageContainerHeader from './page-container-header'
+import PageContainerFooter from './page-container-footer'
+
export default class PageContainer extends Component {
static propTypes = {
- children: PropTypes.node.isRequired,
+ // PageContainerHeader props
+ title: PropTypes.string.isRequired,
+ subtitle: PropTypes.string,
+ onClose: PropTypes.func,
+ showBackButton: PropTypes.bool,
+ onBackButtonClick: PropTypes.func,
+ backButtonStyles: PropTypes.object,
+ backButtonString: PropTypes.string,
+ // Content props
+ ContentComponent: PropTypes.func,
+ contentComponentProps: PropTypes.object,
+ // PageContainerFooter props
+ onCancel: PropTypes.func,
+ cancelText: PropTypes.string,
+ onSubmit: PropTypes.func,
+ submitText: PropTypes.string,
+ disabled: PropTypes.bool,
};
render () {
+ const {
+ title,
+ subtitle,
+ onClose,
+ showBackButton,
+ onBackButtonClick,
+ backButtonStyles,
+ backButtonString,
+ ContentComponent,
+ contentComponentProps,
+ onCancel,
+ cancelText,
+ onSubmit,
+ submitText,
+ disabled,
+ } = this.props
+
return (
<div className="page-container">
- {this.props.children}
+ <PageContainerHeader
+ title={title}
+ subtitle={subtitle}
+ onClose={onClose}
+ showBackButton={showBackButton}
+ onBackButtonClick={onBackButtonClick}
+ backButtonStyles={backButtonStyles}
+ backButtonString={backButtonString}
+ />
+ <div className="page-container__content">
+ <ContentComponent { ...contentComponentProps } />
+ </div>
+ <PageContainerFooter
+ onCancel={onCancel}
+ cancelText={cancelText}
+ onSubmit={onSubmit}
+ submitText={submitText}
+ disabled={disabled}
+ />
</div>
)
}
diff --git a/ui/app/components/page-container/tests/page-container-header-component.test.js b/ui/app/components/page-container/tests/page-container.component.test.js
index e69de29bb..e69de29bb 100644
--- a/ui/app/components/page-container/tests/page-container-header-component.test.js
+++ b/ui/app/components/page-container/tests/page-container.component.test.js
diff --git a/ui/app/components/send/send-v2-container.js b/ui/app/components/send/send-v2-container.js
index 6464439f2..cdbee0cdc 100644
--- a/ui/app/components/send/send-v2-container.js
+++ b/ui/app/components/send/send-v2-container.js
@@ -62,6 +62,7 @@ function mapStateToProps (state) {
tokenContract: getSelectedTokenContract(state),
unapprovedTxs: state.metamask.unapprovedTxs,
network: state.metamask.network,
+ isToken: Boolean(getSelectedToken(state)),
}
}
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 ffece433e..fc7a78a94 100644
--- a/ui/app/components/send_/send-footer/send-footer.component.js
+++ b/ui/app/components/send_/send-footer/send-footer.component.js
@@ -1,6 +1,6 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
-import PageContainerFooter from '../../page-container/page-container-footer.component'
+import PageContainerFooter from '../../page-container/page-container-footer'
import { CONFIRM_TRANSACTION_ROUTE, DEFAULT_ROUTE } from '../../../routes'
export default class SendFooter extends Component {
diff --git a/ui/app/components/send_/send-header/send-header.component.js b/ui/app/components/send_/send-header/send-header.component.js
index 098fd89a4..dc4190b93 100644
--- a/ui/app/components/send_/send-header/send-header.component.js
+++ b/ui/app/components/send_/send-header/send-header.component.js
@@ -1,6 +1,6 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
-import PageContainerHeader from '../../page-container/page-container-header.component'
+import PageContainerHeader from '../../page-container/page-container-header'
import { DEFAULT_ROUTE } from '../../../routes'
export default class SendHeader extends Component {
diff --git a/ui/app/components/send_/send.component.js b/ui/app/components/send_/send.component.js
index 969d76946..e14a97537 100644
--- a/ui/app/components/send_/send.component.js
+++ b/ui/app/components/send_/send.component.js
@@ -6,7 +6,6 @@ import {
doesAmountErrorRequireUpdate,
} from './send.utils'
-import PageContainer from '..//page-container/page-container.component'
import SendHeader from './send-header/send-header.container'
import SendContent from './send-content/send-content.component'
import SendFooter from './send-footer/send-footer.container'
@@ -128,11 +127,11 @@ export default class SendTransactionScreen extends PersistentForm {
const { history } = this.props
return (
- <PageContainer>
+ <div className="page-container">
<SendHeader history={history}/>
<SendContent/>
<SendFooter history={history}/>
- </PageContainer>
+ </div>
)
}
diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js
index 16964b45d..228cb22d0 100644
--- a/ui/app/send-v2.js
+++ b/ui/app/send-v2.js
@@ -3,8 +3,23 @@ const PropTypes = require('prop-types')
const PersistentForm = require('../lib/persistent-form')
const h = require('react-hyperscript')
+const ethAbi = require('ethereumjs-abi')
+const ethUtil = require('ethereumjs-util')
+
+const FromDropdown = require('./components/send/from-dropdown')
+const EnsInput = require('./components/ens-input')
+const CurrencyDisplay = require('./components/send/currency-display')
+const MemoTextArea = require('./components/send/memo-textarea')
+const GasFeeDisplay = require('./components/send/gas-fee-display-v2')
+
+const {
+ TOKEN_TRANSFER_FUNCTION_SIGNATURE,
+} = require('./components/send/send-constants')
+
const {
+ multiplyCurrencies,
conversionGreaterThan,
+ subtractCurrencies,
} = require('./conversion-util')
const {
calcTokenAmount,
@@ -14,11 +29,12 @@ const {
isTokenBalanceSufficient,
getGasTotal,
} = require('./components/send/send-utils')
+const { isValidAddress } = require('./util')
-import PageContainer from './components/page-container/page-container.component'
-import SendHeader from './components/send_/send-header/send-header.container'
-import SendContent from './components/send_/send-content/send-content.component'
-import SendFooter from './components/send_/send-footer/send-footer.container'
+import PageContainer from './components/page-container'
+// import SendHeader from './components/send_/send-header/send-header.container'
+// import PageContainerContent from './components/page-container/page-container-content.component'
+// import PageContainerFooter from './components/page-container/page-container-footer.component'
SendTransactionScreen.contextTypes = {
t: PropTypes.func,
@@ -40,6 +56,8 @@ function SendTransactionScreen () {
gasLoadingError: false,
}
+ this.handleToChange = this.handleToChange.bind(this)
+ this.handleAmountChange = this.handleAmountChange.bind(this)
this.validateAmount = this.validateAmount.bind(this)
}
@@ -74,6 +92,17 @@ SendTransactionScreen.prototype.updateSendTokenBalance = function (usersToken) {
}
SendTransactionScreen.prototype.componentWillMount = function () {
+ const {
+ updateTokenExchangeRate,
+ selectedToken = {},
+ } = this.props
+
+ const { symbol } = selectedToken || {}
+
+ if (symbol) {
+ updateTokenExchangeRate(symbol)
+ }
+
this.updateGas()
}
@@ -84,7 +113,7 @@ SendTransactionScreen.prototype.updateGas = function () {
estimateGas,
selectedAddress,
data,
- setGasTotal,
+ updateGasTotal,
from,
tokenContract,
editingTransactionId,
@@ -110,7 +139,7 @@ SendTransactionScreen.prototype.updateGas = function () {
])
.then(([gasPrice, gas]) => {
const newGasTotal = getGasTotal(gas, gasPrice)
- setGasTotal(newGasTotal)
+ updateGasTotal(newGasTotal)
this.setState({ gasLoadingError: false })
})
.catch(err => {
@@ -118,7 +147,7 @@ SendTransactionScreen.prototype.updateGas = function () {
})
} else {
const newGasTotal = getGasTotal(gasLimit, gasPrice)
- setGasTotal(newGasTotal)
+ updateGasTotal(newGasTotal)
}
}
@@ -157,6 +186,139 @@ SendTransactionScreen.prototype.componentDidUpdate = function (prevProps) {
}
}
+SendTransactionScreen.prototype.renderErrorMessage = function (errorType) {
+ const { errors } = this.props
+ const errorMessage = errors[errorType]
+
+ return errorMessage
+ ? h('div.send-v2__error', [ errorMessage ])
+ : null
+}
+
+SendTransactionScreen.prototype.handleFromChange = async function (newFrom) {
+ const {
+ updateSendFrom,
+ tokenContract,
+ } = this.props
+
+ if (tokenContract) {
+ const usersToken = await tokenContract.balanceOf(newFrom.address)
+ this.updateSendTokenBalance(usersToken)
+ }
+ updateSendFrom(newFrom)
+}
+
+SendTransactionScreen.prototype.renderFromRow = function () {
+ const {
+ from,
+ fromAccounts,
+ conversionRate,
+ } = this.props
+
+ const { fromDropdownOpen } = this.state
+
+ return h('div.send-v2__form-row', [
+
+ h('div.send-v2__form-label', 'From:'),
+
+ h('div.send-v2__form-field', [
+ h(FromDropdown, {
+ dropdownOpen: fromDropdownOpen,
+ accounts: fromAccounts,
+ selectedAccount: from,
+ onSelect: newFrom => this.handleFromChange(newFrom),
+ openDropdown: () => this.setState({ fromDropdownOpen: true }),
+ closeDropdown: () => this.setState({ fromDropdownOpen: false }),
+ conversionRate,
+ }),
+ ]),
+
+ ])
+}
+
+SendTransactionScreen.prototype.handleToChange = function (to, nickname = '') {
+ const {
+ updateSendTo,
+ updateSendErrors,
+ } = this.props
+ let toError = null
+
+ if (!to) {
+ toError = this.context.t('required')
+ } else if (!isValidAddress(to)) {
+ toError = this.context.t('invalidAddressRecipient')
+ }
+
+ updateSendTo(to, nickname)
+ updateSendErrors({ to: toError })
+}
+
+SendTransactionScreen.prototype.renderToRow = function () {
+ const { toAccounts, errors, to, network } = this.props
+
+ const { toDropdownOpen } = this.state
+
+ return h('div.send-v2__form-row', [
+
+ h('div.send-v2__form-label', [
+
+ this.context.t('to'),
+
+ this.renderErrorMessage(this.context.t('to')),
+
+ ]),
+
+ h('div.send-v2__form-field', [
+ h(EnsInput, {
+ name: 'address',
+ placeholder: 'Recipient Address',
+ network,
+ to,
+ accounts: Object.entries(toAccounts).map(([key, account]) => account),
+ dropdownOpen: toDropdownOpen,
+ openDropdown: () => this.setState({ toDropdownOpen: true }),
+ closeDropdown: () => this.setState({ toDropdownOpen: false }),
+ onChange: this.handleToChange,
+ inError: Boolean(errors.to),
+ }),
+ ]),
+
+ ])
+}
+
+SendTransactionScreen.prototype.handleAmountChange = function (value) {
+ const amount = value
+ const { updateSendAmount, setMaxModeTo } = this.props
+
+ setMaxModeTo(false)
+ this.validateAmount(amount)
+ updateSendAmount(amount)
+}
+
+SendTransactionScreen.prototype.setAmountToMax = function () {
+ const {
+ from: { balance },
+ updateSendAmount,
+ updateSendErrors,
+ tokenBalance,
+ selectedToken,
+ gasTotal,
+ } = this.props
+ const { decimals } = selectedToken || {}
+ const multiplier = Math.pow(10, Number(decimals || 0))
+
+ const maxAmount = selectedToken
+ ? multiplyCurrencies(tokenBalance, multiplier, {toNumericBase: 'hex'})
+ : subtractCurrencies(
+ ethUtil.addHexPrefix(balance),
+ ethUtil.addHexPrefix(gasTotal),
+ { toNumericBase: 'hex' }
+ )
+
+ updateSendErrors({ amount: null })
+
+ updateSendAmount(maxAmount)
+}
SendTransactionScreen.prototype.validateAmount = function (value) {
const {
@@ -203,29 +365,291 @@ SendTransactionScreen.prototype.validateAmount = function (value) {
)
if (conversionRate && !sufficientBalance) {
- amountError = 'insufficientFunds'
+ amountError = this.context.t('insufficientFunds')
} else if (verifyTokenBalance && !sufficientTokens) {
- amountError = 'insufficientTokens'
+ amountError = this.context.t('insufficientTokens')
} else if (amountLessThanZero) {
- amountError = 'negativeETH'
+ amountError = this.context.t('negativeETH')
}
updateSendErrors({ amount: amountError })
}
+SendTransactionScreen.prototype.renderAmountRow = function () {
+ const {
+ selectedToken,
+ primaryCurrency = 'ETH',
+ convertedCurrency,
+ amountConversionRate,
+ errors,
+ amount,
+ setMaxModeTo,
+ maxModeOn,
+ gasTotal,
+ } = this.props
+
+ return h('div.send-v2__form-row', [
+
+ h('div.send-v2__form-label', [
+ 'Amount:',
+ this.renderErrorMessage('amount'),
+ !errors.amount && gasTotal && h('div.send-v2__amount-max', {
+ onClick: (event) => {
+ event.preventDefault()
+ setMaxModeTo(true)
+ this.setAmountToMax()
+ },
+ }, [ !maxModeOn ? this.context.t('max') : '' ]),
+ ]),
+
+ h('div.send-v2__form-field', [
+ h(CurrencyDisplay, {
+ inError: Boolean(errors.amount),
+ primaryCurrency,
+ convertedCurrency,
+ selectedToken,
+ value: amount || '0x0',
+ conversionRate: amountConversionRate,
+ handleChange: this.handleAmountChange,
+ }),
+ ]),
+
+ ])
+}
+
+SendTransactionScreen.prototype.renderGasRow = function () {
+ const {
+ conversionRate,
+ convertedCurrency,
+ showCustomizeGasModal,
+ gasTotal,
+ } = this.props
+ const { gasLoadingError } = this.state
+
+ return h('div.send-v2__form-row', [
+
+ h('div.send-v2__form-label', this.context.t('gasFee')),
+
+ h('div.send-v2__form-field', [
+
+ h(GasFeeDisplay, {
+ gasTotal,
+ conversionRate,
+ convertedCurrency,
+ onClick: showCustomizeGasModal,
+ gasLoadingError,
+ }),
+
+ ]),
+
+ ])
+}
+
+SendTransactionScreen.prototype.renderMemoRow = function () {
+ const { updateSendMemo, memo } = this.props
+
+ return h('div.send-v2__form-row', [
+
+ h('div.send-v2__form-label', 'Transaction Memo:'),
+
+ h('div.send-v2__form-field', [
+ h(MemoTextArea, {
+ memo,
+ onChange: (event) => updateSendMemo(event.target.value),
+ }),
+ ]),
+
+ ])
+}
+
+SendTransactionScreen.prototype.renderForm = function () {
+ return h(PageContainerContent, [
+ h('.send-v2__form', [
+ this.renderFromRow(),
+
+ this.renderToRow(),
+
+ this.renderAmountRow(),
+
+ this.renderGasRow(),
+ ]),
+ ])
+}
+
+SendTransactionScreen.prototype.renderFooter = function () {
+ const {
+ goHome,
+ clearSend,
+ gasTotal,
+ tokenBalance,
+ selectedToken,
+ errors: { amount: amountError, to: toError },
+ } = this.props
+
+ const missingTokenBalance = selectedToken && !tokenBalance
+ const noErrors = !amountError && toError === null
+
+ return h(PageContainerFooter, {
+ onCancel: () => {
+ clearSend()
+ goHome()
+ },
+ onSubmit: e => this.onSubmit(e),
+ disabled: !noErrors || !gasTotal || missingTokenBalance,
+ })
+}
+
SendTransactionScreen.prototype.render = function () {
- const { history } = this.props
+ const {
+ isToken,
+ clearSend,
+ goHome,
+ gasTotal,
+ tokenBalance,
+ selectedToken,
+ errors: { amount: amountError, to: toError },
+ } = this.props
+
+ const missingTokenBalance = selectedToken && !tokenBalance
+ const noErrors = !amountError && toError === null
return (
- h(PageContainer, [
+ h(PageContainer, {
+ title: isToken ? this.context.t('sendTokens') : this.context.t('sendETH'),
+ subtitle: this.context.t('onlySendToEtherAddress'),
+ onClose: () => {
+ clearSend()
+ goHome()
+ },
+ ContentComponent: this.renderForm,
+ onCancel: () => {
+ clearSend()
+ goHome()
+ },
+ onSubmit: e => this.onSubmit(e),
+ disabled: !noErrors || !gasTotal || missingTokenBalance,
+ })
+ // , [
- h(SendHeader),
+ // h(SendHeader),
- h(SendContent),
+ // this.renderForm(),
- h(SendFooter, { history }),
- ])
+ // this.renderFooter(),
+ // ])
)
}
+
+SendTransactionScreen.prototype.addToAddressBookIfNew = function (newAddress, nickname = '') {
+ const { toAccounts, addToAddressBook } = this.props
+ if (!toAccounts.find(({ address }) => newAddress === address)) {
+ // TODO: nickname, i.e. addToAddressBook(recipient, nickname)
+ addToAddressBook(newAddress, nickname)
+ }
+}
+
+SendTransactionScreen.prototype.getEditedTx = function () {
+ const {
+ from: {address: from},
+ to,
+ amount,
+ gasLimit: gas,
+ gasPrice,
+ selectedToken,
+ editingTransactionId,
+ unapprovedTxs,
+ } = this.props
+
+ const editingTx = {
+ ...unapprovedTxs[editingTransactionId],
+ txParams: {
+ from: ethUtil.addHexPrefix(from),
+ gas: ethUtil.addHexPrefix(gas),
+ gasPrice: ethUtil.addHexPrefix(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, {
+ value: ethUtil.addHexPrefix('0'),
+ to: ethUtil.addHexPrefix(selectedToken.address),
+ data,
+ })
+ } else {
+ const { data } = unapprovedTxs[editingTransactionId].txParams
+
+ Object.assign(editingTx.txParams, {
+ value: ethUtil.addHexPrefix(amount),
+ to: ethUtil.addHexPrefix(to),
+ data,
+ })
+
+ if (typeof editingTx.txParams.data === 'undefined') {
+ delete editingTx.txParams.data
+ }
+ }
+
+ return editingTx
+}
+
+SendTransactionScreen.prototype.onSubmit = function (event) {
+ event.preventDefault()
+ const {
+ from: {address: from},
+ to: _to,
+ amount,
+ gasLimit: gas,
+ gasPrice,
+ signTokenTx,
+ signTx,
+ updateTx,
+ selectedToken,
+ editingTransactionId,
+ toNickname,
+ errors: { amount: amountError, to: toError },
+ } = this.props
+
+ const noErrors = !amountError && toError === null
+
+ if (!noErrors) {
+ return
+ }
+
+ const to = ethUtil.addHexPrefix(_to)
+
+ this.addToAddressBookIfNew(to, toNickname)
+
+ if (editingTransactionId) {
+ const editedTx = this.getEditedTx()
+
+ updateTx(editedTx)
+ } else {
+
+ const txParams = {
+ from,
+ value: '0',
+ gas,
+ gasPrice,
+ }
+
+ if (!selectedToken) {
+ txParams.value = amount
+ txParams.to = to
+ }
+
+ Object.keys(txParams).forEach(key => {
+ txParams[key] = ethUtil.addHexPrefix(txParams[key])
+ })
+
+ selectedToken
+ ? signTokenTx(selectedToken.address, to, amount, txParams)
+ : signTx(txParams)
+ }
+}