Persist slice of redux state in local storage

This commit is contained in:
Peizhi Zheng 2021-01-14 20:46:41 -08:00 committed by GitHub
parent b1398742b9
commit 1df5004203
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 61 additions and 24 deletions

View File

@ -26,7 +26,7 @@ import DoubleArrowIcon from "@material-ui/icons/DoubleArrow";
import CloseIcon from "@material-ui/icons/Close";
import { AppState } from "./store";
import { paths } from "./paths";
import { makeTheme } from "./theme";
import { useTheme } from "./theme";
import { closeSnackbar } from "./actions/snackbarActions";
import ListItemLink from "./components/ListItemLink";
import SchedulersView from "./views/SchedulersView";
@ -146,7 +146,7 @@ function SlideUpTransition(props: TransitionProps) {
}
function App(props: ConnectedProps<typeof connector>) {
const theme = makeTheme(props.themePreference);
const theme = useTheme(props.themePreference);
const classes = useStyles(theme)();
const [open, setOpen] = useState(true);
const toggleDrawer = () => setOpen(!open);

View File

@ -1,5 +1,4 @@
import { ThemePreference } from "../reducers/settingsReducer";
// List of settings related action types.
export const POLL_INTERVAL_CHANGE = "POLL_INTERVAL_CHANGE";
export const THEME_PREFERENCE_CHANGE = "THEME_PREFERENCE_CHANGE";

View File

@ -5,6 +5,11 @@ import { Provider } from "react-redux";
import App from "./App";
import store from "./store";
import * as serviceWorker from "./serviceWorker";
import { saveState } from "./localStorage";
store.subscribe(() => {
saveState(store.getState());
});
ReactDOM.render(
<React.StrictMode>

24
ui/src/localStorage.ts Normal file
View File

@ -0,0 +1,24 @@
import { AppState } from "./store";
const LOCAL_STORAGE_KEY = "asynqmon:state";
export function loadState(): AppState | undefined {
try {
const serializedState = localStorage.getItem(LOCAL_STORAGE_KEY);
if (serializedState === null) {
return undefined;
}
return JSON.parse(serializedState);
} catch (err) {
return undefined;
}
}
export function saveState(state: AppState) {
try {
const serializedState = JSON.stringify({ settings: state.settings });
localStorage.setItem(LOCAL_STORAGE_KEY, serializedState);
} catch (err) {
console.error("saveState: could not save state: ", err);
}
}

View File

@ -7,6 +7,7 @@ import schedulerEntriesReducer from "./reducers/schedulerEntriesReducer";
import snackbarReducer from "./reducers/snackbarReducer";
import queueStatsReducer from "./reducers/queueStatsReducer";
import redisInfoReducer from "./reducers/redisInfoReducer";
import { loadState } from "./localStorage";
const rootReducer = combineReducers({
settings: settingsReducer,
@ -19,9 +20,14 @@ const rootReducer = combineReducers({
redis: redisInfoReducer,
});
const preloadedState = loadState();
// AppState is the top-level application state maintained by redux store.
export type AppState = ReturnType<typeof rootReducer>;
export default configureStore({
const store = configureStore({
reducer: rootReducer,
preloadedState,
});
export default store;

View File

@ -2,8 +2,7 @@ import { createMuiTheme, Theme } from "@material-ui/core/styles";
import { ThemePreference } from "./reducers/settingsReducer";
import useMediaQuery from "@material-ui/core/useMediaQuery";
export function makeTheme(themePreference: ThemePreference): Theme {
// eslint-disable-next-line react-hooks/rules-of-hooks
export function useTheme(themePreference: ThemePreference): Theme {
let prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
if (themePreference === ThemePreference.Always) {
prefersDarkMode = true;

View File

@ -63,14 +63,14 @@ function SettingsView(props: PropsFromRedux) {
props.selectTheme(event.target.value as ThemePreference);
};
return (
<Container maxWidth="lg" className={classes.container}>
<Container maxWidth="md" className={classes.container}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Typography variant="h5" color="textPrimary">
Settings
</Typography>
</Grid>
<Grid item xs={5}>
<Grid item xs={6}>
<Paper className={classes.paper} variant="outlined">
<Typography color="textPrimary">Polling Interval</Typography>
<Typography gutterBottom color="textSecondary" variant="subtitle1">
@ -93,22 +93,26 @@ function SettingsView(props: PropsFromRedux) {
/>
</Paper>
</Grid>
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel id="theme-label">Dark theme</InputLabel>
<Select
labelId="theme-label"
id="theme-selected"
value={props.themePreference}
onChange={handleThemeChange}
label="theme preference"
>
<MenuItem value={ThemePreference.SystemDefault}>
System Default
</MenuItem>
<MenuItem value={ThemePreference.Always}>Always</MenuItem>
<MenuItem value={ThemePreference.Never}>Never</MenuItem>
</Select>
</FormControl>
<Grid item>
<Paper className={classes.paper} variant="outlined">
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel id="theme-label">Dark theme</InputLabel>
<Select
labelId="theme-label"
id="theme-selected"
value={props.themePreference}
onChange={handleThemeChange}
label="theme preference"
>
<MenuItem value={ThemePreference.SystemDefault}>
System Default
</MenuItem>
<MenuItem value={ThemePreference.Always}>Always</MenuItem>
<MenuItem value={ThemePreference.Never}>Never</MenuItem>
</Select>
</FormControl>
</Paper>
</Grid>
</Grid>
</Container>
);