diff --git a/common/actions/notifications.js b/common/actions/notifications.js index 8b6bb993..5c0cee61 100644 --- a/common/actions/notifications.js +++ b/common/actions/notifications.js @@ -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', diff --git a/common/reducers/index.js b/common/reducers/index.js index e7705f6d..70402039 100644 --- a/common/reducers/index.js +++ b/common/reducers/index.js @@ -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({ diff --git a/common/reducers/swap/index.js b/common/reducers/swap/index.js index b17ed8e0..12d33f42 100644 --- a/common/reducers/swap/index.js +++ b/common/reducers/swap/index.js @@ -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, diff --git a/common/sagas/config.js b/common/sagas/config.js index 0db7c06a..2fd51fa9 100644 --- a/common/sagas/config.js +++ b/common/sagas/config.js @@ -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 setTimeout(() => location.reload(), 250); } -export default function* handleConfigChanges() { +export default function* handleConfigChanges(): Generator { yield takeEvery('CONFIG_LANGUAGE_CHANGE', handleLanguageChange); } diff --git a/common/sagas/contracts.js b/common/sagas/contracts.js index cc8f7d6b..f20a3ab8 100644 --- a/common/sagas/contracts.js +++ b/common/sagas/contracts.js @@ -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 { const contractFunctions = []; if (!action.address || !isValidETHAddress(action.address)) { @@ -36,6 +40,6 @@ function* handleAccessContract(action: AccessContractAction) { } } -export default function* contractsSaga(): Generator { +export default function* contractsSaga(): Generator { yield takeEvery('ACCESS_CONTRACT', handleAccessContract); } diff --git a/common/sagas/deterministicWallets.js b/common/sagas/deterministicWallets.js index 96a15963..da300ba6 100644 --- a/common/sagas/deterministicWallets.js +++ b/common/sagas/deterministicWallets.js @@ -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 { +): Generator { 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 { 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 { 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); diff --git a/common/sagas/ens.js b/common/sagas/ens.js index 50582121..afecc2de 100644 --- a/common/sagas/ens.js +++ b/common/sagas/ens.js @@ -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 { 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 { +export default function* notificationsSaga(): Generator { yield takeEvery('ENS_RESOLVE', resolveEns); } diff --git a/common/sagas/notifications.js b/common/sagas/notifications.js index 71140a65..73ba4479 100644 --- a/common/sagas/notifications.js +++ b/common/sagas/notifications.js @@ -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 { 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 { +export default function* notificationsSaga(): Generator { yield takeEvery('SHOW_NOTIFICATION', handleNotification); } diff --git a/common/sagas/swap/orders.js b/common/sagas/swap/orders.js index 8a00bda5..b74b845f 100644 --- a/common/sagas/swap/orders.js +++ b/common/sagas/swap/orders.js @@ -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 { +export function* pollBityOrderStatus(): Generator { try { let swap = yield select(getSwap); while (true) { @@ -66,7 +73,7 @@ export function* pollBityOrderStatus(): Generator { } } -export function* pollBityOrderStatusSaga(): Generator { +export function* pollBityOrderStatusSaga(): Generator { 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 { } } -function* postBityOrderCreate(action) { +function* postBityOrderCreate( + action: BityOrderCreateRequestedSwapAction +): Generator { const payload = action.payload; try { yield put(stopLoadBityRatesSwap()); @@ -111,11 +120,11 @@ function* postBityOrderCreate(action) { } } -export function* postBityOrderSaga(): Generator { +export function* postBityOrderSaga(): Generator { yield takeEvery('SWAP_ORDER_CREATE_REQUESTED', postBityOrderCreate); } -export function* bityTimeRemaining() { +export function* bityTimeRemaining(): Generator { while (yield take('SWAP_ORDER_START_TIMER')) { let hasShownNotification = false; while (true) { diff --git a/common/sagas/wallet.js b/common/sagas/wallet.js index cbb50850..ccf6ae53 100644 --- a/common/sagas/wallet.js +++ b/common/sagas/wallet.js @@ -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 { try { const wallet: ?BaseWallet = yield select(getWalletInst); if (!wallet) { @@ -40,7 +45,7 @@ function* updateAccountBalance() { } } -function* updateTokenBalances() { +function* updateTokenBalances(): Generator { 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 fork(updateAccountBalance); yield fork(updateTokenBalances); } export function* unlockPrivateKey( action?: UnlockPrivateKeyAction -): Generator { +): Generator { if (!action) return; let wallet = null; @@ -97,7 +102,7 @@ export function* unlockPrivateKey( export function* unlockKeystore( action?: UnlockKeystoreAction -): Generator { +): Generator { if (!action) return; const file = action.payload.file; @@ -138,7 +143,7 @@ export function* unlockKeystore( function* broadcastTx( action: BroadcastTxRequestedAction -): Generator { +): Generator { const signedTx = action.payload.signedTx; try { const node: BaseNode = yield select(getNodeLib); @@ -165,7 +170,7 @@ function* broadcastTx( } } -export default function* walletSaga(): Generator { +export default function* walletSaga(): Generator { // useful for development yield call(updateBalances); yield [