From a7dcd5b2f8421863ab84a70c1d271988d46fdc0c Mon Sep 17 00:00:00 2001 From: Benjamin Chodoroff Date: Mon, 16 Jul 2018 19:41:03 -0400 Subject: [PATCH] Revert "reset outgoing auto-vesting-routes on account recovery" --- package.json | 3 +- src/app/redux/AuthSaga.js | 11 +- src/app/redux/FetchDataSaga.js | 40 ++++-- src/app/redux/MarketSaga.js | 21 ++- src/app/redux/SagaShared.js | 34 +++-- src/app/redux/TransactionSaga.js | 53 ++++---- src/app/redux/TransactionSaga.test.js | 182 ++++++-------------------- src/app/redux/UserSaga.js | 98 ++++++++++---- src/shared/RootSaga.js | 18 --- src/shared/UniversalRender.jsx | 43 +++--- yarn.lock | 10 +- 11 files changed, 242 insertions(+), 271 deletions(-) delete mode 100644 src/shared/RootSaga.js diff --git a/package.json b/package.json index 1a3d97e1b8..c97bff8b1f 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "react-timeago": "3.4.3", "redux": "3.7.2", "redux-form": "5.3.4", - "redux-saga": "0.16.0", + "redux-saga": "0.9.5", "remarkable": "1.7.1", "sanitize-html": "1.14.1", "sass-loader": "6.0.6", @@ -175,7 +175,6 @@ "react-test-renderer": "15.6.2", "react-transform-catch-errors": "1.0.2", "react-transform-hmr": "1.0.4", - "redux-devtools-extension": "2.13.5", "redux-mock-store": "1.5.1", "regenerator-runtime": "0.11.1", "sinon": "1.17.7", diff --git a/src/app/redux/AuthSaga.js b/src/app/redux/AuthSaga.js index ed3baa13ea..4e29d75a89 100644 --- a/src/app/redux/AuthSaga.js +++ b/src/app/redux/AuthSaga.js @@ -1,4 +1,5 @@ -import { call, put, select, takeEvery } from 'redux-saga/effects'; +import { takeEvery } from 'redux-saga'; +import { call, put, select } from 'redux-saga/effects'; import { Set, Map, fromJS, List } from 'immutable'; import { api } from '@steemit/steem-js'; import { PrivateKey } from '@steemit/steem-js/lib/auth/ecc'; @@ -13,9 +14,11 @@ const postingOps = Set( .split(/,\s*/) ); -export const authWatches = [ - takeEvery('user/ACCOUNT_AUTH_LOOKUP', accountAuthLookup), -]; +export const authWatches = [watchForAuth]; + +function* watchForAuth() { + yield* takeEvery('user/ACCOUNT_AUTH_LOOKUP', accountAuthLookup); +} export function* accountAuthLookup({ payload: { account, private_keys, login_owner_pubkey }, diff --git a/src/app/redux/FetchDataSaga.js b/src/app/redux/FetchDataSaga.js index a0df6e51ca..bfc69cdc18 100644 --- a/src/app/redux/FetchDataSaga.js +++ b/src/app/redux/FetchDataSaga.js @@ -1,11 +1,5 @@ -import { - call, - put, - select, - fork, - takeLatest, - takeEvery, -} from 'redux-saga/effects'; +import { takeLatest, takeEvery } from 'redux-saga'; +import { call, put, select, fork } from 'redux-saga/effects'; import { loadFollows, fetchFollowCount } from 'app/redux/FollowSaga'; import { getContent } from 'app/redux/SagaShared'; import * as globalActions from './GlobalReducer'; @@ -19,13 +13,21 @@ const GET_CONTENT = 'fetchDataSaga/GET_CONTENT'; const FETCH_STATE = 'fetchDataSaga/FETCH_STATE'; export const fetchDataWatches = [ - takeLatest(REQUEST_DATA, fetchData), - takeEvery(GET_CONTENT, getContentCaller), - takeLatest('@@router/LOCATION_CHANGE', fetchState), - takeLatest(FETCH_STATE, fetchState), - takeEvery('global/FETCH_JSON', fetchJson), + watchLocationChange, + watchDataRequests, + watchFetchJsonRequests, + watchFetchState, + watchGetContent, ]; +export function* watchDataRequests() { + yield* takeLatest(REQUEST_DATA, fetchData); +} + +export function* watchGetContent() { + yield* takeEvery(GET_CONTENT, getContentCaller); +} + export function* getContentCaller(action) { yield getContent(action.payload); } @@ -118,6 +120,14 @@ function* getAccounts(usernames) { yield put(globalActions.receiveAccounts({ accounts })); } +export function* watchLocationChange() { + yield* takeLatest('@@router/LOCATION_CHANGE', fetchState); +} + +export function* watchFetchState() { + yield* takeLatest(FETCH_STATE, fetchState); +} + export function* fetchData(action) { const { order, author, permlink, accountname } = action.payload; let { category } = action.payload; @@ -357,6 +367,10 @@ export function* fetchMeta({ payload: { id, link } }) { } } +export function* watchFetchJsonRequests() { + yield* takeEvery('global/FETCH_JSON', fetchJson); +} + /** @arg {string} id unique key for result global['fetchJson_' + id] @arg {string} url diff --git a/src/app/redux/MarketSaga.js b/src/app/redux/MarketSaga.js index f236999dc5..99adaedf5f 100644 --- a/src/app/redux/MarketSaga.js +++ b/src/app/redux/MarketSaga.js @@ -1,4 +1,5 @@ -import { call, put, takeLatest } from 'redux-saga/effects'; +import { takeLatest } from 'redux-saga'; +import { call, put } from 'redux-saga/effects'; import { api } from '@steemit/steem-js'; import * as marketActions from './MarketReducer'; @@ -7,9 +8,9 @@ import * as userActions from './UserReducer'; import { getAccount } from './SagaShared'; export const marketWatches = [ - takeLatest(userActions.SET_USER, fetchOpenOrders), - takeLatest('@@router/LOCATION_CHANGE', fetchMarket), - takeLatest(marketActions.UPDATE_MARKET, reloadMarket), + watchLocationChange, + watchUserLogin, + watchMarketUpdate, ]; const wait = ms => @@ -85,3 +86,15 @@ export function* reloadMarket(reload_action) { yield fetchMarket(reload_action); yield fetchOpenOrders(reload_action); } + +export function* watchUserLogin() { + yield* takeLatest(userActions.SET_USER, fetchOpenOrders); +} + +export function* watchLocationChange() { + yield* takeLatest('@@router/LOCATION_CHANGE', fetchMarket); +} + +export function* watchMarketUpdate() { + yield* takeLatest(marketActions.UPDATE_MARKET, reloadMarket); +} diff --git a/src/app/redux/SagaShared.js b/src/app/redux/SagaShared.js index 084f362508..0646f6ac7b 100644 --- a/src/app/redux/SagaShared.js +++ b/src/app/redux/SagaShared.js @@ -1,5 +1,6 @@ import { fromJS } from 'immutable'; -import { call, put, select, takeEvery, takeLatest } from 'redux-saga/effects'; +import { call, put, select } from 'redux-saga/effects'; +import { takeEvery, takeLatest } from 'redux-saga'; import tt from 'counterpart'; import { api } from '@steemit/steem-js'; import * as globalActions from './GlobalReducer'; @@ -13,16 +14,9 @@ const wait = ms => }); export const sharedWatches = [ - takeEvery(globalActions.GET_STATE, getState), - takeLatest( - [ - appActions.SET_USER_PREFERENCES, - appActions.TOGGLE_NIGHTMODE, - appActions.TOGGLE_BLOGMODE, - ], - saveUserPreferences - ), - takeEvery('transaction/ERROR', showTransactionErrorNotification), + watchGetState, + watchTransactionErrors, + watchUserSettingsUpdates, ]; export function* getAccount(username, force = false) { @@ -39,6 +33,9 @@ export function* getAccount(username, force = false) { return account; } +export function* watchGetState() { + yield* takeEvery(globalActions.GET_STATE, getState); +} /** Manual refreshes. The router is in FetchDataSaga. */ export function* getState({ payload: { url } }) { try { @@ -50,6 +47,10 @@ export function* getState({ payload: { url } }) { } } +export function* watchTransactionErrors() { + yield* takeEvery('transaction/ERROR', showTransactionErrorNotification); +} + function* showTransactionErrorNotification() { const errors = yield select(state => state.transaction.get('errors')); for (const [key, message] of errors) { @@ -93,3 +94,14 @@ function* saveUserPreferences({ payload }) { const prefs = yield select(state => state.app.get('user_preferences')); yield setUserPreferences(prefs.toJS()); } + +function* watchUserSettingsUpdates() { + yield* takeLatest( + [ + appActions.SET_USER_PREFERENCES, + appActions.TOGGLE_NIGHTMODE, + appActions.TOGGLE_BLOGMODE, + ], + saveUserPreferences + ); +} diff --git a/src/app/redux/TransactionSaga.js b/src/app/redux/TransactionSaga.js index c0c356bd66..503939db52 100644 --- a/src/app/redux/TransactionSaga.js +++ b/src/app/redux/TransactionSaga.js @@ -1,4 +1,5 @@ -import { call, put, select, all, takeEvery } from 'redux-saga/effects'; +import { takeEvery } from 'redux-saga'; +import { call, put, select } from 'redux-saga/effects'; import { fromJS, Set, Map } from 'immutable'; import tt from 'counterpart'; import getSlug from 'speakingurl'; @@ -17,12 +18,28 @@ import { DEBT_TICKER } from 'app/client_config'; import { serverApiRecordEvent } from 'app/utils/ServerApiClient'; export const transactionWatches = [ - takeEvery(transactionActions.BROADCAST_OPERATION, broadcastOperation), - takeEvery(transactionActions.UPDATE_AUTHORITIES, updateAuthorities), - takeEvery(transactionActions.UPDATE_META, updateMeta), - takeEvery(transactionActions.RECOVER_ACCOUNT, recoverAccount), + watchForBroadcast, + watchForUpdateAuthorities, + watchForUpdateMeta, + watchForRecoverAccount, ]; +export function* watchForBroadcast() { + yield* takeEvery( + transactionActions.BROADCAST_OPERATION, + broadcastOperation + ); +} +export function* watchForUpdateAuthorities() { + yield* takeEvery(transactionActions.UPDATE_AUTHORITIES, updateAuthorities); +} +export function* watchForUpdateMeta() { + yield* takeEvery(transactionActions.UPDATE_META, updateMeta); +} +export function* watchForRecoverAccount() { + yield* takeEvery(transactionActions.RECOVER_ACCOUNT, recoverAccount); +} + const hook = { preBroadcast_comment, preBroadcast_transfer, @@ -164,7 +181,7 @@ function* error_account_witness_vote({ } /** Keys, username, and password are not needed for the initial call. This will check the login and may trigger an action to prompt for the password / key. */ -export function* broadcastOperation({ +function* broadcastOperation({ payload: { type, operation, @@ -680,7 +697,7 @@ function slug(text) { const pwPubkey = (name, pw, role) => auth.wifToPublic(auth.toWif(name, pw.trim(), role)); -export function* recoverAccount({ +function* recoverAccount({ payload: { account_to_recover, old_password, @@ -693,7 +710,6 @@ export function* recoverAccount({ [api, api.getAccountsAsync], [account_to_recover] ); - if (!account) { onError('Unknown account ' + account); return; @@ -744,7 +760,6 @@ export function* recoverAccount({ }; try { - // TODO: Investigate wrapping in a redux-saga call fn, so it can be tested!. yield broadcast.sendAsync( { extensions: [], @@ -765,7 +780,6 @@ export function* recoverAccount({ // change password // change password probably requires a separate transaction (single trx has not been tested) const { json_metadata } = account; - // TODO: Investigate wrapping in a redux-saga call fn, so it can be tested! yield broadcast.sendAsync( { extensions: [], @@ -792,21 +806,6 @@ export function* recoverAccount({ }, [newOwnerPrivate] ); - // Reset all outgoing auto-vesting routes for this user. Condenser - #2835 - const outgoingAutoVestingRoutes = yield call( - [api, api.getWithdrawRoutes], - [account.name, 'outgoing'] - ); - if (outgoingAutoVestingRoutes && outgoingAutoVestingRoutes.length > 0) { - yield all( - outgoingAutoVestingRoutes.map(ovr => { - return call( - [broadcast, broadcast.setWithdrawVestingRoute], - [newActive, ovr.from_account, ovr.to_account, 0, true] - ); - }) - ); - } if (onSuccess) onSuccess(); } catch (error) { console.error('Recover account', error); @@ -816,7 +815,7 @@ export function* recoverAccount({ /** auths must start with most powerful key: owner for example */ // const twofaAccount = 'steem' -export function* updateAuthorities({ +function* updateAuthorities({ payload: { accountName, signingKey, auths, twofa, onSuccess, onError }, }) { // Be sure this account is up-to-date (other required fields are sent in the update) @@ -956,7 +955,7 @@ export function* updateAuthorities({ /** auths must start with most powerful key: owner for example */ // const twofaAccount = 'steem' -export function* updateMeta(params) { +function* updateMeta(params) { // console.log('params', params) const { meta, diff --git a/src/app/redux/TransactionSaga.test.js b/src/app/redux/TransactionSaga.test.js index f438139561..cb44121b50 100644 --- a/src/app/redux/TransactionSaga.test.js +++ b/src/app/redux/TransactionSaga.test.js @@ -1,19 +1,16 @@ /* global describe, it, before, beforeEach, after, afterEach */ -import { call, select, all, takeEvery } from 'redux-saga/effects'; -import steem, { api, broadcast } from '@steemit/steem-js'; -import { cloneableGenerator } from 'redux-saga/utils'; -import * as transactionActions from 'app/redux/TransactionReducer'; +import { call, select } from 'redux-saga/effects'; +import { api } from '@steemit/steem-js'; import { preBroadcast_comment, createPermlink, createPatch, - recoverAccount, + watchForBroadcast, + watchForUpdateAuthorities, + watchForUpdateMeta, + watchForRecoverAccount, preBroadcast_transfer, - transactionWatches, - broadcastOperation, - updateAuthorities, - updateMeta, } from './TransactionSaga'; import { DEBT_TICKER } from 'app/client_config'; @@ -45,137 +42,6 @@ const operation = { const username = 'Beatrice'; describe('TransactionSaga', () => { - describe('watch user actions and trigger appropriate saga', () => { - const gen = transactionWatches; - it('should call the broadcastOperation saga with every transactionActions.BROADCAST_OPERATION action', () => { - expect(gen).toEqual([ - takeEvery( - transactionActions.BROADCAST_OPERATION, - broadcastOperation - ), - takeEvery( - transactionActions.UPDATE_AUTHORITIES, - updateAuthorities - ), - takeEvery(transactionActions.UPDATE_META, updateMeta), - takeEvery(transactionActions.RECOVER_ACCOUNT, recoverAccount), - ]); - }); - }); - - describe('recoverAccount', () => { - const gen = cloneableGenerator(recoverAccount)({ - payload: { - account_to_recover: 'one', - old_password: 'two34567', - new_password: 'two34567', - onError: () => 'error!', - onSuccess: () => 'success!', - }, - }); - it('should call getAccountsAsync with account_to_recover username as argument', () => { - const actual = gen.next([{ id: 123, name: 'one' }]).value; - const mockCall = call([api, api.getAccountsAsync], ['one']); - expect(actual).toEqual(mockCall); - }); - it('should call sendAsync with recover_account operation', () => { - const actual = gen.next([{ id: 123, name: 'one' }]).value; - const mockCall = broadcast.sendAsync( - { - extensions: [], - operations: [ - [ - 'recover_account', - { - account_to_recover: 'one', - new_owner_authority: 'idk', - recent_owner_authority: 'something', - }, - ], - ], - }, - ['123', '345'] - ); - expect(actual).toEqual(mockCall); - }); - it('should call sendAsync with account_update operation', () => { - const actual = gen.next().value; - const mockCall = broadcast.sendAsync( - { - extensions: [], - operations: [ - [ - 'account_update', - { - account_to_recover: 'one', - new_owner_authority: 'idk', - recent_owner_authority: 'something', - - account: 'one', - active: { - weight_threshold: 1, - account_auths: [], - key_auths: [['newactive', 1]], - }, - posting: { - weight_threshold: 1, - account_auths: [], - key_auths: [['newposting', 1]], - }, - memo_key: 'newmemo', - }, - ], - ], - }, - ['newownerprivate'] - ); - expect(actual).toEqual(mockCall); - }); - it('should call getWithdrawRoutes with account name and outgoing as parameters', () => { - const noAutoVests = gen.clone(); - const actual = noAutoVests.next().value; - const mockCall = call( - [api, api.getWithdrawRoutes], - ['one', 'outgoing'] - ); - expect(actual).toEqual(mockCall); - const done = noAutoVests.next().done; - expect(done).toBe(true); - }); - it('should call getWithdrawRoutes with account name and outgoing as parameters, and be done if none are found', () => { - const noAutoVests = gen.clone(); - const actual = noAutoVests.next().value; - const mockCall = call( - [api, api.getWithdrawRoutes], - ['one', 'outgoing'] - ); - expect(actual).toEqual(mockCall); - const done = noAutoVests.next().done; - expect(done).toBe(true); - }); - it('should call getWithdrawRoutes with account name and outgoing as parameters, and reset all outgoing auto vesting routes to 0.', () => { - const withAutoVests = gen.clone(); - withAutoVests.next([{ from_account: 'one', to_account: 'two' }]) - .value; - const actual = withAutoVests.next([ - { from_account: 'one', to_account: 'two' }, - ]).value; - const mockCall = all([ - call( - [broadcast, broadcast.setWithdrawVestingRoute], - [ - 'STM7UbRctdfcdBU6rMBEX5yPjWaR68xmq6buCkotR7RVEJHYWt1Jb', - 'one', - 'two', - 0, - true, - ] - ), - ]); - expect(actual).toEqual(mockCall); - }); - }); - describe('createPatch', () => { it('should return undefined if empty arguments are passed', () => { const actual = createPatch('', ''); @@ -191,6 +57,42 @@ describe('TransactionSaga', () => { }); }); + describe('watchForBroadcast', () => { + const gen = watchForBroadcast(); + it('should call takeEvery with BROADCAST_OPERATION', () => { + const actual = gen.next().value; + const expected = { + '@@redux-saga/IO': true, + TAKE: 'transaction/BROADCAST_OPERATION', + }; + expect(actual).toEqual(expected); + }); + }); + + describe('watchForUpdateAuthorities', () => { + const gen = watchForUpdateAuthorities(); + it('should call takeEvery with UPDATE_AUTHORITIES', () => { + const actual = gen.next().value; + const expected = { + '@@redux-saga/IO': true, + TAKE: 'transaction/UPDATE_AUTHORITIES', + }; + expect(actual).toEqual(expected); + }); + }); + + describe('watchForUpdateMeta', () => { + const gen = watchForUpdateMeta(); + it('should call takeEvery with UPDATE_META', () => { + const actual = gen.next().value; + const expected = { + '@@redux-saga/IO': true, + TAKE: 'transaction/UPDATE_META', + }; + expect(actual).toEqual(expected); + }); + }); + describe('preBroadcast_transfer', () => { const operationSansMemo = { ...operation, diff --git a/src/app/redux/UserSaga.js b/src/app/redux/UserSaga.js index 3f5cef7f23..84a0ad55a3 100644 --- a/src/app/redux/UserSaga.js +++ b/src/app/redux/UserSaga.js @@ -1,5 +1,6 @@ import { fromJS, Set, List } from 'immutable'; -import { call, put, select, fork, takeLatest } from 'redux-saga/effects'; +import { takeLatest } from 'redux-saga'; +import { call, put, select, fork } from 'redux-saga/effects'; import { api } from '@steemit/steem-js'; import { PrivateKey, Signature, hash } from '@steemit/steem-js/lib/auth/ecc'; @@ -20,34 +21,17 @@ import { translate } from 'app/Translator'; import DMCAUserList from 'app/utils/DMCAUserList'; export const userWatches = [ - takeLatest('@@router/LOCATION_CHANGE', removeHighSecurityKeys), // keep first to remove keys early when a page change happens - takeLatest( - 'user/lookupPreviousOwnerAuthority', - lookupPreviousOwnerAuthority - ), - takeLatest(userActions.USERNAME_PASSWORD_LOGIN, usernamePasswordLogin), - takeLatest(userActions.SAVE_LOGIN, saveLogin_localStorage), - takeLatest(userActions.LOGOUT, logout), - takeLatest(userActions.LOGIN_ERROR, loginError), - takeLatest(userActions.LOAD_SAVINGS_WITHDRAW, loadSavingsWithdraw), - takeLatest(userActions.UPLOAD_IMAGE, uploadImage), - takeLatest(userActions.ACCEPT_TERMS, function*() { - try { - yield call(acceptTos); - } catch (e) { - // TODO: log error to server, conveyor is unavailable - } - }), - function* getLatestFeedPrice() { - try { - const history = yield call([api, api.getFeedHistoryAsync]); - const feed = history['price_history']; - const last = fromJS(feed[feed.length - 1]); - yield put(userActions.setLatestFeedPrice(last)); - } catch (error) { - // (exceedingly rare) ignore, UI will fall back to feed_price - } - }, + watchRemoveHighSecurityKeys, // keep first to remove keys early when a page change happens + loginWatch, + saveLoginWatch, + logoutWatch, + // getCurrentAccountWatch, + loginErrorWatch, + lookupPreviousOwnerAuthorityWatch, + watchLoadSavingsWithdraw, + uploadImageWatch, + acceptTosWatch, + getLatestFeedPrice, ]; const highSecurityPages = [ @@ -56,6 +40,48 @@ const highSecurityPages = [ /\/~witnesses/, ]; +function* lookupPreviousOwnerAuthorityWatch() { + yield* takeLatest( + 'user/lookupPreviousOwnerAuthority', + lookupPreviousOwnerAuthority + ); +} +function* loginWatch() { + yield* takeLatest( + userActions.USERNAME_PASSWORD_LOGIN, + usernamePasswordLogin + ); +} +function* saveLoginWatch() { + yield* takeLatest(userActions.SAVE_LOGIN, saveLogin_localStorage); +} +function* logoutWatch() { + yield* takeLatest(userActions.LOGOUT, logout); +} + +function* loginErrorWatch() { + yield* takeLatest(userActions.LOGIN_ERROR, loginError); +} + +function* watchLoadSavingsWithdraw() { + yield* takeLatest(userActions.LOAD_SAVINGS_WITHDRAW, loadSavingsWithdraw); +} + +export function* watchRemoveHighSecurityKeys() { + yield* takeLatest('@@router/LOCATION_CHANGE', removeHighSecurityKeys); +} + +function* getLatestFeedPrice() { + try { + const history = yield call([api, api.getFeedHistoryAsync]); + const feed = history['price_history']; + const last = fromJS(feed[feed.length - 1]); + yield put(userActions.setLatestFeedPrice(last)); + } catch (error) { + // (exceedingly rare) ignore, UI will fall back to feed_price + } +} + function* loadSavingsWithdraw() { const username = yield select(state => state.user.getIn(['current', 'username']) @@ -391,6 +417,16 @@ function* promptTosAcceptance(username) { } } +function* acceptTosWatch() { + yield* takeLatest(userActions.ACCEPT_TERMS, function*() { + try { + yield call(acceptTos); + } catch (e) { + // TODO: log error to server, conveyor is unavailable + } + }); +} + function* getFeatureFlags(username, posting_private) { try { const flags = yield call( @@ -522,6 +558,10 @@ function* lookupPreviousOwnerAuthority({ payload: {} }) { yield put(userActions.setUser({ previous_owner_authority })); } +function* uploadImageWatch() { + yield* takeLatest(userActions.UPLOAD_IMAGE, uploadImage); +} + function* uploadImage({ payload: { file, dataUrl, filename = 'image.txt', progress }, }) { diff --git a/src/shared/RootSaga.js b/src/shared/RootSaga.js deleted file mode 100644 index ac1bd02638..0000000000 --- a/src/shared/RootSaga.js +++ /dev/null @@ -1,18 +0,0 @@ -import { all } from 'redux-saga/effects'; -import { fetchDataWatches } from 'app/redux/FetchDataSaga'; -import { marketWatches } from 'app/redux/MarketSaga'; -import { sharedWatches } from 'app/redux/SagaShared'; -import { userWatches } from 'app/redux/UserSaga'; -import { authWatches } from 'app/redux/AuthSaga'; -import { transactionWatches } from 'app/redux/TransactionSaga'; - -export default function* rootSaga() { - yield all([ - ...userWatches, // keep first to remove keys early when a page change happens - ...fetchDataWatches, - ...sharedWatches, - ...authWatches, - ...transactionWatches, - ...marketWatches, - ]); -} diff --git a/src/shared/UniversalRender.jsx b/src/shared/UniversalRender.jsx index f2bba95189..fda3168d65 100644 --- a/src/shared/UniversalRender.jsx +++ b/src/shared/UniversalRender.jsx @@ -18,10 +18,14 @@ import * as appActions from 'app/redux/AppReducer'; import { createStore, applyMiddleware, compose } from 'redux'; import { useScroll } from 'react-router-scroll'; import createSagaMiddleware from 'redux-saga'; -import { all } from 'redux-saga/effects'; import { syncHistoryWithStore } from 'react-router-redux'; import rootReducer from 'app/redux/RootReducer'; -import rootSaga from 'shared/RootSaga'; +import { fetchDataWatches } from 'app/redux/FetchDataSaga'; +import { marketWatches } from 'app/redux/MarketSaga'; +import { sharedWatches } from 'app/redux/SagaShared'; +import { userWatches } from 'app/redux/UserSaga'; +import { authWatches } from 'app/redux/AuthSaga'; +import { transactionWatches } from 'app/redux/TransactionSaga'; import { component as NotFound } from 'app/components/pages/NotFound'; import extractMeta from 'app/utils/ExtractMeta'; import Translator from 'app/Translator'; @@ -192,13 +196,24 @@ class OffsetScrollBehavior extends ScrollBehavior { } //END: SCROLL CODE -const bindMiddleware = middleware => { - if (process.env.BROWSER && process.env.NODE_ENV === 'development') { - const { composeWithDevTools } = require('redux-devtools-extension'); - return composeWithDevTools(applyMiddleware(...middleware)); - } - return applyMiddleware(...middleware); -}; +const sagaMiddleware = createSagaMiddleware( + ...userWatches, // keep first to remove keys early when a page change happens + ...fetchDataWatches, + ...sharedWatches, + ...authWatches, + ...transactionWatches, + ...marketWatches +); + +let middleware; + +if (process.env.BROWSER && process.env.NODE_ENV === 'development') { + const composeEnhancers = + window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; // eslint-disable-line no-underscore-dangle + middleware = composeEnhancers(applyMiddleware(sagaMiddleware)); +} else { + middleware = applyMiddleware(sagaMiddleware); +} const runRouter = (location, routes) => { return new Promise(resolve => @@ -376,6 +391,7 @@ export async function serverRender( /** * dependencies: + * middleware * browserHistory * useScroll * OffsetScrollBehavior @@ -384,13 +400,8 @@ export async function serverRender( * @param {*} initialState */ export function clientRender(initialState) { - const sagaMiddleware = createSagaMiddleware(); - const store = createStore( - rootReducer, - initialState, - bindMiddleware([sagaMiddleware]) - ); - sagaMiddleware.run(rootSaga); + const store = createStore(rootReducer, initialState, middleware); + const history = syncHistoryWithStore(browserHistory, store); /** diff --git a/yarn.lock b/yarn.lock index 232819da74..59a5ba0bf6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7954,10 +7954,6 @@ reduce-function-call@^1.0.1: dependencies: balanced-match "^0.4.2" -redux-devtools-extension@2.13.5: - version "2.13.5" - resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.5.tgz#3ff34f7227acfeef3964194f5f7fc2765e5c5a39" - redux-form@5.3.4: version "5.3.4" resolved "https://registry.yarnpkg.com/redux-form/-/redux-form-5.3.4.tgz#0536ec71daf919fc6ec93c9b39a9581213715980" @@ -7974,9 +7970,9 @@ redux-mock-store@1.5.1: dependencies: lodash.isplainobject "^4.0.6" -redux-saga@0.16.0: - version "0.16.0" - resolved "https://registry.yarnpkg.com/redux-saga/-/redux-saga-0.16.0.tgz#0a231db0a1489301dd980f6f2f88d8ced418f724" +redux-saga@0.9.5: + version "0.9.5" + resolved "https://registry.yarnpkg.com/redux-saga/-/redux-saga-0.9.5.tgz#f4bde5896e466932f758f86247b2fa6a4694ec2a" redux@3.7.2, redux@^3.7.2: version "3.7.2"