aboutsummaryrefslogtreecommitdiffstats
path: root/ui/app/components
diff options
context:
space:
mode:
Diffstat (limited to 'ui/app/components')
-rw-r--r--ui/app/components/account-dropdowns.js235
-rw-r--r--ui/app/components/account-info-link.js41
-rw-r--r--ui/app/components/drop-menu-item.js59
-rw-r--r--ui/app/components/dropdown.js92
-rw-r--r--ui/app/components/editable-label.js7
-rw-r--r--ui/app/components/loading.js48
-rw-r--r--ui/app/components/network.js1
-rw-r--r--ui/app/components/shapeshift-form.js10
-rw-r--r--ui/app/components/tab-bar.js1
-rw-r--r--ui/app/components/token-list.js42
-rw-r--r--ui/app/components/transaction-list.js18
11 files changed, 400 insertions, 154 deletions
diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js
new file mode 100644
index 000000000..4ef9a5c14
--- /dev/null
+++ b/ui/app/components/account-dropdowns.js
@@ -0,0 +1,235 @@
+const Component = require('react').Component
+const PropTypes = require('react').PropTypes
+const h = require('react-hyperscript')
+const actions = require('../actions')
+const genAccountLink = require('../../lib/account-link.js')
+const connect = require('react-redux').connect
+const Dropdown = require('./dropdown').Dropdown
+const DropdownMenuItem = require('./dropdown').DropdownMenuItem
+const Identicon = require('./identicon')
+const ethUtil = require('ethereumjs-util')
+const copyToClipboard = require('copy-to-clipboard')
+
+class AccountDropdowns extends Component {
+ constructor (props) {
+ super(props)
+ this.state = {
+ accountSelectorActive: false,
+ optionsMenuActive: false,
+ }
+ this.accountSelectorToggleClassName = 'fa-angle-down'
+ this.optionsMenuToggleClassName = 'fa-ellipsis-h'
+ }
+
+ renderAccounts () {
+ const { identities, selected } = this.props
+
+ return Object.keys(identities).map((key) => {
+ const identity = identities[key]
+ const isSelected = identity.address === selected
+
+ return h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => {},
+ onClick: () => {
+ this.props.actions.showAccountDetail(identity.address)
+ },
+ },
+ [
+ h(
+ Identicon,
+ {
+ address: identity.address,
+ diameter: 16,
+ },
+ ),
+ h('span', { style: { marginLeft: '10px' } }, identity.name || ''),
+ h('span', { style: { marginLeft: '10px' } }, isSelected ? h('.check', '✓') : null),
+ ]
+ )
+ })
+ }
+
+ renderAccountSelector () {
+ const { actions } = this.props
+ const { accountSelectorActive } = this.state
+
+ return h(
+ Dropdown,
+ {
+ style: {
+ marginLeft: '-125px',
+ minWidth: '180px',
+ overflowY: 'auto',
+ maxHeight: '300px',
+ },
+ isOpen: accountSelectorActive,
+ onClickOutside: (event) => {
+ const { classList } = event.target
+ const isNotToggleElement = !classList.contains(this.accountSelectorToggleClassName)
+ if (accountSelectorActive && isNotToggleElement) {
+ this.setState({ accountSelectorActive: false })
+ }
+ },
+ },
+ [
+ ...this.renderAccounts(),
+ h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => {},
+ onClick: () => actions.addNewAccount(),
+ },
+ [
+ h(
+ Identicon,
+ {
+ diameter: 16,
+ },
+ ),
+ h('span', { style: { marginLeft: '10px' } }, 'Create Account'),
+ ],
+ ),
+ h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => {},
+ onClick: () => actions.showImportPage(),
+ },
+ [
+ h(
+ Identicon,
+ {
+ diameter: 16,
+ },
+ ),
+ h('span', { style: { marginLeft: '10px' } }, 'Import Account'),
+ ]
+ ),
+ ]
+ )
+ }
+
+ renderAccountOptions () {
+ const { actions } = this.props
+ const { optionsMenuActive } = this.state
+
+ return h(
+ Dropdown,
+ {
+ style: {
+ marginLeft: '-162px',
+ minWidth: '180px',
+ },
+ isOpen: optionsMenuActive,
+ onClickOutside: () => {
+ const { classList } = event.target
+ const isNotToggleElement = !classList.contains(this.optionsMenuToggleClassName)
+ if (optionsMenuActive && isNotToggleElement) {
+ this.setState({ optionsMenuActive: false })
+ }
+ },
+ },
+ [
+ h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => {},
+ onClick: () => {
+ const { selected, network } = this.props
+ const url = genAccountLink(selected, network)
+ global.platform.openWindow({ url })
+ },
+ },
+ 'View account on Etherscan',
+ ),
+ h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => {},
+ onClick: () => {
+ const { selected } = this.props
+ const checkSumAddress = selected && ethUtil.toChecksumAddress(selected)
+ copyToClipboard(checkSumAddress)
+ },
+ },
+ 'Copy Address to clipboard',
+ ),
+ h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => {},
+ onClick: () => {
+ actions.requestAccountExport()
+ },
+ },
+ 'Export Private Key',
+ ),
+ ]
+ )
+ }
+
+ render () {
+ const { style } = this.props
+ const { optionsMenuActive, accountSelectorActive } = this.state
+
+ return h(
+ 'span',
+ {
+ style: style,
+ },
+ [
+ h(
+ 'i.fa.fa-angle-down',
+ {
+ style: {},
+ onClick: (event) => {
+ event.stopPropagation()
+ this.setState({
+ accountSelectorActive: !accountSelectorActive,
+ optionsMenuActive: false,
+ })
+ },
+ },
+ this.renderAccountSelector(),
+ ),
+ h(
+ 'i.fa.fa-ellipsis-h',
+ {
+ style: { 'marginLeft': '10px'},
+ onClick: (event) => {
+ event.stopPropagation()
+ this.setState({
+ accountSelectorActive: false,
+ optionsMenuActive: !optionsMenuActive,
+ })
+ },
+ },
+ this.renderAccountOptions()
+ ),
+ ]
+ )
+ }
+}
+
+AccountDropdowns.propTypes = {
+ identities: PropTypes.objectOf(PropTypes.object),
+ selected: PropTypes.string,
+}
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ actions: {
+ showConfigPage: () => dispatch(actions.showConfigPage()),
+ requestAccountExport: () => dispatch(actions.requestExportAccount()),
+ showAccountDetail: (address) => dispatch(actions.showAccountDetail(address)),
+ addNewAccount: () => dispatch(actions.addNewAccount()),
+ showImportPage: () => dispatch(actions.showImportPage()),
+ },
+ }
+}
+
+module.exports = {
+ AccountDropdowns: connect(null, mapDispatchToProps)(AccountDropdowns),
+}
diff --git a/ui/app/components/account-info-link.js b/ui/app/components/account-info-link.js
deleted file mode 100644
index 6526ab502..000000000
--- a/ui/app/components/account-info-link.js
+++ /dev/null
@@ -1,41 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const Tooltip = require('./tooltip')
-const genAccountLink = require('../../lib/account-link')
-
-module.exports = AccountInfoLink
-
-inherits(AccountInfoLink, Component)
-function AccountInfoLink () {
- Component.call(this)
-}
-
-AccountInfoLink.prototype.render = function () {
- const { selected, network } = this.props
- const title = 'View account on Etherscan'
- const url = genAccountLink(selected, network)
-
- if (!url) {
- return null
- }
-
- return h('.account-info-link', {
- style: {
- display: 'flex',
- alignItems: 'center',
- },
- }, [
-
- h(Tooltip, {
- title,
- }, [
- h('i.fa.fa-info-circle.cursor-pointer.color-orange', {
- style: {
- margin: '5px',
- },
- onClick () { global.platform.openWindow({ url }) },
- }),
- ]),
- ])
-}
diff --git a/ui/app/components/drop-menu-item.js b/ui/app/components/drop-menu-item.js
deleted file mode 100644
index e42948209..000000000
--- a/ui/app/components/drop-menu-item.js
+++ /dev/null
@@ -1,59 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-
-module.exports = DropMenuItem
-
-inherits(DropMenuItem, Component)
-function DropMenuItem () {
- Component.call(this)
-}
-
-DropMenuItem.prototype.render = function () {
- return h('li.drop-menu-item', {
- onClick: () => {
- this.props.closeMenu()
- this.props.action()
- },
- style: {
- listStyle: 'none',
- padding: '6px 16px 6px 5px',
- fontFamily: 'Montserrat Regular',
- color: 'rgb(125, 128, 130)',
- cursor: 'pointer',
- display: 'flex',
- justifyContent: 'flex-start',
- },
- }, [
- this.props.icon,
- this.props.label,
- this.activeNetworkRender(),
- ])
-}
-
-DropMenuItem.prototype.activeNetworkRender = function () {
- 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 'Ropsten Test Network':
- if (providerType === 'ropsten') return h('.check', '✓')
- break
- case 'Kovan Test Network':
- if (providerType === 'kovan') return h('.check', '✓')
- break
- case 'Rinkeby Test Network':
- if (providerType === 'rinkeby') return h('.check', '✓')
- break
- case 'Localhost 8545':
- if (activeNetwork === 'http://localhost:8545') return h('.check', '✓')
- break
- default:
- if (activeNetwork === 'custom') return h('.check', '✓')
- }
-}
diff --git a/ui/app/components/dropdown.js b/ui/app/components/dropdown.js
new file mode 100644
index 000000000..759800fd6
--- /dev/null
+++ b/ui/app/components/dropdown.js
@@ -0,0 +1,92 @@
+const Component = require('react').Component
+const PropTypes = require('react').PropTypes
+const h = require('react-hyperscript')
+const MenuDroppo = require('menu-droppo')
+const extend = require('xtend')
+
+const noop = () => {}
+
+class Dropdown extends Component {
+ render () {
+ const { isOpen, onClickOutside, style, innerStyle, children } = this.props
+
+ const innerStyleDefaults = extend({
+ borderRadius: '4px',
+ padding: '8px 16px',
+ background: 'rgba(0, 0, 0, 0.8)',
+ boxShadow: 'rgba(0, 0, 0, 0.15) 0px 2px 2px 2px',
+ }, innerStyle)
+
+ return h(
+ MenuDroppo,
+ {
+ isOpen,
+ zIndex: 11,
+ onClickOutside,
+ style,
+ innerStyle: innerStyleDefaults,
+ },
+ [
+ h(
+ 'style',
+ `
+ li.dropdown-menu-item:hover { color:rgb(225, 225, 225); }
+ li.dropdown-menu-item { color: rgb(185, 185, 185); }
+ `
+ ),
+ ...children,
+ ]
+ )
+ }
+}
+
+Dropdown.defaultProps = {
+ isOpen: false,
+ onClick: noop,
+}
+
+Dropdown.propTypes = {
+ isOpen: PropTypes.bool.isRequired,
+ onClick: PropTypes.func.isRequired,
+ children: PropTypes.node,
+ style: PropTypes.object.isRequired,
+}
+
+class DropdownMenuItem extends Component {
+ render () {
+ const { onClick, closeMenu, children } = this.props
+
+ return h(
+ 'li.dropdown-menu-item',
+ {
+ onClick: () => {
+ onClick()
+ closeMenu()
+ },
+ style: {
+ listStyle: 'none',
+ padding: '8px 0px 8px 0px',
+ fontSize: '12px',
+ fontStyle: 'normal',
+ fontFamily: 'Montserrat Regular',
+ cursor: 'pointer',
+ display: 'flex',
+ justifyContent: 'flex-start',
+ alignItems: 'center',
+ },
+ },
+ children
+ )
+ }
+}
+
+DropdownMenuItem.propTypes = {
+ closeMenu: PropTypes.func.isRequired,
+ onClick: PropTypes.func.isRequired,
+ children: PropTypes.node,
+}
+
+module.exports = {
+ Dropdown,
+ DropdownMenuItem,
+}
diff --git a/ui/app/components/editable-label.js b/ui/app/components/editable-label.js
index 41936f5e0..167be7eaf 100644
--- a/ui/app/components/editable-label.js
+++ b/ui/app/components/editable-label.js
@@ -30,7 +30,12 @@ EditableLabel.prototype.render = function () {
} else {
return h('div.name-label', {
onClick: (event) => {
- this.setState({ isEditingLabel: true })
+ const nameAttribute = event.target.getAttribute('name')
+ // checks for class to handle smaller CTA above the account name
+ const classAttribute = event.target.getAttribute('class')
+ if (nameAttribute === 'edit' || classAttribute === 'edit-text') {
+ this.setState({ isEditingLabel: true })
+ }
},
}, this.props.children)
}
diff --git a/ui/app/components/loading.js b/ui/app/components/loading.js
index 87d6f5d20..163792584 100644
--- a/ui/app/components/loading.js
+++ b/ui/app/components/loading.js
@@ -1,7 +1,6 @@
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)
@@ -15,35 +14,28 @@ LoadingIndicator.prototype.render = function () {
const { isLoading, loadingMessage } = this.props
return (
- h(ReactCSSTransitionGroup, {
- className: 'css-transition-group',
- transitionName: 'loader',
- transitionEnterTimeout: 150,
- transitionLeaveTimeout: 150,
+ isLoading ? h('.full-flex-height', {
+ style: {
+ left: '0px',
+ zIndex: 10,
+ position: 'absolute',
+ flexDirection: 'column',
+ display: 'flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ height: '100%',
+ width: '100%',
+ background: 'rgba(255, 255, 255, 0.8)',
+ },
}, [
+ h('img', {
+ src: 'images/loading.svg',
+ }),
- isLoading ? h('div', {
- style: {
- zIndex: 10,
- position: 'absolute',
- flexDirection: 'column',
- display: 'flex',
- justifyContent: 'center',
- alignItems: 'center',
- height: '100%',
- width: '100%',
- background: 'rgba(255, 255, 255, 0.8)',
- },
- }, [
- h('img', {
- src: 'images/loading.svg',
- }),
-
- h('br'),
-
- showMessageIfAny(loadingMessage),
- ]) : null,
- ])
+ h('br'),
+
+ showMessageIfAny(loadingMessage),
+ ]) : null
)
}
diff --git a/ui/app/components/network.js b/ui/app/components/network.js
index d5d3e18cd..698a0bbb9 100644
--- a/ui/app/components/network.js
+++ b/ui/app/components/network.js
@@ -39,7 +39,6 @@ Network.prototype.render = function () {
}),
h('i.fa.fa-sort-desc'),
])
-
} else if (providerName === 'mainnet') {
hoverText = 'Main Ethereum Network'
iconName = 'ethereum-network'
diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js
index e0a720426..76a265d63 100644
--- a/ui/app/components/shapeshift-form.js
+++ b/ui/app/components/shapeshift-form.js
@@ -2,7 +2,6 @@ const PersistentForm = require('../../lib/persistent-form')
const h = require('react-hyperscript')
const inherits = require('util').inherits
const connect = require('react-redux').connect
-const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
const actions = require('../actions')
const Qr = require('./qr-code')
const isValidAddress = require('../util').isValidAddress
@@ -24,14 +23,7 @@ function ShapeshiftForm () {
}
ShapeshiftForm.prototype.render = function () {
- return h(ReactCSSTransitionGroup, {
- className: 'css-transition-group',
- transitionName: 'main',
- transitionEnterTimeout: 300,
- transitionLeaveTimeout: 300,
- }, [
- this.props.qrRequested ? h(Qr, {key: 'qr'}) : this.renderMain(),
- ])
+ return this.props.qrRequested ? h(Qr, {key: 'qr'}) : this.renderMain()
}
ShapeshiftForm.prototype.renderMain = function () {
diff --git a/ui/app/components/tab-bar.js b/ui/app/components/tab-bar.js
index 6295e7dd9..bef444a48 100644
--- a/ui/app/components/tab-bar.js
+++ b/ui/app/components/tab-bar.js
@@ -21,6 +21,7 @@ TabBar.prototype.render = function () {
background: '#EBEBEB',
color: '#AEAEAE',
paddingTop: '4px',
+ minHeight: '30px',
},
}, tabs.map((tab) => {
const { key, content } = tab
diff --git a/ui/app/components/token-list.js b/ui/app/components/token-list.js
index 20cfa897e..5ea31ae8d 100644
--- a/ui/app/components/token-list.js
+++ b/ui/app/components/token-list.js
@@ -47,10 +47,11 @@ TokenList.prototype.render = function () {
return h(TokenCell, tokenData)
})
- return h('div', [
- h('ol', {
+ return h('.full-flex-height', [
+ this.renderTokenStatusBar(),
+
+ h('ol.full-flex-height.flex-column', {
style: {
- height: '260px',
overflowY: 'auto',
display: 'flex',
flexDirection: 'column',
@@ -63,6 +64,7 @@ TokenList.prototype.render = function () {
flex-direction: row;
align-items: center;
padding: 10px;
+ min-height: 50px;
}
li.token-cell > h3 {
@@ -76,17 +78,37 @@ TokenList.prototype.render = function () {
`),
...tokenViews,
- tokenViews.length ? null : this.message('No Tokens Found.'),
+ h('.flex-grow'),
]),
- this.addTokenButtonElement(),
])
}
-TokenList.prototype.addTokenButtonElement = function () {
- return h('div', [
- h('div.footer.hover-white.pointer', {
+TokenList.prototype.renderTokenStatusBar = function () {
+ const { tokens } = this.state
+
+ let msg
+ if (tokens.length === 1) {
+ msg = `You own 1 token`
+ } else if (tokens.length === 1) {
+ msg = `You own ${tokens.length} tokens`
+ } else {
+ msg = `No tokens found`
+ }
+
+ return h('div', {
+ style: {
+ display: 'flex',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ minHeight: '70px',
+ padding: '10px',
+ },
+ }, [
+ h('span', msg),
+ h('button', {
key: 'reveal-account-bar',
- onClick: () => {
+ onClick: (event) => {
+ event.preventDefault()
this.props.addToken()
},
style: {
@@ -97,7 +119,7 @@ TokenList.prototype.addTokenButtonElement = function () {
alignItems: 'center',
},
}, [
- h('i.fa.fa-plus.fa-lg'),
+ 'ADD TOKEN',
]),
])
}
diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js
index 3b4ba741e..69b72614c 100644
--- a/ui/app/components/transaction-list.js
+++ b/ui/app/components/transaction-list.js
@@ -24,7 +24,11 @@ TransactionList.prototype.render = function () {
return (
- h('section.transaction-list', [
+ h('section.transaction-list.full-flex-height', {
+ style: {
+ justifyContent: 'center',
+ },
+ }, [
h('style', `
.transaction-list .transaction-list-item:not(:last-of-type) {
@@ -39,7 +43,7 @@ TransactionList.prototype.render = function () {
h('.tx-list', {
style: {
overflowY: 'auto',
- height: '300px',
+ height: '100%',
padding: '0 20px',
textAlign: 'center',
},
@@ -64,13 +68,17 @@ TransactionList.prototype.render = function () {
},
})
})
- : h('.flex-center', {
+ : h('.flex-center.full-flex-height', {
style: {
flexDirection: 'column',
- height: '100%',
+ justifyContent: 'center',
},
}, [
- 'No transaction history.',
+ h('p', {
+ style: {
+ marginTop: '50px',
+ },
+ }, 'No transaction history.'),
]),
]),
])