Files
bsky-social-app/src/components/dialogs/nuxs/index.tsx
T
Eric Bailey 66af8f1fbf [APP-1782] Migrate to new analytics APIs (#9735)
* Migrate logEvent to useAnalytics

* Migrate logger.metric to useAnalytics

* Migrate tricky spot, fix types

* Migrate remaining tricky spot

* Missed one

* Remove metric() from logger

* Migrate useGate to useAnalytics

* Remove all other StatSig mentions

* Update event payload

* Update logger tests

* Mock expo method
2026-01-21 19:31:39 -06:00

193 lines
4.6 KiB
TypeScript

import {
createContext,
useCallback,
useContext,
useEffect,
useMemo,
useState,
} from 'react'
import {type AppBskyActorDefs} from '@atproto/api'
import {logger} from '#/logger'
import {STALE} from '#/state/queries'
import {Nux, useNuxs, useResetNuxs, useSaveNux} from '#/state/queries/nuxs'
import {
usePreferencesQuery,
type UsePreferencesQueryResponse,
} from '#/state/queries/preferences'
import {useProfileQuery} from '#/state/queries/profile'
import {type SessionAccount, useSession} from '#/state/session'
import {useOnboardingState} from '#/state/shell'
import {
enabled as isLiveNowBetaDialogEnabled,
LiveNowBetaDialog,
} 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 = {
activeNux: Nux | undefined
dismissActiveNux: () => void
}
const queuedNuxs: {
id: Nux
enabled?: (props: EnabledCheckProps) => boolean
}[] = [
{
id: Nux.LiveNowBetaDialog,
enabled: isLiveNowBetaDialogEnabled,
},
]
const Context = createContext<Context>({
activeNux: undefined,
dismissActiveNux: () => {},
})
Context.displayName = 'NuxDialogContext'
export function useNuxDialogContext() {
return useContext(Context)
}
export function NuxDialogs() {
const {currentAccount} = useSession()
const {data: preferences} = usePreferencesQuery()
const {data: profile} = useProfileQuery({
did: currentAccount?.did,
staleTime: STALE.INFINITY, // createdAt isn't gonna change
})
const onboardingActive = useOnboardingState().isActive
const isLoading =
onboardingActive ||
!currentAccount ||
!preferences ||
!profile ||
// Profile isn't legit ready until createdAt is a real date.
!profile.createdAt ||
profile.createdAt === '0001-01-01T00:00:00.000Z' // TODO: Fix this in AppView.
return !isLoading ? (
<Inner
currentAccount={currentAccount}
currentProfile={profile}
preferences={preferences}
/>
) : null
}
function Inner({
currentAccount,
currentProfile,
preferences,
}: {
currentAccount: SessionAccount
currentProfile: AppBskyActorDefs.ProfileViewDetailed
preferences: UsePreferencesQueryResponse
}) {
const ax = useAnalytics()
const geolocation = useGeolocation()
const {nuxs} = useNuxs()
const [snoozed, setSnoozed] = useState(() => {
return isSnoozed()
})
const [activeNux, setActiveNux] = useState<Nux | undefined>()
const {mutateAsync: saveNux} = useSaveNux()
const {mutate: resetNuxs} = useResetNuxs()
const snoozeNuxDialog = useCallback(() => {
snooze()
setSnoozed(true)
}, [setSnoozed])
const dismissActiveNux = useCallback(() => {
if (!activeNux) return
setActiveNux(undefined)
}, [activeNux, setActiveNux])
if (__DEV__ && typeof window !== 'undefined') {
// @ts-ignore
window.clearNuxDialog = (id: Nux) => {
if (!__DEV__ || !id) return
resetNuxs([id])
unsnooze()
}
}
useEffect(() => {
if (snoozed) return // comment this out to test
if (!nuxs) return
for (const {id, enabled} of queuedNuxs) {
const nux = nuxs.find(nux => nux.id === id)
// check if completed first
if (nux && nux.completed) {
continue // comment this out to test
}
// then check gate (track exposure)
if (
enabled &&
!enabled({
feature: ax.feature,
currentAccount,
currentProfile,
preferences,
geolocation,
})
) {
continue
}
logger.debug(`NUX dialogs: activating '${id}' NUX`)
// we have a winner
setActiveNux(id)
// immediately snooze for a day
snoozeNuxDialog()
// immediately update remote data (affects next reload)
saveNux({
id,
completed: true,
data: undefined,
}).catch(e => {
logger.error(`NUX dialogs: failed to upsert '${id}' NUX`, {
safeMessage: e.message,
})
})
break
}
}, [
ax.feature,
nuxs,
snoozed,
snoozeNuxDialog,
saveNux,
currentAccount,
currentProfile,
preferences,
geolocation,
])
const ctx = useMemo(() => {
return {
activeNux,
dismissActiveNux,
}
}, [activeNux, dismissActiveNux])
return (
<Context.Provider value={ctx}>
{/*For example, activeNux === Nux.NeueTypography && <NeueTypography />*/}
{activeNux === Nux.LiveNowBetaDialog && <LiveNowBetaDialog />}
</Context.Provider>
)
}