type dropdown, config actions

This commit is contained in:
crptm 2017-07-04 05:25:01 +04:00
parent 13bb96e966
commit 85759d73b4
14 changed files with 256 additions and 278 deletions

View File

@ -1,18 +1,30 @@
// @flow // @flow
import { setLanguage } from 'translations'; 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) => { export type ChangeNodeAction = {
setLanguage(value.sign); type: 'CONFIG_NODE_CHANGE',
// FIXME $keyof?
value: string
};
export type ChangeLanguageAction = {
type: 'CONFIG_LANGUAGE_CHANGE',
value: string
};
export type ConfigAction = ChangeNodeAction | ChangeLanguageAction;
export function changeLanguage(sign: string) {
setLanguage(sign);
return { return {
type: CONFIG_LANGUAGE_CHANGE, type: 'CONFIG_LANGUAGE_CHANGE',
value value: sign
};
}; };
}
export const CHANGE_NODE = (value: any) => export function changeNode(value: string): ChangeNodeAction {
Object({ return {
type: CONFIG_NODE_CHANGE, type: 'CONFIG_NODE_CHANGE',
value value
}); };
}

View File

@ -1,26 +1,23 @@
// @flow // @flow
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types';
import TabsOptions from './components/TabsOptions'; import TabsOptions from './components/TabsOptions';
import { Link } from 'react-router'; import { Link } from 'react-router';
import { Dropdown } from 'components/ui'; import { Dropdown } from 'components/ui';
import { languages, nodeList } from '../../config/data'; import { languages, NODES } from '../../config/data';
export default class Header extends Component { export default class Header extends Component {
static propTypes = { props: {
location: PropTypes.object, languageSelection: string,
nodeSelection: string,
// Language DropDown changeLanguage: (sign: string) => any,
changeLanguage: PropTypes.func, changeNode: (key: string) => any
languageSelection: PropTypes.object,
// Node Dropdown
changeNode: PropTypes.func,
nodeSelection: PropTypes.object
}; };
render() { 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 ( return (
<div> <div>
@ -41,10 +38,10 @@ export default class Header extends Component {
</span> </span>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
<Dropdown <Dropdown
ariaLabel={`change language. current language ${languageSelection.name}`} ariaLabel={`change language. current language ${selectedLanguage.name}`}
options={languages} options={languages}
formatTitle={o => o.name} formatTitle={o => o.name}
value={languageSelection} value={selectedLanguage}
extra={[ extra={[
<li key={'separator'} role="separator" className="divider" />, <li key={'separator'} role="separator" className="divider" />,
<li key={'disclaimer'}> <li key={'disclaimer'}>
@ -53,23 +50,23 @@ export default class Header extends Component {
</a> </a>
</li> </li>
]} ]}
onChange={changeLanguage} onChange={this.changeLanguage}
/> />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
<Dropdown <Dropdown
ariaLabel={`change node. current node ${nodeSelection.name} node by ${nodeSelection.service}`} ariaLabel={`change node. current node ${selectedNode.network} node by ${selectedNode.service}`}
options={nodeList} options={Object.keys(NODES)}
formatTitle={o => [ formatTitle={o => [
o.name, NODES[o].network,
' ', ' ',
<small key="service">({o.service})</small> <small key="service">
({NODES[o].service})
</small>
]} ]}
value={nodeSelection} value={nodeSelection}
extra={ extra={
<li> <li>
<a onClick={() => {}}> <a onClick={() => {}}>Add Custom Node</a>
Add Custom Node
</a>
</li> </li>
} }
onChange={changeNode} onChange={changeNode}
@ -79,8 +76,11 @@ export default class Header extends Component {
</section> </section>
<TabsOptions {...this.props} /> <TabsOptions {...this.props} />
</div> </div>
); );
} }
changeLanguage = (value: { sign: string }) => {
this.props.changeLanguage(value.sign);
};
} }

View File

@ -1,3 +1,5 @@
export Header from './Header'; // @flow
export Footer from './Footer';
export Root from './Root'; export { default as Header } from './Header';
export { default as Footer } from './Footer';
export { default as Root } from './Root';

View File

@ -1,26 +1,21 @@
// @flow // @flow
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types';
export default class DropdownComponent extends Component { type Props<T> = {
static propTypes = { value: T,
value: PropTypes.object.isRequired, options: T[],
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, ariaLabel: string,
formatTitle: (option: any) => any, formatTitle: (option: T) => any,
extra?: any, extra?: any,
onChange: (value: any) => void onChange: (value: T) => void
}; }
type State = {
expanded: boolean
}
export default class DropdownComponent<T: *> extends Component<void, Props<T>, State> {
props: Props<T>
state = { state = {
expanded: false expanded: false

View File

@ -1,3 +1,6 @@
// @flow
import { RPCNode } from 'libs/nodes';
export const DONATION_ADDRESSES_MAP = { export const DONATION_ADDRESSES_MAP = {
BTC: '1MEWT2SGbqtz6mPCgFcnea8XmWV5Z4Wc6', BTC: '1MEWT2SGbqtz6mPCgFcnea8XmWV5Z4Wc6',
ETH: '0x7cB57B5A97eAbe94205C07890BE4c1aD31E486A8', ETH: '0x7cB57B5A97eAbe94205C07890BE4c1aD31E486A8',
@ -99,70 +102,23 @@ export const languages = [
} }
]; ];
export const nodeList = [ export const NETWORKS = {
{ ETH: {
name: 'ETH', name: 'ETH',
blockExplorerTX: 'https://etherscan.io/tx/[[txHash]]', blockExplorerTX: 'https://etherscan.io/tx/[[txHash]]',
blockExplorerAddr: 'https://etherscan.io/address/[[address]]', blockExplorerAddr: 'https://etherscan.io/address/[[address]]',
// 'type': nodes.nodeTypes.ETH, chainId: 1
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 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'),
}
};

View File

@ -2,32 +2,23 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Footer, Header } from 'components'; import { Footer, Header } from 'components';
import PropTypes from 'prop-types';
import Notifications from './Notifications'; import Notifications from './Notifications';
import * as actions from 'actions/config';
import { CHANGE_LANGUAGE, CHANGE_NODE } from 'actions/config';
class App extends Component { class App extends Component {
constructor(props) { props: {
super(props); // FIXME
} children: any,
location: any,
router: any,
isMobile: boolean,
static propTypes = { languageSelection: string,
children: PropTypes.node.isRequired, nodeSelection: string,
location: PropTypes.object,
handleWindowResize: PropTypes.func,
router: PropTypes.object, changeLanguage: typeof actions.changeLanguage,
isMobile: PropTypes.bool, changeNode: typeof actions.changeNode,
handleWindowResize: () => void
// BEGIN ACTUAL
languageSelection: PropTypes.object,
changeLanguage: PropTypes.func,
changeNode: PropTypes.func,
nodeSelection: PropTypes.object,
showNotification: PropTypes.func
}; };
render() { render() {
@ -72,16 +63,4 @@ function mapStateToProps(state) {
}; };
} }
function mapDispatchToProps(dispatch) { export default connect(mapStateToProps, actions)(App);
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);

View File

@ -0,0 +1,8 @@
// @flow
export default class BaseNode {
// FIXME bignumber?
queryBalance(address: string): Promise<number> {
throw 'Implement me';
}
}

View File

@ -0,0 +1,3 @@
// @flow
export { default as BaseNode } from './base';
export { default as RPCNode } from './rpc';

10
common/libs/nodes/rpc.js Normal file
View File

@ -0,0 +1,10 @@
// @flow
import BaseNode from './base';
export default class RPCNode extends BaseNode {
endpoint: string;
constructor(endpoint: string) {
super();
this.endpoint = endpoint;
}
}

View File

@ -1,36 +1,39 @@
// @flow // @flow
import { import type { ConfigAction, ChangeNodeAction, ChangeLanguageAction } from 'actions/config';
CONFIG_LANGUAGE_CHANGE, import { languages, NODES } from '../config/data';
CONFIG_NODE_CHANGE
} from 'actions/config';
import {languages, nodeList} from '../config/data';
export type State = { export type State = {
// FIXME // FIXME
languageSelection: string, languageSelection: string,
nodeSelection: string nodeSelection: string
} };
const initialState = { const initialState: State = {
languageSelection: languages[0], languageSelection: languages[0].sign,
nodeSelection: nodeList[0] nodeSelection: Object.keys(NODES)[0]
} };
export function config(state: State = initialState, action): State { function changeLanguage(state: State, action: ChangeLanguageAction): State {
switch (action.type) {
case CONFIG_LANGUAGE_CHANGE: {
return { return {
...state, ...state,
languageSelection: action.value languageSelection: action.value
};
} }
}
case CONFIG_NODE_CHANGE: { function changeNode(state: State, action: ChangeNodeAction): State {
return { return {
...state, ...state,
nodeSelection: action.value nodeSelection: action.value
};
} }
}
export function config(state: State = initialState, action: ConfigAction): State {
switch (action.type) {
case 'CONFIG_LANGUAGE_CHANGE':
return changeLanguage(state, action);
case 'CONFIG_NODE_CHANGE':
return changeNode(state, action);
default: default:
return state return state;
} }
} }

View File

@ -22,7 +22,7 @@ import { routerReducer } from 'react-router-redux';
export type State = { export type State = {
generateWallet: GenerateWalletState, generateWallet: GenerateWalletState,
conig: ConfigState, config: ConfigState,
notifications: NotificationsState, notifications: NotificationsState,
ens: EnsState, ens: EnsState,
wallet: WalletState wallet: WalletState

View File

@ -8,7 +8,7 @@ import PrivKeyWallet from 'libs/wallet/privkey';
function* init() { function* init() {
yield put(initWallet()); yield put(initWallet());
// const node = select(node); // const node = select(getNode);
// yield call(); // yield call();
// fetch balance, // fetch balance,
// fetch tokens // fetch tokens

View File

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

View File

@ -37,7 +37,9 @@ export function setLanguage(code: string) {
export default function translate(key: string) { export default function translate(key: string) {
return markupToReact( return markupToReact(
repository[activeLanguage][key] || repository[fallbackLanguage][key] || key (repository[activeLanguage] && repository[activeLanguage][key]) ||
repository[fallbackLanguage][key] ||
key
); );
} }