diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..38de99f8
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,10 @@
+# http://editorconfig.org
+root = true
+
+[{*.js,*.jsx}]
+end_of_line = lf
+charset = utf-8
+indent_size = 4
+indent_style = space
+trim_trailing_whitespace = true
+insert_final_newline = true
diff --git a/common/actions/config.js b/common/actions/config.js
index 6c012794..2ff73428 100644
--- a/common/actions/config.js
+++ b/common/actions/config.js
@@ -1,22 +1,12 @@
// @flow
export const CONFIG_LANGUAGE_CHANGE = 'CONFIG_LANGUAGE_CHANGE';
-export const CONFIG_LANGUAGE_DROPDOWN_TOGGLE = 'CONFIG_LANGUAGE_DROPDOWN_TOGGLE';
export const CONFIG_NODE_CHANGE = 'CONFIG_NODE_CHANGE';
-export const CONFIG_NODE_DROPDOWN_TOGGLE = 'CONFIG_NODE_DROPDOWN_TOGGLE';
-export const CHANGE_LANGUAGE = (index: number) => Object({
- type: CONFIG_LANGUAGE_CHANGE, index: index
+export const CHANGE_LANGUAGE = (value: any) => Object({
+ type: CONFIG_LANGUAGE_CHANGE, value
})
-export const TOGGLE_LANGUAGE_DROPDOWN = () => Object({
- type: CONFIG_LANGUAGE_DROPDOWN_TOGGLE
+export const CHANGE_NODE = (value: any) => Object({
+ type: CONFIG_NODE_CHANGE, value
})
-
-export const CHANGE_NODE = (index: number) => Object({
- type: CONFIG_NODE_CHANGE, index: index
-})
-
-export const TOGGLE_NODE_DROPDOWN = () => Object({
- type: CONFIG_NODE_DROPDOWN_TOGGLE
-})
\ No newline at end of file
diff --git a/common/components/Header/components/LanguageDropdownComponent.jsx b/common/components/Header/components/LanguageDropdownComponent.jsx
deleted file mode 100644
index 9bfb4a80..00000000
--- a/common/components/Header/components/LanguageDropdownComponent.jsx
+++ /dev/null
@@ -1,61 +0,0 @@
-import React, {Component} from "react";
-import {languages} from "reducers/config";
-import PropTypes from "prop-types";
-
-
-export default class LanguageDropdownComponent extends Component {
- constructor(props) {
- super(props);
- }
-
- static propTypes = {
- changeLanguage: PropTypes.func,
- languageSelection: PropTypes.number,
- languageToggle: PropTypes.bool,
- toggleLanguageDropdown: PropTypes.func
- };
-
- render() {
- let {
- languageSelection,
- changeLanguage,
- toggleLanguageDropdown,
- languageToggle
- } = this.props;
-
- return (
-
- toggleLanguageDropdown()}>
- {languages[languageSelection].name}
-
-
- {
- languageToggle &&
-
- }
-
- )
- }
-}
\ No newline at end of file
diff --git a/common/components/Header/components/NodeDropdownComponent.jsx b/common/components/Header/components/NodeDropdownComponent.jsx
deleted file mode 100644
index 45bae364..00000000
--- a/common/components/Header/components/NodeDropdownComponent.jsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import React, {Component} from "react";
-import {nodeList} from "reducers/config";
-import PropTypes from "prop-types";
-
-
-export default class NodeDropdownComponent extends Component {
- constructor(props) {
- super(props);
- }
-
- static propTypes = {
- changeNode: PropTypes.func,
- toggleNodeDropdown: PropTypes.func,
- nodeSelection: PropTypes.number,
- nodeToggle: PropTypes.bool
- };
-
- customNodeModalOpen() {
-
- }
-
- render() {
- let {
- changeNode,
- toggleNodeDropdown,
- nodeSelection,
- nodeToggle
- } = this.props;
-
- return (
-
- toggleNodeDropdown()}>
- {nodeList[nodeSelection].name}
- {' '} ({nodeList[nodeSelection].service})
-
-
- {
- nodeToggle &&
-
- }
-
- )
- }
-}
diff --git a/common/components/Header/index.jsx b/common/components/Header/index.jsx
index f3b720f5..f7674c2c 100644
--- a/common/components/Header/index.jsx
+++ b/common/components/Header/index.jsx
@@ -1,55 +1,24 @@
-import React, {Component} from "react";
-import NodeDropdownComponent from "./components/NodeDropdownComponent";
-import LanguageDropDownComponent from "./components/LanguageDropdownComponent";
-import PropTypes from "prop-types";
-import TabsOptions from "./components/TabsOptions";
-import {Link} from "react-router";
-
+// @flow
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import TabsOptions from './components/TabsOptions';
+import { Link } from 'react-router';
+import Dropdown from '../ui/Dropdown';
+import { languages, nodeList } from '../../config/data';
export default class Header extends Component {
- constructor(props) {
- super(props)
- }
-
static propTypes = {
- // LanguageDropDownComponentProps
+ // Language DropDown
changeLanguage: PropTypes.func,
- toggleLanguageDropdown: PropTypes.func,
- languageSelection: PropTypes.number,
- languageToggle: PropTypes.bool,
+ languageSelection: PropTypes.object,
- // NodeDropdownComponentProps
+ // Node Dropdown
changeNode: PropTypes.func,
- toggleNodeDropdown: PropTypes.func,
- nodeSelection: PropTypes.number,
- nodeToggle: PropTypes.bool
+ nodeSelection: PropTypes.object
};
render() {
- let {
- languageSelection,
- changeLanguage,
- toggleLanguageDropdown,
- languageToggle,
- changeNode,
- toggleNodeDropdown,
- nodeSelection,
- nodeToggle
- } = this.props;
-
- let LanguageDropDownComponentProps = {
- languageSelection,
- changeLanguage,
- toggleLanguageDropdown,
- languageToggle
- }
-
- let NodeDropdownComponentProps = {
- changeNode,
- toggleNodeDropdown,
- nodeSelection,
- nodeToggle
- }
+ const { languageSelection, changeLanguage, changeNode, nodeSelection } = this.props;
return (
@@ -58,26 +27,58 @@ export default class Header extends Component {
{/* TODO - don't hardcode image path*/}
+ alt="MyEtherWallet"
+ />
-
- Open-Source & Client-Side Ether Wallet · v3.6.0
-
+
+ Open-Source & Client-Side Ether Wallet · v3.6.0
+
-
+
o.name}
+ value={languageSelection}
+ extra={[
+ ,
+
+
+ Disclaimer
+
+
+ ]}
+ onChange={changeLanguage}
+ />
-
+ [
+ o.name,
+ ' ',
+ ({o.service})
+ ]}
+ value={nodeSelection}
+ extra={
+
+ {}}>
+ Add Custom Node
+
+
+ }
+ onChange={changeNode}
+ />
-
+
- )
+ );
}
}
diff --git a/common/components/ui/Dropdown.jsx b/common/components/ui/Dropdown.jsx
new file mode 100644
index 00000000..4c70ed0f
--- /dev/null
+++ b/common/components/ui/Dropdown.jsx
@@ -0,0 +1,81 @@
+// @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
+ };
+
+ // FIXME
+ props: {
+ value: any,
+ options: any[],
+ ariaLabel: string,
+ formatTitle: (option: any) => any,
+ extra?: any,
+ onChange: () => void
+ };
+
+ state = {
+ expanded: false
+ };
+
+ render() {
+ const { options, value, ariaLabel, extra } = this.props;
+
+ return (
+
+
+ {this.formatTitle(value)}
+
+
+ {this.state.expanded &&
+ }
+
+ );
+ }
+
+ formatTitle(option: any) {
+ return this.props.formatTitle(option);
+ }
+
+ toggleExpanded = () => {
+ this.setState(state => {
+ return {
+ expanded: !state.expanded
+ };
+ });
+ };
+
+ onChange = (value: any) => {
+ this.props.onChange(value);
+ this.setState({ expanded: false });
+ };
+}
diff --git a/common/config/base.js b/common/config/base.js
index bea121a3..1ef3b252 100644
--- a/common/config/base.js
+++ b/common/config/base.js
@@ -1,4 +1,2 @@
-'use strict';
-
// Settings configured here will be merged into the final config object.
export default {}
diff --git a/common/config/data.js b/common/config/data.js
new file mode 100644
index 00000000..1d2fc98d
--- /dev/null
+++ b/common/config/data.js
@@ -0,0 +1,159 @@
+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': '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', '')
+ }
+]
diff --git a/common/containers/App/index.jsx b/common/containers/App/index.jsx
index 28850d13..780f39a1 100644
--- a/common/containers/App/index.jsx
+++ b/common/containers/App/index.jsx
@@ -1,14 +1,13 @@
-import React, {Component} from "react";
-import {connect} from "react-redux";
-import {Footer, Header} from "components";
-import PropTypes from "prop-types";
-
-import {CHANGE_LANGUAGE, CHANGE_NODE, TOGGLE_LANGUAGE_DROPDOWN, TOGGLE_NODE_DROPDOWN} from "actions/config";
+import React, { Component } from 'react';
+import { connect } from 'react-redux';
+import { Footer, Header } from 'components';
+import PropTypes from 'prop-types';
+import { CHANGE_LANGUAGE, CHANGE_NODE } from 'actions/config';
class App extends Component {
constructor(props) {
- super(props)
+ super(props);
}
static propTypes = {
@@ -20,64 +19,50 @@ class App extends Component {
isMobile: PropTypes.bool,
// BEGIN ACTUAL
- languageSelection: PropTypes.number,
- languageToggle: PropTypes.bool,
+ languageSelection: PropTypes.object,
changeLanguage: PropTypes.func,
- toggleLanguageDropdown: PropTypes.func,
changeNode: PropTypes.func,
- toggleNodeDropdown: PropTypes.func,
- nodeSelection: PropTypes.number,
- nodeToggle: PropTypes.bool,
- }
-
+ nodeSelection: PropTypes.object
+ };
componentWillMount() {
- let {handleWindowResize} = this.props
- window.addEventListener('resize', handleWindowResize)
+ let { handleWindowResize } = this.props;
+ window.addEventListener('resize', handleWindowResize);
}
-
render() {
let {
children,
// APP
languageSelection,
changeLanguage,
- languageToggle,
- toggleLanguageDropdown,
changeNode,
- toggleNodeDropdown,
- nodeSelection,
- nodeToggle
+ nodeSelection
} = this.props;
// let title = children.props.route.name;
let headerProps = {
changeLanguage,
- toggleLanguageDropdown,
languageSelection,
- languageToggle,
changeNode,
- toggleNodeDropdown,
- nodeSelection,
- nodeToggle
- }
+ nodeSelection
+ };
return (
-
+
- { children}
+ {children}
-
+
- )
+ );
}
}
@@ -87,24 +72,18 @@ function mapStateToProps(state) {
nodeToggle: state.config.nodeToggle,
languageSelection: state.config.languageSelection,
languageToggle: state.config.languageToggle
- }
+ };
}
function mapDispatchToProps(dispatch) {
return {
changeNode: (i: number) => {
- dispatch(CHANGE_NODE(i))
- },
- toggleNodeDropdown: () => {
- dispatch(TOGGLE_NODE_DROPDOWN())
+ dispatch(CHANGE_NODE(i));
},
changeLanguage: (i: number) => {
- dispatch(CHANGE_LANGUAGE(i))
- },
- toggleLanguageDropdown: () => {
- dispatch(TOGGLE_LANGUAGE_DROPDOWN())
+ dispatch(CHANGE_LANGUAGE(i));
}
- }
+ };
}
-export default connect(mapStateToProps, mapDispatchToProps)(App)
+export default connect(mapStateToProps, mapDispatchToProps)(App);
diff --git a/common/reducers/config.js b/common/reducers/config.js
index 137a1634..aaf5b38a 100644
--- a/common/reducers/config.js
+++ b/common/reducers/config.js
@@ -1,16 +1,12 @@
import {
CONFIG_LANGUAGE_CHANGE,
- CONFIG_LANGUAGE_DROPDOWN_TOGGLE,
- CONFIG_NODE_CHANGE,
- CONFIG_NODE_DROPDOWN_TOGGLE
-} from 'actions/config'
-
+ CONFIG_NODE_CHANGE
+} from 'actions/config';
+import {languages, nodeList} from '../config/data';
const initialState = {
- languageSelection: 0,
- languageToggle: false,
- nodeSelection: 0,
- nodeToggle: false
+ languageSelection: languages[0],
+ nodeSelection: nodeList[0]
}
export function config(state = initialState, action) {
@@ -18,186 +14,16 @@ export function config(state = initialState, action) {
case CONFIG_LANGUAGE_CHANGE: {
return {
...state,
- languageSelection: action.index,
- languageToggle: false
- }
- }
- case CONFIG_LANGUAGE_DROPDOWN_TOGGLE: {
- return {
- ...state,
- languageToggle: !state.languageToggle
+ languageSelection: action.value
}
}
case CONFIG_NODE_CHANGE: {
return {
...state,
- nodeSelection: action.index,
- nodeToggle: false
- }
- }
- case CONFIG_NODE_DROPDOWN_TOGGLE: {
- return {
- ...state,
- nodeToggle: !state.nodeToggle
+ nodeSelection: action.value
}
}
default:
return state
}
}
-
-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': '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', '')
- }
-]