From 7fb46bfe27126c3209a7df0323d79b99c8e017b9 Mon Sep 17 00:00:00 2001 From: Jeremy Kahn Date: Mon, 5 Sep 2022 17:35:40 -0500 Subject: [PATCH] feat: persist color theme setting --- src/Bootstrap.test.tsx | 1 + src/Bootstrap.tsx | 63 ++++++++++++++++++++++----------- src/components/Shell/Shell.tsx | 16 +++++---- src/contexts/SettingsContext.ts | 16 +++++++++ src/models/settings.ts | 1 + 5 files changed, 71 insertions(+), 26 deletions(-) create mode 100644 src/contexts/SettingsContext.ts diff --git a/src/Bootstrap.test.tsx b/src/Bootstrap.test.tsx index 19381e8..f1c5a1e 100644 --- a/src/Bootstrap.test.tsx +++ b/src/Bootstrap.test.tsx @@ -52,6 +52,7 @@ test('persists user settings if none were already persisted', async () => { }) expect(mockSetItem).toHaveBeenCalledWith(PersistedStorageKeys.USER_SETTINGS, { + colorMode: 'dark', userId: 'abc123', }) }) diff --git a/src/Bootstrap.tsx b/src/Bootstrap.tsx index 9d734b7..ce5226f 100644 --- a/src/Bootstrap.tsx +++ b/src/Bootstrap.tsx @@ -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({ + 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) => { + const newSettings = { + ...userSettings, + ...changedSettings, + } + + await persistedStorage.setItem( + PersistedStorageKeys.USER_SETTINGS, + newSettings + ) + + setUserSettings(newSettings) + }, + getUserSettings: () => ({ ...userSettings }), + } return ( - - {hasLoadedSettings ? ( - - {['/', '/index.html'].map(path => ( - } /> - ))} - } - /> - - ) : ( - <> - )} - + + + {hasLoadedSettings ? ( + + {['/', '/index.html'].map(path => ( + } /> + ))} + } + /> + + ) : ( + <> + )} + + ) } diff --git a/src/components/Shell/Shell.tsx b/src/components/Shell/Shell.tsx index f5b25d9..5cb5750 100644 --- a/src/components/Shell/Shell.tsx +++ b/src/components/Shell/Shell.tsx @@ -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 = ( diff --git a/src/contexts/SettingsContext.ts b/src/contexts/SettingsContext.ts new file mode 100644 index 0000000..1afa9c9 --- /dev/null +++ b/src/contexts/SettingsContext.ts @@ -0,0 +1,16 @@ +import { createContext } from 'react' + +import { UserSettings } from 'models/settings' + +interface SettingsContextProps { + updateUserSettings: (settings: Partial) => Promise + getUserSettings: () => UserSettings +} + +export const SettingsContext = createContext({ + updateUserSettings: () => Promise.resolve(), + getUserSettings: () => ({ + userId: '', + colorMode: 'dark', + }), +}) diff --git a/src/models/settings.ts b/src/models/settings.ts index c9572f1..f30d084 100644 --- a/src/models/settings.ts +++ b/src/models/settings.ts @@ -1,3 +1,4 @@ export interface UserSettings { + colorMode: 'dark' | 'light' userId: string }