Make selectors for new state

This commit is contained in:
HenryNguyen5 2018-01-27 15:20:02 -05:00
parent db78639ac8
commit dd896d197d
15 changed files with 208 additions and 130 deletions

View File

@ -0,0 +1,12 @@
import { meta, State as MetaState } from './meta';
import { networks, State as NetworksState } from './networks';
import { nodes, State as NodesState } from './nodes';
import { combineReducers } from 'redux';
export interface State {
meta: MetaState;
networks: NetworksState;
nodes: NodesState;
}
export const config = combineReducers<State>({ meta, networks, nodes });

View File

@ -0,0 +1 @@
export * from './meta';

View File

@ -1,27 +1,18 @@
import { ChangeLanguageAction, SetLatestBlockAction, ConfigAction } from 'actions/config';
import { ChangeLanguageAction, SetLatestBlockAction, MetaAction } from 'actions/config';
import { TypeKeys } from 'actions/config/constants';
export interface State {
// FIXME
languageSelection: string;
nodeSelection: string;
isChangingNode: boolean;
offline: boolean;
autoGasLimit: boolean;
latestBlock: string;
}
const defaultNode = 'eth_mew';
export const INITIAL_STATE: State = {
const INITIAL_STATE: State = {
languageSelection: 'en',
nodeSelection: defaultNode,
node: NODES[defaultNode],
network: NETWORKS[NODES[defaultNode].network],
isChangingNode: false,
offline: false,
autoGasLimit: true,
customNodes: [],
customNetworks: [],
latestBlock: '???'
};
@ -53,7 +44,7 @@ function setLatestBlock(state: State, action: SetLatestBlockAction): State {
};
}
export function config(state: State = INITIAL_STATE, action: ConfigAction): State {
export function meta(state: State = INITIAL_STATE, action: MetaAction): State {
switch (action.type) {
case TypeKeys.CONFIG_LANGUAGE_CHANGE:
return changeLanguage(state, action);

View File

@ -6,10 +6,13 @@ import {
} from 'actions/config';
import { CustomNetworkConfig } from 'reducers/config/networks/typings';
export interface State {
// TODO: this doesn't accurately represent state, as
interface State1 {
[customNetworkId: string]: CustomNetworkConfig;
}
export type State = Partial<State1>;
const addCustomNetwork = (state: State, { payload }: AddCustomNetworkAction): State => ({
...state,
[payload.id]: payload.config

View File

@ -10,13 +10,13 @@ import {
UBQ_DEFAULT
} from 'config/dpaths';
import {
NetworkConfig,
DefaultNetworkConfig,
BlockExplorerConfig,
DefaultNetworkNames
} from 'reducers/config/networks/typings';
import { ConfigAction } from 'actions/config';
export type State = { [key in DefaultNetworkNames]: NetworkConfig };
export type State = { [key in DefaultNetworkNames]: DefaultNetworkConfig };
// Must be a website that follows the ethplorer convention of /tx/[hash] and
// address/[address] to generate the correct functions.

View File

@ -27,7 +27,7 @@ export interface DPathFormats {
mnemonicPhrase: DPath;
}
export interface NetworkConfig {
export interface DefaultNetworkConfig {
// TODO really try not to allow strings due to custom networks
name: DefaultNetworkNames;
unit: string;

View File

@ -7,7 +7,7 @@ interface NodeLoaded {
interface NodeChangePending {
pending: true;
nodeName: null;
nodeName: undefined;
}
export type State = NodeLoaded | NodeChangePending;
@ -23,7 +23,7 @@ const changeNode = (_: State, { payload }: ChangeNodeAction): State => ({
});
const changeNodeIntent = (_: State, _2: ChangeNodeIntentAction): State => ({
nodeName: null,
nodeName: undefined,
pending: true
});

View File

@ -25,7 +25,7 @@ import {
} from 'utils/node';
import { makeCustomNetworkId, getNetworkConfigFromId } from 'utils/network';
import {
getNode,
getNodeName,
getNodeConfig,
getCustomNodeConfigs,
getCustomNetworkConfigs,
@ -120,7 +120,7 @@ export function* reload(): SagaIterator {
}
export function* handleNodeChangeIntent(action: ChangeNodeIntentAction): SagaIterator {
const currentNode: string = yield select(getNode);
const currentNode: string = yield select(getNodeName);
const currentConfig: NodeConfig = yield select(getNodeConfig);
const customNets: CustomNetworkConfig[] = yield select(getCustomNetworkConfigs);
const currentNetwork =
@ -213,7 +213,7 @@ export function* cleanCustomNetworks(): SagaIterator {
// unset web3 as the selected node if a non-web3 wallet has been selected
export function* unsetWeb3NodeOnWalletEvent(action): SagaIterator {
const node = yield select(getNode);
const node = yield select(getNodeName);
const nodeConfig = yield select(getNodeConfig);
const newWallet = action.payload;
const isWeb3Wallet = newWallet instanceof Web3Wallet;
@ -227,7 +227,7 @@ export function* unsetWeb3NodeOnWalletEvent(action): SagaIterator {
}
export function* unsetWeb3Node(): SagaIterator {
const node = yield select(getNode);
const node = yield select(getNodeName);
if (node !== 'web3') {
return;

View File

@ -1,104 +0,0 @@
import {
CustomNetworkConfig,
CustomNodeConfig,
NetworkConfig,
NetworkContract,
NodeConfig,
Token
} from 'config';
import { INode } from 'libs/nodes/INode';
import { AppState } from 'reducers';
import { getUnit } from 'selectors/transaction/meta';
import { isEtherUnit } from 'libs/units';
import { SHAPESHIFT_TOKEN_WHITELIST } from 'api/shapeshift';
export function getNode(state: AppState): string {
return state.config.nodeSelection;
}
export function getIsWeb3Node(state: AppState): boolean {
return getNode(state) === 'web3';
}
export function getNodeConfig(state: AppState): NodeConfig {
return state.config.node;
}
export function getNodeLib(state: AppState): INode {
return getNodeConfig(state).lib;
}
export function getNetworkConfig(state: AppState): NetworkConfig {
return state.config.network;
}
export function getNetworkContracts(state: AppState): NetworkContract[] | null {
const network = getNetworkConfig(state);
return network ? network.contracts : [];
}
export function getNetworkTokens(state: AppState): Token[] {
const network = getNetworkConfig(state);
return network ? network.tokens : [];
}
export function getAllTokens(state: AppState): Token[] {
const networkTokens = getNetworkTokens(state);
return networkTokens.concat(state.customTokens);
}
export function getSelectedTokenContractAddress(state: AppState): string {
const allTokens = getAllTokens(state);
const currentUnit = getUnit(state);
if (currentUnit === 'ether') {
return '';
}
return allTokens.reduce((tokenAddr, tokenInfo) => {
if (tokenAddr && tokenAddr.length) {
return tokenAddr;
}
if (tokenInfo.symbol === currentUnit) {
return tokenInfo.address;
}
return tokenAddr;
}, '');
}
export function tokenExists(state: AppState, token: string): boolean {
const existInWhitelist = SHAPESHIFT_TOKEN_WHITELIST.includes(token);
const existsInNetwork = !!getAllTokens(state).find(t => t.symbol === token);
return existsInNetwork || existInWhitelist;
}
export function getLanguageSelection(state: AppState): string {
return state.config.languageSelection;
}
export function getCustomNodeConfigs(state: AppState): CustomNodeConfig[] {
return state.config.customNodes;
}
export function getCustomNetworkConfigs(state: AppState): CustomNetworkConfig[] {
return state.config.customNetworks;
}
export function getOffline(state: AppState): boolean {
return state.config.offline;
}
export function getAutoGasLimitEnabled(state: AppState): boolean {
return state.config.autoGasLimit;
}
export function isSupportedUnit(state: AppState, unit: string) {
const isToken: boolean = tokenExists(state, unit);
const isEther: boolean = isEtherUnit(unit);
if (!isToken && !isEther) {
return false;
}
return true;
}

View File

@ -0,0 +1,7 @@
import { AppState } from 'reducers';
export * from './meta';
export * from './networks';
export * from './nodes';
export * from './tokens';
export const getConfig = (state: AppState) => state.config;

View File

@ -0,0 +1,20 @@
import { AppState } from 'reducers';
import { getConfig } from 'sagas/config';
export const getMeta = (state: AppState) => getConfig(state).meta;
export function getOffline(state: AppState): boolean {
return getMeta(state).offline;
}
export function getAutoGasLimitEnabled(state: AppState): boolean {
return getMeta(state).autoGasLimit;
}
export function getLanguageSelection(state: AppState): string {
return getMeta(state).languageSelection;
}
export function getLatestBlock(state: AppState) {
return getMeta(state).latestBlock;
}

View File

@ -0,0 +1,41 @@
import { AppState } from 'reducers';
import { getConfig } from 'selectors/config';
import {
DefaultNetworkConfig,
CustomNetworkConfig,
DefaultNetworkNames,
NetworkContract
} from 'reducers/config/networks/typings';
export const getNetworks = (state: AppState) => getConfig(state).networks;
export const isCurrentNetworkDefault = (state: AppState): DefaultNetworkConfig | undefined => {
const { defaultNetworks, selectedNetwork } = getNetworks(state);
const isDefaultNetworkName = (networkName: string): networkName is DefaultNetworkNames =>
Object.keys(defaultNetworks).includes(networkName);
const defaultNetwork = isDefaultNetworkName(selectedNetwork)
? defaultNetworks[selectedNetwork]
: undefined;
return defaultNetwork;
};
export const isCurrentNetworkCustom = (state: AppState): CustomNetworkConfig | undefined => {
const { customNetworks, selectedNetwork } = getNetworks(state);
const customNetwork = customNetworks[selectedNetwork];
return customNetwork;
};
export const getNetworkConfig = (
state: AppState
): DefaultNetworkConfig | CustomNetworkConfig | undefined =>
isCurrentNetworkDefault(state) || isCurrentNetworkCustom(state);
export const getNetworkContracts = (state: AppState): NetworkContract[] | null => {
const network = isCurrentNetworkDefault(state);
return network ? network.contracts : [];
};
export const getCustomNetworkConfigs = (state: AppState): (CustomNetworkConfig | undefined)[] => {
const { customNetworks } = getNetworks(state);
return Object.values(customNetworks);
};

View File

@ -0,0 +1,55 @@
import { AppState } from 'reducers';
import { getConfig } from 'selectors/config';
import {
DefaultNodeConfig,
DefaultNodeName,
CustomNodeConfig
} from 'reducers/config/nodes/typings';
import { INode } from 'libs/nodes/INode';
export const getNodes = (state: AppState) => getConfig(state).nodes;
export const isCurrentNodeDefault = (state: AppState): DefaultNodeConfig | undefined => {
const { defaultNodes, selectedNode: { nodeName } } = getNodes(state);
if (nodeName === undefined) {
return nodeName;
}
const isDefaultNodeName = (networkName: string): networkName is DefaultNodeName =>
Object.keys(defaultNodes).includes(networkName);
const defaultNetwork = isDefaultNodeName(nodeName) ? defaultNodes[nodeName] : undefined;
return defaultNetwork;
};
export const isCurrentNetworkCustom = (state: AppState): CustomNodeConfig | undefined => {
const { customNodes, selectedNode: { nodeName } } = getNodes(state);
if (nodeName === undefined) {
return nodeName;
}
const customNetwork = customNodes[nodeName];
return customNetwork;
};
export function getCustomNodeConfigs(state: AppState): CustomNodeConfig[] {
return Object.values(getNodes(state).customNodes);
}
export function getNodeName(state: AppState): string | undefined {
return getNodes(state).selectedNode.nodeName;
}
export function getIsWeb3Node(state: AppState): boolean {
return getNodeName(state) === 'web3';
}
export function getNodeConfig(state: AppState): DefaultNodeConfig | CustomNodeConfig | undefined {
return isCurrentNodeDefault(state) || isCurrentNetworkCustom(state);
}
export function getNodeLib(state: AppState): INode | undefined {
const config = isCurrentNodeDefault(state);
return config ? config.lib : undefined;
}

View File

@ -0,0 +1,52 @@
import { AppState } from 'reducers';
import { getUnit } from 'selectors/transaction/meta';
import { isEtherUnit } from 'libs/units';
import { SHAPESHIFT_TOKEN_WHITELIST } from 'api/shapeshift';
import { isCurrentNetworkDefault } from 'selectors/config';
import { Token } from 'reducers/config/networks/typings';
export function getNetworkTokens(state: AppState): Token[] {
const network = isCurrentNetworkDefault(state);
return network ? network.tokens : [];
}
export function getAllTokens(state: AppState): Token[] {
const networkTokens = getNetworkTokens(state);
return networkTokens.concat(state.customTokens);
}
export function getSelectedTokenContractAddress(state: AppState): string {
const allTokens = getAllTokens(state);
const currentUnit = getUnit(state);
if (isEtherUnit(currentUnit)) {
return '';
}
return allTokens.reduce((tokenAddr, tokenInfo) => {
if (tokenAddr && tokenAddr.length) {
return tokenAddr;
}
if (tokenInfo.symbol === currentUnit) {
return tokenInfo.address;
}
return tokenAddr;
}, '');
}
export function tokenExists(state: AppState, token: string): boolean {
const existInWhitelist = SHAPESHIFT_TOKEN_WHITELIST.includes(token);
const existsInNetwork = !!getAllTokens(state).find(t => t.symbol === token);
return existsInNetwork || existInWhitelist;
}
export function isSupportedUnit(state: AppState, unit: string) {
const isToken: boolean = tokenExists(state, unit);
const isEther: boolean = isEtherUnit(unit);
if (!isToken && !isEther) {
return false;
}
return true;
}

View File

@ -14,7 +14,7 @@ import {
} from 'sagas/config';
import { NODES, NodeConfig, NETWORKS } from 'config';
import {
getNode,
getNodeName,
getNodeConfig,
getOffline,
getCustomNodeConfigs,
@ -176,7 +176,7 @@ describe('handleNodeChangeIntent*', () => {
});
it('should select getNode', () => {
expect(data.gen.next().value).toEqual(select(getNode));
expect(data.gen.next().value).toEqual(select(getNodeName));
});
it('should select nodeConfig', () => {
@ -263,7 +263,7 @@ describe('unsetWeb3Node*', () => {
const gen = unsetWeb3Node();
it('should select getNode', () => {
expect(gen.next().value).toEqual(select(getNode));
expect(gen.next().value).toEqual(select(getNodeName));
});
it('should select getNodeConfig', () => {
@ -293,7 +293,7 @@ describe('unsetWeb3NodeOnWalletEvent*', () => {
const gen = unsetWeb3NodeOnWalletEvent(fakeAction);
it('should select getNode', () => {
expect(gen.next().value).toEqual(select(getNode));
expect(gen.next().value).toEqual(select(getNodeName));
});
it('should select getNodeConfig', () => {