From d33e474f474a0bf953279e92db927296b3f29963 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 21 Jan 2026 17:29:34 -0600 Subject: [PATCH] Migrate useGate to useAnalytics --- src/App.native.tsx | 93 +++++++++---------- src/App.web.tsx | 85 ++++++++--------- src/analytics/index.tsx | 1 + src/components/PostControls/DiscoverDebug.tsx | 6 +- .../PostControls/PostMenu/PostMenuItems.tsx | 4 +- .../dialogs/nuxs/LiveNowBetaDialog.tsx | 3 +- src/components/dialogs/nuxs/index.tsx | 8 +- src/components/dialogs/nuxs/utils.ts | 4 +- src/lib/hooks/useIsBskyTeam.ts | 6 +- src/lib/statsig/gates.ts | 7 -- src/lib/statsig/statsig.tsx | 12 --- src/screens/Onboarding/StepProfile/index.tsx | 4 +- src/screens/Onboarding/index.tsx | 6 +- src/screens/Settings/Settings.tsx | 6 +- src/state/service-config.tsx | 6 +- 15 files changed, 112 insertions(+), 139 deletions(-) delete mode 100644 src/lib/statsig/gates.ts delete mode 100644 src/lib/statsig/statsig.tsx diff --git a/src/App.native.tsx b/src/App.native.tsx index fe57ba86d3..1568f7b8ae 100644 --- a/src/App.native.tsx +++ b/src/App.native.tsx @@ -17,7 +17,6 @@ import * as Sentry from '@sentry/react-native' import {KeyboardControllerProvider} from '#/lib/hooks/useEnableKeyboardController' import {Provider as HideBottomBarBorderProvider} from '#/lib/hooks/useHideBottomBarBorder' import {QueryProvider} from '#/lib/react-query' -import {Provider as StatsigProvider} from '#/lib/statsig/statsig' import {s} from '#/lib/styles' import {ThemeProvider} from '#/lib/ThemeContext' import I18nProvider from '#/locale/i18nProvider' @@ -153,53 +152,51 @@ function InnerApp() { - - - - - - {/* LabelDefsProvider MUST come before ModerationOptsProvider */} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + {/* LabelDefsProvider MUST come before ModerationOptsProvider */} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/App.web.tsx b/src/App.web.tsx index 0a632ccdbf..a0eff936f5 100644 --- a/src/App.web.tsx +++ b/src/App.web.tsx @@ -9,7 +9,6 @@ import {useLingui} from '@lingui/react' import * as Sentry from '@sentry/react-native' import {QueryProvider} from '#/lib/react-query' -import {Provider as StatsigProvider} from '#/lib/statsig/statsig' import {ThemeProvider} from '#/lib/ThemeContext' import I18nProvider from '#/locale/i18nProvider' import {logger} from '#/logger' @@ -132,49 +131,47 @@ function InnerApp() { - - - - - - {/* LabelDefsProvider MUST come before ModerationOptsProvider */} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + {/* LabelDefsProvider MUST come before ModerationOptsProvider */} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/analytics/index.tsx b/src/analytics/index.tsx index 28a8fe1ea9..3639c893ad 100644 --- a/src/analytics/index.tsx +++ b/src/analytics/index.tsx @@ -24,6 +24,7 @@ import {device} from '#/storage' export * as utils from '#/analytics/utils' export const features = {init, refresh} +export {Features} from '#/analytics/features' export {type Metrics} from '#/analytics/metrics' type LoggerType = { diff --git a/src/components/PostControls/DiscoverDebug.tsx b/src/components/PostControls/DiscoverDebug.tsx index 93d6126d99..5c18322c5e 100644 --- a/src/components/PostControls/DiscoverDebug.tsx +++ b/src/components/PostControls/DiscoverDebug.tsx @@ -3,11 +3,11 @@ import * as Clipboard from 'expo-clipboard' import {t} from '@lingui/macro' import {DISCOVER_DEBUG_DIDS} from '#/lib/constants' -import {useGate} from '#/lib/statsig/statsig' import {useSession} from '#/state/session' import {atoms as a, useTheme} from '#/alf' import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' +import {useAnalytics} from '#/analytics' import {IS_INTERNAL} from '#/env' export function DiscoverDebug({ @@ -15,12 +15,12 @@ export function DiscoverDebug({ }: { feedContext: string | undefined }) { + const ax = useAnalytics() const {currentAccount} = useSession() - const gate = useGate() const isDiscoverDebugUser = IS_INTERNAL || DISCOVER_DEBUG_DIDS[currentAccount?.did || ''] || - gate('debug_show_feedcontext') + ax.feature(ax.Features.DebugFeedContext) const theme = useTheme() return ( diff --git a/src/components/PostControls/PostMenu/PostMenuItems.tsx b/src/components/PostControls/PostMenu/PostMenuItems.tsx index 15fd3a3450..1413678d2e 100644 --- a/src/components/PostControls/PostMenu/PostMenuItems.tsx +++ b/src/components/PostControls/PostMenu/PostMenuItems.tsx @@ -26,7 +26,6 @@ import { type CommonNavigatorParams, type NavigationProp, } from '#/lib/routes/types' -import {useGate} from '#/lib/statsig/statsig' import {richTextToString} from '#/lib/strings/rich-text-helpers' import {toShareUrl} from '#/lib/strings/url-helpers' import {logger} from '#/logger' @@ -463,11 +462,10 @@ let PostMenuItems = ({ const onSignIn = () => requireSignIn(() => {}) - const gate = useGate() const isDiscoverDebugUser = IS_INTERNAL || DISCOVER_DEBUG_DIDS[currentAccount?.did || ''] || - gate('debug_show_feedcontext') + ax.feature(ax.Features.DebugFeedContext) return ( <> diff --git a/src/components/dialogs/nuxs/LiveNowBetaDialog.tsx b/src/components/dialogs/nuxs/LiveNowBetaDialog.tsx index bf9f72a5b8..e8488bf6e1 100644 --- a/src/components/dialogs/nuxs/LiveNowBetaDialog.tsx +++ b/src/components/dialogs/nuxs/LiveNowBetaDialog.tsx @@ -15,6 +15,7 @@ import { } from '#/components/dialogs/nuxs/utils' import {Beaker_Stroke2_Corner2_Rounded as BeakerIcon} from '#/components/icons/Beaker' import {Text} from '#/components/Typography' +import {Features} from '#/analytics' import {IS_E2E, IS_WEB} from '#/env' export const enabled = createIsEnabledCheck(props => { @@ -24,7 +25,7 @@ export const enabled = createIsEnabledCheck(props => { '2026-01-16T00:00:00.000Z', props.currentProfile.createdAt, ) && - !props.gate('disable_live_now_beta') + !props.feature(Features.DisableLiveNowBeta) ) }) diff --git a/src/components/dialogs/nuxs/index.tsx b/src/components/dialogs/nuxs/index.tsx index eadadeb8eb..b07164ce75 100644 --- a/src/components/dialogs/nuxs/index.tsx +++ b/src/components/dialogs/nuxs/index.tsx @@ -8,7 +8,6 @@ import { } from 'react' import {type AppBskyActorDefs} from '@atproto/api' -import {useGate} from '#/lib/statsig/statsig' import {logger} from '#/logger' import {STALE} from '#/state/queries' import {Nux, useNuxs, useResetNuxs, useSaveNux} from '#/state/queries/nuxs' @@ -25,6 +24,7 @@ import { } from '#/components/dialogs/nuxs/LiveNowBetaDialog' import {isSnoozed, snooze, unsnooze} from '#/components/dialogs/nuxs/snoozing' import {type EnabledCheckProps} from '#/components/dialogs/nuxs/utils' +import {useAnalytics} from '#/analytics' import {useGeolocation} from '#/geolocation' type Context = { @@ -88,7 +88,7 @@ function Inner({ currentProfile: AppBskyActorDefs.ProfileViewDetailed preferences: UsePreferencesQueryResponse }) { - const gate = useGate() + const ax = useAnalytics() const geolocation = useGeolocation() const {nuxs} = useNuxs() const [snoozed, setSnoozed] = useState(() => { @@ -133,7 +133,7 @@ function Inner({ if ( enabled && !enabled({ - gate, + feature: ax.feature, currentAccount, currentProfile, preferences, @@ -165,11 +165,11 @@ function Inner({ break } }, [ + ax.feature, nuxs, snoozed, snoozeNuxDialog, saveNux, - gate, currentAccount, currentProfile, preferences, diff --git a/src/components/dialogs/nuxs/utils.ts b/src/components/dialogs/nuxs/utils.ts index 68ea38ebf2..b5d2463001 100644 --- a/src/components/dialogs/nuxs/utils.ts +++ b/src/components/dialogs/nuxs/utils.ts @@ -1,12 +1,12 @@ import {type AppBskyActorDefs} from '@atproto/api' -import {type useGate} from '#/lib/statsig/statsig' import {type UsePreferencesQueryResponse} from '#/state/queries/preferences' import {type SessionAccount} from '#/state/session' +import {type AnalyticsContextType} from '#/analytics' import {type Geolocation} from '#/geolocation' export type EnabledCheckProps = { - gate: ReturnType + feature: AnalyticsContextType['feature'] currentAccount: SessionAccount currentProfile: AppBskyActorDefs.ProfileViewDetailed preferences: UsePreferencesQueryResponse diff --git a/src/lib/hooks/useIsBskyTeam.ts b/src/lib/hooks/useIsBskyTeam.ts index d653e7fd5e..15136597aa 100644 --- a/src/lib/hooks/useIsBskyTeam.ts +++ b/src/lib/hooks/useIsBskyTeam.ts @@ -1,8 +1,8 @@ import {useMemo} from 'react' -import {useGate} from '#/lib/statsig/statsig' +import {useAnalytics} from '#/analytics' export function useIsBskyTeam() { - const gate = useGate() - return useMemo(() => gate('is_bsky_team_member'), [gate]) + const ax = useAnalytics() + return useMemo(() => ax.feature(ax.Features.IsBskyTeam), [ax]) } diff --git a/src/lib/statsig/gates.ts b/src/lib/statsig/gates.ts deleted file mode 100644 index b0fe1b9377..0000000000 --- a/src/lib/statsig/gates.ts +++ /dev/null @@ -1,7 +0,0 @@ -export type Gate = - // Keep this alphabetic please. - | 'debug_show_feedcontext' - | 'is_bsky_team_member' // special, do not remove - | 'disable_onboarding_find_contacts' - | 'disable_settings_find_contacts' - | 'disable_live_now_beta' diff --git a/src/lib/statsig/statsig.tsx b/src/lib/statsig/statsig.tsx deleted file mode 100644 index cf27803b24..0000000000 --- a/src/lib/statsig/statsig.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import type React from 'react' - -import {type Gate} from './gates' - -const fn = () => false -export function useGate(): (_gateName: Gate, _options?: any) => boolean { - return fn -} - -export function Provider({children}: {children: React.ReactNode}) { - return children -} diff --git a/src/screens/Onboarding/StepProfile/index.tsx b/src/screens/Onboarding/StepProfile/index.tsx index 025cf12996..c1a72b7d60 100644 --- a/src/screens/Onboarding/StepProfile/index.tsx +++ b/src/screens/Onboarding/StepProfile/index.tsx @@ -14,7 +14,6 @@ import {compressIfNeeded} from '#/lib/media/manip' import {openCropper} from '#/lib/media/picker' import {getDataUriSize} from '#/lib/media/util' import {useRequestNotificationsPermission} from '#/lib/notifications/notifications' -import {useGate} from '#/lib/statsig/statsig' import {isCancelledError} from '#/lib/strings/errors' import {logger} from '#/logger' import { @@ -72,7 +71,6 @@ export function StepProfile() { const t = useTheme() const {gtMobile} = useBreakpoints() const {requestPhotoAccessIfNeeded} = usePhotoLibraryPermission() - const gate = useGate() const requestNotificationsPermission = useRequestNotificationsPermission() const creatorControl = Dialog.useDialogControl() @@ -91,7 +89,7 @@ export function StepProfile() { React.useEffect(() => { requestNotificationsPermission('StartOnboarding') - }, [gate, requestNotificationsPermission]) + }, [requestNotificationsPermission]) const sheetWrapper = useSheetWrapper() const openPicker = React.useCallback( diff --git a/src/screens/Onboarding/index.tsx b/src/screens/Onboarding/index.tsx index c7538d471c..befebee64c 100644 --- a/src/screens/Onboarding/index.tsx +++ b/src/screens/Onboarding/index.tsx @@ -3,7 +3,6 @@ import {View} from 'react-native' import * as bcp47Match from 'bcp-47-match' import {useEnableKeyboardControllerScreen} from '#/lib/hooks/useEnableKeyboardController' -import {useGate} from '#/lib/statsig/statsig' import {useLanguagePrefs} from '#/state/preferences' import { Layout, @@ -23,6 +22,7 @@ import {useIsFindContactsFeatureEnabledBasedOnGeolocation} from '#/components/co import {useFindContactsFlowState} from '#/components/contacts/state' import {Portal} from '#/components/Portal' import {ScreenTransition} from '#/components/ScreenTransition' +import {useAnalytics} from '#/analytics' import {ENV, IS_NATIVE} from '#/env' import {StepFindContacts} from './StepFindContacts' import {StepFindContactsIntro} from './StepFindContactsIntro' @@ -31,7 +31,7 @@ import {StepSuggestedStarterpacks} from './StepSuggestedStarterpacks' export function Onboarding() { const t = useTheme() - const gate = useGate() + const ax = useAnalytics() const {contentLanguages} = useLanguagePrefs() const probablySpeaksEnglish = useMemo(() => { @@ -48,7 +48,7 @@ export function Onboarding() { ENV !== 'e2e' && IS_NATIVE && findContactsEnabled && - !gate('disable_onboarding_find_contacts') + !ax.feature(ax.Features.DisableOnboardingFindContacts) const [state, dispatch] = useReducer( reducer, diff --git a/src/screens/Settings/Settings.tsx b/src/screens/Settings/Settings.tsx index 0b7d8aee32..e7d89a6817 100644 --- a/src/screens/Settings/Settings.tsx +++ b/src/screens/Settings/Settings.tsx @@ -15,7 +15,6 @@ import { type CommonNavigatorParams, type NavigationProp, } from '#/lib/routes/types' -import {useGate} from '#/lib/statsig/statsig' import {sanitizeDisplayName} from '#/lib/strings/display-names' import {sanitizeHandle} from '#/lib/strings/handles' import {useProfileShadow} from '#/state/cache/profile-shadow' @@ -69,12 +68,14 @@ import { shouldShowVerificationCheckButton, VerificationCheckButton, } from '#/components/verification/VerificationCheckButton' +import {useAnalytics} from '#/analytics' import {IS_INTERNAL, IS_IOS, IS_NATIVE} from '#/env' import {device, useStorage} from '#/storage' import {useActivitySubscriptionsNudged} from '#/storage/hooks/activity-subscriptions-nudged' type Props = NativeStackScreenProps export function SettingsScreen({}: Props) { + const ax = useAnalytics() const {_} = useLingui() const reducedMotion = useReducedMotion() const {logoutEveryAccount} = useSessionApi() @@ -92,7 +93,6 @@ export function SettingsScreen({}: Props) { const [showDevOptions, setShowDevOptions] = useState(false) const findContactsEnabled = useIsFindContactsFeatureEnabledBasedOnGeolocation() - const gate = useGate() return ( @@ -213,7 +213,7 @@ export function SettingsScreen({}: Props) { {IS_NATIVE && findContactsEnabled && - !gate('disable_settings_find_contacts') && ( + !ax.feature(ax.Features.DisableSettingsFindContacts) && ( diff --git a/src/state/service-config.tsx b/src/state/service-config.tsx index cea9ca114a..780cf3bba3 100644 --- a/src/state/service-config.tsx +++ b/src/state/service-config.tsx @@ -1,9 +1,9 @@ import {createContext, useContext, useMemo} from 'react' -import {useGate} from '#/lib/statsig/statsig' import {useLanguagePrefs} from '#/state/preferences/languages' import {useServiceConfigQuery} from '#/state/queries/service-config' import {useSession} from '#/state/session' +import {useAnalytics} from '#/analytics' import {IS_DEV} from '#/env' import {device} from '#/storage' @@ -107,10 +107,10 @@ export function useLiveNowConfig(): LiveNowConfig { } export function useCanGoLive() { - const gate = useGate() + const ax = useAnalytics() const {hasSession} = useSession() if (!hasSession) return false - return IS_DEV ? true : !gate('disable_live_now_beta') + return IS_DEV ? true : !ax.feature(ax.Features.DisableLiveNowBeta) } export function useCheckEmailConfirmed() {