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
);
}