diff --git a/src/ageAssurance/components/NoAccessScreen.tsx b/src/ageAssurance/components/NoAccessScreen.tsx index ca5716a37a..9515b820e3 100644 --- a/src/ageAssurance/components/NoAccessScreen.tsx +++ b/src/ageAssurance/components/NoAccessScreen.tsx @@ -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 {' '} @@ -321,7 +319,7 @@ function AccessSection() { color={hasInitiated ? 'secondary' : 'primary'} onPress={() => { control.open() - logger.metric('ageAssurance:initDialogOpen', { + ax.metric('ageAssurance:initDialogOpen', { hasInitiatedPreviously: hasInitiated, }) }}> diff --git a/src/ageAssurance/components/RedirectOverlay.tsx b/src/ageAssurance/components/RedirectOverlay.tsx index b7bc51df3c..dbd498447a 100644 --- a/src/ageAssurance/components/RedirectOverlay.tsx +++ b/src/ageAssurance/components/RedirectOverlay.tsx @@ -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 ( diff --git a/src/ageAssurance/useBeginAgeAssurance.ts b/src/ageAssurance/useBeginAgeAssurance.ts index 897b03bbdb..28a4591747 100644 --- a/src/ageAssurance/useBeginAgeAssurance.ts +++ b/src/ageAssurance/useBeginAgeAssurance.ts @@ -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 diff --git a/src/components/PostControls/BookmarkButton.tsx b/src/components/PostControls/BookmarkButton.tsx index ac391a1ae9..3b8e8db3d9 100644 --- a/src/components/PostControls/BookmarkButton.tsx +++ b/src/components/PostControls/BookmarkButton.tsx @@ -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, diff --git a/src/components/PostControls/ShareMenu/RecentChats.tsx b/src/components/PostControls/ShareMenu/RecentChats.tsx index e17a6adb2a..2648b485e1 100644 --- a/src/components/PostControls/ShareMenu/RecentChats.tsx +++ b/src/components/PostControls/ShareMenu/RecentChats.tsx @@ -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, diff --git a/src/components/PostControls/ShareMenu/ShareMenuItems.tsx b/src/components/PostControls/ShareMenu/ShareMenuItems.tsx index 8ba9ea3e25..fe2f0a9c77 100644 --- a/src/components/PostControls/ShareMenu/ShareMenuItems.tsx +++ b/src/components/PostControls/ShareMenu/ShareMenuItems.tsx @@ -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() @@ -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() }}> diff --git a/src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx b/src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx index 408035db90..c1da73ca82 100644 --- a/src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx +++ b/src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx @@ -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() }}> @@ -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() }}> {_(msg`Embed post`)} diff --git a/src/components/PostControls/ShareMenu/index.tsx b/src/components/PostControls/ShareMenu/index.tsx index 0748f1a371..b53bd63c01 100644 --- a/src/components/PostControls/ShareMenu/index.tsx +++ b/src/components/PostControls/ShareMenu/index.tsx @@ -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) diff --git a/src/components/PostControls/index.tsx b/src/components/PostControls/index.tsx index 45688c2617..4eb67879ab 100644 --- a/src/components/PostControls/index.tsx +++ b/src/components/PostControls/index.tsx @@ -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, diff --git a/src/components/StarterPack/QrCodeDialog.tsx b/src/components/StarterPack/QrCodeDialog.tsx index 4c9bcc510d..e0c894a769 100644 --- a/src/components/StarterPack/QrCodeDialog.tsx +++ b/src/components/StarterPack/QrCodeDialog.tsx @@ -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', diff --git a/src/components/StarterPack/ShareDialog.tsx b/src/components/StarterPack/ShareDialog.tsx index 1dbbb07eef..eb9e98b3b1 100644 --- a/src/components/StarterPack/ShareDialog.tsx +++ b/src/components/StarterPack/ShareDialog.tsx @@ -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', }) diff --git a/src/components/StarterPack/Wizard/WizardListCard.tsx b/src/components/StarterPack/Wizard/WizardListCard.tsx index 089092636d..b5cd15a112 100644 --- a/src/components/StarterPack/Wizard/WizardListCard.tsx +++ b/src/components/StarterPack/Wizard/WizardListCard.tsx @@ -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}) } } diff --git a/src/components/WelcomeModal.tsx b/src/components/WelcomeModal.tsx index 1271a5f3ac..9b4ab08ebb 100644 --- a/src/components/WelcomeModal.tsx +++ b/src/components/WelcomeModal.tsx @@ -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" diff --git a/src/components/WhoCanReply.tsx b/src/components/WhoCanReply.tsx index 292d041b70..8e93ee4fcc 100644 --- a/src/components/WhoCanReply.tsx +++ b/src/components/WhoCanReply.tsx @@ -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() } diff --git a/src/components/activity-notifications/SubscribeProfileDialog.tsx b/src/components/activity-notifications/SubscribeProfileDialog.tsx index a8a5df39f2..cb0cae9fcc 100644 --- a/src/components/activity-notifications/SubscribeProfileDialog.tsx +++ b/src/components/activity-notifications/SubscribeProfileDialog.tsx @@ -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}) }, }) diff --git a/src/components/ageAssurance/AgeAssuranceAccountCard.tsx b/src/components/ageAssurance/AgeAssuranceAccountCard.tsx index 41659d3edb..7d7b5ade06 100644 --- a/src/components/ageAssurance/AgeAssuranceAccountCard.tsx +++ b/src/components/ageAssurance/AgeAssuranceAccountCard.tsx @@ -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 {' '} @@ -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, }) }}> diff --git a/src/components/ageAssurance/AgeAssuranceAdmonition.tsx b/src/components/ageAssurance/AgeAssuranceAdmonition.tsx index 1ef29dfbbb..426924b637 100644 --- a/src/components/ageAssurance/AgeAssuranceAdmonition.tsx +++ b/src/components/ageAssurance/AgeAssuranceAdmonition.tsx @@ -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. diff --git a/src/components/ageAssurance/AgeAssuranceAppealDialog.tsx b/src/components/ageAssurance/AgeAssuranceAppealDialog.tsx index d8330a94c3..c7f4c170e1 100644 --- a/src/components/ageAssurance/AgeAssuranceAppealDialog.tsx +++ b/src/components/ageAssurance/AgeAssuranceAppealDialog.tsx @@ -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( { diff --git a/src/components/ageAssurance/AgeAssuranceDismissibleFeedBanner.tsx b/src/components/ageAssurance/AgeAssuranceDismissibleFeedBanner.tsx index aa1d527f62..b32a2457b3 100644 --- a/src/components/ageAssurance/AgeAssuranceDismissibleFeedBanner.tsx +++ b/src/components/ageAssurance/AgeAssuranceDismissibleFeedBanner.tsx @@ -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]}> { close() - logger.metric('ageAssurance:dismissFeedBanner', {}) + ax.metric('ageAssurance:dismissFeedBanner', {}) }} style={[ a.absolute, diff --git a/src/components/ageAssurance/AgeAssuranceDismissibleNotice.tsx b/src/components/ageAssurance/AgeAssuranceDismissibleNotice.tsx index 14c7ed300f..fcfdf18017 100644 --- a/src/components/ageAssurance/AgeAssuranceDismissibleNotice.tsx +++ b/src/components/ageAssurance/AgeAssuranceDismissibleNotice.tsx @@ -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, diff --git a/src/components/ageAssurance/AgeAssuranceInitDialog.tsx b/src/components/ageAssurance/AgeAssuranceInitDialog.tsx index 32f6b0044a..8414b5fbd8 100644 --- a/src/components/ageAssurance/AgeAssuranceInitDialog.tsx +++ b/src/components/ageAssurance/AgeAssuranceInitDialog.tsx @@ -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() { ) - 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) diff --git a/src/components/ageAssurance/AgeAssuranceRedirectDialog.tsx b/src/components/ageAssurance/AgeAssuranceRedirectDialog.tsx index 0cbf6bed04..fc8dfeef4a 100644 --- a/src/components/ageAssurance/AgeAssuranceRedirectDialog.tsx +++ b/src/components/ageAssurance/AgeAssuranceRedirectDialog.tsx @@ -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 ( diff --git a/src/components/ageAssurance/AgeRestrictedScreen.tsx b/src/components/ageAssurance/AgeRestrictedScreen.tsx index 9f9c4c4d5b..8c77e8e43d 100644 --- a/src/components/ageAssurance/AgeRestrictedScreen.tsx +++ b/src/components/ageAssurance/AgeRestrictedScreen.tsx @@ -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', {}) }}> Go to account settings diff --git a/src/components/contacts/FindContactsBannerNUX.tsx b/src/components/contacts/FindContactsBannerNUX.tsx index 768fee519b..577474a3a4 100644 --- a/src/components/contacts/FindContactsBannerNUX.tsx +++ b/src/components/contacts/FindContactsBannerNUX.tsx @@ -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} diff --git a/src/components/contacts/screens/GetContacts.tsx b/src/components/contacts/screens/GetContacts.tsx index 5df967a8a5..909be81abc 100644 --- a/src/components/contacts/screens/GetContacts.tsx +++ b/src/components/contacts/screens/GetContacts.tsx @@ -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), }) diff --git a/src/components/contacts/screens/PhoneInput.tsx b/src/components/contacts/screens/PhoneInput.tsx index 25bffaf144..8eec5742e8 100644 --- a/src/components/contacts/screens/PhoneInput.tsx +++ b/src/components/contacts/screens/PhoneInput.tsx @@ -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() diff --git a/src/components/contacts/screens/VerifyNumber.tsx b/src/components/contacts/screens/VerifyNumber.tsx index ec676ad724..c316c66af7 100644 --- a/src/components/contacts/screens/VerifyNumber.tsx +++ b/src/components/contacts/screens/VerifyNumber.tsx @@ -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 => { diff --git a/src/components/contacts/screens/ViewMatches.tsx b/src/components/contacts/screens/ViewMatches.tsx index d92cb88b1e..b9aec3ed95 100644 --- a/src/components/contacts/screens/ViewMatches.tsx +++ b/src/components/contacts/screens/ViewMatches.tsx @@ -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 { diff --git a/src/components/dialogs/PostInteractionSettingsDialog.tsx b/src/components/dialogs/PostInteractionSettingsDialog.tsx index 11eb725a38..bca1485f87 100644 --- a/src/components/dialogs/PostInteractionSettingsDialog.tsx +++ b/src/components/dialogs/PostInteractionSettingsDialog.tsx @@ -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]) } diff --git a/src/components/dialogs/ServerInput.tsx b/src/components/dialogs/ServerInput.tsx index d7c02bb9f4..57be836614 100644 --- a/src/components/dialogs/ServerInput.tsx +++ b/src/components/dialogs/ServerInput.tsx @@ -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(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 ( { @@ -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') }) diff --git a/src/components/dialogs/nuxs/InitialVerificationAnnouncement.tsx b/src/components/dialogs/nuxs/InitialVerificationAnnouncement.tsx index a95a577b53..f3b659d43c 100644 --- a/src/components/dialogs/nuxs/InitialVerificationAnnouncement.tsx +++ b/src/components/dialogs/nuxs/InitialVerificationAnnouncement.tsx @@ -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', + }) }}> Read blog post diff --git a/src/components/dms/MessageContextMenu.tsx b/src/components/dms/MessageContextMenu.tsx index 85831c541f..6090e41559 100644 --- a/src/components/dms/MessageContextMenu.tsx +++ b/src/components/dms/MessageContextMenu.tsx @@ -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) diff --git a/src/components/live/LiveStatusDialog.tsx b/src/components/live/LiveStatusDialog.tsx index 5abf9bc2bf..122ef5f1b9 100644 --- a/src/components/live/LiveStatusDialog.tsx +++ b/src/components/live/LiveStatusDialog.tsx @@ -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) }}> @@ -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() }}> diff --git a/src/components/live/queries.ts b/src/components/live/queries.ts index 7db944d06d..21a5e9048e 100644 --- a/src/components/live/queries.ts +++ b/src/components/live/queries.ts @@ -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 diff --git a/src/components/moderation/ReportDialog/index.tsx b/src/components/moderation/ReportDialog/index.tsx index 4c8287f373..479a765783 100644 --- a/src/components/moderation/ReportDialog/index.tsx +++ b/src/components/moderation/ReportDialog/index.tsx @@ -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 @@ -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 ( @@ -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(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', }) @@ -238,7 +235,7 @@ function Inner(props: ReportDialogProps) { }, [_, submitReport, state, dispatch, props, setPending, setSuccess]) React.useEffect(() => { - logger.metric( + ax.metric( 'reportDialog:open', { subjectType: props.subject.type, diff --git a/src/components/verification/VerificationCheckButton.tsx b/src/components/verification/VerificationCheckButton.tsx index 45449f43cf..bf3ad66ef3 100644 --- a/src/components/verification/VerificationCheckButton.tsx +++ b/src/components/verification/VerificationCheckButton.tsx @@ -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 { diff --git a/src/components/verification/VerificationsDialog.tsx b/src/components/verification/VerificationsDialog.tsx index 4091b80531..c51d5fe7bb 100644 --- a/src/components/verification/VerificationsDialog.tsx +++ b/src/components/verification/VerificationsDialog.tsx @@ -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', + }) }}> Learn more diff --git a/src/components/verification/VerifierDialog.tsx b/src/components/verification/VerifierDialog.tsx index 85e13ecb9c..057bb8673d 100644 --- a/src/components/verification/VerifierDialog.tsx +++ b/src/components/verification/VerifierDialog.tsx @@ -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,7 +127,7 @@ function Inner({ color="primary" style={[a.justify_center]} onPress={() => { - logger.metric( + ax.metric( 'verification:learn-more', { location: 'verifierDialog', diff --git a/src/features/liveEvents/components/LiveEventFeedCardCompact.tsx b/src/features/liveEvents/components/LiveEventFeedCardCompact.tsx index 69c24b2dc5..562b4eb205 100644 --- a/src/features/liveEvents/components/LiveEventFeedCardCompact.tsx +++ b/src/features/liveEvents/components/LiveEventFeedCardCompact.tsx @@ -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, }) diff --git a/src/features/liveEvents/components/LiveEventFeedCardWide.tsx b/src/features/liveEvents/components/LiveEventFeedCardWide.tsx index 1ed3a49df2..21af557379 100644 --- a/src/features/liveEvents/components/LiveEventFeedCardWide.tsx +++ b/src/features/liveEvents/components/LiveEventFeedCardWide.tsx @@ -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, }) diff --git a/src/features/liveEvents/preferences.ts b/src/features/liveEvents/preferences.ts index 9d1d53bf90..f3a05bbb5e 100644 --- a/src/features/liveEvents/preferences.ts +++ b/src/features/liveEvents/preferences.ts @@ -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, }) } diff --git a/src/lib/hooks/useCallOnce.ts b/src/lib/hooks/useCallOnce.ts index fa01cf4aa3..33e0d6b974 100644 --- a/src/lib/hooks/useCallOnce.ts +++ b/src/lib/hooks/useCallOnce.ts @@ -8,6 +8,7 @@ const called: Record = { [OnceKey.PreferencesThread]: false, } +// TODO dedupe with runCallbackOnce export function useCallOnce(key: OnceKey) { return useCallback( (cb: () => void) => { diff --git a/src/lib/hooks/useIntentHandler.ts b/src/lib/hooks/useIntentHandler.ts index de1eaa9728..347aa42122 100644 --- a/src/lib/hooks/useIntentHandler.ts +++ b/src/lib/hooks/useIntentHandler.ts @@ -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, diff --git a/src/lib/notifications/notifications.ts b/src/lib/notifications/notifications.ts index 2895eeaa7b..1c2e6dbe5a 100644 --- a/src/lib/notifications/notifications.ts +++ b/src/lib/notifications/notifications.ts @@ -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, }) diff --git a/src/screens/Bookmarks/index.tsx b/src/screens/Bookmarks/index.tsx index ce16d03abd..95c1291e77 100644 --- a/src/screens/Bookmarks/index.tsx +++ b/src/screens/Bookmarks/index.tsx @@ -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 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, + item: bookmark.item, }, }) } @@ -154,7 +155,7 @@ function BookmarksInner() { key: bookmark.item.uri, bookmark: { ...bookmark, - item: bookmark.item as $Typed, + item: bookmark.item, }, }) } @@ -270,6 +271,25 @@ function BookmarkNotFound({ ) } +function BookmarkItem({ + item, + hideTopBorder, +}: { + item: Extract + hideTopBorder: boolean +}) { + const ax = useAnalytics() + return ( + { + 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 } case 'bookmark': { - return ( - { - logger.metric('bookmarks:post-clicked', {}) - }} - /> - ) + return } case 'bookmarkNotFound': { return ( diff --git a/src/screens/Moderation/VerificationSettings.tsx b/src/screens/Moderation/VerificationSettings.tsx index aec70cf857..85d0a0590c 100644 --- a/src/screens/Moderation/VerificationSettings.tsx +++ b/src/screens/Moderation/VerificationSettings.tsx @@ -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. diff --git a/src/screens/Onboarding/StepFindContacts/index.tsx b/src/screens/Onboarding/StepFindContacts/index.tsx index 8d8b5dd52f..c16d3ac2cd 100644 --- a/src/screens/Onboarding/StepFindContacts/index.tsx +++ b/src/screens/Onboarding/StepFindContacts/index.tsx @@ -2,10 +2,10 @@ import {useCallback, useState} from 'react' import {LayoutAnimationConfig} from 'react-native-reanimated' import {SafeAreaView} from 'react-native-safe-area-context' -import {logger} from '#/logger' 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 +16,7 @@ export function StepFindContacts({ flowDispatch: React.ActionDispatch<[Action]> }) { const {dispatch} = useOnboardingInternalState() + const ax = useAnalytics() const [transitionDirection, setTransitionDirection] = useState< 'Forward' | 'Backward' @@ -24,10 +25,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(() => { diff --git a/src/screens/Onboarding/StepSuggestedAccounts/index.tsx b/src/screens/Onboarding/StepSuggestedAccounts/index.tsx index 41419c9036..9dd13cd788 100644 --- a/src/screens/Onboarding/StepSuggestedAccounts/index.tsx +++ b/src/screens/Onboarding/StepSuggestedAccounts/index.tsx @@ -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(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, + }) }} /> diff --git a/src/screens/Onboarding/StepSuggestedStarterpacks/StarterPackCard.tsx b/src/screens/Onboarding/StepSuggestedStarterpacks/StarterPackCard.tsx index 28b331dec4..3ee9cbe52a 100644 --- a/src/screens/Onboarding/StepSuggestedStarterpacks/StarterPackCard.tsx +++ b/src/screens/Onboarding/StepSuggestedStarterpacks/StarterPackCard.tsx @@ -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, diff --git a/src/screens/PostThread/components/HeaderDropdown.tsx b/src/screens/PostThread/components/HeaderDropdown.tsx index def3979b78..06bfdad879 100644 --- a/src/screens/PostThread/components/HeaderDropdown.tsx +++ b/src/screens/PostThread/components/HeaderDropdown.tsx @@ -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 ( @@ -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}> diff --git a/src/screens/PostThread/components/ThreadItemAnchor.tsx b/src/screens/PostThread/components/ThreadItemAnchor.tsx index bd468f2028..6db47c8308 100644 --- a/src/screens/PostThread/components/ThreadItemAnchor.tsx +++ b/src/screens/PostThread/components/ThreadItemAnchor.tsx @@ -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 ( diff --git a/src/screens/PostThread/components/ThreadItemShowOtherReplies.tsx b/src/screens/PostThread/components/ThreadItemShowOtherReplies.tsx index e418375b65..2d60554aa8 100644 --- a/src/screens/PostThread/components/ThreadItemShowOtherReplies.tsx +++ b/src/screens/PostThread/components/ThreadItemShowOtherReplies.tsx @@ -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 (