Move account export to subview

Account detail view now has an animated transitioning `subview` section that allows us to show extra details within it.

Clicking `export` now slide replaces the transaction list with the export UI.

Added cancel/done/submit buttons to the Export UI. Done submits like Enter did, the other two transition back to the transaction list.

For some reason when first unlocking, the selected account is being instantly replaced with the accounts list, so I need to fix that before merging this into master.
feature/default_network_editable
Dan Finlay 9 years ago
parent 95582f8bde
commit f4d58ebc70
  1. 106
      ui/app/account-detail.js
  2. 87
      ui/app/components/account-export.js
  3. 2
      ui/app/components/transaction-list.js
  4. 17
      ui/app/reducers/app.js

@ -1,11 +1,15 @@
const inherits = require('util').inherits
const extend = require('xtend')
const Component = require('react').Component
const h = require('react-hyperscript')
const connect = require('react-redux').connect
const copyToClipboard = require('copy-to-clipboard')
const actions = require('./actions')
const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
const AccountPanel = require('./components/account-panel')
const transactionList = require('./components/transaction-list')
const ExportAccountView = require('./components/account-export')
module.exports = connect(mapStateToProps)(AccountDetailScreen)
@ -78,12 +82,13 @@ AccountDetailScreen.prototype.render = function() {
}, 'EXPORT'),
]),
transactionList(transactions
.filter(tx => tx.txParams.from === state.address)
.filter(tx => tx.txParams.metamaskNetworkId === state.networkVersion)
.sort((a, b) => b.time - a.time), state.networkVersion),
this.exportedAccount(accountDetail),
h(ReactCSSTransitionGroup, {
transitionName: "main",
transitionEnterTimeout: 300,
transitionLeaveTimeout: 300,
}, [
this.subview(),
]),
// transaction table
/*
h('section.flex-column', [
@ -94,72 +99,41 @@ AccountDetailScreen.prototype.render = function() {
)
}
AccountDetailScreen.prototype.subview = function() {
var subview
try {
subview = this.props.accountDetail.subview
} catch (e) {
subview = null
}
switch (subview) {
case 'transactions':
return this.transactionList()
case 'export':
var state = extend({key: 'export'}, this.props)
return h(ExportAccountView, state)
default:
return this.transactionList()
}
}
AccountDetailScreen.prototype.transactionList = function() {
var state = this.props
var transactions = state.transactions
return transactionList(transactions
.filter(tx => tx.txParams.from === state.address)
.filter(tx => tx.txParams.metamaskNetworkId === state.networkVersion)
.sort((a, b) => b.time - a.time), state.networkVersion)
}
AccountDetailScreen.prototype.navigateToAccounts = function(event){
event.stopPropagation()
this.props.dispatch(actions.showAccountsPage())
}
AccountDetailScreen.prototype.exportAccount = function(address) {
this.props.dispatch(actions.exportAccount(address))
}
AccountDetailScreen.prototype.requestAccountExport = function() {
this.props.dispatch(actions.requestExportAccount())
}
AccountDetailScreen.prototype.exportedAccount = function(accountDetail) {
if (!accountDetail) return
var accountExport = accountDetail.accountExport
var notExporting = accountExport === 'none'
var exportRequested = accountExport === 'requested'
var accountExported = accountExport === 'completed'
if (notExporting) return
if (exportRequested) {
var warning = `Exporting your private key is very dangerous,
and you should only do it if you know what you're doing.`
var confirmation = `If you're absolutely sure, type "I understand" below and
hit Enter.`
return h('div', {}, [
h('p.error', warning),
h('p', confirmation),
h('input#exportAccount', {
onKeyPress: this.onExportKeyPress.bind(this),
})
])
}
if (accountExported) {
return h('div.privateKey', {
}, [
h('label', 'Your private key (click to copy):'),
h('p.error.cursor-pointer', {
style: {
textOverflow: 'ellipsis',
overflow: 'hidden',
webkitUserSelect: 'text',
width: '100%',
},
onClick: function(event) {
copyToClipboard(accountDetail.privateKey)
}
}, accountDetail.privateKey),
])
}
}
AccountDetailScreen.prototype.onExportKeyPress = function(event) {
if (event.key !== 'Enter') return
event.preventDefault()
var input = document.getElementById('exportAccount')
if (input.value === 'I understand') {
this.props.dispatch(actions.exportAccount(this.props.address))
} else {
input.value = ''
input.placeholder = 'Please retype "I understand" exactly.'
}
}

@ -0,0 +1,87 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const actions = require('../actions')
module.exports = ExportAccountView
inherits(ExportAccountView, Component)
function ExportAccountView() {
Component.call(this)
}
ExportAccountView.prototype.render = function() {
console.log("EXPORT VIEW")
console.dir(this.props)
var state = this.props
var accountDetail = state.accountDetail
if (!accountDetail) return h('div')
var accountExport = accountDetail.accountExport
var notExporting = accountExport === 'none'
var exportRequested = accountExport === 'requested'
var accountExported = accountExport === 'completed'
if (notExporting) return h('div')
if (exportRequested) {
var warning = `Exporting your private key is very dangerous,
and you should only do it if you know what you're doing.`
var confirmation = `If you're absolutely sure, type "I understand" below and
submit.`
return h('div', { key: 'exporting' }, [
h('p.error', warning),
h('p', confirmation),
h('input#exportAccount', {
onKeyPress: this.onExportKeyPress.bind(this),
}),
h('button', {
onClick: () => this.onExportKeyPress({ key: 'Enter', preventDefault: () => {} }),
}, 'Submit'),
h('button', {
onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address))
}, 'Cancel'),
])
}
if (accountExported) {
return h('div.privateKey', {
}, [
h('label', 'Your private key (click to copy):'),
h('p.error.cursor-pointer', {
style: {
textOverflow: 'ellipsis',
overflow: 'hidden',
webkitUserSelect: 'text',
width: '100%',
},
onClick: function(event) {
copyToClipboard(accountDetail.privateKey)
}
}, accountDetail.privateKey),
h('button', {
onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address))
}, 'Done'),
])
}
}
ExportAccountView.prototype.onExportKeyPress = function(event) {
if (event.key !== 'Enter') return
event.preventDefault()
var input = document.getElementById('exportAccount')
if (input.value === 'I understand') {
this.props.dispatch(actions.exportAccount(this.props.address))
} else {
input.value = ''
input.placeholder = 'Please retype "I understand" exactly.'
}
}
ExportAccountView.prototype.exportAccount = function(address) {
this.props.dispatch(actions.exportAccount(address))
}

@ -4,7 +4,7 @@ const addressSummary = require('../util').addressSummary
const explorerLink = require('../../lib/explorer-link')
module.exports = function(transactions, network) {
return h('details', [
return h('details', { key: 'transaction-list' }, [
h('summary', [
h('div.font-small', {style: {display: 'inline'}}, 'Transactions'),

@ -23,6 +23,9 @@ function reduceApp(state, action) {
var appState = extend({
currentView: seedWords ? seedConfView : defaultView,
accountDetail: {
subview: 'transactions',
},
currentDomain: 'example.com',
transForward: true, // Used to render transition direction
isLoading: false, // Used to display loading indicator
@ -131,6 +134,7 @@ function reduceApp(state, action) {
return extend(appState, {
currentView: {},
accountDetail: {
subview: 'transactions',
accountExport: 'none',
privateKey: '',
},
@ -144,6 +148,7 @@ function reduceApp(state, action) {
context: action.value || account,
},
accountDetail: {
subview: 'transactions',
accountExport: 'none',
privateKey: '',
},
@ -157,6 +162,7 @@ function reduceApp(state, action) {
context: action.value,
},
accountDetail: {
subview: 'transactions',
accountExport: 'none',
privateKey: '',
},
@ -218,6 +224,9 @@ function reduceApp(state, action) {
name: 'accountDetail',
context: state.metamask.selectedAddress,
},
accountDetail: {
subview: 'transactions',
},
})
}
@ -285,7 +294,13 @@ function reduceApp(state, action) {
case actions.REQUEST_ACCOUNT_EXPORT:
return extend(appState, {
transForward: true,
currentView: {
name: 'accountDetail',
context: appState.currentView.context,
},
accountDetail: {
subview: 'export',
accountExport: 'requested',
},
})
@ -293,6 +308,7 @@ function reduceApp(state, action) {
case actions.EXPORT_ACCOUNT:
return extend(appState, {
accountDetail: {
subview: 'export',
accountExport: 'completed',
},
})
@ -300,6 +316,7 @@ function reduceApp(state, action) {
case actions.SHOW_PRIVATE_KEY:
return extend(appState, {
accountDetail: {
subview: 'export',
accountExport: 'completed',
privateKey: action.value,
},

Loading…
Cancel
Save