aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--ui/app/account-detail.js33
-rw-r--r--ui/app/accounts/account-panel.js7
-rw-r--r--ui/app/accounts/index.js16
-rw-r--r--ui/app/app.js51
-rw-r--r--ui/app/components/transaction-list-item.js126
-rw-r--r--ui/app/components/transaction-list.js132
-rw-r--r--ui/app/css/lib.css14
-rw-r--r--ui/app/reducers/app.js24
9 files changed, 226 insertions, 179 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2fc67168c..7e2a608c2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,8 @@
## Current Master
- Added copy address button to account list.
+- Fixed back button on confirm transaction screen.
+- Add indication of pending transactions to account list screen.
- Fixed bug where error warning was sometimes not cleared on view transition.
## 2.0.0 2016-05-23
diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js
index bae44ec85..1dcce1d08 100644
--- a/ui/app/account-detail.js
+++ b/ui/app/account-detail.js
@@ -7,10 +7,11 @@ const copyToClipboard = require('copy-to-clipboard')
const actions = require('./actions')
const addressSummary = require('./util').addressSummary
const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
+const valuesFor = require('./util').valuesFor
const Identicon = require('./components/identicon')
const EtherBalance = require('./components/eth-balance')
-const transactionList = require('./components/transaction-list')
+const TransactionList = require('./components/transaction-list')
const ExportAccountView = require('./components/account-export')
const ethUtil = require('ethereumjs-util')
const EditableLabel = require('./components/editable-label')
@@ -24,7 +25,9 @@ function mapStateToProps(state) {
address: state.metamask.selectedAccount,
accountDetail: state.appState.accountDetail,
transactions: state.metamask.transactions,
- networkVersion: state.metamask.network,
+ network: state.metamask.network,
+ unconfTxs: valuesFor(state.metamask.unconfTxs),
+ unconfMsgs: valuesFor(state.metamask.unconfMsgs),
}
}
@@ -139,7 +142,7 @@ AccountDetailScreen.prototype.render = function() {
}),
h('button', {
- onClick: () => this.props.dispatch(actions.showSendPage()),
+ onClick: () => props.dispatch(actions.showSendPage()),
style: {
margin: 10,
},
@@ -183,18 +186,22 @@ AccountDetailScreen.prototype.subview = function() {
}
AccountDetailScreen.prototype.transactionList = function() {
- var state = this.props
- var transactions = state.transactions
+ const { transactions, unconfTxs, unconfMsgs, address, network } = this.props
var txsToRender = transactions
- // only transactions that are from the current address
- .filter(tx => tx.txParams.from === state.address)
- // only transactions that are on the current network
- .filter(tx => tx.txParams.metamaskNetworkId === state.networkVersion)
- // sort by recency
- .sort((a, b) => b.time - a.time)
-
- return transactionList(txsToRender, state.networkVersion)
+ // only transactions that are from the current address
+ .filter(tx => tx.txParams.from === address)
+ // only transactions that are on the current network
+ .filter(tx => tx.txParams.metamaskNetworkId === network)
+ // sort by recency
+ .sort((a, b) => b.time - a.time)
+
+ return h(TransactionList, {
+ txsToRender,
+ network,
+ unconfTxs,
+ unconfMsgs,
+ })
}
AccountDetailScreen.prototype.navigateToAccounts = function(event){
diff --git a/ui/app/accounts/account-panel.js b/ui/app/accounts/account-panel.js
index 5ade7fe0e..8afb7308d 100644
--- a/ui/app/accounts/account-panel.js
+++ b/ui/app/accounts/account-panel.js
@@ -34,6 +34,7 @@ NewComponent.prototype.render = function() {
}, [
h('.identicon-wrapper.flex-column.flex-center.select-none', [
+ this.pendingOrNot(),
h(Identicon, {
address: identity.address
}),
@@ -61,3 +62,9 @@ NewComponent.prototype.render = function() {
])
)
}
+
+NewComponent.prototype.pendingOrNot = function() {
+ const pending = this.props.pending
+ if (pending.length === 0) return null
+ return h('.pending-dot', pending.length)
+}
diff --git a/ui/app/accounts/index.js b/ui/app/accounts/index.js
index 1a42f7470..9cfab54e5 100644
--- a/ui/app/accounts/index.js
+++ b/ui/app/accounts/index.js
@@ -12,6 +12,10 @@ module.exports = connect(mapStateToProps)(AccountsScreen)
function mapStateToProps(state) {
+ const pendingTxs = valuesFor(state.metamask.unconfTxs)
+ const pendingMsgs = valuesFor(state.metamask.unconfMsgs)
+ const pending = pendingTxs.concat(pendingMsgs)
+
return {
accounts: state.metamask.accounts,
identities: state.metamask.identities,
@@ -19,6 +23,7 @@ function mapStateToProps(state) {
selectedAddress: state.metamask.selectedAddress,
currentDomain: state.appState.currentDomain,
scrollToBottom: state.appState.scrollToBottom,
+ pending,
}
}
@@ -62,12 +67,23 @@ AccountsScreen.prototype.render = function() {
},
[
identityList.map((identity) => {
+ const pending = this.props.pending.filter((txOrMsg) => {
+ if ('txParams' in txOrMsg) {
+ return txOrMsg.txParams.from === identity.address
+ } else if ('msgParams' in txOrMsg) {
+ return txOrMsg.msgParams.from === identity.address
+ } else {
+ return false
+ }
+ })
+
return h(AccountPanel, {
key: `acct-panel-${identity.address}`,
identity,
selectedAddress: this.props.selectedAddress,
accounts: this.props.accounts,
onShowDetail: this.onShowDetail.bind(this),
+ pending,
})
}),
diff --git a/ui/app/app.js b/ui/app/app.js
index 511012fab..7e7ca24ad 100644
--- a/ui/app/app.js
+++ b/ui/app/app.js
@@ -86,43 +86,6 @@ App.prototype.render = function() {
this.renderPrimary(),
]),
]),
-
- // footer
- // h('.app-footer.flex-row.flex-space-around', {
- // style: {
- // display: shouldHaveFooter ? 'flex' : 'none',
- // alignItems: 'center',
- // height: '56px',
- // }
- // }, [
-
- // // settings icon
- // h('i.fa.fa-cog.fa-lg' + (view === 'config' ? '.active' : '.cursor-pointer'), {
- // style: {
- // opacity: state.isUnlocked ? '1.0' : '0.0',
- // transition: 'opacity 200ms ease-in',
- // //transform: `translateX(${state.isUnlocked ? '0px' : '-100px'})`,
- // },
- // onClick: function(ev) {
- // state.dispatch(actions.showConfigPage())
- // },
- // }),
-
- // // toggle
- // onOffToggle({
- // toggleMetamaskActive: this.toggleMetamaskActive.bind(this),
- // isUnlocked: state.isUnlocked,
- // }),
-
- // // help
- // h('i.fa.fa-question.fa-lg.cursor-pointer', {
- // style: {
- // opacity: state.isUnlocked ? '1.0' : '0.0',
- // },
- // onClick() { state.dispatch(actions.showInfoPage()) }
- // }),
- // ]),
-
])
)
}
@@ -276,11 +239,7 @@ App.prototype.renderPrimary = function(){
return h(CreateVaultScreen, {key: 'createVault'})
default:
- if (this.hasPendingTxs()) {
- return h(ConfirmTxScreen, {key: 'confirm-tx'})
- } else {
- return h(AccountDetailScreen, {key: 'account-detail'})
- }
+ return h(AccountDetailScreen, {key: 'account-detail'})
}
}
@@ -296,14 +255,6 @@ App.prototype.toggleMetamaskActive = function(){
}
}
-App.prototype.hasPendingTxs = function() {
- var state = this.props
- var unconfTxs = state.unconfTxs
- var unconfMsgs = state.unconfMsgs
- var unconfTxList = txHelper(unconfTxs, unconfMsgs)
- return unconfTxList.length > 0
-}
-
function onOffToggle(state){
var buttonSize = '50px';
var lockWidth = '20px';
diff --git a/ui/app/components/transaction-list-item.js b/ui/app/components/transaction-list-item.js
new file mode 100644
index 000000000..a0715db0b
--- /dev/null
+++ b/ui/app/components/transaction-list-item.js
@@ -0,0 +1,126 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+
+const Identicon = require('./identicon')
+const EtherBalance = require('./eth-balance')
+const addressSummary = require('../util').addressSummary
+const explorerLink = require('../../lib/explorer-link')
+const formatBalance = require('../util').formatBalance
+const vreme = new (require('vreme'))
+
+module.exports = TransactionListItem
+
+
+inherits(TransactionListItem, Component)
+function TransactionListItem() {
+ Component.call(this)
+}
+
+TransactionListItem.prototype.render = function() {
+ const { transaction, i } = this.props
+
+ var date = formatDate(transaction.time)
+
+ var isMsg = ('msgParams' in transaction)
+ var isTx = ('txParams' in transaction)
+
+ var txParams = transaction.txParams
+
+ return (
+ h(`.transaction-list-item.flex-row.flex-space-between${transaction.hash ? '.pointer' : ''}`, {
+ key: `tx-${transaction.id + i}`,
+ onClick: (event) => {
+ if (!transaction.hash) return
+ var url = explorerLink(transaction.hash, parseInt(network))
+ chrome.tabs.create({ url })
+ },
+ style: {
+ padding: '20px 0',
+ },
+ }, [
+
+ // large identicon
+ h('.identicon-wrapper.flex-column.flex-center.select-none', [
+ identicon(txParams, transaction),
+ ]),
+
+ h('.flex-column', [
+
+ h('div', date),
+
+ recipientField(txParams, transaction),
+
+ ]),
+
+ h(EtherBalance, {
+ value: txParams.value,
+ }),
+ ])
+ )
+}
+
+
+function recipientField(txParams, transaction) {
+ if (txParams.to) {
+ return h('div', {
+ style: {
+ fontSize: 'small',
+ color: '#ABA9AA',
+ },
+ }, [
+ addressSummary(txParams.to),
+ failIfFailed(transaction),
+ ])
+
+ } else {
+
+ return h('div', {
+ style: {
+ fontSize: 'small',
+ color: '#ABA9AA',
+ },
+ },[
+ 'Contract Published',
+ failIfFailed(transaction),
+ ])
+ }
+}
+
+TransactionListItem.prototype.renderMessage = function() {
+ const { transaction, i } = this.props
+ return h('div', 'wowie, thats a message')
+}
+
+function formatDate(date){
+ return vreme.format(new Date(date), 'March 16 2014 14:30')
+}
+
+function identicon(txParams, transaction) {
+ if (transaction.status === 'rejected') {
+ return h('i.fa.fa-exclamation-triangle.fa-lg.error', {
+ style: {
+ width: '24px',
+ }
+ })
+ }
+
+ if (txParams.to) {
+ return h(Identicon, {
+ diameter: 24,
+ address: txParams.to || transaction.hash,
+ })
+ } else {
+ return h('i.fa.fa-file-text-o.fa-lg', {
+ style: {
+ width: '24px',
+ }
+ })
+ }
+}
+
+function failIfFailed(transaction) {
+ if (transaction.status === 'rejected') {
+ return h('span.error', ' (Failed)')
+ }
+}
diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js
index f85aab70f..86abd9709 100644
--- a/ui/app/components/transaction-list.js
+++ b/ui/app/components/transaction-list.js
@@ -1,14 +1,21 @@
+const Component = require('react').Component
const h = require('react-hyperscript')
-const vreme = new (require('vreme'))
-const formatBalance = require('../util').formatBalance
-const addressSummary = require('../util').addressSummary
-const explorerLink = require('../../lib/explorer-link')
-const Panel = require('./panel')
-const Identicon = require('./identicon')
-const EtherBalance = require('./eth-balance')
+const inherits = require('util').inherits
+const TransactionListItem = require('./transaction-list-item')
+
+module.exports = TransactionList
+
+
+inherits(TransactionList, Component)
+function TransactionList() {
+ Component.call(this)
+}
+
+TransactionList.prototype.render = function() {
+ const { txsToRender, network, unconfTxs, unconfMsgs } = this.props
+ const transactions = txsToRender
-module.exports = function(transactions, network) {
return (
h('section.transaction-list', [
@@ -42,118 +49,19 @@ module.exports = function(transactions, network) {
}, (
transactions.length ?
- transactions.map(renderTransaction)
+ transactions.map((transaction, i) => {
+ return h(TransactionListItem, {
+ transaction, i
+ })
+ })
:
[h('.flex-center', {
style: {
height: '100%',
},
}, 'No transaction history...')]
-
))
-
])
-
)
-
-
- function renderTransaction(transaction, i){
-
- var txParams = transaction.txParams
- var date = formatDate(transaction.time)
-
- return (
-
- h(`.transaction-list-item.flex-row.flex-space-between${transaction.hash ? '.pointer' : ''}`, {
- key: `tx-${transaction.id + i}`,
- onClick: (event) => {
- if (!transaction.hash) return
- var url = explorerLink(transaction.hash, parseInt(network))
- chrome.tabs.create({ url })
- },
- style: {
- padding: '20px 0',
- },
- }, [
-
- // large identicon
- h('.identicon-wrapper.flex-column.flex-center.select-none', [
- identicon(txParams, transaction),
- ]),
-
- h('.flex-column', [
-
- h('div', date),
-
- recipientField(txParams, transaction),
-
- ]),
-
- h(EtherBalance, {
- value: txParams.value,
- }),
- ])
-
- )
- }
-}
-
-function recipientField(txParams, transaction) {
- if (txParams.to) {
- return h('div', {
- style: {
- fontSize: 'small',
- color: '#ABA9AA',
- },
- }, [
- addressSummary(txParams.to),
- failIfFailed(transaction),
- ])
-
- } else {
-
- return h('div', {
- style: {
- fontSize: 'small',
- color: '#ABA9AA',
- },
- },[
- 'Contract Published',
- failIfFailed(transaction),
- ])
-
- }
-}
-
-function formatDate(date){
- return vreme.format(new Date(date), 'March 16 2014 14:30')
}
-function identicon(txParams, transaction) {
- if (transaction.status === 'rejected') {
- return h('i.fa.fa-exclamation-triangle.fa-lg.error', {
- style: {
- width: '24px',
- }
- })
- }
-
- if (txParams.to) {
- return h(Identicon, {
- diameter: 24,
- address: txParams.to || transaction.hash,
- })
- } else {
- return h('i.fa.fa-file-text-o.fa-lg', {
- style: {
- width: '24px',
- }
- })
- }
-}
-
-function failIfFailed(transaction) {
- if (transaction.status === 'rejected') {
- return h('span.error', ' (Failed)')
- }
-}
diff --git a/ui/app/css/lib.css b/ui/app/css/lib.css
index d9719b1e3..73be4023e 100644
--- a/ui/app/css/lib.css
+++ b/ui/app/css/lib.css
@@ -166,3 +166,17 @@ hr.horizontal-line {
.hover-white:hover {
background: white;
}
+
+.pending-dot {
+ background: red;
+ left: 57px;
+ color: white;
+ border-radius: 10px;
+ height: 20px;
+ min-width: 20px;
+ position: absolute;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 4px;
+}
diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js
index 493246a35..a98b809d6 100644
--- a/ui/app/reducers/app.js
+++ b/ui/app/reducers/app.js
@@ -9,8 +9,17 @@ function reduceApp(state, action) {
// clone and defaults
const selectedAccount = state.metamask.selectedAccount
+ const pendingTxs = hasPendingTxs(state)
+ let name = 'accounts'
+ if (selectedAccount) {
+ defaultView = 'accountDetail'
+ }
+ if (pendingTxs) {
+ defaultView = 'confTx'
+ }
+
var defaultView = {
- name: selectedAccount ? 'accountDetail' : 'accounts',
+ name,
detailView: null,
context: selectedAccount,
}
@@ -122,7 +131,6 @@ function reduceApp(state, action) {
case actions.UNLOCK_METAMASK:
return extend(appState, {
- currentView: {},
detailView: {},
transForward: true,
isLoading: false,
@@ -145,7 +153,9 @@ function reduceApp(state, action) {
case actions.GO_HOME:
return extend(appState, {
- currentView: {},
+ currentView: extend(appState.currentView, {
+ name: 'accountDetail',
+ }),
accountDetail: {
subview: 'transactions',
accountExport: 'none',
@@ -347,6 +357,12 @@ function reduceApp(state, action) {
default:
return appState
-
}
}
+
+function hasPendingTxs (state) {
+ var unconfTxs = state.metamask.unconfTxs
+ var unconfMsgs = state.metamask.unconfMsgs
+ var unconfTxList = txHelper(unconfTxs, unconfMsgs)
+ return unconfTxList.length > 0
+}