diff --git a/native/components/feature-flags-provider.react.js b/native/components/feature-flags-provider.react.js index 9b7394cb3..cd51c7c24 100644 --- a/native/components/feature-flags-provider.react.js +++ b/native/components/feature-flags-provider.react.js @@ -1,65 +1,97 @@ // @flow +import AsyncStorage from '@react-native-async-storage/async-storage'; import * as React from 'react'; import { Platform } from 'react-native'; import { fetchFeatureFlags } from 'lib/utils/feature-flags-utils.js'; import { useIsCurrentUserStaff } from 'native/utils/staff-utils.js'; import { codeVersion } from '../redux/persist.js'; type FeatureFlagsConfiguration = { +[feature: string]: boolean, }; type FeatureFlagsContextType = { +configuration: FeatureFlagsConfiguration, - +loaded: boolean, + +loadedFromService: boolean, }; const defaultContext = { configuration: {}, - loaded: false, + loadedFromService: false, }; const FeatureFlagsContext: React.Context = React.createContext(defaultContext); +const featureFlagsStorageKey = 'FeatureFlags'; + type Props = { +children: React.Node, }; function FeatureFlagsProvider(props: Props): React.Node { const { children } = props; const isStaff = useIsCurrentUserStaff(); const [featuresConfig, setFeaturesConfig] = React.useState(defaultContext); + + React.useEffect(() => { + (async () => { + if (featuresConfig.loadedFromService) { + return; + } + + const persistedFeaturesConfig = await AsyncStorage.getItem( + featureFlagsStorageKey, + ); + if (!persistedFeaturesConfig) { + return; + } + + setFeaturesConfig(config => + config.loadedFromService + ? config + : { + configuration: JSON.parse(persistedFeaturesConfig), + loadedFromService: false, + }, + ); + })(); + }, [featuresConfig.loadedFromService]); + React.useEffect(() => { (async () => { try { const config = await fetchFeatureFlags( Platform.OS, isStaff, codeVersion, ); const configuration = {}; for (const feature of config.enabledFeatures) { configuration[feature] = true; } setFeaturesConfig({ configuration, - loaded: true, + loadedFromService: true, }); + await AsyncStorage.setItem( + featureFlagsStorageKey, + JSON.stringify(configuration), + ); } catch (e) { console.error('Feature flag retrieval failed:', e); } })(); }, [isStaff]); return ( {children} ); } -export { FeatureFlagsContext, FeatureFlagsProvider }; +export { FeatureFlagsContext, FeatureFlagsProvider, featureFlagsStorageKey }; diff --git a/native/utils/crash-utils.js b/native/utils/crash-utils.js index 79a4e31dd..b774b0981 100644 --- a/native/utils/crash-utils.js +++ b/native/utils/crash-utils.js @@ -1,21 +1,23 @@ // @flow import AsyncStorage from '@react-native-async-storage/async-storage'; import sleep from 'lib/utils/sleep.js'; +import { featureFlagsStorageKey } from '../components/feature-flags-provider.react.js'; import { commCoreModule } from '../native-modules.js'; import { navStateAsyncStorageKey } from '../navigation/persistance.js'; import { getPersistor } from '../redux/persist.js'; async function wipeAndExit() { await Promise.all([ getPersistor().purge(), __DEV__ ? AsyncStorage.removeItem(navStateAsyncStorageKey) : null, AsyncStorage.removeItem('ANDROID_REFERRER'), + AsyncStorage.removeItem(featureFlagsStorageKey), ]); await sleep(50); commCoreModule.terminate(); } export { wipeAndExit };