feat: persist color theme setting

This commit is contained in:
Jeremy Kahn 2022-09-05 17:35:40 -05:00
parent 82673d54fd
commit 7fb46bfe27
5 changed files with 71 additions and 26 deletions

View File

@ -52,6 +52,7 @@ test('persists user settings if none were already persisted', async () => {
})
expect(mockSetItem).toHaveBeenCalledWith(PersistedStorageKeys.USER_SETTINGS, {
colorMode: 'dark',
userId: 'abc123',
})
})

View File

@ -3,6 +3,7 @@ import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import { v4 as uuid } from 'uuid'
import localforage from 'localforage'
import { SettingsContext } from 'contexts/SettingsContext'
import { Home } from 'pages/Home/'
import { PublicRoom } from 'pages/PublicRoom/'
import { UserSettings } from 'models/settings'
@ -22,8 +23,11 @@ function Bootstrap({
getUuid = uuid,
}: BootstrapProps) {
const [hasLoadedSettings, setHasLoadedSettings] = useState(false)
const [settings, setSettings] = useState({ userId: getUuid() })
const { userId } = settings
const [userSettings, setUserSettings] = useState<UserSettings>({
userId: getUuid(),
colorMode: 'dark',
})
const { userId } = userSettings
useEffect(() => {
;(async () => {
@ -35,35 +39,54 @@ function Bootstrap({
)
if (persistedUserSettings) {
setSettings(persistedUserSettings)
setUserSettings(persistedUserSettings)
} else {
await persistedStorage.setItem(
PersistedStorageKeys.USER_SETTINGS,
settings
userSettings
)
}
setHasLoadedSettings(true)
})()
}, [hasLoadedSettings, persistedStorage, settings, userId])
}, [hasLoadedSettings, persistedStorage, userSettings, userId])
const settingsContextValue = {
updateUserSettings: async (changedSettings: Partial<UserSettings>) => {
const newSettings = {
...userSettings,
...changedSettings,
}
await persistedStorage.setItem(
PersistedStorageKeys.USER_SETTINGS,
newSettings
)
setUserSettings(newSettings)
},
getUserSettings: () => ({ ...userSettings }),
}
return (
<Router>
<Shell userPeerId={userId}>
{hasLoadedSettings ? (
<Routes>
{['/', '/index.html'].map(path => (
<Route key={path} path={path} element={<Home />} />
))}
<Route
path="/public/:roomId"
element={<PublicRoom userId={userId} />}
/>
</Routes>
) : (
<></>
)}
</Shell>
<SettingsContext.Provider value={settingsContextValue}>
<Shell userPeerId={userId}>
{hasLoadedSettings ? (
<Routes>
{['/', '/index.html'].map(path => (
<Route key={path} path={path} element={<Home />} />
))}
<Route
path="/public/:roomId"
element={<PublicRoom userId={userId} />}
/>
</Routes>
) : (
<></>
)}
</Shell>
</SettingsContext.Provider>
</Router>
)
}

View File

@ -1,11 +1,12 @@
import {
forwardRef,
PropsWithChildren,
SyntheticEvent,
forwardRef,
useCallback,
useContext,
useEffect,
useMemo,
useState,
SyntheticEvent,
} from 'react'
import { Link } from 'react-router-dom'
import CssBaseline from '@mui/material/CssBaseline'
@ -34,6 +35,7 @@ import Brightness4Icon from '@mui/icons-material/Brightness4'
import Brightness7Icon from '@mui/icons-material/Brightness7'
import { ShellContext } from 'contexts/ShellContext'
import { SettingsContext } from 'contexts/SettingsContext'
import { AlertOptions } from 'models/shell'
import { PeerNameDisplay } from 'components/PeerNameDisplay'
@ -98,6 +100,7 @@ const DrawerHeader = styled('div')(({ theme }) => ({
}))
export const Shell = ({ children, userPeerId }: ShellProps) => {
const settingsContext = useContext(SettingsContext)
const [isAlertShowing, setIsAlertShowing] = useState(false)
const [isDrawerOpen, setIsDrawerOpen] = useState(false)
const [doShowPeers, setDoShowPeers] = useState(false)
@ -125,20 +128,21 @@ export const Shell = ({ children, userPeerId }: ShellProps) => {
[numberOfPeers, setDoShowPeers, setNumberOfPeers, setTitle, showAlert]
)
const [mode, setMode] = useState<'light' | 'dark'>('dark')
const colorMode = settingsContext.getUserSettings().colorMode
const handleColorModeToggleClick = () => {
setMode(prevMode => (prevMode === 'light' ? 'dark' : 'light'))
const newMode = colorMode === 'light' ? 'dark' : 'light'
settingsContext.updateUserSettings({ colorMode: newMode })
}
const theme = useMemo(
() =>
createTheme({
palette: {
mode,
mode: colorMode,
},
}),
[mode]
[colorMode]
)
const handleAlertClose = (

View File

@ -0,0 +1,16 @@
import { createContext } from 'react'
import { UserSettings } from 'models/settings'
interface SettingsContextProps {
updateUserSettings: (settings: Partial<UserSettings>) => Promise<void>
getUserSettings: () => UserSettings
}
export const SettingsContext = createContext<SettingsContextProps>({
updateUserSettings: () => Promise.resolve(),
getUserSettings: () => ({
userId: '',
colorMode: 'dark',
}),
})

View File

@ -1,3 +1,4 @@
export interface UserSettings {
colorMode: 'dark' | 'light'
userId: string
}