aboutsummaryrefslogtreecommitdiffstats
path: root/ui/app/components
diff options
context:
space:
mode:
Diffstat (limited to 'ui/app/components')
-rw-r--r--ui/app/components/account-eth-balance.js140
-rw-r--r--ui/app/components/account-export.js9
-rw-r--r--ui/app/components/account-info-link.js2
-rw-r--r--ui/app/components/buy-button-subview.js106
-rw-r--r--ui/app/components/coinbase-form.js21
-rw-r--r--ui/app/components/copyButton.js4
-rw-r--r--ui/app/components/drop-menu-item.js10
-rw-r--r--ui/app/components/eth-balance.js27
-rw-r--r--ui/app/components/fiat-value.js71
-rw-r--r--ui/app/components/identicon.js30
-rw-r--r--ui/app/components/loading.js50
-rw-r--r--ui/app/components/mascot.js27
-rw-r--r--ui/app/components/network.js25
-rw-r--r--ui/app/components/notice.js110
-rw-r--r--ui/app/components/pending-msg.js9
-rw-r--r--ui/app/components/pending-tx-details.js87
-rw-r--r--ui/app/components/pending-tx.js32
-rw-r--r--ui/app/components/qr-code.js14
-rw-r--r--ui/app/components/range-slider.js58
-rw-r--r--ui/app/components/shapeshift-form.js27
-rw-r--r--ui/app/components/shift-list-item.js1
-rw-r--r--ui/app/components/tab-bar.js35
-rw-r--r--ui/app/components/tooltip.js8
-rw-r--r--ui/app/components/transaction-list-item-icon.js33
-rw-r--r--ui/app/components/transaction-list-item.js34
-rw-r--r--ui/app/components/transaction-list.js9
26 files changed, 614 insertions, 365 deletions
diff --git a/ui/app/components/account-eth-balance.js b/ui/app/components/account-eth-balance.js
deleted file mode 100644
index 8d693685f..000000000
--- a/ui/app/components/account-eth-balance.js
+++ /dev/null
@@ -1,140 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const connect = require('react-redux').connect
-const formatBalance = require('../util').formatBalance
-const generateBalanceObject = require('../util').generateBalanceObject
-const Tooltip = require('./tooltip.js')
-
-module.exports = connect(mapStateToProps)(EthBalanceComponent)
-
-function mapStateToProps (state) {
- return {
- conversionRate: state.metamask.conversionRate,
- conversionDate: state.metamask.conversionDate,
- currentFiat: state.metamask.currentFiat,
- }
-}
-
-inherits(EthBalanceComponent, Component)
-function EthBalanceComponent () {
- Component.call(this)
-}
-
-EthBalanceComponent.prototype.render = function () {
- var state = this.props
- var style = state.style
-
- const value = formatBalance(state.value, 6)
- var width = state.width
-
- return (
-
- h('.ether-balance', {
- style: style,
- }, [
- h('.ether-balance-amount', {
- style: {
- display: 'inline',
- width: width,
- },
- }, this.renderBalance(value, state)),
- ])
-
- )
-}
-EthBalanceComponent.prototype.renderBalance = function (value, state) {
- if (value === 'None') return value
- var balanceObj = generateBalanceObject(value, state.shorten ? 1 : 3)
- var balance, fiatDisplayNumber, fiatTooltipNumber
- var splitBalance = value.split(' ')
- var ethNumber = splitBalance[0]
- var ethSuffix = splitBalance[1]
-
-
- if (state.conversionRate !== 0) {
- fiatTooltipNumber = Number(splitBalance[0]) * state.conversionRate
- fiatDisplayNumber = fiatTooltipNumber.toFixed(2)
- } else {
- fiatDisplayNumber = 'N/A'
- }
-
- var fiatSuffix = state.currentFiat
-
- if (state.shorten) {
- balance = balanceObj.shortBalance
- } else {
- balance = balanceObj.balance
- }
-
- var label = balanceObj.label
-
- return (
- h('.flex-column', [
- h(Tooltip, {
- position: 'bottom',
- title: `${ethNumber} ${ethSuffix}`,
- }, [
- h('.flex-row', {
- style: {
- alignItems: 'flex-end',
- lineHeight: '13px',
- fontFamily: 'Montserrat Light',
- textRendering: 'geometricPrecision',
- marginBottom: '5px',
- },
- }, [
- h('div', {
- style: {
- width: '100%',
- textAlign: 'right',
- },
- }, balance),
- h('div', {
- style: {
- color: '#AEAEAE',
- marginLeft: '5px',
- },
- }, label),
- ]),
- ]),
- h(Tooltip, {
- position: 'bottom',
- title: `${fiatTooltipNumber} ${fiatSuffix}`,
- }, [
- fiatDisplay(fiatDisplayNumber, fiatSuffix),
- ]),
- ])
- )
-}
-
-function fiatDisplay (fiatDisplayNumber, fiatSuffix) {
- if (fiatDisplayNumber !== 'N/A') {
- return h('.flex-row', {
- style: {
- alignItems: 'flex-end',
- lineHeight: '13px',
- fontFamily: 'Montserrat Light',
- textRendering: 'geometricPrecision',
- },
- }, [
- h('div', {
- style: {
- width: '100%',
- textAlign: 'right',
- fontSize: '12px',
- color: '#333333',
- },
- }, fiatDisplayNumber),
- h('div', {
- style: {
- color: '#AEAEAE',
- marginLeft: '5px',
- fontSize: '12px',
- },
- }, fiatSuffix),
- ])
- } else {
- return h('div')
- }
-}
diff --git a/ui/app/components/account-export.js b/ui/app/components/account-export.js
index f36b9faeb..6d8b099a5 100644
--- a/ui/app/components/account-export.js
+++ b/ui/app/components/account-export.js
@@ -3,6 +3,7 @@ const h = require('react-hyperscript')
const inherits = require('util').inherits
const copyToClipboard = require('copy-to-clipboard')
const actions = require('../actions')
+const ethUtil = require('ethereumjs-util')
module.exports = ExportAccountView
@@ -61,7 +62,9 @@ ExportAccountView.prototype.render = function () {
if (accountExported) {
return h('div.privateKey', {
-
+ style: {
+ margin: '0 20px',
+ },
}, [
h('label', 'Your private key (click to copy):'),
h('p.error.cursor-pointer', {
@@ -72,9 +75,9 @@ ExportAccountView.prototype.render = function () {
width: '100%',
},
onClick: function (event) {
- copyToClipboard(accountDetail.privateKey)
+ copyToClipboard(ethUtil.stripHexPrefix(accountDetail.privateKey))
},
- }, accountDetail.privateKey),
+ }, ethUtil.stripHexPrefix(accountDetail.privateKey)),
h('button', {
onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)),
}, 'Done'),
diff --git a/ui/app/components/account-info-link.js b/ui/app/components/account-info-link.js
index 4fe3b8b5d..49c42e9ec 100644
--- a/ui/app/components/account-info-link.js
+++ b/ui/app/components/account-info-link.js
@@ -14,7 +14,7 @@ function AccountInfoLink () {
AccountInfoLink.prototype.render = function () {
const { selected, network } = this.props
- const title = 'View account on etherscan'
+ const title = 'View account on Etherscan'
const url = genAccountLink(selected, network)
if (!url) {
diff --git a/ui/app/components/buy-button-subview.js b/ui/app/components/buy-button-subview.js
index 742241e5b..3074bd7cd 100644
--- a/ui/app/components/buy-button-subview.js
+++ b/ui/app/components/buy-button-subview.js
@@ -6,16 +6,19 @@ const actions = require('../actions')
const CoinbaseForm = require('./coinbase-form')
const ShapeshiftForm = require('./shapeshift-form')
const extension = require('../../../app/scripts/lib/extension')
+const Loading = require('./loading')
+const TabBar = require('./tab-bar')
module.exports = connect(mapStateToProps)(BuyButtonSubview)
function mapStateToProps (state) {
return {
- selectedAccount: state.selectedAccount,
warning: state.appState.warning,
buyView: state.appState.buyView,
network: state.metamask.network,
provider: state.metamask.provider,
+ context: state.appState.currentView.context,
+ isSubLoading: state.appState.isSubLoading,
}
}
@@ -26,7 +29,7 @@ function BuyButtonSubview () {
BuyButtonSubview.prototype.render = function () {
const props = this.props
- const currentForm = props.buyView.formView
+ const isLoading = props.isSubLoading
return (
h('.buy-eth-section', [
@@ -38,7 +41,7 @@ BuyButtonSubview.prototype.render = function () {
},
}, [
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', {
- onClick: () => props.dispatch(actions.backToAccountDetail(props.selectedAccount)),
+ onClick: this.backButtonContext.bind(this),
style: {
position: 'absolute',
left: '10px',
@@ -46,43 +49,56 @@ BuyButtonSubview.prototype.render = function () {
}),
h('h2.page-subtitle', 'Buy Eth'),
]),
- h('h3.flex-row.text-transform-uppercase', {
- style: {
- background: '#EBEBEB',
- color: '#AEAEAE',
- paddingTop: '4px',
- justifyContent: 'space-around',
+
+ h(Loading, { isLoading }),
+
+ h(TabBar, {
+ tabs: [
+ {
+ content: [
+ 'Coinbase',
+ h('a', {
+ onClick: (event) => this.navigateTo('https://github.com/MetaMask/faq/blob/master/COINBASE.md'),
+ }, [
+ h('i.fa.fa-question-circle', {
+ style: {
+ margin: '0px 5px',
+ },
+ }),
+ ]),
+ ],
+ key: 'coinbase',
+ },
+ {
+ content: [
+ 'Shapeshift',
+ h('a', {
+ href: 'https://github.com/MetaMask/faq/blob/master/COINBASE.md',
+ onClick: (event) => this.navigateTo('https://info.shapeshift.io/about'),
+ }, [
+ h('i.fa.fa-question-circle', {
+ style: {
+ margin: '0px 5px',
+ },
+ }),
+ ]),
+ ],
+ key: 'shapeshift',
+ },
+ ],
+ defaultTab: 'coinbase',
+ tabSelected: (key) => {
+ switch (key) {
+ case 'coinbase':
+ props.dispatch(actions.coinBaseSubview())
+ break
+ case 'shapeshift':
+ props.dispatch(actions.shapeShiftSubview(props.provider.type))
+ break
+ }
},
- }, [
- h(currentForm.coinbase ? '.activeForm' : '.inactiveForm.pointer', {
- onClick: () => props.dispatch(actions.coinBaseSubview()),
- }, 'Coinbase'),
- h('a', {
- onClick: (event) => this.navigateTo('https://github.com/MetaMask/faq/blob/master/COINBASE.md'),
- }, [
- h('i.fa.fa-question-circle', {
- style: {
- position: 'relative',
- right: '33px',
- },
- }),
- ]),
- h(currentForm.shapeshift ? '.activeForm' : '.inactiveForm.pointer', {
- onClick: () => props.dispatch(actions.shapeShiftSubview(props.provider.type)),
- }, 'Shapeshift'),
+ }),
- h('a', {
- href: 'https://github.com/MetaMask/faq/blob/master/COINBASE.md',
- onClick: (event) => this.navigateTo('https://info.shapeshift.io/about'),
- }, [
- h('i.fa.fa-question-circle', {
- style: {
- position: 'relative',
- right: '28px',
- },
- }),
- ]),
- ]),
this.formVersionSubview(),
])
)
@@ -106,9 +122,9 @@ BuyButtonSubview.prototype.formVersionSubview = function () {
style: {
width: '225px',
},
- }, 'In order to access this feature please switch too the Main Network'),
- h('h3.text-transform-uppercase', 'or:'),
- this.props.network === '2' ? h('button.text-transform-uppercase', {
+ }, 'In order to access this feature, please switch to the Main Network'),
+ (this.props.network === '3') ? h('h3.text-transform-uppercase', 'or:') : null,
+ (this.props.network === '3') ? h('button.text-transform-uppercase', {
onClick: () => this.props.dispatch(actions.buyEth()),
style: {
marginTop: '15px',
@@ -121,3 +137,11 @@ BuyButtonSubview.prototype.formVersionSubview = function () {
BuyButtonSubview.prototype.navigateTo = function (url) {
extension.tabs.create({ url })
}
+
+BuyButtonSubview.prototype.backButtonContext = function () {
+ if (this.props.context === 'confTx') {
+ this.props.dispatch(actions.showConfTxPage(false))
+ } else {
+ this.props.dispatch(actions.goHome())
+ }
+}
diff --git a/ui/app/components/coinbase-form.js b/ui/app/components/coinbase-form.js
index efd05ec96..40f5719bb 100644
--- a/ui/app/components/coinbase-form.js
+++ b/ui/app/components/coinbase-form.js
@@ -7,16 +7,15 @@ const actions = require('../actions')
const isValidAddress = require('../util').isValidAddress
module.exports = connect(mapStateToProps)(CoinbaseForm)
-function mapStateToProps(state) {
+function mapStateToProps (state) {
return {
- selectedAccount: state.selectedAccount,
warning: state.appState.warning,
}
}
inherits(CoinbaseForm, Component)
-function CoinbaseForm() {
+function CoinbaseForm () {
Component.call(this)
}
@@ -72,7 +71,7 @@ CoinbaseForm.prototype.render = function () {
lineHeight: '13px',
},
},
- `there is a USD$ 5 a day max and a USD$ 50
+ `there is a USD$ 15 a day max and a USD$ 50
dollar limit per the life time of an account without a
coinbase account. A fee of 3.75% will be aplied to debit/credit cards.`),
@@ -116,15 +115,14 @@ CoinbaseForm.prototype.toCoinbase = function () {
props.dispatch(actions.buyEth(address, props.buyView.amount))
} else if (!isValidAmountforCoinBase(amount).valid) {
message = isValidAmountforCoinBase(amount).message
- return props.dispatch(actions.showWarning(message))
+ return props.dispatch(actions.displayWarning(message))
} else {
message = 'Receiving address is invalid.'
- return props.dispatch(actions.showWarning(message))
+ return props.dispatch(actions.displayWarning(message))
}
}
CoinbaseForm.prototype.renderLoading = function () {
-
return h('img', {
style: {
width: '27px',
@@ -134,18 +132,17 @@ CoinbaseForm.prototype.renderLoading = function () {
})
}
-function isValidAmountforCoinBase(amount) {
+function isValidAmountforCoinBase (amount) {
amount = parseFloat(amount)
-
if (amount) {
- if (amount <= 5 && amount > 0) {
+ if (amount <= 15 && amount > 0) {
return {
valid: true,
}
- } else if (amount > 5) {
+ } else if (amount > 15) {
return {
valid: false,
- message: 'The amount can not be greater then $5',
+ message: 'The amount can not be greater then $15',
}
} else {
return {
diff --git a/ui/app/components/copyButton.js b/ui/app/components/copyButton.js
index a01603585..a25d0719c 100644
--- a/ui/app/components/copyButton.js
+++ b/ui/app/components/copyButton.js
@@ -50,12 +50,10 @@ CopyButton.prototype.render = function () {
])
}
-CopyButton.prototype.debounceRestore = function() {
-
+CopyButton.prototype.debounceRestore = function () {
this.setState({ copied: true })
clearTimeout(this.timeout)
this.timeout = setTimeout(() => {
this.setState({ copied: false })
}, 850)
-
}
diff --git a/ui/app/components/drop-menu-item.js b/ui/app/components/drop-menu-item.js
index 0ca1988c6..9f002234e 100644
--- a/ui/app/components/drop-menu-item.js
+++ b/ui/app/components/drop-menu-item.js
@@ -32,17 +32,17 @@ DropMenuItem.prototype.render = function () {
}
DropMenuItem.prototype.activeNetworkRender = function () {
- let activeNetwork = this.props.activeNetworkRender
- let { provider } = this.props
- let providerType = provider ? provider.type : null
+ const activeNetwork = this.props.activeNetworkRender
+ const { provider } = this.props
+ const providerType = provider ? provider.type : null
if (activeNetwork === undefined) return
switch (this.props.label) {
case 'Main Ethereum Network':
if (providerType === 'mainnet') return h('.check', '✓')
break
- case 'Morden Test Network':
- if (activeNetwork === '2') return h('.check', '✓')
+ case 'Ropsten Test Network':
+ if (provider.type === 'testnet') return h('.check', '✓')
break
case 'Localhost 8545':
if (activeNetwork === 'http://localhost:8545') return h('.check', '✓')
diff --git a/ui/app/components/eth-balance.js b/ui/app/components/eth-balance.js
index 498873faa..57ca84564 100644
--- a/ui/app/components/eth-balance.js
+++ b/ui/app/components/eth-balance.js
@@ -4,6 +4,7 @@ const inherits = require('util').inherits
const formatBalance = require('../util').formatBalance
const generateBalanceObject = require('../util').generateBalanceObject
const Tooltip = require('./tooltip.js')
+const FiatValue = require('./fiat-value.js')
module.exports = EthBalanceComponent
@@ -13,11 +14,12 @@ function EthBalanceComponent () {
}
EthBalanceComponent.prototype.render = function () {
- var state = this.props
- var style = state.style
+ var props = this.props
+ let { value } = props
+ var style = props.style
var needsParse = this.props.needsParse !== undefined ? this.props.needsParse : true
- const value = formatBalance(state.value, 6, needsParse)
- var width = state.width
+ value = value ? formatBalance(value, 6, needsParse) : '...'
+ var width = props.width
return (
@@ -35,15 +37,17 @@ EthBalanceComponent.prototype.render = function () {
)
}
EthBalanceComponent.prototype.renderBalance = function (value) {
- var state = this.props
+ var props = this.props
if (value === 'None') return value
- var balanceObj = generateBalanceObject(value, state.shorten ? 1 : 3)
+ if (value === '...') return value
+ var balanceObj = generateBalanceObject(value, props.shorten ? 1 : 3)
var balance
var splitBalance = value.split(' ')
var ethNumber = splitBalance[0]
var ethSuffix = splitBalance[1]
+ const showFiat = 'showFiat' in props ? props.showFiat : true
- if (state.shorten) {
+ if (props.shorten) {
balance = balanceObj.shortBalance
} else {
balance = balanceObj.balance
@@ -55,8 +59,8 @@ EthBalanceComponent.prototype.renderBalance = function (value) {
h(Tooltip, {
position: 'bottom',
title: `${ethNumber} ${ethSuffix}`,
- }, [
- h('.flex-column', {
+ }, h('div.flex-column', [
+ h('.flex-row', {
style: {
alignItems: 'flex-end',
lineHeight: '13px',
@@ -74,9 +78,12 @@ EthBalanceComponent.prototype.renderBalance = function (value) {
style: {
color: ' #AEAEAE',
fontSize: '12px',
+ marginLeft: '5px',
},
}, label),
]),
- ])
+
+ showFiat ? h(FiatValue, { value: props.value }) : null,
+ ]))
)
}
diff --git a/ui/app/components/fiat-value.js b/ui/app/components/fiat-value.js
new file mode 100644
index 000000000..13ee48245
--- /dev/null
+++ b/ui/app/components/fiat-value.js
@@ -0,0 +1,71 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const connect = require('react-redux').connect
+const formatBalance = require('../util').formatBalance
+
+module.exports = connect(mapStateToProps)(FiatValue)
+
+function mapStateToProps (state) {
+ return {
+ conversionRate: state.metamask.conversionRate,
+ currentFiat: state.metamask.currentFiat,
+ }
+}
+
+inherits(FiatValue, Component)
+function FiatValue () {
+ Component.call(this)
+}
+
+FiatValue.prototype.render = function () {
+ const props = this.props
+ const value = formatBalance(props.value, 6)
+
+ if (value === 'None') return value
+ var fiatDisplayNumber, fiatTooltipNumber
+ var splitBalance = value.split(' ')
+
+ if (props.conversionRate !== 0) {
+ fiatTooltipNumber = Number(splitBalance[0]) * props.conversionRate
+ fiatDisplayNumber = fiatTooltipNumber.toFixed(2)
+ } else {
+ fiatDisplayNumber = 'N/A'
+ fiatTooltipNumber = 'Unknown'
+ }
+
+ var fiatSuffix = props.currentFiat
+
+ return fiatDisplay(fiatDisplayNumber, fiatSuffix)
+}
+
+function fiatDisplay (fiatDisplayNumber, fiatSuffix) {
+ if (fiatDisplayNumber !== 'N/A') {
+ return h('.flex-row', {
+ style: {
+ alignItems: 'flex-end',
+ lineHeight: '13px',
+ fontFamily: 'Montserrat Light',
+ textRendering: 'geometricPrecision',
+ },
+ }, [
+ h('div', {
+ style: {
+ width: '100%',
+ textAlign: 'right',
+ fontSize: '12px',
+ color: '#333333',
+ },
+ }, fiatDisplayNumber),
+ h('div', {
+ style: {
+ color: '#AEAEAE',
+ marginLeft: '5px',
+ fontSize: '12px',
+ },
+ }, fiatSuffix),
+ ])
+ } else {
+ return h('div')
+ }
+}
diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js
index 4b2bf899e..6d4871d02 100644
--- a/ui/app/components/identicon.js
+++ b/ui/app/components/identicon.js
@@ -16,8 +16,8 @@ function IdenticonComponent () {
}
IdenticonComponent.prototype.render = function () {
- var state = this.props
- var diameter = state.diameter || this.defaultDiameter
+ var props = this.props
+ var diameter = props.diameter || this.defaultDiameter
return (
h('div', {
key: 'identicon-' + this.props.address,
@@ -33,15 +33,31 @@ IdenticonComponent.prototype.render = function () {
}
IdenticonComponent.prototype.componentDidMount = function () {
- var state = this.props
- var address = state.address
+ var props = this.props
+ var address = props.address
if (!address) return
var container = findDOMNode(this)
- var diameter = state.diameter || this.defaultDiameter
- var imageify = state.imageify === undefined ? true : state.imageify
- var img = iconFactory.iconForAddress(address, diameter, imageify)
+ var diameter = props.diameter || this.defaultDiameter
+ var img = iconFactory.iconForAddress(address, diameter, false)
container.appendChild(img)
}
+IdenticonComponent.prototype.componentDidUpdate = function () {
+ var props = this.props
+ var address = props.address
+
+ if (!address) return
+
+ var container = findDOMNode(this)
+
+ var children = container.children
+ for (var i = 0; i < children.length; i++) {
+ container.removeChild(children[i])
+ }
+
+ var diameter = props.diameter || this.defaultDiameter
+ var img = iconFactory.iconForAddress(address, diameter, false)
+ container.appendChild(img)
+}
diff --git a/ui/app/components/loading.js b/ui/app/components/loading.js
new file mode 100644
index 000000000..88dc535df
--- /dev/null
+++ b/ui/app/components/loading.js
@@ -0,0 +1,50 @@
+const inherits = require('util').inherits
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
+
+
+inherits(LoadingIndicator, Component)
+module.exports = LoadingIndicator
+
+function LoadingIndicator () {
+ Component.call(this)
+}
+
+LoadingIndicator.prototype.render = function () {
+ const { isLoading, loadingMessage } = this.props
+
+ return (
+ h(ReactCSSTransitionGroup, {
+ className: 'css-transition-group',
+ transitionName: 'loader',
+ transitionEnterTimeout: 150,
+ transitionLeaveTimeout: 150,
+ }, [
+
+ isLoading ? h('div', {
+ style: {
+ zIndex: 10,
+ position: 'absolute',
+ display: 'flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ height: '100%',
+ width: '100%',
+ background: 'rgba(255, 255, 255, 0.5)',
+ },
+ }, [
+ h('img', {
+ src: 'images/loading.svg',
+ }),
+
+ showMessageIfAny(loadingMessage),
+ ]) : null,
+ ])
+ )
+}
+
+function showMessageIfAny (loadingMessage) {
+ if (!loadingMessage) return null
+ return h('span', loadingMessage)
+}
diff --git a/ui/app/components/mascot.js b/ui/app/components/mascot.js
index f2b00262b..f015d0c4d 100644
--- a/ui/app/components/mascot.js
+++ b/ui/app/components/mascot.js
@@ -14,9 +14,8 @@ function Mascot () {
pxNotRatio: true,
width: 200,
height: 200,
- staticImage: './images/icon-512.png',
})
- if (!this.logo.webGLSupport) return
+
this.refollowMouse = debounce(this.logo.setFollowMouse.bind(this.logo, true), 1000)
this.unfollowMouse = this.logo.setFollowMouse.bind(this.logo, false)
}
@@ -27,32 +26,25 @@ Mascot.prototype.render = function () {
// and we dont get that until render
this.handleAnimationEvents()
- return (
-
- h('#metamask-mascot-container')
-
- )
+ return h('#metamask-mascot-container', {
+ style: { zIndex: 2 },
+ })
}
Mascot.prototype.componentDidMount = function () {
var targetDivId = 'metamask-mascot-container'
var container = document.getElementById(targetDivId)
- if (!this.logo.webGLSupport) {
- var staticLogo = this.logo.staticLogo
- staticLogo.style.marginBottom = '40px'
- container.appendChild(staticLogo)
- } else {
- container.appendChild(this.logo.canvas)
- }
+ container.appendChild(this.logo.container)
}
Mascot.prototype.componentWillUnmount = function () {
- if (!this.logo.webGLSupport) return
- this.logo.canvas.remove()
+ this.animations = this.props.animationEventEmitter
+ this.animations.removeAllListeners()
+ this.logo.container.remove()
+ this.logo.stopAnimation()
}
Mascot.prototype.handleAnimationEvents = function () {
- if (!this.logo.webGLSupport) return
// only setup listeners once
if (this.animations) return
this.animations = this.props.animationEventEmitter
@@ -61,7 +53,6 @@ Mascot.prototype.handleAnimationEvents = function () {
}
Mascot.prototype.lookAt = function (target) {
- if (!this.logo.webGLSupport) return
this.unfollowMouse()
this.logo.lookAt(target)
this.refollowMouse()
diff --git a/ui/app/components/network.js b/ui/app/components/network.js
index 2f1bf639a..77805fd57 100644
--- a/ui/app/components/network.js
+++ b/ui/app/components/network.js
@@ -22,7 +22,6 @@ Network.prototype.render = function () {
let iconName, hoverText
if (networkNumber === 'loading') {
-
return h('img.network-indicator', {
title: 'Attempting to connect to blockchain.',
onClick: (event) => this.props.onClick(event),
@@ -32,23 +31,22 @@ Network.prototype.render = function () {
},
src: 'images/loading.svg',
})
-
} else if (providerName === 'mainnet') {
hoverText = 'Main Ethereum Network'
iconName = 'ethereum-network'
- } else if (parseInt(networkNumber) === 2) {
- hoverText = 'Morden Test Network'
- iconName = 'morden-test-network'
+ } else if (providerName === 'testnet') {
+ hoverText = 'Ropsten Test Network'
+ iconName = 'ropsten-test-network'
+ } else if (parseInt(networkNumber) === 3) {
+ hoverText = 'Ropsten Test Network'
+ iconName = 'ropsten-test-network'
} else {
hoverText = 'Unknown Private Network'
iconName = 'unknown-private-network'
}
+
return (
- h('#network_component.flex-center.pointer', {
- style: {
- marginRight: '-27px',
- marginLeft: '-3px',
- },
+ h('#network_component.pointer', {
title: hoverText,
onClick: (event) => this.props.onClick(event),
}, [
@@ -61,21 +59,20 @@ Network.prototype.render = function () {
style: {
color: '#039396',
}},
- 'Etherum Main Net'),
+ 'Ethereum Main Net'),
])
- case 'morden-test-network':
+ case 'ropsten-test-network':
return h('.network-indicator', [
h('.menu-icon.red-dot'),
h('.network-name', {
style: {
color: '#ff6666',
}},
- 'Morden Test Net'),
+ 'Ropsten Test Net'),
])
default:
return h('.network-indicator', [
h('i.fa.fa-question-circle.fa-lg', {
- ariaHidden: true,
style: {
margin: '10px',
color: 'rgb(125, 128, 130)',
diff --git a/ui/app/components/notice.js b/ui/app/components/notice.js
new file mode 100644
index 000000000..00db734d7
--- /dev/null
+++ b/ui/app/components/notice.js
@@ -0,0 +1,110 @@
+const inherits = require('util').inherits
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const ReactMarkdown = require('react-markdown')
+const linker = require('extension-link-enabler')
+const findDOMNode = require('react-dom').findDOMNode
+
+module.exports = Notice
+
+inherits(Notice, Component)
+function Notice () {
+ Component.call(this)
+}
+
+Notice.prototype.render = function () {
+ const { notice, onConfirm } = this.props
+ const { title, date, body } = notice
+
+ return (
+ h('.flex-column.flex-center.flex-grow', [
+ h('h3.flex-center.text-transform-uppercacse.terms-header', {
+ style: {
+ background: '#EBEBEB',
+ color: '#AEAEAE',
+ width: '100%',
+ fontSize: '20px',
+ textAlign: 'center',
+ padding: 6,
+ },
+ }, [
+ title,
+ ]),
+
+ h('h5.flex-center.text-transform-uppercacse.terms-header', {
+ style: {
+ background: '#EBEBEB',
+ color: '#AEAEAE',
+ marginBottom: 24,
+ width: '100%',
+ fontSize: '20px',
+ textAlign: 'center',
+ padding: 6,
+ },
+ }, [
+ date,
+ ]),
+
+ h('style', `
+
+ .markdown {
+ overflow-x: hidden;
+ }
+
+ .markdown h1, .markdown h2, .markdown h3 {
+ margin: 10px 0;
+ font-weight: bold;
+ }
+
+ .markdown strong {
+ font-weight: bold;
+ }
+ .markdown em {
+ font-style: italic;
+ }
+
+ .markdown p {
+ margin: 10px 0;
+ }
+
+ .markdown a {
+ color: #df6b0e;
+ }
+
+ `),
+
+ h('div.markdown', {
+ style: {
+ background: 'rgb(235, 235, 235)',
+ height: '310px',
+ padding: '6px',
+ width: '90%',
+ overflowY: 'scroll',
+ scroll: 'auto',
+ },
+ }, [
+ h(ReactMarkdown, {
+ source: body,
+ skipHtml: true,
+ }),
+ ]),
+
+ h('button', {
+ onClick: onConfirm,
+ style: {
+ marginTop: '18px',
+ },
+ }, 'Continue'),
+ ])
+ )
+}
+
+Notice.prototype.componentDidMount = function () {
+ var node = findDOMNode(this)
+ linker.setupListener(node)
+}
+
+Notice.prototype.componentWillUnmount = function () {
+ var node = findDOMNode(this)
+ linker.teardownListener(node)
+}
diff --git a/ui/app/components/pending-msg.js b/ui/app/components/pending-msg.js
index f4bde91dc..b2cac164a 100644
--- a/ui/app/components/pending-msg.js
+++ b/ui/app/components/pending-msg.js
@@ -28,6 +28,15 @@ PendingMsg.prototype.render = function () {
},
}, 'Sign Message'),
+ h('.error', {
+ style: {
+ margin: '10px',
+ },
+ }, `Signing this message can have
+ dangerous side effects. Only sign messages from
+ sites you fully trust with your entire account.
+ This will be fixed in a future version.`),
+
// message details
h(PendingTxDetails, state),
diff --git a/ui/app/components/pending-tx-details.js b/ui/app/components/pending-tx-details.js
index 2fb0eae3f..e8615404e 100644
--- a/ui/app/components/pending-tx-details.js
+++ b/ui/app/components/pending-tx-details.js
@@ -1,16 +1,12 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
-const carratInline = require('fs').readFileSync('./images/forward-carrat.svg', 'utf8')
const MiniAccountPanel = require('./mini-account-panel')
-const EtherBalance = require('./eth-balance')
-const addressSummary = require('../util').addressSummary
-const formatBalance = require('../util').formatBalance
+const EthBalance = require('./eth-balance')
+const util = require('../util')
+const addressSummary = util.addressSummary
const nameForAddress = require('../../lib/contract-namer')
-const ethUtil = require('ethereumjs-util')
-const BN = ethUtil.BN
-
module.exports = PendingTxDetails
@@ -31,13 +27,9 @@ PTXP.render = function () {
var account = props.accounts[address]
var balance = account ? account.balance : '0x0'
- var gasCost = new BN(ethUtil.stripHexPrefix(txParams.gas || txData.estimatedGas), 16)
- var gasPrice = new BN(ethUtil.stripHexPrefix(txParams.gasPrice || '0x4a817c800'), 16)
- var txFee = gasCost.mul(gasPrice)
- var txValue = new BN(ethUtil.stripHexPrefix(txParams.value || '0x0'), 16)
- var maxCost = txValue.add(txFee)
+ var txFee = txData.txFee || ''
+ var maxCost = txData.maxCost || ''
var dataLength = txParams.data ? (txParams.data.length - 2) / 2 : 0
-
var imageify = props.imageifyIdenticons === undefined ? true : props.imageifyIdenticons
return (
@@ -70,7 +62,7 @@ PTXP.render = function () {
fontFamily: 'Montserrat Light, Montserrat, sans-serif',
},
}, [
- h(EtherBalance, {
+ h(EthBalance, {
value: balance,
inline: true,
labelColor: '#F7861C',
@@ -79,7 +71,7 @@ PTXP.render = function () {
]),
- forwardCarrat(imageify),
+ forwardCarrat(),
this.miniAccountPanelForRecipient(),
]),
@@ -107,12 +99,12 @@ PTXP.render = function () {
h('.row', [
h('.cell.label', 'Amount'),
- h('.cell.value', formatBalance(txParams.value)),
+ h(EthBalance, { value: txParams.value }),
]),
h('.cell.row', [
h('.cell.label', 'Max Transaction Fee'),
- h('.cell.value', formatBalance(txFee.toString(16))),
+ h(EthBalance, { value: txFee.toString(16) }),
]),
h('.cell.row', {
@@ -129,7 +121,7 @@ PTXP.render = function () {
alignItems: 'center',
},
}, [
- h(EtherBalance, {
+ h(EthBalance, {
value: maxCost.toString(16),
inline: true,
labelColor: 'black',
@@ -154,8 +146,6 @@ PTXP.render = function () {
]),
]), // End of Table
- this.warnIfNeeded(),
-
])
)
}
@@ -201,53 +191,16 @@ PTXP.miniAccountPanelForRecipient = function () {
}
}
-// Should analyze if there is a DELEGATECALL opcode
-// in the recipient contract, and show a warning if so.
-PTXP.warnIfNeeded = function () {
- const containsDelegateCall = !!this.props.txData.containsDelegateCall
-
- if (!containsDelegateCall) {
- return null
- }
-
- return h('span.error', {
- style: {
- fontFamily: 'Montserrat Light',
- fontSize: '13px',
- display: 'flex',
- justifyContent: 'center',
- },
- }, [
- h('i.fa.fa-lg.fa-info-circle', { style: { margin: '5px' } }),
- h('span', ' Your identity may be used in other contracts!'),
- ])
-}
-
-
-function forwardCarrat (imageify) {
- if (imageify) {
- return (
-
- h('img', {
- src: 'images/forward-carrat.svg',
- style: {
- padding: '5px 6px 0px 10px',
- height: '37px',
- },
- })
+function forwardCarrat () {
+ return (
- )
- } else {
- return (
+ h('img', {
+ src: 'images/forward-carrat.svg',
+ style: {
+ padding: '5px 6px 0px 10px',
+ height: '37px',
+ },
+ })
- h('div', {
- dangerouslySetInnerHTML: { __html: carratInline },
- style: {
- padding: '0px 6px 0px 10px',
- height: '45px',
- },
- })
-
- )
- }
+ )
}
diff --git a/ui/app/components/pending-tx.js b/ui/app/components/pending-tx.js
index 1feedbbbc..96f968929 100644
--- a/ui/app/components/pending-tx.js
+++ b/ui/app/components/pending-tx.js
@@ -3,7 +3,6 @@ const h = require('react-hyperscript')
const inherits = require('util').inherits
const PendingTxDetails = require('./pending-tx-details')
-
module.exports = PendingTx
inherits(PendingTx, Component)
@@ -31,6 +30,24 @@ PendingTx.prototype.render = function () {
}
`),
+ txData.simulationFails ?
+ h('.error', {
+ style: {
+ marginLeft: 50,
+ fontSize: '0.9em',
+ },
+ }, 'Transaction Error. Exception thrown in contract code.')
+ : null,
+
+ state.insufficientBalance ?
+ h('span.error', {
+ style: {
+ marginLeft: 50,
+ fontSize: '0.9em',
+ },
+ }, 'Insufficient balance for transaction')
+ : null,
+
// send + cancel
h('.flex-row.flex-space-around.conf-buttons', {
style: {
@@ -39,17 +56,22 @@ PendingTx.prototype.render = function () {
margin: '14px 25px',
},
}, [
+
+ state.insufficientBalance ?
+ h('button.btn-green', {
+ onClick: state.buyEth,
+ }, 'Buy Ether')
+ : null,
+
h('button.confirm', {
+ disabled: state.insufficientBalance,
onClick: state.sendTransaction,
- style: { background: 'rgb(251,117,1)' },
}, 'Accept'),
- h('button.cancel', {
+ h('button.cancel.btn-red', {
onClick: state.cancelTransaction,
- style: { background: 'rgb(254,35,17)' },
}, 'Reject'),
]),
])
)
}
-
diff --git a/ui/app/components/qr-code.js b/ui/app/components/qr-code.js
index c26b02b94..5488599eb 100644
--- a/ui/app/components/qr-code.js
+++ b/ui/app/components/qr-code.js
@@ -1,5 +1,6 @@
const Component = require('react').Component
const h = require('react-hyperscript')
+const qrCode = require('qrcode-npm').qrcode
const inherits = require('util').inherits
const connect = require('react-redux').connect
const CopyButton = require('./copyButton')
@@ -23,15 +24,22 @@ function QrCodeView () {
QrCodeView.prototype.render = function () {
var props = this.props
var Qr = props.Qr
+ var qrImage = qrCode(4, 'M')
+
+ qrImage.addData(Qr.data)
+ qrImage.make()
+
return h('.main-container.flex-column', {
key: 'qr',
style: {
justifyContent: 'center',
- padding: '45px',
+ paddingBottom: '45px',
+ paddingLeft: '45px',
+ paddingRight: '45px',
alignItems: 'center',
},
}, [
- Array.isArray(Qr.message) ? h('.message-container', this.renderMultiMessage()) : h('h3', Qr.message),
+ Array.isArray(Qr.message) ? h('.message-container', this.renderMultiMessage()) : h('.qr-header', Qr.message),
this.props.warning ? this.props.warning && h('span.error.flex-center', {
style: {
@@ -48,7 +56,7 @@ QrCodeView.prototype.render = function () {
marginBottom: '15px',
},
dangerouslySetInnerHTML: {
- __html: Qr.image,
+ __html: qrImage.createTableTag(4),
},
}),
h('.flex-row', [
diff --git a/ui/app/components/range-slider.js b/ui/app/components/range-slider.js
new file mode 100644
index 000000000..823f5eb01
--- /dev/null
+++ b/ui/app/components/range-slider.js
@@ -0,0 +1,58 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+
+module.exports = RangeSlider
+
+inherits(RangeSlider, Component)
+function RangeSlider () {
+ Component.call(this)
+}
+
+RangeSlider.prototype.render = function () {
+ const state = this.state || {}
+ const props = this.props
+ const onInput = props.onInput || function () {}
+ const name = props.name
+ const {
+ min = 0,
+ max = 100,
+ increment = 1,
+ defaultValue = 50,
+ mirrorInput = false,
+ } = this.props.options
+ const {container, input, range} = props.style
+
+ return (
+ h('.flex-row', {
+ style: container,
+ }, [
+ h('input', {
+ type: 'range',
+ name: name,
+ min: min,
+ max: max,
+ step: increment,
+ style: range,
+ value: state.value || defaultValue,
+ onChange: mirrorInput ? this.mirrorInputs.bind(this, event) : onInput,
+ }),
+
+ // Mirrored input for range
+ mirrorInput ? h('input.large-input', {
+ type: 'number',
+ name: `${name}Mirror`,
+ min: min,
+ max: max,
+ value: state.value || defaultValue,
+ step: increment,
+ style: input,
+ onChange: this.mirrorInputs.bind(this, event),
+ }) : null,
+ ])
+ )
+}
+
+RangeSlider.prototype.mirrorInputs = function (event) {
+ this.setState({value: event.target.value})
+}
diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js
index b8650f7d5..8c9686035 100644
--- a/ui/app/components/shapeshift-form.js
+++ b/ui/app/components/shapeshift-form.js
@@ -1,4 +1,4 @@
-const Component = require('react').Component
+const PersistentForm = require('../../lib/persistent-form')
const h = require('react-hyperscript')
const inherits = require('util').inherits
const connect = require('react-redux').connect
@@ -8,20 +8,21 @@ const Qr = require('./qr-code')
const isValidAddress = require('../util').isValidAddress
module.exports = connect(mapStateToProps)(ShapeshiftForm)
-function mapStateToProps(state) {
+function mapStateToProps (state) {
return {
- selectedAccount: state.selectedAccount,
warning: state.appState.warning,
isSubLoading: state.appState.isSubLoading,
qrRequested: state.appState.qrRequested,
}
}
-inherits(ShapeshiftForm, Component)
+inherits(ShapeshiftForm, PersistentForm)
function ShapeshiftForm () {
- Component.call(this)
+ PersistentForm.call(this)
+ this.persistentFormParentId = 'shapeshift-buy-form'
}
+
ShapeshiftForm.prototype.render = function () {
return h(ReactCSSTransitionGroup, {
className: 'css-transition-group',
@@ -31,7 +32,6 @@ ShapeshiftForm.prototype.render = function () {
}, [
this.props.qrRequested ? h(Qr, {key: 'qr'}) : this.renderMain(),
])
-
}
ShapeshiftForm.prototype.renderMain = function () {
@@ -66,6 +66,9 @@ ShapeshiftForm.prototype.renderMain = function () {
h('input#fromCoin.buy-inputs.ex-coins', {
type: 'text',
list: 'coinList',
+ dataset: {
+ persistentFormId: 'input-coin',
+ },
style: {
boxSizing: 'border-box',
},
@@ -122,7 +125,6 @@ ShapeshiftForm.prototype.renderMain = function () {
this.props.isSubLoading ? this.renderLoading() : null,
h('.flex-column', {
style: {
- width: '235px',
alignItems: 'flex-start',
},
}, [
@@ -159,6 +161,9 @@ ShapeshiftForm.prototype.renderMain = function () {
h('input#fromCoinAddress.buy-inputs', {
type: 'text',
placeholder: `Your ${coin} Refund Address`,
+ dataset: {
+ persistentFormId: 'refund-address',
+ },
style: {
boxSizing: 'border-box',
width: '278px',
@@ -236,7 +241,7 @@ ShapeshiftForm.prototype.updateCoin = function (event) {
if (!coinOptions[coin.toUpperCase()] || coin.toUpperCase() === 'ETH') {
var message = 'Not a valid coin'
- return props.dispatch(actions.showWarning(message))
+ return props.dispatch(actions.displayWarning(message))
} else {
return props.dispatch(actions.pairUpdate(coin))
}
@@ -261,17 +266,17 @@ ShapeshiftForm.prototype.renderInfo = function () {
return h('span', {
style: {
- marginTop: '15px',
+ marginTop: '10px',
marginBottom: '15px',
},
}, [
h('h3.flex-row.text-transform-uppercase', {
style: {
- color: '#AEAEAE',
+ color: '#868686',
paddingTop: '4px',
justifyContent: 'space-around',
textAlign: 'center',
- fontSize: '14px',
+ fontSize: '17px',
},
}, `Market Info for ${marketinfo.pair.replace('_', ' to ').toUpperCase()}:`),
h('.marketinfo', ['Status : ', `${coinOptions[coin].status}`]),
diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js
index 38c19eb28..e0243e247 100644
--- a/ui/app/components/shift-list-item.js
+++ b/ui/app/components/shift-list-item.js
@@ -26,7 +26,6 @@ function ShiftListItem () {
}
ShiftListItem.prototype.render = function () {
-
return (
h('.transaction-list-item.flex-row', {
style: {
diff --git a/ui/app/components/tab-bar.js b/ui/app/components/tab-bar.js
new file mode 100644
index 000000000..65078e0a4
--- /dev/null
+++ b/ui/app/components/tab-bar.js
@@ -0,0 +1,35 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+
+module.exports = TabBar
+
+inherits(TabBar, Component)
+function TabBar () {
+ Component.call(this)
+}
+
+TabBar.prototype.render = function () {
+ const props = this.props
+ const state = this.state || {}
+ const { tabs = [], defaultTab, tabSelected } = props
+ const { subview = defaultTab } = state
+
+ return (
+ h('.flex-row.space-around.text-transform-uppercase', {
+ style: {
+ background: '#EBEBEB',
+ color: '#AEAEAE',
+ paddingTop: '4px',
+ },
+ }, tabs.map((tab) => {
+ const { key, content } = tab
+ return h(subview === key ? '.activeForm' : '.inactiveForm.pointer', {
+ onClick: () => {
+ this.setState({ subview: key })
+ tabSelected(key)
+ },
+ }, content)
+ }))
+ )
+}
diff --git a/ui/app/components/tooltip.js b/ui/app/components/tooltip.js
index fb67c717e..edbc074bb 100644
--- a/ui/app/components/tooltip.js
+++ b/ui/app/components/tooltip.js
@@ -12,11 +12,11 @@ function Tooltip () {
Tooltip.prototype.render = function () {
const props = this.props
+ const { position, title, children } = props
return h(ReactTooltip, {
- position: props.position ? props.position : 'left',
- title: props.title,
+ position: position || 'left',
+ title,
fixed: false,
- }, props.children)
-
+ }, children)
}
diff --git a/ui/app/components/transaction-list-item-icon.js b/ui/app/components/transaction-list-item-icon.js
index 8b118b1d4..90b4ec094 100644
--- a/ui/app/components/transaction-list-item-icon.js
+++ b/ui/app/components/transaction-list-item-icon.js
@@ -13,13 +13,34 @@ function TransactionIcon () {
TransactionIcon.prototype.render = function () {
const { transaction, txParams, isMsg } = this.props
+ switch (transaction.status) {
+ case 'unapproved':
+ return h( !isMsg ? '.unapproved-tx-icon' : 'i.fa.fa-certificate.fa-lg', {
+ style: {
+ width: '24px',
+ },
+ })
- if (transaction.status === 'rejected') {
- return h('i.fa.fa-exclamation-triangle.fa-lg.warning', {
- style: {
- width: '24px',
- },
- })
+ case 'rejected':
+ return h('i.fa.fa-exclamation-triangle.fa-lg.warning', {
+ style: {
+ width: '24px',
+ },
+ })
+
+ case 'failed':
+ return h('i.fa.fa-exclamation-triangle.fa-lg.error', {
+ style: {
+ width: '24px',
+ },
+ })
+
+ case 'submitted':
+ return h('i.fa.fa-ellipsis-h', {
+ style: {
+ fontSize: '27px',
+ },
+ })
}
if (isMsg) {
diff --git a/ui/app/components/transaction-list-item.js b/ui/app/components/transaction-list-item.js
index 1b85464e1..44d2dc587 100644
--- a/ui/app/components/transaction-list-item.js
+++ b/ui/app/components/transaction-list-item.js
@@ -8,6 +8,7 @@ const explorerLink = require('../../lib/explorer-link')
const CopyButton = require('./copyButton')
const vreme = new (require('vreme'))
const extension = require('../../../app/scripts/lib/extension')
+const Tooltip = require('./tooltip')
const TransactionIcon = require('./transaction-list-item-icon')
const ShiftListItem = require('./shift-list-item')
@@ -27,12 +28,11 @@ TransactionListItem.prototype.render = function () {
let isLinkable = false
const numericNet = parseInt(network)
- isLinkable = numericNet === 1 || numericNet === 2
+ isLinkable = numericNet === 1 || numericNet === 3
var isMsg = ('msgParams' in transaction)
var isTx = ('txParams' in transaction)
- var isPending = transaction.status === 'unconfirmed'
-
+ var isPending = transaction.status === 'unapproved'
let txParams
if (isTx) {
txParams = transaction.txParams
@@ -41,14 +41,13 @@ TransactionListItem.prototype.render = function () {
}
const isClickable = ('hash' in transaction && isLinkable) || isPending
-
return (
h(`.transaction-list-item.flex-row.flex-space-between${isClickable ? '.pointer' : ''}`, {
onClick: (event) => {
if (isPending) {
this.props.showTx(transaction.id)
}
-
+ event.stopPropagation()
if (!transaction.hash || !isLinkable) return
var url = explorerLink(transaction.hash, parseInt(network))
extension.tabs.create({ url })
@@ -58,10 +57,17 @@ TransactionListItem.prototype.render = function () {
},
}, [
- // large identicon
h('.identicon-wrapper.flex-column.flex-center.select-none', [
- transaction.status === 'unconfirmed' ? h('i.fa.fa-ellipsis-h', {style: { fontSize: '27px' }})
- : h(TransactionIcon, { txParams, transaction, isTx, isMsg }),
+ h('.pop-hover', {
+ onClick: (event) => {
+ event.stopPropagation()
+ if (!isTx || isPending) return
+ var url = `https://metamask.github.io/eth-tx-viz/?tx=${transaction.hash}`
+ extension.tabs.create({ url })
+ },
+ }, [
+ h(TransactionIcon, { txParams, transaction, isTx, isMsg }),
+ ]),
]),
h('.flex-column', {style: {width: '200px', overflow: 'hidden'}}, [
@@ -77,6 +83,7 @@ TransactionListItem.prototype.render = function () {
value: txParams.value,
width: '55px',
shorten: true,
+ showFiat: false,
style: {fontSize: '15px'},
}) : h('.flex-column'),
])
@@ -127,7 +134,14 @@ function failIfFailed (transaction) {
if (transaction.status === 'rejected') {
return h('span.error', ' (Rejected)')
}
- if (transaction.status === 'failed') {
- return h('span.error', ' (Failed)')
+ if (transaction.err) {
+
+ return h(Tooltip, {
+ title: transaction.err.message,
+ position: 'bottom',
+ }, [
+ h('span.error', ' (Failed)'),
+ ])
}
+
}
diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js
index 7e1bedb05..3ae953637 100644
--- a/ui/app/components/transaction-list.js
+++ b/ui/app/components/transaction-list.js
@@ -13,12 +13,13 @@ function TransactionList () {
}
TransactionList.prototype.render = function () {
- const { txsToRender, network, unconfMsgs } = this.props
+ const { transactions, network, unapprovedMsgs } = this.props
+
var shapeShiftTxList
if (network === '1') {
shapeShiftTxList = this.props.shapeShiftTxList
}
- const transactions = !shapeShiftTxList ? txsToRender.concat(unconfMsgs) : txsToRender.concat(unconfMsgs, shapeShiftTxList)
+ const txsToRender = !shapeShiftTxList ? transactions.concat(unapprovedMsgs) : transactions.concat(unapprovedMsgs, shapeShiftTxList)
.sort((a, b) => b.time - a.time)
return (
@@ -55,8 +56,8 @@ TransactionList.prototype.render = function () {
},
}, [
- transactions.length
- ? transactions.map((transaction, i) => {
+ txsToRender.length
+ ? txsToRender.map((transaction, i) => {
let key
switch (transaction.key) {
case 'shapeshift':