-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
TAP-6059: Added TaplyticsProvider (#13)
* Refactored SDK to be more modular * Removed TaplyticsProvider imports * Removed unused and undocumented native methods * Added _newSessionCallback native method and exported it as part of `setTaplyticsNewSessionListener` method * Changed newSyncObject to take in NSDictionary * Added getVariables and registerVaraiblesChangedListener methods and removed lodash and only added lodash.clonedeep * Add library to gitignore and prettierignore * Added extra line on ignore files * Added push method types and cleaned up the push methods * Removed old index files and added push types to index * Added TaplyticsProvider * Removed console.log and exported TaplyticsProvider from index.ts * Updated TaplyticsProvider to fetch properties on App Start for android * Export TaplyticsProvider * Added useFeatureFlag hook (#15)
- Loading branch information
1 parent
d2f04d5
commit 5c9b1d9
Showing
9 changed files
with
233 additions
and
14 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import { useEffect, useRef } from 'react' | ||
import { AppState, AppStateStatus, EventSubscription, Platform } from 'react-native' | ||
|
||
import { getRunningFeatureFlags, getRunningExperimentsAndVariations } from '../experiments' | ||
import { setTaplyticsNewSessionListener } from '../user' | ||
|
||
import { TaplyticsProviderHooksArgs } from './TaplyticsProvider.types' | ||
|
||
/** | ||
* Helper function that returns a promise that resolves in an array of running feature flags, | ||
* and experiments and variations. | ||
*/ | ||
const getProperties = async () => Promise.all([getRunningFeatureFlags(), getRunningExperimentsAndVariations()]) | ||
|
||
/** | ||
* @description This hook utilizes the `setTaplyticsNewSessionListener` listener to detect | ||
* when a new session has been initiated and updates the context state. The listener also | ||
* gets triggered when the `user_id` or `email` attribute of the user is updated through the | ||
* `setUserAttributes` method. | ||
* | ||
* On `android` the `setTaplyticsNewSessionListener` is not triggered upon app start. | ||
* The `getRunningExperimentsAndVariations` method is used instead. | ||
* | ||
* @param setStateFunctions An object of type `TaplyticsProviderHooksArgs` which contains | ||
* functions to manipulate the context state. | ||
*/ | ||
export const useAppStartAndNewSessionListener = ({ | ||
setError, | ||
setIsLoading, | ||
setRunningFeatureFlags, | ||
setExperiments, | ||
}: TaplyticsProviderHooksArgs): void => { | ||
useEffect(() => { | ||
let subscriber: EventSubscription | undefined | ||
|
||
try { | ||
setIsLoading(true) | ||
|
||
// If on Android, fetch properties on App Start | ||
if (Platform.OS === 'android') { | ||
;(async () => { | ||
const [runningFeatureFlags, experiments] = await getProperties() | ||
setRunningFeatureFlags(runningFeatureFlags) | ||
setExperiments(experiments) | ||
|
||
setIsLoading(false) | ||
})() | ||
} | ||
|
||
subscriber = setTaplyticsNewSessionListener(async () => { | ||
const [runningFeatureFlags, experiments] = await getProperties() | ||
|
||
setRunningFeatureFlags(runningFeatureFlags) | ||
setExperiments(experiments) | ||
|
||
setIsLoading(false) | ||
}) | ||
} catch (error) { | ||
setIsLoading(false) | ||
setError(error) | ||
} | ||
|
||
return () => { | ||
subscriber?.remove && subscriber.remove() | ||
} | ||
}, []) | ||
} | ||
|
||
/** | ||
* @description This hook utilizes the react-native `AppState` listener to detect | ||
* when the app goes from background to foreground and updates the context state. | ||
* | ||
* @param setStateFunctions An object of type `TaplyticsProviderHooksArgs` which contains | ||
* functions to manipulate the context state. | ||
*/ | ||
export const useAppStateListener = ({ setError, setIsLoading, setRunningFeatureFlags, setExperiments }: TaplyticsProviderHooksArgs) => { | ||
const appState = useRef<AppStateStatus>(AppState.currentState) | ||
|
||
const handleAppStateChange = async (nextAppState: AppStateStatus) => { | ||
if (appState.current === 'background' && nextAppState === 'active') { | ||
try { | ||
setIsLoading(true) | ||
|
||
const [runningFeatureFlags, experiments] = await getProperties() | ||
|
||
setRunningFeatureFlags(runningFeatureFlags) | ||
setExperiments(experiments) | ||
|
||
setIsLoading(false) | ||
} catch (error) { | ||
setIsLoading(false) | ||
setError(error) | ||
} | ||
} | ||
appState.current = nextAppState | ||
} | ||
|
||
useEffect(() => { | ||
AppState.addEventListener('change', handleAppStateChange) | ||
|
||
return () => { | ||
AppState.removeEventListener('change', handleAppStateChange) | ||
} | ||
}, []) | ||
} |
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,51 @@ | ||
import React, { FC, createContext, useState } from 'react' | ||
|
||
import { TaplyticsFeatureFlags, TaplyticsExperiments } from '../experiments' | ||
|
||
import { useAppStateListener, useAppStartAndNewSessionListener } from './TaplyticsProvider.hooks' | ||
import { ITaplyticsContext, TaplyticsProviderHooksArgs } from './TaplyticsProvider.types' | ||
|
||
export const TaplyticsContext = createContext<ITaplyticsContext>({ | ||
loading: false, | ||
error: null, | ||
runningFeatureFlags: {}, | ||
experiments: {}, | ||
}) | ||
|
||
/** | ||
* A provider component that is used to wrap an application/component. This allows you to be able to | ||
* utilize hooks provided by Taplytics. | ||
* | ||
*/ | ||
const TaplyticsProvider: FC = ({ children }) => { | ||
const [loading, setIsLoading] = useState<boolean>(false) | ||
const [error, setError] = useState<Error | null>(null) | ||
|
||
const [runningFeatureFlags, setRunningFeatureFlags] = useState<TaplyticsFeatureFlags>({}) | ||
const [experiments, setExperiments] = useState<TaplyticsExperiments>({}) | ||
|
||
const hooksArgs: TaplyticsProviderHooksArgs = { | ||
setError, | ||
setIsLoading, | ||
setRunningFeatureFlags, | ||
setExperiments, | ||
} | ||
|
||
useAppStartAndNewSessionListener(hooksArgs) | ||
useAppStateListener(hooksArgs) | ||
|
||
return ( | ||
<TaplyticsContext.Provider | ||
value={{ | ||
loading, | ||
error, | ||
runningFeatureFlags, | ||
experiments, | ||
}} | ||
> | ||
{children} | ||
</TaplyticsContext.Provider> | ||
) | ||
} | ||
|
||
export default TaplyticsProvider |
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 { TaplyticsFeatureFlags, TaplyticsExperiments } from '../experiments' | ||
|
||
export interface ITaplyticsContext { | ||
loading: boolean | ||
error: Error | null | ||
runningFeatureFlags: TaplyticsFeatureFlags | ||
experiments: TaplyticsExperiments | ||
} | ||
|
||
export type TaplyticsHookMetaData = { | ||
loading: boolean | ||
error: Error | null | ||
} | ||
|
||
export type TaplyticsProviderHooksArgs = { | ||
setIsLoading: (isLoading: boolean) => void | ||
setError: (error: Error) => void | ||
setRunningFeatureFlags: (runningFeatureFlags: TaplyticsFeatureFlags) => void | ||
setExperiments: (experiments: TaplyticsExperiments) => void | ||
} |
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,5 @@ | ||
import TaplyticsProvider, { TaplyticsContext } from './TaplyticsProvider' | ||
import { TaplyticsHookMetaData, ITaplyticsContext, TaplyticsProviderHooksArgs } from './TaplyticsProvider.types' | ||
|
||
export { TaplyticsContext, TaplyticsHookMetaData, ITaplyticsContext, TaplyticsProviderHooksArgs } | ||
export default TaplyticsProvider |
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,3 @@ | ||
import useFeatureFlag from './useFeatureFlag' | ||
|
||
export { useFeatureFlag } |
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,32 @@ | ||
import { useContext } from 'react' | ||
import { TaplyticsFeatureFlags } from '../experiments' | ||
import { TaplyticsContext, TaplyticsHookMetaData } from '../TaplyticsProvider' | ||
|
||
/** | ||
* Returns all available feature flags, and a meta data object. | ||
* | ||
*/ | ||
function useFeatureFlag(): [TaplyticsFeatureFlags, TaplyticsHookMetaData] | ||
|
||
/** | ||
* Returns a boolean indicating if the feature flag is turned on, and a meta data object. | ||
* | ||
* @param name The name of the feature flag | ||
* | ||
*/ | ||
function useFeatureFlag(name: string): [boolean, TaplyticsHookMetaData] | ||
|
||
function useFeatureFlag(name?: any) { | ||
const { runningFeatureFlags, loading, error } = useContext(TaplyticsContext) | ||
|
||
const metaData: TaplyticsHookMetaData = { loading, error } | ||
|
||
if (name === undefined) return [runningFeatureFlags, metaData] | ||
|
||
const featureFlags = Object.values(runningFeatureFlags) | ||
const isFeatureFlagActive = featureFlags.includes(name) | ||
|
||
return [!!isFeatureFlagActive, metaData] | ||
} | ||
|
||
export default useFeatureFlag |
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