Address flow issues in sagas (#162)

This commit is contained in:
Bryan Fillmer 2017-09-04 10:30:31 -06:00 committed by Daniel Ternyak
parent d05525e682
commit b666d0e143
10 changed files with 86 additions and 51 deletions

View File

@ -20,7 +20,7 @@ export type ShowNotificationAction = {
export function showNotification(
level: NOTIFICATION_LEVEL = 'info',
msg: Element<*> | string,
duration?: number
duration?: number | INFINITY
): ShowNotificationAction {
return {
type: 'SHOW_NOTIFICATION',

View File

@ -28,6 +28,8 @@ import type { State as ContractsState } from './contracts';
import * as deterministicWallets from './deterministicWallets';
import type { State as DeterministicWalletsState } from './deterministicWallets';
import type { State as SwapState } from './swap';
import { reducer as formReducer } from 'redux-form';
import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
@ -45,7 +47,8 @@ export type State = {
deterministicWallets: DeterministicWalletsState,
// Third party reducers (TODO: Fill these out)
form: Object,
routing: Object
routing: Object,
swap: SwapState
};
export default combineReducers({

View File

@ -10,7 +10,7 @@ export const ALL_CRYPTO_KIND_OPTIONS = ['BTC', 'ETH', 'REP'];
const DEFAULT_ORIGIN_KIND = 'BTC';
const DEFAULT_DESTINATION_KIND = 'ETH';
type State = {
export type State = {
originAmount: ?number,
destinationAmount: ?number,
originKind: string,

View File

@ -1,11 +1,13 @@
import { takeEvery } from 'redux-saga/effects';
import type { Yield, Return, Next } from 'sagas/types';
// @HACK For now we reload the app when doing a language swap to force non-connected
// data to reload. Also the use of timeout to avoid using additional actions for now.
function* handleLanguageChange() {
function* handleLanguageChange(): Generator<Yield, Return, Next> {
yield setTimeout(() => location.reload(), 250);
}
export default function* handleConfigChanges() {
export default function* handleConfigChanges(): Generator<Yield, Return, Next> {
yield takeEvery('CONFIG_LANGUAGE_CHANGE', handleLanguageChange);
}

View File

@ -1,15 +1,19 @@
import { takeEvery, put } from 'redux-saga/effects';
import type { Effect } from 'redux-saga/effects';
import type { Yield, Return, Next } from 'sagas/types';
import translate from 'translations';
import { isValidETHAddress } from 'libs/validators';
import {
AccessContractAction,
setInteractiveContract
} from 'actions/contracts';
import { showNotification } from 'actions/notifications';
import { isValidETHAddress } from 'libs/validators';
function* handleAccessContract(action: AccessContractAction) {
function* handleAccessContract(
action: AccessContractAction
): Generator<Yield, Return, Next> {
const contractFunctions = [];
if (!action.address || !isValidETHAddress(action.address)) {
@ -36,6 +40,6 @@ function* handleAccessContract(action: AccessContractAction) {
}
}
export default function* contractsSaga(): Generator<Effect, void, any> {
export default function* contractsSaga(): Generator<Yield, Return, Next> {
yield takeEvery('ACCESS_CONTRACT', handleAccessContract);
}

View File

@ -11,26 +11,29 @@ import {
} from 'redux-saga/effects';
import HDKey from 'hdkey';
import { publicToAddress, toChecksumAddress } from 'ethereumjs-util';
import {
setDeterministicWallets,
updateDeterministicWallet
} from 'actions/deterministicWallets';
import { getWallets, getDesiredToken } from 'selectors/deterministicWallets';
import { getNodeLib } from 'selectors/config';
import { getTokens } from 'selectors/wallet';
import type {
DeterministicWalletData,
GetDeterministicWalletsAction
} from 'actions/deterministicWallets';
import type { Effect } from 'redux-saga/effects';
import type { Yield, Return, Next } from 'sagas/types';
import { getWallets, getDesiredToken } from 'selectors/deterministicWallets';
import { getNodeLib } from 'selectors/config';
import { getTokens } from 'selectors/wallet';
import type { BaseNode } from 'libs/nodes';
import type { Token } from 'config/data';
// TODO: BIP39 for mnemonic wallets?
function* getDeterministicWallets(
action?: GetDeterministicWalletsAction
): Generator<Effect, void, any> {
): Generator<Yield, Return, Next> {
if (!action) return;
const { publicKey, chainCode, limit, offset } = action.payload;
@ -56,7 +59,7 @@ function* getDeterministicWallets(
}
// Grab each wallet's main network token, and update it with it
function* updateWalletValues() {
function* updateWalletValues(): Generator<Yield, Return, Next> {
const node: BaseNode = yield select(getNodeLib);
const wallets: DeterministicWalletData[] = yield select(getWallets);
const calls = wallets.map(w => apply(node, node.getBalance, [w.address]));
@ -73,7 +76,7 @@ function* updateWalletValues() {
}
// Grab the current desired token, and update the wallet with it
function* updateWalletTokenValues() {
function* updateWalletTokenValues(): Generator<Yield, Return, Next> {
const desiredToken: string = yield select(getDesiredToken);
if (!desiredToken) return;
@ -102,9 +105,9 @@ function* updateWalletTokenValues() {
}
export default function* deterministicWalletsSaga(): Generator<
Effect,
void,
any
Yield,
Return,
Next
> {
yield takeLatest('DW_GET_WALLETS', getDeterministicWallets);
yield takeEvery('DW_SET_DESIRED_TOKEN', updateWalletTokenValues);

View File

@ -1,13 +1,18 @@
// @flow
import { takeEvery, call, put, select } from 'redux-saga/effects';
import { delay } from 'redux-saga';
import type { Effect } from 'redux-saga/effects';
import { cacheEnsAddress } from 'actions/ens';
import type { ResolveEnsNameAction } from 'actions/ens';
import { getEnsAddress } from 'selectors/ens';
import { donationAddressMap } from 'config/data';
function* resolveEns(action?: ResolveEnsNameAction) {
import type { Yield, Return, Next } from 'sagas/types';
function* resolveEns(
action?: ResolveEnsNameAction
): Generator<Yield, Return, Next> {
if (!action) return;
const ensName = action.payload;
// FIXME Add resolve logic
@ -31,6 +36,6 @@ function* resolveEns(action?: ResolveEnsNameAction) {
yield put(cacheEnsAddress(ensName, donationAddressMap.ETH));
}
export default function* notificationsSaga(): Generator<Effect, void, any> {
export default function* notificationsSaga(): Generator<Yield, Return, Next> {
yield takeEvery('ENS_RESOLVE', resolveEns);
}

View File

@ -1,11 +1,15 @@
// @flow
import { takeEvery, put, call } from 'redux-saga/effects';
import { delay } from 'redux-saga';
import type { Effect } from 'redux-saga/effects';
import type { Yield, Return, Next } from 'sagas/types';
import { closeNotification } from 'actions/notifications';
import type { ShowNotificationAction } from 'actions/notifications';
function* handleNotification(action?: ShowNotificationAction) {
function* handleNotification(
action?: ShowNotificationAction
): Generator<Yield, Return, Next> {
if (!action) return;
const { duration } = action.payload;
// show forever
@ -18,6 +22,6 @@ function* handleNotification(action?: ShowNotificationAction) {
yield put(closeNotification(action.payload));
}
export default function* notificationsSaga(): Generator<Effect, void, any> {
export default function* notificationsSaga(): Generator<Yield, Return, Next> {
yield takeEvery('SHOW_NOTIFICATION', handleNotification);
}

View File

@ -1,6 +1,5 @@
import { showNotification } from 'actions/notifications';
// @flow
import { delay } from 'redux-saga';
import { postOrder, getOrderStatus } from 'api/bity';
import {
call,
put,
@ -9,9 +8,11 @@ import {
cancel,
select,
cancelled,
takeEvery,
Effect
takeEvery
} from 'redux-saga/effects';
import moment from 'moment';
import { showNotification } from 'actions/notifications';
import {
orderTimeSwap,
bityOrderCreateSucceededSwap,
@ -23,19 +24,25 @@ import {
startPollBityOrderStatus,
stopPollBityOrderStatus
} from 'actions/swap';
import moment from 'moment';
export const getSwap = state => state.swap;
import { postOrder, getOrderStatus } from 'api/bity';
import type { Yield, Return, Next } from 'sagas/types';
import type { State as SwapState } from 'reducers/swap';
import type { State } from 'reducers';
import type { BityOrderCreateRequestedSwapAction } from 'actions/swapTypes';
export const getSwap = (state: State): SwapState => state.swap;
const ONE_SECOND = 1000;
const TEN_SECONDS = ONE_SECOND * 10;
const BITY_TIMEOUT_MESSAGE = `
Time has run out.
If you have already sent, please wait 1 hour.
If your order has not be processed after 1 hour,
Time has run out.
If you have already sent, please wait 1 hour.
If your order has not be processed after 1 hour,
please press the orange 'Issue with your Swap?' button.
`;
export function* pollBityOrderStatus(): Generator<Effect, void, any> {
export function* pollBityOrderStatus(): Generator<Yield, Return, Next> {
try {
let swap = yield select(getSwap);
while (true) {
@ -66,7 +73,7 @@ export function* pollBityOrderStatus(): Generator<Effect, void, any> {
}
}
export function* pollBityOrderStatusSaga(): Generator<Effect, void, any> {
export function* pollBityOrderStatusSaga(): Generator<Yield, Return, Next> {
while (yield take('SWAP_START_POLL_BITY_ORDER_STATUS')) {
// starts the task in the background
const pollBityOrderStatusTask = yield fork(pollBityOrderStatus);
@ -78,7 +85,9 @@ export function* pollBityOrderStatusSaga(): Generator<Effect, void, any> {
}
}
function* postBityOrderCreate(action) {
function* postBityOrderCreate(
action: BityOrderCreateRequestedSwapAction
): Generator<Yield, Return, Next> {
const payload = action.payload;
try {
yield put(stopLoadBityRatesSwap());
@ -111,11 +120,11 @@ function* postBityOrderCreate(action) {
}
}
export function* postBityOrderSaga(): Generator<Effect, void, any> {
export function* postBityOrderSaga(): Generator<Yield, Return, Next> {
yield takeEvery('SWAP_ORDER_CREATE_REQUESTED', postBityOrderCreate);
}
export function* bityTimeRemaining() {
export function* bityTimeRemaining(): Generator<Yield, Return, Next> {
while (yield take('SWAP_ORDER_START_TIMER')) {
let hasShownNotification = false;
while (true) {

View File

@ -1,13 +1,17 @@
// @flow
import React from 'react';
import { takeEvery, call, apply, put, select, fork } from 'redux-saga/effects';
import type { Effect } from 'redux-saga/effects';
import { setWallet, setBalance, setTokenBalances } from 'actions/wallet';
import type {
UnlockPrivateKeyAction,
UnlockKeystoreAction
} from 'actions/wallet';
import { showNotification } from 'actions/notifications';
import type { BroadcastTxRequestedAction } from 'actions/wallet';
import type { Yield, Return, Next } from 'sagas/types';
import translate from 'translations';
import {
PresaleWallet,
@ -18,13 +22,14 @@ import {
BaseWallet
} from 'libs/wallet';
import { BaseNode } from 'libs/nodes';
import { determineKeystoreType } from 'libs/keystore';
import { getNodeLib } from 'selectors/config';
import { getWalletInst, getTokens } from 'selectors/wallet';
import { determineKeystoreType } from 'libs/keystore';
import TransactionSucceeded from 'components/ExtendedNotifications/TransactionSucceeded';
import type { BroadcastTxRequestedAction } from 'actions/wallet';
function* updateAccountBalance() {
import TransactionSucceeded from 'components/ExtendedNotifications/TransactionSucceeded';
function* updateAccountBalance(): Generator<Yield, Return, Next> {
try {
const wallet: ?BaseWallet = yield select(getWalletInst);
if (!wallet) {
@ -40,7 +45,7 @@ function* updateAccountBalance() {
}
}
function* updateTokenBalances() {
function* updateTokenBalances(): Generator<Yield, Return, Next> {
try {
const node: BaseNode = yield select(getNodeLib);
const wallet: ?BaseWallet = yield select(getWalletInst);
@ -68,14 +73,14 @@ function* updateTokenBalances() {
}
}
function* updateBalances() {
function* updateBalances(): Generator<Yield, Return, Next> {
yield fork(updateAccountBalance);
yield fork(updateTokenBalances);
}
export function* unlockPrivateKey(
action?: UnlockPrivateKeyAction
): Generator<Effect, void, any> {
): Generator<Yield, Return, Next> {
if (!action) return;
let wallet = null;
@ -97,7 +102,7 @@ export function* unlockPrivateKey(
export function* unlockKeystore(
action?: UnlockKeystoreAction
): Generator<Effect, void, any> {
): Generator<Yield, Return, Next> {
if (!action) return;
const file = action.payload.file;
@ -138,7 +143,7 @@ export function* unlockKeystore(
function* broadcastTx(
action: BroadcastTxRequestedAction
): Generator<Effect, void, any> {
): Generator<Yield, Return, Next> {
const signedTx = action.payload.signedTx;
try {
const node: BaseNode = yield select(getNodeLib);
@ -165,7 +170,7 @@ function* broadcastTx(
}
}
export default function* walletSaga(): Generator<Effect | Effect[], void, any> {
export default function* walletSaga(): Generator<Yield, Return, Next> {
// useful for development
yield call(updateBalances);
yield [