type dropdown, config actions
This commit is contained in:
parent
13bb96e966
commit
85759d73b4
|
@ -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
|
||||||
});
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
<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}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<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);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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'),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -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);
|
|
||||||
|
|
|
@ -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
|
// @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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
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
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue