forked from Shiloh/remnantchat
feat: persist color theme setting
This commit is contained in:
parent
82673d54fd
commit
7fb46bfe27
@ -52,6 +52,7 @@ test('persists user settings if none were already persisted', async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
expect(mockSetItem).toHaveBeenCalledWith(PersistedStorageKeys.USER_SETTINGS, {
|
expect(mockSetItem).toHaveBeenCalledWith(PersistedStorageKeys.USER_SETTINGS, {
|
||||||
|
colorMode: 'dark',
|
||||||
userId: 'abc123',
|
userId: 'abc123',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -3,6 +3,7 @@ import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
|
|||||||
import { v4 as uuid } from 'uuid'
|
import { v4 as uuid } from 'uuid'
|
||||||
import localforage from 'localforage'
|
import localforage from 'localforage'
|
||||||
|
|
||||||
|
import { SettingsContext } from 'contexts/SettingsContext'
|
||||||
import { Home } from 'pages/Home/'
|
import { Home } from 'pages/Home/'
|
||||||
import { PublicRoom } from 'pages/PublicRoom/'
|
import { PublicRoom } from 'pages/PublicRoom/'
|
||||||
import { UserSettings } from 'models/settings'
|
import { UserSettings } from 'models/settings'
|
||||||
@ -22,8 +23,11 @@ function Bootstrap({
|
|||||||
getUuid = uuid,
|
getUuid = uuid,
|
||||||
}: BootstrapProps) {
|
}: BootstrapProps) {
|
||||||
const [hasLoadedSettings, setHasLoadedSettings] = useState(false)
|
const [hasLoadedSettings, setHasLoadedSettings] = useState(false)
|
||||||
const [settings, setSettings] = useState({ userId: getUuid() })
|
const [userSettings, setUserSettings] = useState<UserSettings>({
|
||||||
const { userId } = settings
|
userId: getUuid(),
|
||||||
|
colorMode: 'dark',
|
||||||
|
})
|
||||||
|
const { userId } = userSettings
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
;(async () => {
|
;(async () => {
|
||||||
@ -35,20 +39,38 @@ function Bootstrap({
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (persistedUserSettings) {
|
if (persistedUserSettings) {
|
||||||
setSettings(persistedUserSettings)
|
setUserSettings(persistedUserSettings)
|
||||||
} else {
|
} else {
|
||||||
await persistedStorage.setItem(
|
await persistedStorage.setItem(
|
||||||
PersistedStorageKeys.USER_SETTINGS,
|
PersistedStorageKeys.USER_SETTINGS,
|
||||||
settings
|
userSettings
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
setHasLoadedSettings(true)
|
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 (
|
return (
|
||||||
<Router>
|
<Router>
|
||||||
|
<SettingsContext.Provider value={settingsContextValue}>
|
||||||
<Shell userPeerId={userId}>
|
<Shell userPeerId={userId}>
|
||||||
{hasLoadedSettings ? (
|
{hasLoadedSettings ? (
|
||||||
<Routes>
|
<Routes>
|
||||||
@ -64,6 +86,7 @@ function Bootstrap({
|
|||||||
<></>
|
<></>
|
||||||
)}
|
)}
|
||||||
</Shell>
|
</Shell>
|
||||||
|
</SettingsContext.Provider>
|
||||||
</Router>
|
</Router>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import {
|
import {
|
||||||
forwardRef,
|
|
||||||
PropsWithChildren,
|
PropsWithChildren,
|
||||||
|
SyntheticEvent,
|
||||||
|
forwardRef,
|
||||||
useCallback,
|
useCallback,
|
||||||
|
useContext,
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
useState,
|
useState,
|
||||||
SyntheticEvent,
|
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import CssBaseline from '@mui/material/CssBaseline'
|
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 Brightness7Icon from '@mui/icons-material/Brightness7'
|
||||||
|
|
||||||
import { ShellContext } from 'contexts/ShellContext'
|
import { ShellContext } from 'contexts/ShellContext'
|
||||||
|
import { SettingsContext } from 'contexts/SettingsContext'
|
||||||
import { AlertOptions } from 'models/shell'
|
import { AlertOptions } from 'models/shell'
|
||||||
import { PeerNameDisplay } from 'components/PeerNameDisplay'
|
import { PeerNameDisplay } from 'components/PeerNameDisplay'
|
||||||
|
|
||||||
@ -98,6 +100,7 @@ const DrawerHeader = styled('div')(({ theme }) => ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
export const Shell = ({ children, userPeerId }: ShellProps) => {
|
export const Shell = ({ children, userPeerId }: ShellProps) => {
|
||||||
|
const settingsContext = useContext(SettingsContext)
|
||||||
const [isAlertShowing, setIsAlertShowing] = useState(false)
|
const [isAlertShowing, setIsAlertShowing] = useState(false)
|
||||||
const [isDrawerOpen, setIsDrawerOpen] = useState(false)
|
const [isDrawerOpen, setIsDrawerOpen] = useState(false)
|
||||||
const [doShowPeers, setDoShowPeers] = useState(false)
|
const [doShowPeers, setDoShowPeers] = useState(false)
|
||||||
@ -125,20 +128,21 @@ export const Shell = ({ children, userPeerId }: ShellProps) => {
|
|||||||
[numberOfPeers, setDoShowPeers, setNumberOfPeers, setTitle, showAlert]
|
[numberOfPeers, setDoShowPeers, setNumberOfPeers, setTitle, showAlert]
|
||||||
)
|
)
|
||||||
|
|
||||||
const [mode, setMode] = useState<'light' | 'dark'>('dark')
|
const colorMode = settingsContext.getUserSettings().colorMode
|
||||||
|
|
||||||
const handleColorModeToggleClick = () => {
|
const handleColorModeToggleClick = () => {
|
||||||
setMode(prevMode => (prevMode === 'light' ? 'dark' : 'light'))
|
const newMode = colorMode === 'light' ? 'dark' : 'light'
|
||||||
|
settingsContext.updateUserSettings({ colorMode: newMode })
|
||||||
}
|
}
|
||||||
|
|
||||||
const theme = useMemo(
|
const theme = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createTheme({
|
createTheme({
|
||||||
palette: {
|
palette: {
|
||||||
mode,
|
mode: colorMode,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[mode]
|
[colorMode]
|
||||||
)
|
)
|
||||||
|
|
||||||
const handleAlertClose = (
|
const handleAlertClose = (
|
||||||
|
16
src/contexts/SettingsContext.ts
Normal file
16
src/contexts/SettingsContext.ts
Normal 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',
|
||||||
|
}),
|
||||||
|
})
|
@ -1,3 +1,4 @@
|
|||||||
export interface UserSettings {
|
export interface UserSettings {
|
||||||
|
colorMode: 'dark' | 'light'
|
||||||
userId: string
|
userId: string
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user