From 139b5ed2c8b2f1997244501662e14394057b2d4b Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 21 Jan 2026 17:09:09 -0600 Subject: [PATCH] Migrate tricky spot, fix types --- src/analytics/index.tsx | 4 +- .../moderation/ReportDialog/index.tsx | 13 ++--- .../verification/VerifierDialog.tsx | 10 ++-- src/screens/Settings/FindContactsSettings.tsx | 1 + src/screens/Signup/index.tsx | 17 +++++-- src/screens/Signup/state.ts | 50 ++++++++++--------- src/state/queries/handle-availability.ts | 19 ++++--- 7 files changed, 61 insertions(+), 53 deletions(-) diff --git a/src/analytics/index.tsx b/src/analytics/index.tsx index 3753e335c1..28a8fe1ea9 100644 --- a/src/analytics/index.tsx +++ b/src/analytics/index.tsx @@ -38,7 +38,7 @@ type LoggerType = { useContext: (context: Exclude) => LoggerType Context: typeof Logger.Context } -type AnalyticsContextType = { +export type AnalyticsContextType = { metadata: Metadata logger: LoggerType metric: ( @@ -49,7 +49,7 @@ type AnalyticsContextType = { feature: (feature: Features) => boolean Features: typeof Features } -type AnalyticsBaseContextType = Omit< +export type AnalyticsBaseContextType = Omit< AnalyticsContextType, 'feature' | 'Features' > diff --git a/src/components/moderation/ReportDialog/index.tsx b/src/components/moderation/ReportDialog/index.tsx index 479a765783..d975c69d47 100644 --- a/src/components/moderation/ReportDialog/index.tsx +++ b/src/components/moderation/ReportDialog/index.tsx @@ -234,15 +234,12 @@ function Inner(props: ReportDialogProps) { } }, [_, submitReport, state, dispatch, props, setPending, setSuccess]) + // TODO once React.useEffect(() => { - ax.metric( - 'reportDialog:open', - { - subjectType: props.subject.type, - }, - {statsig: false}, - ) - }, [props.subject]) + ax.metric('reportDialog:open', { + subjectType: props.subject.type, + }) + }, [ax, props.subject]) return ( { - ax.metric( - 'verification:learn-more', - { - location: 'verifierDialog', - }, - {statsig: true}, - ) + ax.metric('verification:learn-more', { + location: 'verifierDialog', + }) }}> Learn more diff --git a/src/screens/Settings/FindContactsSettings.tsx b/src/screens/Settings/FindContactsSettings.tsx index 6d7b8d9d9f..461a28ffbc 100644 --- a/src/screens/Settings/FindContactsSettings.tsx +++ b/src/screens/Settings/FindContactsSettings.tsx @@ -171,6 +171,7 @@ function SyncStatus({ info: AppBskyContactDefs.SyncStatus refetchStatus: () => Promise }) { + const ax = useAnalytics() const agent = useAgent() const queryClient = useQueryClient() const {_} = useLingui() diff --git a/src/screens/Signup/index.tsx b/src/screens/Signup/index.tsx index 35287bee5e..a796d6dd40 100644 --- a/src/screens/Signup/index.tsx +++ b/src/screens/Signup/index.tsx @@ -29,17 +29,28 @@ import {LinearGradientBackground} from '#/components/LinearGradientBackground' import {InlineLinkText} from '#/components/Link' import {ScreenTransition} from '#/components/ScreenTransition' import {Text} from '#/components/Typography' -import {IS_ANDROID} from '#/env' -import {GCP_PROJECT_ID} from '#/env' +import {useAnalytics} from '#/analytics' +import {GCP_PROJECT_ID, IS_ANDROID} from '#/env' import * as bsky from '#/types/bsky' export function Signup({onPressBack}: {onPressBack: () => void}) { + const ax = useAnalytics() const {_} = useLingui() const t = useTheme() - const [state, dispatch] = useReducer(reducer, initialState) + const [state, dispatch] = useReducer(reducer, { + ...initialState, + analytics: ax, + }) const {gtMobile} = useBreakpoints() const submit = useSubmitSignup() + useEffect(() => { + dispatch({ + type: 'setAnalytics', + value: ax, + }) + }, [ax]) + const activeStarterPack = useActiveStarterPack() const { data: starterPack, diff --git a/src/screens/Signup/state.ts b/src/screens/Signup/state.ts index 5bf0466d75..7add770548 100644 --- a/src/screens/Signup/state.ts +++ b/src/screens/Signup/state.ts @@ -12,9 +12,9 @@ import {DEFAULT_SERVICE} from '#/lib/constants' import {cleanError} from '#/lib/strings/errors' import {createFullHandle} from '#/lib/strings/handles' import {getAge} from '#/lib/strings/time' -import {logger} from '#/logger' import {useSessionApi} from '#/state/session' import {useOnboardingDispatch} from '#/state/shell' +import {type AnalyticsContextType, useAnalytics} from '#/analytics' export type ServiceDescription = ComAtprotoServerDescribeServer.OutputSchema @@ -39,6 +39,8 @@ type ErrorField = | 'date-of-birth' export type SignupState = { + analytics?: AnalyticsContextType + hasPrev: boolean activeStep: SignupStep screenTransitionDirection: 'Forward' | 'Backward' @@ -65,6 +67,7 @@ export type SignupState = { } export type SignupAction = + | {type: 'setAnalytics'; value: AnalyticsContextType} | {type: 'prev'} | {type: 'next'} | {type: 'finish'} @@ -83,6 +86,8 @@ export type SignupAction = | {type: 'incrementBackgroundCount'} export const initialState: SignupState = { + analytics: undefined, + hasPrev: false, activeStep: SignupStep.INFO, screenTransitionDirection: 'Forward', @@ -126,6 +131,10 @@ export function reducer(s: SignupState, a: SignupAction): SignupState { let next = {...s} switch (a.type) { + case 'setAnalytics': { + next.analytics = a.value + break + } case 'prev': { if (s.activeStep !== SignupStep.INFO) { next.screenTransitionDirection = 'Backward' @@ -194,16 +203,12 @@ export function reducer(s: SignupState, a: SignupAction): SignupState { next.fieldErrors[a.field] = (next.fieldErrors[a.field] || 0) + 1 // Log the field error - logger.metric( - 'signup:fieldError', - { - field: a.field, - errorCount: next.fieldErrors[a.field], - errorMessage: a.value, - activeStep: next.activeStep, - }, - {statsig: true}, - ) + s.analytics?.metric('signup:fieldError', { + field: a.field, + errorCount: next.fieldErrors[a.field], + errorMessage: a.value, + activeStep: next.activeStep, + }) } break } @@ -220,24 +225,22 @@ export function reducer(s: SignupState, a: SignupAction): SignupState { next.backgroundCount = s.backgroundCount + 1 // Log background/foreground event during signup - logger.metric( - 'signup:backgrounded', - { - activeStep: next.activeStep, - backgroundCount: next.backgroundCount, - }, - {statsig: true}, - ) + s.analytics?.metric('signup:backgrounded', { + activeStep: next.activeStep, + backgroundCount: next.backgroundCount, + }) break } } next.hasPrev = next.activeStep !== SignupStep.INFO - logger.debug('signup', next) + s.analytics?.logger.debug('signup', next) if (s.activeStep !== next.activeStep) { - logger.debug('signup: step changed', {activeStep: next.activeStep}) + s.analytics?.logger.debug('signup: step changed', { + activeStep: next.activeStep, + }) } return next @@ -252,6 +255,7 @@ SignupContext.displayName = 'SignupContext' export const useSignupContext = () => React.useContext(SignupContext) export function useSubmitSignup() { + const ax = useAnalytics() const {_} = useLingui() const {createAccount} = useSessionApi() const onboardingDispatch = useOnboardingDispatch() @@ -295,7 +299,7 @@ export function useSubmitSignup() { !state.pendingSubmit?.verificationCode ) { dispatch({type: 'setStep', value: SignupStep.CAPTCHA}) - logger.error('Signup Flow Error', { + ax.logger.error('Signup Flow Error', { errorMessage: 'Verification captcha code was not set.', registrationHandle: state.handle, }) @@ -358,7 +362,7 @@ export function useSubmitSignup() { }) dispatch({type: 'setStep', value: isHandleError ? 2 : 1}) - logger.error('Signup Flow Error', { + ax.logger.error('Signup Flow Error', { errorMessage: error, registrationHandle: state.handle, }) diff --git a/src/state/queries/handle-availability.ts b/src/state/queries/handle-availability.ts index 06fc6eebbe..e3f7a6b741 100644 --- a/src/state/queries/handle-availability.ts +++ b/src/state/queries/handle-availability.ts @@ -7,8 +7,8 @@ import { PUBLIC_BSKY_SERVICE, } from '#/lib/constants' import {createFullHandle} from '#/lib/strings/handles' -import {logger} from '#/logger' import {useDebouncedValue} from '#/components/live/utils' +import {useAnalytics} from '#/analytics' import * as bsky from '#/types/bsky' import {Agent} from '../session/agent' @@ -36,6 +36,7 @@ export function useHandleAvailabilityQuery( }, debounceDelayMs = 500, ) { + const ax = useAnalytics() const name = username.trim() const debouncedHandle = useDebouncedValue(name, debounceDelayMs) @@ -51,11 +52,16 @@ export function useHandleAvailabilityQuery( ), queryFn: async () => { const handle = createFullHandle(name, serviceDomain) - return await checkHandleAvailability(handle, serviceDid, { + const res = await checkHandleAvailability(handle, serviceDid, { email, birthDate, - typeahead: true, }) + if (res.available) { + ax.metric('signup:handleAvailable', {typeahead: true}) + } else { + ax.metric('signup:handleTaken', {typeahead: true}) + } + return res }, }), } @@ -67,11 +73,9 @@ export async function checkHandleAvailability( { email, birthDate, - typeahead, }: { email?: string birthDate?: string - typeahead?: boolean }, ) { if (serviceDid === BSKY_SERVICE_DID) { @@ -89,8 +93,6 @@ export async function checkHandleAvailability( ComAtprotoTempCheckHandleAvailability.isResultAvailable, ) ) { - logger.metric('signup:handleAvailable', {typeahead}, {statsig: true}) - return {available: true} as const } else if ( bsky.dangerousIsType( @@ -98,7 +100,6 @@ export async function checkHandleAvailability( ComAtprotoTempCheckHandleAvailability.isResultUnavailable, ) ) { - logger.metric('signup:handleTaken', {typeahead}, {statsig: true}) return { available: false, suggestions: data.result.suggestions, @@ -117,11 +118,9 @@ export async function checkHandleAvailability( }) if (res.data.did) { - logger.metric('signup:handleTaken', {typeahead}, {statsig: true}) return {available: false} as const } } catch {} - logger.metric('signup:handleAvailable', {typeahead}, {statsig: true}) return {available: true} as const } }