Redux promise middleware (v2) (#233)
* add redux-promise-middleware to package.json and update package-lock.json * intergrate redux-promise-middleware and simplify rates by replacing saga with promise * fix unrelated breaking test * -improve user messaging when network request fails. \n Clean up rates actions and reducers * Address tslint errors
This commit is contained in:
parent
3660260efb
commit
af84a589c5
|
@ -1,19 +1,11 @@
|
|||
import * as interfaces from './actionTypes';
|
||||
import { TypeKeys } from './constants';
|
||||
import { fetchRates, CCResponse } from './actionPayloads';
|
||||
|
||||
export type TFiatRequestedRates = typeof fiatRequestedRates;
|
||||
export function fiatRequestedRates(): interfaces.FiatRequestedRatesAction {
|
||||
export type TFetchCCRates = typeof fetchCCRates;
|
||||
export function fetchCCRates(): interfaces.FetchCCRates {
|
||||
return {
|
||||
type: TypeKeys.RATES_FIAT_REQUESTED
|
||||
};
|
||||
}
|
||||
|
||||
export type TFiatSucceededRates = typeof fiatSucceededRates;
|
||||
export function fiatSucceededRates(payload: {
|
||||
[key: string]: number;
|
||||
}): interfaces.FiatSucceededRatesAction {
|
||||
return {
|
||||
type: TypeKeys.RATES_FIAT_SUCCEEDED,
|
||||
payload
|
||||
type: TypeKeys.RATES_FETCH_CC,
|
||||
payload: fetchRates()
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
import { handleJSONResponse } from 'api/utils';
|
||||
|
||||
export const symbols = ['USD', 'EUR', 'GBP', 'BTC', 'CHF', 'REP'];
|
||||
const symbolsURL = symbols.join(',');
|
||||
// TODO - internationalize
|
||||
const ERROR_MESSAGE = 'Could not fetch rate data.';
|
||||
const CCApi = 'https://min-api.cryptocompare.com';
|
||||
|
||||
const CCRates = CCSymbols => `${CCApi}/data/price?fsym=ETH&tsyms=${CCSymbols}`;
|
||||
|
||||
export interface CCResponse {
|
||||
BTC: number;
|
||||
EUR: number;
|
||||
GBP: number;
|
||||
CHF: number;
|
||||
REP: number;
|
||||
}
|
||||
|
||||
export const fetchRates = (): Promise<CCResponse> =>
|
||||
fetch(CCRates(symbolsURL)).then(response =>
|
||||
handleJSONResponse(response, ERROR_MESSAGE)
|
||||
);
|
|
@ -1,13 +1,23 @@
|
|||
import { TypeKeys } from './constants';
|
||||
export interface FiatRequestedRatesAction {
|
||||
type: TypeKeys.RATES_FIAT_REQUESTED;
|
||||
import { CCResponse } from './actionPayloads';
|
||||
|
||||
export interface FetchCCRates {
|
||||
type: TypeKeys.RATES_FETCH_CC;
|
||||
payload: Promise<CCResponse>;
|
||||
}
|
||||
|
||||
/*** Set rates ***/
|
||||
export interface FiatSucceededRatesAction {
|
||||
type: TypeKeys.RATES_FIAT_SUCCEEDED;
|
||||
payload: { [key: string]: number };
|
||||
export interface FetchCCRatesSucceeded {
|
||||
type: TypeKeys.RATES_FETCH_CC_SUCCEEDED;
|
||||
payload: CCResponse;
|
||||
}
|
||||
|
||||
export interface FetchCCRatesFailed {
|
||||
type: TypeKeys.RATES_FETCH_CC_FAILED;
|
||||
}
|
||||
|
||||
/*** Union Type ***/
|
||||
export type RatesAction = FiatSucceededRatesAction | FiatRequestedRatesAction;
|
||||
export type RatesAction =
|
||||
| FetchCCRatesSucceeded
|
||||
| FetchCCRates
|
||||
| FetchCCRatesFailed;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
export enum TypeKeys {
|
||||
RATES_FIAT_REQUESTED = 'RATES_FIAT_REQUESTED',
|
||||
RATES_FIAT_SUCCEEDED = 'RATES_FIAT_SUCCEEDED'
|
||||
RATES_FETCH_CC = 'RATES_FETCH_CC',
|
||||
RATES_FETCH_CC_FAILED = 'RATES_FETCH_CC_FAILED',
|
||||
RATES_FETCH_CC_SUCCEEDED = 'RATES_FETCH_CC_SUCCEEDED'
|
||||
}
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
export * from './actionCreators';
|
||||
export * from './actionTypes';
|
||||
export * from './actionPayloads';
|
||||
|
|
|
@ -2,10 +2,7 @@ export function checkHttpStatus(response) {
|
|||
if (response.status >= 200 && response.status < 300) {
|
||||
return response;
|
||||
} else {
|
||||
const error = new Error(response.statusText);
|
||||
// TODO: why assign response?
|
||||
// error.response = response;
|
||||
throw error;
|
||||
return new Error(response.statusText);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,8 +12,7 @@ export function parseJSON(response) {
|
|||
|
||||
export async function handleJSONResponse(response, errorMessage) {
|
||||
if (response.ok) {
|
||||
const json = await response.json();
|
||||
return json;
|
||||
return await response.json();
|
||||
}
|
||||
if (errorMessage) {
|
||||
throw new Error(errorMessage);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { FiatRequestedRatesAction } from 'actions/rates';
|
||||
import { TFetchCCRates } from 'actions/rates';
|
||||
import { Identicon } from 'components/ui';
|
||||
import { NetworkConfig } from 'config/data';
|
||||
import { Ether } from 'libs/units';
|
||||
|
@ -12,7 +12,7 @@ interface Props {
|
|||
balance: Ether;
|
||||
wallet: IWallet;
|
||||
network: NetworkConfig;
|
||||
fiatRequestedRates(): FiatRequestedRatesAction;
|
||||
fetchCCRates: TFetchCCRates;
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
@ -26,9 +26,9 @@ export default class AccountInfo extends React.Component<Props, State> {
|
|||
};
|
||||
|
||||
public componentDidMount() {
|
||||
this.props.fiatRequestedRates();
|
||||
this.props.wallet.getAddress().then(addr => {
|
||||
this.setState({ address: addr });
|
||||
this.props.fetchCCRates();
|
||||
this.props.wallet.getAddress().then(address => {
|
||||
this.setState({ address });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -57,9 +57,7 @@ export default class AccountInfo extends React.Component<Props, State> {
|
|||
<div className="AccountInfo-address-icon">
|
||||
<Identicon address={address} size="100%" />
|
||||
</div>
|
||||
<div className="AccountInfo-address-addr">
|
||||
{address}
|
||||
</div>
|
||||
<div className="AccountInfo-address-addr">{address}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -82,26 +80,29 @@ export default class AccountInfo extends React.Component<Props, State> {
|
|||
</ul>
|
||||
</div>
|
||||
|
||||
{(!!blockExplorer || !!tokenExplorer) &&
|
||||
<div className="AccountInfo-section">
|
||||
<h5 className="AccountInfo-section-header">
|
||||
{translate('sidebar_TransHistory')}
|
||||
</h5>
|
||||
<ul className="AccountInfo-list">
|
||||
{!!blockExplorer &&
|
||||
<li className="AccountInfo-list-item">
|
||||
<a href={blockExplorer.address(address)} target="_blank">
|
||||
{`${network.name} (${blockExplorer.name})`}
|
||||
</a>
|
||||
</li>}
|
||||
{!!tokenExplorer &&
|
||||
<li className="AccountInfo-list-item">
|
||||
<a href={tokenExplorer.address(address)} target="_blank">
|
||||
{`Tokens (${tokenExplorer.name})`}
|
||||
</a>
|
||||
</li>}
|
||||
</ul>
|
||||
</div>}
|
||||
{(!!blockExplorer || !!tokenExplorer) && (
|
||||
<div className="AccountInfo-section">
|
||||
<h5 className="AccountInfo-section-header">
|
||||
{translate('sidebar_TransHistory')}
|
||||
</h5>
|
||||
<ul className="AccountInfo-list">
|
||||
{!!blockExplorer && (
|
||||
<li className="AccountInfo-list-item">
|
||||
<a href={blockExplorer.address(address)} target="_blank">
|
||||
{`${network.name} (${blockExplorer.name})`}
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
{!!tokenExplorer && (
|
||||
<li className="AccountInfo-list-item">
|
||||
<a href={tokenExplorer.address(address)} target="_blank">
|
||||
{`Tokens (${tokenExplorer.name})`}
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,27 +3,26 @@ import React from 'react';
|
|||
import translate from 'translations';
|
||||
import { formatNumber } from 'utils/formatters';
|
||||
import './EquivalentValues.scss';
|
||||
|
||||
const ratesKeys = ['BTC', 'REP', 'EUR', 'USD', 'GBP', 'CHF'];
|
||||
import { State } from 'reducers/rates';
|
||||
import { symbols } from 'actions/rates';
|
||||
|
||||
interface Props {
|
||||
balance?: Ether;
|
||||
rates?: { [key: string]: number };
|
||||
rates?: State['rates'];
|
||||
ratesError?: State['ratesError'];
|
||||
}
|
||||
|
||||
export default class EquivalentValues extends React.Component<Props, {}> {
|
||||
public render() {
|
||||
const { balance, rates } = this.props;
|
||||
const { balance, rates, ratesError } = this.props;
|
||||
|
||||
return (
|
||||
<div className="EquivalentValues">
|
||||
<h5 className="EquivalentValues-title">
|
||||
{translate('sidebar_Equiv')}
|
||||
</h5>
|
||||
<h5 className="EquivalentValues-title">{translate('sidebar_Equiv')}</h5>
|
||||
|
||||
<ul className="EquivalentValues-values">
|
||||
{rates
|
||||
? ratesKeys.map(key => {
|
||||
? symbols.map(key => {
|
||||
if (!rates[key]) {
|
||||
return null;
|
||||
}
|
||||
|
@ -33,14 +32,15 @@ export default class EquivalentValues extends React.Component<Props, {}> {
|
|||
{key}:
|
||||
</span>
|
||||
<span className="EquivalentValues-values-currency-value">
|
||||
{' '}{balance
|
||||
{' '}
|
||||
{balance
|
||||
? formatNumber(balance.amount.times(rates[key]))
|
||||
: '???'}
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
})
|
||||
: <h5>No rates were loaded.</h5>}
|
||||
: ratesError && <h5>{ratesError}</h5>}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -5,10 +5,7 @@ import {
|
|||
TRemoveCustomToken
|
||||
} from 'actions/customTokens';
|
||||
import { showNotification, TShowNotification } from 'actions/notifications';
|
||||
import {
|
||||
fiatRequestedRates as dFiatRequestedRates,
|
||||
TFiatRequestedRates
|
||||
} from 'actions/rates';
|
||||
import { fetchCCRates as dFetchCCRates, TFetchCCRates } from 'actions/rates';
|
||||
import { NetworkConfig } from 'config/data';
|
||||
import { Ether } from 'libs/units';
|
||||
import { IWallet } from 'libs/wallet/IWallet';
|
||||
|
@ -25,17 +22,19 @@ import AccountInfo from './AccountInfo';
|
|||
import EquivalentValues from './EquivalentValues';
|
||||
import Promos from './Promos';
|
||||
import TokenBalances from './TokenBalances';
|
||||
import { State } from 'reducers/rates';
|
||||
|
||||
interface Props {
|
||||
wallet: IWallet;
|
||||
balance: Ether;
|
||||
network: NetworkConfig;
|
||||
tokenBalances: TokenBalance[];
|
||||
rates: { [key: string]: number };
|
||||
rates: State['rates'];
|
||||
ratesError: State['ratesError'];
|
||||
showNotification: TShowNotification;
|
||||
addCustomToken: TAddCustomToken;
|
||||
removeCustomToken: TRemoveCustomToken;
|
||||
fiatRequestedRates: TFiatRequestedRates;
|
||||
fetchCCRates: TFetchCCRates;
|
||||
}
|
||||
|
||||
interface Block {
|
||||
|
@ -52,7 +51,8 @@ export class BalanceSidebar extends React.Component<Props, {}> {
|
|||
network,
|
||||
tokenBalances,
|
||||
rates,
|
||||
fiatRequestedRates
|
||||
ratesError,
|
||||
fetchCCRates
|
||||
} = this.props;
|
||||
if (!wallet) {
|
||||
return null;
|
||||
|
@ -66,7 +66,7 @@ export class BalanceSidebar extends React.Component<Props, {}> {
|
|||
wallet={wallet}
|
||||
balance={balance}
|
||||
network={network}
|
||||
fiatRequestedRates={fiatRequestedRates}
|
||||
fetchCCRates={fetchCCRates}
|
||||
/>
|
||||
)
|
||||
},
|
||||
|
@ -87,20 +87,26 @@ export class BalanceSidebar extends React.Component<Props, {}> {
|
|||
},
|
||||
{
|
||||
name: 'Equivalent Values',
|
||||
content: <EquivalentValues balance={balance} rates={rates} />
|
||||
content: (
|
||||
<EquivalentValues
|
||||
balance={balance}
|
||||
rates={rates}
|
||||
ratesError={ratesError}
|
||||
/>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<aside>
|
||||
{blocks.map(block =>
|
||||
{blocks.map(block => (
|
||||
<section
|
||||
className={`Block ${block.isFullWidth ? 'is-full-width' : ''}`}
|
||||
key={block.name}
|
||||
>
|
||||
{block.content}
|
||||
</section>
|
||||
)}
|
||||
))}
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
@ -112,7 +118,8 @@ function mapStateToProps(state: AppState) {
|
|||
balance: state.wallet.balance,
|
||||
tokenBalances: getTokenBalances(state),
|
||||
network: getNetworkConfig(state),
|
||||
rates: state.rates
|
||||
rates: state.rates.rates,
|
||||
ratesError: state.rates.ratesError
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -120,5 +127,5 @@ export default connect(mapStateToProps, {
|
|||
addCustomToken,
|
||||
removeCustomToken,
|
||||
showNotification,
|
||||
fiatRequestedRates: dFiatRequestedRates
|
||||
fetchCCRates: dFetchCCRates
|
||||
})(BalanceSidebar);
|
||||
|
|
|
@ -104,8 +104,8 @@ export default class PaperWallet extends React.Component<Props, State> {
|
|||
if (!this.props.wallet) {
|
||||
return;
|
||||
}
|
||||
this.props.wallet.getAddress().then(addr => {
|
||||
this.setState({ address: addr });
|
||||
this.props.wallet.getAddress().then(address => {
|
||||
this.setState({ address });
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -27,8 +27,8 @@ export default class DownloadWallet extends Component<Props, State> {
|
|||
};
|
||||
|
||||
public componentDidMount() {
|
||||
this.props.wallet.getAddress().then(addr => {
|
||||
this.setState({ address: addr });
|
||||
this.props.wallet.getAddress().then(address => {
|
||||
this.setState({ address });
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,33 @@
|
|||
import { FiatSucceededRatesAction, RatesAction } from 'actions/rates';
|
||||
import {
|
||||
FetchCCRatesSucceeded,
|
||||
FetchCCRatesFailed,
|
||||
RatesAction,
|
||||
CCResponse
|
||||
} from 'actions/rates';
|
||||
import { TypeKeys } from 'actions/rates/constants';
|
||||
import { Optional } from 'utils/types';
|
||||
|
||||
// SYMBOL -> PRICE TO BUY 1 ETH
|
||||
export interface State {
|
||||
[key: string]: number;
|
||||
rates?: Optional<CCResponse>;
|
||||
ratesError?: string | null;
|
||||
}
|
||||
|
||||
export const INITIAL_STATE: State = {};
|
||||
|
||||
function fiatSucceededRates(
|
||||
function fetchCCRatesSucceeded(
|
||||
state: State,
|
||||
action: FiatSucceededRatesAction
|
||||
action: FetchCCRatesSucceeded
|
||||
): State {
|
||||
return action.payload;
|
||||
return { ...state, rates: action.payload };
|
||||
}
|
||||
|
||||
function fetchCCRatesFailed(state: State, action: FetchCCRatesFailed): State {
|
||||
// TODO: Make library for error messages
|
||||
return {
|
||||
...state,
|
||||
ratesError: 'Sorry. We were unable to fetch equivalent rates.'
|
||||
};
|
||||
}
|
||||
|
||||
export function rates(
|
||||
|
@ -19,8 +35,10 @@ export function rates(
|
|||
action: RatesAction
|
||||
): State {
|
||||
switch (action.type) {
|
||||
case TypeKeys.RATES_FIAT_SUCCEEDED:
|
||||
return fiatSucceededRates(state, action);
|
||||
case TypeKeys.RATES_FETCH_CC_SUCCEEDED:
|
||||
return fetchCCRatesSucceeded(state, action);
|
||||
case TypeKeys.RATES_FETCH_CC_FAILED:
|
||||
return fetchCCRatesFailed(state, action);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ import handleConfigChanges from './config';
|
|||
import contracts from './contracts';
|
||||
import deterministicWallets from './deterministicWallets';
|
||||
import notifications from './notifications';
|
||||
import rates from './rates';
|
||||
import {
|
||||
bityTimeRemaining,
|
||||
pollBityOrderStatusSaga,
|
||||
|
@ -19,7 +18,6 @@ export default {
|
|||
getBityRatesSaga,
|
||||
contracts,
|
||||
notifications,
|
||||
rates,
|
||||
wallet,
|
||||
deterministicWallets
|
||||
};
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
import { fiatSucceededRates } from 'actions/rates';
|
||||
import { handleJSONResponse } from 'api/utils';
|
||||
import { SagaIterator } from 'redux-saga';
|
||||
import { call, put, takeLatest } from 'redux-saga/effects';
|
||||
|
||||
const symbols = ['USD', 'EUR', 'GBP', 'BTC', 'CHF', 'REP'];
|
||||
const symbolsURL = symbols.join(',');
|
||||
// TODO - internationalize
|
||||
const ERROR_MESSAGE = 'Could not fetch rate data.';
|
||||
|
||||
const fetchRates = () =>
|
||||
fetch(
|
||||
`https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=${symbolsURL}`
|
||||
).then(response => handleJSONResponse(response, ERROR_MESSAGE));
|
||||
|
||||
export function* handleRatesRequest(): SagaIterator {
|
||||
try {
|
||||
const rates = yield call(fetchRates);
|
||||
yield put(fiatSucceededRates(rates));
|
||||
} catch (error) {
|
||||
yield put({ type: 'RATES_FIAT_FAILED', payload: error });
|
||||
}
|
||||
}
|
||||
|
||||
export default function* ratesSaga(): SagaIterator {
|
||||
yield takeLatest('RATES_FIAT_REQUESTED', handleRatesRequest);
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
import { Effect } from 'redux-saga/effects';
|
||||
|
||||
export type Yield = Effect | {};
|
||||
export type Return = void;
|
||||
export type Next = any;
|
|
@ -8,14 +8,11 @@ import { applyMiddleware, createStore } from 'redux';
|
|||
import { composeWithDevTools } from 'redux-devtools-extension';
|
||||
import { createLogger } from 'redux-logger';
|
||||
import createSagaMiddleware from 'redux-saga';
|
||||
import {
|
||||
loadState,
|
||||
loadStatePropertyOrEmptyObject,
|
||||
saveState
|
||||
} from 'utils/localStorage';
|
||||
import { loadStatePropertyOrEmptyObject, saveState } from 'utils/localStorage';
|
||||
import RootReducer from './reducers';
|
||||
import { State as CustomTokenState } from './reducers/customTokens';
|
||||
import { State as SwapState } from './reducers/swap';
|
||||
import promiseMiddleware from 'redux-promise-middleware';
|
||||
|
||||
import sagas from './sagas';
|
||||
|
||||
|
@ -27,17 +24,26 @@ const configureStore = () => {
|
|||
collapsed: true
|
||||
});
|
||||
const sagaMiddleware = createSagaMiddleware();
|
||||
const reduxPromiseMiddleWare = promiseMiddleware({
|
||||
promiseTypeSuffixes: ['REQUESTED', 'SUCCEEDED', 'FAILED']
|
||||
});
|
||||
let middleware;
|
||||
let store;
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
(window as MyWindow).Perf = Perf;
|
||||
middleware = composeWithDevTools(
|
||||
applyMiddleware(sagaMiddleware, logger, routerMiddleware(history as any))
|
||||
applyMiddleware(
|
||||
sagaMiddleware,
|
||||
logger,
|
||||
reduxPromiseMiddleWare,
|
||||
routerMiddleware(history as any)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
middleware = applyMiddleware(
|
||||
sagaMiddleware,
|
||||
reduxPromiseMiddleWare,
|
||||
routerMiddleware(history as any)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
// Maps interface keys to optional
|
||||
export type Optional<T> = { [P in keyof T]?: T[P] };
|
||||
// Maps interface keys to nullable
|
||||
export type Nullable<T> = { [P in keyof T]: T[P] | null };
|
|
@ -145,6 +145,15 @@
|
|||
"redux": "3.7.2"
|
||||
}
|
||||
},
|
||||
"@types/redux-promise-middleware": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/redux-promise-middleware/-/redux-promise-middleware-0.0.8.tgz",
|
||||
"integrity": "sha512-5GFSEoerhY5EAXgtc276k3TOq8HSY4vmqI0AinzpejJlgRHW5Aw6gl2wmy0cqxoPqkhrd8yWbs2uxRa5FOMdvQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"redux": "3.7.2"
|
||||
}
|
||||
},
|
||||
"@types/redux-saga": {
|
||||
"version": "0.10.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/redux-saga/-/redux-saga-0.10.5.tgz",
|
||||
|
@ -10878,6 +10887,11 @@
|
|||
"deep-diff": "0.3.8"
|
||||
}
|
||||
},
|
||||
"redux-promise-middleware": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/redux-promise-middleware/-/redux-promise-middleware-4.4.1.tgz",
|
||||
"integrity": "sha512-1B5eiSGbZIbTKutIwYBwvz8visA5Bdnqtlxm2UnVsl7pgyU7hc7wigBwj17cLOnvG6deO4yft9NXFjWpg7k7PQ=="
|
||||
},
|
||||
"redux-saga": {
|
||||
"version": "0.15.4",
|
||||
"resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-0.15.4.tgz",
|
||||
|
|
13
package.json
13
package.json
|
@ -33,6 +33,7 @@
|
|||
"redux": "^3.6.0",
|
||||
"redux-form": "^6.6.3",
|
||||
"redux-logger": "^3.0.1",
|
||||
"redux-promise-middleware": "^4.4.1",
|
||||
"redux-saga": "^0.15.3",
|
||||
"scryptsy": "^2.0.0",
|
||||
"store2": "^2.5.5",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"@types/react-router-redux": "^4.0.50",
|
||||
"@types/redux-form": "^7.0.5",
|
||||
"@types/redux-logger": "^3.0.3",
|
||||
"@types/redux-promise-middleware": "0.0.8",
|
||||
"@types/redux-saga": "^0.10.5",
|
||||
"@types/uuid": "^3.4.2",
|
||||
"@types/webpack-env": "^1.13.1",
|
||||
|
@ -107,8 +109,7 @@
|
|||
"db": "nodemon ./db",
|
||||
"build": "webpack --config webpack_config/webpack.prod.js",
|
||||
"prebuild": "check-node-version --package",
|
||||
"build:demo":
|
||||
"BUILD_GH_PAGES=true webpack --config webpack_config/webpack.prod.js",
|
||||
"build:demo": "BUILD_GH_PAGES=true webpack --config webpack_config/webpack.prod.js",
|
||||
"prebuild:demo": "check-node-version --package",
|
||||
"test": "jest --config=jest_config/jest.config.json --coverage",
|
||||
"pretest": "check-node-version --package",
|
||||
|
@ -116,14 +117,16 @@
|
|||
"predev": "check-node-version --package",
|
||||
"dev:https": "HTTPS=true node webpack_config/server.js",
|
||||
"predev:https": "check-node-version --package",
|
||||
"derivation-checker":
|
||||
"webpack --config=./webpack_config/webpack.derivation-checker.js && node ./dist/derivation-checker.js",
|
||||
"derivation-checker": "webpack --config=./webpack_config/webpack.derivation-checker.js && node ./dist/derivation-checker.js",
|
||||
"tslint": "tslint --project . --exclude common/vendor/*",
|
||||
"postinstall": "webpack --config=./webpack_config/webpack.dll.js",
|
||||
"start": "npm run dev",
|
||||
"precommit": "lint-staged"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{ts,tsx}": ["prettier --write --single-quote", "git add"]
|
||||
"*.{ts,tsx}": [
|
||||
"prettier --write --single-quote",
|
||||
"git add"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue