From 4cd33453dc14ae9e6a797c16cccb52598904941a Mon Sep 17 00:00:00 2001 From: sdtsui Date: Sun, 13 Aug 2017 22:15:21 +0200 Subject: [WIP] Extract network dropdown into own component --- ui/app/actions.js | 18 ++ ui/app/app.js | 23 +- ui/app/components/dropdowns/index.js | 2 +- ui/app/components/dropdowns/network-dropdown.js | 276 ++++++++++++++++++++++++ ui/app/components/dropdowns/network.js | 259 ---------------------- ui/app/reducers/app.js | 13 +- 6 files changed, 327 insertions(+), 264 deletions(-) create mode 100644 ui/app/components/dropdowns/network-dropdown.js delete mode 100644 ui/app/components/dropdowns/network.js diff --git a/ui/app/actions.js b/ui/app/actions.js index 69fc46ca4..ae6d92733 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -15,6 +15,11 @@ var actions = { SIDEBAR_CLOSE: 'UI_SIDEBAR_CLOSE', showSidebar: showSidebar, hideSidebar: hideSidebar, + // network dropdown open + NETWORK_DROPDOWN_OPEN: 'UI_NETWORK_DROPDOWN_OPEN', + NETWORK_DROPDOWN_CLOSE: 'UI_NETWORK_DROPDOWN_CLOSE', + showNetworkDropdown: showNetworkDropdown, + hideNetworkDropdown: hideNetworkDropdown, // menu state getNetworkStatus: 'getNetworkStatus', // transition state @@ -773,6 +778,19 @@ function useEtherscanProvider () { } } +function showNetworkDropdown () { + return { + type: actions.NETWORK_DROPDOWN_OPEN, + } +} + +function hideNetworkDropdown () { + return { + type: actions.NETWORK_DROPDOWN_CLOSE, + } +} + + function showModal () { return { type: actions.MODAL_OPEN, diff --git a/ui/app/app.js b/ui/app/app.js index ea9104d7d..8ca60fee1 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -36,6 +36,8 @@ const HDRestoreVaultScreen = require('./keychains/hd/restore-vault') const RevealSeedConfirmation = require('./keychains/hd/recover-seed/confirmation') const ReactCSSTransitionGroup = require('react-addons-css-transition-group') const AccountDropdowns = require('./components/account-dropdowns').AccountDropdowns +const NetworkDropdown = require('./components/dropdowns/network-dropdown') +console.log('imported:', NetworkDropdown) // Global Modals const BuyModal = require('./components/modals/index').BuyModal @@ -55,6 +57,7 @@ function mapStateToProps (state) { return { // state from plugin + networkDropdownOpen: state.appState.networkDropdownOpen, sidebarOpen: state.appState.sidebarOpen, isLoading: state.appState.isLoading, loadingMessage: state.appState.loadingMessage, @@ -81,9 +84,11 @@ function mapStateToProps (state) { } } -function mapDispatchToProps (dispatch) { +function mapDispatchToProps (dispatch, ownProps) { return { hideSidebar: () => {dispatch(actions.hideSidebar())}, + showNetworkDropdown: () => {dispatch(actions.showNetworkDropdown())}, + hideNetworkDropdown: () => {dispatch(actions.hideNetworkDropdown())}, } } @@ -115,7 +120,11 @@ App.prototype.render = function () { this.renderSidebar(), // network dropdown - this.renderNetworkDropdown(), + h(NetworkDropdown, { + provider: this.props.provider, + frequentRpcList: this.props.frequentRpcList, + }, []), + // this.renderNetworkDropdown(), // this.renderDropdown(), h(Loading, { @@ -233,7 +242,14 @@ App.prototype.renderAppBar = function () { onClick: (event) => { event.preventDefault() event.stopPropagation() - this.setState({ isNetworkMenuOpen: !isNetworkMenuOpen }) + console.log("NI CLICK:", this.props.networkDropdownOpen) + if (this.props.networkDropdownOpen === false) { + this.props.showNetworkDropdown() + } else { + this.props.hideNetworkDropdown() + } + // this.props.toggleNetworkOpen() + // this.setState({ isNetworkMenuOpen: !isNetworkMenuOpen }) }, }), @@ -249,6 +265,7 @@ App.prototype.renderNetworkDropdown = function () { const { provider: { type: providerType, rpcTarget: activeNetwork } } = props const rpcList = props.frequentRpcList const state = this.state || {} + console.log("this.state:", state) const isOpen = state.isNetworkMenuOpen return h(Dropdown, { diff --git a/ui/app/components/dropdowns/index.js b/ui/app/components/dropdowns/index.js index b52dd8802..6723a2048 100644 --- a/ui/app/components/dropdowns/index.js +++ b/ui/app/components/dropdowns/index.js @@ -5,7 +5,7 @@ // App-Specific Instances // const AccountSelectionDropdown = require('./account-selection-dropdown') // const AccountOptionsDropdown = require('./account-options-dropdown') -const NetworkDropdown = require('./network-dropdown') +const NetworkDropdown = require('./network-dropdown').default module.exports = { // AccountSelectionDropdown, diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js new file mode 100644 index 000000000..42ab53c60 --- /dev/null +++ b/ui/app/components/dropdowns/network-dropdown.js @@ -0,0 +1,276 @@ +const Component = require('react').Component +const h = require('react-hyperscript') +const inherits = require('util').inherits +const connect = require('react-redux').connect +const actions = require('../../actions') +const Dropdown = require('../dropdown').Dropdown +const DropdownMenuItem = require('../dropdown').DropdownMenuItem + +function mapStateToProps (state) { + return { + provider: state.metamask.provider, + frequentRpcList: state.metamask.frequentRpcList || [], + networkDropdownOpen: state.appState.networkDropdownOpen, + } +} + +function mapDispatchToProps (dispatch) { + return { + hideModal: () => { + dispatch(actions.hideModal()) + }, + setProviderType: (type) => { + dispatch(actions.setProviderType(type)) + }, + setDefaultRpcTarget: () => { + dispatch(actions.setDefaultRpcTarget(type)) + }, + setRpcTarget: (target) => { + dispatch(actions.setRpcTarget(target)) + }, + showConfigPage: () => { + dispatch(actions.showConfigPage()) + }, + showNetworkDropdown: () => {dispatch(actions.showNetworkDropdown())}, + hideNetworkDropdown: () => {dispatch(actions.hideNetworkDropdown())}, + } +} + + +inherits(NetworkDropdown, Component) +function NetworkDropdown () { + Component.call(this) +} + +// renderNetworkDropdown +// renderCustomOption +// renderCommonRpc +// TODO: specify default props and proptypes +NetworkDropdown.prototype.render = function () { + console.log("RENDER") + const props = this.props + const { provider: { type: providerType, rpcTarget: activeNetwork } } = props + const rpcList = props.frequentRpcList + const state = this.state || {} + console.log("this.state", state) + const isOpen = this.props.networkDropdownOpen + + console.log("isOpen", isOpen) + + return h(Dropdown, { + useCssTransition: true, + isOpen, + onClickOutside: (event) => { + const { classList } = event.target + const isNotToggleElement = [ + classList.contains('menu-icon'), + classList.contains('network-name'), + classList.contains('network-indicator'), + ].filter(bool => bool).length === 0 + // classes from three constituent nodes of the toggle element + + if (isNotToggleElement) { + this.props.hideNetworkDropdown() + } + }, + zIndex: 11, + style: { + position: 'absolute', + right: '2px', + top: '38px', + }, + innerStyle: { + padding: '2px 16px 2px 0px', + }, + }, [ + + h( + DropdownMenuItem, + { + key: 'main', + closeMenu: () => this.props.hideNetworkDropdown(), + onClick: () => props.setProviderType('mainnet'), + style: { + fontSize: '18px', + }, + }, + [ + h('.menu-icon.diamond'), + 'Main Ethereum Network', + providerType === 'mainnet' ? h('.check', '✓') : null, + ] + ), + + h( + DropdownMenuItem, + { + key: 'ropsten', + closeMenu: () => this.props.hideNetworkDropdown(), + onClick: () => props.setProviderType('ropsten'), + style: { + fontSize: '18px', + }, + }, + [ + h('.menu-icon.red-dot'), + 'Ropsten Test Network', + providerType === 'ropsten' ? h('.check', '✓') : null, + ] + ), + + h( + DropdownMenuItem, + { + key: 'kovan', + closeMenu: () => this.props.hideNetworkDropdown(), + onClick: () => props.setProviderType('kovan'), + style: { + fontSize: '18px', + }, + }, + [ + h('.menu-icon.hollow-diamond'), + 'Kovan Test Network', + providerType === 'kovan' ? h('.check', '✓') : null, + ] + ), + + h( + DropdownMenuItem, + { + key: 'rinkeby', + closeMenu: () => this.props.hideNetworkDropdown(), + onClick: () => propssetProviderType('rinkeby'), + style: { + fontSize: '18px', + }, + }, + [ + h('.menu-icon.golden-square'), + 'Rinkeby Test Network', + providerType === 'rinkeby' ? h('.check', '✓') : null, + ] + ), + + h( + DropdownMenuItem, + { + key: 'default', + closeMenu: () => this.props.hideNetworkDropdown(), + onClick: () => props.setDefaultRpcTarget(), + style: { + fontSize: '18px', + }, + }, + [ + h('i.fa.fa-question-circle.fa-lg.menu-icon'), + 'Localhost 8545', + activeNetwork === 'http://localhost:8545' ? h('.check', '✓') : null, + ] + ), + + this.renderCustomOption(props.provider), + this.renderCommonRpc(rpcList, props.provider), + + h( + DropdownMenuItem, + { + closeMenu: () => this.props.hideNetworkDropdown(), + onClick: () => this.props.showConfigPage(), + style: { + fontSize: '18px', + }, + }, + [ + h('i.fa.fa-question-circle.fa-lg.menu-icon'), + 'Custom RPC', + activeNetwork === 'custom' ? h('.check', '✓') : null, + ] + ), + + ]) +} + + +NetworkDropdown.prototype.getNetworkName = function () { + const { provider } = this.props + const providerName = provider.type + + let name + + if (providerName === 'mainnet') { + name = 'Main Ethereum Network' + } else if (providerName === 'ropsten') { + name = 'Ropsten Test Network' + } else if (providerName === 'kovan') { + name = 'Kovan Test Network' + } else if (providerName === 'rinkeby') { + name = 'Rinkeby Test Network' + } else { + name = 'Unknown Private Network' + } + + return name +} + +NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) { + const props = this.props + const rpcTarget = provider.rpcTarget + + return rpcList.map((rpc) => { + if ((rpc === 'http://localhost:8545') || (rpc === rpcTarget)) { + return null + } else { + return h( + DropdownMenuItem, + { + key: `common${rpc}`, + closeMenu: () => this.props.hideNetworkDropdown(), + onClick: () => props.setRpcTarget(rpc), + }, + [ + h('i.fa.fa-question-circle.fa-lg.menu-icon'), + rpc, + rpcTarget === rpc ? h('.check', '✓') : null, + ] + ) + } + }) +} + +NetworkDropdown.prototype.renderCustomOption = function (provider) { + const { rpcTarget, type } = provider + const props = this.props + + if (type !== 'rpc') return null + + // Concatenate long URLs + let label = rpcTarget + if (rpcTarget.length > 31) { + label = label.substr(0, 34) + '...' + } + + switch (rpcTarget) { + + case 'http://localhost:8545': + return null + + default: + return h( + DropdownMenuItem, + { + key: rpcTarget, + onClick: () => props.setRpcTarget(rpcTarget), + closeMenu: () => this.props.hideNetworkDropdown(), + }, + [ + h('i.fa.fa-question-circle.fa-lg.menu-icon'), + label, + h('.check', '✓'), + ] + ) + } +} + +const comp = connect(mapStateToProps, mapDispatchToProps)(NetworkDropdown) +module.exports = comp diff --git a/ui/app/components/dropdowns/network.js b/ui/app/components/dropdowns/network.js deleted file mode 100644 index 2b693803b..000000000 --- a/ui/app/components/dropdowns/network.js +++ /dev/null @@ -1,259 +0,0 @@ -const Component = require('react').Component -const h = require('react-hyperscript') -const inherits = require('util').inherits -const connect = require('react-redux').connect -const actions = require('../../actions') - -// connect, dispatch actions... - // onClick: () => props.dispatch(actions.setProviderType('mainnet')), - // onClick: () => props.dispatch(actions.setDefaultRpcTarget()), - // onClick: () => props.dispatch(actions.setRpcTarget(rpcTarget)), - // onClick: () => this.props.dispatch(actions.showConfigPage()), - -function mapStateToProps (state) { - return { - active: state.appState.modalOpen - } -} - -function mapDispatchToProps (dispatch) { - return { - hideModal: () => { - dispatch(actions.hideModal()) - }, - } -} - - -inherits(NetworkDropdown, Component) -function NetworkDropdown () { - Component.call(this) -} - -module.exports = connect(mapStateToProps, mapDispatchToProps)(NetworkDropdown) - -// renderNetworkDropdown -// renderCustomOption -// renderCommonRpc -// TODO: specify default props and proptypes -NetworkDropdown.prototype.render = function () { - const props = this.props - const { provider: { type: providerType, rpcTarget: activeNetwork } } = props - const rpcList = props.frequentRpcList - const state = this.state || {} - const isOpen = state.isNetworkMenuOpen - - return h(Dropdown, { - useCssTransition: true, - isOpen, - onClickOutside: (event) => { - const { classList } = event.target - const isNotToggleElement = [ - classList.contains('menu-icon'), - classList.contains('network-name'), - classList.contains('network-indicator'), - ].filter(bool => bool).length === 0 - // classes from three constituent nodes of the toggle element - - if (isNotToggleElement) { - this.setState({ isNetworkMenuOpen: false }) - } - }, - zIndex: 11, - style: { - position: 'absolute', - right: '2px', - top: '38px', - }, - innerStyle: { - padding: '2px 16px 2px 0px', - }, - }, [ - - h( - DropdownMenuItem, - { - key: 'main', - closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }), - onClick: () => props.dispatch(actions.setProviderType('mainnet')), - style: { - fontSize: '18px', - }, - }, - [ - h('.menu-icon.diamond'), - 'Main Ethereum Network', - providerType === 'mainnet' ? h('.check', '✓') : null, - ] - ), - - h( - DropdownMenuItem, - { - key: 'ropsten', - closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }), - onClick: () => props.dispatch(actions.setProviderType('ropsten')), - style: { - fontSize: '18px', - }, - }, - [ - h('.menu-icon.red-dot'), - 'Ropsten Test Network', - providerType === 'ropsten' ? h('.check', '✓') : null, - ] - ), - - h( - DropdownMenuItem, - { - key: 'kovan', - closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }), - onClick: () => props.dispatch(actions.setProviderType('kovan')), - style: { - fontSize: '18px', - }, - }, - [ - h('.menu-icon.hollow-diamond'), - 'Kovan Test Network', - providerType === 'kovan' ? h('.check', '✓') : null, - ] - ), - - h( - DropdownMenuItem, - { - key: 'rinkeby', - closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }), - onClick: () => props.dispatch(actions.setProviderType('rinkeby')), - style: { - fontSize: '18px', - }, - }, - [ - h('.menu-icon.golden-square'), - 'Rinkeby Test Network', - providerType === 'rinkeby' ? h('.check', '✓') : null, - ] - ), - - h( - DropdownMenuItem, - { - key: 'default', - closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }), - onClick: () => props.dispatch(actions.setDefaultRpcTarget()), - style: { - fontSize: '18px', - }, - }, - [ - h('i.fa.fa-question-circle.fa-lg.menu-icon'), - 'Localhost 8545', - activeNetwork === 'http://localhost:8545' ? h('.check', '✓') : null, - ] - ), - - this.renderCustomOption(props.provider), - this.renderCommonRpc(rpcList, props.provider), - - h( - DropdownMenuItem, - { - closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }), - onClick: () => this.props.dispatch(actions.showConfigPage()), - style: { - fontSize: '18px', - }, - }, - [ - h('i.fa.fa-question-circle.fa-lg.menu-icon'), - 'Custom RPC', - activeNetwork === 'custom' ? h('.check', '✓') : null, - ] - ), - - ]) -} - - -NetworkDropdown.prototype.getNetworkName = function () { - const { provider } = this.props - const providerName = provider.type - - let name - - if (providerName === 'mainnet') { - name = 'Main Ethereum Network' - } else if (providerName === 'ropsten') { - name = 'Ropsten Test Network' - } else if (providerName === 'kovan') { - name = 'Kovan Test Network' - } else if (providerName === 'rinkeby') { - name = 'Rinkeby Test Network' - } else { - name = 'Unknown Private Network' - } - - return name -} - -NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) { - const props = this.props - const rpcTarget = provider.rpcTarget - - return rpcList.map((rpc) => { - if ((rpc === 'http://localhost:8545') || (rpc === rpcTarget)) { - return null - } else { - return h( - DropdownMenuItem, - { - key: `common${rpc}`, - closeMenu: () => this.setState({ isNetworkMenuOpen: false }), - onClick: () => props.dispatch(actions.setRpcTarget(rpc)), - }, - [ - h('i.fa.fa-question-circle.fa-lg.menu-icon'), - rpc, - rpcTarget === rpc ? h('.check', '✓') : null, - ] - ) - } - }) -} - -NetworkDropdown.prototype.renderCustomOption = function (provider) { - const { rpcTarget, type } = provider - const props = this.props - - if (type !== 'rpc') return null - - // Concatenate long URLs - let label = rpcTarget - if (rpcTarget.length > 31) { - label = label.substr(0, 34) + '...' - } - - switch (rpcTarget) { - - case 'http://localhost:8545': - return null - - default: - return h( - DropdownMenuItem, - { - key: rpcTarget, - onClick: () => props.dispatch(actions.setRpcTarget(rpcTarget)), - closeMenu: () => this.setState({ isNetworkMenuOpen: false }), - }, - [ - h('i.fa.fa-question-circle.fa-lg.menu-icon'), - label, - h('.check', '✓'), - ] - ) - } -} diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js index 878852bf6..3e74fb732 100644 --- a/ui/app/reducers/app.js +++ b/ui/app/reducers/app.js @@ -38,6 +38,7 @@ function reduceApp (state, action) { menuOpen: false, modalOpen: false, sidebarOpen: false, + networkDropdownOpen: false, currentView: seedWords ? seedConfView : defaultView, accountDetail: { subview: 'transactions', @@ -51,6 +52,17 @@ function reduceApp (state, action) { }, state.appState) switch (action.type) { + // dropdown methods + case actions.NETWORK_DROPDOWN_OPEN: + return extend(appState, { + networkDropdownOpen: true, + }) + + case actions.NETWORK_DROPDOWN_CLOSE: + return extend(appState, { + networkDropdownOpen: false, + }) + // sidebar methods case actions.SIDEBAR_OPEN: return extend(appState, { @@ -74,7 +86,6 @@ function reduceApp (state, action) { }) // transition methods - case actions.TRANSITION_FORWARD: return extend(appState, { transForward: true, -- cgit v1.2.3