aboutsummaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorDan Finlay <dan@danfinlay.com>2017-03-24 04:44:09 +0800
committerDan Finlay <dan@danfinlay.com>2017-03-24 04:44:09 +0800
commite7a3330b980b150d4b7eae9c628e4ad2b0a1af34 (patch)
tree374d64c1d26b323e466e972a53ad97bbcc9eaa4a /ui
parentde0d9af066d57f98580d53359a53271bf8760515 (diff)
downloadtangerine-wallet-browser-e7a3330b980b150d4b7eae9c628e4ad2b0a1af34.tar
tangerine-wallet-browser-e7a3330b980b150d4b7eae9c628e4ad2b0a1af34.tar.gz
tangerine-wallet-browser-e7a3330b980b150d4b7eae9c628e4ad2b0a1af34.tar.bz2
tangerine-wallet-browser-e7a3330b980b150d4b7eae9c628e4ad2b0a1af34.tar.lz
tangerine-wallet-browser-e7a3330b980b150d4b7eae9c628e4ad2b0a1af34.tar.xz
tangerine-wallet-browser-e7a3330b980b150d4b7eae9c628e4ad2b0a1af34.tar.zst
tangerine-wallet-browser-e7a3330b980b150d4b7eae9c628e4ad2b0a1af34.zip
Combine pending-tx-details component into pending-tx-details
These were only separated originally so we could make the notification-based TX approval work, which provided its own buttons. This two templates are logically highly coupled, and keeping them working while separate has been difficult at times, and has even required resorting to dubious practices, like using React's `refs` pattern. This combines them into one fairly large component, but I think it's ok, we can still break this up into components, just not the separation that it had previously.
Diffstat (limited to 'ui')
-rw-r--r--ui/app/components/pending-tx-details.js364
-rw-r--r--ui/app/components/pending-tx.js352
2 files changed, 346 insertions, 370 deletions
diff --git a/ui/app/components/pending-tx-details.js b/ui/app/components/pending-tx-details.js
deleted file mode 100644
index 375a50f22..000000000
--- a/ui/app/components/pending-tx-details.js
+++ /dev/null
@@ -1,364 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const extend = require('xtend')
-const ethUtil = require('ethereumjs-util')
-const BN = ethUtil.BN
-
-const MiniAccountPanel = require('./mini-account-panel')
-const EthBalance = require('./eth-balance')
-const util = require('../util')
-const addressSummary = util.addressSummary
-const nameForAddress = require('../../lib/contract-namer')
-const HexInput = require('./hex-as-decimal-input')
-
-const DEFAULT_GAS_PRICE_BN = new BN(20000000000, '10')
-const DEFAULT_GAS_PRICE = DEFAULT_GAS_PRICE_BN.toString(16)
-
-const MIN_GAS_PRICE_BN = new BN(20000000)
-
-module.exports = PendingTxDetails
-
-inherits(PendingTxDetails, Component)
-function PendingTxDetails () {
- Component.call(this)
- this.state = { valid: true }
-}
-
-const PTXP = PendingTxDetails.prototype
-
-PTXP.render = function () {
- var props = this.props
- var state = this.state || {}
- var txData = state.txMeta || props.txData
-
- var txParams = txData.txParams || {}
- var address = txParams.from || props.selectedAddress
- var identity = props.identities[address] || { address: address }
- var account = props.accounts[address]
- var balance = account ? account.balance : '0x0'
-
- const gas = (state.gas === undefined) ? txParams.gas : state.gas
- const gasPrice = (state.gasPrice === undefined) ? txData.gasPrice : state.gasPrice
-
- var txFee = state.txFee || txData.txFee || ''
- var txFeeBn = new BN(txFee, 16)
- var maxCost = state.maxCost || txData.maxCost || ''
- var dataLength = txParams.data ? (txParams.data.length - 2) / 2 : 0
- var imageify = props.imageifyIdenticons === undefined ? true : props.imageifyIdenticons
-
- log.debug(`rendering gas: ${gas}, gasPrice: ${gasPrice}, txFee: ${txFee}, maxCost: ${maxCost}`)
-
- return (
- h('div', [
-
- h('.flex-row.flex-center', {
- style: {
- maxWidth: '100%',
- },
- }, [
-
- h(MiniAccountPanel, {
- imageSeed: address,
- imageifyIdenticons: imageify,
- picOrder: 'right',
- }, [
- h('span.font-small', {
- style: {
- fontFamily: 'Montserrat Bold, Montserrat, sans-serif',
- },
- }, identity.name),
- h('span.font-small', {
- style: {
- fontFamily: 'Montserrat Light, Montserrat, sans-serif',
- },
- }, addressSummary(address, 6, 4, false)),
-
- h('span.font-small', {
- style: {
- fontFamily: 'Montserrat Light, Montserrat, sans-serif',
- },
- }, [
- h(EthBalance, {
- value: balance,
- inline: true,
- labelColor: '#F7861C',
- }),
- ]),
- ]),
-
- forwardCarrat(),
-
- this.miniAccountPanelForRecipient(),
- ]),
-
- h('style', `
- .table-box {
- margin: 7px 0px 0px 0px;
- width: 100%;
- }
- .table-box .row {
- margin: 0px;
- background: rgb(236,236,236);
- display: flex;
- justify-content: space-between;
- font-family: Montserrat Light, sans-serif;
- font-size: 13px;
- padding: 5px 25px;
- }
- .table-box .row .value {
- font-family: Montserrat Regular;
- }
- `),
-
- h('.table-box', [
-
- // Ether Value
- // Currently not customizable, but easily modified
- // in the way that gas and gasLimit currently are.
- h('.row', [
- h('.cell.label', 'Amount'),
- h(EthBalance, { value: txParams.value }),
- ]),
-
- // Gas Limit (customizable)
- h('.cell.row', [
- h('.cell.label', 'Gas Limit'),
- h('.cell.value', {
- }, [
- h(HexInput, {
- name: 'Gas Limit',
- value: gas,
- min: 21000, // The hard lower limit for gas.
- suffix: 'UNITS',
- style: {
- position: 'relative',
- top: '5px',
- },
- onChange: (newHex) => {
- log.info(`Gas limit changed to ${newHex}`)
- this.setState({ gas: newHex })
- },
- }),
- ]),
- ]),
-
- // Gas Price (customizable)
- h('.cell.row', [
- h('.cell.label', 'Gas Price'),
- h('.cell.value', {
- }, [
- h(HexInput, {
- name: 'Gas Price',
- value: gasPrice,
- suffix: 'WEI',
- min: MIN_GAS_PRICE_BN.toString(10),
- style: {
- position: 'relative',
- top: '5px',
- },
- onChange: (newHex) => {
- log.info(`Gas price changed to: ${newHex}`)
- this.setState({ gasPrice: newHex })
- },
- }),
- ]),
- ]),
-
- // Max Transaction Fee (calculated)
- h('.cell.row', [
- h('.cell.label', 'Max Transaction Fee'),
- h(EthBalance, { value: txFeeBn.toString(16) }),
- ]),
-
- h('.cell.row', {
- style: {
- fontFamily: 'Montserrat Regular',
- background: 'white',
- padding: '10px 25px',
- },
- }, [
- h('.cell.label', 'Max Total'),
- h('.cell.value', {
- style: {
- display: 'flex',
- alignItems: 'center',
- },
- }, [
- h(EthBalance, {
- value: maxCost.toString(16),
- inline: true,
- labelColor: 'black',
- fontSize: '16px',
- }),
- ]),
- ]),
-
- // Data size row:
- h('.cell.row', {
- style: {
- background: '#f7f7f7',
- paddingBottom: '0px',
- },
- }, [
- h('.cell.label'),
- h('.cell.value', {
- style: {
- fontFamily: 'Montserrat Light',
- fontSize: '11px',
- },
- }, `Data included: ${dataLength} bytes`),
- ]),
- ]), // End of Table
-
- ])
- )
-}
-
-PTXP.miniAccountPanelForRecipient = function () {
- var props = this.props
- var txData = props.txData
- var txParams = txData.txParams || {}
- var isContractDeploy = !('to' in txParams)
- var imageify = props.imageifyIdenticons === undefined ? true : props.imageifyIdenticons
-
- // If it's not a contract deploy, send to the account
- if (!isContractDeploy) {
- return h(MiniAccountPanel, {
- imageSeed: txParams.to,
- imageifyIdenticons: imageify,
- picOrder: 'left',
- }, [
- h('span.font-small', {
- style: {
- fontFamily: 'Montserrat Bold, Montserrat, sans-serif',
- },
- }, nameForAddress(txParams.to, props.identities)),
- h('span.font-small', {
- style: {
- fontFamily: 'Montserrat Light, Montserrat, sans-serif',
- },
- }, addressSummary(txParams.to, 6, 4, false)),
- ])
- } else {
- return h(MiniAccountPanel, {
- imageifyIdenticons: imageify,
- picOrder: 'left',
- }, [
-
- h('span.font-small', {
- style: {
- fontFamily: 'Montserrat Bold, Montserrat, sans-serif',
- },
- }, 'New Contract'),
-
- ])
- }
-}
-
-PTXP.componentDidUpdate = function (prevProps, previousState) {
- log.debug(`pending-tx-details componentDidUpdate`)
- const state = this.state || {}
- const prevState = previousState || {}
- const { gas, gasPrice } = state
-
- // Only if gas or gasPrice changed:
- if (!prevState ||
- (gas !== prevState.gas ||
- gasPrice !== prevState.gasPrice)) {
- log.debug(`recalculating gas since prev state change: ${JSON.stringify({ prevState, state })}`)
- this.calculateGas()
- }
-}
-
-PTXP.isValid = function () {
- return this.state.valid
-}
-
-PTXP.calculateGas = function () {
- const txMeta = this.gatherParams()
- log.debug(`pending-tx-details calculating gas for ${JSON.stringify(txMeta)}`)
-
- var txParams = txMeta.txParams
- var gasCost = new BN(ethUtil.stripHexPrefix(txParams.gas || txMeta.estimatedGas), 16)
- var gasPrice = new BN(ethUtil.stripHexPrefix(txParams.gasPrice || DEFAULT_GAS_PRICE), 16)
-
- const valid = !gasPrice.lt(MIN_GAS_PRICE_BN)
- this.props.validChanged(valid)
-
- var txFee = gasCost.mul(gasPrice)
- var txValue = new BN(ethUtil.stripHexPrefix(txParams.value || '0x0'), 16)
- var maxCost = txValue.add(txFee)
-
- const txFeeHex = '0x' + txFee.toString('hex')
- const maxCostHex = '0x' + maxCost.toString('hex')
- const gasPriceHex = '0x' + gasPrice.toString('hex')
-
- txMeta.txFee = txFeeHex
- txMeta.maxCost = maxCostHex
- txMeta.txParams.gasPrice = gasPriceHex
-
- const newState = {
- txFee: '0x' + txFee.toString('hex'),
- maxCost: '0x' + maxCost.toString('hex'),
- }
- log.info(`tx form updating local state with ${JSON.stringify(newState)}`)
- this.setState(newState)
-
- if (this.props.onTxChange) {
- this.props.onTxChange(txMeta)
- }
-}
-
-PTXP.resetGasFields = function () {
- log.debug(`pending-tx-details#resetGasFields`)
- const txData = this.props.txData
- this.setState({
- gas: txData.txParams.gas,
- gasPrice: txData.gasPrice,
- })
-}
-
-// After a customizable state value has been updated,
-PTXP.gatherParams = function () {
- log.debug(`pending-tx-details#gatherParams`)
- const props = this.props
- const state = this.state || {}
- const txData = state.txData || props.txData
- const txParams = txData.txParams
- const gas = state.gas || txParams.gas
- const gasPrice = state.gasPrice || txParams.gasPrice
- const resultTx = extend(txParams, {
- gas,
- gasPrice,
- })
- const resultTxMeta = extend(txData, {
- txParams: resultTx,
- })
- log.debug(`UI has computed tx params ${JSON.stringify(resultTx)}`)
- return resultTxMeta
-}
-
-PTXP.verifyGasParams = function () {
- // We call this in case the gas has not been modified at all
- if (!this.state) { return true }
- return this._notZeroOrEmptyString(this.state.gas) && this._notZeroOrEmptyString(this.state.gasPrice)
-}
-
-PTXP._notZeroOrEmptyString = function (obj) {
- return obj !== '' && obj !== '0x0'
-}
-
-function forwardCarrat () {
- return (
-
- h('img', {
- src: 'images/forward-carrat.svg',
- style: {
- padding: '5px 6px 0px 10px',
- height: '37px',
- },
- })
-
- )
-}
diff --git a/ui/app/components/pending-tx.js b/ui/app/components/pending-tx.js
index f6fb6f85e..f550c1d35 100644
--- a/ui/app/components/pending-tx.js
+++ b/ui/app/components/pending-tx.js
@@ -2,10 +2,25 @@ const Component = require('react').Component
const connect = require('react-redux').connect
const h = require('react-hyperscript')
const inherits = require('util').inherits
-const PendingTxDetails = require('./pending-tx-details')
const extend = require('xtend')
const actions = require('../actions')
+const ethUtil = require('ethereumjs-util')
+const BN = ethUtil.BN
+
+const MiniAccountPanel = require('./mini-account-panel')
+const EthBalance = require('./eth-balance')
+const util = require('../util')
+const addressSummary = util.addressSummary
+const nameForAddress = require('../../lib/contract-namer')
+const HexInput = require('./hex-as-decimal-input')
+
+const DEFAULT_GAS_PRICE_BN = new BN(20000000000, '10')
+const DEFAULT_GAS_PRICE = DEFAULT_GAS_PRICE_BN.toString(16)
+
+const MIN_GAS_PRICE_BN = new BN(20000000)
+
+
module.exports = connect(mapStateToProps)(PendingTx)
function mapStateToProps (state) {
@@ -22,12 +37,28 @@ function PendingTx () {
PendingTx.prototype.render = function () {
const props = this.props
- const newProps = extend(props, {
- ref: 'details',
- validChanged: this.validChanged.bind(this),
- })
const txData = props.txData
+ const state = this.state
+
+ const txParams = txData.txParams || {}
+ const address = txParams.from || props.selectedAddress
+ const identity = props.identities[address] || { address: address }
+ const account = props.accounts[address]
+ const balance = account ? account.balance : '0x0'
+
+ const gas = (state.gas === undefined) ? txParams.gas : state.gas
+ const gasPrice = (state.gasPrice === undefined) ? txData.gasPrice : state.gasPrice
+
+ const txFee = state.txFee || txData.txFee || ''
+ const txFeeBn = new BN(txFee, 16)
+ const maxCost = state.maxCost || txData.maxCost || ''
+ const dataLength = txParams.data ? (txParams.data.length - 2) / 2 : 0
+ const imageify = props.imageifyIdenticons === undefined ? true : props.imageifyIdenticons
+
+ console.log('miniaccountpanelforrecipient?')
+ console.dir(this.miniAccountPanelForRecipient)
+
return (
h('div', {
@@ -50,7 +81,168 @@ PendingTx.prototype.render = function () {
}, [
// tx info
- h(PendingTxDetails, newProps),
+ h('div', [
+
+ h('.flex-row.flex-center', {
+ style: {
+ maxWidth: '100%',
+ },
+ }, [
+
+ h(MiniAccountPanel, {
+ imageSeed: address,
+ imageifyIdenticons: imageify,
+ picOrder: 'right',
+ }, [
+ h('span.font-small', {
+ style: {
+ fontFamily: 'Montserrat Bold, Montserrat, sans-serif',
+ },
+ }, identity.name),
+ h('span.font-small', {
+ style: {
+ fontFamily: 'Montserrat Light, Montserrat, sans-serif',
+ },
+ }, addressSummary(address, 6, 4, false)),
+
+ h('span.font-small', {
+ style: {
+ fontFamily: 'Montserrat Light, Montserrat, sans-serif',
+ },
+ }, [
+ h(EthBalance, {
+ value: balance,
+ inline: true,
+ labelColor: '#F7861C',
+ }),
+ ]),
+ ]),
+
+ forwardCarrat(),
+
+ this.miniAccountPanelForRecipient(),
+ ]),
+
+ h('style', `
+ .table-box {
+ margin: 7px 0px 0px 0px;
+ width: 100%;
+ }
+ .table-box .row {
+ margin: 0px;
+ background: rgb(236,236,236);
+ display: flex;
+ justify-content: space-between;
+ font-family: Montserrat Light, sans-serif;
+ font-size: 13px;
+ padding: 5px 25px;
+ }
+ .table-box .row .value {
+ font-family: Montserrat Regular;
+ }
+ `),
+
+ h('.table-box', [
+
+ // Ether Value
+ // Currently not customizable, but easily modified
+ // in the way that gas and gasLimit currently are.
+ h('.row', [
+ h('.cell.label', 'Amount'),
+ h(EthBalance, { value: txParams.value }),
+ ]),
+
+ // Gas Limit (customizable)
+ h('.cell.row', [
+ h('.cell.label', 'Gas Limit'),
+ h('.cell.value', {
+ }, [
+ h(HexInput, {
+ name: 'Gas Limit',
+ value: gas,
+ min: 21000, // The hard lower limit for gas.
+ suffix: 'UNITS',
+ style: {
+ position: 'relative',
+ top: '5px',
+ },
+ onChange: (newHex) => {
+ log.info(`Gas limit changed to ${newHex}`)
+ this.setState({ gas: newHex })
+ },
+ }),
+ ]),
+ ]),
+
+ // Gas Price (customizable)
+ h('.cell.row', [
+ h('.cell.label', 'Gas Price'),
+ h('.cell.value', {
+ }, [
+ h(HexInput, {
+ name: 'Gas Price',
+ value: gasPrice,
+ suffix: 'WEI',
+ min: MIN_GAS_PRICE_BN.toString(10),
+ style: {
+ position: 'relative',
+ top: '5px',
+ },
+ onChange: (newHex) => {
+ log.info(`Gas price changed to: ${newHex}`)
+ this.setState({ gasPrice: newHex })
+ },
+ }),
+ ]),
+ ]),
+
+ // Max Transaction Fee (calculated)
+ h('.cell.row', [
+ h('.cell.label', 'Max Transaction Fee'),
+ h(EthBalance, { value: txFeeBn.toString(16) }),
+ ]),
+
+ h('.cell.row', {
+ style: {
+ fontFamily: 'Montserrat Regular',
+ background: 'white',
+ padding: '10px 25px',
+ },
+ }, [
+ h('.cell.label', 'Max Total'),
+ h('.cell.value', {
+ style: {
+ display: 'flex',
+ alignItems: 'center',
+ },
+ }, [
+ h(EthBalance, {
+ value: maxCost.toString(16),
+ inline: true,
+ labelColor: 'black',
+ fontSize: '16px',
+ }),
+ ]),
+ ]),
+
+ // Data size row:
+ h('.cell.row', {
+ style: {
+ background: '#f7f7f7',
+ paddingBottom: '0px',
+ },
+ }, [
+ h('.cell.label'),
+ h('.cell.value', {
+ style: {
+ fontFamily: 'Montserrat Light',
+ fontSize: '11px',
+ },
+ }, `Data included: ${dataLength} bytes`),
+ ]),
+ ]), // End of Table
+
+ ]),
h('style', `
.conf-buttons button {
@@ -118,3 +310,151 @@ PendingTx.prototype.render = function () {
PendingTx.prototype.validChanged = function (newValid) {
this.setState({ valid: newValid })
}
+
+PendingTx.prototype.miniAccountPanelForRecipient = function () {
+ const props = this.props
+ const txData = props.txData
+ const txParams = txData.txParams || {}
+ const isContractDeploy = !('to' in txParams)
+ const imageify = props.imageifyIdenticons === undefined ? true : props.imageifyIdenticons
+
+ // If it's not a contract deploy, send to the account
+ if (!isContractDeploy) {
+ return h(MiniAccountPanel, {
+ imageSeed: txParams.to,
+ imageifyIdenticons: imageify,
+ picOrder: 'left',
+ }, [
+ h('span.font-small', {
+ style: {
+ fontFamily: 'Montserrat Bold, Montserrat, sans-serif',
+ },
+ }, nameForAddress(txParams.to, props.identities)),
+ h('span.font-small', {
+ style: {
+ fontFamily: 'Montserrat Light, Montserrat, sans-serif',
+ },
+ }, addressSummary(txParams.to, 6, 4, false)),
+ ])
+ } else {
+ return h(MiniAccountPanel, {
+ imageifyIdenticons: imageify,
+ picOrder: 'left',
+ }, [
+
+ h('span.font-small', {
+ style: {
+ fontFamily: 'Montserrat Bold, Montserrat, sans-serif',
+ },
+ }, 'New Contract'),
+
+ ])
+ }
+}
+
+PendingTx.prototype.componentDidUpdate = function (prevProps, previousState) {
+ log.debug(`pending-tx-details componentDidUpdate`)
+ const state = this.state || {}
+ const prevState = previousState || {}
+ const { gas, gasPrice } = state
+
+ // Only if gas or gasPrice changed:
+ if (!prevState ||
+ (gas !== prevState.gas ||
+ gasPrice !== prevState.gasPrice)) {
+ log.debug(`recalculating gas since prev state change: ${JSON.stringify({ prevState, state })}`)
+ this.calculateGas()
+ }
+}
+
+PendingTx.prototype.isValid = function () {
+ return this.state.valid
+}
+
+PendingTx.prototype.calculateGas = function () {
+ const txMeta = this.gatherParams()
+ log.debug(`pending-tx-details calculating gas for ${JSON.stringify(txMeta)}`)
+
+ const txParams = txMeta.txParams
+ const gasCost = new BN(ethUtil.stripHexPrefix(txParams.gas || txMeta.estimatedGas), 16)
+ const gasPrice = new BN(ethUtil.stripHexPrefix(txParams.gasPrice || DEFAULT_GAS_PRICE), 16)
+
+ const valid = !gasPrice.lt(MIN_GAS_PRICE_BN)
+ this.validChanged(valid)
+
+ const txFee = gasCost.mul(gasPrice)
+ const txValue = new BN(ethUtil.stripHexPrefix(txParams.value || '0x0'), 16)
+ const maxCost = txValue.add(txFee)
+
+ const txFeeHex = '0x' + txFee.toString('hex')
+ const maxCostHex = '0x' + maxCost.toString('hex')
+ const gasPriceHex = '0x' + gasPrice.toString('hex')
+
+ txMeta.txFee = txFeeHex
+ txMeta.maxCost = maxCostHex
+ txMeta.txParams.gasPrice = gasPriceHex
+
+ const newState = {
+ txFee: '0x' + txFee.toString('hex'),
+ maxCost: '0x' + maxCost.toString('hex'),
+ }
+ log.info(`tx form updating local state with ${JSON.stringify(newState)}`)
+ this.setState(newState)
+
+ if (this.props.onTxChange) {
+ this.props.onTxChange(txMeta)
+ }
+}
+
+PendingTx.prototype.resetGasFields = function () {
+ log.debug(`pending-tx-details#resetGasFields`)
+ const txData = this.props.txData
+ this.setState({
+ gas: txData.txParams.gas,
+ gasPrice: txData.gasPrice,
+ })
+}
+
+// After a customizable state value has been updated,
+PendingTx.prototype.gatherParams = function () {
+ log.debug(`pending-tx-details#gatherParams`)
+ const props = this.props
+ const state = this.state || {}
+ const txData = state.txData || props.txData
+ const txParams = txData.txParams
+ const gas = state.gas || txParams.gas
+ const gasPrice = state.gasPrice || txParams.gasPrice
+ const resultTx = extend(txParams, {
+ gas,
+ gasPrice,
+ })
+ const resultTxMeta = extend(txData, {
+ txParams: resultTx,
+ })
+ log.debug(`UI has computed tx params ${JSON.stringify(resultTx)}`)
+ return resultTxMeta
+}
+
+PendingTx.prototype.verifyGasParams = function () {
+ // We call this in case the gas has not been modified at all
+ if (!this.state) { return true }
+ return this._notZeroOrEmptyString(this.state.gas) && this._notZeroOrEmptyString(this.state.gasPrice)
+}
+
+PendingTx.prototype._notZeroOrEmptyString = function (obj) {
+ return obj !== '' && obj !== '0x0'
+}
+
+function forwardCarrat () {
+ return (
+
+ h('img', {
+ src: 'images/forward-carrat.svg',
+ style: {
+ padding: '5px 6px 0px 10px',
+ height: '37px',
+ },
+ })
+
+ )
+}