Skip to content

Commit

Permalink
Merge pull request #1242 from andrew-bierman/fix/persist_theme_state
Browse files Browse the repository at this point in the history
persist theme state
  • Loading branch information
taronaleksanian authored and pinocchio-life-like committed Sep 16, 2024
1 parent b07d04a commit 8cdb8ee
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 82 deletions.
105 changes: 35 additions & 70 deletions packages/app/context/theme.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ import { createContext, useEffect, useReducer, useState } from 'react';
import { theme, darkTheme } from '../theme';
import ThirdPartyThemeProviders from './ThirdPartyThemeProviders';
import React from 'react';
import { useColorScheme } from 'react-native';

import { Platform } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useColorScheme, Platform } from 'react-native';
import { useStorageState } from 'app/hooks/storage/useStorageState';

const initialState = {
Expand All @@ -14,105 +11,73 @@ const initialState = {
currentTheme: theme,
loading: true,
};

const handlers = {
/**
* Enables dark mode by updating the state object.
*
* @param {object} state - The current state object.
* @return {object} The updated state object with dark mode enabled.
*/
ENABLE_DARK_MODE: (state) => ({
...state,
isDark: true,
isLight: false,
currentTheme: darkTheme,
}),
/**
* Enables light mode by updating the state object.
*
* @param {object} state - The current state object.
* @return {object} The updated state object with light mode enabled.
*/
ENABLE_LIGHT_MODE: (state) => ({
...state,
isDark: false,
isLight: true,
currentTheme: theme,
}),
};

const reducer = (state, action) => {
const handler = handlers[action.type];
return handler ? handler(state, action) : state;
};

const ThemeContext = createContext({
...initialState,
platform: 'JWT',
enableDarkMode: async () => {
await Promise.resolve();
},
enableLightMode: async () => {
await Promise.resolve();
},
platform: Platform.OS,
enableDarkMode: async () => {},
enableLightMode: async () => {},
});

/**
* Creates a ThemeProvider component that wraps the provided children with a context provider for managing the theme state.
*
* @param {Object} props - The properties object.
* @param {ReactNode} props.children - The children components to be wrapped.
* @return {ReactNode} - The wrapped children components.
*/
export const ThemeProvider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState);
const [[, storedIsEnabled], setStoredIsEnabled] =
useStorageState('isEnabled');
const [[, storedIsEnabled], setStoredIsEnabled] = useStorageState('isEnabled');
const [loading, setLoading] = useState(true);
const colorScheme = useColorScheme();

// Fetch theme from storage and apply it
useEffect(() => {
// const fetchTheme = async () => {
// try {
// if (storedIsEnabled !== null) {
// const isEnabled = JSON.parse(storedIsEnabled);
// dispatch({
// type: isEnabled ? 'ENABLE_DARK_MODE' : 'ENABLE_LIGHT_MODE',
// });
// } else {
// dispatch({ type: 'ENABLE_LIGHT_MODE' });
// }
// } catch (e) {
// console.error('Local storage is unavailable:', e);
// } finally {
// setLoading(false);
// }
// };
// fetchTheme();
setLoading(false);
}, [storedIsEnabled]);
const fetchTheme = async () => {
try {
if (storedIsEnabled !== null) {
const isEnabled = JSON.parse(storedIsEnabled);
dispatch({
type: isEnabled ? 'ENABLE_DARK_MODE' : 'ENABLE_LIGHT_MODE',
});
} else {
// No preference found, default to the system color scheme
if (colorScheme === 'dark') {
dispatch({ type: 'ENABLE_DARK_MODE' });
} else {
dispatch({ type: 'ENABLE_LIGHT_MODE' });
}
}
} catch (e) {
console.error('Storage retrieval failed:', e);
} finally {
setLoading(false);
}
};
fetchTheme();
}, [colorScheme, storedIsEnabled]);

useEffect(() => {
console.log(colorScheme);
if (colorScheme === 'dark') {
dispatch({ type: 'ENABLE_DARK_MODE' });
} else {
dispatch({ type: 'ENABLE_LIGHT_MODE' });
}
}, [colorScheme]);
/**
* Enable dark mode.
*
* @return {undefined} No return value.
*/
// Enable dark mode and save preference
const enableDarkMode = () => {
dispatch({ type: 'ENABLE_DARK_MODE' });
setStoredIsEnabled(JSON.stringify(true));
};
/**
* Enables light mode.
*
* @param {void} - This function does not take any parameters.
* @return {void} - This function does not return any value.
*/

// Enable light mode and save preference
const enableLightMode = () => {
dispatch({ type: 'ENABLE_LIGHT_MODE' });
setStoredIsEnabled(JSON.stringify(false));
Expand Down
25 changes: 13 additions & 12 deletions packages/app/hooks/storage/useStorageState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,40 +14,41 @@ function useAsyncState<T>(
) as UseStateHook<T>;
}

// Function to set storage items based on the platform
export async function setStorageItemAsync(key: string, value: string | null) {
if (Platform.OS === 'web') {
try {
if (value == null) {
await AsyncStorage.removeItem(key);
if (value === null) {
localStorage.removeItem(key);
} else {
await AsyncStorage.setItem(key, value);
localStorage.setItem(key, value);
}
} catch (e) {
console.error('Local storage is unavailable:', e);
console.error('Web localStorage is unavailable:', e);
}
} else {
if (value == null) {
if (value === null) {
await SecureStore.deleteItemAsync(key);
} else {
await SecureStore.setItemAsync(key, value);
}
}
}

// Custom hook to manage storage state (works for both web and native platforms)
export function useStorageState(key: string): UseStateHook<string> {
// Public
// Public state
const [state, setState] = useAsyncState<string>();

// Get
// Get storage value on mount
React.useEffect(() => {
const getToken = async () => {
if (Platform.OS === 'web') {
try {
const token = await AsyncStorage.getItem(key);
if (!token) return '';
const token = localStorage.getItem(key);
setState(token);
} catch (e) {
console.error('Local storage is unavailable:', e);
console.error('Web localStorage is unavailable:', e);
}
} else {
await SecureStore.getItemAsync(key).then((value) => {
Expand All @@ -59,11 +60,11 @@ export function useStorageState(key: string): UseStateHook<string> {
try {
getToken();
} catch (e) {
console.error('Local storage is unavailable:', e);
console.error('Storage retrieval error:', e);
}
}, [key]);

// Set
// Set storage value
const setValue = React.useCallback(
(value: string | null) => {
setStorageItemAsync(key, value).then(() => {
Expand Down

0 comments on commit 8cdb8ee

Please sign in to comment.