-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
# Description Adds `useFeatureFlags` hook to easily enable and disable features in the app based on environment variables. This will enable us to continuously build and release changes without long lived feature branches. This is a very basic feature flag implementation based on an environment variable `FEATURES_ENABLED` which has been added to `.env.example`, but it allows us to turn on features locally and in a future "Canary" app build whilst having the code merged and released to production with feature turned off. Other hosted options give more flexibility but come at a cost 💵 Once merged, we can attempt a build and release to app stores which will get code in the wild along with some other improvements that have been merged since last release, without adding unfinished features. **Expo limitations** Since this uses an environment variable, which is only loaded once when the Expo cli is started (`npm run start`), changing the value will require restarting expo cli and Expo Go on simulator. In practice we shouldn't be changing this much during development, except to add a new feature flag, so this should only cause pain during initial testing. ## Type of change Please delete options that are not relevant - [] Bug fix (non-breaking change which fixes an issue) - [x] New Feature (non-breaking change which adds functionality) - [] Breaking change(fix or feature that would cause existing functionality to not work as expected) - [] This change requires a documentation update # Testing locally Update your `.env` file with suggested `FEATURES_ENABLED` from `.env.example`, restart Expo cli and Expo Go, verify `Profile` and `Events` tabs appear in bottom nav. Remove `FEATURES_ENABLED` from `.env` (or make it's value empty), restart Expo cli and Expo Go, verify `Profile` and `Events` tabs **do not** appear in bottom nav. This is the config that we will initially release to app stores. # Checklist - [] My code follows the style guidelines of this project - [] I have performed a self-review of my own code - [] I have commented my code, particularly in hard-to-understand areas - [] I have removed any unnecessary comments or console logging - [] I have made corresponding changes to the documentation (if required) - [] I have addressed accessibility, if needed - [] I have followed best practices, e.g. NativeBase approaches and theming - [] I have checked the app in dark mode, if making front-end design changes - [] My changes generate no new warnings - [] I have added tests that prove my fix is effective or that my feature works - [] New and existing unit tests pass locally with my changes - [] I have updated the version numbers in `package.json` files in the [app](DEPLOYMENT.md#app-deployment) and/or [api](DEPLOYMENT.md#api-deployment-on-aws) directories as needed
- Loading branch information
Showing
7 changed files
with
117 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './useFeatureFlags' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import React from 'react' | ||
import { renderHook } from '@testing-library/react-native' | ||
import { useFeatureFlags, FeatureFlagsProvider } from './useFeatureFlags' | ||
|
||
describe('useFeatureFlags', () => { | ||
test('uses features config or defaults to false', () => { | ||
const { result } = renderHook(() => useFeatureFlags(), { | ||
wrapper: ({ children }) => ( | ||
<FeatureFlagsProvider features={['profileScreen']}> | ||
{children} | ||
</FeatureFlagsProvider> | ||
), | ||
}) | ||
|
||
expect(result.current).toEqual({ | ||
profileScreen: true, | ||
events: false, | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import React, { createContext, useContext, useEffect, useState } from 'react' | ||
|
||
export enum FeatureFlags { | ||
'profileScreen' = 'profileScreen', | ||
'events' = 'events', | ||
} | ||
|
||
type FeatureFlagsType = { | ||
[key in keyof typeof FeatureFlags]: boolean | ||
} | ||
|
||
interface FeatureFlagsContextType { | ||
features: FeatureFlagsType | ||
} | ||
|
||
const defaultFeatures = Object.keys(FeatureFlags).reduce( | ||
(acc, key) => ({ | ||
...acc, | ||
[key]: false, | ||
}), | ||
{} as FeatureFlagsType, | ||
) | ||
|
||
export const FeatureFlagsContext = createContext<FeatureFlagsContextType>({ | ||
features: defaultFeatures, | ||
}) | ||
|
||
export const useFeatureFlags = () => { | ||
const { features } = useContext(FeatureFlagsContext) | ||
return features | ||
} | ||
|
||
export const FeatureFlagsProvider = ({ | ||
features, | ||
children, | ||
}: { | ||
features: string[] | ||
children?: React.ReactNode | ||
}) => { | ||
console.log(features) | ||
const [context, setContext] = useState<FeatureFlagsType>(defaultFeatures) | ||
|
||
useEffect(() => { | ||
setContext( | ||
Object.keys(FeatureFlags).reduce( | ||
(acc, key) => ({ | ||
...acc, | ||
[key]: features.includes(key), | ||
}), | ||
{} as FeatureFlagsType, | ||
), | ||
) | ||
}, [features]) | ||
|
||
return ( | ||
<FeatureFlagsContext.Provider value={{ features: context }}> | ||
{children} | ||
</FeatureFlagsContext.Provider> | ||
) | ||
} |