From 85759d73b4c8cdbfe8e79736a3e0acb4890fd5d2 Mon Sep 17 00:00:00 2001 From: crptm Date: Tue, 4 Jul 2017 05:25:01 +0400 Subject: [PATCH] type dropdown, config actions --- common/actions/config.js | 36 ++-- common/components/Header/index.jsx | 46 ++--- common/components/index.js | 8 +- common/components/ui/Dropdown.jsx | 33 ++-- common/config/data.js | 280 ++++++++++++----------------- common/containers/App/index.jsx | 47 ++--- common/libs/nodes/base.js | 8 + common/libs/nodes/index.js | 3 + common/libs/nodes/rpc.js | 10 ++ common/reducers/config.js | 47 ++--- common/reducers/index.js | 2 +- common/sagas/wallet.js | 2 +- common/selectors/config.js | 8 + common/translations/index.js | 4 +- 14 files changed, 256 insertions(+), 278 deletions(-) create mode 100644 common/libs/nodes/base.js create mode 100644 common/libs/nodes/index.js create mode 100644 common/libs/nodes/rpc.js create mode 100644 common/selectors/config.js diff --git a/common/actions/config.js b/common/actions/config.js index ee0d607f..8cbd61b2 100644 --- a/common/actions/config.js +++ b/common/actions/config.js @@ -1,18 +1,30 @@ // @flow import { setLanguage } from 'translations'; -export const CONFIG_LANGUAGE_CHANGE = 'CONFIG_LANGUAGE_CHANGE'; -export const CONFIG_NODE_CHANGE = 'CONFIG_NODE_CHANGE'; -export const CHANGE_LANGUAGE = (value: any) => { - setLanguage(value.sign); - return { - type: CONFIG_LANGUAGE_CHANGE, - value - }; +export type ChangeNodeAction = { + type: 'CONFIG_NODE_CHANGE', + // FIXME $keyof? + value: string }; -export const CHANGE_NODE = (value: any) => - Object({ - type: CONFIG_NODE_CHANGE, +export type ChangeLanguageAction = { + type: 'CONFIG_LANGUAGE_CHANGE', + value: string +}; + +export type ConfigAction = ChangeNodeAction | ChangeLanguageAction; + +export function changeLanguage(sign: string) { + setLanguage(sign); + return { + type: 'CONFIG_LANGUAGE_CHANGE', + value: sign + }; +} + +export function changeNode(value: string): ChangeNodeAction { + return { + type: 'CONFIG_NODE_CHANGE', value - }); + }; +} diff --git a/common/components/Header/index.jsx b/common/components/Header/index.jsx index 727d4cac..a721008f 100644 --- a/common/components/Header/index.jsx +++ b/common/components/Header/index.jsx @@ -1,26 +1,23 @@ // @flow import React, { Component } from 'react'; -import PropTypes from 'prop-types'; import TabsOptions from './components/TabsOptions'; import { Link } from 'react-router'; import { Dropdown } from 'components/ui'; -import { languages, nodeList } from '../../config/data'; +import { languages, NODES } from '../../config/data'; export default class Header extends Component { - static propTypes = { - location: PropTypes.object, + props: { + languageSelection: string, + nodeSelection: string, - // Language DropDown - changeLanguage: PropTypes.func, - languageSelection: PropTypes.object, - - // Node Dropdown - changeNode: PropTypes.func, - nodeSelection: PropTypes.object + changeLanguage: (sign: string) => any, + changeNode: (key: string) => any }; render() { - const { languageSelection, changeLanguage, changeNode, nodeSelection } = this.props; + const { languageSelection, changeNode, nodeSelection } = this.props; + const selectedLanguage = languages.find(l => l.sign === languageSelection) || languages[0]; + const selectedNode = NODES[nodeSelection]; return (
@@ -41,10 +38,10 @@ export default class Header extends Component {     o.name} - value={languageSelection} + value={selectedLanguage} extra={[
  • ,
  • @@ -53,23 +50,23 @@ export default class Header extends Component {
  • ]} - onChange={changeLanguage} + onChange={this.changeLanguage} />     [ - o.name, + NODES[o].network, ' ', - ({o.service}) + + ({NODES[o].service}) + ]} value={nodeSelection} extra={
  • - {}}> - Add Custom Node - + {}}>Add Custom Node
  • } onChange={changeNode} @@ -79,8 +76,11 @@ export default class Header extends Component { -
    ); } + + changeLanguage = (value: { sign: string }) => { + this.props.changeLanguage(value.sign); + }; } diff --git a/common/components/index.js b/common/components/index.js index 9372d321..e4fe4b8f 100644 --- a/common/components/index.js +++ b/common/components/index.js @@ -1,3 +1,5 @@ -export Header from './Header'; -export Footer from './Footer'; -export Root from './Root'; +// @flow + +export { default as Header } from './Header'; +export { default as Footer } from './Footer'; +export { default as Root } from './Root'; diff --git a/common/components/ui/Dropdown.jsx b/common/components/ui/Dropdown.jsx index 0ccc6c43..f576ffef 100644 --- a/common/components/ui/Dropdown.jsx +++ b/common/components/ui/Dropdown.jsx @@ -1,26 +1,21 @@ // @flow import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -export default class DropdownComponent extends Component { - static propTypes = { - value: PropTypes.object.isRequired, - options: PropTypes.arrayOf(PropTypes.object).isRequired, - ariaLabel: PropTypes.string.isRequired, - formatTitle: PropTypes.func.isRequired, - extra: PropTypes.node, - onChange: PropTypes.func.isRequired - }; +type Props = { + value: T, + options: T[], + ariaLabel: string, + formatTitle: (option: T) => any, + extra?: any, + onChange: (value: T) => void +} - // FIXME - props: { - value: any, - options: any[], - ariaLabel: string, - formatTitle: (option: any) => any, - extra?: any, - onChange: (value: any) => void - }; +type State = { + expanded: boolean +} + +export default class DropdownComponent extends Component, State> { + props: Props state = { expanded: false diff --git a/common/config/data.js b/common/config/data.js index dac459b5..09dd1a6d 100644 --- a/common/config/data.js +++ b/common/config/data.js @@ -1,168 +1,124 @@ +// @flow +import { RPCNode } from 'libs/nodes'; + export const DONATION_ADDRESSES_MAP = { - BTC: '1MEWT2SGbqtz6mPCgFcnea8XmWV5Z4Wc6', - ETH: '0x7cB57B5A97eAbe94205C07890BE4c1aD31E486A8', - REP: '0x7cB57B5A97eAbe94205C07890BE4c1aD31E486A8' + BTC: '1MEWT2SGbqtz6mPCgFcnea8XmWV5Z4Wc6', + ETH: '0x7cB57B5A97eAbe94205C07890BE4c1aD31E486A8', + REP: '0x7cB57B5A97eAbe94205C07890BE4c1aD31E486A8' }; export const languages = [ - { - sign: 'en', - name: 'English' - }, - { - sign: 'de', - name: 'Deutsch' - }, - { - sign: 'el', - name: 'Ελληνικά' - }, - { - sign: 'es', - name: 'Español' - }, - { - sign: 'fi', - name: 'Suomi' - }, - { - sign: 'fr', - name: 'Français' - }, - { - sign: 'hu', - name: 'Magyar' - }, - { - sign: 'id', - name: 'Indonesian' - }, - { - sign: 'it', - name: 'Italiano' - }, - { - sign: 'ja', - name: '日本語' - }, - { - sign: 'nl', - name: 'Nederlands' - }, - { - sign: 'no', - name: 'Norsk Bokmål' - }, - { - sign: 'pl', - name: 'Polski' - }, - { - sign: 'pt', - name: 'Português' - }, - { - sign: 'ru', - name: 'Русский' - }, - { - sign: 'ko', - name: 'Korean' - }, - // { - // 'sign': 'sk', - // 'name': 'Slovenčina' - // }, - // { - // 'sign': 'sl', - // 'name': 'Slovenščina' - // }, - // { - // 'sign': 'sv', - // 'name': 'Svenska' - // }, - { - sign: 'tr', - name: 'Türkçe' - }, - { - sign: 'vi', - name: 'Tiếng Việt' - }, - { - sign: 'zhcn', - name: '简体中文' - }, - { - sign: 'zhtw', - name: '繁體中文' - } + { + sign: 'en', + name: 'English' + }, + { + sign: 'de', + name: 'Deutsch' + }, + { + sign: 'el', + name: 'Ελληνικά' + }, + { + sign: 'es', + name: 'Español' + }, + { + sign: 'fi', + name: 'Suomi' + }, + { + sign: 'fr', + name: 'Français' + }, + { + sign: 'hu', + name: 'Magyar' + }, + { + sign: 'id', + name: 'Indonesian' + }, + { + sign: 'it', + name: 'Italiano' + }, + { + sign: 'ja', + name: '日本語' + }, + { + sign: 'nl', + name: 'Nederlands' + }, + { + sign: 'no', + name: 'Norsk Bokmål' + }, + { + sign: 'pl', + name: 'Polski' + }, + { + sign: 'pt', + name: 'Português' + }, + { + sign: 'ru', + name: 'Русский' + }, + { + sign: 'ko', + name: 'Korean' + }, + // { + // 'sign': 'sk', + // 'name': 'Slovenčina' + // }, + // { + // 'sign': 'sl', + // 'name': 'Slovenščina' + // }, + // { + // 'sign': 'sv', + // 'name': 'Svenska' + // }, + { + sign: 'tr', + name: 'Türkçe' + }, + { + sign: 'vi', + name: 'Tiếng Việt' + }, + { + sign: 'zhcn', + name: '简体中文' + }, + { + sign: 'zhtw', + name: '繁體中文' + } ]; -export const nodeList = [ - { - name: 'ETH', - blockExplorerTX: 'https://etherscan.io/tx/[[txHash]]', - blockExplorerAddr: 'https://etherscan.io/address/[[address]]', - // 'type': nodes.nodeTypes.ETH, - eip155: true, - chainId: 1, - // 'tokenList': require('./tokens/ethTokens.json'), - // 'abiList': require('./abiDefinitions/ethAbi.json'), - estimateGas: true, - service: 'MyEtherWallet' - // 'lib': new nodes.customNode('https://api.myetherapi.com/eth', '') - }, - { - name: 'ETH', - blockExplorerTX: 'https://etherscan.io/tx/[[txHash]]', - blockExplorerAddr: 'https://etherscan.io/address/[[address]]', - // 'type': nodes.nodeTypes.ETH, - eip155: true, - chainId: 1, - // 'tokenList': require('./tokens/ethTokens.json'), - // 'abiList': require('./abiDefinitions/ethAbi.json'), - estimateGas: false, - service: 'Etherscan.io' - // 'lib': require('./nodeHelpers/etherscan') - }, - { - name: 'Ropsten', - // 'type': nodes.nodeTypes.Ropsten, - blockExplorerTX: 'https://ropsten.etherscan.io/tx/[[txHash]]', - blockExplorerAddr: 'https://ropsten.etherscan.io/address/[[address]]', - eip155: true, - chainId: 3, - // 'tokenList': require('./tokens/ropstenTokens.json'), - // 'abiList': require('./abiDefinitions/ropstenAbi.json'), - estimateGas: false, - service: 'MyEtherWallet' - // 'lib': new nodes.customNode('https://api.myetherapi.com/rop', '') - }, - { - name: 'Kovan', - // 'type': nodes.nodeTypes.Kovan, - blockExplorerTX: 'https://kovan.etherscan.io/tx/[[txHash]]', - blockExplorerAddr: 'https://kovan.etherscan.io/address/[[address]]', - eip155: true, - chainId: 42, - // 'tokenList': require('./tokens/kovanTokens.json'), - // 'abiList': require('./abiDefinitions/kovanAbi.json'), - estimateGas: false, - service: 'Etherscan.io' - // 'lib': require('./nodeHelpers/etherscanKov') - }, - { - name: 'ETC', - blockExplorerTX: 'https://gastracker.io/tx/[[txHash]]', - blockExplorerAddr: 'https://gastracker.io/addr/[[address]]', - // 'type': nodes.nodeTypes.ETC, - eip155: true, - chainId: 61, - // 'tokenList': require('./tokens/etcTokens.json'), - // 'abiList': require('./abiDefinitions/etcAbi.json'), - estimateGas: false, - service: 'Epool.io' - // 'lib': new nodes.customNode('https://mewapi.epool.io', '') - } -]; +export const NETWORKS = { + ETH: { + name: 'ETH', + blockExplorerTX: 'https://etherscan.io/tx/[[txHash]]', + blockExplorerAddr: 'https://etherscan.io/address/[[address]]', + chainId: 1 + } +}; + +export const NODES = { + eth_mew: { + network: 'ETH', + lib: new RPCNode('https://api.myetherapi.com/eth'), + service: 'MyEtherWallet', + estimateGas: true, + eip155: true + // 'tokenList': require('./tokens/ethTokens.json'), + // 'abiList': require('./abiDefinitions/ethAbi.json'), + } +}; diff --git a/common/containers/App/index.jsx b/common/containers/App/index.jsx index 1d6d3127..47c300e3 100644 --- a/common/containers/App/index.jsx +++ b/common/containers/App/index.jsx @@ -2,32 +2,23 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { Footer, Header } from 'components'; -import PropTypes from 'prop-types'; import Notifications from './Notifications'; - -import { CHANGE_LANGUAGE, CHANGE_NODE } from 'actions/config'; +import * as actions from 'actions/config'; class App extends Component { - constructor(props) { - super(props); - } + props: { + // FIXME + children: any, + location: any, + router: any, + isMobile: boolean, - static propTypes = { - children: PropTypes.node.isRequired, - location: PropTypes.object, - handleWindowResize: PropTypes.func, + languageSelection: string, + nodeSelection: string, - router: PropTypes.object, - isMobile: PropTypes.bool, - - // BEGIN ACTUAL - languageSelection: PropTypes.object, - changeLanguage: PropTypes.func, - - changeNode: PropTypes.func, - nodeSelection: PropTypes.object, - - showNotification: PropTypes.func + changeLanguage: typeof actions.changeLanguage, + changeNode: typeof actions.changeNode, + handleWindowResize: () => void }; render() { @@ -72,16 +63,4 @@ function mapStateToProps(state) { }; } -function mapDispatchToProps(dispatch) { - return { - // FIXME replace with actual types - changeNode: (i: any) => { - dispatch(CHANGE_NODE(i)); - }, - changeLanguage: (i: any) => { - dispatch(CHANGE_LANGUAGE(i)); - } - }; -} - -export default connect(mapStateToProps, mapDispatchToProps)(App); +export default connect(mapStateToProps, actions)(App); diff --git a/common/libs/nodes/base.js b/common/libs/nodes/base.js new file mode 100644 index 00000000..2cf5a517 --- /dev/null +++ b/common/libs/nodes/base.js @@ -0,0 +1,8 @@ +// @flow + +export default class BaseNode { + // FIXME bignumber? + queryBalance(address: string): Promise { + throw 'Implement me'; + } +} diff --git a/common/libs/nodes/index.js b/common/libs/nodes/index.js new file mode 100644 index 00000000..4ac70297 --- /dev/null +++ b/common/libs/nodes/index.js @@ -0,0 +1,3 @@ +// @flow +export { default as BaseNode } from './base'; +export { default as RPCNode } from './rpc'; diff --git a/common/libs/nodes/rpc.js b/common/libs/nodes/rpc.js new file mode 100644 index 00000000..1c4e3059 --- /dev/null +++ b/common/libs/nodes/rpc.js @@ -0,0 +1,10 @@ +// @flow +import BaseNode from './base'; + +export default class RPCNode extends BaseNode { + endpoint: string; + constructor(endpoint: string) { + super(); + this.endpoint = endpoint; + } +} diff --git a/common/reducers/config.js b/common/reducers/config.js index 984a08a5..16bc939f 100644 --- a/common/reducers/config.js +++ b/common/reducers/config.js @@ -1,36 +1,39 @@ // @flow -import { - CONFIG_LANGUAGE_CHANGE, - CONFIG_NODE_CHANGE -} from 'actions/config'; -import {languages, nodeList} from '../config/data'; +import type { ConfigAction, ChangeNodeAction, ChangeLanguageAction } from 'actions/config'; +import { languages, NODES } from '../config/data'; export type State = { // FIXME languageSelection: string, nodeSelection: string +}; + +const initialState: State = { + languageSelection: languages[0].sign, + nodeSelection: Object.keys(NODES)[0] +}; + +function changeLanguage(state: State, action: ChangeLanguageAction): State { + return { + ...state, + languageSelection: action.value + }; } -const initialState = { - languageSelection: languages[0], - nodeSelection: nodeList[0] +function changeNode(state: State, action: ChangeNodeAction): State { + return { + ...state, + nodeSelection: action.value + }; } -export function config(state: State = initialState, action): State { +export function config(state: State = initialState, action: ConfigAction): State { switch (action.type) { - case CONFIG_LANGUAGE_CHANGE: { - return { - ...state, - languageSelection: action.value - } - } - case CONFIG_NODE_CHANGE: { - return { - ...state, - nodeSelection: action.value - } - } + case 'CONFIG_LANGUAGE_CHANGE': + return changeLanguage(state, action); + case 'CONFIG_NODE_CHANGE': + return changeNode(state, action); default: - return state + return state; } } diff --git a/common/reducers/index.js b/common/reducers/index.js index a56d3b27..1813c015 100644 --- a/common/reducers/index.js +++ b/common/reducers/index.js @@ -22,7 +22,7 @@ import { routerReducer } from 'react-router-redux'; export type State = { generateWallet: GenerateWalletState, - conig: ConfigState, + config: ConfigState, notifications: NotificationsState, ens: EnsState, wallet: WalletState diff --git a/common/sagas/wallet.js b/common/sagas/wallet.js index 0a356630..b09bd42b 100644 --- a/common/sagas/wallet.js +++ b/common/sagas/wallet.js @@ -8,7 +8,7 @@ import PrivKeyWallet from 'libs/wallet/privkey'; function* init() { yield put(initWallet()); - // const node = select(node); + // const node = select(getNode); // yield call(); // fetch balance, // fetch tokens diff --git a/common/selectors/config.js b/common/selectors/config.js new file mode 100644 index 00000000..00389dfd --- /dev/null +++ b/common/selectors/config.js @@ -0,0 +1,8 @@ +// @flow +import type { State } from 'reducers'; +import { BaseNode } from 'libs/nodes'; +import { NODES } from 'config/data'; + +export function getNodeLib(state: State): BaseNode { + return NODES[state.config.nodeSelection].lib; +} diff --git a/common/translations/index.js b/common/translations/index.js index df491f12..668599a3 100644 --- a/common/translations/index.js +++ b/common/translations/index.js @@ -37,7 +37,9 @@ export function setLanguage(code: string) { export default function translate(key: string) { return markupToReact( - repository[activeLanguage][key] || repository[fallbackLanguage][key] || key + (repository[activeLanguage] && repository[activeLanguage][key]) || + repository[fallbackLanguage][key] || + key ); }