// @flow import * as ACTIONS from 'constants/action_types'; import isEqual from 'util/deep-equal'; import { doPreferenceSet } from 'redux/actions/sync'; const RUN_PREFERENCES_DELAY_MS = 2000; const SHARED_PREFERENCE_VERSION = '0.1'; let oldShared = {}; let timeout; export const buildSharedStateMiddleware = ( actions: Array, sharedStateFilters: {}, sharedStateCb?: (any) => void ) => ({ getState, dispatch }: { getState: GetState, dispatch: Dispatch }) => (next: ({}) => void) => (action: { type: string, data: any, }) => { // We don't care if sync is disabled here, we always want to backup preferences to the wallet if (!actions.includes(action.type) || typeof action === 'function') { return next(action); } clearTimeout(timeout); const actionResult = next(action); // Call `getState` after calling `next` to ensure the state has updated in response to the action function runPreferences() { const nextState = getState(); const syncEnabled = nextState?.settings?.clientSettings?.enable_sync; const hasVerifiedEmail = nextState?.user?.user?.has_verified_email; const prefsReady = nextState?.sync.prefsReady; const preferenceKey = syncEnabled && hasVerifiedEmail && prefsReady ? 'shared' : 'local'; const shared = {}; Object.keys(sharedStateFilters).forEach((key) => { const filter = sharedStateFilters[key]; const { source, property, transform } = filter; let value = nextState[source][property]; if (transform) { value = transform(value); } shared[key] = value; }); if (!isEqual(oldShared, shared)) { // only update if the preference changed from last call in the same session oldShared = shared; dispatch(doPreferenceSet(preferenceKey, shared, SHARED_PREFERENCE_VERSION)); } if (sharedStateCb) { // Pass dispatch to the callback to consumers can dispatch actions in response to preference set sharedStateCb({ dispatch, getState, syncId: timeout }); } clearTimeout(timeout); return actionResult; } timeout = setTimeout(runPreferences, RUN_PREFERENCES_DELAY_MS); dispatch({ type: ACTIONS.SHARED_STATE_SYNC_ID_CHANGED, data: timeout }); };