Improve styling in Confirmation Screen; Show decoded send token data

feature/default_network_editable
Chi Kei Chan 7 years ago
parent b64471833f
commit 8b5f2a95df
  1. 1
      app/scripts/popup-core.js
  2. 2
      package.json
  3. 1
      ui/app/actions.js
  4. 339
      ui/app/components/pending-tx.js
  5. 104
      ui/app/css/itcss/components/confirm.scss

@ -49,7 +49,6 @@ function setupControllerConnection (connectionStream, cb) {
}) })
connectionStream.pipe(accountManagerDnode).pipe(connectionStream) connectionStream.pipe(accountManagerDnode).pipe(connectionStream)
accountManagerDnode.once('remote', function (accountManager) { accountManagerDnode.once('remote', function (accountManager) {
console.log({ accountManager })
// setup push events // setup push events
accountManager.on = eventEmitter.on.bind(eventEmitter) accountManager.on = eventEmitter.on.bind(eventEmitter)
cb(null, accountManager) cb(null, accountManager)

@ -49,6 +49,7 @@
] ]
}, },
"dependencies": { "dependencies": {
"abi-decoder": "^1.0.8",
"async": "^2.5.0", "async": "^2.5.0",
"await-semaphore": "^0.1.1", "await-semaphore": "^0.1.1",
"babel-runtime": "^6.23.0", "babel-runtime": "^6.23.0",
@ -92,6 +93,7 @@
"gulp-eslint": "^4.0.0", "gulp-eslint": "^4.0.0",
"gulp-sass": "^3.1.0", "gulp-sass": "^3.1.0",
"hat": "0.0.3", "hat": "0.0.3",
"human-standard-token-abi": "^1.0.2",
"idb-global": "^2.1.0", "idb-global": "^2.1.0",
"identicon.js": "^2.3.1", "identicon.js": "^2.3.1",
"iframe": "^1.0.0", "iframe": "^1.0.0",

@ -194,7 +194,6 @@ module.exports = actions
var background = null var background = null
function _setBackgroundConnection (backgroundConnection) { function _setBackgroundConnection (backgroundConnection) {
background = backgroundConnection background = backgroundConnection
console.log({ background })
} }
function goHome () { function goHome () {

@ -1,12 +1,14 @@
const Component = require('react').Component const Component = require('react').Component
const { connect } = require('react-redux') const { connect } = require('react-redux')
const h = require('react-hyperscript') const h = require('react-hyperscript')
const abi = require('human-standard-token-abi')
const abiDecoder = require('abi-decoder')
abiDecoder.addABI(abi)
const inherits = require('util').inherits const inherits = require('util').inherits
const actions = require('../actions') const actions = require('../actions')
const clone = require('clone') const clone = require('clone')
const FiatValue = require('./fiat-value') const FiatValue = require('./fiat-value')
const Identicon = require('./identicon') const Identicon = require('./identicon')
const { setCurrentCurrency } = require('../actions')
const ethUtil = require('ethereumjs-util') const ethUtil = require('ethereumjs-util')
const BN = ethUtil.BN const BN = ethUtil.BN
@ -33,16 +35,19 @@ function mapStateToProps (state) {
conversionRate, conversionRate,
identities, identities,
} = state.metamask } = state.metamask
const accounts = state.metamask.accounts
const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0]
return { return {
conversionRate, conversionRate,
identities, identities,
selectedAddress,
} }
} }
function mapDispatchToProps (dispatch) { function mapDispatchToProps (dispatch) {
return { return {
setCurrentCurrencyToUSD: () => dispatch(setCurrentCurrency('USD')) setCurrentCurrencyToUSD: () => dispatch(actions.setCurrentCurrency('USD')),
backToAccountDetail: address => dispatch(actions.backToAccountDetail(address)),
} }
} }
@ -54,258 +59,242 @@ function PendingTx () {
txData: null, txData: null,
submitting: false, submitting: false,
} }
this.onSubmit = this.onSubmit.bind(this)
} }
PendingTx.prototype.componentWillMount = function () { PendingTx.prototype.componentWillMount = function () {
this.props.setCurrentCurrencyToUSD() this.props.setCurrentCurrencyToUSD()
} }
PendingTx.prototype.render = function () { PendingTx.prototype.getTotal = function () {
const props = this.props const { conversionRate } = this.props
const { blockGasLimit, conversionRate, identities } = props
const txMeta = this.gatherTxMeta() const txMeta = this.gatherTxMeta()
const txParams = txMeta.txParams || {} const txParams = txMeta.txParams || {}
const decodedData = txParams.data && abiDecoder.decodeMethod(txParams.data)
const { params = [] } = decodedData || {}
const { name, value } = params[1] || {}
const amountBn = name === '_value'
? new BN(value)
: hexToBn(txParams.value)
const USD = conversionUtil(amountBn, {
fromFormat: 'BN',
toCurrency: 'USD',
conversionRate,
})
const ETH = conversionUtil(amountBn, {
fromFormat: 'BN',
toCurrency: 'ETH',
conversionRate,
})
// Account Details return {
const address = txParams.from || props.selectedAddress USD,
const account = props.accounts[address] ETH,
const balance = account ? account.balance : '0x0' }
}
// recipient check PendingTx.prototype.getGasFee = function () {
const isValidAddress = !txParams.to || util.isValidAddress(txParams.to) const { conversionRate } = this.props
const txMeta = this.gatherTxMeta()
const txParams = txMeta.txParams || {}
// Gas // Gas
const gas = txParams.gas const gas = txParams.gas
const gasBn = hexToBn(gas) const gasBn = hexToBn(gas)
// Gas Price // Gas Price
const gasPrice = txParams.gasPrice || MIN_GAS_PRICE_BN.toString(16) const gasPrice = txParams.gasPrice || MIN_GAS_PRICE_BN.toString(16)
const gasPriceBn = hexToBn(gasPrice) const gasPriceBn = hexToBn(gasPrice)
const txFeeBn = gasBn.mul(gasPriceBn) const txFeeBn = gasBn.mul(gasPriceBn)
const amountBn = hexToBn(txParams.value) const USD = conversionUtil(txFeeBn, {
// TODO: insufficient balance should be handled on send screen
// const maxCost = txFeeBn.add(amountBn)
// const balanceBn = hexToBn(balance)
// const insufficientBalance = balanceBn.lt(maxCost)
const fromName = identities[txParams.from].name
const to = identities[txParams.to]
const toName = to ? to.name : ' '
const endOfFromAddress = txParams.from.slice(txParams.from.length - 4)
const endOfToAddress = txParams.to.slice(txParams.to.length - 4)
const gasFeeInUSD = conversionUtil(txFeeBn, {
fromFormat: 'BN', fromFormat: 'BN',
fromCurrency: 'GWEI', fromCurrency: 'GWEI',
toCurrency: 'USD', toCurrency: 'USD',
conversionRate, conversionRate,
}) })
const gasFeeInETH = conversionUtil(txFeeBn, { const ETH = conversionUtil(txFeeBn, {
fromFormat: 'BN', fromFormat: 'BN',
fromCurrency: 'GWEI', fromCurrency: 'GWEI',
toCurrency: 'ETH', toCurrency: 'ETH',
conversionRate, conversionRate,
}) })
const totalInUSD = conversionUtil(amountBn, { return {
fromFormat: 'BN', USD,
toCurrency: 'USD', ETH,
conversionRate, }
}) }
const totalInETH = conversionUtil(amountBn, {
fromFormat: 'BN', PendingTx.prototype.getData = function () {
toCurrency: 'ETH', const { identities } = this.props
conversionRate, const txMeta = this.gatherTxMeta()
}) const txParams = txMeta.txParams || {}
const decodedData = txParams.data && abiDecoder.decodeMethod(txParams.data)
const { name, params = [] } = decodedData || {}
const { type, value } = params[0] || {}
const { USD: gasFeeInUSD, ETH: gasFeeInETH } = this.getGasFee()
const { USD: totalInUSD, ETH: totalInETH } = this.getTotal()
if (name === 'transfer' && type === 'address') {
return {
from: {
address: txParams.from,
name: identities[txParams.from].name,
},
to: {
address: value,
name: identities[value] ? identities[value].name : 'New Recipient',
},
memo: txParams.memo || '',
gasFeeInUSD,
gasFeeInETH,
totalInUSD,
totalInETH,
}
} else {
return {
from: {
address: txParams.from,
name: identities[txParams.from].name,
},
to: {
address: txParams.to,
name: identities[txParams.to] ? identities[txParams.to].name : 'New Recipient',
},
memo: txParams.memo || '',
gasFeeInUSD,
gasFeeInETH,
totalInUSD,
totalInETH,
}
}
}
PendingTx.prototype.render = function () {
const { backToAccountDetail, selectedAddress } = this.props
const txMeta = this.gatherTxMeta()
const txParams = txMeta.txParams || {}
// recipient check
// const isValidAddress = !txParams.to || util.isValidAddress(txParams.to)
const {
from: {
address: fromAddress,
name: fromName,
},
to: {
address: toAddress,
name: toName,
},
memo,
gasFeeInUSD,
gasFeeInETH,
totalInUSD,
totalInETH,
} = this.getData()
this.inputs = [] this.inputs = []
return ( return (
h('div.flex-column.flex-grow.confirm-screen-container', { h('div.flex-column.flex-grow.confirm-screen-container', {
style: { style: { minWidth: '355px' },
// overflow: 'scroll',
minWidth: '355px', // TODO: maxWidth TBD, use home.html
},
}, [ }, [
// Main Send token Card // Main Send token Card
h('div.confirm-screen-wrapper.flex-column.flex-grow', {}, [ h('div.confirm-screen-wrapper.flex-column.flex-grow', [
h('h3.flex-center.confirm-screen-header', [
h('h3.flex-center.confirm-screen-header', {}, [ h('button.confirm-screen-back-button', {
onClick: () => backToAccountDetail(selectedAddress),
h('button.confirm-screen-back-button', {}, 'BACK'), }, 'BACK'),
h('div.confirm-screen-title', 'Confirm Transaction'),
h('div.confirm-screen-title', {}, 'Confirm Transaction'),
]), ]),
h('div.flex-row.flex-center.confirm-screen-identicons', [
h('div.flex-row.flex-center.confirm-screen-identicons', {}, [ h('div.confirm-screen-account-wrapper', [
h('div.confirm-screen-account-wrapper', {}, [
h( h(
Identicon, Identicon,
{ {
address: txParams.from, address: fromAddress,
diameter: 64, diameter: 100,
style: {},
}, },
), ),
h('span.confirm-screen-account-name', {}, fromName), h('span.confirm-screen-account-name', fromName),
h('span.confirm-screen-account-number', {}, endOfFromAddress), h('span.confirm-screen-account-number', fromAddress.slice(fromAddress.length - 4)),
]), ]),
h('i.fa.fa-arrow-right.fa-lg'), h('i.fa.fa-arrow-right.fa-lg'),
h('div.confirm-screen-account-wrapper', [
h('div.confirm-screen-account-wrapper', {}, [
h( h(
Identicon, Identicon,
{ {
address: txParams.to, address: txParams.to,
diameter: 64, diameter: 100,
style: {},
}, },
), ),
h('span.confirm-screen-account-name', {}, toName), h('span.confirm-screen-account-name', toName),
h('span.confirm-screen-account-number', {}, endOfToAddress), h('span.confirm-screen-account-number', toAddress.slice(toAddress.length - 4)),
]) ]),
]), ]),
h('h3.flex-center.confirm-screen-sending-to-message', { h('h3.flex-center.confirm-screen-sending-to-message', {
style: { style: {
textAlign: 'center', textAlign: 'center',
fontSize: '16px', fontSize: '16px',
} },
}, [ }, [
`You're sending to Recipient ...${endOfToAddress}` `You're sending to Recipient ...${toAddress.slice(toAddress.length - 4)}`,
]), ]),
h('h3.flex-center.confirm-screen-send-amount', {}, [`$${totalInUSD}`]), h('h3.flex-center.confirm-screen-send-amount', [`$${totalInUSD}`]),
h('h3.flex-center.confirm-screen-send-amount-currency', [ 'USD' ]),
h('h3.flex-center.confirm-screen-send-amount-currency', {}, [ h('div.flex-center.confirm-memo-wrapper', [
'USD', h('h3.confirm-screen-send-memo', [ memo ]),
]), ]),
h('div.flex-center.confirm-memo-wrapper', {}, h( h('div.confirm-screen-rows', [
'h3.confirm-screen-send-memo', {}, txParams.memo || 'Fake memo' h('section.flex-row.flex-center.confirm-screen-row', [
)), h('span.confirm-screen-label.confirm-screen-section-column', [ 'From' ]),
h('div.confirm-screen-section-column', [
// TODO: put this error message in the right place h('div.confirm-screen-row-info', fromName),
// props.error && h('span.error.flex-center', props.error), h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`),
h('section.flex-row.flex-center.confirm-screen-row', {
}, [
h('div', {
style: {
width: '50%',
},
}, [
h('span.confirm-screen-label', {}, [
'From',
]), ]),
]), ]),
h('div', { h('section.flex-row.flex-center.confirm-screen-row', [
style: { h('span.confirm-screen-label.confirm-screen-section-column', [ 'To' ]),
width: '50%', h('div.confirm-screen-section-column', [
}, h('div.confirm-screen-row-info', toName),
}, [ h('div.confirm-screen-row-detail', `...${toAddress.slice(toAddress.length - 4)}`),
h('div.confirm-screen-row-info', {}, fromName),
h('div.confirm-screen-row-detail', {}, `...${endOfFromAddress}`),
]),
]),
h('section.flex-row.flex-center.confirm-screen-row', {
}, [
h('div', {
style: {
width: '50%',
},
}, [
h('span.confirm-screen-label', {}, [
'To',
]), ]),
]), ]),
h('div', { h('section.flex-row.flex-center.confirm-screen-row', [
style: { h('span.confirm-screen-label.confirm-screen-section-column', [ 'Gas Fee' ]),
width: '50%', h('div.confirm-screen-section-column', [
}, h('div.confirm-screen-row-info', `$${gasFeeInUSD} USD`),
}, [
h('div.confirm-screen-row-info', {}, toName),
h('div.confirm-screen-row-detail', {}, `...${endOfToAddress}`), h('div.confirm-screen-row-detail', `${gasFeeInETH} ETH`),
]),
]),
h('section.flex-row.flex-center.confirm-screen-row', {
}, [
h('div', {
style: {
width: '50%',
},
}, [
h('span.confirm-screen-label', {}, [
'Gas Fee',
]), ]),
]), ]),
h('div', {
style: {
width: '50%',
},
}, [
h('div.confirm-screen-row-info', {}, `$${gasFeeInUSD} USD`),
h('div.confirm-screen-row-detail', {}, `${gasFeeInETH} ETH`),
]),
]),
h('section.flex-row.flex-center.confirm-screen-total-box ', {}, [ h('section.flex-row.flex-center.confirm-screen-total-box ', [
h('div', { h('div.confirm-screen-section-column', [
style: { h('span.confirm-screen-label', [ 'Total ' ]),
width: '50%', h('div.confirm-screen-total-box__subtitle', [ 'Amount + Gas' ]),
},
}, [
h('span.confirm-screen-label', {}, [
'Total ',
]), ]),
h('div', { h('div.confirm-screen-section-column', [
style: { h('div.confirm-screen-row-info', `$${totalInUSD} USD`),
textAlign: 'left', h('div.confirm-screen-row-detail', `${totalInETH} ETH`),
fontSize: '8px',
},
}, [
'Amount + Gas',
]), ]),
]),
]),
h('div', {
style: {
width: '50%',
},
}, [
h('div.confirm-screen-row-info', {}, `$${totalInUSD} USD`),
h('div.confirm-screen-row-detail', {}, `${totalInETH} ETH`),
]),
]), ]),
]), // end of container ]),
h('form#pending-tx-form.flex-column.flex-center', { h('form#pending-tx-form.flex-column.flex-center', {
onSubmit: this.onSubmit.bind(this), onSubmit: this.onSubmit,
}, [ }, [
// Reset Button // Reset Button
// h('button', { // h('button', {
@ -325,7 +314,7 @@ PendingTx.prototype.render = function () {
// Cancel Button // Cancel Button
h('button.cancel.btn-light.confirm-screen-cancel-button', {}, 'CANCEL'), h('button.cancel.btn-light.confirm-screen-cancel-button', {}, 'CANCEL'),
]), ]),
]) // end of minwidth wrapper ])
) )
} }

@ -4,6 +4,7 @@
@media screen and (max-width: 575px) { @media screen and (max-width: 575px) {
margin-top: 35px; margin-top: 35px;
width: 100%;
} }
@media screen and (min-width: 576px) { @media screen and (min-width: 576px) {
@ -14,30 +15,21 @@
.confirm-screen-wrapper { .confirm-screen-wrapper {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-width: 320px; align-items: center;
min-height: 753px;
z-index: 100; z-index: 100;
top: 5%; top: 5%;
font-family: 'DIN NEXT'; font-family: 'DIN NEXT';
margin-left: 3.5%;
margin-right: 3.5%;
background: $white; background: $white;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .08); box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .08);
padding-top: 20px; // padding: 20px 24px 32px;
padding-bottom: 31px; color: $scorpion;
width: 100%;
@media screen and (min-width: $break-large) { @media screen and (min-width: $break-large) {
width: 498px; width: 498px;
} }
} }
.confirm-screen-wrapper > h3,
.confirm-screen-wrapper > div,
.confirm-screen-wrapper > section {
margin-left: 23px;
margin-right: 23px;
}
.confirm-screen-wrapper > .confirm-screen-total-box { .confirm-screen-wrapper > .confirm-screen-total-box {
margin-left: 10px; margin-left: 10px;
margin-right: 10px; margin-right: 10px;
@ -48,6 +40,7 @@
} }
.confirm-screen-wrapper > .confirm-screen-header { .confirm-screen-wrapper > .confirm-screen-header {
@media screen and (max-width: $break-small) { @media screen and (max-width: $break-small) {
margin-left: 8px; margin-left: 8px;
} }
@ -56,23 +49,30 @@
.confirm-screen-header { .confirm-screen-header {
font-size: 26px; font-size: 26px;
position: relative; position: relative;
display: flex;
flex-flow: row nowrap;
align-items: center;
width: 100%;
padding: 20px 24px 0;
@media screen and (max-width: $break-small) { @media screen and (max-width: $break-small) {
font-size: 22px; font-size: 22px;
} }
} }
.confirm-screen-title { .confirm-screen-title {
line-height: 27px;
@media screen and (max-width: $break-small) { @media screen and (max-width: $break-small) {
margin-left: 22px; margin-left: 22px;
margin-right: 8px; margin-right: 8px;
} }
} }
.confirm-screen-back-button { .confirm-screen-back-button {
background: $white; background: $white;
border: 1px solid $dusty-gray; border: 1px solid $dusty-gray;
left: 0; left: 24px;
position: absolute; position: absolute;
text-align: center; text-align: center;
color: $black; color: $black;
@ -82,7 +82,7 @@
width: 54px; width: 54px;
@media screen and (max-width: $break-small) { @media screen and (max-width: $break-small) {
margin-right: 12px; margin-right: 12px;
} }
} }
@ -91,7 +91,12 @@
flex-direction: column; flex-direction: column;
} }
.confirm-screen-account-name, .confirm-screen-row-info { .confirm-screen-account-name {
margin-top: 12px;
}
.confirm-screen-account-name,
.confirm-screen-row-info {
font-size: 16px; font-size: 16px;
line-height: 24px; line-height: 24px;
color: $scorpion; color: $scorpion;
@ -106,11 +111,11 @@
} }
.confirm-screen-identicons { .confirm-screen-identicons {
margin-top: 48px; margin-top: 24px;
i { i {
align-self: start; align-self: start;
margin: 20px 14px 0 14px; margin: 42px 14px 0;
} }
} }
@ -118,13 +123,14 @@
text-align: center; text-align: center;
font-size: 16px; font-size: 16px;
margin-top: 30px; margin-top: 30px;
font-family: 'DIN NEXT Light';
} }
.confirm-screen-send-amount { .confirm-screen-send-amount {
font-size: 64px; font-size: 64px;
color: $scorpion; color: $scorpion;
margin-top: 12px; margin-top: 12px;
line-height: 60px; line-height: 60px;
text-align: center; text-align: center;
font-family: 'DIN NEXT Light'; font-family: 'DIN NEXT Light';
} }
@ -136,8 +142,9 @@
} }
.confirm-memo-wrapper { .confirm-memo-wrapper {
min-height: 24px;
width: 100%; width: 100%;
border-bottom: 1px solid $gallery; border-bottom: 1px solid $alto;
} }
.confirm-screen-send-memo { .confirm-screen-send-memo {
@ -147,11 +154,12 @@
text-align: center; text-align: center;
margin-top: 21px; margin-top: 21px;
margin-bottom: 18px; margin-bottom: 18px;
font-family: 'DIN NEXT Light';
} }
.confirm-screen-label { .confirm-screen-label {
font-size: 18px; font-size: 18px;
line-height: 25px; line-height: 40px;
color: $scorpion; color: $scorpion;
text-align: left; text-align: left;
} }
@ -163,32 +171,60 @@ section .confirm-screen-account-number,
text-align: left; text-align: left;
} }
.confirm-screen-rows {
display: flex;
flex-flow: column nowrap;
width: 100%;
padding: 0 24px 32px;
}
.confirm-screen-section-column {
flex: .5;
}
.confirm-screen-row { .confirm-screen-row {
margin-top: 15px; display: flex;
margin-bottom: 11.5px; flex-flow: row nowrap;
border-bottom: 1px solid $alto;
width: calc(100% - 24px);
align-items: center;
padding: 12px 0;
margin: 0 12px;
} }
.confirm-screen-row-detail { .confirm-screen-row-detail {
font-size: 12px; font-size: 12px;
line-height: 16px; line-height: 16px;
color: $dusty-gray; color: $dusty-gray;
font-family: 'DIN NEXT Light';
} }
.confirm-screen-total-box { .confirm-screen-total-box {
background-color: $wild-sand; background-color: $wild-sand;
border-radius: 8px; border-radius: 8px;
margin-left: 10px; padding: 22px 14px;
margin-right: 10px;
padding: 22px 14px 22px;
margin-bottom: 10px;
margin-top: 13px; margin-top: 13px;
.confirm-screen-label {
line-height: 18px;
}
.confirm-screen-row-detail {
color: $scorpion;
}
&__subtitle {
font-size: 14px;
line-height: 20px;
font-family: 'DIN NEXT Light';
}
} }
.confirm-screen-confirm-button { .confirm-screen-confirm-button {
height: 62px; height: 62px;
width: 216.88px; width: 216.88px;
border-radius: 2px; border-radius: 2px;
background-color: #02C9B1; background-color: #02c9b1;
font-size: 16px; font-size: 16px;
color: $white; color: $white;
text-align: center; text-align: center;
@ -218,7 +254,3 @@ section .confirm-screen-account-number,
#pending-tx-form { #pending-tx-form {
flex: 1 0 auto; flex: 1 0 auto;
} }
.confirm-screen-row + .confirm-screen-row {
border-top: 1px solid $gallery;
}

Loading…
Cancel
Save