From 7e406e4f7702080318cf56f7bf20bb82b9be30fd Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Thu, 21 Feb 2019 14:14:46 +0000 Subject: [PATCH] Split the store construction to a separate file. --- src/store/construct.ts | 165 +++++++++++++++++++++++++++++++++++++++++ src/store/index.ts | 16 +--- src/store/reducers.ts | 163 +++------------------------------------- 3 files changed, 176 insertions(+), 168 deletions(-) create mode 100644 src/store/construct.ts diff --git a/src/store/construct.ts b/src/store/construct.ts new file mode 100644 index 0000000..d070fb6 --- /dev/null +++ b/src/store/construct.ts @@ -0,0 +1,165 @@ +import * as localforage from 'localforage'; +import { combineReducers } from 'redux'; +import { createMigrate, persistReducer, createTransform } from 'redux-persist'; +import session from 'redux-persist/lib/storage/session'; + +import { List, Map as ImmutableMap } from 'immutable'; + +import * as EteSync from '../api/EteSync'; +import { + JournalsData, FetchType, EntriesData, EntriesFetchRecord, UserInfoData, JournalsFetchRecord, UserInfoFetchRecord, + CredentialsTypeRemote, JournalsType, EntriesType, UserInfoType, SettingsType, + fetchCount, journals, entries, credentials, userInfo, settingsReducer, encryptionKeyReducer, +} from './reducers'; + +export interface StoreState { + fetchCount: number; + credentials: CredentialsTypeRemote; + settings: SettingsType; + encryptionKey: {key: string}; + cache: { + journals: JournalsType; + entries: EntriesType; + userInfo: UserInfoType; + }; +} + +const settingsPersistConfig = { + key: 'settings', + storage: localforage, +}; + +const credentialsPersistConfig = { + key: 'credentials', + storage: localforage, + whitelist: ['value'], +}; + +const encryptionKeyPersistConfig = { + key: 'encryptionKey', + storage: session, +}; + +const journalsSerialize = (state: JournalsData) => { + if (state === null) { + return null; + } + + return state.map((x, uid) => x.serialize()).toJS(); +}; + +const journalsDeserialize = (state: {}) => { + if (state === null) { + return null; + } + + const newState = new Map(); + Object.keys(state).forEach((uid) => { + const x = state[uid]; + const ret = new EteSync.Journal(x.version); + ret.deserialize(x); + newState.set(uid, ret); + }); + return ImmutableMap(newState); +}; + +const entriesSerialize = (state: FetchType) => { + if ((state === null) || (state.value == null)) { + return null; + } + + return state.value.map((x) => x.serialize()).toJS(); +}; + +const entriesDeserialize = (state: EteSync.EntryJson[]): FetchType => { + if (state === null) { + return new EntriesFetchRecord({value: null}); + } + + return new EntriesFetchRecord({value: List(state.map((x: any) => { + let ret = new EteSync.Entry(); + ret.deserialize(x); + return ret; + }))}); +}; + +const userInfoSerialize = (state: FetchType) => { + if ((state === null) || (state.value == null)) { + return null; + } + + return state.value.serialize(); +}; + +const userInfoDeserialize = (state: EteSync.UserInfoJson) => { + if (state === null) { + return null; + } + + let ret = new EteSync.UserInfo(state.owner!, state.version); + ret.deserialize(state); + return ret; +}; + +const cacheSerialize = (state: any, key: string) => { + if (key === 'entries') { + let ret = {}; + state.forEach((value: FetchType, mapKey: string) => { + ret[mapKey] = entriesSerialize(value); + }); + return ret; + } else if (key === 'journals') { + return journalsSerialize(state.value); + } else if (key === 'userInfo') { + return userInfoSerialize(state); + } + + return state; +}; + +const cacheDeserialize = (state: any, key: string) => { + if (key === 'entries') { + let ret = {}; + Object.keys(state).forEach((mapKey) => { + ret[mapKey] = entriesDeserialize(state[mapKey]); + }); + return ImmutableMap(ret); + } else if (key === 'journals') { + return new JournalsFetchRecord({value: journalsDeserialize(state)}); + } else if (key === 'userInfo') { + return new UserInfoFetchRecord({value: userInfoDeserialize(state)}); + } + + return state; +}; + +const cacheMigrations = { + 0: (state: any) => { + return { + ...state, + journals: undefined + }; + }, +}; + +const cachePersistConfig = { + key: 'cache', + version: 1, + storage: localforage, + transforms: [createTransform(cacheSerialize, cacheDeserialize)], + migrate: createMigrate(cacheMigrations, { debug: false}), +}; + +const reducers = combineReducers({ + fetchCount, + settings: persistReducer(settingsPersistConfig, settingsReducer), + credentials: persistReducer(credentialsPersistConfig, credentials), + encryptionKey: persistReducer(encryptionKeyPersistConfig, encryptionKeyReducer), + cache: persistReducer(cachePersistConfig, combineReducers({ + entries, + journals, + userInfo, + })), +}); + +export default reducers; diff --git a/src/store/index.ts b/src/store/index.ts index 97f83f7..835e67e 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -5,23 +5,11 @@ import { createLogger } from 'redux-logger'; import promiseMiddleware from './promise-middleware'; -import reducers from './reducers'; -import { CredentialsTypeRemote, JournalsType, EntriesType, UserInfoType, SettingsType } from './reducers'; +import reducers from './construct'; // Workaround babel limitation export * from './reducers'; - -export interface StoreState { - fetchCount: number; - credentials: CredentialsTypeRemote; - settings: SettingsType; - encryptionKey: {key: string}; - cache: { - journals: JournalsType; - entries: EntriesType; - userInfo: UserInfoType; - }; -} +export * from './construct'; let middleware = [ thunkMiddleware, diff --git a/src/store/reducers.ts b/src/store/reducers.ts index c5f0b75..d233eec 100644 --- a/src/store/reducers.ts +++ b/src/store/reducers.ts @@ -1,10 +1,5 @@ -import { combineReducers } from 'redux'; -import { createMigrate, persistReducer, createTransform } from 'redux-persist'; import { Action, ActionFunctionAny, combineActions, handleAction, handleActions } from 'redux-actions'; -import * as localforage from 'localforage'; -import session from 'redux-persist/lib/storage/session'; - import { List, Map as ImmutableMap, Record } from 'immutable'; import * as EteSync from '../api/EteSync'; @@ -43,20 +38,20 @@ export type CredentialsType = FetchType; export type CredentialsTypeRemote = FetchType; export type JournalsData = ImmutableMap; -const JournalsFetchRecord = fetchTypeRecord(); +export const JournalsFetchRecord = fetchTypeRecord(); export type JournalsType = FetchType; export type JournalsTypeImmutable = Record; export type EntriesData = List; -const EntriesFetchRecord = fetchTypeRecord(); +export const EntriesFetchRecord = fetchTypeRecord(); export type EntriesTypeImmutable = ImmutableMap>>; export type EntriesType = ImmutableMap>; export type UserInfoData = EteSync.UserInfo; -const UserInfoFetchRecord = fetchTypeRecord(); +export const UserInfoFetchRecord = fetchTypeRecord(); export type UserInfoType = FetchType; export type UserInfoTypeImmutable = Record; @@ -87,7 +82,7 @@ function fetchTypeIdentityReducer( } } -const encryptionKeyReducer = handleActions( +export const encryptionKeyReducer = handleActions( { [actions.deriveKey.toString()]: (state: {key: string | null}, action: any) => ( {key: action.payload} @@ -99,7 +94,7 @@ const encryptionKeyReducer = handleActions( {key: null} ); -const credentials = handleActions( +export const credentials = handleActions( { [actions.fetchCredentials.toString()]: ( state: CredentialsTypeRemote, action: any, extend: boolean = false) => { @@ -212,14 +207,14 @@ export const entries = handleAction( ImmutableMap({}) ); -const journals = handleActions( +export const journals = handleActions( { ...mapReducerActionsMapCreator('Journal'), }, new JournalsFetchRecord(), ); -const userInfo = handleAction( +export const userInfo = handleAction( combineActions( actions.fetchUserInfo, actions.createUserInfo @@ -258,7 +253,7 @@ for (const func in actions) { } // Indicates network activity, not just fetch -const fetchCount = handleAction( +export const fetchCount = handleAction( combineActions( ...fetchActions, ), @@ -277,7 +272,7 @@ export interface SettingsType { locale: string; }; -const settingsReducer = handleActions( +export const settingsReducer = handleActions( { [actions.setSettings.toString()]: (state: {key: string | null}, action: any) => ( {...action.payload} @@ -285,143 +280,3 @@ const settingsReducer = handleActions( }, { locale: 'en-gb' } ); - -const settingsPersistConfig = { - key: 'settings', - storage: localforage, -}; - -const credentialsPersistConfig = { - key: 'credentials', - storage: localforage, - whitelist: ['value'], -}; - -const encryptionKeyPersistConfig = { - key: 'encryptionKey', - storage: session, -}; - -const journalsSerialize = (state: JournalsData) => { - if (state === null) { - return null; - } - - return state.map((x, uid) => x.serialize()).toJS(); -}; - -const journalsDeserialize = (state: {}) => { - if (state === null) { - return null; - } - - const newState = new Map(); - Object.keys(state).forEach((uid) => { - const x = state[uid]; - const ret = new EteSync.Journal(x.version); - ret.deserialize(x); - newState.set(uid, ret); - }); - return ImmutableMap(newState); -}; - -const entriesSerialize = (state: FetchType) => { - if ((state === null) || (state.value == null)) { - return null; - } - - return state.value.map((x) => x.serialize()).toJS(); -}; - -const entriesDeserialize = (state: EteSync.EntryJson[]): FetchType => { - if (state === null) { - return new EntriesFetchRecord({value: null}); - } - - return new EntriesFetchRecord({value: List(state.map((x: any) => { - let ret = new EteSync.Entry(); - ret.deserialize(x); - return ret; - }))}); -}; - -const userInfoSerialize = (state: FetchType) => { - if ((state === null) || (state.value == null)) { - return null; - } - - return state.value.serialize(); -}; - -const userInfoDeserialize = (state: EteSync.UserInfoJson) => { - if (state === null) { - return null; - } - - let ret = new EteSync.UserInfo(state.owner!, state.version); - ret.deserialize(state); - return ret; -}; - -const cacheSerialize = (state: any, key: string) => { - if (key === 'entries') { - let ret = {}; - state.forEach((value: FetchType, mapKey: string) => { - ret[mapKey] = entriesSerialize(value); - }); - return ret; - } else if (key === 'journals') { - return journalsSerialize(state.value); - } else if (key === 'userInfo') { - return userInfoSerialize(state); - } - - return state; -}; - -const cacheDeserialize = (state: any, key: string) => { - if (key === 'entries') { - let ret = {}; - Object.keys(state).forEach((mapKey) => { - ret[mapKey] = entriesDeserialize(state[mapKey]); - }); - return ImmutableMap(ret); - } else if (key === 'journals') { - return new JournalsFetchRecord({value: journalsDeserialize(state)}); - } else if (key === 'userInfo') { - return new UserInfoFetchRecord({value: userInfoDeserialize(state)}); - } - - return state; -}; - -const cacheMigrations = { - 0: (state: any) => { - return { - ...state, - journals: undefined - }; - }, -}; - -const cachePersistConfig = { - key: 'cache', - version: 1, - storage: localforage, - transforms: [createTransform(cacheSerialize, cacheDeserialize)], - migrate: createMigrate(cacheMigrations, { debug: false}), -}; - -const reducers = combineReducers({ - fetchCount, - settings: persistReducer(settingsPersistConfig, settingsReducer), - credentials: persistReducer(credentialsPersistConfig, credentials), - encryptionKey: persistReducer(encryptionKeyPersistConfig, encryptionKeyReducer), - cache: persistReducer(cachePersistConfig, combineReducers({ - entries, - journals, - userInfo, - })), -}); - -export default reducers;