feat: store state in localStorage
This commit is contained in:
Generated
+5
@@ -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",
|
||||||
|
|||||||
@@ -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
@@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user