type dropdown, config actions
This commit is contained in:
parent
13bb96e966
commit
85759d73b4
|
@ -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
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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 (
|
||||
<div>
|
||||
|
@ -41,10 +38,10 @@ export default class Header extends Component {
|
|||
</span>
|
||||
|
||||
<Dropdown
|
||||
ariaLabel={`change language. current language ${languageSelection.name}`}
|
||||
ariaLabel={`change language. current language ${selectedLanguage.name}`}
|
||||
options={languages}
|
||||
formatTitle={o => o.name}
|
||||
value={languageSelection}
|
||||
value={selectedLanguage}
|
||||
extra={[
|
||||
<li key={'separator'} role="separator" className="divider" />,
|
||||
<li key={'disclaimer'}>
|
||||
|
@ -53,23 +50,23 @@ export default class Header extends Component {
|
|||
</a>
|
||||
</li>
|
||||
]}
|
||||
onChange={changeLanguage}
|
||||
onChange={this.changeLanguage}
|
||||
/>
|
||||
|
||||
<Dropdown
|
||||
ariaLabel={`change node. current node ${nodeSelection.name} node by ${nodeSelection.service}`}
|
||||
options={nodeList}
|
||||
ariaLabel={`change node. current node ${selectedNode.network} node by ${selectedNode.service}`}
|
||||
options={Object.keys(NODES)}
|
||||
formatTitle={o => [
|
||||
o.name,
|
||||
NODES[o].network,
|
||||
' ',
|
||||
<small key="service">({o.service})</small>
|
||||
<small key="service">
|
||||
({NODES[o].service})
|
||||
</small>
|
||||
]}
|
||||
value={nodeSelection}
|
||||
extra={
|
||||
<li>
|
||||
<a onClick={() => {}}>
|
||||
Add Custom Node
|
||||
</a>
|
||||
<a onClick={() => {}}>Add Custom Node</a>
|
||||
</li>
|
||||
}
|
||||
onChange={changeNode}
|
||||
|
@ -79,8 +76,11 @@ export default class Header extends Component {
|
|||
</section>
|
||||
|
||||
<TabsOptions {...this.props} />
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
changeLanguage = (value: { sign: string }) => {
|
||||
this.props.changeLanguage(value.sign);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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<T> = {
|
||||
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<T: *> extends Component<void, Props<T>, State> {
|
||||
props: Props<T>
|
||||
|
||||
state = {
|
||||
expanded: false
|
||||
|
|
|
@ -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'),
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
// @flow
|
||||
|
||||
export default class BaseNode {
|
||||
// FIXME bignumber?
|
||||
queryBalance(address: string): Promise<number> {
|
||||
throw 'Implement me';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
// @flow
|
||||
export { default as BaseNode } from './base';
|
||||
export { default as RPCNode } from './rpc';
|
|
@ -0,0 +1,10 @@
|
|||
// @flow
|
||||
import BaseNode from './base';
|
||||
|
||||
export default class RPCNode extends BaseNode {
|
||||
endpoint: string;
|
||||
constructor(endpoint: string) {
|
||||
super();
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue