aboutsummaryrefslogtreecommitdiffstats
path: root/ui/app/components/pages
diff options
context:
space:
mode:
authorAlexander Tseung <alextsg@gmail.com>2018-06-23 14:52:45 +0800
committerAlexander Tseung <alextsg@gmail.com>2018-07-07 07:27:08 +0800
commitea9d51e427b8e607e612a01629bebf153e516ad9 (patch)
tree6363cd72b7517442c718901cc8b8ed023d134081 /ui/app/components/pages
parentb4aaf30d6fe829f18dea68a5e6cc321b9fb00d4e (diff)
downloadtangerine-wallet-browser-ea9d51e427b8e607e612a01629bebf153e516ad9.tar
tangerine-wallet-browser-ea9d51e427b8e607e612a01629bebf153e516ad9.tar.gz
tangerine-wallet-browser-ea9d51e427b8e607e612a01629bebf153e516ad9.tar.bz2
tangerine-wallet-browser-ea9d51e427b8e607e612a01629bebf153e516ad9.tar.lz
tangerine-wallet-browser-ea9d51e427b8e607e612a01629bebf153e516ad9.tar.xz
tangerine-wallet-browser-ea9d51e427b8e607e612a01629bebf153e516ad9.tar.zst
tangerine-wallet-browser-ea9d51e427b8e607e612a01629bebf153e516ad9.zip
Refactor and redesign confirm transaction views
Diffstat (limited to 'ui/app/components/pages')
-rw-r--r--ui/app/components/pages/confirm-approve/confirm-approve.component.js30
-rw-r--r--ui/app/components/pages/confirm-approve/confirm-approve.container.js28
-rw-r--r--ui/app/components/pages/confirm-approve/index.js1
-rw-r--r--ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.component.js64
-rw-r--r--ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.container.js12
-rw-r--r--ui/app/components/pages/confirm-deploy-contract/index.js1
-rw-r--r--ui/app/components/pages/confirm-send-ether/confirm-send-ether.component.js31
-rw-r--r--ui/app/components/pages/confirm-send-ether/confirm-send-ether.container.js37
-rw-r--r--ui/app/components/pages/confirm-send-ether/index.js1
-rw-r--r--ui/app/components/pages/confirm-send-token/confirm-send-token.component.js39
-rw-r--r--ui/app/components/pages/confirm-send-token/confirm-send-token.container.js72
-rw-r--r--ui/app/components/pages/confirm-send-token/index.js1
-rw-r--r--ui/app/components/pages/confirm-send-token/index.scss19
-rw-r--r--ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js382
-rw-r--r--ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js95
-rw-r--r--ui/app/components/pages/confirm-transaction-base/index.js1
-rw-r--r--ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.component.js71
-rw-r--r--ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.constants.js2
-rw-r--r--ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.container.js11
-rw-r--r--ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.util.js12
-rw-r--r--ui/app/components/pages/confirm-transaction-switch/index.js2
-rw-r--r--ui/app/components/pages/confirm-transaction/confirm-transaction.component.js59
-rw-r--r--ui/app/components/pages/confirm-transaction/confirm-transaction.container.js19
-rw-r--r--ui/app/components/pages/confirm-transaction/index.js2
-rw-r--r--ui/app/components/pages/home.js94
-rw-r--r--ui/app/components/pages/index.scss2
26 files changed, 994 insertions, 94 deletions
diff --git a/ui/app/components/pages/confirm-approve/confirm-approve.component.js b/ui/app/components/pages/confirm-approve/confirm-approve.component.js
new file mode 100644
index 000000000..d775b0362
--- /dev/null
+++ b/ui/app/components/pages/confirm-approve/confirm-approve.component.js
@@ -0,0 +1,30 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import ConfirmTransactionBase from '../confirm-transaction-base'
+
+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,
+ }
+
+ render () {
+ const { toAddress, tokenAddress, tokenAmount, tokenSymbol } = this.props
+
+ return (
+ <ConfirmTransactionBase
+ toAddress={toAddress}
+ identiconAddress={tokenAddress}
+ title={`${tokenAmount} ${tokenSymbol}`}
+ warning={`By approving this action, you grant permission for this contract to spend up to ${tokenAmount} of your ${tokenSymbol}.`}
+ hideSubtitle
+ />
+ )
+ }
+}
diff --git a/ui/app/components/pages/confirm-approve/confirm-approve.container.js b/ui/app/components/pages/confirm-approve/confirm-approve.container.js
new file mode 100644
index 000000000..040e499ae
--- /dev/null
+++ b/ui/app/components/pages/confirm-approve/confirm-approve.container.js
@@ -0,0 +1,28 @@
+import { connect } from 'react-redux'
+import ConfirmApprove from './confirm-approve.component'
+
+const mapStateToProps = state => {
+ const { confirmTransaction } = state
+ const {
+ tokenData = {},
+ txData: { txParams: { to: tokenAddress } = {} } = {},
+ tokenProps: { tokenSymbol } = {},
+ } = confirmTransaction
+ const { params = [] } = tokenData
+
+ let toAddress = ''
+ let tokenAmount = ''
+
+ if (params && params.length === 2) {
+ [{ value: toAddress }, { value: tokenAmount }] = params
+ }
+
+ return {
+ toAddress,
+ tokenAddress,
+ tokenAmount,
+ tokenSymbol,
+ }
+}
+
+export default connect(mapStateToProps)(ConfirmApprove)
diff --git a/ui/app/components/pages/confirm-approve/index.js b/ui/app/components/pages/confirm-approve/index.js
new file mode 100644
index 000000000..791297be7
--- /dev/null
+++ b/ui/app/components/pages/confirm-approve/index.js
@@ -0,0 +1 @@
+export { default } from './confirm-approve.container'
diff --git a/ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.component.js b/ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.component.js
new file mode 100644
index 000000000..9bc0daab9
--- /dev/null
+++ b/ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.component.js
@@ -0,0 +1,64 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import ethUtil from 'ethereumjs-util'
+import ConfirmTransactionBase from '../confirm-transaction-base'
+
+export default class ConfirmDeployContract extends Component {
+ static contextTypes = {
+ t: PropTypes.func,
+ }
+
+ static propTypes = {
+ txData: PropTypes.object,
+ }
+
+ renderData () {
+ const { t } = this.context
+ const {
+ txData: {
+ origin,
+ txParams: {
+ data,
+ } = {},
+ } = {},
+ } = this.props
+
+ return (
+ <div className="confirm-page-container-content__data">
+ <div className="confirm-page-container-content__data-box">
+ <div className="confirm-page-container-content__data-field">
+ <div className="confirm-page-container-content__data-field-label">
+ { `${t('origin')}:` }
+ </div>
+ <div>
+ { origin }
+ </div>
+ </div>
+ <div className="confirm-page-container-content__data-field">
+ <div className="confirm-page-container-content__data-field-label">
+ { `${t('bytes')}:` }
+ </div>
+ <div>
+ { ethUtil.toBuffer(data).length }
+ </div>
+ </div>
+ </div>
+ <div className="confirm-page-container-content__data-box-label">
+ { `${t('hexData')}:` }
+ </div>
+ <div className="confirm-page-container-content__data-box">
+ { data }
+ </div>
+ </div>
+ )
+ }
+
+ render () {
+ return (
+ <ConfirmTransactionBase
+ action={this.context.t('contractDeployment')}
+ dataComponent={this.renderData()}
+ />
+ )
+ }
+}
diff --git a/ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.container.js b/ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.container.js
new file mode 100644
index 000000000..336ee83ea
--- /dev/null
+++ b/ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.container.js
@@ -0,0 +1,12 @@
+import { connect } from 'react-redux'
+import ConfirmDeployContract from './confirm-deploy-contract.component'
+
+const mapStateToProps = state => {
+ const { confirmTransaction: { txData } = {} } = state
+
+ return {
+ txData,
+ }
+}
+
+export default connect(mapStateToProps)(ConfirmDeployContract)
diff --git a/ui/app/components/pages/confirm-deploy-contract/index.js b/ui/app/components/pages/confirm-deploy-contract/index.js
new file mode 100644
index 000000000..c4fb01b52
--- /dev/null
+++ b/ui/app/components/pages/confirm-deploy-contract/index.js
@@ -0,0 +1 @@
+export { default } from './confirm-deploy-contract.container'
diff --git a/ui/app/components/pages/confirm-send-ether/confirm-send-ether.component.js b/ui/app/components/pages/confirm-send-ether/confirm-send-ether.component.js
new file mode 100644
index 000000000..c590bacf3
--- /dev/null
+++ b/ui/app/components/pages/confirm-send-ether/confirm-send-ether.component.js
@@ -0,0 +1,31 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import ConfirmTransactionBase from '../confirm-transaction-base'
+import { SEND_ROUTE } from '../../../routes'
+
+export default class ConfirmSendEther extends Component {
+ static contextTypes = {
+ t: PropTypes.func,
+ }
+
+ static propTypes = {
+ editTransaction: PropTypes.func,
+ history: PropTypes.object,
+ }
+
+ handleEdit ({ txData }) {
+ const { editTransaction, history } = this.props
+ editTransaction(txData)
+ history.push(SEND_ROUTE)
+ }
+
+ render () {
+ return (
+ <ConfirmTransactionBase
+ action={this.context.t('confirm')}
+ hideData
+ onEdit={confirmTransactionData => this.handleEdit(confirmTransactionData)}
+ />
+ )
+ }
+}
diff --git a/ui/app/components/pages/confirm-send-ether/confirm-send-ether.container.js b/ui/app/components/pages/confirm-send-ether/confirm-send-ether.container.js
new file mode 100644
index 000000000..898735d1a
--- /dev/null
+++ b/ui/app/components/pages/confirm-send-ether/confirm-send-ether.container.js
@@ -0,0 +1,37 @@
+import { connect } from 'react-redux'
+import { compose } from 'recompose'
+import { withRouter } from 'react-router-dom'
+import { updateSend } from '../../../actions'
+import { clearConfirmTransaction } from '../../../ducks/confirm-transaction.duck'
+import ConfirmSendEther from './confirm-send-ether.component'
+
+const mapDispatchToProps = dispatch => {
+ return {
+ editTransaction: txData => {
+ const { id, txParams } = txData
+ const {
+ gas: gasLimit,
+ gasPrice,
+ to,
+ value: amount,
+ } = txParams
+
+ dispatch(updateSend({
+ gasLimit,
+ gasPrice,
+ gasTotal: null,
+ to,
+ amount,
+ errors: { to: null, amount: null },
+ editingTransactionId: id && id.toString(),
+ }))
+
+ dispatch(clearConfirmTransaction())
+ },
+ }
+}
+
+export default compose(
+ withRouter,
+ connect(null, mapDispatchToProps)
+)(ConfirmSendEther)
diff --git a/ui/app/components/pages/confirm-send-ether/index.js b/ui/app/components/pages/confirm-send-ether/index.js
new file mode 100644
index 000000000..2d5767c39
--- /dev/null
+++ b/ui/app/components/pages/confirm-send-ether/index.js
@@ -0,0 +1 @@
+export { default } from './confirm-send-ether.container'
diff --git a/ui/app/components/pages/confirm-send-token/confirm-send-token.component.js b/ui/app/components/pages/confirm-send-token/confirm-send-token.component.js
new file mode 100644
index 000000000..46ad9ccab
--- /dev/null
+++ b/ui/app/components/pages/confirm-send-token/confirm-send-token.component.js
@@ -0,0 +1,39 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import ConfirmTransactionBase from '../confirm-transaction-base'
+import { SEND_ROUTE } from '../../../routes'
+
+export default class ConfirmSendToken extends Component {
+ static contextTypes = {
+ t: PropTypes.func,
+ }
+
+ static propTypes = {
+ history: PropTypes.object,
+ tokenAddress: PropTypes.string,
+ toAddress: PropTypes.string,
+ numberOfTokens: PropTypes.number,
+ tokenSymbol: PropTypes.string,
+ editTransaction: PropTypes.func,
+ }
+
+ handleEdit (confirmTransactionData) {
+ const { editTransaction, history } = this.props
+ editTransaction(confirmTransactionData)
+ history.push(SEND_ROUTE)
+ }
+
+ render () {
+ const { toAddress, tokenAddress, tokenSymbol, numberOfTokens } = this.props
+
+ return (
+ <ConfirmTransactionBase
+ toAddress={toAddress}
+ identiconAddress={tokenAddress}
+ title={`${numberOfTokens} ${tokenSymbol}`}
+ onEdit={confirmTransactionData => this.handleEdit(confirmTransactionData)}
+ hideSubtitle
+ />
+ )
+ }
+}
diff --git a/ui/app/components/pages/confirm-send-token/confirm-send-token.container.js b/ui/app/components/pages/confirm-send-token/confirm-send-token.container.js
new file mode 100644
index 000000000..2d7efeed6
--- /dev/null
+++ b/ui/app/components/pages/confirm-send-token/confirm-send-token.container.js
@@ -0,0 +1,72 @@
+import { connect } from 'react-redux'
+import { compose } from 'recompose'
+import { withRouter } from 'react-router-dom'
+import ConfirmSendToken from './confirm-send-token.component'
+import { calcTokenAmount } from '../../../token-util'
+import { clearConfirmTransaction } from '../../../ducks/confirm-transaction.duck'
+import { setSelectedToken, updateSend, showSendTokenPage } from '../../../actions'
+import { conversionUtil } from '../../../conversion-util'
+
+const mapStateToProps = state => {
+ const { confirmTransaction } = state
+ const {
+ tokenData = {},
+ tokenProps: { tokenSymbol, tokenDecimals } = {},
+ txData: { txParams: { to: tokenAddress } = {} } = {},
+ } = confirmTransaction
+ const { params = [] } = tokenData
+
+ let toAddress = ''
+ let tokenAmount = ''
+
+ if (params && params.length === 2) {
+ [{ value: toAddress }, { value: tokenAmount }] = params
+ }
+
+ const numberOfTokens = tokenAmount && tokenDecimals
+ ? calcTokenAmount(tokenAmount, tokenDecimals)
+ : 0
+
+ return {
+ toAddress,
+ tokenAddress,
+ tokenSymbol,
+ numberOfTokens,
+ }
+}
+
+const mapDispatchToProps = dispatch => {
+ return {
+ editTransaction: ({ txData, tokenData, tokenProps }) => {
+ const { txParams: { to: tokenAddress, gas: gasLimit, gasPrice } = {}, id } = txData
+ const { params = [] } = tokenData
+ const { value: to } = params[0] || {}
+ const { value: tokenAmountInDec } = params[1] || {}
+ const tokenAmountInHex = conversionUtil(tokenAmountInDec, {
+ fromNumericBase: 'dec',
+ toNumericBase: 'hex',
+ })
+ dispatch(setSelectedToken(tokenAddress))
+ dispatch(updateSend({
+ gasLimit,
+ gasPrice,
+ gasTotal: null,
+ to,
+ amount: tokenAmountInHex,
+ errors: { to: null, amount: null },
+ editingTransactionId: id && id.toString(),
+ token: {
+ ...tokenProps,
+ address: tokenAddress,
+ },
+ }))
+ dispatch(clearConfirmTransaction())
+ dispatch(showSendTokenPage())
+ },
+ }
+}
+
+export default compose(
+ withRouter,
+ connect(mapStateToProps, mapDispatchToProps)
+)(ConfirmSendToken)
diff --git a/ui/app/components/pages/confirm-send-token/index.js b/ui/app/components/pages/confirm-send-token/index.js
new file mode 100644
index 000000000..409b6ef3d
--- /dev/null
+++ b/ui/app/components/pages/confirm-send-token/index.js
@@ -0,0 +1 @@
+export { default } from './confirm-send-token.container'
diff --git a/ui/app/components/pages/confirm-send-token/index.scss b/ui/app/components/pages/confirm-send-token/index.scss
new file mode 100644
index 000000000..0476749f6
--- /dev/null
+++ b/ui/app/components/pages/confirm-send-token/index.scss
@@ -0,0 +1,19 @@
+.confirm-send-token {
+ &__title {
+ padding: 4px 0;
+ display: flex;
+ align-items: center;
+ }
+
+ &__identicon {
+ flex: 0 0 auto;
+ }
+
+ &__title-text {
+ font-size: 2.25rem;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ padding-left: 8px;
+ }
+}
diff --git a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js
new file mode 100644
index 000000000..3b60a5d5d
--- /dev/null
+++ b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js
@@ -0,0 +1,382 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import ConfirmPageContainer, { ConfirmDetailRow } from '../../confirm-page-container'
+import { formatCurrency, getHexGasTotal } from '../../../helpers/confirm-transaction/util'
+import { isBalanceSufficient } from '../../send_/send.utils'
+import { DEFAULT_ROUTE } from '../../../routes'
+import { conversionGreaterThan } from '../../../conversion-util'
+import { MIN_GAS_LIMIT_DEC } from '../../send_/send.constants'
+
+export default class ConfirmTransactionBase extends Component {
+ static contextTypes = {
+ t: PropTypes.func,
+ }
+
+ static propTypes = {
+ match: PropTypes.object,
+ history: PropTypes.object,
+ // Redux props
+ txData: PropTypes.object,
+ tokenData: PropTypes.object,
+ tokenProps: PropTypes.object,
+ isTxReprice: PropTypes.bool,
+ nonce: PropTypes.string,
+ fromName: PropTypes.string,
+ fromAddress: PropTypes.string,
+ toName: PropTypes.string,
+ toAddress: PropTypes.string,
+ transactionStatus: PropTypes.string,
+ ethTransactionAmount: PropTypes.string,
+ ethTransactionFee: PropTypes.string,
+ ethTransactionTotal: PropTypes.string,
+ fiatTransactionAmount: PropTypes.string,
+ fiatTransactionFee: PropTypes.string,
+ fiatTransactionTotal: PropTypes.string,
+ hexGasTotal: PropTypes.string,
+ balance: PropTypes.string,
+ currentCurrency: PropTypes.string,
+ conversionRate: PropTypes.number,
+ setTransactionToConfirm: PropTypes.func,
+ clearConfirmTransaction: PropTypes.func,
+ cancelTransaction: PropTypes.func,
+ clearSend: PropTypes.func,
+ sendTransaction: PropTypes.func,
+ editTransaction: PropTypes.func,
+ showCustomizeGasModal: PropTypes.func,
+ updateGasAndCalculate: PropTypes.func,
+ showTransactionConfirmedModal: PropTypes.func,
+ // Component props
+ action: PropTypes.string,
+ hideDetails: PropTypes.bool,
+ hideData: PropTypes.bool,
+ detailsComponent: PropTypes.node,
+ dataComponent: PropTypes.node,
+ summaryComponent: PropTypes.node,
+ contentComponent: PropTypes.node,
+ title: PropTypes.string,
+ subtitle: PropTypes.string,
+ hideSubtitle: PropTypes.bool,
+ valid: PropTypes.bool,
+ errorMessage: PropTypes.string,
+ warning: PropTypes.string,
+ identiconAddress: PropTypes.string,
+ onEdit: PropTypes.func,
+ onEditGas: PropTypes.func,
+ onCancel: PropTypes.func,
+ onSubmit: PropTypes.func,
+ }
+
+ componentDidMount () {
+ const { match: { params: { id } = {} }, setTransactionToConfirm } = this.props
+ setTransactionToConfirm(id)
+ }
+
+ componentDidUpdate (prevProps) {
+ const {
+ transactionStatus,
+ showTransactionConfirmedModal,
+ history,
+ clearConfirmTransaction,
+ match: { params: { id } = {} },
+ setTransactionToConfirm,
+ txData,
+ } = this.props
+
+ if (transactionStatus === 'dropped') {
+ showTransactionConfirmedModal({
+ onHide: () => {
+ clearConfirmTransaction()
+ history.push(DEFAULT_ROUTE)
+ },
+ })
+
+ return
+ }
+
+ if (id && id !== txData.id + '') {
+ setTransactionToConfirm(id)
+ }
+ }
+
+ getError () {
+ const INSUFFICIENT_FUNDS_ERROR = this.context.t('insufficientFunds')
+ const TRANSACTION_ERROR = this.context.t('transactionError')
+ const {
+ balance,
+ conversionRate,
+ hexGasTotal,
+ txData: {
+ simulationFails,
+ txParams: {
+ value: amount,
+ } = {},
+ } = {},
+ } = this.props
+
+ const insufficientBalance = balance && !isBalanceSufficient({
+ amount,
+ gasTotal: hexGasTotal || '0x0',
+ balance,
+ conversionRate,
+ })
+
+ if (insufficientBalance) {
+ return {
+ valid: false,
+ errorMessage: INSUFFICIENT_FUNDS_ERROR,
+ }
+ }
+
+ if (simulationFails) {
+ return {
+ valid: false,
+ errorMessage: TRANSACTION_ERROR,
+ }
+ }
+
+ return {
+ valid: true,
+ }
+ }
+
+ validateEditGas ({ gasLimit, gasPrice }) {
+ const { t } = this.context
+ const {
+ balance,
+ conversionRate,
+ txData: {
+ txParams: {
+ value: amount,
+ } = {},
+ } = {},
+ } = this.props
+
+ const INSUFFICIENT_FUNDS_ERROR = t('insufficientFunds')
+ const GAS_LIMIT_TOO_LOW_ERROR = t('gasLimitTooLow')
+
+ const gasTotal = getHexGasTotal({ gasLimit, gasPrice })
+ const hasSufficientBalance = isBalanceSufficient({
+ amount,
+ gasTotal,
+ balance,
+ conversionRate,
+ })
+
+ if (!hasSufficientBalance) {
+ return {
+ valid: false,
+ errorMessage: INSUFFICIENT_FUNDS_ERROR,
+ }
+ }
+
+ const gasLimitTooLow = gasLimit && conversionGreaterThan(
+ {
+ value: MIN_GAS_LIMIT_DEC,
+ fromNumericBase: 'dec',
+ conversionRate,
+ },
+ {
+ value: gasLimit,
+ fromNumericBase: 'hex',
+ },
+ )
+
+ if (gasLimitTooLow) {
+ return {
+ valid: false,
+ errorMessage: GAS_LIMIT_TOO_LOW_ERROR,
+ }
+ }
+
+ return {
+ valid: true,
+ }
+ }
+
+ handleEditGas () {
+ const { onEditGas, showCustomizeGasModal, txData, updateGasAndCalculate } = this.props
+
+ if (onEditGas) {
+ onEditGas()
+ } else {
+ showCustomizeGasModal({
+ txData,
+ onSubmit: txData => updateGasAndCalculate(txData),
+ validate: ({ gasLimit, gasPrice }) => this.validateEditGas({ gasLimit, gasPrice }),
+ })
+ }
+ }
+
+ renderDetails () {
+ const {
+ detailsComponent,
+ fiatTransactionFee,
+ ethTransactionFee,
+ currentCurrency,
+ fiatTransactionTotal,
+ ethTransactionTotal,
+ hideDetails,
+ } = this.props
+
+ if (hideDetails) {
+ return null
+ }
+
+ return (
+ detailsComponent || (
+ <div className="confirm-page-container-content__details">
+ <div className="confirm-page-container-content__gas-fee">
+ <ConfirmDetailRow
+ label="Gas Fee"
+ fiatFee={formatCurrency(fiatTransactionFee, currentCurrency)}
+ ethFee={ethTransactionFee}
+ headerText="Edit"
+ headerTextClassName="confirm-detail-row__header-text--edit"
+ onHeaderClick={() => this.handleEditGas()}
+ />
+ </div>
+ <div>
+ <ConfirmDetailRow
+ label="Total"
+ fiatFee={formatCurrency(fiatTransactionTotal, currentCurrency)}
+ ethFee={ethTransactionTotal}
+ headerText="Amount + Gas Fee"
+ headerTextClassName="confirm-detail-row__header-text--total"
+ fiatFeeColor="#2f9ae0"
+ />
+ </div>
+ </div>
+ )
+ )
+ }
+
+ renderData () {
+ const { t } = this.context
+ const {
+ txData: {
+ txParams: {
+ data,
+ } = {},
+ } = {},
+ tokenData: {
+ name,
+ params,
+ } = {},
+ hideData,
+ dataComponent,
+ } = this.props
+
+ if (hideData) {
+ return null
+ }
+
+ return dataComponent || (
+ <div className="confirm-page-container-content__data">
+ <div className="confirm-page-container-content__data-box-label">
+ {`${t('functionType')}:`}
+ <span className="confirm-page-container-content__function-type">
+ { name }
+ </span>
+ </div>
+ <div className="confirm-page-container-content__data-box">
+ { JSON.stringify(params, null, 2) }
+ </div>
+ <div className="confirm-page-container-content__data-box-label">
+ {`${t('hexData')}:`}
+ </div>
+ <div className="confirm-page-container-content__data-box">
+ { data }
+ </div>
+ </div>
+ )
+ }
+
+ handleEdit () {
+ const { txData, tokenData, tokenProps, onEdit } = this.props
+ onEdit({ txData, tokenData, tokenProps })
+ }
+
+ handleCancel () {
+ const { onCancel, txData, cancelTransaction, history, clearConfirmTransaction } = this.props
+
+ if (onCancel) {
+ onCancel(txData)
+ } else {
+ cancelTransaction(txData)
+ .then(() => {
+ clearConfirmTransaction()
+ history.push(DEFAULT_ROUTE)
+ })
+ }
+ }
+
+ handleSubmit () {
+ const { sendTransaction, clearConfirmTransaction, txData, history, onSubmit } = this.props
+
+ if (onSubmit) {
+ onSubmit(txData)
+ } else {
+ sendTransaction(txData)
+ .then(() => {
+ clearConfirmTransaction()
+ history.push(DEFAULT_ROUTE)
+ })
+ }
+ }
+
+ render () {
+ const {
+ isTxReprice,
+ fromName,
+ fromAddress,
+ toName,
+ toAddress,
+ tokenData,
+ ethTransactionAmount,
+ fiatTransactionAmount,
+ valid: propsValid,
+ errorMessage: propsErrorMessage,
+ currentCurrency,
+ action,
+ title,
+ subtitle,
+ hideSubtitle,
+ identiconAddress,
+ summaryComponent,
+ contentComponent,
+ onEdit,
+ nonce,
+ warning,
+ } = this.props
+
+ const { name } = tokenData
+ const fiatConvertedAmount = formatCurrency(fiatTransactionAmount, currentCurrency)
+ const { valid, errorMessage } = this.getError()
+
+ return (
+ <ConfirmPageContainer
+ fromName={fromName}
+ fromAddress={fromAddress}
+ toName={toName}
+ toAddress={toAddress}
+ showEdit={onEdit && !isTxReprice}
+ action={action || name}
+ title={title || `${fiatConvertedAmount} ${currentCurrency.toUpperCase()}`}
+ subtitle={subtitle || `\u2666 ${ethTransactionAmount}`}
+ hideSubtitle={hideSubtitle}
+ summaryComponent={summaryComponent}
+ detailsComponent={this.renderDetails()}
+ dataComponent={this.renderData()}
+ contentComponent={contentComponent}
+ nonce={nonce}
+ identiconAddress={identiconAddress}
+ errorMessage={propsErrorMessage || errorMessage}
+ warning={warning}
+ valid={propsValid || valid}
+ onEdit={() => this.handleEdit()}
+ onCancel={() => this.handleCancel()}
+ onSubmit={() => this.handleSubmit()}
+ />
+ )
+ }
+}
diff --git a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js
new file mode 100644
index 000000000..ea1a1d296
--- /dev/null
+++ b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js
@@ -0,0 +1,95 @@
+import { connect } from 'react-redux'
+import { compose } from 'recompose'
+import { withRouter } from 'react-router-dom'
+import R from 'ramda'
+import ConfirmTransactionBase from './confirm-transaction-base.component'
+import {
+ setTransactionToConfirm,
+ clearConfirmTransaction,
+ updateGasAndCalculate,
+} from '../../../ducks/confirm-transaction.duck'
+import { clearSend, cancelTx, updateAndApproveTx, showModal } from '../../../actions'
+
+const mapStateToProps = (state, props) => {
+ const { toAddress: propsToAddress } = props
+ const { confirmTransaction, metamask } = state
+ const {
+ ethTransactionAmount,
+ ethTransactionFee,
+ ethTransactionTotal,
+ fiatTransactionAmount,
+ fiatTransactionFee,
+ fiatTransactionTotal,
+ hexGasTotal,
+ tokenData,
+ txData,
+ tokenProps,
+ nonce,
+ } = confirmTransaction
+ const { txParams = {}, lastGasPrice, id: transactionId } = txData
+ const { from: fromAddress, to: txParamsToAddress } = txParams
+ const {
+ conversionRate,
+ identities,
+ currentCurrency,
+ accounts,
+ selectedAddress,
+ selectedAddressTxList,
+ } = metamask
+
+ const { balance } = accounts[selectedAddress]
+ const { name: fromName } = identities[selectedAddress]
+ const toAddress = propsToAddress || txParamsToAddress
+ const toName = identities[toAddress] && identities[toAddress].name
+ const isTxReprice = Boolean(lastGasPrice)
+
+ const transaction = R.find(({ id }) => id === transactionId)(selectedAddressTxList)
+ const transactionStatus = transaction ? transaction.status : ''
+
+ return {
+ balance,
+ fromAddress,
+ fromName,
+ toAddress,
+ toName,
+ ethTransactionAmount,
+ ethTransactionFee,
+ ethTransactionTotal,
+ fiatTransactionAmount,
+ fiatTransactionFee,
+ fiatTransactionTotal,
+ hexGasTotal,
+ txData,
+ tokenData,
+ tokenProps,
+ isTxReprice,
+ currentCurrency,
+ conversionRate,
+ transactionStatus,
+ nonce,
+ }
+}
+
+const mapDispatchToProps = dispatch => {
+ return {
+ setTransactionToConfirm: transactionId => dispatch(setTransactionToConfirm(transactionId)),
+ clearConfirmTransaction: () => dispatch(clearConfirmTransaction()),
+ clearSend: () => dispatch(clearSend()),
+ showTransactionConfirmedModal: ({ onHide }) => {
+ return dispatch(showModal({ name: 'TRANSACTION_CONFIRMED', onHide }))
+ },
+ showCustomizeGasModal: ({ txData, onSubmit, validate }) => {
+ return dispatch(showModal({ name: 'CONFIRM_CUSTOMIZE_GAS', txData, onSubmit, validate }))
+ },
+ updateGasAndCalculate: ({ gasLimit, gasPrice }) => {
+ return dispatch(updateGasAndCalculate({ gasLimit, gasPrice }))
+ },
+ cancelTransaction: ({ id }) => dispatch(cancelTx({ id })),
+ sendTransaction: txData => dispatch(updateAndApproveTx(txData)),
+ }
+}
+
+export default compose(
+ withRouter,
+ connect(mapStateToProps, mapDispatchToProps)
+)(ConfirmTransactionBase)
diff --git a/ui/app/components/pages/confirm-transaction-base/index.js b/ui/app/components/pages/confirm-transaction-base/index.js
new file mode 100644
index 000000000..9996e9aeb
--- /dev/null
+++ b/ui/app/components/pages/confirm-transaction-base/index.js
@@ -0,0 +1 @@
+export { default } from './confirm-transaction-base.container'
diff --git a/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.component.js b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.component.js
new file mode 100644
index 000000000..5f337ab61
--- /dev/null
+++ b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.component.js
@@ -0,0 +1,71 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import { Redirect } from 'react-router-dom'
+import R from 'ramda'
+import Loading from '../../loading-screen'
+import {
+ CONFIRM_DEPLOY_CONTRACT_ROUTE,
+ CONFIRM_SEND_ETHER_ROUTE,
+ CONFIRM_SEND_TOKEN_ROUTE,
+ CONFIRM_APPROVE_ROUTE,
+ CONFIRM_TOKEN_METHOD_ROUTE,
+ SIGNATURE_REQUEST_ROUTE,
+} from '../../../routes'
+import { isConfirmDeployContract, getTokenData } from './confirm-transaction-switch.util'
+import { TOKEN_METHOD_TRANSFER, TOKEN_METHOD_APPROVE } from './confirm-transaction-switch.constants'
+
+export default class ConfirmTransactionSwitch extends Component {
+ static propTypes = {
+ unconfirmedTransactions: PropTypes.array,
+ match: PropTypes.object,
+ }
+
+ getTransaction () {
+ const { unconfirmedTransactions, match } = this.props
+ const { params: { id: paramsTransactionId } = {} } = match
+
+ return paramsTransactionId
+ ? R.find(({ id }) => id + '' === paramsTransactionId)(unconfirmedTransactions)
+ : unconfirmedTransactions[0]
+ }
+
+ redirectToTransaction (txData) {
+ const { id, txParams: { data } } = txData
+
+ if (isConfirmDeployContract(txData)) {
+ return <Redirect to={{ pathname: `${CONFIRM_DEPLOY_CONTRACT_ROUTE}/${id}` }} />
+ }
+
+ if (data) {
+ const tokenData = getTokenData(data)
+ const { name: tokenMethodName } = tokenData || {}
+
+ switch (tokenMethodName) {
+ case TOKEN_METHOD_TRANSFER:
+ return <Redirect to={{ pathname: `${CONFIRM_SEND_TOKEN_ROUTE}/${id}` }} />
+ case TOKEN_METHOD_APPROVE:
+ return <Redirect to={{ pathname: `${CONFIRM_APPROVE_ROUTE}/${id}` }} />
+ default:
+ return <Redirect to={{ pathname: `${CONFIRM_TOKEN_METHOD_ROUTE}/${id}` }} />
+ }
+ }
+
+ return <Redirect to={{ pathname: `${CONFIRM_SEND_ETHER_ROUTE}/${id}` }} />
+ }
+
+ render () {
+ const txData = this.getTransaction()
+
+ if (!txData) {
+ return <Loading />
+ }
+
+ if (txData.txParams) {
+ return this.redirectToTransaction(txData)
+ } else if (txData.msgParams) {
+ return <Redirect to={{ pathname: SIGNATURE_REQUEST_ROUTE }} />
+ }
+
+ return <Loading />
+ }
+}
diff --git a/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.constants.js b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.constants.js
new file mode 100644
index 000000000..622d2a37a
--- /dev/null
+++ b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.constants.js
@@ -0,0 +1,2 @@
+export const TOKEN_METHOD_TRANSFER = 'transfer'
+export const TOKEN_METHOD_APPROVE = 'approve'
diff --git a/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.container.js b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.container.js
new file mode 100644
index 000000000..cb6008acb
--- /dev/null
+++ b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.container.js
@@ -0,0 +1,11 @@
+import { connect } from 'react-redux'
+import ConfirmTransactionSwitch from './confirm-transaction-switch.component'
+import { unconfirmedTransactionsListSelector } from '../../../selectors/confirm-transaction'
+
+const mapStateToProps = state => {
+ return {
+ unconfirmedTransactions: unconfirmedTransactionsListSelector(state),
+ }
+}
+
+export default connect(mapStateToProps)(ConfirmTransactionSwitch)
diff --git a/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.util.js b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.util.js
new file mode 100644
index 000000000..dd1dec6ae
--- /dev/null
+++ b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.util.js
@@ -0,0 +1,12 @@
+import abi from 'human-standard-token-abi'
+import abiDecoder from 'abi-decoder'
+abiDecoder.addABI(abi)
+
+export function isConfirmDeployContract (txData = {}) {
+ const { txParams = {} } = txData
+ return !txParams.to
+}
+
+export function getTokenData (data = {}) {
+ return abiDecoder.decodeMethod(data)
+}
diff --git a/ui/app/components/pages/confirm-transaction-switch/index.js b/ui/app/components/pages/confirm-transaction-switch/index.js
new file mode 100644
index 000000000..c288acb1a
--- /dev/null
+++ b/ui/app/components/pages/confirm-transaction-switch/index.js
@@ -0,0 +1,2 @@
+import ConfirmTransactionSwitch from './confirm-transaction-switch.container'
+module.exports = ConfirmTransactionSwitch
diff --git a/ui/app/components/pages/confirm-transaction/confirm-transaction.component.js b/ui/app/components/pages/confirm-transaction/confirm-transaction.component.js
new file mode 100644
index 000000000..cc0b019e0
--- /dev/null
+++ b/ui/app/components/pages/confirm-transaction/confirm-transaction.component.js
@@ -0,0 +1,59 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import { Switch, Route } from 'react-router-dom'
+import ConfirmTransactionSwitch from '../confirm-transaction-switch'
+import ConfirmTransactionBase from '../confirm-transaction-base'
+import ConfirmSendEther from '../confirm-send-ether'
+import ConfirmSendToken from '../confirm-send-token'
+import ConfirmDeployContract from '../confirm-deploy-contract'
+import ConfirmApprove from '../confirm-approve'
+import ConfTx from '../../../conf-tx'
+import {
+ DEFAULT_ROUTE,
+ CONFIRM_TRANSACTION_ROUTE,
+ CONFIRM_DEPLOY_CONTRACT_ROUTE,
+ CONFIRM_SEND_ETHER_ROUTE,
+ CONFIRM_SEND_TOKEN_ROUTE,
+ CONFIRM_APPROVE_ROUTE,
+ CONFIRM_TOKEN_METHOD_ROUTE,
+ SIGNATURE_REQUEST_ROUTE,
+} from '../../../routes'
+
+export default class ConfirmTransaction extends Component {
+ static propTypes = {
+ history: PropTypes.object.isRequired,
+ totalUnapprovedCount: PropTypes.number.isRequired,
+ match: PropTypes.object,
+ send: PropTypes.object,
+ }
+
+ componentDidMount () {
+ const { totalUnapprovedCount = 0, send = {}, history } = this.props
+
+ if (!totalUnapprovedCount && !send.to) {
+ history.replace(DEFAULT_ROUTE)
+ }
+ }
+
+ render () {
+ return (
+ <Switch>
+ <Route
+ exact
+ path={`${CONFIRM_DEPLOY_CONTRACT_ROUTE}/:id?`}
+ component={ConfirmDeployContract}
+ />
+ <Route
+ exact
+ path={`${CONFIRM_TOKEN_METHOD_ROUTE}/:id?`}
+ component={ConfirmTransactionBase}
+ />
+ <Route exact path={`${CONFIRM_SEND_ETHER_ROUTE}/:id?`} component={ConfirmSendEther} />
+ <Route exact path={`${CONFIRM_SEND_TOKEN_ROUTE}/:id?`} component={ConfirmSendToken} />
+ <Route exact path={`${CONFIRM_APPROVE_ROUTE}/:id?`} component={ConfirmApprove} />
+ <Route exact path={SIGNATURE_REQUEST_ROUTE} component={ConfTx} />
+ <Route path={`${CONFIRM_TRANSACTION_ROUTE}/:id?`} component={ConfirmTransactionSwitch} />
+ </Switch>
+ )
+ }
+}
diff --git a/ui/app/components/pages/confirm-transaction/confirm-transaction.container.js b/ui/app/components/pages/confirm-transaction/confirm-transaction.container.js
new file mode 100644
index 000000000..6779e69b7
--- /dev/null
+++ b/ui/app/components/pages/confirm-transaction/confirm-transaction.container.js
@@ -0,0 +1,19 @@
+import { connect } from 'react-redux'
+import { compose } from 'recompose'
+import { withRouter } from 'react-router-dom'
+import ConfirmTransaction from './confirm-transaction.component'
+import { getTotalUnapprovedCount } from '../../../selectors'
+
+const mapStateToProps = (state, props) => {
+ const { metamask: { send } } = state
+
+ return {
+ totalUnapprovedCount: getTotalUnapprovedCount(state),
+ send,
+ }
+}
+
+export default compose(
+ withRouter,
+ connect(mapStateToProps),
+)(ConfirmTransaction)
diff --git a/ui/app/components/pages/confirm-transaction/index.js b/ui/app/components/pages/confirm-transaction/index.js
new file mode 100644
index 000000000..4bf42d85c
--- /dev/null
+++ b/ui/app/components/pages/confirm-transaction/index.js
@@ -0,0 +1,2 @@
+import ConfirmTransaction from './confirm-transaction.container'
+module.exports = ConfirmTransaction
diff --git a/ui/app/components/pages/home.js b/ui/app/components/pages/home.js
index c53413d3b..86bd32c8a 100644
--- a/ui/app/components/pages/home.js
+++ b/ui/app/components/pages/home.js
@@ -83,51 +83,6 @@ class Home extends Component {
})
}
- // if (!props.noActiveNotices) {
- // log.debug('rendering notice screen for unread notices.')
- // return h(NoticeScreen, {
- // notice: props.nextUnreadNotice,
- // key: 'NoticeScreen',
- // onConfirm: () => props.dispatch(actions.markNoticeRead(props.nextUnreadNotice)),
- // })
- // } else if (props.lostAccounts && props.lostAccounts.length > 0) {
- // log.debug('rendering notice screen for lost accounts view.')
- // return h(NoticeScreen, {
- // notice: generateLostAccountsNotice(props.lostAccounts),
- // key: 'LostAccountsNotice',
- // onConfirm: () => props.dispatch(actions.markAccountsFound()),
- // })
- // }
-
- // if (props.seedWords) {
- // log.debug('rendering seed words')
- // return h(HDCreateVaultComplete, {key: 'HDCreateVaultComplete'})
- // }
-
- // show initialize screen
- // if (!isInitialized || forgottenPassword) {
- // // show current view
- // log.debug('rendering an initialize screen')
- // // switch (props.currentView.name) {
-
- // // case 'restoreVault':
- // // log.debug('rendering restore vault screen')
- // // return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'})
-
- // // default:
- // // log.debug('rendering menu screen')
- // // return h(InitializeScreen, {key: 'menuScreenInit'})
- // // }
- // }
-
- // // show unlock screen
- // if (!props.isUnlocked) {
- // return h(MainContainer, {
- // currentViewName: props.currentView.name,
- // isUnlocked: props.isUnlocked,
- // })
- // }
-
// show current view
switch (currentView.name) {
@@ -135,59 +90,10 @@ class Home extends Component {
log.debug('rendering main container')
return h(MainContainer, {key: 'account-detail'})
- // case 'sendTransaction':
- // log.debug('rendering send tx screen')
-
- // // Going to leave this here until we are ready to delete SendTransactionScreen v1
- // // const SendComponentToRender = checkFeatureToggle('send-v2')
- // // ? SendTransactionScreen2
- // // : SendTransactionScreen
-
- // return h(SendTransactionScreen2, {key: 'send-transaction'})
-
- // case 'sendToken':
- // log.debug('rendering send token screen')
-
- // // Going to leave this here until we are ready to delete SendTransactionScreen v1
- // // const SendTokenComponentToRender = checkFeatureToggle('send-v2')
- // // ? SendTransactionScreen2
- // // : SendTokenScreen
-
- // return h(SendTransactionScreen2, {key: 'sendToken'})
-
case 'newKeychain':
log.debug('rendering new keychain screen')
return h(NewKeyChainScreen, {key: 'new-keychain'})
- // case 'confTx':
- // log.debug('rendering confirm tx screen')
- // return h(Redirect, {
- // to: {
- // pathname: CONFIRM_TRANSACTION_ROUTE,
- // },
- // })
- // return h(ConfirmTxScreen, {key: 'confirm-tx'})
-
- // case 'add-token':
- // log.debug('rendering add-token screen from unlock screen.')
- // return h(AddTokenScreen, {key: 'add-token'})
-
- // case 'config':
- // log.debug('rendering config screen')
- // return h(Settings, {key: 'config'})
-
- // case 'import-menu':
- // log.debug('rendering import screen')
- // return h(Import, {key: 'import-menu'})
-
- // case 'reveal-seed-conf':
- // log.debug('rendering reveal seed confirmation screen')
- // return h(RevealSeedConfirmation, {key: 'reveal-seed-conf'})
-
- // case 'info':
- // log.debug('rendering info screen')
- // return h(Settings, {key: 'info', tab: 'info'})
-
case 'buyEth':
log.debug('rendering buy ether screen')
return h(BuyView, {key: 'buyEthView'})
diff --git a/ui/app/components/pages/index.scss b/ui/app/components/pages/index.scss
index b15c59863..8b333b6a8 100644
--- a/ui/app/components/pages/index.scss
+++ b/ui/app/components/pages/index.scss
@@ -3,3 +3,5 @@
@import './add-token/index';
@import './confirm-add-token/index';
+
+@import './confirm-send-token/index';