feat: store state in localStorage

This commit is contained in:
Deluan
2020-03-31 14:04:10 -04:00
parent 944f3695c4
commit 083a11a563
6 changed files with 140 additions and 39 deletions
+5
View File
@@ -10436,6 +10436,11 @@
"lodash._reinterpolate": "^3.0.0" "lodash._reinterpolate": "^3.0.0"
} }
}, },
"lodash.throttle": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
"integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ="
},
"lodash.uniq": { "lodash.uniq": {
"version": "4.5.0", "version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
+1
View File
@@ -8,6 +8,7 @@
"@testing-library/user-event": "^10.0.0", "@testing-library/user-event": "^10.0.0",
"deepmerge": "^4.2.2", "deepmerge": "^4.2.2",
"jwt-decode": "^2.2.0", "jwt-decode": "^2.2.0",
"lodash.throttle": "^4.1.1",
"md5-hex": "^3.0.1", "md5-hex": "^3.0.1",
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"ra-data-json-server": "^3.3.1", "ra-data-json-server": "^3.3.1",
+53 -35
View File
@@ -1,4 +1,6 @@
import React from 'react' import React from 'react'
import { Provider } from 'react-redux'
import { createHashHistory } from 'history'
import { Admin, resolveBrowserLocale, Resource } from 'react-admin' import { Admin, resolveBrowserLocale, Resource } from 'react-admin'
import dataProvider from './dataProvider' import dataProvider from './dataProvider'
import authProvider from './authProvider' import authProvider from './authProvider'
@@ -15,12 +17,15 @@ import { Player, playQueueReducer } from './audioplayer'
import { albumViewReducer } from './album/albumState' import { albumViewReducer } from './album/albumState'
import customRoutes from './routes' import customRoutes from './routes'
import themeReducer from './configuration/themeReducer' import themeReducer from './configuration/themeReducer'
import createAdminStore from './store/createAdminStore'
const i18nProvider = polyglotI18nProvider( const i18nProvider = polyglotI18nProvider(
(locale) => (messages[locale] ? messages[locale] : messages.en), (locale) => (messages[locale] ? messages[locale] : messages.en),
resolveBrowserLocale() resolveBrowserLocale()
) )
const history = createHashHistory()
const App = () => { const App = () => {
try { try {
const appConfig = JSON.parse(window.__APP_CONFIG__) const appConfig = JSON.parse(window.__APP_CONFIG__)
@@ -32,44 +37,57 @@ const App = () => {
} catch (e) {} } catch (e) {}
return ( return (
<Admin <Provider
customReducers={{ store={createAdminStore({
queue: playQueueReducer, authProvider,
albumView: albumViewReducer, dataProvider,
theme: themeReducer history,
}} customReducers: {
dataProvider={dataProvider} queue: playQueueReducer,
authProvider={authProvider} albumView: albumViewReducer,
i18nProvider={i18nProvider} theme: themeReducer
customRoutes={customRoutes} }
layout={Layout} })}
loginPage={Login}
> >
{(permissions) => [ <Admin
<Resource name="artist" {...artist} options={{ subMenu: 'library' }} />, dataProvider={dataProvider}
<Resource name="album" {...album} options={{ subMenu: 'library' }} />, authProvider={authProvider}
<Resource name="song" {...song} options={{ subMenu: 'library' }} />, i18nProvider={i18nProvider}
<Resource name="albumSong" />, customRoutes={customRoutes}
permissions === 'admin' ? ( history={history}
<Resource name="user" {...user} options={{ subMenu: 'settings' }} /> layout={Layout}
) : null, loginPage={Login}
<Resource >
name="player" {(permissions) => [
{...player}
options={{ subMenu: 'settings' }}
/>,
permissions === 'admin' ? (
<Resource <Resource
name="transcoding" name="artist"
{...transcoding} {...artist}
options={{ subMenu: 'library' }}
/>,
<Resource name="album" {...album} options={{ subMenu: 'library' }} />,
<Resource name="song" {...song} options={{ subMenu: 'library' }} />,
<Resource name="albumSong" />,
permissions === 'admin' ? (
<Resource name="user" {...user} options={{ subMenu: 'settings' }} />
) : null,
<Resource
name="player"
{...player}
options={{ subMenu: 'settings' }} options={{ subMenu: 'settings' }}
/> />,
) : ( permissions === 'admin' ? (
<Resource name="transcoding" /> <Resource
), name="transcoding"
<Player /> {...transcoding}
]} options={{ subMenu: 'settings' }}
</Admin> />
) : (
<Resource name="transcoding" />
),
<Player />
]}
</Admin>
</Provider>
) )
} }
+2 -4
View File
@@ -22,8 +22,8 @@ const selectAlbumList = (mode) => ({ type: mode })
const albumViewReducer = ( const albumViewReducer = (
previousState = { previousState = {
mode: localStorage.getItem('albumViewMode') || ALBUM_MODE_LIST, mode: ALBUM_MODE_LIST,
list: localStorage.getItem('albumListType') || ALBUM_LIST_ALL, list: ALBUM_LIST_ALL,
params: { sort: {}, filter: {} } params: { sort: {}, filter: {} }
}, },
payload payload
@@ -32,14 +32,12 @@ const albumViewReducer = (
switch (type) { switch (type) {
case ALBUM_MODE_GRID: case ALBUM_MODE_GRID:
case ALBUM_MODE_LIST: case ALBUM_MODE_LIST:
localStorage.setItem('albumViewMode', type)
return { ...previousState, mode: type } return { ...previousState, mode: type }
case ALBUM_LIST_ALL: case ALBUM_LIST_ALL:
case ALBUM_LIST_RANDOM: case ALBUM_LIST_RANDOM:
case ALBUM_LIST_NEWEST: case ALBUM_LIST_NEWEST:
case ALBUM_LIST_RECENT: case ALBUM_LIST_RECENT:
case ALBUM_LIST_STARRED: case ALBUM_LIST_STARRED:
localStorage.setItem('albumListType', type)
return { ...previousState, list: type, params: albumListParams[type] } return { ...previousState, list: type, params: albumListParams[type] }
default: default:
return previousState return previousState
+59
View File
@@ -0,0 +1,59 @@
import { applyMiddleware, combineReducers, compose, createStore } from 'redux'
import { routerMiddleware, connectRouter } from 'connected-react-router'
import createSagaMiddleware from 'redux-saga'
import { all, fork } from 'redux-saga/effects'
import { adminReducer, adminSaga, USER_LOGOUT } from 'react-admin'
import throttle from 'lodash.throttle'
import { loadState, saveState } from './persistState'
export default ({
authProvider,
dataProvider,
history,
customReducers = {}
}) => {
const reducer = combineReducers({
admin: adminReducer,
router: connectRouter(history),
...customReducers
})
const resettableAppReducer = (state, action) =>
reducer(action.type !== USER_LOGOUT ? state : undefined, action)
const saga = function* rootSaga() {
yield all([adminSaga(dataProvider, authProvider)].map(fork))
}
const sagaMiddleware = createSagaMiddleware()
const composeEnhancers =
(process.env.NODE_ENV === 'development' &&
typeof window !== 'undefined' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
trace: true,
traceLimit: 25
})) ||
compose
const persistedState = loadState()
const store = createStore(
resettableAppReducer,
persistedState,
composeEnhancers(applyMiddleware(sagaMiddleware, routerMiddleware(history)))
)
store.subscribe(
throttle(() => {
const state = store.getState()
saveState({
theme: state.theme,
// queue: state.queue, TODO: Need to make queue serializable (remove functions from it)
albumView: state.albumView
})
}),
1000
)
sagaMiddleware.run(saga)
return store
}
+20
View File
@@ -0,0 +1,20 @@
export const loadState = () => {
try {
const serializedState = localStorage.getItem('state')
if (serializedState === null) {
return undefined
}
return JSON.parse(serializedState)
} catch (err) {
return undefined
}
}
export const saveState = (state) => {
try {
const serializedState = JSON.stringify(state)
localStorage.setItem('state', serializedState)
} catch (err) {
// Ignore write errors
}
}