[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
This commit is contained in:
+45
-48
@@ -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() {
|
||||
<AnalyticsFeaturesContext>
|
||||
<QueryProvider currentDid={currentAccount?.did}>
|
||||
<PolicyUpdateOverlayProvider>
|
||||
<StatsigProvider>
|
||||
<LiveEventsProvider>
|
||||
<AgeAssuranceV2Provider>
|
||||
<ComposerProvider>
|
||||
<MessagesProvider>
|
||||
{/* LabelDefsProvider MUST come before ModerationOptsProvider */}
|
||||
<LabelDefsProvider>
|
||||
<ModerationOptsProvider>
|
||||
<LoggedOutViewProvider>
|
||||
<SelectedFeedProvider>
|
||||
<HiddenRepliesProvider>
|
||||
<HomeBadgeProvider>
|
||||
<UnreadNotifsProvider>
|
||||
<BackgroundNotificationPreferencesProvider>
|
||||
<MutedThreadsProvider>
|
||||
<ProgressGuideProvider>
|
||||
<ServiceAccountManager>
|
||||
<EmailVerificationProvider>
|
||||
<HideBottomBarBorderProvider>
|
||||
<GestureHandlerRootView
|
||||
style={s.h100pct}>
|
||||
<GlobalGestureEventsProvider>
|
||||
<IntentDialogProvider>
|
||||
<TestCtrls />
|
||||
<Shell />
|
||||
<ToastOutlet />
|
||||
</IntentDialogProvider>
|
||||
</GlobalGestureEventsProvider>
|
||||
</GestureHandlerRootView>
|
||||
</HideBottomBarBorderProvider>
|
||||
</EmailVerificationProvider>
|
||||
</ServiceAccountManager>
|
||||
</ProgressGuideProvider>
|
||||
</MutedThreadsProvider>
|
||||
</BackgroundNotificationPreferencesProvider>
|
||||
</UnreadNotifsProvider>
|
||||
</HomeBadgeProvider>
|
||||
</HiddenRepliesProvider>
|
||||
</SelectedFeedProvider>
|
||||
</LoggedOutViewProvider>
|
||||
</ModerationOptsProvider>
|
||||
</LabelDefsProvider>
|
||||
</MessagesProvider>
|
||||
</ComposerProvider>
|
||||
</AgeAssuranceV2Provider>
|
||||
</LiveEventsProvider>
|
||||
</StatsigProvider>
|
||||
<LiveEventsProvider>
|
||||
<AgeAssuranceV2Provider>
|
||||
<ComposerProvider>
|
||||
<MessagesProvider>
|
||||
{/* LabelDefsProvider MUST come before ModerationOptsProvider */}
|
||||
<LabelDefsProvider>
|
||||
<ModerationOptsProvider>
|
||||
<LoggedOutViewProvider>
|
||||
<SelectedFeedProvider>
|
||||
<HiddenRepliesProvider>
|
||||
<HomeBadgeProvider>
|
||||
<UnreadNotifsProvider>
|
||||
<BackgroundNotificationPreferencesProvider>
|
||||
<MutedThreadsProvider>
|
||||
<ProgressGuideProvider>
|
||||
<ServiceAccountManager>
|
||||
<EmailVerificationProvider>
|
||||
<HideBottomBarBorderProvider>
|
||||
<GestureHandlerRootView
|
||||
style={s.h100pct}>
|
||||
<GlobalGestureEventsProvider>
|
||||
<IntentDialogProvider>
|
||||
<TestCtrls />
|
||||
<Shell />
|
||||
<ToastOutlet />
|
||||
</IntentDialogProvider>
|
||||
</GlobalGestureEventsProvider>
|
||||
</GestureHandlerRootView>
|
||||
</HideBottomBarBorderProvider>
|
||||
</EmailVerificationProvider>
|
||||
</ServiceAccountManager>
|
||||
</ProgressGuideProvider>
|
||||
</MutedThreadsProvider>
|
||||
</BackgroundNotificationPreferencesProvider>
|
||||
</UnreadNotifsProvider>
|
||||
</HomeBadgeProvider>
|
||||
</HiddenRepliesProvider>
|
||||
</SelectedFeedProvider>
|
||||
</LoggedOutViewProvider>
|
||||
</ModerationOptsProvider>
|
||||
</LabelDefsProvider>
|
||||
</MessagesProvider>
|
||||
</ComposerProvider>
|
||||
</AgeAssuranceV2Provider>
|
||||
</LiveEventsProvider>
|
||||
</PolicyUpdateOverlayProvider>
|
||||
</QueryProvider>
|
||||
</AnalyticsFeaturesContext>
|
||||
|
||||
+41
-44
@@ -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() {
|
||||
<AnalyticsFeaturesContext>
|
||||
<QueryProvider currentDid={currentAccount?.did}>
|
||||
<PolicyUpdateOverlayProvider>
|
||||
<StatsigProvider>
|
||||
<LiveEventsProvider>
|
||||
<AgeAssuranceV2Provider>
|
||||
<ComposerProvider>
|
||||
<MessagesProvider>
|
||||
{/* LabelDefsProvider MUST come before ModerationOptsProvider */}
|
||||
<LabelDefsProvider>
|
||||
<ModerationOptsProvider>
|
||||
<LoggedOutViewProvider>
|
||||
<SelectedFeedProvider>
|
||||
<HiddenRepliesProvider>
|
||||
<HomeBadgeProvider>
|
||||
<UnreadNotifsProvider>
|
||||
<BackgroundNotificationPreferencesProvider>
|
||||
<MutedThreadsProvider>
|
||||
<SafeAreaProvider>
|
||||
<ProgressGuideProvider>
|
||||
<ServiceConfigProvider>
|
||||
<EmailVerificationProvider>
|
||||
<HideBottomBarBorderProvider>
|
||||
<IntentDialogProvider>
|
||||
<Shell />
|
||||
<ToastOutlet />
|
||||
</IntentDialogProvider>
|
||||
</HideBottomBarBorderProvider>
|
||||
</EmailVerificationProvider>
|
||||
</ServiceConfigProvider>
|
||||
</ProgressGuideProvider>
|
||||
</SafeAreaProvider>
|
||||
</MutedThreadsProvider>
|
||||
</BackgroundNotificationPreferencesProvider>
|
||||
</UnreadNotifsProvider>
|
||||
</HomeBadgeProvider>
|
||||
</HiddenRepliesProvider>
|
||||
</SelectedFeedProvider>
|
||||
</LoggedOutViewProvider>
|
||||
</ModerationOptsProvider>
|
||||
</LabelDefsProvider>
|
||||
</MessagesProvider>
|
||||
</ComposerProvider>
|
||||
</AgeAssuranceV2Provider>
|
||||
</LiveEventsProvider>
|
||||
</StatsigProvider>
|
||||
<LiveEventsProvider>
|
||||
<AgeAssuranceV2Provider>
|
||||
<ComposerProvider>
|
||||
<MessagesProvider>
|
||||
{/* LabelDefsProvider MUST come before ModerationOptsProvider */}
|
||||
<LabelDefsProvider>
|
||||
<ModerationOptsProvider>
|
||||
<LoggedOutViewProvider>
|
||||
<SelectedFeedProvider>
|
||||
<HiddenRepliesProvider>
|
||||
<HomeBadgeProvider>
|
||||
<UnreadNotifsProvider>
|
||||
<BackgroundNotificationPreferencesProvider>
|
||||
<MutedThreadsProvider>
|
||||
<SafeAreaProvider>
|
||||
<ProgressGuideProvider>
|
||||
<ServiceConfigProvider>
|
||||
<EmailVerificationProvider>
|
||||
<HideBottomBarBorderProvider>
|
||||
<IntentDialogProvider>
|
||||
<Shell />
|
||||
<ToastOutlet />
|
||||
</IntentDialogProvider>
|
||||
</HideBottomBarBorderProvider>
|
||||
</EmailVerificationProvider>
|
||||
</ServiceConfigProvider>
|
||||
</ProgressGuideProvider>
|
||||
</SafeAreaProvider>
|
||||
</MutedThreadsProvider>
|
||||
</BackgroundNotificationPreferencesProvider>
|
||||
</UnreadNotifsProvider>
|
||||
</HomeBadgeProvider>
|
||||
</HiddenRepliesProvider>
|
||||
</SelectedFeedProvider>
|
||||
</LoggedOutViewProvider>
|
||||
</ModerationOptsProvider>
|
||||
</LabelDefsProvider>
|
||||
</MessagesProvider>
|
||||
</ComposerProvider>
|
||||
</AgeAssuranceV2Provider>
|
||||
</LiveEventsProvider>
|
||||
</PolicyUpdateOverlayProvider>
|
||||
</QueryProvider>
|
||||
</AnalyticsFeaturesContext>
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
useCreateSupportLink,
|
||||
} from '#/lib/hooks/useCreateSupportLink'
|
||||
import {dateDiff, useGetTimeAgo} from '#/lib/hooks/useTimeAgo'
|
||||
import {logger} from '#/logger'
|
||||
import {useIsBirthdateUpdateAllowed} from '#/state/birthdate'
|
||||
import {useSessionApi} from '#/state/session'
|
||||
import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
|
||||
@@ -36,8 +35,8 @@ import {
|
||||
isLegacyBirthdateBug,
|
||||
useAgeAssuranceRegionConfig,
|
||||
} from '#/ageAssurance/util'
|
||||
import {IS_WEB} from '#/env'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_NATIVE, IS_WEB} from '#/env'
|
||||
import {useDeviceGeolocationApi} from '#/geolocation'
|
||||
|
||||
const textStyles = [a.text_md, a.leading_snug]
|
||||
@@ -45,6 +44,7 @@ const textStyles = [a.text_md, a.leading_snug]
|
||||
export function NoAccessScreen() {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const {gtPhone} = useBreakpoints()
|
||||
const insets = useSafeAreaInsets()
|
||||
const birthdateControl = useDialogControl()
|
||||
@@ -63,8 +63,8 @@ export function NoAccessScreen() {
|
||||
|
||||
useEffect(() => {
|
||||
// just counting overall hits here
|
||||
logger.metric(`blockedGeoOverlay:shown`, {})
|
||||
logger.metric(`ageAssurance:noAccessScreen:shown`, {
|
||||
ax.metric(`blockedGeoOverlay:shown`, {})
|
||||
ax.metric(`ageAssurance:noAccessScreen:shown`, {
|
||||
accountCreatedAt: data?.accountCreatedAt || 'unknown',
|
||||
isAARegion,
|
||||
hasDeclaredAge,
|
||||
@@ -103,10 +103,7 @@ export function NoAccessScreen() {
|
||||
label={_(msg`Click here to update your birthdate`)}
|
||||
style={[textStyles]}
|
||||
{...createStaticClick(() => {
|
||||
logger.metric(
|
||||
'ageAssurance:noAccessScreen:openBirthdateDialog',
|
||||
{},
|
||||
)
|
||||
ax.metric('ageAssurance:noAccessScreen:openBirthdateDialog', {})
|
||||
birthdateControl.open()
|
||||
})}>
|
||||
clicking here
|
||||
@@ -272,6 +269,7 @@ export function NoAccessScreen() {
|
||||
function AccessSection() {
|
||||
const t = useTheme()
|
||||
const {_, i18n} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const control = useDialogControl()
|
||||
const appealControl = Dialog.useDialogControl()
|
||||
const locationControl = Dialog.useDialogControl()
|
||||
@@ -305,7 +303,7 @@ function AccessSection() {
|
||||
label={_(msg`Contact our moderation team`)}
|
||||
{...createStaticClick(() => {
|
||||
appealControl.open()
|
||||
logger.metric('ageAssurance:appealDialogOpen', {})
|
||||
ax.metric('ageAssurance:appealDialogOpen', {})
|
||||
})}>
|
||||
contact our moderation team
|
||||
</SimpleInlineLinkText>{' '}
|
||||
@@ -321,7 +319,7 @@ function AccessSection() {
|
||||
color={hasInitiated ? 'secondary' : 'primary'}
|
||||
onPress={() => {
|
||||
control.open()
|
||||
logger.metric('ageAssurance:initDialogOpen', {
|
||||
ax.metric('ageAssurance:initDialogOpen', {
|
||||
hasInitiatedPreviously: hasInitiated,
|
||||
})
|
||||
}}>
|
||||
|
||||
@@ -25,9 +25,8 @@ import {CircleInfo_Stroke2_Corner0_Rounded as ErrorIcon} from '#/components/icon
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {refetchAgeAssuranceServerState} from '#/ageAssurance'
|
||||
import {logger} from '#/ageAssurance'
|
||||
import {IS_WEB} from '#/env'
|
||||
import {IS_IOS} from '#/env'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_IOS, IS_WEB} from '#/env'
|
||||
|
||||
export type RedirectOverlayState = {
|
||||
result: 'success' | 'unknown'
|
||||
@@ -174,6 +173,7 @@ export function RedirectOverlay() {
|
||||
|
||||
function Inner() {
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const agent = useAgent()
|
||||
const polling = useRef(false)
|
||||
@@ -187,7 +187,7 @@ function Inner() {
|
||||
|
||||
polling.current = true
|
||||
|
||||
logger.metric('ageAssurance:redirectDialogOpen', {})
|
||||
ax.metric('ageAssurance:redirectDialogOpen', {})
|
||||
|
||||
wait(
|
||||
3e3,
|
||||
@@ -218,18 +218,18 @@ function Inner() {
|
||||
|
||||
setSuccess(true)
|
||||
|
||||
logger.metric('ageAssurance:redirectDialogSuccess', {})
|
||||
ax.metric('ageAssurance:redirectDialogSuccess', {})
|
||||
})
|
||||
.catch(() => {
|
||||
if (unmounted.current) return
|
||||
setError(true)
|
||||
logger.metric('ageAssurance:redirectDialogFail', {})
|
||||
ax.metric('ageAssurance:redirectDialogFail', {})
|
||||
})
|
||||
|
||||
return () => {
|
||||
unmounted.current = true
|
||||
}
|
||||
}, [agent])
|
||||
}, [ax, agent])
|
||||
|
||||
if (success) {
|
||||
return (
|
||||
|
||||
@@ -12,6 +12,7 @@ import {isNetworkError} from '#/lib/hooks/useCleanError'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {usePatchAgeAssuranceServerState} from '#/ageAssurance'
|
||||
import {logger} from '#/ageAssurance/logger'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {BLUESKY_PROXY_DID} from '#/env'
|
||||
import {useGeolocation} from '#/geolocation'
|
||||
|
||||
@@ -19,6 +20,7 @@ const IS_DEV_ENV = BLUESKY_PROXY_DID !== PUBLIC_APPVIEW_DID
|
||||
const APPVIEW = IS_DEV_ENV ? DEV_ENV_APPVIEW : PUBLIC_APPVIEW
|
||||
|
||||
export function useBeginAgeAssurance() {
|
||||
const ax = useAnalytics()
|
||||
const agent = useAgent()
|
||||
const geolocation = useGeolocation()
|
||||
const patchAgeAssuranceStateResponse = usePatchAgeAssuranceServerState()
|
||||
@@ -48,15 +50,11 @@ export function useBeginAgeAssurance() {
|
||||
appView.sessionManager.session.accessJwt = token
|
||||
appView.sessionManager.session.refreshJwt = ''
|
||||
|
||||
logger.metric(
|
||||
'ageAssurance:api:begin',
|
||||
{
|
||||
platform: Platform.OS,
|
||||
countryCode,
|
||||
regionCode,
|
||||
},
|
||||
{statsig: false},
|
||||
)
|
||||
ax.metric('ageAssurance:api:begin', {
|
||||
platform: Platform.OS,
|
||||
countryCode,
|
||||
regionCode,
|
||||
})
|
||||
|
||||
/*
|
||||
* 2s wait is good actually. Email sending takes a hot sec and this helps
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
} from '#/analytics/features'
|
||||
import {
|
||||
getAndMigrateDeviceId,
|
||||
getDeviceIdOrThrow,
|
||||
getDeviceId,
|
||||
getInitialSessionId,
|
||||
useSessionId,
|
||||
} from '#/analytics/identifiers'
|
||||
@@ -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 = {
|
||||
@@ -38,7 +39,7 @@ type LoggerType = {
|
||||
useContext: (context: Exclude<Logger['context'], undefined>) => LoggerType
|
||||
Context: typeof Logger.Context
|
||||
}
|
||||
type AnalyticsContextType = {
|
||||
export type AnalyticsContextType = {
|
||||
metadata: Metadata
|
||||
logger: LoggerType
|
||||
metric: <E extends keyof Metrics>(
|
||||
@@ -49,7 +50,7 @@ type AnalyticsContextType = {
|
||||
feature: (feature: Features) => boolean
|
||||
Features: typeof Features
|
||||
}
|
||||
type AnalyticsBaseContextType = Omit<
|
||||
export type AnalyticsBaseContextType = Omit<
|
||||
AnalyticsContextType,
|
||||
'feature' | 'Features'
|
||||
>
|
||||
@@ -75,11 +76,14 @@ function createLogger(
|
||||
const Context = createContext<AnalyticsBaseContextType>({
|
||||
logger: createLogger(Logger.Context.Default, {}),
|
||||
metric: (event, payload, metadata) => {
|
||||
if (metadata && '__meta' in metadata) {
|
||||
delete metadata.__meta
|
||||
}
|
||||
metrics.track(event, payload, metadata)
|
||||
},
|
||||
metadata: {
|
||||
base: {
|
||||
deviceId: getDeviceIdOrThrow() ?? 'unknown',
|
||||
deviceId: getDeviceId() ?? 'unknown',
|
||||
sessionId: getInitialSessionId(),
|
||||
platform: Platform.OS,
|
||||
appVersion: env.APP_VERSION,
|
||||
@@ -114,8 +118,7 @@ export function AnalyticsContext({
|
||||
metadata?: MergeableMetadata
|
||||
}) {
|
||||
if (metadata) {
|
||||
// @ts-ignore
|
||||
if (metadata.__meta !== true) {
|
||||
if (!('__meta' in metadata)) {
|
||||
throw new Error(
|
||||
'Use the useMeta() helper when passing metadata to AnalyticsContext',
|
||||
)
|
||||
|
||||
@@ -74,7 +74,7 @@ export class MetricsClient<M extends Record<string, any>> {
|
||||
})
|
||||
|
||||
try {
|
||||
const body = JSON.stringify(events)
|
||||
const body = JSON.stringify({events})
|
||||
if (env.IS_WEB && 'navigator' in globalThis && navigator.sendBeacon) {
|
||||
navigator.sendBeacon(
|
||||
TRACKING_ENDPOINT,
|
||||
|
||||
@@ -148,6 +148,7 @@ export type Events = {
|
||||
feedUrl: string
|
||||
feedType: string
|
||||
index: number
|
||||
reason?: string
|
||||
}
|
||||
'feed:endReached': {
|
||||
feedUrl: string
|
||||
|
||||
@@ -6,7 +6,6 @@ import {useLingui} from '@lingui/react'
|
||||
import type React from 'react'
|
||||
|
||||
import {useCleanError} from '#/lib/hooks/useCleanError'
|
||||
import {logger} from '#/logger'
|
||||
import {type Shadow} from '#/state/cache/post-shadow'
|
||||
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
||||
import {useBookmarkMutation} from '#/state/queries/bookmarks/useBookmarkMutation'
|
||||
@@ -15,6 +14,7 @@ import {useTheme} from '#/alf'
|
||||
import {Bookmark, BookmarkFilled} from '#/components/icons/Bookmark'
|
||||
import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash'
|
||||
import * as toast from '#/components/Toast'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {PostControlButton, PostControlButtonIcon} from './PostControlButton'
|
||||
|
||||
export const BookmarkButton = memo(function BookmarkButton({
|
||||
@@ -29,6 +29,7 @@ export const BookmarkButton = memo(function BookmarkButton({
|
||||
hitSlop?: Insets
|
||||
}): React.ReactNode {
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const {mutateAsync: bookmark} = useBookmarkMutation()
|
||||
const cleanError = useCleanError()
|
||||
@@ -52,7 +53,7 @@ export const BookmarkButton = memo(function BookmarkButton({
|
||||
post,
|
||||
})
|
||||
|
||||
logger.metric('post:bookmark', {
|
||||
ax.metric('post:bookmark', {
|
||||
uri: post.uri,
|
||||
authorDid: post.author.did,
|
||||
logContext,
|
||||
@@ -92,7 +93,7 @@ export const BookmarkButton = memo(function BookmarkButton({
|
||||
uri: post.uri,
|
||||
})
|
||||
|
||||
logger.metric('post:unbookmark', {
|
||||
ax.metric('post:unbookmark', {
|
||||
uri: post.uri,
|
||||
authorDid: post.author.did,
|
||||
logContext,
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -26,15 +26,17 @@ import {
|
||||
type CommonNavigatorParams,
|
||||
type NavigationProp,
|
||||
} from '#/lib/routes/types'
|
||||
import {logEvent, useGate} from '#/lib/statsig/statsig'
|
||||
import {richTextToString} from '#/lib/strings/rich-text-helpers'
|
||||
import {toShareUrl} from '#/lib/strings/url-helpers'
|
||||
import {logger} from '#/logger'
|
||||
import {type Shadow} from '#/state/cache/post-shadow'
|
||||
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
||||
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
||||
import {useLanguagePrefs} from '#/state/preferences'
|
||||
import {useHiddenPosts, useHiddenPostsApi} from '#/state/preferences'
|
||||
import {
|
||||
useHiddenPosts,
|
||||
useHiddenPostsApi,
|
||||
useLanguagePrefs,
|
||||
} from '#/state/preferences'
|
||||
import {usePinnedPostMutation} from '#/state/queries/pinned-post'
|
||||
import {
|
||||
usePostDeleteMutation,
|
||||
@@ -71,13 +73,17 @@ import {
|
||||
import {Eye_Stroke2_Corner0_Rounded as Eye} from '#/components/icons/Eye'
|
||||
import {EyeSlash_Stroke2_Corner0_Rounded as EyeSlash} from '#/components/icons/EyeSlash'
|
||||
import {Filter_Stroke2_Corner0_Rounded as Filter} from '#/components/icons/Filter'
|
||||
import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute'
|
||||
import {Mute_Stroke2_Corner0_Rounded as Mute} from '#/components/icons/Mute'
|
||||
import {
|
||||
Mute_Stroke2_Corner0_Rounded as Mute,
|
||||
Mute_Stroke2_Corner0_Rounded as MuteIcon,
|
||||
} from '#/components/icons/Mute'
|
||||
import {PersonX_Stroke2_Corner0_Rounded as PersonX} from '#/components/icons/Person'
|
||||
import {Pin_Stroke2_Corner0_Rounded as PinIcon} from '#/components/icons/Pin'
|
||||
import {SettingsGear2_Stroke2_Corner0_Rounded as Gear} from '#/components/icons/SettingsGear2'
|
||||
import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker'
|
||||
import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute} from '#/components/icons/Speaker'
|
||||
import {
|
||||
SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute,
|
||||
SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon,
|
||||
} from '#/components/icons/Speaker'
|
||||
import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
|
||||
import {Warning_Stroke2_Corner0_Rounded as Warning} from '#/components/icons/Warning'
|
||||
import {Loader} from '#/components/Loader'
|
||||
@@ -87,6 +93,7 @@ import {
|
||||
useReportDialogControl,
|
||||
} from '#/components/moderation/ReportDialog'
|
||||
import * as Prompt from '#/components/Prompt'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_INTERNAL} from '#/env'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
@@ -116,6 +123,7 @@ let PostMenuItems = ({
|
||||
}): React.ReactNode => {
|
||||
const {hasSession, currentAccount} = useSession()
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const langPrefs = useLanguagePrefs()
|
||||
const {mutateAsync: deletePostMutate} = usePostDeleteMutation()
|
||||
const {mutateAsync: pinPostMutate, isPending: isPinPending} =
|
||||
@@ -212,7 +220,7 @@ let PostMenuItems = ({
|
||||
try {
|
||||
if (isThreadMuted) {
|
||||
unmuteThread()
|
||||
logger.metric('post:unmute', {
|
||||
ax.metric('post:unmute', {
|
||||
uri: postUri,
|
||||
authorDid: postAuthor.did,
|
||||
logContext,
|
||||
@@ -221,7 +229,7 @@ let PostMenuItems = ({
|
||||
Toast.show(_(msg`You will now receive notifications for this thread`))
|
||||
} else {
|
||||
muteThread()
|
||||
logger.metric('post:mute', {
|
||||
ax.metric('post:mute', {
|
||||
uri: postUri,
|
||||
authorDid: postAuthor.did,
|
||||
logContext,
|
||||
@@ -258,21 +266,17 @@ let PostMenuItems = ({
|
||||
AppBskyFeedPost.isRecord,
|
||||
)
|
||||
) {
|
||||
logger.metric(
|
||||
'translate',
|
||||
{
|
||||
sourceLanguages: post.record.langs ?? [],
|
||||
targetLanguage: langPrefs.primaryLanguage,
|
||||
textLength: post.record.text.length,
|
||||
},
|
||||
{statsig: false},
|
||||
)
|
||||
ax.metric('translate', {
|
||||
sourceLanguages: post.record.langs ?? [],
|
||||
targetLanguage: langPrefs.primaryLanguage,
|
||||
textLength: post.record.text.length,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const onHidePost = () => {
|
||||
hidePost({uri: postUri})
|
||||
logEvent('thread:click:hideReplyForMe', {})
|
||||
ax.metric('thread:click:hideReplyForMe', {})
|
||||
}
|
||||
|
||||
const hideInPWI = !!postAuthor.labels?.find(
|
||||
@@ -286,7 +290,7 @@ let PostMenuItems = ({
|
||||
feedContext: postFeedContext,
|
||||
reqId: postReqId,
|
||||
})
|
||||
logger.metric('post:showMore', {
|
||||
ax.metric('post:showMore', {
|
||||
uri: postUri,
|
||||
authorDid: postAuthor.did,
|
||||
logContext,
|
||||
@@ -304,7 +308,7 @@ let PostMenuItems = ({
|
||||
feedContext: postFeedContext,
|
||||
reqId: postReqId,
|
||||
})
|
||||
logger.metric('post:showLess', {
|
||||
ax.metric('post:showLess', {
|
||||
uri: postUri,
|
||||
authorDid: postAuthor.did,
|
||||
logContext,
|
||||
@@ -368,7 +372,7 @@ let PostMenuItems = ({
|
||||
|
||||
// Log metric only when hiding (not when showing)
|
||||
if (isHide) {
|
||||
logEvent('thread:click:hideReplyForEveryone', {})
|
||||
ax.metric('thread:click:hideReplyForEveryone', {})
|
||||
}
|
||||
|
||||
Toast.show(
|
||||
@@ -405,7 +409,7 @@ let PostMenuItems = ({
|
||||
}
|
||||
|
||||
const onPressPin = () => {
|
||||
logEvent(isPinned ? 'post:unpin' : 'post:pin', {})
|
||||
ax.metric(isPinned ? 'post:unpin' : 'post:pin', {})
|
||||
pinPostMutate({
|
||||
postUri,
|
||||
postCid,
|
||||
@@ -458,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 (
|
||||
<>
|
||||
|
||||
@@ -8,7 +8,6 @@ import {isBlockedOrBlocking, isMuted} from '#/lib/moderation/blocked-and-muted'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {logger} from '#/logger'
|
||||
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {useListConvosQuery} from '#/state/queries/messages/list-conversations'
|
||||
@@ -20,9 +19,11 @@ import {useDialogContext} from '#/components/Dialog'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useSimpleVerificationState} from '#/components/verification'
|
||||
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
export function RecentChats({postUri}: {postUri: string}) {
|
||||
const ax = useAnalytics()
|
||||
const control = useDialogContext()
|
||||
const {currentAccount} = useSession()
|
||||
const {data} = useListConvosQuery({status: 'accepted'})
|
||||
@@ -32,7 +33,7 @@ export function RecentChats({postUri}: {postUri: string}) {
|
||||
|
||||
const onSelectChat = (convoId: string) => {
|
||||
control.close(() => {
|
||||
logger.metric('share:press:recentDm', {}, {statsig: true})
|
||||
ax.metric('share:press:recentDm', {})
|
||||
navigation.navigate('MessagesConversation', {
|
||||
conversation: convoId,
|
||||
embed: postUri,
|
||||
|
||||
@@ -9,7 +9,6 @@ import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {shareText, shareUrl} from '#/lib/sharing'
|
||||
import {toShareUrl} from '#/lib/strings/url-helpers'
|
||||
import {logger} from '#/logger'
|
||||
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
||||
import {useSession} from '#/state/session'
|
||||
import * as Toast from '#/view/com/util/Toast'
|
||||
@@ -23,6 +22,7 @@ import {Clipboard_Stroke2_Corner2_Rounded as ClipboardIcon} from '#/components/i
|
||||
import {PaperPlane_Stroke2_Corner0_Rounded as PaperPlaneIcon} from '#/components/icons/PaperPlane'
|
||||
import * as Menu from '#/components/Menu'
|
||||
import {useAgeAssurance} from '#/ageAssurance'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_IOS} from '#/env'
|
||||
import {useDevMode} from '#/storage/hooks/dev-mode'
|
||||
import {RecentChats} from './RecentChats'
|
||||
@@ -32,6 +32,7 @@ let ShareMenuItems = ({
|
||||
post,
|
||||
onShare: onShareProp,
|
||||
}: ShareMenuItemsProps): React.ReactNode => {
|
||||
const ax = useAnalytics()
|
||||
const {hasSession} = useSession()
|
||||
const {_} = useLingui()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
@@ -54,14 +55,14 @@ let ShareMenuItems = ({
|
||||
}, [postAuthor])
|
||||
|
||||
const onSharePost = () => {
|
||||
logger.metric('share:press:nativeShare', {}, {statsig: true})
|
||||
ax.metric('share:press:nativeShare', {})
|
||||
const url = toShareUrl(href)
|
||||
shareUrl(url)
|
||||
onShareProp()
|
||||
}
|
||||
|
||||
const onCopyLink = async () => {
|
||||
logger.metric('share:press:copyLink', {}, {statsig: true})
|
||||
ax.metric('share:press:copyLink', {})
|
||||
const url = toShareUrl(href)
|
||||
if (IS_IOS) {
|
||||
// iOS only
|
||||
@@ -100,7 +101,7 @@ let ShareMenuItems = ({
|
||||
testID="postDropdownSendViaDMBtn"
|
||||
label={_(msg`Send via direct message`)}
|
||||
onPress={() => {
|
||||
logger.metric('share:press:openDmSearch', {}, {statsig: true})
|
||||
ax.metric('share:press:openDmSearch', {})
|
||||
sendViaChatControl.open()
|
||||
}}>
|
||||
<Menu.ItemText>
|
||||
|
||||
@@ -8,7 +8,6 @@ import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {shareText, shareUrl} from '#/lib/sharing'
|
||||
import {toShareUrl} from '#/lib/strings/url-helpers'
|
||||
import {logger} from '#/logger'
|
||||
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useBreakpoints} from '#/alf'
|
||||
@@ -21,6 +20,7 @@ import {CodeBrackets_Stroke2_Corner0_Rounded as CodeBracketsIcon} from '#/compon
|
||||
import {PaperPlane_Stroke2_Corner0_Rounded as Send} from '#/components/icons/PaperPlane'
|
||||
import * as Menu from '#/components/Menu'
|
||||
import {useAgeAssurance} from '#/ageAssurance'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_WEB} from '#/env'
|
||||
import {useDevMode} from '#/storage/hooks/dev-mode'
|
||||
import {type ShareMenuItemsProps} from './ShareMenuItems.types'
|
||||
@@ -31,6 +31,7 @@ let ShareMenuItems = ({
|
||||
timestamp,
|
||||
onShare: onShareProp,
|
||||
}: ShareMenuItemsProps): React.ReactNode => {
|
||||
const ax = useAnalytics()
|
||||
const {hasSession} = useSession()
|
||||
const {gtMobile} = useBreakpoints()
|
||||
const {_} = useLingui()
|
||||
@@ -56,14 +57,14 @@ let ShareMenuItems = ({
|
||||
}, [postAuthor])
|
||||
|
||||
const onCopyLink = () => {
|
||||
logger.metric('share:press:copyLink', {}, {statsig: true})
|
||||
ax.metric('share:press:copyLink', {})
|
||||
const url = toShareUrl(href)
|
||||
shareUrl(url)
|
||||
onShareProp()
|
||||
}
|
||||
|
||||
const onSelectChatToShareTo = (conversation: string) => {
|
||||
logger.metric('share:press:dmSelected', {}, {statsig: true})
|
||||
ax.metric('share:press:dmSelected', {})
|
||||
navigation.navigate('MessagesConversation', {
|
||||
conversation,
|
||||
embed: postUri,
|
||||
@@ -102,7 +103,7 @@ let ShareMenuItems = ({
|
||||
testID="postDropdownSendViaDMBtn"
|
||||
label={_(msg`Send via direct message`)}
|
||||
onPress={() => {
|
||||
logger.metric('share:press:openDmSearch', {}, {statsig: true})
|
||||
ax.metric('share:press:openDmSearch', {})
|
||||
sendViaChatControl.open()
|
||||
}}>
|
||||
<Menu.ItemText>
|
||||
@@ -117,7 +118,7 @@ let ShareMenuItems = ({
|
||||
testID="postDropdownEmbedBtn"
|
||||
label={_(msg`Embed post`)}
|
||||
onPress={() => {
|
||||
logger.metric('share:press:embed', {}, {statsig: true})
|
||||
ax.metric('share:press:embed', {})
|
||||
embedPostControl.open()
|
||||
}}>
|
||||
<Menu.ItemText>{_(msg`Embed post`)}</Menu.ItemText>
|
||||
|
||||
@@ -13,7 +13,6 @@ import {useLingui} from '@lingui/react'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {shareUrl} from '#/lib/sharing'
|
||||
import {toShareUrl} from '#/lib/strings/url-helpers'
|
||||
import {logger} from '#/logger'
|
||||
import {type Shadow} from '#/state/cache/post-shadow'
|
||||
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
||||
import {EventStopper} from '#/view/com/util/EventStopper'
|
||||
@@ -21,6 +20,7 @@ import {native} from '#/alf'
|
||||
import {ArrowShareRight_Stroke2_Corner2_Rounded as ArrowShareRightIcon} from '#/components/icons/ArrowShareRight'
|
||||
import {useMenuControl} from '#/components/Menu'
|
||||
import * as Menu from '#/components/Menu'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {PostControlButton, PostControlButtonIcon} from '../PostControlButton'
|
||||
import {ShareMenuItems} from './ShareMenuItems'
|
||||
|
||||
@@ -47,6 +47,7 @@ let ShareMenuButton = ({
|
||||
hitSlop?: Insets
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
}): React.ReactNode => {
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const {feedDescriptor} = useFeedFeedbackContext()
|
||||
|
||||
@@ -61,20 +62,17 @@ let ShareMenuButton = ({
|
||||
// menuControl.open() fires but RN doesn't expose flushSync.
|
||||
setTimeout(menuControl.open)
|
||||
|
||||
logger.metric(
|
||||
'post:share',
|
||||
{
|
||||
uri: post.uri,
|
||||
authorDid: post.author.did,
|
||||
logContext,
|
||||
feedDescriptor,
|
||||
postContext: big ? 'thread' : 'feed',
|
||||
},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('post:share', {
|
||||
uri: post.uri,
|
||||
authorDid: post.author.did,
|
||||
logContext,
|
||||
feedDescriptor,
|
||||
postContext: big ? 'thread' : 'feed',
|
||||
})
|
||||
},
|
||||
}),
|
||||
[
|
||||
ax,
|
||||
menuControl,
|
||||
setHasBeenOpen,
|
||||
big,
|
||||
@@ -86,7 +84,7 @@ let ShareMenuButton = ({
|
||||
)
|
||||
|
||||
const onNativeLongPress = () => {
|
||||
logger.metric('share:press:nativeShare', {}, {statsig: true})
|
||||
ax.metric('share:press:nativeShare', {})
|
||||
const urip = new AtUri(post.uri)
|
||||
const href = makeProfileLink(post.author, 'post', urip.rkey)
|
||||
const url = toShareUrl(href)
|
||||
|
||||
@@ -13,7 +13,6 @@ import {CountWheel} from '#/lib/custom-animations/CountWheel'
|
||||
import {AnimatedLikeIcon} from '#/lib/custom-animations/LikeIcon'
|
||||
import {useHaptics} from '#/lib/haptics'
|
||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||
import {logger} from '#/logger'
|
||||
import {type Shadow} from '#/state/cache/types'
|
||||
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
||||
import {
|
||||
@@ -30,6 +29,7 @@ import {atoms as a, useBreakpoints} from '#/alf'
|
||||
import {Reply as Bubble} from '#/components/icons/Reply'
|
||||
import {useFormatPostStatCount} from '#/components/PostControls/util'
|
||||
import * as Skele from '#/components/Skeleton'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {BookmarkButton} from './BookmarkButton'
|
||||
import {
|
||||
PostControlButton,
|
||||
@@ -71,6 +71,7 @@ let PostControls = ({
|
||||
viaRepost?: {uri: string; cid: string}
|
||||
variant?: 'compact' | 'normal' | 'large'
|
||||
}): React.ReactNode => {
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const {openComposer} = useOpenComposer()
|
||||
const {feedDescriptor} = useFeedFeedbackContext()
|
||||
@@ -175,7 +176,7 @@ let PostControls = ({
|
||||
feedContext,
|
||||
reqId,
|
||||
})
|
||||
logger.metric('post:clickQuotePost', {
|
||||
ax.metric('post:clickQuotePost', {
|
||||
uri: post.uri,
|
||||
authorDid: post.author.did,
|
||||
logContext,
|
||||
@@ -226,7 +227,7 @@ let PostControls = ({
|
||||
!replyDisabled
|
||||
? () =>
|
||||
requireAuth(() => {
|
||||
logger.metric('post:clickReply', {
|
||||
ax.metric('post:clickReply', {
|
||||
uri: post.uri,
|
||||
authorDid: post.author.did,
|
||||
logContext,
|
||||
|
||||
@@ -10,8 +10,6 @@ import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {popularInterests, useInterestsDisplayNames} from '#/lib/interests'
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {logger} from '#/logger'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {useActorSearch} from '#/state/queries/actor-search'
|
||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||
@@ -36,6 +34,7 @@ import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
||||
import {boostInterests, InterestTabs} from '#/components/InterestTabs'
|
||||
import * as ProfileCard from '#/components/ProfileCard'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_WEB} from '#/env'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
import {ProgressGuideTask} from './Task'
|
||||
@@ -67,6 +66,7 @@ export function FollowDialog({
|
||||
guide: Follow10ProgressGuide
|
||||
showArrow?: boolean
|
||||
}) {
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const control = Dialog.useDialogControl()
|
||||
const {gtPhone} = useBreakpoints()
|
||||
@@ -78,7 +78,7 @@ export function FollowDialog({
|
||||
label={_(msg`Find people to follow`)}
|
||||
onPress={() => {
|
||||
control.open()
|
||||
logEvent('progressGuide:followDialog:open', {})
|
||||
ax.metric('progressGuide:followDialog:open', {})
|
||||
}}
|
||||
size={gtPhone ? 'small' : 'large'}
|
||||
color="primary">
|
||||
@@ -118,6 +118,7 @@ let lastSearchText = ''
|
||||
|
||||
function DialogInner({guide}: {guide?: Follow10ProgressGuide}) {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const interestsDisplayNames = useInterestsDisplayNames()
|
||||
const {data: preferences} = usePreferencesQuery()
|
||||
const personalizedInterests = preferences?.interests?.tags
|
||||
@@ -271,17 +272,13 @@ function DialogInner({guide}: {guide?: Follow10ProgressGuide}) {
|
||||
const position = itemsRef.current.findIndex(
|
||||
i => i.type === 'profile' && i.profile.did === item.profile.did,
|
||||
)
|
||||
logger.metric(
|
||||
'suggestedUser:seen',
|
||||
{
|
||||
logContext: 'ProgressGuide',
|
||||
recId: undefined,
|
||||
position: position !== -1 ? position : 0,
|
||||
suggestedDid: item.profile.did,
|
||||
category: selectedInterestRef.current,
|
||||
},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('suggestedUser:seen', {
|
||||
logContext: 'ProgressGuide',
|
||||
recId: undefined,
|
||||
position: position !== -1 ? position : 0,
|
||||
suggestedDid: item.profile.did,
|
||||
category: selectedInterestRef.current,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import {FloppyDisk_Stroke2_Corner0_Rounded as FloppyDiskIcon} from '#/components
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {QrCode} from '#/components/StarterPack/QrCode'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_NATIVE, IS_WEB} from '#/env'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
@@ -32,6 +33,7 @@ export function QrCodeDialog({
|
||||
control: DialogControlProps
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const {gtMobile} = useBreakpoints()
|
||||
const [isSaveProcessing, setIsSaveProcessing] = useState(false)
|
||||
const [isCopyProcessing, setIsCopyProcessing] = useState(false)
|
||||
@@ -104,7 +106,7 @@ export function QrCodeDialog({
|
||||
link.click()
|
||||
}
|
||||
|
||||
logger.metric('starterPack:share', {
|
||||
ax.metric('starterPack:share', {
|
||||
starterPack: starterPack.uri,
|
||||
shareType: 'qrcode',
|
||||
qrShareType: 'save',
|
||||
@@ -129,7 +131,7 @@ export function QrCodeDialog({
|
||||
navigator.clipboard.write([item])
|
||||
})
|
||||
|
||||
logger.metric('starterPack:share', {
|
||||
ax.metric('starterPack:share', {
|
||||
starterPack: starterPack.uri,
|
||||
shareType: 'qrcode',
|
||||
qrShareType: 'copy',
|
||||
@@ -145,7 +147,7 @@ export function QrCodeDialog({
|
||||
control.close(() => {
|
||||
Sharing.shareAsync(uri, {mimeType: 'image/png', UTI: 'image/png'}).then(
|
||||
() => {
|
||||
logger.metric('starterPack:share', {
|
||||
ax.metric('starterPack:share', {
|
||||
starterPack: starterPack.uri,
|
||||
shareType: 'qrcode',
|
||||
qrShareType: 'share',
|
||||
|
||||
@@ -7,7 +7,6 @@ import {useLingui} from '@lingui/react'
|
||||
import {useSaveImageToMediaLibrary} from '#/lib/media/save-image'
|
||||
import {shareUrl} from '#/lib/sharing'
|
||||
import {getStarterPackOgCard} from '#/lib/strings/starter-pack'
|
||||
import {logger} from '#/logger'
|
||||
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||
import {type DialogControlProps} from '#/components/Dialog'
|
||||
@@ -17,6 +16,7 @@ import {Download_Stroke2_Corner0_Rounded as DownloadIcon} from '#/components/ico
|
||||
import {QrCode_Stroke2_Corner0_Rounded as QrCodeIcon} from '#/components/icons/QrCode'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_NATIVE, IS_WEB} from '#/env'
|
||||
|
||||
interface Props {
|
||||
@@ -46,6 +46,7 @@ function ShareDialogInner({
|
||||
control,
|
||||
}: Props) {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const t = useTheme()
|
||||
const {gtMobile} = useBreakpoints()
|
||||
|
||||
@@ -54,7 +55,7 @@ function ShareDialogInner({
|
||||
const onShareLink = async () => {
|
||||
if (!link) return
|
||||
shareUrl(link)
|
||||
logger.metric('starterPack:share', {
|
||||
ax.metric('starterPack:share', {
|
||||
starterPack: starterPack.uri,
|
||||
shareType: 'link',
|
||||
})
|
||||
|
||||
@@ -13,7 +13,6 @@ import {useLingui} from '@lingui/react'
|
||||
import {DISCOVER_FEED_URI, STARTER_PACK_MAX_SIZE} from '#/lib/constants'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {logger} from '#/logger'
|
||||
import {useSession} from '#/state/session'
|
||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||
import {
|
||||
@@ -25,6 +24,7 @@ import {Button, ButtonText} from '#/components/Button'
|
||||
import * as Toggle from '#/components/forms/Toggle'
|
||||
import {Checkbox} from '#/components/forms/Toggle'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
function WizardListCard({
|
||||
@@ -130,6 +130,7 @@ export function WizardProfileCard({
|
||||
profile: bsky.profile.AnyProfileView
|
||||
moderationOpts: ModerationOpts
|
||||
}) {
|
||||
const ax = useAnalytics()
|
||||
const {currentAccount} = useSession()
|
||||
|
||||
// Determine the "main" profile for this starter pack - either targetDid or current account
|
||||
@@ -151,10 +152,10 @@ export function WizardProfileCard({
|
||||
if (profile.did === targetProfileDid) return
|
||||
|
||||
if (!included) {
|
||||
logger.metric('starterPack:addUser', {})
|
||||
ax.metric('starterPack:addUser', {})
|
||||
dispatch({type: 'AddProfile', profile})
|
||||
} else {
|
||||
logger.metric('starterPack:removeUser', {})
|
||||
ax.metric('starterPack:removeUser', {})
|
||||
dispatch({type: 'RemoveProfile', profileDid: profile.did})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,13 @@ import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {FocusGuards, FocusScope} from 'radix-ui/internal'
|
||||
|
||||
import {logger} from '#/logger'
|
||||
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
||||
import {Logo} from '#/view/icons/Logo'
|
||||
import {atoms as a, flatten, useBreakpoints, web} from '#/alf'
|
||||
import {Button, ButtonText} from '#/components/Button'
|
||||
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
const welcomeModalBg = require('../../assets/images/welcome-modal-bg.jpg')
|
||||
|
||||
@@ -25,6 +25,7 @@ interface WelcomeModalProps {
|
||||
|
||||
export function WelcomeModal({control}: WelcomeModalProps) {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const {requestSwitchToAccount} = useLoggedOutViewControls()
|
||||
const {gtMobile} = useBreakpoints()
|
||||
const [isExiting, setIsExiting] = useState(false)
|
||||
@@ -40,23 +41,24 @@ export function WelcomeModal({control}: WelcomeModalProps) {
|
||||
|
||||
useEffect(() => {
|
||||
if (control.isOpen) {
|
||||
logger.metric('welcomeModal:presented', {})
|
||||
ax.metric('welcomeModal:presented', {})
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [control.isOpen])
|
||||
|
||||
const onPressCreateAccount = () => {
|
||||
logger.metric('welcomeModal:signupClicked', {})
|
||||
ax.metric('welcomeModal:signupClicked', {})
|
||||
control.close()
|
||||
requestSwitchToAccount({requestedAccount: 'new'})
|
||||
}
|
||||
|
||||
const onPressExplore = () => {
|
||||
logger.metric('welcomeModal:exploreClicked', {})
|
||||
ax.metric('welcomeModal:exploreClicked', {})
|
||||
fadeOutAndClose()
|
||||
}
|
||||
|
||||
const onPressSignIn = () => {
|
||||
logger.metric('welcomeModal:signinClicked', {})
|
||||
ax.metric('welcomeModal:signinClicked', {})
|
||||
control.close()
|
||||
requestSwitchToAccount({requestedAccount: 'existing'})
|
||||
}
|
||||
@@ -222,7 +224,7 @@ export function WelcomeModal({control}: WelcomeModalProps) {
|
||||
]}
|
||||
hoverStyle={[a.bg_transparent]}
|
||||
onPress={() => {
|
||||
logger.metric('welcomeModal:dismissed', {})
|
||||
ax.metric('welcomeModal:dismissed', {})
|
||||
fadeOutAndClose()
|
||||
}}
|
||||
color="secondary"
|
||||
|
||||
@@ -17,7 +17,6 @@ import {useLingui} from '@lingui/react'
|
||||
|
||||
import {HITSLOP_10} from '#/lib/constants'
|
||||
import {makeListLink, makeProfileLink} from '#/lib/routes/links'
|
||||
import {logger} from '#/logger'
|
||||
import {
|
||||
type ThreadgateAllowUISetting,
|
||||
threadgateViewToAllowUISetting,
|
||||
@@ -36,6 +35,7 @@ import {Earth_Stroke2_Corner0_Rounded as EarthIcon} from '#/components/icons/Glo
|
||||
import {Group3_Stroke2_Corner0_Rounded as GroupIcon} from '#/components/icons/Group'
|
||||
import {InlineLinkText} from '#/components/Link'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
@@ -46,8 +46,9 @@ interface WhoCanReplyProps {
|
||||
}
|
||||
|
||||
export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const infoDialogControl = useDialogControl()
|
||||
const editDialogControl = useDialogControl()
|
||||
|
||||
@@ -90,7 +91,7 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
|
||||
Keyboard.dismiss()
|
||||
}
|
||||
if (isThreadAuthor) {
|
||||
logger.metric('thread:click:editOwnThreadgate', {})
|
||||
ax.metric('thread:click:editOwnThreadgate', {})
|
||||
|
||||
// wait on prefetch if it manages to resolve in under 200ms
|
||||
// otherwise, proceed immediately and show the spinner -sfn
|
||||
@@ -101,7 +102,7 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
|
||||
editDialogControl.open()
|
||||
})
|
||||
} else {
|
||||
logger.metric('thread:click:viewSomeoneElsesThreadgate', {})
|
||||
ax.metric('thread:click:viewSomeoneElsesThreadgate', {})
|
||||
|
||||
infoDialogControl.open()
|
||||
}
|
||||
|
||||
@@ -17,13 +17,11 @@ import {
|
||||
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
|
||||
import {cleanError} from '#/lib/strings/errors'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {logger} from '#/logger'
|
||||
import {updateProfileShadow} from '#/state/cache/profile-shadow'
|
||||
import {RQKEY_getActivitySubscriptions} from '#/state/queries/activity-subscriptions'
|
||||
import {useAgent} from '#/state/session'
|
||||
import * as Toast from '#/view/com/util/Toast'
|
||||
import {platform, useTheme, web} from '#/alf'
|
||||
import {atoms as a} from '#/alf'
|
||||
import {atoms as a, platform, useTheme, web} from '#/alf'
|
||||
import {Admonition} from '#/components/Admonition'
|
||||
import {
|
||||
Button,
|
||||
@@ -36,6 +34,7 @@ import * as Toggle from '#/components/forms/Toggle'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import * as ProfileCard from '#/components/ProfileCard'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_WEB} from '#/env'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
@@ -71,6 +70,7 @@ function DialogInner({
|
||||
moderationOpts: ModerationOpts
|
||||
includeProfile?: boolean
|
||||
}) {
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
const agent = useAgent()
|
||||
@@ -133,7 +133,7 @@ function DialogInner({
|
||||
})
|
||||
|
||||
if (!activitySubscription.post && !activitySubscription.reply) {
|
||||
logger.metric('activitySubscription:disable', {})
|
||||
ax.metric('activitySubscription:disable', {})
|
||||
Toast.show(
|
||||
_(
|
||||
msg`You will no longer receive notifications for ${sanitizeHandle(profile.handle, '@')}`,
|
||||
@@ -160,7 +160,7 @@ function DialogInner({
|
||||
},
|
||||
)
|
||||
} else {
|
||||
logger.metric('activitySubscription:enable', {
|
||||
ax.metric('activitySubscription:enable', {
|
||||
setting: activitySubscription.reply ? 'posts_and_replies' : 'posts',
|
||||
})
|
||||
if (!initialState.post && !initialState.reply) {
|
||||
@@ -177,7 +177,7 @@ function DialogInner({
|
||||
})
|
||||
},
|
||||
onError: err => {
|
||||
logger.error('Could not save activity subscription', {message: err})
|
||||
ax.logger.error('Could not save activity subscription', {message: err})
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -20,8 +20,9 @@ import {Divider} from '#/components/Divider'
|
||||
import {createStaticClick, InlineLinkText} from '#/components/Link'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {logger, useAgeAssurance} from '#/ageAssurance'
|
||||
import {useAgeAssurance} from '#/ageAssurance'
|
||||
import {useComputeAgeAssuranceRegionAccess} from '#/ageAssurance/useComputeAgeAssuranceRegionAccess'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
import {useDeviceGeolocationApi} from '#/geolocation'
|
||||
|
||||
@@ -41,6 +42,7 @@ export function AgeAssuranceAccountCard({style}: ViewStyleProp & {}) {
|
||||
function Inner({style}: ViewStyleProp & {}) {
|
||||
const t = useTheme()
|
||||
const {_, i18n} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const control = useDialogControl()
|
||||
const appealControl = Dialog.useDialogControl()
|
||||
const locationControl = Dialog.useDialogControl()
|
||||
@@ -138,7 +140,7 @@ function Inner({style}: ViewStyleProp & {}) {
|
||||
label={_(msg`Contact our moderation team`)}
|
||||
{...createStaticClick(() => {
|
||||
appealControl.open()
|
||||
logger.metric('ageAssurance:appealDialogOpen', {})
|
||||
ax.metric('ageAssurance:appealDialogOpen', {})
|
||||
})}>
|
||||
contact our moderation team
|
||||
</InlineLinkText>{' '}
|
||||
@@ -167,7 +169,7 @@ function Inner({style}: ViewStyleProp & {}) {
|
||||
color={hasInitiated ? 'secondary' : 'primary'}
|
||||
onPress={() => {
|
||||
control.open()
|
||||
logger.metric('ageAssurance:initDialogOpen', {
|
||||
ax.metric('ageAssurance:initDialogOpen', {
|
||||
hasInitiatedPreviously: hasInitiated,
|
||||
})
|
||||
}}>
|
||||
|
||||
@@ -10,7 +10,7 @@ import {ShieldCheck_Stroke2_Corner0_Rounded as Shield} from '#/components/icons/
|
||||
import {InlineLinkText} from '#/components/Link'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAgeAssurance} from '#/ageAssurance'
|
||||
import {logger} from '#/ageAssurance'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
export function AgeAssuranceAdmonition({
|
||||
children,
|
||||
@@ -40,6 +40,7 @@ function Inner({
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -92,7 +93,7 @@ function Inner({
|
||||
to={'/settings/account'}
|
||||
style={[a.text_sm, a.leading_snug, a.font_semi_bold]}
|
||||
onPress={() => {
|
||||
logger.metric('ageAssurance:navigateToSettings', {})
|
||||
ax.metric('ageAssurance:navigateToSettings', {})
|
||||
}}>
|
||||
account settings.
|
||||
</InlineLinkText>
|
||||
|
||||
@@ -15,6 +15,7 @@ import * as Dialog from '#/components/Dialog'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {logger} from '#/ageAssurance'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
export function AgeAssuranceAppealDialog({
|
||||
control,
|
||||
@@ -37,6 +38,7 @@ export function AgeAssuranceAppealDialog({
|
||||
|
||||
function Inner({control}: {control: Dialog.DialogControlProps}) {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const {currentAccount} = useSession()
|
||||
const {gtPhone} = useBreakpoints()
|
||||
const agent = useAgent()
|
||||
@@ -46,7 +48,7 @@ function Inner({control}: {control: Dialog.DialogControlProps}) {
|
||||
|
||||
const {mutate, isPending} = useMutation({
|
||||
mutationFn: async () => {
|
||||
logger.metric('ageAssurance:appealDialogSubmit', {})
|
||||
ax.metric('ageAssurance:appealDialogSubmit', {})
|
||||
|
||||
await agent.createModerationReport(
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@ import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
||||
import {Link} from '#/components/Link'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAgeAssurance} from '#/ageAssurance'
|
||||
import {logger} from '#/ageAssurance'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
export function useInternalState() {
|
||||
const aa = useAgeAssurance()
|
||||
@@ -42,6 +42,7 @@ export function useInternalState() {
|
||||
|
||||
export function AgeAssuranceDismissibleFeedBanner() {
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const {visible, close} = useInternalState()
|
||||
const copy = useAgeAssuranceCopy()
|
||||
@@ -66,7 +67,7 @@ export function AgeAssuranceDismissibleFeedBanner() {
|
||||
to="/settings/account"
|
||||
onPress={() => {
|
||||
close()
|
||||
logger.metric('ageAssurance:navigateToSettings', {})
|
||||
ax.metric('ageAssurance:navigateToSettings', {})
|
||||
}}
|
||||
style={[a.w_full, a.justify_between, a.align_center, a.gap_md]}>
|
||||
<View
|
||||
@@ -105,7 +106,7 @@ export function AgeAssuranceDismissibleFeedBanner() {
|
||||
size="small"
|
||||
onPress={() => {
|
||||
close()
|
||||
logger.metric('ageAssurance:dismissFeedBanner', {})
|
||||
ax.metric('ageAssurance:dismissFeedBanner', {})
|
||||
}}
|
||||
style={[
|
||||
a.absolute,
|
||||
|
||||
@@ -10,10 +10,11 @@ import {useAgeAssuranceCopy} from '#/components/ageAssurance/useAgeAssuranceCopy
|
||||
import {Button, ButtonIcon} from '#/components/Button'
|
||||
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
||||
import {useAgeAssurance} from '#/ageAssurance'
|
||||
import {logger} from '#/ageAssurance'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
export function AgeAssuranceDismissibleNotice({style}: ViewStyleProp & {}) {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const aa = useAgeAssurance()
|
||||
const {nux} = useNux(Nux.AgeAssuranceDismissibleNotice)
|
||||
const copy = useAgeAssuranceCopy()
|
||||
@@ -45,7 +46,7 @@ export function AgeAssuranceDismissibleNotice({style}: ViewStyleProp & {}) {
|
||||
completed: true,
|
||||
data: undefined,
|
||||
})
|
||||
logger.metric('ageAssurance:dismissSettingsNotice', {})
|
||||
ax.metric('ageAssurance:dismissSettingsNotice', {})
|
||||
}}
|
||||
style={[
|
||||
a.absolute,
|
||||
|
||||
@@ -19,8 +19,7 @@ import {useSession} from '#/state/session'
|
||||
import {atoms as a, web} from '#/alf'
|
||||
import {Admonition} from '#/components/Admonition'
|
||||
import {AgeAssuranceBadge} from '#/components/ageAssurance/AgeAssuranceBadge'
|
||||
import {urls} from '#/components/ageAssurance/const'
|
||||
import {KWS_SUPPORTED_LANGS} from '#/components/ageAssurance/const'
|
||||
import {KWS_SUPPORTED_LANGS, urls} from '#/components/ageAssurance/const'
|
||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||
import * as Dialog from '#/components/Dialog'
|
||||
import {Divider} from '#/components/Divider'
|
||||
@@ -30,9 +29,9 @@ import {LanguageSelect} from '#/components/LanguageSelect'
|
||||
import {SimpleInlineLinkText} from '#/components/Link'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {logger} from '#/ageAssurance'
|
||||
import {useAgeAssurance} from '#/ageAssurance'
|
||||
import {useBeginAgeAssurance} from '#/ageAssurance/useBeginAgeAssurance'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
export {useDialogControl} from '#/components/Dialog/context'
|
||||
|
||||
@@ -64,6 +63,7 @@ export function AgeAssuranceInitDialog({
|
||||
|
||||
function Inner() {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const {currentAccount} = useSession()
|
||||
const langPrefs = useLanguagePrefs()
|
||||
const cleanError = useCleanError()
|
||||
@@ -116,7 +116,7 @@ function Inner() {
|
||||
const onSubmit = async () => {
|
||||
setLanguageError(false)
|
||||
|
||||
logger.metric('ageAssurance:initDialogSubmit', {})
|
||||
ax.metric('ageAssurance:initDialogSubmit', {})
|
||||
|
||||
try {
|
||||
const {status} = runEmailValidation()
|
||||
@@ -143,7 +143,7 @@ function Inner() {
|
||||
error = _(
|
||||
msg`Please enter a valid, non-temporary email address. You may need to access this email in the future.`,
|
||||
)
|
||||
logger.metric('ageAssurance:initDialogError', {code: 'InvalidEmail'})
|
||||
ax.metric('ageAssurance:initDialogError', {code: 'InvalidEmail'})
|
||||
} else if (e.error === 'DidTooLong') {
|
||||
error = (
|
||||
<>
|
||||
@@ -159,14 +159,14 @@ function Inner() {
|
||||
</Trans>
|
||||
</>
|
||||
)
|
||||
logger.metric('ageAssurance:initDialogError', {code: 'DidTooLong'})
|
||||
ax.metric('ageAssurance:initDialogError', {code: 'DidTooLong'})
|
||||
} else {
|
||||
logger.metric('ageAssurance:initDialogError', {code: 'other'})
|
||||
ax.metric('ageAssurance:initDialogError', {code: 'other'})
|
||||
}
|
||||
} else {
|
||||
const {clean, raw} = cleanError(e)
|
||||
error = clean || raw || error
|
||||
logger.metric('ageAssurance:initDialogError', {code: 'other'})
|
||||
ax.metric('ageAssurance:initDialogError', {code: 'other'})
|
||||
}
|
||||
|
||||
setError(error)
|
||||
|
||||
@@ -16,7 +16,7 @@ import {CircleInfo_Stroke2_Corner0_Rounded as ErrorIcon} from '#/components/icon
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {refetchAgeAssuranceServerState} from '#/ageAssurance'
|
||||
import {logger} from '#/ageAssurance'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
|
||||
export type AgeAssuranceRedirectDialogState = {
|
||||
@@ -81,6 +81,7 @@ export function AgeAssuranceRedirectDialog() {
|
||||
|
||||
export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const agent = useAgent()
|
||||
const polling = useRef(false)
|
||||
@@ -94,7 +95,7 @@ export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
|
||||
|
||||
polling.current = true
|
||||
|
||||
logger.metric('ageAssurance:redirectDialogOpen', {})
|
||||
ax.metric('ageAssurance:redirectDialogOpen', {})
|
||||
|
||||
wait(
|
||||
3e3,
|
||||
@@ -125,18 +126,18 @@ export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
|
||||
|
||||
setSuccess(true)
|
||||
|
||||
logger.metric('ageAssurance:redirectDialogSuccess', {})
|
||||
ax.metric('ageAssurance:redirectDialogSuccess', {})
|
||||
})
|
||||
.catch(() => {
|
||||
if (unmounted.current) return
|
||||
setError(true)
|
||||
logger.metric('ageAssurance:redirectDialogFail', {})
|
||||
ax.metric('ageAssurance:redirectDialogFail', {})
|
||||
})
|
||||
|
||||
return () => {
|
||||
unmounted.current = true
|
||||
}
|
||||
}, [agent, control])
|
||||
}, [ax, agent, control])
|
||||
|
||||
if (success) {
|
||||
return (
|
||||
|
||||
@@ -13,7 +13,7 @@ import * as Layout from '#/components/Layout'
|
||||
import {Link} from '#/components/Link'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAgeAssurance} from '#/ageAssurance'
|
||||
import {logger} from '#/ageAssurance'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
export function AgeRestrictedScreen({
|
||||
children,
|
||||
@@ -27,6 +27,7 @@ export function AgeRestrictedScreen({
|
||||
rightHeaderSlot?: React.ReactNode
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const copy = useAgeAssuranceCopy()
|
||||
const aa = useAgeAssurance()
|
||||
|
||||
@@ -74,7 +75,7 @@ export function AgeRestrictedScreen({
|
||||
variant="solid"
|
||||
color="primary"
|
||||
onPress={() => {
|
||||
logger.metric('ageAssurance:navigateToSettings', {})
|
||||
ax.metric('ageAssurance:navigateToSettings', {})
|
||||
}}>
|
||||
<ButtonText>
|
||||
<Trans>Go to account settings</Trans>
|
||||
|
||||
@@ -6,12 +6,12 @@ import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {HITSLOP_10} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {Nux, useNux, useSaveNux} from '#/state/queries/nuxs'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Button} from '#/components/Button'
|
||||
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_WEB} from '#/env'
|
||||
import {Link} from '../Link'
|
||||
import {useIsFindContactsFeatureEnabledBasedOnGeolocation} from './country-allowlist'
|
||||
@@ -19,6 +19,7 @@ import {useIsFindContactsFeatureEnabledBasedOnGeolocation} from './country-allow
|
||||
export function FindContactsBannerNUX() {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const {visible, close} = useInternalState()
|
||||
|
||||
if (!visible) return null
|
||||
@@ -30,7 +31,7 @@ export function FindContactsBannerNUX() {
|
||||
to={{screen: 'FindContactsFlow'}}
|
||||
label={_(msg`Import contacts to find your friends`)}
|
||||
onPress={() => {
|
||||
logger.metric('contacts:nux:bannerPressed', {})
|
||||
ax.metric('contacts:nux:bannerPressed', {})
|
||||
}}
|
||||
style={[
|
||||
a.w_full,
|
||||
@@ -84,6 +85,7 @@ export function FindContactsBannerNUX() {
|
||||
)
|
||||
}
|
||||
function useInternalState() {
|
||||
const ax = useAnalytics()
|
||||
const {nux} = useNux(Nux.FindContactsDismissibleBanner)
|
||||
const {mutate: save, variables} = useSaveNux()
|
||||
const hidden = !!variables
|
||||
@@ -103,7 +105,7 @@ function useInternalState() {
|
||||
completed: true,
|
||||
data: undefined,
|
||||
})
|
||||
logger.metric('contacts:nux:bannerDismissed', {})
|
||||
ax.metric('contacts:nux:bannerDismissed', {})
|
||||
}
|
||||
|
||||
return {visible, close}
|
||||
|
||||
@@ -28,6 +28,7 @@ import * as Layout from '#/components/Layout'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {
|
||||
contactsWithPhoneNumbersOnly,
|
||||
filterMatchedNumbers,
|
||||
@@ -51,6 +52,7 @@ export function GetContacts({
|
||||
context: 'Onboarding' | 'Standalone'
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const agent = useAgent()
|
||||
const insets = useSafeAreaInsets()
|
||||
const gutters = useGutters([0, 'wide'])
|
||||
@@ -100,16 +102,16 @@ export function GetContacts({
|
||||
},
|
||||
onSuccess: (result, contacts) => {
|
||||
if (context === 'Onboarding') {
|
||||
logger.metric('onboarding:contacts:contactsShared', {})
|
||||
ax.metric('onboarding:contacts:contactsShared', {})
|
||||
}
|
||||
if (result.matches.length > 0) {
|
||||
logger.metric('contacts:import:success', {
|
||||
ax.metric('contacts:import:success', {
|
||||
contactCount: contacts.length,
|
||||
matchCount: result.matches.length,
|
||||
entryPoint: context,
|
||||
})
|
||||
} else {
|
||||
logger.metric('contacts:import:failure', {
|
||||
ax.metric('contacts:import:failure', {
|
||||
reason: 'noValidNumbers',
|
||||
entryPoint: context,
|
||||
})
|
||||
@@ -134,7 +136,7 @@ export function GetContacts({
|
||||
})
|
||||
},
|
||||
onError: err => {
|
||||
logger.metric('contacts:import:failure', {
|
||||
ax.metric('contacts:import:failure', {
|
||||
reason: isNetworkError(err) ? 'networkError' : 'unknown',
|
||||
entryPoint: context,
|
||||
})
|
||||
@@ -180,7 +182,7 @@ export function GetContacts({
|
||||
permissions = await Contacts.requestPermissionsAsync()
|
||||
}
|
||||
|
||||
logger.metric('contacts:permission:request', {
|
||||
ax.metric('contacts:permission:request', {
|
||||
status: permissions.granted ? 'granted' : 'denied',
|
||||
accessLevelIOS: ios(permissions.accessPrivileges),
|
||||
})
|
||||
|
||||
@@ -31,6 +31,7 @@ import * as Layout from '#/components/Layout'
|
||||
import {InlineLinkText} from '#/components/Link'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {useGeolocation} from '#/geolocation'
|
||||
import {isFindContactsFeatureEnabled} from '../country-allowlist'
|
||||
import {
|
||||
@@ -52,6 +53,7 @@ export function PhoneInput({
|
||||
onSkip: () => void
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const t = useTheme()
|
||||
const agent = useAgent()
|
||||
const location = useGeolocation()
|
||||
@@ -85,7 +87,7 @@ export function PhoneInput({
|
||||
payload: {phoneCountryCode, phoneNumber},
|
||||
})
|
||||
|
||||
logger.metric('contacts:phone:phoneEntered', {entryPoint: context})
|
||||
ax.metric('contacts:phone:phoneEntered', {entryPoint: context})
|
||||
},
|
||||
onMutate: () => {
|
||||
Keyboard.dismiss()
|
||||
|
||||
@@ -23,6 +23,7 @@ import * as Layout from '#/components/Layout'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {OTPInput} from '../components/OTPInput'
|
||||
import {constructFullPhoneNumber, prettyPhoneNumber} from '../phone-number'
|
||||
import {type Action, type State, useOnPressBackButton} from '../state'
|
||||
@@ -40,6 +41,7 @@ export function VerifyNumber({
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const agent = useAgent()
|
||||
const gutters = useGutters([0, 'wide'])
|
||||
|
||||
@@ -83,7 +85,7 @@ export function VerifyNumber({
|
||||
})
|
||||
}, 1000)
|
||||
|
||||
logger.metric('contacts:phone:phoneVerified', {entryPoint: context})
|
||||
ax.metric('contacts:phone:phoneVerified', {entryPoint: context})
|
||||
},
|
||||
onMutate: () => setError(null),
|
||||
onError: err => {
|
||||
|
||||
@@ -39,6 +39,7 @@ import {Loader} from '#/components/Loader'
|
||||
import * as ProfileCard from '#/components/ProfileCard'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
import {InviteInfo} from '../components/InviteInfo'
|
||||
import {type Action, type Contact, type Match, type State} from '../state'
|
||||
@@ -83,6 +84,7 @@ export function ViewMatches({
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const gutter = useGutters([0, 'wide'])
|
||||
const moderationOpts = useModerationOpts()
|
||||
const queryClient = useQueryClient()
|
||||
@@ -109,9 +111,9 @@ export function ViewMatches({
|
||||
|
||||
const cumulativeFollowCount = useRef(0)
|
||||
const onFollow = useCallback(() => {
|
||||
logger.metric('contacts:matches:follow', {entryPoint: context})
|
||||
ax.metric('contacts:matches:follow', {entryPoint: context})
|
||||
cumulativeFollowCount.current += 1
|
||||
}, [context])
|
||||
}, [ax, context])
|
||||
|
||||
const {mutate: followAll, isPending: isFollowingAll} = useMutation({
|
||||
mutationFn: async () => {
|
||||
@@ -132,7 +134,7 @@ export function ViewMatches({
|
||||
return followableDids
|
||||
},
|
||||
onMutate: () =>
|
||||
logger.metric('contacts:matches:followAll', {
|
||||
ax.metric('contacts:matches:followAll', {
|
||||
followCount: followableDids.length,
|
||||
entryPoint: context,
|
||||
}),
|
||||
@@ -218,7 +220,7 @@ export function ViewMatches({
|
||||
await agent.app.bsky.contact.dismissMatch({subject: did})
|
||||
},
|
||||
onMutate: did => {
|
||||
logger.metric('contacts:matches:dismiss', {entryPoint: context})
|
||||
ax.metric('contacts:matches:dismiss', {entryPoint: context})
|
||||
dispatch({type: 'DISMISS_MATCH', payload: {did}})
|
||||
},
|
||||
onSuccess: (_res, did) => {
|
||||
@@ -392,7 +394,7 @@ export function ViewMatches({
|
||||
label={context === 'Onboarding' ? _(msg`Next`) : _(msg`Done`)}
|
||||
onPress={() => {
|
||||
if (context === 'Onboarding') {
|
||||
logger.metric('onboarding:contacts:nextPressed', {
|
||||
ax.metric('onboarding:contacts:nextPressed', {
|
||||
matchCount: allMatches.length,
|
||||
followCount: cumulativeFollowCount.current,
|
||||
dismissedMatchCount: state.dismissedMatches.length,
|
||||
@@ -516,6 +518,7 @@ function ContactItem({
|
||||
const gutter = useGutters([0, 'wide'])
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const {currentAccount} = useSession()
|
||||
|
||||
const name = contact.name ?? contact.firstName ?? contact.lastName
|
||||
@@ -564,7 +567,7 @@ function ContactItem({
|
||||
color="secondary"
|
||||
size="small"
|
||||
onPress={async () => {
|
||||
logger.metric('contacts:matches:invite', {
|
||||
ax.metric('contacts:matches:invite', {
|
||||
entryPoint: context,
|
||||
})
|
||||
try {
|
||||
|
||||
@@ -11,7 +11,6 @@ import {Image} from 'expo-image'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {cleanError} from '#/lib/strings/errors'
|
||||
import {
|
||||
type Gif,
|
||||
@@ -30,6 +29,7 @@ import {useThrottledValue} from '#/components/hooks/useThrottledValue'
|
||||
import {ArrowLeft_Stroke2_Corner0_Rounded as Arrow} from '#/components/icons/Arrow'
|
||||
import {MagnifyingGlass_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass'
|
||||
import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_WEB} from '#/env'
|
||||
|
||||
export function GifSelectDialog({
|
||||
@@ -280,14 +280,15 @@ export function GifPreview({
|
||||
gif: Gif
|
||||
onSelectGif: (gif: Gif) => void
|
||||
}) {
|
||||
const ax = useAnalytics()
|
||||
const {gtTablet} = useBreakpoints()
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
|
||||
const onPress = useCallback(() => {
|
||||
logEvent('composer:gif:select', {})
|
||||
ax.metric('composer:gif:select', {})
|
||||
onSelectGif(gif)
|
||||
}, [onSelectGif, gif])
|
||||
}, [ax, onSelectGif, gif])
|
||||
|
||||
return (
|
||||
<Button
|
||||
|
||||
@@ -11,7 +11,6 @@ import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {useHaptics} from '#/lib/haptics'
|
||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||
import {logger} from '#/logger'
|
||||
import {STALE} from '#/state/queries'
|
||||
import {useMyListsQuery} from '#/state/queries/my-lists'
|
||||
import {useGetPost} from '#/state/queries/post'
|
||||
@@ -51,6 +50,7 @@ import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/ico
|
||||
import {CloseQuote_Stroke2_Corner1_Rounded as QuoteIcon} from '#/components/icons/Quote'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_IOS} from '#/env'
|
||||
|
||||
export type PostInteractionSettingsFormProps = {
|
||||
@@ -80,8 +80,9 @@ export function PostInteractionSettingsControlledDialog({
|
||||
}: PostInteractionSettingsFormProps & {
|
||||
control: Dialog.DialogControlProps
|
||||
}) {
|
||||
const ax = useAnalytics()
|
||||
const onClose = useNonReactiveCallback(() => {
|
||||
logger.metric('composer:threadgate:save', {
|
||||
ax.metric('composer:threadgate:save', {
|
||||
hasChanged: !!rest.isDirty,
|
||||
persist: !!rest.persist,
|
||||
replyOptions:
|
||||
@@ -161,6 +162,7 @@ export function PostInteractionSettingsDialog(
|
||||
export function PostInteractionSettingsDialogControlledInner(
|
||||
props: PostInteractionSettingsDialogProps,
|
||||
) {
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const {currentAccount} = useSession()
|
||||
const [isSaving, setIsSaving] = useState(false)
|
||||
@@ -229,7 +231,7 @@ export function PostInteractionSettingsDialogControlledInner(
|
||||
|
||||
props.control.close()
|
||||
} catch (e: any) {
|
||||
logger.error(`Failed to save post interaction settings`, {
|
||||
ax.logger.error(`Failed to save post interaction settings`, {
|
||||
source: 'PostInteractionSettingsDialogControlledInner',
|
||||
safeMessage: e.message,
|
||||
})
|
||||
@@ -244,6 +246,7 @@ export function PostInteractionSettingsDialogControlledInner(
|
||||
}
|
||||
}, [
|
||||
_,
|
||||
ax,
|
||||
props.postUri,
|
||||
props.rootPostUri,
|
||||
props.control,
|
||||
@@ -689,6 +692,7 @@ export function usePrefetchPostInteractionSettings({
|
||||
postUri: string
|
||||
rootPostUri: string
|
||||
}) {
|
||||
const ax = useAnalytics()
|
||||
const queryClient = useQueryClient()
|
||||
const agent = useAgent()
|
||||
const getPost = useGetPost()
|
||||
@@ -712,9 +716,9 @@ export function usePrefetchPostInteractionSettings({
|
||||
}),
|
||||
])
|
||||
} catch (e: any) {
|
||||
logger.error(`Failed to prefetch post interaction settings`, {
|
||||
ax.logger.error(`Failed to prefetch post interaction settings`, {
|
||||
safeMessage: e.message,
|
||||
})
|
||||
}
|
||||
}, [queryClient, agent, postUri, rootPostUri, getPost])
|
||||
}, [ax, queryClient, agent, postUri, rootPostUri, getPost])
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import {useCallback, useImperativeHandle, useRef, useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {useWindowDimensions} from 'react-native'
|
||||
import {useWindowDimensions, View} from 'react-native'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {BSKY_SERVICE} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import * as persisted from '#/state/persisted'
|
||||
import {useSession} from '#/state/session'
|
||||
import {atoms as a, platform, useBreakpoints, useTheme, web} from '#/alf'
|
||||
@@ -17,6 +15,7 @@ import * as TextField from '#/components/forms/TextField'
|
||||
import {Globe_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe'
|
||||
import {InlineLinkText} from '#/components/Link'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
type SegmentedControlOptions = typeof BSKY_SERVICE | 'custom'
|
||||
|
||||
@@ -27,6 +26,7 @@ export function ServerInputDialog({
|
||||
control: Dialog.DialogOuterProps['control']
|
||||
onSelect: (url: string) => void
|
||||
}) {
|
||||
const ax = useAnalytics()
|
||||
const {height} = useWindowDimensions()
|
||||
const formRef = useRef<DialogInnerRef>(null)
|
||||
|
||||
@@ -43,10 +43,10 @@ export function ServerInputDialog({
|
||||
setPreviousCustomAddress(result)
|
||||
}
|
||||
}
|
||||
logger.metric('signin:hostingProviderPressed', {
|
||||
ax.metric('signin:hostingProviderPressed', {
|
||||
hostingProviderDidChange: fixedOption !== BSKY_SERVICE,
|
||||
})
|
||||
}, [onSelect, fixedOption])
|
||||
}, [ax, onSelect, fixedOption])
|
||||
|
||||
return (
|
||||
<Dialog.Outer
|
||||
|
||||
@@ -11,7 +11,6 @@ import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {useRequireEmailVerification} from '#/lib/hooks/useRequireEmailVerification'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {logger} from '#/logger'
|
||||
import {
|
||||
invalidateActorStarterPacksWithMembershipQuery,
|
||||
useActorStarterPacksWithMembershipsQuery,
|
||||
@@ -31,6 +30,7 @@ import {StarterPack} from '#/components/icons/StarterPack'
|
||||
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_WEB} from '#/env'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
@@ -244,8 +244,9 @@ function StarterPackItem({
|
||||
starterPackWithMembership: StarterPackWithMembership
|
||||
targetDid: string
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const starterPack = starterPackWithMembership.starterPack
|
||||
@@ -304,7 +305,7 @@ function StarterPackItem({
|
||||
listUri: listUri,
|
||||
actorDid: targetDid,
|
||||
})
|
||||
logger.metric('starterPack:addUser', {starterPack: starterPackUri})
|
||||
ax.metric('starterPack:addUser', {starterPack: starterPackUri})
|
||||
} else {
|
||||
if (!starterPackWithMembership.listItem?.uri) {
|
||||
console.error('Cannot remove: missing membership URI')
|
||||
@@ -316,7 +317,7 @@ function StarterPackItem({
|
||||
actorDid: targetDid,
|
||||
membershipUri: starterPackWithMembership.listItem.uri,
|
||||
})
|
||||
logger.metric('starterPack:removeUser', {starterPack: starterPackUri})
|
||||
ax.metric('starterPack:removeUser', {starterPack: starterPackUri})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import {LinearGradient} from 'expo-linear-gradient'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {logger} from '#/logger'
|
||||
import {atoms as a, useTheme, web} from '#/alf'
|
||||
import {Button, ButtonText} from '#/components/Button'
|
||||
import {isFindContactsFeatureEnabled} from '#/components/contacts/country-allowlist'
|
||||
@@ -16,8 +15,8 @@ import {
|
||||
isExistingUserAsOf,
|
||||
} from '#/components/dialogs/nuxs/utils'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {IS_NATIVE, IS_WEB} from '#/env'
|
||||
import {IS_E2E} from '#/env'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_E2E, IS_NATIVE, IS_WEB} from '#/env'
|
||||
import {navigate} from '#/Navigation'
|
||||
|
||||
export const enabled = createIsEnabledCheck(props => {
|
||||
@@ -35,6 +34,7 @@ export const enabled = createIsEnabledCheck(props => {
|
||||
export function FindContactsAnnouncement() {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const nuxDialogs = useNuxDialogContext()
|
||||
const control = Dialog.useDialogControl()
|
||||
|
||||
@@ -115,7 +115,7 @@ export function FindContactsAnnouncement() {
|
||||
size="large"
|
||||
color="primary"
|
||||
onPress={() => {
|
||||
logger.metric('contacts:nux:ctaPressed', {})
|
||||
ax.metric('contacts:nux:ctaPressed', {})
|
||||
control.close(() => {
|
||||
navigate('FindContactsFlow')
|
||||
})
|
||||
|
||||
@@ -5,7 +5,6 @@ import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {urls} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
||||
import {Button, ButtonText} from '#/components/Button'
|
||||
import * as Dialog from '#/components/Dialog'
|
||||
@@ -14,11 +13,13 @@ import {Sparkle_Stroke2_Corner0_Rounded as SparkleIcon} from '#/components/icons
|
||||
import {VerifierCheck} from '#/components/icons/VerifierCheck'
|
||||
import {Link} from '#/components/Link'
|
||||
import {Span, Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
|
||||
export function InitialVerificationAnnouncement() {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const {gtMobile} = useBreakpoints()
|
||||
const nuxDialogs = useNuxDialogContext()
|
||||
const control = Dialog.useDialogControl()
|
||||
@@ -161,13 +162,9 @@ export function InitialVerificationAnnouncement() {
|
||||
color="primary"
|
||||
style={[a.justify_center, a.w_full]}
|
||||
onPress={() => {
|
||||
logger.metric(
|
||||
'verification:learn-more',
|
||||
{
|
||||
location: 'initialAnnouncementeNux',
|
||||
},
|
||||
{statsig: false},
|
||||
)
|
||||
ax.metric('verification:learn-more', {
|
||||
location: 'initialAnnouncementeNux',
|
||||
})
|
||||
}}>
|
||||
<ButtonText>
|
||||
<Trans>Read blog post</Trans>
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<typeof useGate>
|
||||
feature: AnalyticsContextType['feature']
|
||||
currentAccount: SessionAccount
|
||||
currentProfile: AppBskyActorDefs.ProfileViewDetailed
|
||||
preferences: UsePreferencesQueryResponse
|
||||
|
||||
@@ -7,7 +7,6 @@ import {useLingui} from '@lingui/react'
|
||||
|
||||
import {useTranslate} from '#/lib/hooks/useTranslate'
|
||||
import {richTextToString} from '#/lib/strings/rich-text-helpers'
|
||||
import {logger} from '#/logger'
|
||||
import {useConvoActive} from '#/state/messages/convo'
|
||||
import {useLanguagePrefs} from '#/state/preferences'
|
||||
import {useSession} from '#/state/session'
|
||||
@@ -22,6 +21,7 @@ import {Warning_Stroke2_Corner0_Rounded as Warning} from '#/components/icons/War
|
||||
import {ReportDialog} from '#/components/moderation/ReportDialog'
|
||||
import * as Prompt from '#/components/Prompt'
|
||||
import {usePromptControl} from '#/components/Prompt'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
import {EmojiReactionPicker} from './EmojiReactionPicker'
|
||||
import {hasReachedReactionLimit} from './util'
|
||||
@@ -34,6 +34,7 @@ export let MessageContextMenu = ({
|
||||
children: TriggerProps['children']
|
||||
}): React.ReactNode => {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const {currentAccount} = useSession()
|
||||
const convo = useConvoActive()
|
||||
const deleteControl = usePromptControl()
|
||||
@@ -60,16 +61,12 @@ export let MessageContextMenu = ({
|
||||
const onPressTranslateMessage = useCallback(() => {
|
||||
translate(message.text, langPrefs.primaryLanguage)
|
||||
|
||||
logger.metric(
|
||||
'translate',
|
||||
{
|
||||
sourceLanguages: [],
|
||||
targetLanguage: langPrefs.primaryLanguage,
|
||||
textLength: message.text.length,
|
||||
},
|
||||
{statsig: false},
|
||||
)
|
||||
}, [langPrefs.primaryLanguage, message.text, translate])
|
||||
ax.metric('translate', {
|
||||
sourceLanguages: [],
|
||||
targetLanguage: langPrefs.primaryLanguage,
|
||||
textLength: message.text.length,
|
||||
})
|
||||
}, [ax, langPrefs.primaryLanguage, message.text, translate])
|
||||
|
||||
const onDelete = useCallback(() => {
|
||||
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
|
||||
|
||||
@@ -7,7 +7,6 @@ import {useNavigation} from '@react-navigation/native'
|
||||
|
||||
import {useRequireEmailVerification} from '#/lib/hooks/useRequireEmailVerification'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {useGetConvoAvailabilityQuery} from '#/state/queries/messages/get-convo-availability'
|
||||
import {useGetConvoForMembers} from '#/state/queries/messages/get-convo-for-members'
|
||||
import * as Toast from '#/view/com/util/Toast'
|
||||
@@ -15,6 +14,7 @@ import {atoms as a, useTheme} from '#/alf'
|
||||
import {Button, ButtonIcon} from '#/components/Button'
|
||||
import {canBeMessaged} from '#/components/dms/util'
|
||||
import {Message_Stroke2_Corner0_Rounded as Message} from '#/components/icons/Message'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
export function MessageProfileButton({
|
||||
profile,
|
||||
@@ -23,13 +23,14 @@ export function MessageProfileButton({
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const requireEmailVerification = useRequireEmailVerification()
|
||||
|
||||
const {data: convoAvailability} = useGetConvoAvailabilityQuery(profile.did)
|
||||
const {mutate: initiateConvo} = useGetConvoForMembers({
|
||||
onSuccess: ({convo}) => {
|
||||
logEvent('chat:open', {logContext: 'ProfileHeader'})
|
||||
ax.metric('chat:open', {logContext: 'ProfileHeader'})
|
||||
navigation.navigate('MessagesConversation', {conversation: convo.id})
|
||||
},
|
||||
onError: () => {
|
||||
@@ -43,15 +44,15 @@ export function MessageProfileButton({
|
||||
}
|
||||
|
||||
if (convoAvailability.convo) {
|
||||
logEvent('chat:open', {logContext: 'ProfileHeader'})
|
||||
ax.metric('chat:open', {logContext: 'ProfileHeader'})
|
||||
navigation.navigate('MessagesConversation', {
|
||||
conversation: convoAvailability.convo.id,
|
||||
})
|
||||
} else {
|
||||
logEvent('chat:create', {logContext: 'ProfileHeader'})
|
||||
ax.metric('chat:create', {logContext: 'ProfileHeader'})
|
||||
initiateConvo([profile.did])
|
||||
}
|
||||
}, [navigation, profile.did, initiateConvo, convoAvailability])
|
||||
}, [ax, navigation, profile.did, initiateConvo, convoAvailability])
|
||||
|
||||
const wrappedOnPress = requireEmailVerification(onPress, {
|
||||
instructions: [
|
||||
|
||||
@@ -3,7 +3,6 @@ import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {useRequireEmailVerification} from '#/lib/hooks/useRequireEmailVerification'
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {logger} from '#/logger'
|
||||
import {useGetConvoForMembers} from '#/state/queries/messages/get-convo-for-members'
|
||||
import {FAB} from '#/view/com/util/fab/FAB'
|
||||
@@ -12,6 +11,7 @@ import {useTheme} from '#/alf'
|
||||
import * as Dialog from '#/components/Dialog'
|
||||
import {SearchablePeopleList} from '#/components/dialogs/SearchablePeopleList'
|
||||
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
export function NewChat({
|
||||
control,
|
||||
@@ -22,6 +22,7 @@ export function NewChat({
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const requireEmailVerification = useRequireEmailVerification()
|
||||
|
||||
const {mutate: createChat} = useGetConvoForMembers({
|
||||
@@ -29,9 +30,9 @@ export function NewChat({
|
||||
onNewChat(data.convo.id)
|
||||
|
||||
if (!data.convo.lastMessage) {
|
||||
logEvent('chat:create', {logContext: 'NewChatDialog'})
|
||||
ax.metric('chat:create', {logContext: 'NewChatDialog'})
|
||||
}
|
||||
logEvent('chat:open', {logContext: 'NewChatDialog'})
|
||||
ax.metric('chat:open', {logContext: 'NewChatDialog'})
|
||||
},
|
||||
onError: error => {
|
||||
logger.error('Failed to create chat', {safeMessage: error})
|
||||
|
||||
@@ -2,12 +2,12 @@ import {useCallback} from 'react'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {logger} from '#/logger'
|
||||
import {useGetConvoForMembers} from '#/state/queries/messages/get-convo-for-members'
|
||||
import * as Toast from '#/view/com/util/Toast'
|
||||
import * as Dialog from '#/components/Dialog'
|
||||
import {SearchablePeopleList} from '#/components/dialogs/SearchablePeopleList'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
export function SendViaChatDialog({
|
||||
control,
|
||||
@@ -32,14 +32,15 @@ function SendViaChatDialogInner({
|
||||
onSelectChat: (chatId: string) => void
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const {mutate: createChat} = useGetConvoForMembers({
|
||||
onSuccess: data => {
|
||||
onSelectChat(data.convo.id)
|
||||
|
||||
if (!data.convo.lastMessage) {
|
||||
logEvent('chat:create', {logContext: 'SendViaChatDialog'})
|
||||
ax.metric('chat:create', {logContext: 'SendViaChatDialog'})
|
||||
}
|
||||
logEvent('chat:open', {logContext: 'SendViaChatDialog'})
|
||||
ax.metric('chat:open', {logContext: 'SendViaChatDialog'})
|
||||
},
|
||||
onError: error => {
|
||||
logger.error('Failed to share post to chat', {message: error})
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {View} from 'react-native'
|
||||
import {AppBskyEmbedVideo} from '@atproto/api'
|
||||
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {type FeedPostSliceItem} from '#/state/queries/post-feed'
|
||||
import {type VideoFeedSourceContext} from '#/screens/VideoFeed/types'
|
||||
import {atoms as a, useGutters} from '#/alf'
|
||||
@@ -10,6 +9,7 @@ import {
|
||||
VideoPostCard,
|
||||
VideoPostCardPlaceholder,
|
||||
} from '#/components/VideoPostCard'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
export function PostFeedVideoGridRow({
|
||||
items: slices,
|
||||
@@ -18,6 +18,7 @@ export function PostFeedVideoGridRow({
|
||||
items: FeedPostSliceItem[]
|
||||
sourceContext: VideoFeedSourceContext
|
||||
}) {
|
||||
const ax = useAnalytics()
|
||||
const gutters = useGutters(['base', 'base', 0, 'base'])
|
||||
const posts = slices
|
||||
.filter(slice => AppBskyEmbedVideo.isView(slice.post.embed))
|
||||
@@ -43,7 +44,7 @@ export function PostFeedVideoGridRow({
|
||||
sourceContext={sourceContext}
|
||||
moderation={post.moderation}
|
||||
onInteract={() => {
|
||||
logEvent('videoCard:click', {context: 'feed'})
|
||||
ax.metric('videoCard:click', {context: 'feed'})
|
||||
}}
|
||||
/>
|
||||
</Grid.Col>
|
||||
|
||||
@@ -3,7 +3,6 @@ import {ScrollView, View} from 'react-native'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {
|
||||
useTrendingSettings,
|
||||
useTrendingSettingsApi,
|
||||
@@ -19,6 +18,7 @@ import {Trending2_Stroke2_Corner2_Rounded as Graph} from '#/components/icons/Tre
|
||||
import * as Prompt from '#/components/Prompt'
|
||||
import {TrendingTopicLink} from '#/components/TrendingTopics'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
export function TrendingInterstitial() {
|
||||
const {enabled} = useTrendingConfig()
|
||||
@@ -29,6 +29,7 @@ export function TrendingInterstitial() {
|
||||
export function Inner() {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const gutters = useGutters([0, 'base', 0, 'base'])
|
||||
const trendingPrompt = Prompt.usePromptControl()
|
||||
const {setTrendingDisabled} = useTrendingSettingsApi()
|
||||
@@ -36,9 +37,9 @@ export function Inner() {
|
||||
const noTopics = !isLoading && !error && !trending?.topics?.length
|
||||
|
||||
const onConfirmHide = React.useCallback(() => {
|
||||
logEvent('trendingTopics:hide', {context: 'interstitial'})
|
||||
ax.metric('trendingTopics:hide', {context: 'interstitial'})
|
||||
setTrendingDisabled(true)
|
||||
}, [setTrendingDisabled])
|
||||
}, [ax, setTrendingDisabled])
|
||||
|
||||
return error || noTopics ? null : (
|
||||
<View style={[t.atoms.border_contrast_low, a.border_t, a.border_b]}>
|
||||
@@ -94,7 +95,9 @@ export function Inner() {
|
||||
key={topic.link}
|
||||
topic={topic}
|
||||
onPress={() => {
|
||||
logEvent('trendingTopic:click', {context: 'interstitial'})
|
||||
ax.metric('trendingTopic:click', {
|
||||
context: 'interstitial',
|
||||
})
|
||||
}}>
|
||||
<View style={[a.py_lg]}>
|
||||
<Text
|
||||
|
||||
@@ -7,10 +7,8 @@ import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {VIDEO_FEED_URI} from '#/lib/constants'
|
||||
import {makeCustomFeedLink} from '#/lib/routes/links'
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {useTrendingSettingsApi} from '#/state/preferences/trending'
|
||||
import {usePostFeedQuery} from '#/state/queries/post-feed'
|
||||
import {RQKEY} from '#/state/queries/post-feed'
|
||||
import {RQKEY, usePostFeedQuery} from '#/state/queries/post-feed'
|
||||
import {BlockDrawerGesture} from '#/view/shell/BlockDrawerGesture'
|
||||
import {atoms as a, useGutters, useTheme} from '#/alf'
|
||||
import {Button, ButtonIcon} from '#/components/Button'
|
||||
@@ -23,6 +21,7 @@ import {
|
||||
CompactVideoPostCard,
|
||||
CompactVideoPostCardPlaceholder,
|
||||
} from '#/components/VideoPostCard'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
const CARD_WIDTH = 108
|
||||
|
||||
@@ -36,6 +35,7 @@ const FEED_PARAMS: {
|
||||
export function TrendingVideos() {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const gutters = useGutters([0, 'base'])
|
||||
const {data, isLoading, error} = usePostFeedQuery(FEED_DESC, FEED_PARAMS)
|
||||
|
||||
@@ -57,8 +57,8 @@ export function TrendingVideos() {
|
||||
|
||||
const onConfirmHide = useCallback(() => {
|
||||
setTrendingVideoDisabled(true)
|
||||
logEvent('trendingVideos:hide', {context: 'interstitial:discover'})
|
||||
}, [setTrendingVideoDisabled])
|
||||
ax.metric('trendingVideos:hide', {context: 'interstitial:discover'})
|
||||
}, [ax, setTrendingVideoDisabled])
|
||||
|
||||
if (error) {
|
||||
return null
|
||||
@@ -147,6 +147,7 @@ function VideoCards({
|
||||
}: {
|
||||
data: Exclude<ReturnType<typeof usePostFeedQuery>['data'], undefined>
|
||||
}) {
|
||||
const ax = useAnalytics()
|
||||
const items = useMemo(() => {
|
||||
return data.pages
|
||||
.flatMap(page => page.slices)
|
||||
@@ -169,7 +170,7 @@ function VideoCards({
|
||||
sourceInterstitial: 'discover',
|
||||
}}
|
||||
onInteract={() => {
|
||||
logEvent('videoCard:click', {
|
||||
ax.metric('videoCard:click', {
|
||||
context: 'interstitial:discover',
|
||||
})
|
||||
}}
|
||||
|
||||
@@ -11,7 +11,6 @@ import {useOpenLink} from '#/lib/hooks/useOpenLink'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {toNiceDomain} from '#/lib/strings/url-helpers'
|
||||
import {logger} from '#/logger'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {unstableCacheProfileView} from '#/state/queries/profile'
|
||||
import {android, atoms as a, platform, tokens, useTheme, web} from '#/alf'
|
||||
@@ -22,6 +21,7 @@ import {createStaticClick, SimpleInlineLinkText} from '#/components/Link'
|
||||
import {useGlobalReportDialogControl} from '#/components/moderation/ReportDialog'
|
||||
import * as ProfileCard from '#/components/ProfileCard'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
import {Globe_Stroke2_Corner0_Rounded} from '../icons/Globe'
|
||||
import {SquareArrowTopRight_Stroke2_Corner0_Rounded as SquareArrowTopRightIcon} from '../icons/SquareArrowTopRight'
|
||||
@@ -103,6 +103,7 @@ export function LiveStatus({
|
||||
padding?: 'lg' | 'xl'
|
||||
onPressOpenProfile: () => void
|
||||
}) {
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
const queryClient = useQueryClient()
|
||||
@@ -174,11 +175,7 @@ export function LiveStatus({
|
||||
color="primary"
|
||||
variant="solid"
|
||||
onPress={() => {
|
||||
logger.metric(
|
||||
'live:card:watch',
|
||||
{subject: profile.did},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('live:card:watch', {subject: profile.did})
|
||||
openLink(embed.external.uri, false)
|
||||
}}>
|
||||
<ButtonText>
|
||||
@@ -207,11 +204,7 @@ export function LiveStatus({
|
||||
color="secondary"
|
||||
variant="solid"
|
||||
onPress={() => {
|
||||
logger.metric(
|
||||
'live:card:openProfile',
|
||||
{subject: profile.did},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('live:card:openProfile', {subject: profile.did})
|
||||
unstableCacheProfileView(queryClient, profile)
|
||||
onPressOpenProfile()
|
||||
}}>
|
||||
|
||||
@@ -12,13 +12,13 @@ import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
||||
import {uploadBlob} from '#/lib/api'
|
||||
import {imageToThumb} from '#/lib/api/resolve'
|
||||
import {getLinkMeta, type LinkMeta} from '#/lib/link-meta/link-meta'
|
||||
import {logger} from '#/logger'
|
||||
import {updateProfileShadow} from '#/state/cache/profile-shadow'
|
||||
import {useLiveNowConfig} from '#/state/service-config'
|
||||
import {useAgent, useSession} from '#/state/session'
|
||||
import * as Toast from '#/view/com/util/Toast'
|
||||
import {useDialogContext} from '#/components/Dialog'
|
||||
import {getLiveServiceNames} from '#/components/live/utils'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
export function useLiveLinkMetaQuery(url: string | null) {
|
||||
const liveNowConfig = useLiveNowConfig()
|
||||
@@ -50,6 +50,7 @@ export function useUpsertLiveStatusMutation(
|
||||
linkMeta: LinkMeta | null | undefined,
|
||||
createdAt?: string,
|
||||
) {
|
||||
const ax = useAnalytics()
|
||||
const {currentAccount} = useSession()
|
||||
const agent = useAgent()
|
||||
const queryClient = useQueryClient()
|
||||
@@ -77,7 +78,7 @@ export function useUpsertLiveStatusMutation(
|
||||
thumb = blob.data.blob
|
||||
}
|
||||
} catch (e: any) {
|
||||
logger.error(`Failed to upload thumbnail for live status`, {
|
||||
ax.logger.error(`Failed to upload thumbnail for live status`, {
|
||||
url: linkMeta.url,
|
||||
image: linkMeta.image,
|
||||
safeMessage: e,
|
||||
@@ -133,7 +134,7 @@ export function useUpsertLiveStatusMutation(
|
||||
}
|
||||
},
|
||||
onError: (e: any) => {
|
||||
logger.error(`Failed to upsert live status`, {
|
||||
ax.logger.error(`Failed to upsert live status`, {
|
||||
url: linkMeta?.url,
|
||||
image: linkMeta?.image,
|
||||
safeMessage: e,
|
||||
@@ -141,17 +142,9 @@ export function useUpsertLiveStatusMutation(
|
||||
},
|
||||
onSuccess: ({record, image}) => {
|
||||
if (createdAt) {
|
||||
logger.metric(
|
||||
'live:edit',
|
||||
{duration: record.durationMinutes},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('live:edit', {duration: record.durationMinutes})
|
||||
} else {
|
||||
logger.metric(
|
||||
'live:create',
|
||||
{duration: record.durationMinutes},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('live:create', {duration: record.durationMinutes})
|
||||
}
|
||||
|
||||
Toast.show(_(msg`You are now live!`))
|
||||
@@ -187,6 +180,7 @@ export function useUpsertLiveStatusMutation(
|
||||
}
|
||||
|
||||
export function useRemoveLiveStatusMutation() {
|
||||
const ax = useAnalytics()
|
||||
const {currentAccount} = useSession()
|
||||
const agent = useAgent()
|
||||
const queryClient = useQueryClient()
|
||||
@@ -203,12 +197,12 @@ export function useRemoveLiveStatusMutation() {
|
||||
})
|
||||
},
|
||||
onError: (e: any) => {
|
||||
logger.error(`Failed to remove live status`, {
|
||||
ax.logger.error(`Failed to remove live status`, {
|
||||
safeMessage: e,
|
||||
})
|
||||
},
|
||||
onSuccess: () => {
|
||||
logger.metric('live:remove', {}, {statsig: true})
|
||||
ax.metric('live:remove', {})
|
||||
Toast.show(_(msg`You are no longer live`))
|
||||
control.close(() => {
|
||||
if (!currentAccount) return
|
||||
|
||||
@@ -7,7 +7,6 @@ import {useLingui} from '@lingui/react'
|
||||
import {wait} from '#/lib/async/wait'
|
||||
import {getLabelingServiceTitle} from '#/lib/moderation'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {Logger} from '#/logger'
|
||||
import {useMyLabelersQuery} from '#/state/queries/preferences'
|
||||
import {CharProgress} from '#/view/com/composer/char-progress/CharProgress'
|
||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||
@@ -28,6 +27,7 @@ import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
||||
import {createStaticClick, InlineLinkText, Link} from '#/components/Link'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
import {useSubmitReportMutation} from './action'
|
||||
import {
|
||||
@@ -53,8 +53,6 @@ export function useGlobalReportDialogControl() {
|
||||
return useGlobalDialogsControlContext().reportDialogControl
|
||||
}
|
||||
|
||||
const logger = Logger.create(Logger.Context.ReportDialog)
|
||||
|
||||
export function GlobalReportDialog() {
|
||||
const {value, control} = useGlobalReportDialogControl()
|
||||
return <ReportDialog control={control} subject={value?.subject} />
|
||||
@@ -65,13 +63,14 @@ export function ReportDialog(
|
||||
subject?: ReportSubject
|
||||
},
|
||||
) {
|
||||
const ax = useAnalytics()
|
||||
const subject = React.useMemo(
|
||||
() => (props.subject ? parseReportSubject(props.subject) : undefined),
|
||||
[props.subject],
|
||||
)
|
||||
const onClose = React.useCallback(() => {
|
||||
logger.metric('reportDialog:close', {}, {statsig: false})
|
||||
}, [])
|
||||
ax.metric('reportDialog:close', {})
|
||||
}, [ax])
|
||||
return (
|
||||
<Dialog.Outer control={props.control} onClose={onClose}>
|
||||
<Dialog.Handle />
|
||||
@@ -103,6 +102,8 @@ function Invalid() {
|
||||
}
|
||||
|
||||
function Inner(props: ReportDialogProps) {
|
||||
const ax = useAnalytics()
|
||||
const logger = ax.logger.useContext(ax.logger.Context.ReportDialog)
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const ref = React.useRef<ScrollView>(null)
|
||||
@@ -208,15 +209,11 @@ function Inner(props: ReportDialogProps) {
|
||||
}),
|
||||
)
|
||||
setSuccess(true)
|
||||
logger.metric(
|
||||
'reportDialog:success',
|
||||
{
|
||||
reason: state.selectedOption?.reason ?? '',
|
||||
labeler: state.selectedLabeler?.creator.handle ?? '',
|
||||
details: !!state.details,
|
||||
},
|
||||
{statsig: false},
|
||||
)
|
||||
ax.metric('reportDialog:success', {
|
||||
reason: state.selectedOption?.reason ?? '',
|
||||
labeler: state.selectedLabeler?.creator.handle ?? '',
|
||||
details: !!state.details,
|
||||
})
|
||||
// give time for user feedback
|
||||
setTimeout(() => {
|
||||
props.control.close(() => {
|
||||
@@ -224,7 +221,7 @@ function Inner(props: ReportDialogProps) {
|
||||
})
|
||||
}, 1e3)
|
||||
} catch (e: any) {
|
||||
logger.metric('reportDialog:failure', {}, {statsig: false})
|
||||
ax.metric('reportDialog:failure', {})
|
||||
logger.error(e, {
|
||||
source: 'ReportDialog',
|
||||
})
|
||||
@@ -237,15 +234,12 @@ function Inner(props: ReportDialogProps) {
|
||||
}
|
||||
}, [_, submitReport, state, dispatch, props, setPending, setSuccess])
|
||||
|
||||
// TODO once
|
||||
React.useEffect(() => {
|
||||
logger.metric(
|
||||
'reportDialog:open',
|
||||
{
|
||||
subjectType: props.subject.type,
|
||||
},
|
||||
{statsig: false},
|
||||
)
|
||||
}, [props.subject])
|
||||
ax.metric('reportDialog:open', {
|
||||
subjectType: props.subject.type,
|
||||
})
|
||||
}, [ax, props.subject])
|
||||
|
||||
return (
|
||||
<Dialog.ScrollableInner
|
||||
|
||||
@@ -2,7 +2,6 @@ import {View} from 'react-native'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {logger} from '#/logger'
|
||||
import {type Shadow} from '#/state/cache/types'
|
||||
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
||||
import {Button} from '#/components/Button'
|
||||
@@ -12,6 +11,7 @@ import {type FullVerificationState} from '#/components/verification'
|
||||
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
||||
import {VerificationsDialog} from '#/components/verification/VerificationsDialog'
|
||||
import {VerifierDialog} from '#/components/verification/VerifierDialog'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
export function shouldShowVerificationCheckButton(
|
||||
@@ -77,6 +77,7 @@ export function Badge({
|
||||
size: 'lg' | 'md' | 'sm'
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const verificationsDialogControl = useDialogControl()
|
||||
const verifierDialogControl = useDialogControl()
|
||||
@@ -101,7 +102,7 @@ export function Badge({
|
||||
hitSlop={20}
|
||||
onPress={evt => {
|
||||
evt.preventDefault()
|
||||
logger.metric('verification:badge:click', {}, {statsig: true})
|
||||
ax.metric('verification:badge:click', {})
|
||||
if (state.profile.role === 'verifier') {
|
||||
verifierDialogControl.open()
|
||||
} else {
|
||||
|
||||
@@ -5,7 +5,6 @@ import {useLingui} from '@lingui/react'
|
||||
|
||||
import {urls} from '#/lib/constants'
|
||||
import {getUserDisplayName} from '#/lib/getUserDisplayName'
|
||||
import {logger} from '#/logger'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {useProfileQuery} from '#/state/queries/profile'
|
||||
import {useSession} from '#/state/session'
|
||||
@@ -20,6 +19,7 @@ import * as ProfileCard from '#/components/ProfileCard'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {type FullVerificationState} from '#/components/verification'
|
||||
import {VerificationRemovePrompt} from '#/components/verification/VerificationRemovePrompt'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
export {useDialogControl} from '#/components/Dialog'
|
||||
@@ -55,6 +55,7 @@ function Inner({
|
||||
verificationState: FullVerificationState
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const {gtMobile} = useBreakpoints()
|
||||
|
||||
@@ -158,13 +159,9 @@ function Inner({
|
||||
color="secondary"
|
||||
style={[a.justify_center]}
|
||||
onPress={() => {
|
||||
logger.metric(
|
||||
'verification:learn-more',
|
||||
{
|
||||
location: 'verificationsDialog',
|
||||
},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('verification:learn-more', {
|
||||
location: 'verificationsDialog',
|
||||
})
|
||||
}}>
|
||||
<ButtonText>
|
||||
<Trans context="english-only-resource">Learn more</Trans>
|
||||
|
||||
@@ -5,7 +5,6 @@ import {useLingui} from '@lingui/react'
|
||||
|
||||
import {urls} from '#/lib/constants'
|
||||
import {getUserDisplayName} from '#/lib/getUserDisplayName'
|
||||
import {logger} from '#/logger'
|
||||
import {useSession} from '#/state/session'
|
||||
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
||||
import {Button, ButtonText} from '#/components/Button'
|
||||
@@ -14,6 +13,7 @@ import {VerifierCheck} from '#/components/icons/VerifierCheck'
|
||||
import {Link} from '#/components/Link'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {type FullVerificationState} from '#/components/verification'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
export {useDialogControl} from '#/components/Dialog'
|
||||
@@ -49,6 +49,7 @@ function Inner({
|
||||
verificationState: FullVerificationState
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const {gtMobile} = useBreakpoints()
|
||||
const {currentAccount} = useSession()
|
||||
@@ -126,13 +127,9 @@ function Inner({
|
||||
color="primary"
|
||||
style={[a.justify_center]}
|
||||
onPress={() => {
|
||||
logger.metric(
|
||||
'verification:learn-more',
|
||||
{
|
||||
location: 'verifierDialog',
|
||||
},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('verification:learn-more', {
|
||||
location: 'verifierDialog',
|
||||
})
|
||||
}}>
|
||||
<ButtonText>
|
||||
<Trans context="english-only-resource">Learn more</Trans>
|
||||
|
||||
Vendored
+1
-1
@@ -50,7 +50,7 @@ export const BUNDLE_IDENTIFIER: string =
|
||||
|
||||
/**
|
||||
* This will always be in the format of YYMMDDHH, so that it always increases
|
||||
* for each build. This should only be used for StatSig reporting and shouldn't
|
||||
* for each build. This should only be used for analytics reporting and shouldn't
|
||||
* be used to identify a specific bundle.
|
||||
*/
|
||||
export const BUNDLE_DATE: number =
|
||||
|
||||
@@ -6,11 +6,11 @@ import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {isBskyCustomFeedUrl} from '#/lib/strings/url-helpers'
|
||||
import {logger} from '#/logger'
|
||||
import {atoms as a, utils} from '#/alf'
|
||||
import {Live_Stroke2_Corner0_Rounded as LiveIcon} from '#/components/icons/Live'
|
||||
import {Link} from '#/components/Link'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {
|
||||
type LiveEventFeed,
|
||||
type LiveEventFeedMetricContext,
|
||||
@@ -26,6 +26,7 @@ export function LiveEventFeedCardCompact({
|
||||
metricContext: LiveEventFeedMetricContext
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
|
||||
const layout = feed.layouts.compact
|
||||
const overlayColor = layout.overlayColor
|
||||
@@ -39,7 +40,7 @@ export function LiveEventFeedCardCompact({
|
||||
}, [feed.url])
|
||||
|
||||
useEffect(() => {
|
||||
logger.metric('liveEvents:feedBanner:seen', {
|
||||
ax.metric('liveEvents:feedBanner:seen', {
|
||||
feed: feed.url,
|
||||
context: metricContext,
|
||||
})
|
||||
@@ -52,7 +53,7 @@ export function LiveEventFeedCardCompact({
|
||||
label={_(msg`Live event happening now: ${feed.title}`)}
|
||||
style={[a.w_full]}
|
||||
onPress={() => {
|
||||
logger.metric('liveEvents:feedBanner:click', {
|
||||
ax.metric('liveEvents:feedBanner:click', {
|
||||
feed: feed.url,
|
||||
context: metricContext,
|
||||
})
|
||||
|
||||
@@ -6,10 +6,10 @@ import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {isBskyCustomFeedUrl} from '#/lib/strings/url-helpers'
|
||||
import {logger} from '#/logger'
|
||||
import {atoms as a, useBreakpoints, utils} from '#/alf'
|
||||
import {Link} from '#/components/Link'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {
|
||||
type LiveEventFeed,
|
||||
type LiveEventFeedMetricContext,
|
||||
@@ -24,6 +24,7 @@ export function LiveEventFeedCardWide({
|
||||
feed: LiveEventFeed
|
||||
metricContext: LiveEventFeedMetricContext
|
||||
}) {
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const {gtPhone} = useBreakpoints()
|
||||
|
||||
@@ -38,8 +39,9 @@ export function LiveEventFeedCardWide({
|
||||
return '/'
|
||||
}, [feed.url])
|
||||
|
||||
// TODO double check this
|
||||
useEffect(() => {
|
||||
logger.metric('liveEvents:feedBanner:seen', {
|
||||
ax.metric('liveEvents:feedBanner:seen', {
|
||||
feed: feed.url,
|
||||
context: metricContext,
|
||||
})
|
||||
@@ -52,7 +54,7 @@ export function LiveEventFeedCardWide({
|
||||
label={_(msg`Live event happening now: ${feed.title}`)}
|
||||
style={[a.w_full]}
|
||||
onPress={() => {
|
||||
logger.metric('liveEvents:feedBanner:click', {
|
||||
ax.metric('liveEvents:feedBanner:click', {
|
||||
feed: feed.url,
|
||||
context: metricContext,
|
||||
})
|
||||
|
||||
@@ -2,12 +2,12 @@ import {useEffect} from 'react'
|
||||
import {type Agent, AppBskyActorDefs, asPredicate} from '@atproto/api'
|
||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {logger} from '#/logger'
|
||||
import {
|
||||
preferencesQueryKey,
|
||||
usePreferencesQuery,
|
||||
} from '#/state/queries/preferences'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_WEB} from '#/env'
|
||||
import * as env from '#/env'
|
||||
import {
|
||||
@@ -63,6 +63,7 @@ export function useUpdateLiveEventPreferences(props: {
|
||||
undoAction: LiveEventPreferencesAction | null
|
||||
}) => void
|
||||
}) {
|
||||
const ax = useAnalytics()
|
||||
const queryClient = useQueryClient()
|
||||
const agent = useAgent()
|
||||
|
||||
@@ -116,7 +117,7 @@ export function useUpdateLiveEventPreferences(props: {
|
||||
case 'hideFeed':
|
||||
case 'unhideFeed': {
|
||||
if (!props.feed) {
|
||||
logger.error(
|
||||
ax.logger.error(
|
||||
`useUpdateLiveEventPreferences: feed is missing, but required for hiding/unhiding`,
|
||||
{
|
||||
action,
|
||||
@@ -125,7 +126,7 @@ export function useUpdateLiveEventPreferences(props: {
|
||||
break
|
||||
}
|
||||
|
||||
logger.metric(
|
||||
ax.metric(
|
||||
action.type === 'hideFeed'
|
||||
? 'liveEvents:feedBanner:hide'
|
||||
: 'liveEvents:feedBanner:unhide',
|
||||
@@ -138,11 +139,11 @@ export function useUpdateLiveEventPreferences(props: {
|
||||
}
|
||||
case 'toggleHideAllFeeds': {
|
||||
if (prefs!.hideAllFeeds) {
|
||||
logger.metric('liveEvents:hideAllFeedBanners', {
|
||||
ax.metric('liveEvents:hideAllFeedBanners', {
|
||||
context: props.metricContext,
|
||||
})
|
||||
} else {
|
||||
logger.metric('liveEvents:unhideAllFeedBanners', {
|
||||
ax.metric('liveEvents:unhideAllFeedBanners', {
|
||||
context: props.metricContext,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ const called: Record<OnceKey, boolean> = {
|
||||
[OnceKey.PreferencesThread]: false,
|
||||
}
|
||||
|
||||
// TODO dedupe with runCallbackOnce
|
||||
export function useCallOnce(key: OnceKey) {
|
||||
return useCallback(
|
||||
(cb: () => void) => {
|
||||
|
||||
@@ -5,10 +5,10 @@ import * as WebBrowser from 'expo-web-browser'
|
||||
|
||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||
import {parseLinkingUrl} from '#/lib/parseLinkingUrl'
|
||||
import {logger} from '#/logger'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useCloseAllActiveElements} from '#/state/util'
|
||||
import {useIntentDialogs} from '#/components/intents/IntentDialogs'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_IOS, IS_NATIVE} from '#/env'
|
||||
import {Referrer} from '../../../modules/expo-bluesky-swiss-army'
|
||||
import {useApplyPullRequestOTAUpdate} from './useOTAUpdates'
|
||||
@@ -22,6 +22,7 @@ let previousIntentUrl = ''
|
||||
|
||||
export function useIntentHandler() {
|
||||
const incomingUrl = Linking.useLinkingURL()
|
||||
const ax = useAnalytics()
|
||||
const composeIntent = useComposeIntent()
|
||||
const verifyEmailIntent = useVerifyEmailIntent()
|
||||
const {currentAccount} = useSession()
|
||||
@@ -36,7 +37,7 @@ export function useIntentHandler() {
|
||||
|
||||
const referrerInfo = Referrer.getReferrerInfo()
|
||||
if (referrerInfo && referrerInfo.hostname !== 'bsky.app') {
|
||||
logger.metric('deepLink:referrerReceived', {
|
||||
ax.metric('deepLink:referrerReceived', {
|
||||
to: url,
|
||||
referrer: referrerInfo?.referrer,
|
||||
hostname: referrerInfo?.hostname,
|
||||
@@ -95,6 +96,7 @@ export function useIntentHandler() {
|
||||
}
|
||||
}, [
|
||||
incomingUrl,
|
||||
ax,
|
||||
composeIntent,
|
||||
verifyEmailIntent,
|
||||
currentAccount,
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import {truncateAndInvalidate} from '#/state/queries/util'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
||||
import {useCloseAllActiveElements} from '#/state/util'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_ANDROID, IS_IOS} from '#/env'
|
||||
import {resetToTab} from '#/Navigation'
|
||||
import {router} from '#/routes'
|
||||
@@ -75,6 +76,8 @@ let storedAccountSwitchPayload: NotificationPayload
|
||||
let lastHandledNotificationDateDedupe = 0
|
||||
|
||||
export function useNotificationsHandler() {
|
||||
const ax = useAnalytics()
|
||||
const logger = ax.logger.useContext(ax.logger.Context.Notifications)
|
||||
const queryClient = useQueryClient()
|
||||
const {currentAccount, accounts} = useSession()
|
||||
const {onPressSwitchAccount} = useAccountSwitcher()
|
||||
@@ -190,7 +193,7 @@ export function useNotificationsHandler() {
|
||||
if (!payload) return
|
||||
|
||||
if (payload.reason === 'chat-message') {
|
||||
notyLogger.debug(`useNotificationsHandler: handling chat message`, {
|
||||
logger.debug(`useNotificationsHandler: handling chat message`, {
|
||||
payload,
|
||||
})
|
||||
|
||||
@@ -250,7 +253,7 @@ export function useNotificationsHandler() {
|
||||
const [screen, params] = router.matchPath(url)
|
||||
// @ts-expect-error router is not typed :/ -sfn
|
||||
navigation.navigate('HomeTab', {screen, params})
|
||||
notyLogger.debug(`useNotificationsHandler: navigate`, {
|
||||
logger.debug(`useNotificationsHandler: navigate`, {
|
||||
screen,
|
||||
params,
|
||||
})
|
||||
@@ -264,7 +267,7 @@ export function useNotificationsHandler() {
|
||||
|
||||
if (!payload) return DEFAULT_HANDLER_OPTIONS
|
||||
|
||||
notyLogger.debug('useNotificationsHandler: incoming', {e, payload})
|
||||
logger.debug('useNotificationsHandler: incoming', {e, payload})
|
||||
|
||||
if (
|
||||
payload.reason === 'chat-message' &&
|
||||
@@ -290,7 +293,7 @@ export function useNotificationsHandler() {
|
||||
if (e.notification.date === lastHandledNotificationDateDedupe) return
|
||||
lastHandledNotificationDateDedupe = e.notification.date
|
||||
|
||||
notyLogger.debug('useNotificationsHandler: response received', {
|
||||
logger.debug('useNotificationsHandler: response received', {
|
||||
actionIdentifier: e.actionIdentifier,
|
||||
})
|
||||
|
||||
@@ -301,15 +304,14 @@ export function useNotificationsHandler() {
|
||||
const payload = getNotificationPayload(e.notification)
|
||||
|
||||
if (payload) {
|
||||
notyLogger.debug(
|
||||
logger.debug(
|
||||
'User pressed a notification, opening notifications tab',
|
||||
{},
|
||||
)
|
||||
notyLogger.metric(
|
||||
'notifications:openApp',
|
||||
{reason: payload.reason, causedBoot: false},
|
||||
{statsig: false},
|
||||
)
|
||||
ax.metric('notifications:openApp', {
|
||||
reason: payload.reason,
|
||||
causedBoot: false,
|
||||
})
|
||||
|
||||
invalidateCachedUnreadPage()
|
||||
truncateAndInvalidate(queryClient, RQKEY_NOTIFS('all'))
|
||||
@@ -322,7 +324,7 @@ export function useNotificationsHandler() {
|
||||
truncateAndInvalidate(queryClient, RQKEY_NOTIFS('mentions'))
|
||||
}
|
||||
|
||||
notyLogger.debug('Notifications: handleNotification', {
|
||||
logger.debug('Notifications: handleNotification', {
|
||||
content: e.notification.request.content,
|
||||
payload: payload,
|
||||
})
|
||||
@@ -330,7 +332,7 @@ export function useNotificationsHandler() {
|
||||
handleNotification(payload)
|
||||
Notifications.dismissAllNotificationsAsync()
|
||||
} else {
|
||||
notyLogger.error('useNotificationsHandler: received no payload', {
|
||||
logger.error('useNotificationsHandler: received no payload', {
|
||||
identifier: e.notification.request.identifier,
|
||||
})
|
||||
}
|
||||
@@ -350,6 +352,8 @@ export function useNotificationsHandler() {
|
||||
responseReceivedListener.remove()
|
||||
}
|
||||
}, [
|
||||
ax,
|
||||
logger,
|
||||
queryClient,
|
||||
currentAccount,
|
||||
currentConvoId,
|
||||
|
||||
@@ -12,8 +12,7 @@ import {
|
||||
|
||||
import {isNetworkError} from '#/lib/strings/errors'
|
||||
import {logger} from '#/logger'
|
||||
import {IS_ANDROID, IS_IOS} from '#/env'
|
||||
import {IS_TESTFLIGHT} from '#/env'
|
||||
import {IS_ANDROID, IS_IOS, IS_TESTFLIGHT} from '#/env'
|
||||
|
||||
const MINIMUM_MINIMIZE_TIME = 15 * 60e3
|
||||
|
||||
@@ -170,7 +169,7 @@ export function useOTAUpdates() {
|
||||
return
|
||||
}
|
||||
|
||||
// We use this setTimeout to allow Statsig to initialize before we check for an update
|
||||
// We use this setTimeout to allow analytics to initialize before we check for an update
|
||||
// For Testflight users, we can prompt the user to update immediately whenever there's an available update. This
|
||||
// is suspect however with the Apple App Store guidelines, so we don't want to prompt production users to update
|
||||
// immediately.
|
||||
|
||||
@@ -2,7 +2,6 @@ import {useCallback} from 'react'
|
||||
import {Linking} from 'react-native'
|
||||
import * as WebBrowser from 'expo-web-browser'
|
||||
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {
|
||||
createBskyAppAbsoluteUrl,
|
||||
createProxiedUrl,
|
||||
@@ -16,9 +15,11 @@ import {useInAppBrowser} from '#/state/preferences/in-app-browser'
|
||||
import {useTheme} from '#/alf'
|
||||
import {useDialogContext} from '#/components/Dialog'
|
||||
import {useGlobalDialogsControlContext} from '#/components/dialogs/Context'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
|
||||
export function useOpenLink() {
|
||||
const ax = useAnalytics()
|
||||
const enabled = useInAppBrowser()
|
||||
const t = useTheme()
|
||||
const dialogContext = useDialogContext()
|
||||
@@ -31,7 +32,7 @@ export function useOpenLink() {
|
||||
}
|
||||
|
||||
if (!isBskyAppUrl(url)) {
|
||||
logEvent('link:clicked', {
|
||||
ax.metric('link:clicked', {
|
||||
domain: toNiceDomain(url),
|
||||
url,
|
||||
})
|
||||
@@ -72,7 +73,7 @@ export function useOpenLink() {
|
||||
}
|
||||
Linking.openURL(url)
|
||||
},
|
||||
[enabled, inAppBrowserConsentControl, t, dialogContext],
|
||||
[ax, enabled, inAppBrowserConsentControl, t, dialogContext],
|
||||
)
|
||||
|
||||
return openLink
|
||||
|
||||
@@ -2,8 +2,7 @@ import {useCallback, useEffect} from 'react'
|
||||
import {Platform} from 'react-native'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
import {getBadgeCountAsync, setBadgeCountAsync} from 'expo-notifications'
|
||||
import {type AtpAgent} from '@atproto/api'
|
||||
import {type AppBskyNotificationRegisterPush} from '@atproto/api'
|
||||
import {type AppBskyNotificationRegisterPush, type AtpAgent} from '@atproto/api'
|
||||
import debounce from 'lodash.debounce'
|
||||
|
||||
import {
|
||||
@@ -16,8 +15,8 @@ import {isNetworkError} from '#/lib/strings/errors'
|
||||
import {type SessionAccount, useAgent, useSession} from '#/state/session'
|
||||
import BackgroundNotificationHandler from '#/../modules/expo-background-notification-handler'
|
||||
import {useAgeAssurance} from '#/ageAssurance'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
import {IS_DEV} from '#/env'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_DEV, IS_NATIVE} from '#/env'
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -227,6 +226,7 @@ export function useNotificationsRegistration() {
|
||||
}
|
||||
|
||||
export function useRequestNotificationsPermission() {
|
||||
const ax = useAnalytics()
|
||||
const {currentAccount} = useSession()
|
||||
const getAndRegisterPushToken = useGetAndRegisterPushToken()
|
||||
|
||||
@@ -251,7 +251,7 @@ export function useRequestNotificationsPermission() {
|
||||
|
||||
const res = await Notifications.requestPermissionsAsync()
|
||||
|
||||
notyLogger.metric(`notifications:request`, {
|
||||
ax.metric(`notifications:request`, {
|
||||
context: context,
|
||||
status: res.status,
|
||||
})
|
||||
|
||||
@@ -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'
|
||||
@@ -1,26 +0,0 @@
|
||||
import type React from 'react'
|
||||
|
||||
import {type Gate} from './gates'
|
||||
|
||||
/**
|
||||
* @deprecated use `logger.metric()` instead
|
||||
*/
|
||||
export function logEvent(
|
||||
_eventName: string,
|
||||
_rawMetadata: any,
|
||||
_options: {
|
||||
/**
|
||||
* Send to our data lake only, not to StatSig
|
||||
*/
|
||||
lake?: boolean
|
||||
} = {lake: false},
|
||||
) {}
|
||||
|
||||
const fn = () => false
|
||||
export function useGate(): (_gateName: Gate, _options?: any) => boolean {
|
||||
return fn
|
||||
}
|
||||
|
||||
export function Provider({children}: {children: React.ReactNode}) {
|
||||
return children
|
||||
}
|
||||
@@ -45,7 +45,7 @@ describe('general functionality', () => {
|
||||
|
||||
logger.addTransport(mockTransport)
|
||||
|
||||
const extra = {foo: true}
|
||||
const extra = {foo: true, metadata: {}}
|
||||
logger.warn('message', extra)
|
||||
|
||||
expect(mockTransport).toHaveBeenCalledWith(
|
||||
@@ -71,7 +71,7 @@ describe('general functionality', () => {
|
||||
LogLevel.Warn,
|
||||
undefined,
|
||||
'a',
|
||||
{},
|
||||
{metadata: {}},
|
||||
timestamp,
|
||||
)
|
||||
|
||||
@@ -81,7 +81,7 @@ describe('general functionality', () => {
|
||||
LogLevel.Warn,
|
||||
undefined,
|
||||
'b',
|
||||
{},
|
||||
{metadata: {}},
|
||||
timestamp,
|
||||
)
|
||||
|
||||
@@ -91,7 +91,7 @@ describe('general functionality', () => {
|
||||
LogLevel.Warn,
|
||||
undefined,
|
||||
'c',
|
||||
{},
|
||||
{metadata: {}},
|
||||
timestamp,
|
||||
)
|
||||
|
||||
@@ -256,7 +256,7 @@ describe('general functionality', () => {
|
||||
LogLevel.Warn,
|
||||
undefined,
|
||||
'warn',
|
||||
{},
|
||||
{metadata: {}},
|
||||
timestamp,
|
||||
)
|
||||
})
|
||||
@@ -276,7 +276,7 @@ describe('create', () => {
|
||||
LogLevel.Info,
|
||||
Logger.Context.Default,
|
||||
message,
|
||||
{},
|
||||
{metadata: {}},
|
||||
timestamp,
|
||||
)
|
||||
})
|
||||
@@ -300,7 +300,7 @@ describe('debug contexts', () => {
|
||||
LogLevel.Debug,
|
||||
'specific',
|
||||
message,
|
||||
{},
|
||||
{metadata: {}},
|
||||
timestamp,
|
||||
)
|
||||
})
|
||||
@@ -323,7 +323,7 @@ describe('debug contexts', () => {
|
||||
LogLevel.Debug,
|
||||
'namespace:foo',
|
||||
message,
|
||||
{},
|
||||
{metadata: {}},
|
||||
timestamp,
|
||||
)
|
||||
})
|
||||
@@ -345,7 +345,7 @@ describe('debug contexts', () => {
|
||||
LogLevel.Debug,
|
||||
'namespace:bar:baz',
|
||||
message,
|
||||
{},
|
||||
{metadata: {}},
|
||||
timestamp,
|
||||
)
|
||||
})
|
||||
@@ -367,7 +367,7 @@ describe('supports levels', () => {
|
||||
LogLevel.Debug,
|
||||
undefined,
|
||||
message,
|
||||
{},
|
||||
{metadata: {}},
|
||||
timestamp,
|
||||
)
|
||||
|
||||
@@ -376,7 +376,7 @@ describe('supports levels', () => {
|
||||
LogLevel.Info,
|
||||
undefined,
|
||||
message,
|
||||
{},
|
||||
{metadata: {}},
|
||||
timestamp,
|
||||
)
|
||||
|
||||
@@ -385,7 +385,7 @@ describe('supports levels', () => {
|
||||
LogLevel.Warn,
|
||||
undefined,
|
||||
message,
|
||||
{},
|
||||
{metadata: {}},
|
||||
timestamp,
|
||||
)
|
||||
|
||||
@@ -395,7 +395,7 @@ describe('supports levels', () => {
|
||||
LogLevel.Error,
|
||||
undefined,
|
||||
e,
|
||||
{},
|
||||
{metadata: {}},
|
||||
timestamp,
|
||||
)
|
||||
})
|
||||
@@ -418,7 +418,7 @@ describe('supports levels', () => {
|
||||
LogLevel.Info,
|
||||
undefined,
|
||||
message,
|
||||
{},
|
||||
{metadata: {}},
|
||||
timestamp,
|
||||
)
|
||||
})
|
||||
@@ -444,7 +444,7 @@ describe('supports levels', () => {
|
||||
LogLevel.Warn,
|
||||
undefined,
|
||||
message,
|
||||
{},
|
||||
{metadata: {}},
|
||||
timestamp,
|
||||
)
|
||||
})
|
||||
@@ -474,7 +474,7 @@ describe('supports levels', () => {
|
||||
LogLevel.Error,
|
||||
undefined,
|
||||
e,
|
||||
{},
|
||||
{metadata: {}},
|
||||
timestamp,
|
||||
)
|
||||
})
|
||||
|
||||
+1
-17
@@ -10,7 +10,6 @@ import {
|
||||
type Transport,
|
||||
} from '#/logger/types'
|
||||
import {enabledLogLevels} from '#/logger/util'
|
||||
import {type Events as Metrics} from '#/analytics/metrics/types'
|
||||
import {ENV} from '#/env'
|
||||
|
||||
const TRANSPORTS: Transport[] = (function configureTransports() {
|
||||
@@ -97,21 +96,6 @@ export class Logger {
|
||||
this.transport({level: LogLevel.Error, message: error, metadata})
|
||||
}
|
||||
|
||||
metric<E extends keyof Metrics>(
|
||||
event: E & string,
|
||||
metadata: Metrics[E],
|
||||
_: {
|
||||
/**
|
||||
* Optionally also send to StatSig
|
||||
*/
|
||||
statsig?: boolean
|
||||
} = {statsig: true},
|
||||
) {
|
||||
for (const transport of this.transports) {
|
||||
transport(LogLevel.Info, LogContext.Metric, event, metadata, Date.now())
|
||||
}
|
||||
}
|
||||
|
||||
addTransport(transport: Transport) {
|
||||
this.transports.push(transport)
|
||||
return () => {
|
||||
@@ -139,7 +123,7 @@ export class Logger {
|
||||
const timestamp = Date.now()
|
||||
const meta: Metadata = {
|
||||
...metadata,
|
||||
inherited: this.inheritedMetadata,
|
||||
metadata: this.inheritedMetadata,
|
||||
}
|
||||
|
||||
// send every log to syslog
|
||||
|
||||
@@ -24,6 +24,14 @@ export function prepareMetadata(
|
||||
if (value instanceof Error) {
|
||||
value = value.toString()
|
||||
}
|
||||
if (
|
||||
typeof value === 'object' &&
|
||||
value !== null &&
|
||||
Object.keys(value).length === 0 &&
|
||||
value.constructor === Object
|
||||
) {
|
||||
return acc
|
||||
}
|
||||
return {...acc, [key]: value}
|
||||
}, {})
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import {
|
||||
type CommonNavigatorParams,
|
||||
type NativeStackScreenProps,
|
||||
} from '#/lib/routes/types'
|
||||
import {logger} from '#/logger'
|
||||
import {useBookmarkMutation} from '#/state/queries/bookmarks/useBookmarkMutation'
|
||||
import {useBookmarksQuery} from '#/state/queries/bookmarks/useBookmarksQuery'
|
||||
import {useSetMinimalShellMode} from '#/state/shell'
|
||||
@@ -37,18 +36,20 @@ import {ListFooter} from '#/components/Lists'
|
||||
import * as Skele from '#/components/Skeleton'
|
||||
import * as toast from '#/components/Toast'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_IOS} from '#/env'
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Bookmarks'>
|
||||
|
||||
export function BookmarksScreen({}: Props) {
|
||||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
const ax = useAnalytics()
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
setMinimalShellMode(false)
|
||||
logger.metric('bookmarks:view', {})
|
||||
}, [setMinimalShellMode]),
|
||||
ax.metric('bookmarks:view', {})
|
||||
}, [setMinimalShellMode, ax]),
|
||||
)
|
||||
|
||||
return (
|
||||
@@ -144,7 +145,7 @@ function BookmarksInner() {
|
||||
key: bookmark.item.uri,
|
||||
bookmark: {
|
||||
...bookmark,
|
||||
item: bookmark.item as $Typed<AppBskyFeedDefs.NotFoundPost>,
|
||||
item: bookmark.item,
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -154,7 +155,7 @@ function BookmarksInner() {
|
||||
key: bookmark.item.uri,
|
||||
bookmark: {
|
||||
...bookmark,
|
||||
item: bookmark.item as $Typed<AppBskyFeedDefs.PostView>,
|
||||
item: bookmark.item,
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -270,6 +271,25 @@ function BookmarkNotFound({
|
||||
)
|
||||
}
|
||||
|
||||
function BookmarkItem({
|
||||
item,
|
||||
hideTopBorder,
|
||||
}: {
|
||||
item: Extract<ListItem, {type: 'bookmark'}>
|
||||
hideTopBorder: boolean
|
||||
}) {
|
||||
const ax = useAnalytics()
|
||||
return (
|
||||
<Post
|
||||
post={item.bookmark.item}
|
||||
hideTopBorder={hideTopBorder}
|
||||
onBeforePress={() => {
|
||||
ax.metric('bookmarks:post-clicked', {})
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function BookmarksEmpty() {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
@@ -301,15 +321,7 @@ function renderItem({item, index}: {item: ListItem; index: number}) {
|
||||
return <BookmarksEmpty />
|
||||
}
|
||||
case 'bookmark': {
|
||||
return (
|
||||
<Post
|
||||
post={item.bookmark.item}
|
||||
hideTopBorder={index === 0}
|
||||
onBeforePress={() => {
|
||||
logger.metric('bookmarks:post-clicked', {})
|
||||
}}
|
||||
/>
|
||||
)
|
||||
return <BookmarkItem item={item} hideTopBorder={index === 0} />
|
||||
}
|
||||
case 'bookmarkNotFound': {
|
||||
return (
|
||||
|
||||
@@ -3,7 +3,6 @@ import {View} from 'react-native'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {logger} from '#/logger'
|
||||
import {type SessionAccount, useSession, useSessionApi} from '#/state/session'
|
||||
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
||||
@@ -12,6 +11,7 @@ import {atoms as a, web} from '#/alf'
|
||||
import {AccountList} from '#/components/AccountList'
|
||||
import {Button, ButtonText} from '#/components/Button'
|
||||
import * as TextField from '#/components/forms/TextField'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {FormContainer} from './FormContainer'
|
||||
|
||||
export const ChooseAccountForm = ({
|
||||
@@ -23,6 +23,7 @@ export const ChooseAccountForm = ({
|
||||
}) => {
|
||||
const [pendingDid, setPendingDid] = React.useState<string | null>(null)
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const {currentAccount} = useSession()
|
||||
const {resumeSession} = useSessionApi()
|
||||
const {setShowLoggedOut} = useLoggedOutViewControls()
|
||||
@@ -46,7 +47,7 @@ export const ChooseAccountForm = ({
|
||||
try {
|
||||
setPendingDid(account.did)
|
||||
await resumeSession(account, true)
|
||||
logEvent('account:loggedIn', {
|
||||
ax.metric('account:loggedIn', {
|
||||
logContext: 'ChooseAccountForm',
|
||||
withPassword: false,
|
||||
})
|
||||
|
||||
@@ -3,9 +3,7 @@ import {ActivityIndicator, View} from 'react-native'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {isNetworkError} from '#/lib/strings/errors'
|
||||
import {cleanError} from '#/lib/strings/errors'
|
||||
import {cleanError, isNetworkError} from '#/lib/strings/errors'
|
||||
import {checkAndFormatResetCode} from '#/lib/strings/password'
|
||||
import {logger} from '#/logger'
|
||||
import {Agent} from '#/state/session/agent'
|
||||
@@ -16,6 +14,7 @@ import * as TextField from '#/components/forms/TextField'
|
||||
import {Lock_Stroke2_Corner0_Rounded as Lock} from '#/components/icons/Lock'
|
||||
import {Ticket_Stroke2_Corner0_Rounded as Ticket} from '#/components/icons/Ticket'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {FormContainer} from './FormContainer'
|
||||
|
||||
export const SetNewPasswordForm = ({
|
||||
@@ -33,6 +32,7 @@ export const SetNewPasswordForm = ({
|
||||
}) => {
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
|
||||
const [isProcessing, setIsProcessing] = useState<boolean>(false)
|
||||
const [resetCode, setResetCode] = useState<string>('')
|
||||
@@ -49,7 +49,7 @@ export const SetNewPasswordForm = ({
|
||||
msg`You have entered an invalid code. It should look like XXXXX-XXXXX.`,
|
||||
),
|
||||
)
|
||||
logEvent('signin:passwordResetFailure', {})
|
||||
ax.metric('signin:passwordResetFailure', {})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -69,11 +69,11 @@ export const SetNewPasswordForm = ({
|
||||
password,
|
||||
})
|
||||
onPasswordSet()
|
||||
logEvent('signin:passwordResetSuccess', {})
|
||||
ax.metric('signin:passwordResetSuccess', {})
|
||||
} catch (e: any) {
|
||||
const errMsg = e.toString()
|
||||
logger.warn('Failed to set new password', {error: e})
|
||||
logEvent('signin:passwordResetFailure', {})
|
||||
ax.metric('signin:passwordResetFailure', {})
|
||||
setIsProcessing(false)
|
||||
if (isNetworkError(e)) {
|
||||
setError(
|
||||
|
||||
@@ -5,7 +5,6 @@ import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {DEFAULT_SERVICE} from '#/lib/constants'
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {logger} from '#/logger'
|
||||
import {useServiceQuery} from '#/state/queries/service'
|
||||
import {type SessionAccount, useSession} from '#/state/session'
|
||||
@@ -17,6 +16,7 @@ import {PasswordUpdatedForm} from '#/screens/Login/PasswordUpdatedForm'
|
||||
import {SetNewPasswordForm} from '#/screens/Login/SetNewPasswordForm'
|
||||
import {atoms as a, native} from '#/alf'
|
||||
import {ScreenTransition} from '#/components/ScreenTransition'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {ChooseAccountForm} from './ChooseAccountForm'
|
||||
|
||||
enum Forms {
|
||||
@@ -64,6 +64,7 @@ export const Login = ({onPressBack}: {onPressBack: () => void}) => {
|
||||
'Forward' | 'Backward'
|
||||
>('Forward')
|
||||
|
||||
const ax = useAnalytics()
|
||||
const {
|
||||
data: serviceDescription,
|
||||
error: serviceError,
|
||||
@@ -96,7 +97,7 @@ export const Login = ({onPressBack}: {onPressBack: () => void}) => {
|
||||
logger.warn(`Failed to fetch service description for ${serviceUrl}`, {
|
||||
error: String(serviceError),
|
||||
})
|
||||
logEvent('signin:hostingProviderFailedResolution', {})
|
||||
ax.metric('signin:hostingProviderFailedResolution', {})
|
||||
} else {
|
||||
setError('')
|
||||
}
|
||||
@@ -104,19 +105,19 @@ export const Login = ({onPressBack}: {onPressBack: () => void}) => {
|
||||
|
||||
const onPressForgotPassword = () => {
|
||||
gotoForm(Forms.ForgotPassword)
|
||||
logEvent('signin:forgotPasswordPressed', {})
|
||||
ax.metric('signin:forgotPasswordPressed', {})
|
||||
}
|
||||
|
||||
const handlePressBack = () => {
|
||||
onPressBack()
|
||||
setScreenTransitionDirection('Backward')
|
||||
logEvent('signin:backPressed', {
|
||||
ax.metric('signin:backPressed', {
|
||||
failedAttemptsCount: failedAttemptCountRef.current,
|
||||
})
|
||||
}
|
||||
|
||||
const onAttemptSuccess = () => {
|
||||
logEvent('signin:success', {
|
||||
ax.metric('signin:success', {
|
||||
isUsingCustomProvider: serviceUrl !== DEFAULT_SERVICE,
|
||||
timeTakenSeconds: Math.round((Date.now() - startTimeRef.current) / 1000),
|
||||
failedAttemptsCount: failedAttemptCountRef.current,
|
||||
|
||||
@@ -13,7 +13,6 @@ import {useQueryClient} from '@tanstack/react-query'
|
||||
import {GestureActionView} from '#/lib/custom-animations/GestureActionView'
|
||||
import {useHaptics} from '#/lib/haptics'
|
||||
import {decrementBadgeCount} from '#/lib/notifications/notifications'
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {
|
||||
postUriToRelativePath,
|
||||
@@ -45,6 +44,7 @@ import {createPortalGroup} from '#/components/Portal'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useSimpleVerificationState} from '#/components/verification'
|
||||
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
@@ -96,6 +96,7 @@ function ChatListItemReady({
|
||||
showMenu?: boolean
|
||||
children?: React.ReactNode
|
||||
}) {
|
||||
const ax = useAnalytics()
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const {currentAccount} = useSession()
|
||||
@@ -290,10 +291,10 @@ function ChatListItemReady({
|
||||
menuControl.open()
|
||||
return false
|
||||
} else {
|
||||
logEvent('chat:open', {logContext: 'ChatsList'})
|
||||
ax.metric('chat:open', {logContext: 'ChatsList'})
|
||||
}
|
||||
},
|
||||
[isDeletedAccount, menuControl, queryClient, profile, convo],
|
||||
[ax, isDeletedAccount, menuControl, queryClient, profile, convo],
|
||||
)
|
||||
|
||||
const onLongPress = useCallback(() => {
|
||||
|
||||
@@ -3,7 +3,6 @@ import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {urls} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {
|
||||
usePreferencesQuery,
|
||||
type UsePreferencesQueryResponse,
|
||||
@@ -17,9 +16,11 @@ import {CircleCheck_Stroke2_Corner0_Rounded as CircleCheck} from '#/components/i
|
||||
import * as Layout from '#/components/Layout'
|
||||
import {InlineLinkText} from '#/components/Link'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
export function Screen() {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const gutters = useGutters(['base'])
|
||||
const {data: preferences} = usePreferencesQuery()
|
||||
|
||||
@@ -51,13 +52,9 @@ export function Screen() {
|
||||
}),
|
||||
)}
|
||||
onPress={() => {
|
||||
logger.metric(
|
||||
'verification:learn-more',
|
||||
{
|
||||
location: 'verificationSettings',
|
||||
},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('verification:learn-more', {
|
||||
location: 'verificationSettings',
|
||||
})
|
||||
}}>
|
||||
Learn more here.
|
||||
</InlineLinkText>
|
||||
|
||||
@@ -2,10 +2,11 @@ import {useCallback, useState} from 'react'
|
||||
import {LayoutAnimationConfig} from 'react-native-reanimated'
|
||||
import {SafeAreaView} from 'react-native-safe-area-context'
|
||||
|
||||
import {logger} from '#/logger'
|
||||
import {useRunCallbackOnce} from '#/lib/runCallbackOnce'
|
||||
import {FindContactsFlow} from '#/components/contacts/FindContactsFlow'
|
||||
import {type Action, type State} from '#/components/contacts/state'
|
||||
import {ScreenTransition} from '#/components/ScreenTransition'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {useOnboardingInternalState} from '../state'
|
||||
|
||||
export function StepFindContacts({
|
||||
@@ -16,6 +17,11 @@ export function StepFindContacts({
|
||||
flowDispatch: React.ActionDispatch<[Action]>
|
||||
}) {
|
||||
const {dispatch} = useOnboardingInternalState()
|
||||
const ax = useAnalytics()
|
||||
|
||||
useRunCallbackOnce(() => {
|
||||
ax.metric('onboarding:contacts:begin', {})
|
||||
})
|
||||
|
||||
const [transitionDirection, setTransitionDirection] = useState<
|
||||
'Forward' | 'Backward'
|
||||
@@ -24,10 +30,10 @@ export function StepFindContacts({
|
||||
const isFinalStep = flowState.step === '4: view matches'
|
||||
const onSkip = useCallback(() => {
|
||||
if (!isFinalStep) {
|
||||
logger.metric('onboarding:contacts:skipPressed', {})
|
||||
ax.metric('onboarding:contacts:skipPressed', {})
|
||||
}
|
||||
dispatch({type: 'next'})
|
||||
}, [dispatch, isFinalStep])
|
||||
}, [dispatch, isFinalStep, ax])
|
||||
|
||||
const canGoBack = flowState.step === '2: verify number'
|
||||
const onBack = useCallback(() => {
|
||||
|
||||
@@ -5,11 +5,13 @@ import {useLingui} from '@lingui/react'
|
||||
import {useQuery} from '@tanstack/react-query'
|
||||
|
||||
import {urls} from '#/lib/constants'
|
||||
import {useRunCallbackOnce} from '#/lib/runCallbackOnce'
|
||||
import {atoms as a} from '#/alf'
|
||||
import {Admonition} from '#/components/Admonition'
|
||||
import {Button, ButtonText} from '#/components/Button'
|
||||
import {ContactsHeroImage} from '#/components/contacts/components/HeroImage'
|
||||
import {InlineLinkText} from '#/components/Link'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {
|
||||
OnboardingControls,
|
||||
OnboardingDescriptionText,
|
||||
@@ -19,9 +21,14 @@ import {
|
||||
import {useOnboardingInternalState} from '../state'
|
||||
|
||||
export function StepFindContactsIntro() {
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const {dispatch} = useOnboardingInternalState()
|
||||
|
||||
useRunCallbackOnce(() => {
|
||||
ax.metric('onboarding:contacts:presented', {})
|
||||
})
|
||||
|
||||
const {data: isAvailable, isSuccess} = useQuery({
|
||||
queryKey: ['contacts-available'],
|
||||
queryFn: async () => await Contacts.isAvailableAsync(),
|
||||
|
||||
@@ -20,7 +20,6 @@ import {
|
||||
VIDEO_SAVED_FEED,
|
||||
} from '#/lib/constants'
|
||||
import {useRequestNotificationsPermission} from '#/lib/notifications/notifications'
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {logger} from '#/logger'
|
||||
import {useSetHasCheckedForStarterPack} from '#/state/preferences/used-starter-packs'
|
||||
import {getAllListMembers} from '#/state/queries/list-members'
|
||||
@@ -46,12 +45,14 @@ import {atoms as a, useBreakpoints} from '#/alf'
|
||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||
import {ArrowRight_Stroke2_Corner0_Rounded as ArrowRight} from '#/components/icons/Arrow'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_WEB} from '#/env'
|
||||
import * as bsky from '#/types/bsky'
|
||||
import {ValuePropositionPager} from './ValuePropositionPager'
|
||||
|
||||
export function StepFinished() {
|
||||
const {state, dispatch} = useOnboardingInternalState()
|
||||
const ax = useAnalytics()
|
||||
const onboardDispatch = useOnboardingDispatch()
|
||||
const [saving, setSaving] = useState(false)
|
||||
const queryClient = useQueryClient()
|
||||
@@ -165,7 +166,7 @@ export function StepFinished() {
|
||||
return next
|
||||
})
|
||||
|
||||
logEvent('onboarding:finished:avatarResult', {
|
||||
ax.metric('onboarding:finished:avatarResult', {
|
||||
avatarResult: profileStepResults.isCreatedAvatar
|
||||
? 'created'
|
||||
: profileStepResults.image
|
||||
@@ -200,7 +201,7 @@ export function StepFinished() {
|
||||
startProgressGuide('follow-10')
|
||||
dispatch({type: 'finish'})
|
||||
onboardDispatch({type: 'finish'})
|
||||
logEvent('onboarding:finished:nextPressed', {
|
||||
ax.metric('onboarding:finished:nextPressed', {
|
||||
usedStarterPack: Boolean(starterPack),
|
||||
starterPackName:
|
||||
starterPack &&
|
||||
@@ -216,13 +217,14 @@ export function StepFinished() {
|
||||
feedsPinned: starterPack?.feeds?.length ?? 0,
|
||||
})
|
||||
if (starterPack && listItems?.length) {
|
||||
logEvent('starterPack:followAll', {
|
||||
ax.metric('starterPack:followAll', {
|
||||
logContext: 'Onboarding',
|
||||
starterPack: starterPack.uri,
|
||||
count: listItems?.length,
|
||||
})
|
||||
}
|
||||
}, [
|
||||
ax,
|
||||
queryClient,
|
||||
agent,
|
||||
dispatch,
|
||||
@@ -255,6 +257,7 @@ function ValueProposition({
|
||||
}) {
|
||||
const [subStep, setSubStep] = useState<0 | 1 | 2>(0)
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const {gtMobile} = useBreakpoints()
|
||||
|
||||
const onPress = () => {
|
||||
@@ -262,10 +265,10 @@ function ValueProposition({
|
||||
finishOnboarding() // has its own metrics
|
||||
} else if (subStep === 1) {
|
||||
setSubStep(2)
|
||||
logger.metric('onboarding:valueProp:stepTwo:nextPressed', {})
|
||||
ax.metric('onboarding:valueProp:stepTwo:nextPressed', {})
|
||||
} else if (subStep === 0) {
|
||||
setSubStep(1)
|
||||
logger.metric('onboarding:valueProp:stepOne:nextPressed', {})
|
||||
ax.metric('onboarding:valueProp:stepOne:nextPressed', {})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,7 +283,7 @@ function ValueProposition({
|
||||
size="small"
|
||||
label={_(msg`Skip introduction and start using your account`)}
|
||||
onPress={() => {
|
||||
logger.metric('onboarding:valueProp:skipPressed', {})
|
||||
ax.metric('onboarding:valueProp:skipPressed', {})
|
||||
finishOnboarding()
|
||||
}}
|
||||
style={[a.bg_transparent]}>
|
||||
|
||||
@@ -4,7 +4,6 @@ import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {interests, useInterestsDisplayNames} from '#/lib/interests'
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {capitalize} from '#/lib/strings/capitalize'
|
||||
import {logger} from '#/logger'
|
||||
import {
|
||||
@@ -19,9 +18,11 @@ import {atoms as a} from '#/alf'
|
||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||
import * as Toggle from '#/components/forms/Toggle'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
export function StepInterests() {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const interestsDisplayNames = useInterestsDisplayNames()
|
||||
|
||||
const {state, dispatch} = useOnboardingInternalState()
|
||||
@@ -40,7 +41,7 @@ export function StepInterests() {
|
||||
selectedInterests,
|
||||
})
|
||||
dispatch({type: 'next'})
|
||||
logEvent('onboarding:interests:nextPressed', {
|
||||
ax.metric('onboarding:interests:nextPressed', {
|
||||
selectedInterests,
|
||||
selectedInterestsLength: selectedInterests.length,
|
||||
})
|
||||
@@ -48,7 +49,7 @@ export function StepInterests() {
|
||||
logger.info(`onboading: error saving interests`)
|
||||
logger.error(e)
|
||||
}
|
||||
}, [selectedInterests, setSaving, dispatch])
|
||||
}, [ax, selectedInterests, setSaving, dispatch])
|
||||
|
||||
return (
|
||||
<View style={[a.align_start, a.gap_sm]} testID="onboardingInterests">
|
||||
|
||||
@@ -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 {logEvent, useGate} from '#/lib/statsig/statsig'
|
||||
import {isCancelledError} from '#/lib/strings/errors'
|
||||
import {logger} from '#/logger'
|
||||
import {
|
||||
@@ -37,6 +36,7 @@ import * as Dialog from '#/components/Dialog'
|
||||
import {useSheetWrapper} from '#/components/Dialog/sheet-wrapper'
|
||||
import {CircleInfo_Stroke2_Corner0_Rounded} from '#/components/icons/CircleInfo'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_NATIVE, IS_WEB} from '#/env'
|
||||
import {type AvatarColor, avatarColors, type Emoji, emojiItems} from './types'
|
||||
|
||||
@@ -66,11 +66,11 @@ const randomColor =
|
||||
avatarColors[Math.floor(Math.random() * avatarColors.length)]
|
||||
|
||||
export function StepProfile() {
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
const {gtMobile} = useBreakpoints()
|
||||
const {requestPhotoAccessIfNeeded} = usePhotoLibraryPermission()
|
||||
const gate = useGate()
|
||||
const requestNotificationsPermission = useRequestNotificationsPermission()
|
||||
|
||||
const creatorControl = Dialog.useDialogControl()
|
||||
@@ -89,7 +89,7 @@ export function StepProfile() {
|
||||
|
||||
React.useEffect(() => {
|
||||
requestNotificationsPermission('StartOnboarding')
|
||||
}, [gate, requestNotificationsPermission])
|
||||
}, [requestNotificationsPermission])
|
||||
|
||||
const sheetWrapper = useSheetWrapper()
|
||||
const openPicker = React.useCallback(
|
||||
@@ -156,8 +156,8 @@ export function StepProfile() {
|
||||
}
|
||||
|
||||
dispatch({type: 'next'})
|
||||
logEvent('onboarding:profile:nextPressed', {})
|
||||
}, [avatar, dispatch])
|
||||
ax.metric('onboarding:profile:nextPressed', {})
|
||||
}, [ax, avatar, dispatch])
|
||||
|
||||
const onDoneCreating = React.useCallback(() => {
|
||||
setAvatar(prev => ({
|
||||
|
||||
@@ -9,7 +9,6 @@ import * as bcp47Match from 'bcp-47-match'
|
||||
import {wait} from '#/lib/async/wait'
|
||||
import {popularInterests, useInterestsDisplayNames} from '#/lib/interests'
|
||||
import {isBlockedOrBlocking, isMuted} from '#/lib/moderation/blocked-and-muted'
|
||||
import {logger} from '#/logger'
|
||||
import {updateProfileShadow} from '#/state/cache/profile-shadow'
|
||||
import {useLanguagePrefs} from '#/state/preferences'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
@@ -30,12 +29,14 @@ import {boostInterests, InterestTabs} from '#/components/InterestTabs'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import * as ProfileCard from '#/components/ProfileCard'
|
||||
import * as toast from '#/components/Toast'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_WEB} from '#/env'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
import {bulkWriteFollows} from '../util'
|
||||
|
||||
export function StepSuggestedAccounts() {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const t = useTheme()
|
||||
const {gtMobile} = useBreakpoints()
|
||||
const moderationOpts = useModerationOpts()
|
||||
@@ -92,7 +93,7 @@ export function StepSuggestedAccounts() {
|
||||
|
||||
const {mutate: followAll, isPending: isFollowingAll} = useMutation({
|
||||
onMutate: () => {
|
||||
logger.metric('onboarding:suggestedAccounts:followAllPressed', {
|
||||
ax.metric('onboarding:suggestedAccounts:followAllPressed', {
|
||||
tab: selectedInterest ?? 'all',
|
||||
numAccounts: followableDids.length,
|
||||
})
|
||||
@@ -132,20 +133,16 @@ export function StepSuggestedAccounts() {
|
||||
(did: string, position: number) => {
|
||||
if (!seenProfilesRef.current.has(did)) {
|
||||
seenProfilesRef.current.add(did)
|
||||
logger.metric(
|
||||
'suggestedUser:seen',
|
||||
{
|
||||
logContext: 'Onboarding',
|
||||
recId: undefined,
|
||||
position,
|
||||
suggestedDid: did,
|
||||
category: selectedInterest,
|
||||
},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('suggestedUser:seen', {
|
||||
logContext: 'Onboarding',
|
||||
recId: undefined,
|
||||
position,
|
||||
suggestedDid: did,
|
||||
category: selectedInterest,
|
||||
})
|
||||
}
|
||||
},
|
||||
[selectedInterest],
|
||||
[ax, selectedInterest],
|
||||
)
|
||||
|
||||
return (
|
||||
@@ -297,6 +294,7 @@ function TabBar({
|
||||
defaultTabLabel?: string
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const interestsDisplayNames = useInterestsDisplayNames()
|
||||
const interests = Object.keys(interestsDisplayNames)
|
||||
.sort(boostInterests(popularInterests))
|
||||
@@ -309,11 +307,7 @@ function TabBar({
|
||||
selectedInterest || (hideDefaultTab ? interests[0] : 'all')
|
||||
}
|
||||
onSelectTab={tab => {
|
||||
logger.metric(
|
||||
'onboarding:suggestedAccounts:tabPressed',
|
||||
{tab: tab},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('onboarding:suggestedAccounts:tabPressed', {tab: tab})
|
||||
onSelectInterest(tab === 'all' ? null : tab)
|
||||
}}
|
||||
interestsDisplayNames={
|
||||
@@ -343,6 +337,7 @@ function SuggestedProfileCard({
|
||||
onSeen: (did: string, position: number) => void
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const cardRef = useRef<View>(null)
|
||||
const hasTrackedRef = useRef(false)
|
||||
|
||||
@@ -403,18 +398,14 @@ function SuggestedProfileCard({
|
||||
withIcon={false}
|
||||
logContext="OnboardingSuggestedAccounts"
|
||||
onFollow={() => {
|
||||
logger.metric(
|
||||
'suggestedUser:follow',
|
||||
{
|
||||
logContext: 'Onboarding',
|
||||
location: 'Card',
|
||||
recId: undefined,
|
||||
position,
|
||||
suggestedDid: profile.did,
|
||||
category,
|
||||
},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('suggestedUser:follow', {
|
||||
logContext: 'Onboarding',
|
||||
location: 'Card',
|
||||
recId: undefined,
|
||||
position,
|
||||
suggestedDid: profile.did,
|
||||
category,
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</ProfileCard.Header>
|
||||
|
||||
@@ -19,6 +19,7 @@ import {Check_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Che
|
||||
import {Loader} from '#/components/Loader'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
const IGNORED_ACCOUNT = 'did:plc:pifkcjimdcfwaxkanzhwxufp'
|
||||
@@ -30,6 +31,7 @@ export function StarterPackCard({
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const {currentAccount} = useSession()
|
||||
const {gtPhone} = useBreakpoints()
|
||||
const agent = useAgent()
|
||||
@@ -89,7 +91,7 @@ export function StarterPackCard({
|
||||
}
|
||||
})
|
||||
Toast.show(_(msg`All accounts have been followed!`), {type: 'success'})
|
||||
logger.metric('starterPack:followAll', {
|
||||
ax.metric('starterPack:followAll', {
|
||||
logContext: 'Onboarding',
|
||||
starterPack: view.uri,
|
||||
count: dids.length,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -172,15 +172,6 @@ export function reducer(
|
||||
}
|
||||
}
|
||||
|
||||
if (a.type === 'next') {
|
||||
if (next.activeStep === 'find-contacts-intro') {
|
||||
logger.metric('onboarding:contacts:presented', {})
|
||||
}
|
||||
if (next.activeStep === 'find-contacts') {
|
||||
logger.metric('onboarding:contacts:begin', {})
|
||||
}
|
||||
}
|
||||
|
||||
const state = {
|
||||
...next,
|
||||
hasPrev: next.activeStep !== 'profile',
|
||||
|
||||
@@ -2,11 +2,11 @@ import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {HITSLOP_10} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {type ThreadPreferences} from '#/state/queries/preferences/useThreadPreferences'
|
||||
import {Button, ButtonIcon} from '#/components/Button'
|
||||
import {SettingsSliderVertical_Stroke2_Corner0_Rounded as SettingsSlider} from '#/components/icons/SettingsSlider'
|
||||
import * as Menu from '#/components/Menu'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
export function HeaderDropdown({
|
||||
sort,
|
||||
@@ -17,6 +17,7 @@ export function HeaderDropdown({
|
||||
ThreadPreferences,
|
||||
'sort' | 'setSort' | 'view' | 'setView'
|
||||
>): React.ReactNode {
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
return (
|
||||
<Menu.Root>
|
||||
@@ -30,7 +31,7 @@ export function HeaderDropdown({
|
||||
shape="round"
|
||||
hitSlop={HITSLOP_10}
|
||||
onPress={() => {
|
||||
logger.metric('thread:click:headerMenuOpen', {})
|
||||
ax.metric('thread:click:headerMenuOpen', {})
|
||||
onPress()
|
||||
}}
|
||||
{...props}>
|
||||
|
||||
@@ -18,7 +18,6 @@ import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {niceDate} from '#/lib/strings/time'
|
||||
import {getTranslatorLink, isPostInLanguage} from '#/locale/helpers'
|
||||
import {logger} from '#/logger'
|
||||
import {
|
||||
POST_TOMBSTONE,
|
||||
type Shadow,
|
||||
@@ -60,6 +59,7 @@ import * as Skele from '#/components/Skeleton'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {VerificationCheckButton} from '#/components/verification/VerificationCheckButton'
|
||||
import {WhoCanReply} from '#/components/WhoCanReply'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
export function ThreadItemAnchor({
|
||||
@@ -177,6 +177,7 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({
|
||||
postSource?: PostSource
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const {openComposer} = useOpenComposer()
|
||||
const {currentAccount, hasSession} = useSession()
|
||||
@@ -281,7 +282,7 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({
|
||||
])
|
||||
|
||||
const onOpenAuthor = () => {
|
||||
logger.metric('post:clickthroughAuthor', {
|
||||
ax.metric('post:clickthroughAuthor', {
|
||||
uri: post.uri,
|
||||
authorDid: post.author.did,
|
||||
logContext: 'PostThreadItem',
|
||||
@@ -298,7 +299,7 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({
|
||||
}
|
||||
|
||||
const onOpenEmbed = () => {
|
||||
logger.metric('post:clickthroughEmbed', {
|
||||
ax.metric('post:clickthroughEmbed', {
|
||||
uri: post.uri,
|
||||
authorDid: post.author.did,
|
||||
logContext: 'PostThreadItem',
|
||||
@@ -540,6 +541,7 @@ function ExpandedPostDetails({
|
||||
isThreadAuthor: boolean
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const {_, i18n} = useLingui()
|
||||
const translate = useTranslate()
|
||||
const isRootPost = !('reply' in post.record)
|
||||
@@ -565,7 +567,7 @@ function ExpandedPostDetails({
|
||||
AppBskyFeedPost.isRecord,
|
||||
)
|
||||
) {
|
||||
logger.metric('translate', {
|
||||
ax.metric('translate', {
|
||||
sourceLanguages: post.record.langs ?? [],
|
||||
targetLanguage: langPrefs.primaryLanguage,
|
||||
textLength: post.record.text.length,
|
||||
@@ -574,7 +576,7 @@ function ExpandedPostDetails({
|
||||
|
||||
return false
|
||||
},
|
||||
[translate, langPrefs, post],
|
||||
[ax, translate, langPrefs, post],
|
||||
)
|
||||
|
||||
return (
|
||||
|
||||
@@ -2,22 +2,23 @@ import {View} from 'react-native'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {logger} from '#/logger'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Button} from '#/components/Button'
|
||||
import {EyeSlash_Stroke2_Corner0_Rounded as EyeSlash} from '#/components/icons/EyeSlash'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
export function ThreadItemShowOtherReplies({onPress}: {onPress: () => void}) {
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const label = _(msg`Show more replies`)
|
||||
|
||||
return (
|
||||
<Button
|
||||
onPress={() => {
|
||||
onPress()
|
||||
logger.metric('thread:click:showOtherReplies', {})
|
||||
ax.metric('thread:click:showOtherReplies', {})
|
||||
}}
|
||||
label={label}>
|
||||
{({hovered, pressed}) => (
|
||||
|
||||
@@ -6,7 +6,6 @@ import {Trans} from '@lingui/macro'
|
||||
import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender'
|
||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||
import {usePostViewTracking} from '#/lib/hooks/usePostViewTracking'
|
||||
import {logger} from '#/logger'
|
||||
import {useFeedFeedback} from '#/state/feed-feedback'
|
||||
import {type ThreadViewOption} from '#/state/queries/preferences/useThreadPreferences'
|
||||
import {
|
||||
@@ -44,11 +43,13 @@ import {
|
||||
import {atoms as a, native, platform, useBreakpoints, web} from '#/alf'
|
||||
import * as Layout from '#/components/Layout'
|
||||
import {ListFooter} from '#/components/Lists'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
const PARENT_CHUNK_SIZE = 5
|
||||
const CHILDREN_CHUNK_SIZE = 50
|
||||
|
||||
export function PostThread({uri}: {uri: string}) {
|
||||
const ax = useAnalytics()
|
||||
const {gtMobile} = useBreakpoints()
|
||||
const {hasSession} = useSession()
|
||||
const initialNumToRender = useInitialNumToRender()
|
||||
@@ -84,18 +85,14 @@ export function PostThread({uri}: {uri: string}) {
|
||||
const post = anchor.value.post
|
||||
seenPostUriRef.current = post.uri
|
||||
|
||||
logger.metric(
|
||||
'post:view',
|
||||
{
|
||||
uri: post.uri,
|
||||
authorDid: post.author.did,
|
||||
logContext: 'Post',
|
||||
feedDescriptor: feedFeedback.feedDescriptor,
|
||||
},
|
||||
{statsig: false},
|
||||
)
|
||||
ax.metric('post:view', {
|
||||
uri: post.uri,
|
||||
authorDid: post.author.did,
|
||||
logContext: 'Post',
|
||||
feedDescriptor: feedFeedback.feedDescriptor,
|
||||
})
|
||||
}
|
||||
}, [anchor, feedFeedback.feedDescriptor])
|
||||
}, [ax, anchor, feedFeedback.feedDescriptor])
|
||||
|
||||
// Track post:view events for parent posts and replies (non-anchor posts)
|
||||
const trackThreadItemView = usePostViewTracking('PostThreadItem')
|
||||
|
||||
@@ -14,7 +14,6 @@ import {useLingui} from '@lingui/react'
|
||||
import {MAX_LABELERS} from '#/lib/constants'
|
||||
import {useHaptics} from '#/lib/haptics'
|
||||
import {isAppLabeler} from '#/lib/moderation'
|
||||
import {logger} from '#/logger'
|
||||
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
||||
import {type Shadow} from '#/state/cache/types'
|
||||
import {useLabelerSubscriptionMutation} from '#/state/queries/labeler'
|
||||
@@ -34,6 +33,7 @@ import * as Prompt from '#/components/Prompt'
|
||||
import {RichText} from '#/components/RichText'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_IOS} from '#/env'
|
||||
import {ProfileHeaderDisplayName} from './DisplayName'
|
||||
import {EditProfileDialog} from './EditProfileDialog'
|
||||
@@ -61,6 +61,7 @@ let ProfileHeaderLabeler = ({
|
||||
const profile: Shadow<AppBskyActorDefs.ProfileViewDetailed> =
|
||||
useProfileShadow(profileUnshadowed)
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const {currentAccount, hasSession} = useSession()
|
||||
const playHaptic = useHaptics()
|
||||
@@ -99,9 +100,9 @@ let ProfileHeaderLabeler = ({
|
||||
),
|
||||
{type: 'error'},
|
||||
)
|
||||
logger.error(`Failed to toggle labeler like`, {message: e.message})
|
||||
ax.logger.error(`Failed to toggle labeler like`, {message: e.message})
|
||||
}
|
||||
}, [labeler, playHaptic, likeUri, unlikeMod, likeMod, _])
|
||||
}, [ax, labeler, playHaptic, likeUri, unlikeMod, likeMod, _])
|
||||
|
||||
return (
|
||||
<ProfileHeaderShell
|
||||
@@ -233,8 +234,9 @@ export function HeaderLabelerButtons({
|
||||
/** disable the subscribe button */
|
||||
minimal?: boolean
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const {_} = useLingui()
|
||||
const {currentAccount} = useSession()
|
||||
const requireAuth = useRequireAuth()
|
||||
const playHaptic = useHaptics()
|
||||
@@ -264,12 +266,11 @@ export function HeaderLabelerButtons({
|
||||
subscribe,
|
||||
})
|
||||
|
||||
logger.metric(
|
||||
ax.metric(
|
||||
subscribe
|
||||
? 'moderation:subscribedToLabeler'
|
||||
: 'moderation:unsubscribedFromLabeler',
|
||||
{},
|
||||
{statsig: true},
|
||||
)
|
||||
} catch (e: any) {
|
||||
reset()
|
||||
@@ -277,7 +278,7 @@ export function HeaderLabelerButtons({
|
||||
cantSubscribePrompt.open()
|
||||
return
|
||||
}
|
||||
logger.error(`Failed to subscribe to labeler`, {message: e.message})
|
||||
ax.logger.error(`Failed to subscribe to labeler`, {message: e.message})
|
||||
}
|
||||
})
|
||||
return (
|
||||
|
||||
@@ -18,7 +18,6 @@ import {useActorStatus} from '#/lib/actor-status'
|
||||
import {BACK_HITSLOP} from '#/lib/constants'
|
||||
import {useHaptics} from '#/lib/haptics'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {logger} from '#/logger'
|
||||
import {type Shadow} from '#/state/cache/types'
|
||||
import {useLightboxControls} from '#/state/lightbox'
|
||||
import {useSession} from '#/state/session'
|
||||
@@ -34,6 +33,7 @@ import {LiveIndicator} from '#/components/live/LiveIndicator'
|
||||
import {LiveStatusDialog} from '#/components/live/LiveStatusDialog'
|
||||
import {LabelsOnMe} from '#/components/moderation/LabelsOnMe'
|
||||
import {ProfileHeaderAlerts} from '#/components/moderation/ProfileHeaderAlerts'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_IOS} from '#/env'
|
||||
import {GrowableAvatar} from './GrowableAvatar'
|
||||
import {GrowableBanner} from './GrowableBanner'
|
||||
@@ -54,6 +54,7 @@ let ProfileHeaderShell = ({
|
||||
isPlaceholderProfile,
|
||||
}: React.PropsWithChildren<Props>): React.ReactNode => {
|
||||
const t = useTheme()
|
||||
const ax = useAnalytics()
|
||||
const {currentAccount} = useSession()
|
||||
const {_} = useLingui()
|
||||
const {openLightbox} = useLightboxControls()
|
||||
@@ -116,22 +117,14 @@ let ProfileHeaderShell = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (live.isActive) {
|
||||
logger.metric(
|
||||
'live:view:profile',
|
||||
{subject: profile.did},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('live:view:profile', {subject: profile.did})
|
||||
}
|
||||
}, [live.isActive, profile.did])
|
||||
}, [ax, live.isActive, profile.did])
|
||||
|
||||
const onPressAvi = useCallback(() => {
|
||||
if (live.isActive) {
|
||||
playHaptic('Light')
|
||||
logger.metric(
|
||||
'live:card:open',
|
||||
{subject: profile.did, from: 'profile'},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('live:card:open', {subject: profile.did, from: 'profile'})
|
||||
liveStatusControl.open()
|
||||
} else {
|
||||
const modui = moderation.ui('avatar')
|
||||
@@ -145,6 +138,7 @@ let ProfileHeaderShell = ({
|
||||
}
|
||||
}
|
||||
}, [
|
||||
ax,
|
||||
profile,
|
||||
moderation,
|
||||
_openLightbox,
|
||||
|
||||
@@ -5,8 +5,7 @@ import {msg, Plural, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {useHaptics} from '#/lib/haptics'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {makeCustomFeedLink} from '#/lib/routes/links'
|
||||
import {makeCustomFeedLink, makeProfileLink} from '#/lib/routes/links'
|
||||
import {shareUrl} from '#/lib/sharing'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {toShareUrl} from '#/lib/strings/url-helpers'
|
||||
@@ -51,6 +50,7 @@ import {
|
||||
} from '#/components/moderation/ReportDialog'
|
||||
import {RichText} from '#/components/RichText'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_WEB} from '#/env'
|
||||
|
||||
export function ProfileFeedHeaderSkeleton() {
|
||||
@@ -86,6 +86,7 @@ export function ProfileFeedHeaderSkeleton() {
|
||||
export function ProfileFeedHeader({info}: {info: FeedSourceFeedInfo}) {
|
||||
const t = useTheme()
|
||||
const {_, i18n} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const {hasSession} = useSession()
|
||||
const {gtMobile} = useBreakpoints()
|
||||
const infoControl = Dialog.useDialogControl()
|
||||
@@ -120,7 +121,7 @@ export function ProfileFeedHeader({info}: {info: FeedSourceFeedInfo}) {
|
||||
if (savedFeedConfig) {
|
||||
await removeFeed(savedFeedConfig)
|
||||
Toast.show(_(msg`Removed from your feeds`))
|
||||
logger.metric('feed:unsave', {feedUrl: info.uri})
|
||||
ax.metric('feed:unsave', {feedUrl: info.uri})
|
||||
} else {
|
||||
await addSavedFeeds([
|
||||
{
|
||||
@@ -130,7 +131,7 @@ export function ProfileFeedHeader({info}: {info: FeedSourceFeedInfo}) {
|
||||
},
|
||||
])
|
||||
Toast.show(_(msg`Saved to your feeds`))
|
||||
logger.metric('feed:save', {feedUrl: info.uri})
|
||||
ax.metric('feed:save', {feedUrl: info.uri})
|
||||
}
|
||||
} catch (err) {
|
||||
Toast.show(
|
||||
@@ -158,10 +159,10 @@ export function ProfileFeedHeader({info}: {info: FeedSourceFeedInfo}) {
|
||||
|
||||
if (pinned) {
|
||||
Toast.show(_(msg`Pinned ${info.displayName} to Home`))
|
||||
logger.metric('feed:pin', {feedUrl: info.uri})
|
||||
ax.metric('feed:pin', {feedUrl: info.uri})
|
||||
} else {
|
||||
Toast.show(_(msg`Unpinned ${info.displayName} from Home`))
|
||||
logger.metric('feed:unpin', {feedUrl: info.uri})
|
||||
ax.metric('feed:unpin', {feedUrl: info.uri})
|
||||
}
|
||||
} else {
|
||||
await addSavedFeeds([
|
||||
@@ -172,7 +173,7 @@ export function ProfileFeedHeader({info}: {info: FeedSourceFeedInfo}) {
|
||||
},
|
||||
])
|
||||
Toast.show(_(msg`Pinned ${info.displayName} to Home`))
|
||||
logger.metric('feed:pin', {feedUrl: info.uri})
|
||||
ax.metric('feed:pin', {feedUrl: info.uri})
|
||||
}
|
||||
} catch (e) {
|
||||
Toast.show(_(msg`There was an issue contacting the server`), 'xmark')
|
||||
@@ -388,6 +389,7 @@ function DialogInner({
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const {hasSession} = useSession()
|
||||
const playHaptic = useHaptics()
|
||||
const control = Dialog.useDialogContext()
|
||||
@@ -407,11 +409,11 @@ function DialogInner({
|
||||
if (isLiked && likeUri) {
|
||||
await unlikeFeed({uri: likeUri})
|
||||
setLikeUri('')
|
||||
logger.metric('feed:unlike', {feedUrl: info.uri})
|
||||
ax.metric('feed:unlike', {feedUrl: info.uri})
|
||||
} else {
|
||||
const res = await likeFeed({uri: info.uri, cid: info.cid})
|
||||
setLikeUri(res.uri)
|
||||
logger.metric('feed:like', {feedUrl: info.uri})
|
||||
ax.metric('feed:like', {feedUrl: info.uri})
|
||||
}
|
||||
} catch (err) {
|
||||
Toast.show(
|
||||
@@ -428,7 +430,7 @@ function DialogInner({
|
||||
playHaptic()
|
||||
const url = toShareUrl(info.route.href)
|
||||
shareUrl(url)
|
||||
logger.metric('feed:share', {feedUrl: info.uri})
|
||||
ax.metric('feed:share', {feedUrl: info.uri})
|
||||
}, [info, playHaptic])
|
||||
|
||||
const onPressReport = React.useCallback(() => {
|
||||
|
||||
@@ -21,6 +21,7 @@ import {Pin_Stroke2_Corner0_Rounded as PinIcon} from '#/components/icons/Pin'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {RichText} from '#/components/RichText'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {MoreOptionsMenu} from './MoreOptionsMenu'
|
||||
import {SubscribeMenu} from './SubscribeMenu'
|
||||
|
||||
@@ -34,6 +35,7 @@ export function Header({
|
||||
preferences: UsePreferencesQueryResponse
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const {currentAccount} = useSession()
|
||||
const isCurateList = list.purpose === AppBskyGraphDefs.CURATELIST
|
||||
const isModList = list.purpose === AppBskyGraphDefs.MODLIST
|
||||
@@ -96,11 +98,7 @@ export function Header({
|
||||
try {
|
||||
await muteList({uri: list.uri, mute: false})
|
||||
Toast.show(_(msg({message: 'List unmuted', context: 'toast'})))
|
||||
logger.metric(
|
||||
'moderation:unsubscribedFromList',
|
||||
{listType: 'mute'},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('moderation:unsubscribedFromList', {listType: 'mute'})
|
||||
} catch {
|
||||
Toast.show(
|
||||
_(
|
||||
@@ -114,11 +112,7 @@ export function Header({
|
||||
try {
|
||||
await blockList({uri: list.uri, block: false})
|
||||
Toast.show(_(msg({message: 'List unblocked', context: 'toast'})))
|
||||
logger.metric(
|
||||
'moderation:unsubscribedFromList',
|
||||
{listType: 'block'},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('moderation:unsubscribedFromList', {listType: 'block'})
|
||||
} catch {
|
||||
Toast.show(
|
||||
_(
|
||||
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
} from '#/components/moderation/ReportDialog'
|
||||
import * as Prompt from '#/components/Prompt'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_WEB} from '#/env'
|
||||
|
||||
export function MoreOptionsMenu({
|
||||
@@ -43,6 +44,7 @@ export function MoreOptionsMenu({
|
||||
savedFeedConfig?: AppBskyActorDefs.SavedFeed
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const {currentAccount} = useSession()
|
||||
const editListDialogControl = useDialogControl()
|
||||
const deleteListPromptControl = useDialogControl()
|
||||
@@ -111,11 +113,7 @@ export function MoreOptionsMenu({
|
||||
try {
|
||||
await muteList({uri: list.uri, mute: false})
|
||||
Toast.show(_(msg({message: 'List unmuted', context: 'toast'})))
|
||||
logger.metric(
|
||||
'moderation:unsubscribedFromList',
|
||||
{listType: 'mute'},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('moderation:unsubscribedFromList', {listType: 'mute'})
|
||||
} catch {
|
||||
Toast.show(
|
||||
_(
|
||||
@@ -129,11 +127,7 @@ export function MoreOptionsMenu({
|
||||
try {
|
||||
await blockList({uri: list.uri, block: false})
|
||||
Toast.show(_(msg({message: 'List unblocked', context: 'toast'})))
|
||||
logger.metric(
|
||||
'moderation:unsubscribedFromList',
|
||||
{listType: 'block'},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('moderation:unsubscribedFromList', {listType: 'block'})
|
||||
} catch {
|
||||
Toast.show(
|
||||
_(
|
||||
|
||||
@@ -2,7 +2,6 @@ import {type AppBskyGraphDefs} from '@atproto/api'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {logger} from '#/logger'
|
||||
import {useListBlockMutation, useListMuteMutation} from '#/state/queries/list'
|
||||
import {atoms as a} from '#/alf'
|
||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||
@@ -12,9 +11,11 @@ import {Loader} from '#/components/Loader'
|
||||
import * as Menu from '#/components/Menu'
|
||||
import * as Prompt from '#/components/Prompt'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
export function SubscribeMenu({list}: {list: AppBskyGraphDefs.ListView}) {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const subscribeMutePromptControl = Prompt.usePromptControl()
|
||||
const subscribeBlockPromptControl = Prompt.usePromptControl()
|
||||
|
||||
@@ -29,11 +30,7 @@ export function SubscribeMenu({list}: {list: AppBskyGraphDefs.ListView}) {
|
||||
try {
|
||||
await muteList({uri: list.uri, mute: true})
|
||||
Toast.show(_(msg({message: 'List muted', context: 'toast'})))
|
||||
logger.metric(
|
||||
'moderation:subscribedToList',
|
||||
{listType: 'mute'},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('moderation:subscribedToList', {listType: 'mute'})
|
||||
} catch {
|
||||
Toast.show(
|
||||
_(
|
||||
@@ -48,11 +45,7 @@ export function SubscribeMenu({list}: {list: AppBskyGraphDefs.ListView}) {
|
||||
try {
|
||||
await blockList({uri: list.uri, block: true})
|
||||
Toast.show(_(msg({message: 'List blocked', context: 'toast'})))
|
||||
logger.metric(
|
||||
'moderation:subscribedToList',
|
||||
{listType: 'block'},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('moderation:subscribedToList', {listType: 'block'})
|
||||
} catch {
|
||||
Toast.show(
|
||||
_(
|
||||
|
||||
@@ -4,7 +4,6 @@ import {type AppBskyFeedDefs, AtUri} from '@atproto/api'
|
||||
|
||||
import {PressableScale} from '#/lib/custom-animations/PressableScale'
|
||||
import {makeCustomFeedLink} from '#/lib/routes/links'
|
||||
import {logger} from '#/logger'
|
||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||
import {atoms as a, native, useTheme, type ViewStyleProp} from '#/alf'
|
||||
import {Button, ButtonIcon} from '#/components/Button'
|
||||
@@ -13,6 +12,7 @@ import {sizes as iconSizes} from '#/components/icons/common'
|
||||
import {MagnifyingGlass_Stroke2_Corner0_Rounded as SearchIcon} from '#/components/icons/MagnifyingGlass'
|
||||
import {Link} from '#/components/Link'
|
||||
import {Text, type TextProps} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
|
||||
export function Container({
|
||||
style,
|
||||
@@ -126,6 +126,7 @@ export function SearchButton({
|
||||
metricsTag: 'suggestedAccounts' | 'suggestedFeeds'
|
||||
onPress?: () => void
|
||||
}) {
|
||||
const ax = useAnalytics()
|
||||
return (
|
||||
<Button
|
||||
label={label}
|
||||
@@ -135,11 +136,7 @@ export function SearchButton({
|
||||
shape="round"
|
||||
PressableComponent={native(PressableScale)}
|
||||
onPress={() => {
|
||||
logger.metric(
|
||||
'explore:module:searchButtonPress',
|
||||
{module: metricsTag},
|
||||
{statsig: true},
|
||||
)
|
||||
ax.metric('explore:module:searchButtonPress', {module: metricsTag})
|
||||
onPress?.()
|
||||
}}
|
||||
style={[
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user