diff --git a/package-lock.json b/package-lock.json index b5ad180a23b..03cee3ef21c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62016,7 +62016,8 @@ }, "node_modules/localforage": { "version": "1.10.0", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", + "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==", "dependencies": { "lie": "3.1.1" } @@ -87512,7 +87513,8 @@ }, "node_modules/redux-persist": { "version": "6.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-6.0.0.tgz", + "integrity": "sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==", "peerDependencies": { "redux": ">4.0.0" } @@ -133653,6 +133655,7 @@ "lerp": "1.0.3", "linkify-react": "^4.1.0", "linkifyjs": "4.1.0", + "localforage": "1.10.0", "lodash": "4.17.21", "numeral": "2.0.6", "orbit-controls": "0.0.1", @@ -133687,6 +133690,7 @@ "react-virtualized": "9.22.3", "redux": "4.1.1", "redux-devtools-extension": "2.13.8", + "redux-persist": "6.0.0", "redux-saga": "1.1.3", "redux-sentry-middleware": "0.1.8", "redux-thunk": "2.4.2", diff --git a/packages/common/src/store/pages/index.ts b/packages/common/src/store/pages/index.ts index 5f69b13af0f..b5a1d9c9432 100644 --- a/packages/common/src/store/pages/index.ts +++ b/packages/common/src/store/pages/index.ts @@ -62,7 +62,7 @@ export * as savedPageActions from './saved-page/actions' export * as savedPageSelectors from './saved-page/selectors' export * from './saved-page/types' export * from './saved-page/utils' -export { default as savedPageReducer } from './saved-page/reducer' +export { persistedSavePageReducer } from './saved-page/reducer' export { default as remixesPageLineupReducer, diff --git a/packages/common/src/store/pages/saved-page/actions.ts b/packages/common/src/store/pages/saved-page/actions.ts index 57fc4e738ae..f5d2380e662 100644 --- a/packages/common/src/store/pages/saved-page/actions.ts +++ b/packages/common/src/store/pages/saved-page/actions.ts @@ -21,10 +21,6 @@ export const ADD_LOCAL_COLLECTION = 'SAVED/ADD_LOCAL_COLLECTION' export const REMOVE_LOCAL_COLLECTION = 'SAVED/REMOVE_LOCAL_COLLECTION' export const SET_SELECTED_CATEGORY = 'SAVED/SET_SELECTED_CATEGORY' -export const INIT_COLLECTIONS_CATEGORY_FROM_LOCAL_STORAGE = - 'SAVED/INIT_COLLECTIONS_CATEGORY_FROM_LOCAL_STORAGE' -export const INIT_TRACKS_CATEGORY_FROM_LOCAL_STORAGE = - 'SAVED/INIT_TRACKS_CATEGORY_FROM_LOCAL_STORAGE' export const fetchSaves = ( // the filter query for the "get tracks" query @@ -155,20 +151,6 @@ export const removeLocalCollection = ({ category }) -export const initializeTracksCategoryFromLocalStorage = ( - category: LibraryCategoryType -) => ({ - type: INIT_TRACKS_CATEGORY_FROM_LOCAL_STORAGE, - category -}) - -export const initializeCollectionsCategoryFromLocalStorage = ( - category: LibraryCategoryType -) => ({ - type: INIT_COLLECTIONS_CATEGORY_FROM_LOCAL_STORAGE, - category -}) - export const setSelectedCategory = ({ category, currentTab diff --git a/packages/common/src/store/pages/saved-page/reducer.ts b/packages/common/src/store/pages/saved-page/reducer.ts index 9b55f42c476..1f5d7eacc63 100644 --- a/packages/common/src/store/pages/saved-page/reducer.ts +++ b/packages/common/src/store/pages/saved-page/reducer.ts @@ -1,3 +1,5 @@ +import { Storage, persistReducer } from 'redux-persist' + import { ID } from 'models/Identifiers' import { asLineup } from 'store/lineup/reducer' import { @@ -11,8 +13,6 @@ import { FETCH_SAVES_FAILED, FETCH_SAVES_REQUESTED, FETCH_SAVES_SUCCEEDED, - INIT_COLLECTIONS_CATEGORY_FROM_LOCAL_STORAGE, - INIT_TRACKS_CATEGORY_FROM_LOCAL_STORAGE, REMOVE_LOCAL_COLLECTION, REMOVE_LOCAL_TRACK, SET_SELECTED_CATEGORY @@ -201,18 +201,6 @@ const actionsMap: ActionsMap = { }) } }, - [INIT_TRACKS_CATEGORY_FROM_LOCAL_STORAGE](state, action) { - return { - ...state, - tracksCategory: action.category - } - }, - [INIT_COLLECTIONS_CATEGORY_FROM_LOCAL_STORAGE](state, action) { - return { - ...state, - collectionsCategory: action.category - } - }, [signOut.type]() { return initialState } @@ -229,4 +217,12 @@ const reducer = (state = initialState, action: any) => { return matchingReduceFunction(state, action) } -export default reducer +export const savedPagePersistConfig = (storage: Storage) => ({ + key: 'saved-page', + storage, + whitelist: ['tracksCategory', 'collectionsCategory'] +}) + +export const persistedSavePageReducer = (storage: Storage) => { + return persistReducer(savedPagePersistConfig(storage), reducer) +} diff --git a/packages/common/src/store/pages/saved-page/types.ts b/packages/common/src/store/pages/saved-page/types.ts index de22d7d3e07..e306e643031 100644 --- a/packages/common/src/store/pages/saved-page/types.ts +++ b/packages/common/src/store/pages/saved-page/types.ts @@ -12,10 +12,6 @@ import { LineupTrack } from '../../../models' -export const LIBRARY_TRACKS_CATEGORY_LS_KEY = 'libraryTracksCategory' - -export const LIBRARY_COLLECTIONS_CATEGORY_LS_KEY = 'libraryCollectionsCategory' - export const LibraryCategory = full.GetUserLibraryTracksTypeEnum export type LibraryCategoryType = ValueOf diff --git a/packages/common/src/store/reducers.ts b/packages/common/src/store/reducers.ts index 195107a6ac1..ede79358f0f 100644 --- a/packages/common/src/store/reducers.ts +++ b/packages/common/src/store/reducers.ts @@ -1,4 +1,5 @@ import { combineReducers } from 'redux' +import type { Storage } from 'redux-persist' import apiReducer from '../api/reducer' import { Kind } from '../models' @@ -44,7 +45,7 @@ import premiumTracks from './pages/premium-tracks/slice' import profileReducer from './pages/profile/reducer' import { ProfilePageState } from './pages/profile/types' import remixes from './pages/remixes/slice' -import savedPageReducer from './pages/saved-page/reducer' +import { persistedSavePageReducer } from './pages/saved-page/reducer' import searchResults from './pages/search-results/reducer' import { SearchPageState } from './pages/search-results/types' import settings from './pages/settings/reducer' @@ -132,12 +133,10 @@ import topSupportersUserListReducer from './user-list/top-supporters/reducers' import wallet from './wallet/slice' /** - * A function that creates common reducers. The function takes - * a CommonStoreContext as input such that platforms (native and web) - * may specify system-level APIs, e.g. local storage. + * A function that creates common reducers. * @returns an object of all reducers to be used with `combineReducers` */ -export const reducers = () => ({ +export const reducers = (storage: Storage) => ({ account, api: apiReducer, @@ -234,7 +233,7 @@ export const reducers = () => ({ historyPage: historyPageReducer, profile: profileReducer, smartCollection, - savedPage: savedPageReducer, + savedPage: persistedSavePageReducer(storage), searchResults, tokenDashboard: tokenDashboardSlice.reducer, track, diff --git a/packages/mobile/src/store/store.ts b/packages/mobile/src/store/store.ts index 66df292711b..50a69f11cb2 100644 --- a/packages/mobile/src/store/store.ts +++ b/packages/mobile/src/store/store.ts @@ -6,6 +6,7 @@ import { reducers as commonReducers, chatMiddleware } from '@audius/common' +import AsyncStorage from '@react-native-async-storage/async-storage' import backend from 'audius-client/src/common/store/backend/reducer' import type { BackendState } from 'audius-client/src/common/store/backend/types' import searchBar from 'audius-client/src/common/store/search-bar/reducer' @@ -105,7 +106,7 @@ const onSagaError = ( } } -const commonStoreReducers = commonReducers() +const commonStoreReducers = commonReducers(AsyncStorage) const rootReducer = combineReducers({ ...commonStoreReducers, diff --git a/packages/web/package.json b/packages/web/package.json index fbc8ac93272..9872ecb73d2 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -126,6 +126,7 @@ "lerp": "1.0.3", "linkify-react": "^4.1.0", "linkifyjs": "4.1.0", + "localforage": "1.10.0", "lodash": "4.17.21", "numeral": "2.0.6", "orbit-controls": "0.0.1", @@ -160,6 +161,7 @@ "react-virtualized": "9.22.3", "redux": "4.1.1", "redux-devtools-extension": "2.13.8", + "redux-persist": "6.0.0", "redux-saga": "1.1.3", "redux-sentry-middleware": "0.1.8", "redux-thunk": "2.4.2", diff --git a/packages/web/src/app.tsx b/packages/web/src/app.tsx index 873ae80fa0f..13b4cf6ad5e 100644 --- a/packages/web/src/app.tsx +++ b/packages/web/src/app.tsx @@ -11,6 +11,7 @@ import { ConnectedRouter } from 'connected-react-router' import { Provider, useSelector } from 'react-redux' import { Route, Switch } from 'react-router-dom' import { LastLocationProvider } from 'react-router-last-location' +import { PersistGate } from 'redux-persist/integration/react' import { CoinbasePayButtonProvider } from 'components/coinbase-pay-button' import App from 'pages/App' @@ -26,7 +27,7 @@ import { audiusSdk } from 'services/audius-sdk/audiusSdk' import { env } from 'services/env' import history from 'utils/history' -import { store } from './store/configureStore' +import { store, persistor } from './store/configureStore' import { reportToSentry } from './store/errors/reportToSentry' import './index.css' @@ -49,50 +50,52 @@ const AudiusTrpcProvider = ({ children }: { children: React.ReactNode }) => { const AudiusApp = () => { return ( - - - - - - - {({ mainContentRef }) => ( - <> - - - - - - - - - - - - - - - - )} - - - - - - + + + + + + + + {({ mainContentRef }) => ( + <> + + + + + + + + + + + + + + + + )} + + + + + + + ) } diff --git a/packages/web/src/common/store/pages/saved/sagas.ts b/packages/web/src/common/store/pages/saved/sagas.ts index bbc46eb1e5f..cd24cee7d27 100644 --- a/packages/web/src/common/store/pages/saved/sagas.ts +++ b/packages/web/src/common/store/pages/saved/sagas.ts @@ -1,26 +1,21 @@ import { - accountSelectors, APIActivityV2, + Favorite, + FavoriteType, + LibraryCategoryType, + Nullable, + User, + UserTrackMetadata, + accountSelectors, + savedPageActions as actions, decodeHashId, encodeHashId, getContext, removeNullable, responseAdapter, - savedPageActions as actions, savedPageSelectors, - signOutActions, savedPageTracksLineupActions as tracksActions, - User, - UserTrackMetadata, - waitForValue, - LIBRARY_TRACKS_CATEGORY_LS_KEY, - LIBRARY_COLLECTIONS_CATEGORY_LS_KEY, - isLibraryCategory, - LibraryCategoryType, - Nullable, - calculateNewLibraryCategories, - Favorite, - FavoriteType + waitForValue } from '@audius/common' import { call, fork, put, select, takeLatest } from 'typed-redux-saga' @@ -28,7 +23,6 @@ import { processAndCacheTracks } from 'common/store/cache/tracks/utils' import { waitForRead } from 'utils/sagaHelpers' import tracksSagas from './lineups/sagas' -const { signOut: signOutAction } = signOutActions const { getTrackSaves } = savedPageSelectors const { getAccountUser } = accountSelectors @@ -206,85 +200,6 @@ function* watchFetchMoreSaves() { ) } -/** - * Sets the selected category from local storage when the app loads - */ -function* setInitialSelectedCategory() { - const getLocalStorageItem = yield* getContext('getLocalStorageItem') - - const tracksCategoryFromLocalStorage = yield* call( - getLocalStorageItem, - LIBRARY_TRACKS_CATEGORY_LS_KEY - ) - if ( - tracksCategoryFromLocalStorage != null && - isLibraryCategory(tracksCategoryFromLocalStorage) - ) { - yield* put( - actions.initializeTracksCategoryFromLocalStorage( - tracksCategoryFromLocalStorage - ) - ) - } - - const collectionsCategoryFromLocalStorage = yield* call( - getLocalStorageItem, - LIBRARY_COLLECTIONS_CATEGORY_LS_KEY - ) - - if ( - collectionsCategoryFromLocalStorage != null && - isLibraryCategory(collectionsCategoryFromLocalStorage) - ) { - yield* put( - actions.initializeCollectionsCategoryFromLocalStorage( - collectionsCategoryFromLocalStorage - ) - ) - } -} - -function* setLocalStorageCategory( - rawParams: ReturnType -) { - const setLocalStorageItem = yield* getContext('setLocalStorageItem') - const getLocalStorageItem = yield* getContext('getLocalStorageItem') - const tracksCategoryFromLocalStorage = yield* call( - getLocalStorageItem, - LIBRARY_TRACKS_CATEGORY_LS_KEY - ) - const { collectionsCategory, tracksCategory } = calculateNewLibraryCategories( - { - currentTab: rawParams.currentTab, - chosenCategory: rawParams.category, - prevTracksCategory: tracksCategoryFromLocalStorage - } - ) - setLocalStorageItem(LIBRARY_TRACKS_CATEGORY_LS_KEY, tracksCategory) - setLocalStorageItem(LIBRARY_COLLECTIONS_CATEGORY_LS_KEY, collectionsCategory) -} - -function* watchSetSelectedCategory() { - yield* takeLatest(actions.SET_SELECTED_CATEGORY, setLocalStorageCategory) -} - -function* clearLocalStorageLibraryCategories() { - const removeLocalStorageItem = yield* getContext('removeLocalStorageItem') - removeLocalStorageItem(LIBRARY_COLLECTIONS_CATEGORY_LS_KEY) - removeLocalStorageItem(LIBRARY_TRACKS_CATEGORY_LS_KEY) -} - -function* watchSignOut() { - yield* takeLatest(signOutAction.type, clearLocalStorageLibraryCategories) -} - export default function sagas() { - return [ - ...tracksSagas(), - watchFetchSaves, - watchFetchMoreSaves, - watchSetSelectedCategory, - setInitialSelectedCategory, - watchSignOut - ] + return [...tracksSagas(), watchFetchSaves, watchFetchMoreSaves] } diff --git a/packages/web/src/store/configureStore.ts b/packages/web/src/store/configureStore.ts index c0dda517cfa..e89e3ad8e6d 100644 --- a/packages/web/src/store/configureStore.ts +++ b/packages/web/src/store/configureStore.ts @@ -3,6 +3,7 @@ import { composeWithDevToolsLogOnlyInProduction } from '@redux-devtools/extensio import * as Sentry from '@sentry/browser' import { routerMiddleware } from 'connected-react-router' import { createStore, applyMiddleware, Action, Store } from 'redux' +import { persistStore } from 'redux-persist' import createSagaMiddleware from 'redux-saga' import createSentryMiddleware from 'redux-sentry-middleware' import thunk from 'redux-thunk' @@ -145,6 +146,7 @@ const configureStore = () => { } export const store = configureStore() +export const persistor = persistStore(store) // Mount store to window for easy access window.store = store diff --git a/packages/web/src/store/reducers.ts b/packages/web/src/store/reducers.ts index 4c383fac064..9518f26d76b 100644 --- a/packages/web/src/store/reducers.ts +++ b/packages/web/src/store/reducers.ts @@ -5,6 +5,7 @@ import { } from '@audius/common' import { connectRouter } from 'connected-react-router' import { History } from 'history' +import localForage from 'localforage' import { combineReducers } from 'redux' import backend from 'common/store/backend/reducer' @@ -28,7 +29,7 @@ import userListModal from 'store/application/ui/userListModal/slice' import dragndrop from 'store/dragndrop/slice' import error from 'store/errors/reducers' -export const commonStoreReducers = clientStoreReducers() +export const commonStoreReducers = clientStoreReducers(localForage) const createRootReducer = (routeHistory: History) => combineReducers({