Migrate logger.metric to useAnalytics
This commit is contained in:
@@ -9,7 +9,6 @@ import {
|
|||||||
useCreateSupportLink,
|
useCreateSupportLink,
|
||||||
} from '#/lib/hooks/useCreateSupportLink'
|
} from '#/lib/hooks/useCreateSupportLink'
|
||||||
import {dateDiff, useGetTimeAgo} from '#/lib/hooks/useTimeAgo'
|
import {dateDiff, useGetTimeAgo} from '#/lib/hooks/useTimeAgo'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useIsBirthdateUpdateAllowed} from '#/state/birthdate'
|
import {useIsBirthdateUpdateAllowed} from '#/state/birthdate'
|
||||||
import {useSessionApi} from '#/state/session'
|
import {useSessionApi} from '#/state/session'
|
||||||
import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
|
import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
|
||||||
@@ -36,8 +35,8 @@ import {
|
|||||||
isLegacyBirthdateBug,
|
isLegacyBirthdateBug,
|
||||||
useAgeAssuranceRegionConfig,
|
useAgeAssuranceRegionConfig,
|
||||||
} from '#/ageAssurance/util'
|
} from '#/ageAssurance/util'
|
||||||
import {IS_WEB} from '#/env'
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_NATIVE} from '#/env'
|
import {IS_NATIVE, IS_WEB} from '#/env'
|
||||||
import {useDeviceGeolocationApi} from '#/geolocation'
|
import {useDeviceGeolocationApi} from '#/geolocation'
|
||||||
|
|
||||||
const textStyles = [a.text_md, a.leading_snug]
|
const textStyles = [a.text_md, a.leading_snug]
|
||||||
@@ -45,6 +44,7 @@ const textStyles = [a.text_md, a.leading_snug]
|
|||||||
export function NoAccessScreen() {
|
export function NoAccessScreen() {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {gtPhone} = useBreakpoints()
|
const {gtPhone} = useBreakpoints()
|
||||||
const insets = useSafeAreaInsets()
|
const insets = useSafeAreaInsets()
|
||||||
const birthdateControl = useDialogControl()
|
const birthdateControl = useDialogControl()
|
||||||
@@ -63,8 +63,8 @@ export function NoAccessScreen() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// just counting overall hits here
|
// just counting overall hits here
|
||||||
logger.metric(`blockedGeoOverlay:shown`, {})
|
ax.metric(`blockedGeoOverlay:shown`, {})
|
||||||
logger.metric(`ageAssurance:noAccessScreen:shown`, {
|
ax.metric(`ageAssurance:noAccessScreen:shown`, {
|
||||||
accountCreatedAt: data?.accountCreatedAt || 'unknown',
|
accountCreatedAt: data?.accountCreatedAt || 'unknown',
|
||||||
isAARegion,
|
isAARegion,
|
||||||
hasDeclaredAge,
|
hasDeclaredAge,
|
||||||
@@ -103,10 +103,7 @@ export function NoAccessScreen() {
|
|||||||
label={_(msg`Click here to update your birthdate`)}
|
label={_(msg`Click here to update your birthdate`)}
|
||||||
style={[textStyles]}
|
style={[textStyles]}
|
||||||
{...createStaticClick(() => {
|
{...createStaticClick(() => {
|
||||||
logger.metric(
|
ax.metric('ageAssurance:noAccessScreen:openBirthdateDialog', {})
|
||||||
'ageAssurance:noAccessScreen:openBirthdateDialog',
|
|
||||||
{},
|
|
||||||
)
|
|
||||||
birthdateControl.open()
|
birthdateControl.open()
|
||||||
})}>
|
})}>
|
||||||
clicking here
|
clicking here
|
||||||
@@ -272,6 +269,7 @@ export function NoAccessScreen() {
|
|||||||
function AccessSection() {
|
function AccessSection() {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_, i18n} = useLingui()
|
const {_, i18n} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const control = useDialogControl()
|
const control = useDialogControl()
|
||||||
const appealControl = Dialog.useDialogControl()
|
const appealControl = Dialog.useDialogControl()
|
||||||
const locationControl = Dialog.useDialogControl()
|
const locationControl = Dialog.useDialogControl()
|
||||||
@@ -305,7 +303,7 @@ function AccessSection() {
|
|||||||
label={_(msg`Contact our moderation team`)}
|
label={_(msg`Contact our moderation team`)}
|
||||||
{...createStaticClick(() => {
|
{...createStaticClick(() => {
|
||||||
appealControl.open()
|
appealControl.open()
|
||||||
logger.metric('ageAssurance:appealDialogOpen', {})
|
ax.metric('ageAssurance:appealDialogOpen', {})
|
||||||
})}>
|
})}>
|
||||||
contact our moderation team
|
contact our moderation team
|
||||||
</SimpleInlineLinkText>{' '}
|
</SimpleInlineLinkText>{' '}
|
||||||
@@ -321,7 +319,7 @@ function AccessSection() {
|
|||||||
color={hasInitiated ? 'secondary' : 'primary'}
|
color={hasInitiated ? 'secondary' : 'primary'}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
control.open()
|
control.open()
|
||||||
logger.metric('ageAssurance:initDialogOpen', {
|
ax.metric('ageAssurance:initDialogOpen', {
|
||||||
hasInitiatedPreviously: hasInitiated,
|
hasInitiatedPreviously: hasInitiated,
|
||||||
})
|
})
|
||||||
}}>
|
}}>
|
||||||
|
|||||||
@@ -25,9 +25,8 @@ import {CircleInfo_Stroke2_Corner0_Rounded as ErrorIcon} from '#/components/icon
|
|||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {refetchAgeAssuranceServerState} from '#/ageAssurance'
|
import {refetchAgeAssuranceServerState} from '#/ageAssurance'
|
||||||
import {logger} from '#/ageAssurance'
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_IOS, IS_WEB} from '#/env'
|
||||||
import {IS_IOS} from '#/env'
|
|
||||||
|
|
||||||
export type RedirectOverlayState = {
|
export type RedirectOverlayState = {
|
||||||
result: 'success' | 'unknown'
|
result: 'success' | 'unknown'
|
||||||
@@ -174,6 +173,7 @@ export function RedirectOverlay() {
|
|||||||
|
|
||||||
function Inner() {
|
function Inner() {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const polling = useRef(false)
|
const polling = useRef(false)
|
||||||
@@ -187,7 +187,7 @@ function Inner() {
|
|||||||
|
|
||||||
polling.current = true
|
polling.current = true
|
||||||
|
|
||||||
logger.metric('ageAssurance:redirectDialogOpen', {})
|
ax.metric('ageAssurance:redirectDialogOpen', {})
|
||||||
|
|
||||||
wait(
|
wait(
|
||||||
3e3,
|
3e3,
|
||||||
@@ -218,18 +218,18 @@ function Inner() {
|
|||||||
|
|
||||||
setSuccess(true)
|
setSuccess(true)
|
||||||
|
|
||||||
logger.metric('ageAssurance:redirectDialogSuccess', {})
|
ax.metric('ageAssurance:redirectDialogSuccess', {})
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
if (unmounted.current) return
|
if (unmounted.current) return
|
||||||
setError(true)
|
setError(true)
|
||||||
logger.metric('ageAssurance:redirectDialogFail', {})
|
ax.metric('ageAssurance:redirectDialogFail', {})
|
||||||
})
|
})
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
unmounted.current = true
|
unmounted.current = true
|
||||||
}
|
}
|
||||||
}, [agent])
|
}, [ax, agent])
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {isNetworkError} from '#/lib/hooks/useCleanError'
|
|||||||
import {useAgent} from '#/state/session'
|
import {useAgent} from '#/state/session'
|
||||||
import {usePatchAgeAssuranceServerState} from '#/ageAssurance'
|
import {usePatchAgeAssuranceServerState} from '#/ageAssurance'
|
||||||
import {logger} from '#/ageAssurance/logger'
|
import {logger} from '#/ageAssurance/logger'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {BLUESKY_PROXY_DID} from '#/env'
|
import {BLUESKY_PROXY_DID} from '#/env'
|
||||||
import {useGeolocation} from '#/geolocation'
|
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
|
const APPVIEW = IS_DEV_ENV ? DEV_ENV_APPVIEW : PUBLIC_APPVIEW
|
||||||
|
|
||||||
export function useBeginAgeAssurance() {
|
export function useBeginAgeAssurance() {
|
||||||
|
const ax = useAnalytics()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const geolocation = useGeolocation()
|
const geolocation = useGeolocation()
|
||||||
const patchAgeAssuranceStateResponse = usePatchAgeAssuranceServerState()
|
const patchAgeAssuranceStateResponse = usePatchAgeAssuranceServerState()
|
||||||
@@ -48,15 +50,11 @@ export function useBeginAgeAssurance() {
|
|||||||
appView.sessionManager.session.accessJwt = token
|
appView.sessionManager.session.accessJwt = token
|
||||||
appView.sessionManager.session.refreshJwt = ''
|
appView.sessionManager.session.refreshJwt = ''
|
||||||
|
|
||||||
logger.metric(
|
ax.metric('ageAssurance:api:begin', {
|
||||||
'ageAssurance:api:begin',
|
platform: Platform.OS,
|
||||||
{
|
countryCode,
|
||||||
platform: Platform.OS,
|
regionCode,
|
||||||
countryCode,
|
})
|
||||||
regionCode,
|
|
||||||
},
|
|
||||||
{statsig: false},
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 2s wait is good actually. Email sending takes a hot sec and this helps
|
* 2s wait is good actually. Email sending takes a hot sec and this helps
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import {useLingui} from '@lingui/react'
|
|||||||
import type React from 'react'
|
import type React from 'react'
|
||||||
|
|
||||||
import {useCleanError} from '#/lib/hooks/useCleanError'
|
import {useCleanError} from '#/lib/hooks/useCleanError'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {type Shadow} from '#/state/cache/post-shadow'
|
import {type Shadow} from '#/state/cache/post-shadow'
|
||||||
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
||||||
import {useBookmarkMutation} from '#/state/queries/bookmarks/useBookmarkMutation'
|
import {useBookmarkMutation} from '#/state/queries/bookmarks/useBookmarkMutation'
|
||||||
@@ -15,6 +14,7 @@ import {useTheme} from '#/alf'
|
|||||||
import {Bookmark, BookmarkFilled} from '#/components/icons/Bookmark'
|
import {Bookmark, BookmarkFilled} from '#/components/icons/Bookmark'
|
||||||
import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash'
|
import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash'
|
||||||
import * as toast from '#/components/Toast'
|
import * as toast from '#/components/Toast'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {PostControlButton, PostControlButtonIcon} from './PostControlButton'
|
import {PostControlButton, PostControlButtonIcon} from './PostControlButton'
|
||||||
|
|
||||||
export const BookmarkButton = memo(function BookmarkButton({
|
export const BookmarkButton = memo(function BookmarkButton({
|
||||||
@@ -29,6 +29,7 @@ export const BookmarkButton = memo(function BookmarkButton({
|
|||||||
hitSlop?: Insets
|
hitSlop?: Insets
|
||||||
}): React.ReactNode {
|
}): React.ReactNode {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {mutateAsync: bookmark} = useBookmarkMutation()
|
const {mutateAsync: bookmark} = useBookmarkMutation()
|
||||||
const cleanError = useCleanError()
|
const cleanError = useCleanError()
|
||||||
@@ -52,7 +53,7 @@ export const BookmarkButton = memo(function BookmarkButton({
|
|||||||
post,
|
post,
|
||||||
})
|
})
|
||||||
|
|
||||||
logger.metric('post:bookmark', {
|
ax.metric('post:bookmark', {
|
||||||
uri: post.uri,
|
uri: post.uri,
|
||||||
authorDid: post.author.did,
|
authorDid: post.author.did,
|
||||||
logContext,
|
logContext,
|
||||||
@@ -92,7 +93,7 @@ export const BookmarkButton = memo(function BookmarkButton({
|
|||||||
uri: post.uri,
|
uri: post.uri,
|
||||||
})
|
})
|
||||||
|
|
||||||
logger.metric('post:unbookmark', {
|
ax.metric('post:unbookmark', {
|
||||||
uri: post.uri,
|
uri: post.uri,
|
||||||
authorDid: post.author.did,
|
authorDid: post.author.did,
|
||||||
logContext,
|
logContext,
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import {isBlockedOrBlocking, isMuted} from '#/lib/moderation/blocked-and-muted'
|
|||||||
import {type NavigationProp} from '#/lib/routes/types'
|
import {type NavigationProp} from '#/lib/routes/types'
|
||||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
||||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {useListConvosQuery} from '#/state/queries/messages/list-conversations'
|
import {useListConvosQuery} from '#/state/queries/messages/list-conversations'
|
||||||
@@ -20,9 +19,11 @@ import {useDialogContext} from '#/components/Dialog'
|
|||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {useSimpleVerificationState} from '#/components/verification'
|
import {useSimpleVerificationState} from '#/components/verification'
|
||||||
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import type * as bsky from '#/types/bsky'
|
import type * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
export function RecentChats({postUri}: {postUri: string}) {
|
export function RecentChats({postUri}: {postUri: string}) {
|
||||||
|
const ax = useAnalytics()
|
||||||
const control = useDialogContext()
|
const control = useDialogContext()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const {data} = useListConvosQuery({status: 'accepted'})
|
const {data} = useListConvosQuery({status: 'accepted'})
|
||||||
@@ -32,7 +33,7 @@ export function RecentChats({postUri}: {postUri: string}) {
|
|||||||
|
|
||||||
const onSelectChat = (convoId: string) => {
|
const onSelectChat = (convoId: string) => {
|
||||||
control.close(() => {
|
control.close(() => {
|
||||||
logger.metric('share:press:recentDm', {}, {statsig: true})
|
ax.metric('share:press:recentDm', {})
|
||||||
navigation.navigate('MessagesConversation', {
|
navigation.navigate('MessagesConversation', {
|
||||||
conversation: convoId,
|
conversation: convoId,
|
||||||
embed: postUri,
|
embed: postUri,
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import {makeProfileLink} from '#/lib/routes/links'
|
|||||||
import {type NavigationProp} from '#/lib/routes/types'
|
import {type NavigationProp} from '#/lib/routes/types'
|
||||||
import {shareText, shareUrl} from '#/lib/sharing'
|
import {shareText, shareUrl} from '#/lib/sharing'
|
||||||
import {toShareUrl} from '#/lib/strings/url-helpers'
|
import {toShareUrl} from '#/lib/strings/url-helpers'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import * as Toast from '#/view/com/util/Toast'
|
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 {PaperPlane_Stroke2_Corner0_Rounded as PaperPlaneIcon} from '#/components/icons/PaperPlane'
|
||||||
import * as Menu from '#/components/Menu'
|
import * as Menu from '#/components/Menu'
|
||||||
import {useAgeAssurance} from '#/ageAssurance'
|
import {useAgeAssurance} from '#/ageAssurance'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_IOS} from '#/env'
|
import {IS_IOS} from '#/env'
|
||||||
import {useDevMode} from '#/storage/hooks/dev-mode'
|
import {useDevMode} from '#/storage/hooks/dev-mode'
|
||||||
import {RecentChats} from './RecentChats'
|
import {RecentChats} from './RecentChats'
|
||||||
@@ -32,6 +32,7 @@ let ShareMenuItems = ({
|
|||||||
post,
|
post,
|
||||||
onShare: onShareProp,
|
onShare: onShareProp,
|
||||||
}: ShareMenuItemsProps): React.ReactNode => {
|
}: ShareMenuItemsProps): React.ReactNode => {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {hasSession} = useSession()
|
const {hasSession} = useSession()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const navigation = useNavigation<NavigationProp>()
|
const navigation = useNavigation<NavigationProp>()
|
||||||
@@ -54,14 +55,14 @@ let ShareMenuItems = ({
|
|||||||
}, [postAuthor])
|
}, [postAuthor])
|
||||||
|
|
||||||
const onSharePost = () => {
|
const onSharePost = () => {
|
||||||
logger.metric('share:press:nativeShare', {}, {statsig: true})
|
ax.metric('share:press:nativeShare', {})
|
||||||
const url = toShareUrl(href)
|
const url = toShareUrl(href)
|
||||||
shareUrl(url)
|
shareUrl(url)
|
||||||
onShareProp()
|
onShareProp()
|
||||||
}
|
}
|
||||||
|
|
||||||
const onCopyLink = async () => {
|
const onCopyLink = async () => {
|
||||||
logger.metric('share:press:copyLink', {}, {statsig: true})
|
ax.metric('share:press:copyLink', {})
|
||||||
const url = toShareUrl(href)
|
const url = toShareUrl(href)
|
||||||
if (IS_IOS) {
|
if (IS_IOS) {
|
||||||
// iOS only
|
// iOS only
|
||||||
@@ -100,7 +101,7 @@ let ShareMenuItems = ({
|
|||||||
testID="postDropdownSendViaDMBtn"
|
testID="postDropdownSendViaDMBtn"
|
||||||
label={_(msg`Send via direct message`)}
|
label={_(msg`Send via direct message`)}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric('share:press:openDmSearch', {}, {statsig: true})
|
ax.metric('share:press:openDmSearch', {})
|
||||||
sendViaChatControl.open()
|
sendViaChatControl.open()
|
||||||
}}>
|
}}>
|
||||||
<Menu.ItemText>
|
<Menu.ItemText>
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import {makeProfileLink} from '#/lib/routes/links'
|
|||||||
import {type NavigationProp} from '#/lib/routes/types'
|
import {type NavigationProp} from '#/lib/routes/types'
|
||||||
import {shareText, shareUrl} from '#/lib/sharing'
|
import {shareText, shareUrl} from '#/lib/sharing'
|
||||||
import {toShareUrl} from '#/lib/strings/url-helpers'
|
import {toShareUrl} from '#/lib/strings/url-helpers'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {useBreakpoints} from '#/alf'
|
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 {PaperPlane_Stroke2_Corner0_Rounded as Send} from '#/components/icons/PaperPlane'
|
||||||
import * as Menu from '#/components/Menu'
|
import * as Menu from '#/components/Menu'
|
||||||
import {useAgeAssurance} from '#/ageAssurance'
|
import {useAgeAssurance} from '#/ageAssurance'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
import {useDevMode} from '#/storage/hooks/dev-mode'
|
import {useDevMode} from '#/storage/hooks/dev-mode'
|
||||||
import {type ShareMenuItemsProps} from './ShareMenuItems.types'
|
import {type ShareMenuItemsProps} from './ShareMenuItems.types'
|
||||||
@@ -31,6 +31,7 @@ let ShareMenuItems = ({
|
|||||||
timestamp,
|
timestamp,
|
||||||
onShare: onShareProp,
|
onShare: onShareProp,
|
||||||
}: ShareMenuItemsProps): React.ReactNode => {
|
}: ShareMenuItemsProps): React.ReactNode => {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {hasSession} = useSession()
|
const {hasSession} = useSession()
|
||||||
const {gtMobile} = useBreakpoints()
|
const {gtMobile} = useBreakpoints()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
@@ -56,14 +57,14 @@ let ShareMenuItems = ({
|
|||||||
}, [postAuthor])
|
}, [postAuthor])
|
||||||
|
|
||||||
const onCopyLink = () => {
|
const onCopyLink = () => {
|
||||||
logger.metric('share:press:copyLink', {}, {statsig: true})
|
ax.metric('share:press:copyLink', {})
|
||||||
const url = toShareUrl(href)
|
const url = toShareUrl(href)
|
||||||
shareUrl(url)
|
shareUrl(url)
|
||||||
onShareProp()
|
onShareProp()
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSelectChatToShareTo = (conversation: string) => {
|
const onSelectChatToShareTo = (conversation: string) => {
|
||||||
logger.metric('share:press:dmSelected', {}, {statsig: true})
|
ax.metric('share:press:dmSelected', {})
|
||||||
navigation.navigate('MessagesConversation', {
|
navigation.navigate('MessagesConversation', {
|
||||||
conversation,
|
conversation,
|
||||||
embed: postUri,
|
embed: postUri,
|
||||||
@@ -102,7 +103,7 @@ let ShareMenuItems = ({
|
|||||||
testID="postDropdownSendViaDMBtn"
|
testID="postDropdownSendViaDMBtn"
|
||||||
label={_(msg`Send via direct message`)}
|
label={_(msg`Send via direct message`)}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric('share:press:openDmSearch', {}, {statsig: true})
|
ax.metric('share:press:openDmSearch', {})
|
||||||
sendViaChatControl.open()
|
sendViaChatControl.open()
|
||||||
}}>
|
}}>
|
||||||
<Menu.ItemText>
|
<Menu.ItemText>
|
||||||
@@ -117,7 +118,7 @@ let ShareMenuItems = ({
|
|||||||
testID="postDropdownEmbedBtn"
|
testID="postDropdownEmbedBtn"
|
||||||
label={_(msg`Embed post`)}
|
label={_(msg`Embed post`)}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric('share:press:embed', {}, {statsig: true})
|
ax.metric('share:press:embed', {})
|
||||||
embedPostControl.open()
|
embedPostControl.open()
|
||||||
}}>
|
}}>
|
||||||
<Menu.ItemText>{_(msg`Embed post`)}</Menu.ItemText>
|
<Menu.ItemText>{_(msg`Embed post`)}</Menu.ItemText>
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import {useLingui} from '@lingui/react'
|
|||||||
import {makeProfileLink} from '#/lib/routes/links'
|
import {makeProfileLink} from '#/lib/routes/links'
|
||||||
import {shareUrl} from '#/lib/sharing'
|
import {shareUrl} from '#/lib/sharing'
|
||||||
import {toShareUrl} from '#/lib/strings/url-helpers'
|
import {toShareUrl} from '#/lib/strings/url-helpers'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {type Shadow} from '#/state/cache/post-shadow'
|
import {type Shadow} from '#/state/cache/post-shadow'
|
||||||
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
||||||
import {EventStopper} from '#/view/com/util/EventStopper'
|
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 {ArrowShareRight_Stroke2_Corner2_Rounded as ArrowShareRightIcon} from '#/components/icons/ArrowShareRight'
|
||||||
import {useMenuControl} from '#/components/Menu'
|
import {useMenuControl} from '#/components/Menu'
|
||||||
import * as Menu from '#/components/Menu'
|
import * as Menu from '#/components/Menu'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {PostControlButton, PostControlButtonIcon} from '../PostControlButton'
|
import {PostControlButton, PostControlButtonIcon} from '../PostControlButton'
|
||||||
import {ShareMenuItems} from './ShareMenuItems'
|
import {ShareMenuItems} from './ShareMenuItems'
|
||||||
|
|
||||||
@@ -47,6 +47,7 @@ let ShareMenuButton = ({
|
|||||||
hitSlop?: Insets
|
hitSlop?: Insets
|
||||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {feedDescriptor} = useFeedFeedbackContext()
|
const {feedDescriptor} = useFeedFeedbackContext()
|
||||||
|
|
||||||
@@ -61,20 +62,17 @@ let ShareMenuButton = ({
|
|||||||
// menuControl.open() fires but RN doesn't expose flushSync.
|
// menuControl.open() fires but RN doesn't expose flushSync.
|
||||||
setTimeout(menuControl.open)
|
setTimeout(menuControl.open)
|
||||||
|
|
||||||
logger.metric(
|
ax.metric('post:share', {
|
||||||
'post:share',
|
uri: post.uri,
|
||||||
{
|
authorDid: post.author.did,
|
||||||
uri: post.uri,
|
logContext,
|
||||||
authorDid: post.author.did,
|
feedDescriptor,
|
||||||
logContext,
|
postContext: big ? 'thread' : 'feed',
|
||||||
feedDescriptor,
|
})
|
||||||
postContext: big ? 'thread' : 'feed',
|
|
||||||
},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
|
ax,
|
||||||
menuControl,
|
menuControl,
|
||||||
setHasBeenOpen,
|
setHasBeenOpen,
|
||||||
big,
|
big,
|
||||||
@@ -86,7 +84,7 @@ let ShareMenuButton = ({
|
|||||||
)
|
)
|
||||||
|
|
||||||
const onNativeLongPress = () => {
|
const onNativeLongPress = () => {
|
||||||
logger.metric('share:press:nativeShare', {}, {statsig: true})
|
ax.metric('share:press:nativeShare', {})
|
||||||
const urip = new AtUri(post.uri)
|
const urip = new AtUri(post.uri)
|
||||||
const href = makeProfileLink(post.author, 'post', urip.rkey)
|
const href = makeProfileLink(post.author, 'post', urip.rkey)
|
||||||
const url = toShareUrl(href)
|
const url = toShareUrl(href)
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import {CountWheel} from '#/lib/custom-animations/CountWheel'
|
|||||||
import {AnimatedLikeIcon} from '#/lib/custom-animations/LikeIcon'
|
import {AnimatedLikeIcon} from '#/lib/custom-animations/LikeIcon'
|
||||||
import {useHaptics} from '#/lib/haptics'
|
import {useHaptics} from '#/lib/haptics'
|
||||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {type Shadow} from '#/state/cache/types'
|
import {type Shadow} from '#/state/cache/types'
|
||||||
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
||||||
import {
|
import {
|
||||||
@@ -30,6 +29,7 @@ import {atoms as a, useBreakpoints} from '#/alf'
|
|||||||
import {Reply as Bubble} from '#/components/icons/Reply'
|
import {Reply as Bubble} from '#/components/icons/Reply'
|
||||||
import {useFormatPostStatCount} from '#/components/PostControls/util'
|
import {useFormatPostStatCount} from '#/components/PostControls/util'
|
||||||
import * as Skele from '#/components/Skeleton'
|
import * as Skele from '#/components/Skeleton'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {BookmarkButton} from './BookmarkButton'
|
import {BookmarkButton} from './BookmarkButton'
|
||||||
import {
|
import {
|
||||||
PostControlButton,
|
PostControlButton,
|
||||||
@@ -71,6 +71,7 @@ let PostControls = ({
|
|||||||
viaRepost?: {uri: string; cid: string}
|
viaRepost?: {uri: string; cid: string}
|
||||||
variant?: 'compact' | 'normal' | 'large'
|
variant?: 'compact' | 'normal' | 'large'
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {openComposer} = useOpenComposer()
|
const {openComposer} = useOpenComposer()
|
||||||
const {feedDescriptor} = useFeedFeedbackContext()
|
const {feedDescriptor} = useFeedFeedbackContext()
|
||||||
@@ -175,7 +176,7 @@ let PostControls = ({
|
|||||||
feedContext,
|
feedContext,
|
||||||
reqId,
|
reqId,
|
||||||
})
|
})
|
||||||
logger.metric('post:clickQuotePost', {
|
ax.metric('post:clickQuotePost', {
|
||||||
uri: post.uri,
|
uri: post.uri,
|
||||||
authorDid: post.author.did,
|
authorDid: post.author.did,
|
||||||
logContext,
|
logContext,
|
||||||
@@ -226,7 +227,7 @@ let PostControls = ({
|
|||||||
!replyDisabled
|
!replyDisabled
|
||||||
? () =>
|
? () =>
|
||||||
requireAuth(() => {
|
requireAuth(() => {
|
||||||
logger.metric('post:clickReply', {
|
ax.metric('post:clickReply', {
|
||||||
uri: post.uri,
|
uri: post.uri,
|
||||||
authorDid: post.author.did,
|
authorDid: post.author.did,
|
||||||
logContext,
|
logContext,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {FloppyDisk_Stroke2_Corner0_Rounded as FloppyDiskIcon} from '#/components
|
|||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {QrCode} from '#/components/StarterPack/QrCode'
|
import {QrCode} from '#/components/StarterPack/QrCode'
|
||||||
import * as Toast from '#/components/Toast'
|
import * as Toast from '#/components/Toast'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_NATIVE, IS_WEB} from '#/env'
|
import {IS_NATIVE, IS_WEB} from '#/env'
|
||||||
import * as bsky from '#/types/bsky'
|
import * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
@@ -32,6 +33,7 @@ export function QrCodeDialog({
|
|||||||
control: DialogControlProps
|
control: DialogControlProps
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {gtMobile} = useBreakpoints()
|
const {gtMobile} = useBreakpoints()
|
||||||
const [isSaveProcessing, setIsSaveProcessing] = useState(false)
|
const [isSaveProcessing, setIsSaveProcessing] = useState(false)
|
||||||
const [isCopyProcessing, setIsCopyProcessing] = useState(false)
|
const [isCopyProcessing, setIsCopyProcessing] = useState(false)
|
||||||
@@ -104,7 +106,7 @@ export function QrCodeDialog({
|
|||||||
link.click()
|
link.click()
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.metric('starterPack:share', {
|
ax.metric('starterPack:share', {
|
||||||
starterPack: starterPack.uri,
|
starterPack: starterPack.uri,
|
||||||
shareType: 'qrcode',
|
shareType: 'qrcode',
|
||||||
qrShareType: 'save',
|
qrShareType: 'save',
|
||||||
@@ -129,7 +131,7 @@ export function QrCodeDialog({
|
|||||||
navigator.clipboard.write([item])
|
navigator.clipboard.write([item])
|
||||||
})
|
})
|
||||||
|
|
||||||
logger.metric('starterPack:share', {
|
ax.metric('starterPack:share', {
|
||||||
starterPack: starterPack.uri,
|
starterPack: starterPack.uri,
|
||||||
shareType: 'qrcode',
|
shareType: 'qrcode',
|
||||||
qrShareType: 'copy',
|
qrShareType: 'copy',
|
||||||
@@ -145,7 +147,7 @@ export function QrCodeDialog({
|
|||||||
control.close(() => {
|
control.close(() => {
|
||||||
Sharing.shareAsync(uri, {mimeType: 'image/png', UTI: 'image/png'}).then(
|
Sharing.shareAsync(uri, {mimeType: 'image/png', UTI: 'image/png'}).then(
|
||||||
() => {
|
() => {
|
||||||
logger.metric('starterPack:share', {
|
ax.metric('starterPack:share', {
|
||||||
starterPack: starterPack.uri,
|
starterPack: starterPack.uri,
|
||||||
shareType: 'qrcode',
|
shareType: 'qrcode',
|
||||||
qrShareType: 'share',
|
qrShareType: 'share',
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {useLingui} from '@lingui/react'
|
|||||||
import {useSaveImageToMediaLibrary} from '#/lib/media/save-image'
|
import {useSaveImageToMediaLibrary} from '#/lib/media/save-image'
|
||||||
import {shareUrl} from '#/lib/sharing'
|
import {shareUrl} from '#/lib/sharing'
|
||||||
import {getStarterPackOgCard} from '#/lib/strings/starter-pack'
|
import {getStarterPackOgCard} from '#/lib/strings/starter-pack'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
||||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||||
import {type DialogControlProps} from '#/components/Dialog'
|
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 {QrCode_Stroke2_Corner0_Rounded as QrCodeIcon} from '#/components/icons/QrCode'
|
||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_NATIVE, IS_WEB} from '#/env'
|
import {IS_NATIVE, IS_WEB} from '#/env'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -46,6 +46,7 @@ function ShareDialogInner({
|
|||||||
control,
|
control,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {gtMobile} = useBreakpoints()
|
const {gtMobile} = useBreakpoints()
|
||||||
|
|
||||||
@@ -54,7 +55,7 @@ function ShareDialogInner({
|
|||||||
const onShareLink = async () => {
|
const onShareLink = async () => {
|
||||||
if (!link) return
|
if (!link) return
|
||||||
shareUrl(link)
|
shareUrl(link)
|
||||||
logger.metric('starterPack:share', {
|
ax.metric('starterPack:share', {
|
||||||
starterPack: starterPack.uri,
|
starterPack: starterPack.uri,
|
||||||
shareType: 'link',
|
shareType: 'link',
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import {useLingui} from '@lingui/react'
|
|||||||
import {DISCOVER_FEED_URI, STARTER_PACK_MAX_SIZE} from '#/lib/constants'
|
import {DISCOVER_FEED_URI, STARTER_PACK_MAX_SIZE} from '#/lib/constants'
|
||||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||||
import {
|
import {
|
||||||
@@ -25,6 +24,7 @@ import {Button, ButtonText} from '#/components/Button'
|
|||||||
import * as Toggle from '#/components/forms/Toggle'
|
import * as Toggle from '#/components/forms/Toggle'
|
||||||
import {Checkbox} from '#/components/forms/Toggle'
|
import {Checkbox} from '#/components/forms/Toggle'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import type * as bsky from '#/types/bsky'
|
import type * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
function WizardListCard({
|
function WizardListCard({
|
||||||
@@ -130,6 +130,7 @@ export function WizardProfileCard({
|
|||||||
profile: bsky.profile.AnyProfileView
|
profile: bsky.profile.AnyProfileView
|
||||||
moderationOpts: ModerationOpts
|
moderationOpts: ModerationOpts
|
||||||
}) {
|
}) {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
|
|
||||||
// Determine the "main" profile for this starter pack - either targetDid or current account
|
// 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 (profile.did === targetProfileDid) return
|
||||||
|
|
||||||
if (!included) {
|
if (!included) {
|
||||||
logger.metric('starterPack:addUser', {})
|
ax.metric('starterPack:addUser', {})
|
||||||
dispatch({type: 'AddProfile', profile})
|
dispatch({type: 'AddProfile', profile})
|
||||||
} else {
|
} else {
|
||||||
logger.metric('starterPack:removeUser', {})
|
ax.metric('starterPack:removeUser', {})
|
||||||
dispatch({type: 'RemoveProfile', profileDid: profile.did})
|
dispatch({type: 'RemoveProfile', profileDid: profile.did})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ import {msg, Trans} from '@lingui/macro'
|
|||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {FocusGuards, FocusScope} from 'radix-ui/internal'
|
import {FocusGuards, FocusScope} from 'radix-ui/internal'
|
||||||
|
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
||||||
import {Logo} from '#/view/icons/Logo'
|
import {Logo} from '#/view/icons/Logo'
|
||||||
import {atoms as a, flatten, useBreakpoints, web} from '#/alf'
|
import {atoms as a, flatten, useBreakpoints, web} from '#/alf'
|
||||||
import {Button, ButtonText} from '#/components/Button'
|
import {Button, ButtonText} from '#/components/Button'
|
||||||
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
|
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
const welcomeModalBg = require('../../assets/images/welcome-modal-bg.jpg')
|
const welcomeModalBg = require('../../assets/images/welcome-modal-bg.jpg')
|
||||||
|
|
||||||
@@ -25,6 +25,7 @@ interface WelcomeModalProps {
|
|||||||
|
|
||||||
export function WelcomeModal({control}: WelcomeModalProps) {
|
export function WelcomeModal({control}: WelcomeModalProps) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {requestSwitchToAccount} = useLoggedOutViewControls()
|
const {requestSwitchToAccount} = useLoggedOutViewControls()
|
||||||
const {gtMobile} = useBreakpoints()
|
const {gtMobile} = useBreakpoints()
|
||||||
const [isExiting, setIsExiting] = useState(false)
|
const [isExiting, setIsExiting] = useState(false)
|
||||||
@@ -40,23 +41,24 @@ export function WelcomeModal({control}: WelcomeModalProps) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (control.isOpen) {
|
if (control.isOpen) {
|
||||||
logger.metric('welcomeModal:presented', {})
|
ax.metric('welcomeModal:presented', {})
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [control.isOpen])
|
}, [control.isOpen])
|
||||||
|
|
||||||
const onPressCreateAccount = () => {
|
const onPressCreateAccount = () => {
|
||||||
logger.metric('welcomeModal:signupClicked', {})
|
ax.metric('welcomeModal:signupClicked', {})
|
||||||
control.close()
|
control.close()
|
||||||
requestSwitchToAccount({requestedAccount: 'new'})
|
requestSwitchToAccount({requestedAccount: 'new'})
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPressExplore = () => {
|
const onPressExplore = () => {
|
||||||
logger.metric('welcomeModal:exploreClicked', {})
|
ax.metric('welcomeModal:exploreClicked', {})
|
||||||
fadeOutAndClose()
|
fadeOutAndClose()
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPressSignIn = () => {
|
const onPressSignIn = () => {
|
||||||
logger.metric('welcomeModal:signinClicked', {})
|
ax.metric('welcomeModal:signinClicked', {})
|
||||||
control.close()
|
control.close()
|
||||||
requestSwitchToAccount({requestedAccount: 'existing'})
|
requestSwitchToAccount({requestedAccount: 'existing'})
|
||||||
}
|
}
|
||||||
@@ -222,7 +224,7 @@ export function WelcomeModal({control}: WelcomeModalProps) {
|
|||||||
]}
|
]}
|
||||||
hoverStyle={[a.bg_transparent]}
|
hoverStyle={[a.bg_transparent]}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric('welcomeModal:dismissed', {})
|
ax.metric('welcomeModal:dismissed', {})
|
||||||
fadeOutAndClose()
|
fadeOutAndClose()
|
||||||
}}
|
}}
|
||||||
color="secondary"
|
color="secondary"
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import {useLingui} from '@lingui/react'
|
|||||||
|
|
||||||
import {HITSLOP_10} from '#/lib/constants'
|
import {HITSLOP_10} from '#/lib/constants'
|
||||||
import {makeListLink, makeProfileLink} from '#/lib/routes/links'
|
import {makeListLink, makeProfileLink} from '#/lib/routes/links'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {
|
import {
|
||||||
type ThreadgateAllowUISetting,
|
type ThreadgateAllowUISetting,
|
||||||
threadgateViewToAllowUISetting,
|
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 {Group3_Stroke2_Corner0_Rounded as GroupIcon} from '#/components/icons/Group'
|
||||||
import {InlineLinkText} from '#/components/Link'
|
import {InlineLinkText} from '#/components/Link'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_NATIVE} from '#/env'
|
import {IS_NATIVE} from '#/env'
|
||||||
import * as bsky from '#/types/bsky'
|
import * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
@@ -46,8 +46,9 @@ interface WhoCanReplyProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
|
export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
|
||||||
const {_} = useLingui()
|
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
|
const {_} = useLingui()
|
||||||
const infoDialogControl = useDialogControl()
|
const infoDialogControl = useDialogControl()
|
||||||
const editDialogControl = useDialogControl()
|
const editDialogControl = useDialogControl()
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
|
|||||||
Keyboard.dismiss()
|
Keyboard.dismiss()
|
||||||
}
|
}
|
||||||
if (isThreadAuthor) {
|
if (isThreadAuthor) {
|
||||||
logger.metric('thread:click:editOwnThreadgate', {})
|
ax.metric('thread:click:editOwnThreadgate', {})
|
||||||
|
|
||||||
// wait on prefetch if it manages to resolve in under 200ms
|
// wait on prefetch if it manages to resolve in under 200ms
|
||||||
// otherwise, proceed immediately and show the spinner -sfn
|
// otherwise, proceed immediately and show the spinner -sfn
|
||||||
@@ -101,7 +102,7 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
|
|||||||
editDialogControl.open()
|
editDialogControl.open()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
logger.metric('thread:click:viewSomeoneElsesThreadgate', {})
|
ax.metric('thread:click:viewSomeoneElsesThreadgate', {})
|
||||||
|
|
||||||
infoDialogControl.open()
|
infoDialogControl.open()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,13 +17,11 @@ import {
|
|||||||
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
|
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
|
||||||
import {cleanError} from '#/lib/strings/errors'
|
import {cleanError} from '#/lib/strings/errors'
|
||||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {updateProfileShadow} from '#/state/cache/profile-shadow'
|
import {updateProfileShadow} from '#/state/cache/profile-shadow'
|
||||||
import {RQKEY_getActivitySubscriptions} from '#/state/queries/activity-subscriptions'
|
import {RQKEY_getActivitySubscriptions} from '#/state/queries/activity-subscriptions'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAgent} from '#/state/session'
|
||||||
import * as Toast from '#/view/com/util/Toast'
|
import * as Toast from '#/view/com/util/Toast'
|
||||||
import {platform, useTheme, web} from '#/alf'
|
import {atoms as a, platform, useTheme, web} from '#/alf'
|
||||||
import {atoms as a} from '#/alf'
|
|
||||||
import {Admonition} from '#/components/Admonition'
|
import {Admonition} from '#/components/Admonition'
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@@ -36,6 +34,7 @@ import * as Toggle from '#/components/forms/Toggle'
|
|||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import * as ProfileCard from '#/components/ProfileCard'
|
import * as ProfileCard from '#/components/ProfileCard'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
import type * as bsky from '#/types/bsky'
|
import type * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
@@ -71,6 +70,7 @@ function DialogInner({
|
|||||||
moderationOpts: ModerationOpts
|
moderationOpts: ModerationOpts
|
||||||
includeProfile?: boolean
|
includeProfile?: boolean
|
||||||
}) {
|
}) {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
@@ -133,7 +133,7 @@ function DialogInner({
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (!activitySubscription.post && !activitySubscription.reply) {
|
if (!activitySubscription.post && !activitySubscription.reply) {
|
||||||
logger.metric('activitySubscription:disable', {})
|
ax.metric('activitySubscription:disable', {})
|
||||||
Toast.show(
|
Toast.show(
|
||||||
_(
|
_(
|
||||||
msg`You will no longer receive notifications for ${sanitizeHandle(profile.handle, '@')}`,
|
msg`You will no longer receive notifications for ${sanitizeHandle(profile.handle, '@')}`,
|
||||||
@@ -160,7 +160,7 @@ function DialogInner({
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
logger.metric('activitySubscription:enable', {
|
ax.metric('activitySubscription:enable', {
|
||||||
setting: activitySubscription.reply ? 'posts_and_replies' : 'posts',
|
setting: activitySubscription.reply ? 'posts_and_replies' : 'posts',
|
||||||
})
|
})
|
||||||
if (!initialState.post && !initialState.reply) {
|
if (!initialState.post && !initialState.reply) {
|
||||||
@@ -177,7 +177,7 @@ function DialogInner({
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
onError: err => {
|
onError: err => {
|
||||||
logger.error('Could not save activity subscription', {message: err})
|
ax.logger.error('Could not save activity subscription', {message: err})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ import {Divider} from '#/components/Divider'
|
|||||||
import {createStaticClick, InlineLinkText} from '#/components/Link'
|
import {createStaticClick, InlineLinkText} from '#/components/Link'
|
||||||
import * as Toast from '#/components/Toast'
|
import * as Toast from '#/components/Toast'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {logger, useAgeAssurance} from '#/ageAssurance'
|
import {useAgeAssurance} from '#/ageAssurance'
|
||||||
import {useComputeAgeAssuranceRegionAccess} from '#/ageAssurance/useComputeAgeAssuranceRegionAccess'
|
import {useComputeAgeAssuranceRegionAccess} from '#/ageAssurance/useComputeAgeAssuranceRegionAccess'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_NATIVE} from '#/env'
|
import {IS_NATIVE} from '#/env'
|
||||||
import {useDeviceGeolocationApi} from '#/geolocation'
|
import {useDeviceGeolocationApi} from '#/geolocation'
|
||||||
|
|
||||||
@@ -41,6 +42,7 @@ export function AgeAssuranceAccountCard({style}: ViewStyleProp & {}) {
|
|||||||
function Inner({style}: ViewStyleProp & {}) {
|
function Inner({style}: ViewStyleProp & {}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_, i18n} = useLingui()
|
const {_, i18n} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const control = useDialogControl()
|
const control = useDialogControl()
|
||||||
const appealControl = Dialog.useDialogControl()
|
const appealControl = Dialog.useDialogControl()
|
||||||
const locationControl = Dialog.useDialogControl()
|
const locationControl = Dialog.useDialogControl()
|
||||||
@@ -138,7 +140,7 @@ function Inner({style}: ViewStyleProp & {}) {
|
|||||||
label={_(msg`Contact our moderation team`)}
|
label={_(msg`Contact our moderation team`)}
|
||||||
{...createStaticClick(() => {
|
{...createStaticClick(() => {
|
||||||
appealControl.open()
|
appealControl.open()
|
||||||
logger.metric('ageAssurance:appealDialogOpen', {})
|
ax.metric('ageAssurance:appealDialogOpen', {})
|
||||||
})}>
|
})}>
|
||||||
contact our moderation team
|
contact our moderation team
|
||||||
</InlineLinkText>{' '}
|
</InlineLinkText>{' '}
|
||||||
@@ -167,7 +169,7 @@ function Inner({style}: ViewStyleProp & {}) {
|
|||||||
color={hasInitiated ? 'secondary' : 'primary'}
|
color={hasInitiated ? 'secondary' : 'primary'}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
control.open()
|
control.open()
|
||||||
logger.metric('ageAssurance:initDialogOpen', {
|
ax.metric('ageAssurance:initDialogOpen', {
|
||||||
hasInitiatedPreviously: hasInitiated,
|
hasInitiatedPreviously: hasInitiated,
|
||||||
})
|
})
|
||||||
}}>
|
}}>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {ShieldCheck_Stroke2_Corner0_Rounded as Shield} from '#/components/icons/
|
|||||||
import {InlineLinkText} from '#/components/Link'
|
import {InlineLinkText} from '#/components/Link'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {useAgeAssurance} from '#/ageAssurance'
|
import {useAgeAssurance} from '#/ageAssurance'
|
||||||
import {logger} from '#/ageAssurance'
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
export function AgeAssuranceAdmonition({
|
export function AgeAssuranceAdmonition({
|
||||||
children,
|
children,
|
||||||
@@ -40,6 +40,7 @@ function Inner({
|
|||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -92,7 +93,7 @@ function Inner({
|
|||||||
to={'/settings/account'}
|
to={'/settings/account'}
|
||||||
style={[a.text_sm, a.leading_snug, a.font_semi_bold]}
|
style={[a.text_sm, a.leading_snug, a.font_semi_bold]}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric('ageAssurance:navigateToSettings', {})
|
ax.metric('ageAssurance:navigateToSettings', {})
|
||||||
}}>
|
}}>
|
||||||
account settings.
|
account settings.
|
||||||
</InlineLinkText>
|
</InlineLinkText>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import * as Dialog from '#/components/Dialog'
|
|||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {logger} from '#/ageAssurance'
|
import {logger} from '#/ageAssurance'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
export function AgeAssuranceAppealDialog({
|
export function AgeAssuranceAppealDialog({
|
||||||
control,
|
control,
|
||||||
@@ -37,6 +38,7 @@ export function AgeAssuranceAppealDialog({
|
|||||||
|
|
||||||
function Inner({control}: {control: Dialog.DialogControlProps}) {
|
function Inner({control}: {control: Dialog.DialogControlProps}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const {gtPhone} = useBreakpoints()
|
const {gtPhone} = useBreakpoints()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
@@ -46,7 +48,7 @@ function Inner({control}: {control: Dialog.DialogControlProps}) {
|
|||||||
|
|
||||||
const {mutate, isPending} = useMutation({
|
const {mutate, isPending} = useMutation({
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
logger.metric('ageAssurance:appealDialogSubmit', {})
|
ax.metric('ageAssurance:appealDialogSubmit', {})
|
||||||
|
|
||||||
await agent.createModerationReport(
|
await agent.createModerationReport(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
|||||||
import {Link} from '#/components/Link'
|
import {Link} from '#/components/Link'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {useAgeAssurance} from '#/ageAssurance'
|
import {useAgeAssurance} from '#/ageAssurance'
|
||||||
import {logger} from '#/ageAssurance'
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
export function useInternalState() {
|
export function useInternalState() {
|
||||||
const aa = useAgeAssurance()
|
const aa = useAgeAssurance()
|
||||||
@@ -42,6 +42,7 @@ export function useInternalState() {
|
|||||||
|
|
||||||
export function AgeAssuranceDismissibleFeedBanner() {
|
export function AgeAssuranceDismissibleFeedBanner() {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {visible, close} = useInternalState()
|
const {visible, close} = useInternalState()
|
||||||
const copy = useAgeAssuranceCopy()
|
const copy = useAgeAssuranceCopy()
|
||||||
@@ -66,7 +67,7 @@ export function AgeAssuranceDismissibleFeedBanner() {
|
|||||||
to="/settings/account"
|
to="/settings/account"
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
close()
|
close()
|
||||||
logger.metric('ageAssurance:navigateToSettings', {})
|
ax.metric('ageAssurance:navigateToSettings', {})
|
||||||
}}
|
}}
|
||||||
style={[a.w_full, a.justify_between, a.align_center, a.gap_md]}>
|
style={[a.w_full, a.justify_between, a.align_center, a.gap_md]}>
|
||||||
<View
|
<View
|
||||||
@@ -105,7 +106,7 @@ export function AgeAssuranceDismissibleFeedBanner() {
|
|||||||
size="small"
|
size="small"
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
close()
|
close()
|
||||||
logger.metric('ageAssurance:dismissFeedBanner', {})
|
ax.metric('ageAssurance:dismissFeedBanner', {})
|
||||||
}}
|
}}
|
||||||
style={[
|
style={[
|
||||||
a.absolute,
|
a.absolute,
|
||||||
|
|||||||
@@ -10,10 +10,11 @@ import {useAgeAssuranceCopy} from '#/components/ageAssurance/useAgeAssuranceCopy
|
|||||||
import {Button, ButtonIcon} from '#/components/Button'
|
import {Button, ButtonIcon} from '#/components/Button'
|
||||||
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
||||||
import {useAgeAssurance} from '#/ageAssurance'
|
import {useAgeAssurance} from '#/ageAssurance'
|
||||||
import {logger} from '#/ageAssurance'
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
export function AgeAssuranceDismissibleNotice({style}: ViewStyleProp & {}) {
|
export function AgeAssuranceDismissibleNotice({style}: ViewStyleProp & {}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const aa = useAgeAssurance()
|
const aa = useAgeAssurance()
|
||||||
const {nux} = useNux(Nux.AgeAssuranceDismissibleNotice)
|
const {nux} = useNux(Nux.AgeAssuranceDismissibleNotice)
|
||||||
const copy = useAgeAssuranceCopy()
|
const copy = useAgeAssuranceCopy()
|
||||||
@@ -45,7 +46,7 @@ export function AgeAssuranceDismissibleNotice({style}: ViewStyleProp & {}) {
|
|||||||
completed: true,
|
completed: true,
|
||||||
data: undefined,
|
data: undefined,
|
||||||
})
|
})
|
||||||
logger.metric('ageAssurance:dismissSettingsNotice', {})
|
ax.metric('ageAssurance:dismissSettingsNotice', {})
|
||||||
}}
|
}}
|
||||||
style={[
|
style={[
|
||||||
a.absolute,
|
a.absolute,
|
||||||
|
|||||||
@@ -19,8 +19,7 @@ import {useSession} from '#/state/session'
|
|||||||
import {atoms as a, web} from '#/alf'
|
import {atoms as a, web} from '#/alf'
|
||||||
import {Admonition} from '#/components/Admonition'
|
import {Admonition} from '#/components/Admonition'
|
||||||
import {AgeAssuranceBadge} from '#/components/ageAssurance/AgeAssuranceBadge'
|
import {AgeAssuranceBadge} from '#/components/ageAssurance/AgeAssuranceBadge'
|
||||||
import {urls} from '#/components/ageAssurance/const'
|
import {KWS_SUPPORTED_LANGS, urls} from '#/components/ageAssurance/const'
|
||||||
import {KWS_SUPPORTED_LANGS} from '#/components/ageAssurance/const'
|
|
||||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||||
import * as Dialog from '#/components/Dialog'
|
import * as Dialog from '#/components/Dialog'
|
||||||
import {Divider} from '#/components/Divider'
|
import {Divider} from '#/components/Divider'
|
||||||
@@ -30,9 +29,9 @@ import {LanguageSelect} from '#/components/LanguageSelect'
|
|||||||
import {SimpleInlineLinkText} from '#/components/Link'
|
import {SimpleInlineLinkText} from '#/components/Link'
|
||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {logger} from '#/ageAssurance'
|
|
||||||
import {useAgeAssurance} from '#/ageAssurance'
|
import {useAgeAssurance} from '#/ageAssurance'
|
||||||
import {useBeginAgeAssurance} from '#/ageAssurance/useBeginAgeAssurance'
|
import {useBeginAgeAssurance} from '#/ageAssurance/useBeginAgeAssurance'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
export {useDialogControl} from '#/components/Dialog/context'
|
export {useDialogControl} from '#/components/Dialog/context'
|
||||||
|
|
||||||
@@ -64,6 +63,7 @@ export function AgeAssuranceInitDialog({
|
|||||||
|
|
||||||
function Inner() {
|
function Inner() {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const langPrefs = useLanguagePrefs()
|
const langPrefs = useLanguagePrefs()
|
||||||
const cleanError = useCleanError()
|
const cleanError = useCleanError()
|
||||||
@@ -116,7 +116,7 @@ function Inner() {
|
|||||||
const onSubmit = async () => {
|
const onSubmit = async () => {
|
||||||
setLanguageError(false)
|
setLanguageError(false)
|
||||||
|
|
||||||
logger.metric('ageAssurance:initDialogSubmit', {})
|
ax.metric('ageAssurance:initDialogSubmit', {})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const {status} = runEmailValidation()
|
const {status} = runEmailValidation()
|
||||||
@@ -143,7 +143,7 @@ function Inner() {
|
|||||||
error = _(
|
error = _(
|
||||||
msg`Please enter a valid, non-temporary email address. You may need to access this email in the future.`,
|
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') {
|
} else if (e.error === 'DidTooLong') {
|
||||||
error = (
|
error = (
|
||||||
<>
|
<>
|
||||||
@@ -159,14 +159,14 @@ function Inner() {
|
|||||||
</Trans>
|
</Trans>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
logger.metric('ageAssurance:initDialogError', {code: 'DidTooLong'})
|
ax.metric('ageAssurance:initDialogError', {code: 'DidTooLong'})
|
||||||
} else {
|
} else {
|
||||||
logger.metric('ageAssurance:initDialogError', {code: 'other'})
|
ax.metric('ageAssurance:initDialogError', {code: 'other'})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const {clean, raw} = cleanError(e)
|
const {clean, raw} = cleanError(e)
|
||||||
error = clean || raw || error
|
error = clean || raw || error
|
||||||
logger.metric('ageAssurance:initDialogError', {code: 'other'})
|
ax.metric('ageAssurance:initDialogError', {code: 'other'})
|
||||||
}
|
}
|
||||||
|
|
||||||
setError(error)
|
setError(error)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import {CircleInfo_Stroke2_Corner0_Rounded as ErrorIcon} from '#/components/icon
|
|||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {refetchAgeAssuranceServerState} from '#/ageAssurance'
|
import {refetchAgeAssuranceServerState} from '#/ageAssurance'
|
||||||
import {logger} from '#/ageAssurance'
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_NATIVE} from '#/env'
|
import {IS_NATIVE} from '#/env'
|
||||||
|
|
||||||
export type AgeAssuranceRedirectDialogState = {
|
export type AgeAssuranceRedirectDialogState = {
|
||||||
@@ -81,6 +81,7 @@ export function AgeAssuranceRedirectDialog() {
|
|||||||
|
|
||||||
export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
|
export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const polling = useRef(false)
|
const polling = useRef(false)
|
||||||
@@ -94,7 +95,7 @@ export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
|
|||||||
|
|
||||||
polling.current = true
|
polling.current = true
|
||||||
|
|
||||||
logger.metric('ageAssurance:redirectDialogOpen', {})
|
ax.metric('ageAssurance:redirectDialogOpen', {})
|
||||||
|
|
||||||
wait(
|
wait(
|
||||||
3e3,
|
3e3,
|
||||||
@@ -125,18 +126,18 @@ export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
|
|||||||
|
|
||||||
setSuccess(true)
|
setSuccess(true)
|
||||||
|
|
||||||
logger.metric('ageAssurance:redirectDialogSuccess', {})
|
ax.metric('ageAssurance:redirectDialogSuccess', {})
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
if (unmounted.current) return
|
if (unmounted.current) return
|
||||||
setError(true)
|
setError(true)
|
||||||
logger.metric('ageAssurance:redirectDialogFail', {})
|
ax.metric('ageAssurance:redirectDialogFail', {})
|
||||||
})
|
})
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
unmounted.current = true
|
unmounted.current = true
|
||||||
}
|
}
|
||||||
}, [agent, control])
|
}, [ax, agent, control])
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import * as Layout from '#/components/Layout'
|
|||||||
import {Link} from '#/components/Link'
|
import {Link} from '#/components/Link'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {useAgeAssurance} from '#/ageAssurance'
|
import {useAgeAssurance} from '#/ageAssurance'
|
||||||
import {logger} from '#/ageAssurance'
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
export function AgeRestrictedScreen({
|
export function AgeRestrictedScreen({
|
||||||
children,
|
children,
|
||||||
@@ -27,6 +27,7 @@ export function AgeRestrictedScreen({
|
|||||||
rightHeaderSlot?: React.ReactNode
|
rightHeaderSlot?: React.ReactNode
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const copy = useAgeAssuranceCopy()
|
const copy = useAgeAssuranceCopy()
|
||||||
const aa = useAgeAssurance()
|
const aa = useAgeAssurance()
|
||||||
|
|
||||||
@@ -74,7 +75,7 @@ export function AgeRestrictedScreen({
|
|||||||
variant="solid"
|
variant="solid"
|
||||||
color="primary"
|
color="primary"
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric('ageAssurance:navigateToSettings', {})
|
ax.metric('ageAssurance:navigateToSettings', {})
|
||||||
}}>
|
}}>
|
||||||
<ButtonText>
|
<ButtonText>
|
||||||
<Trans>Go to account settings</Trans>
|
<Trans>Go to account settings</Trans>
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ import {msg, Trans} from '@lingui/macro'
|
|||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {HITSLOP_10} from '#/lib/constants'
|
import {HITSLOP_10} from '#/lib/constants'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {Nux, useNux, useSaveNux} from '#/state/queries/nuxs'
|
import {Nux, useNux, useSaveNux} from '#/state/queries/nuxs'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {Button} from '#/components/Button'
|
import {Button} from '#/components/Button'
|
||||||
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
|
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
import {Link} from '../Link'
|
import {Link} from '../Link'
|
||||||
import {useIsFindContactsFeatureEnabledBasedOnGeolocation} from './country-allowlist'
|
import {useIsFindContactsFeatureEnabledBasedOnGeolocation} from './country-allowlist'
|
||||||
@@ -19,6 +19,7 @@ import {useIsFindContactsFeatureEnabledBasedOnGeolocation} from './country-allow
|
|||||||
export function FindContactsBannerNUX() {
|
export function FindContactsBannerNUX() {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {visible, close} = useInternalState()
|
const {visible, close} = useInternalState()
|
||||||
|
|
||||||
if (!visible) return null
|
if (!visible) return null
|
||||||
@@ -30,7 +31,7 @@ export function FindContactsBannerNUX() {
|
|||||||
to={{screen: 'FindContactsFlow'}}
|
to={{screen: 'FindContactsFlow'}}
|
||||||
label={_(msg`Import contacts to find your friends`)}
|
label={_(msg`Import contacts to find your friends`)}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric('contacts:nux:bannerPressed', {})
|
ax.metric('contacts:nux:bannerPressed', {})
|
||||||
}}
|
}}
|
||||||
style={[
|
style={[
|
||||||
a.w_full,
|
a.w_full,
|
||||||
@@ -84,6 +85,7 @@ export function FindContactsBannerNUX() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
function useInternalState() {
|
function useInternalState() {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {nux} = useNux(Nux.FindContactsDismissibleBanner)
|
const {nux} = useNux(Nux.FindContactsDismissibleBanner)
|
||||||
const {mutate: save, variables} = useSaveNux()
|
const {mutate: save, variables} = useSaveNux()
|
||||||
const hidden = !!variables
|
const hidden = !!variables
|
||||||
@@ -103,7 +105,7 @@ function useInternalState() {
|
|||||||
completed: true,
|
completed: true,
|
||||||
data: undefined,
|
data: undefined,
|
||||||
})
|
})
|
||||||
logger.metric('contacts:nux:bannerDismissed', {})
|
ax.metric('contacts:nux:bannerDismissed', {})
|
||||||
}
|
}
|
||||||
|
|
||||||
return {visible, close}
|
return {visible, close}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import * as Layout from '#/components/Layout'
|
|||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import * as Toast from '#/components/Toast'
|
import * as Toast from '#/components/Toast'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {
|
import {
|
||||||
contactsWithPhoneNumbersOnly,
|
contactsWithPhoneNumbersOnly,
|
||||||
filterMatchedNumbers,
|
filterMatchedNumbers,
|
||||||
@@ -51,6 +52,7 @@ export function GetContacts({
|
|||||||
context: 'Onboarding' | 'Standalone'
|
context: 'Onboarding' | 'Standalone'
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const insets = useSafeAreaInsets()
|
const insets = useSafeAreaInsets()
|
||||||
const gutters = useGutters([0, 'wide'])
|
const gutters = useGutters([0, 'wide'])
|
||||||
@@ -100,16 +102,16 @@ export function GetContacts({
|
|||||||
},
|
},
|
||||||
onSuccess: (result, contacts) => {
|
onSuccess: (result, contacts) => {
|
||||||
if (context === 'Onboarding') {
|
if (context === 'Onboarding') {
|
||||||
logger.metric('onboarding:contacts:contactsShared', {})
|
ax.metric('onboarding:contacts:contactsShared', {})
|
||||||
}
|
}
|
||||||
if (result.matches.length > 0) {
|
if (result.matches.length > 0) {
|
||||||
logger.metric('contacts:import:success', {
|
ax.metric('contacts:import:success', {
|
||||||
contactCount: contacts.length,
|
contactCount: contacts.length,
|
||||||
matchCount: result.matches.length,
|
matchCount: result.matches.length,
|
||||||
entryPoint: context,
|
entryPoint: context,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
logger.metric('contacts:import:failure', {
|
ax.metric('contacts:import:failure', {
|
||||||
reason: 'noValidNumbers',
|
reason: 'noValidNumbers',
|
||||||
entryPoint: context,
|
entryPoint: context,
|
||||||
})
|
})
|
||||||
@@ -134,7 +136,7 @@ export function GetContacts({
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
onError: err => {
|
onError: err => {
|
||||||
logger.metric('contacts:import:failure', {
|
ax.metric('contacts:import:failure', {
|
||||||
reason: isNetworkError(err) ? 'networkError' : 'unknown',
|
reason: isNetworkError(err) ? 'networkError' : 'unknown',
|
||||||
entryPoint: context,
|
entryPoint: context,
|
||||||
})
|
})
|
||||||
@@ -180,7 +182,7 @@ export function GetContacts({
|
|||||||
permissions = await Contacts.requestPermissionsAsync()
|
permissions = await Contacts.requestPermissionsAsync()
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.metric('contacts:permission:request', {
|
ax.metric('contacts:permission:request', {
|
||||||
status: permissions.granted ? 'granted' : 'denied',
|
status: permissions.granted ? 'granted' : 'denied',
|
||||||
accessLevelIOS: ios(permissions.accessPrivileges),
|
accessLevelIOS: ios(permissions.accessPrivileges),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import * as Layout from '#/components/Layout'
|
|||||||
import {InlineLinkText} from '#/components/Link'
|
import {InlineLinkText} from '#/components/Link'
|
||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {useGeolocation} from '#/geolocation'
|
import {useGeolocation} from '#/geolocation'
|
||||||
import {isFindContactsFeatureEnabled} from '../country-allowlist'
|
import {isFindContactsFeatureEnabled} from '../country-allowlist'
|
||||||
import {
|
import {
|
||||||
@@ -52,6 +53,7 @@ export function PhoneInput({
|
|||||||
onSkip: () => void
|
onSkip: () => void
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const location = useGeolocation()
|
const location = useGeolocation()
|
||||||
@@ -85,7 +87,7 @@ export function PhoneInput({
|
|||||||
payload: {phoneCountryCode, phoneNumber},
|
payload: {phoneCountryCode, phoneNumber},
|
||||||
})
|
})
|
||||||
|
|
||||||
logger.metric('contacts:phone:phoneEntered', {entryPoint: context})
|
ax.metric('contacts:phone:phoneEntered', {entryPoint: context})
|
||||||
},
|
},
|
||||||
onMutate: () => {
|
onMutate: () => {
|
||||||
Keyboard.dismiss()
|
Keyboard.dismiss()
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import * as Layout from '#/components/Layout'
|
|||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import * as Toast from '#/components/Toast'
|
import * as Toast from '#/components/Toast'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {OTPInput} from '../components/OTPInput'
|
import {OTPInput} from '../components/OTPInput'
|
||||||
import {constructFullPhoneNumber, prettyPhoneNumber} from '../phone-number'
|
import {constructFullPhoneNumber, prettyPhoneNumber} from '../phone-number'
|
||||||
import {type Action, type State, useOnPressBackButton} from '../state'
|
import {type Action, type State, useOnPressBackButton} from '../state'
|
||||||
@@ -40,6 +41,7 @@ export function VerifyNumber({
|
|||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const gutters = useGutters([0, 'wide'])
|
const gutters = useGutters([0, 'wide'])
|
||||||
|
|
||||||
@@ -83,7 +85,7 @@ export function VerifyNumber({
|
|||||||
})
|
})
|
||||||
}, 1000)
|
}, 1000)
|
||||||
|
|
||||||
logger.metric('contacts:phone:phoneVerified', {entryPoint: context})
|
ax.metric('contacts:phone:phoneVerified', {entryPoint: context})
|
||||||
},
|
},
|
||||||
onMutate: () => setError(null),
|
onMutate: () => setError(null),
|
||||||
onError: err => {
|
onError: err => {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import {Loader} from '#/components/Loader'
|
|||||||
import * as ProfileCard from '#/components/ProfileCard'
|
import * as ProfileCard from '#/components/ProfileCard'
|
||||||
import * as Toast from '#/components/Toast'
|
import * as Toast from '#/components/Toast'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import type * as bsky from '#/types/bsky'
|
import type * as bsky from '#/types/bsky'
|
||||||
import {InviteInfo} from '../components/InviteInfo'
|
import {InviteInfo} from '../components/InviteInfo'
|
||||||
import {type Action, type Contact, type Match, type State} from '../state'
|
import {type Action, type Contact, type Match, type State} from '../state'
|
||||||
@@ -83,6 +84,7 @@ export function ViewMatches({
|
|||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const gutter = useGutters([0, 'wide'])
|
const gutter = useGutters([0, 'wide'])
|
||||||
const moderationOpts = useModerationOpts()
|
const moderationOpts = useModerationOpts()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
@@ -109,9 +111,9 @@ export function ViewMatches({
|
|||||||
|
|
||||||
const cumulativeFollowCount = useRef(0)
|
const cumulativeFollowCount = useRef(0)
|
||||||
const onFollow = useCallback(() => {
|
const onFollow = useCallback(() => {
|
||||||
logger.metric('contacts:matches:follow', {entryPoint: context})
|
ax.metric('contacts:matches:follow', {entryPoint: context})
|
||||||
cumulativeFollowCount.current += 1
|
cumulativeFollowCount.current += 1
|
||||||
}, [context])
|
}, [ax, context])
|
||||||
|
|
||||||
const {mutate: followAll, isPending: isFollowingAll} = useMutation({
|
const {mutate: followAll, isPending: isFollowingAll} = useMutation({
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
@@ -132,7 +134,7 @@ export function ViewMatches({
|
|||||||
return followableDids
|
return followableDids
|
||||||
},
|
},
|
||||||
onMutate: () =>
|
onMutate: () =>
|
||||||
logger.metric('contacts:matches:followAll', {
|
ax.metric('contacts:matches:followAll', {
|
||||||
followCount: followableDids.length,
|
followCount: followableDids.length,
|
||||||
entryPoint: context,
|
entryPoint: context,
|
||||||
}),
|
}),
|
||||||
@@ -218,7 +220,7 @@ export function ViewMatches({
|
|||||||
await agent.app.bsky.contact.dismissMatch({subject: did})
|
await agent.app.bsky.contact.dismissMatch({subject: did})
|
||||||
},
|
},
|
||||||
onMutate: did => {
|
onMutate: did => {
|
||||||
logger.metric('contacts:matches:dismiss', {entryPoint: context})
|
ax.metric('contacts:matches:dismiss', {entryPoint: context})
|
||||||
dispatch({type: 'DISMISS_MATCH', payload: {did}})
|
dispatch({type: 'DISMISS_MATCH', payload: {did}})
|
||||||
},
|
},
|
||||||
onSuccess: (_res, did) => {
|
onSuccess: (_res, did) => {
|
||||||
@@ -392,7 +394,7 @@ export function ViewMatches({
|
|||||||
label={context === 'Onboarding' ? _(msg`Next`) : _(msg`Done`)}
|
label={context === 'Onboarding' ? _(msg`Next`) : _(msg`Done`)}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
if (context === 'Onboarding') {
|
if (context === 'Onboarding') {
|
||||||
logger.metric('onboarding:contacts:nextPressed', {
|
ax.metric('onboarding:contacts:nextPressed', {
|
||||||
matchCount: allMatches.length,
|
matchCount: allMatches.length,
|
||||||
followCount: cumulativeFollowCount.current,
|
followCount: cumulativeFollowCount.current,
|
||||||
dismissedMatchCount: state.dismissedMatches.length,
|
dismissedMatchCount: state.dismissedMatches.length,
|
||||||
@@ -516,6 +518,7 @@ function ContactItem({
|
|||||||
const gutter = useGutters([0, 'wide'])
|
const gutter = useGutters([0, 'wide'])
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
|
|
||||||
const name = contact.name ?? contact.firstName ?? contact.lastName
|
const name = contact.name ?? contact.firstName ?? contact.lastName
|
||||||
@@ -564,7 +567,7 @@ function ContactItem({
|
|||||||
color="secondary"
|
color="secondary"
|
||||||
size="small"
|
size="small"
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
logger.metric('contacts:matches:invite', {
|
ax.metric('contacts:matches:invite', {
|
||||||
entryPoint: context,
|
entryPoint: context,
|
||||||
})
|
})
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {useQueryClient} from '@tanstack/react-query'
|
|||||||
|
|
||||||
import {useHaptics} from '#/lib/haptics'
|
import {useHaptics} from '#/lib/haptics'
|
||||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {STALE} from '#/state/queries'
|
import {STALE} from '#/state/queries'
|
||||||
import {useMyListsQuery} from '#/state/queries/my-lists'
|
import {useMyListsQuery} from '#/state/queries/my-lists'
|
||||||
import {useGetPost} from '#/state/queries/post'
|
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 {CloseQuote_Stroke2_Corner1_Rounded as QuoteIcon} from '#/components/icons/Quote'
|
||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_IOS} from '#/env'
|
import {IS_IOS} from '#/env'
|
||||||
|
|
||||||
export type PostInteractionSettingsFormProps = {
|
export type PostInteractionSettingsFormProps = {
|
||||||
@@ -80,8 +80,9 @@ export function PostInteractionSettingsControlledDialog({
|
|||||||
}: PostInteractionSettingsFormProps & {
|
}: PostInteractionSettingsFormProps & {
|
||||||
control: Dialog.DialogControlProps
|
control: Dialog.DialogControlProps
|
||||||
}) {
|
}) {
|
||||||
|
const ax = useAnalytics()
|
||||||
const onClose = useNonReactiveCallback(() => {
|
const onClose = useNonReactiveCallback(() => {
|
||||||
logger.metric('composer:threadgate:save', {
|
ax.metric('composer:threadgate:save', {
|
||||||
hasChanged: !!rest.isDirty,
|
hasChanged: !!rest.isDirty,
|
||||||
persist: !!rest.persist,
|
persist: !!rest.persist,
|
||||||
replyOptions:
|
replyOptions:
|
||||||
@@ -161,6 +162,7 @@ export function PostInteractionSettingsDialog(
|
|||||||
export function PostInteractionSettingsDialogControlledInner(
|
export function PostInteractionSettingsDialogControlledInner(
|
||||||
props: PostInteractionSettingsDialogProps,
|
props: PostInteractionSettingsDialogProps,
|
||||||
) {
|
) {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const [isSaving, setIsSaving] = useState(false)
|
const [isSaving, setIsSaving] = useState(false)
|
||||||
@@ -229,7 +231,7 @@ export function PostInteractionSettingsDialogControlledInner(
|
|||||||
|
|
||||||
props.control.close()
|
props.control.close()
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
logger.error(`Failed to save post interaction settings`, {
|
ax.logger.error(`Failed to save post interaction settings`, {
|
||||||
source: 'PostInteractionSettingsDialogControlledInner',
|
source: 'PostInteractionSettingsDialogControlledInner',
|
||||||
safeMessage: e.message,
|
safeMessage: e.message,
|
||||||
})
|
})
|
||||||
@@ -244,6 +246,7 @@ export function PostInteractionSettingsDialogControlledInner(
|
|||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
_,
|
_,
|
||||||
|
ax,
|
||||||
props.postUri,
|
props.postUri,
|
||||||
props.rootPostUri,
|
props.rootPostUri,
|
||||||
props.control,
|
props.control,
|
||||||
@@ -689,6 +692,7 @@ export function usePrefetchPostInteractionSettings({
|
|||||||
postUri: string
|
postUri: string
|
||||||
rootPostUri: string
|
rootPostUri: string
|
||||||
}) {
|
}) {
|
||||||
|
const ax = useAnalytics()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const getPost = useGetPost()
|
const getPost = useGetPost()
|
||||||
@@ -712,9 +716,9 @@ export function usePrefetchPostInteractionSettings({
|
|||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
logger.error(`Failed to prefetch post interaction settings`, {
|
ax.logger.error(`Failed to prefetch post interaction settings`, {
|
||||||
safeMessage: e.message,
|
safeMessage: e.message,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, [queryClient, agent, postUri, rootPostUri, getPost])
|
}, [ax, queryClient, agent, postUri, rootPostUri, getPost])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import {useCallback, useImperativeHandle, useRef, useState} from 'react'
|
import {useCallback, useImperativeHandle, useRef, useState} from 'react'
|
||||||
import {View} from 'react-native'
|
import {useWindowDimensions, View} from 'react-native'
|
||||||
import {useWindowDimensions} from 'react-native'
|
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {BSKY_SERVICE} from '#/lib/constants'
|
import {BSKY_SERVICE} from '#/lib/constants'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import * as persisted from '#/state/persisted'
|
import * as persisted from '#/state/persisted'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {atoms as a, platform, useBreakpoints, useTheme, web} from '#/alf'
|
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 {Globe_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe'
|
||||||
import {InlineLinkText} from '#/components/Link'
|
import {InlineLinkText} from '#/components/Link'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
type SegmentedControlOptions = typeof BSKY_SERVICE | 'custom'
|
type SegmentedControlOptions = typeof BSKY_SERVICE | 'custom'
|
||||||
|
|
||||||
@@ -27,6 +26,7 @@ export function ServerInputDialog({
|
|||||||
control: Dialog.DialogOuterProps['control']
|
control: Dialog.DialogOuterProps['control']
|
||||||
onSelect: (url: string) => void
|
onSelect: (url: string) => void
|
||||||
}) {
|
}) {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {height} = useWindowDimensions()
|
const {height} = useWindowDimensions()
|
||||||
const formRef = useRef<DialogInnerRef>(null)
|
const formRef = useRef<DialogInnerRef>(null)
|
||||||
|
|
||||||
@@ -43,10 +43,10 @@ export function ServerInputDialog({
|
|||||||
setPreviousCustomAddress(result)
|
setPreviousCustomAddress(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.metric('signin:hostingProviderPressed', {
|
ax.metric('signin:hostingProviderPressed', {
|
||||||
hostingProviderDidChange: fixedOption !== BSKY_SERVICE,
|
hostingProviderDidChange: fixedOption !== BSKY_SERVICE,
|
||||||
})
|
})
|
||||||
}, [onSelect, fixedOption])
|
}, [ax, onSelect, fixedOption])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog.Outer
|
<Dialog.Outer
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {useQueryClient} from '@tanstack/react-query'
|
|||||||
|
|
||||||
import {useRequireEmailVerification} from '#/lib/hooks/useRequireEmailVerification'
|
import {useRequireEmailVerification} from '#/lib/hooks/useRequireEmailVerification'
|
||||||
import {type NavigationProp} from '#/lib/routes/types'
|
import {type NavigationProp} from '#/lib/routes/types'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {
|
import {
|
||||||
invalidateActorStarterPacksWithMembershipQuery,
|
invalidateActorStarterPacksWithMembershipQuery,
|
||||||
useActorStarterPacksWithMembershipsQuery,
|
useActorStarterPacksWithMembershipsQuery,
|
||||||
@@ -31,6 +30,7 @@ import {StarterPack} from '#/components/icons/StarterPack'
|
|||||||
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
|
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
|
||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
import * as bsky from '#/types/bsky'
|
import * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
@@ -244,8 +244,9 @@ function StarterPackItem({
|
|||||||
starterPackWithMembership: StarterPackWithMembership
|
starterPackWithMembership: StarterPackWithMembership
|
||||||
targetDid: string
|
targetDid: string
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
|
const {_} = useLingui()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
const starterPack = starterPackWithMembership.starterPack
|
const starterPack = starterPackWithMembership.starterPack
|
||||||
@@ -304,7 +305,7 @@ function StarterPackItem({
|
|||||||
listUri: listUri,
|
listUri: listUri,
|
||||||
actorDid: targetDid,
|
actorDid: targetDid,
|
||||||
})
|
})
|
||||||
logger.metric('starterPack:addUser', {starterPack: starterPackUri})
|
ax.metric('starterPack:addUser', {starterPack: starterPackUri})
|
||||||
} else {
|
} else {
|
||||||
if (!starterPackWithMembership.listItem?.uri) {
|
if (!starterPackWithMembership.listItem?.uri) {
|
||||||
console.error('Cannot remove: missing membership URI')
|
console.error('Cannot remove: missing membership URI')
|
||||||
@@ -316,7 +317,7 @@ function StarterPackItem({
|
|||||||
actorDid: targetDid,
|
actorDid: targetDid,
|
||||||
membershipUri: starterPackWithMembership.listItem.uri,
|
membershipUri: starterPackWithMembership.listItem.uri,
|
||||||
})
|
})
|
||||||
logger.metric('starterPack:removeUser', {starterPack: starterPackUri})
|
ax.metric('starterPack:removeUser', {starterPack: starterPackUri})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {LinearGradient} from 'expo-linear-gradient'
|
|||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {atoms as a, useTheme, web} from '#/alf'
|
import {atoms as a, useTheme, web} from '#/alf'
|
||||||
import {Button, ButtonText} from '#/components/Button'
|
import {Button, ButtonText} from '#/components/Button'
|
||||||
import {isFindContactsFeatureEnabled} from '#/components/contacts/country-allowlist'
|
import {isFindContactsFeatureEnabled} from '#/components/contacts/country-allowlist'
|
||||||
@@ -16,8 +15,8 @@ import {
|
|||||||
isExistingUserAsOf,
|
isExistingUserAsOf,
|
||||||
} from '#/components/dialogs/nuxs/utils'
|
} from '#/components/dialogs/nuxs/utils'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {IS_NATIVE, IS_WEB} from '#/env'
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_E2E} from '#/env'
|
import {IS_E2E, IS_NATIVE, IS_WEB} from '#/env'
|
||||||
import {navigate} from '#/Navigation'
|
import {navigate} from '#/Navigation'
|
||||||
|
|
||||||
export const enabled = createIsEnabledCheck(props => {
|
export const enabled = createIsEnabledCheck(props => {
|
||||||
@@ -35,6 +34,7 @@ export const enabled = createIsEnabledCheck(props => {
|
|||||||
export function FindContactsAnnouncement() {
|
export function FindContactsAnnouncement() {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const nuxDialogs = useNuxDialogContext()
|
const nuxDialogs = useNuxDialogContext()
|
||||||
const control = Dialog.useDialogControl()
|
const control = Dialog.useDialogControl()
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ export function FindContactsAnnouncement() {
|
|||||||
size="large"
|
size="large"
|
||||||
color="primary"
|
color="primary"
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric('contacts:nux:ctaPressed', {})
|
ax.metric('contacts:nux:ctaPressed', {})
|
||||||
control.close(() => {
|
control.close(() => {
|
||||||
navigate('FindContactsFlow')
|
navigate('FindContactsFlow')
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {msg, Trans} from '@lingui/macro'
|
|||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {urls} from '#/lib/constants'
|
import {urls} from '#/lib/constants'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
||||||
import {Button, ButtonText} from '#/components/Button'
|
import {Button, ButtonText} from '#/components/Button'
|
||||||
import * as Dialog from '#/components/Dialog'
|
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 {VerifierCheck} from '#/components/icons/VerifierCheck'
|
||||||
import {Link} from '#/components/Link'
|
import {Link} from '#/components/Link'
|
||||||
import {Span, Text} from '#/components/Typography'
|
import {Span, Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_NATIVE} from '#/env'
|
import {IS_NATIVE} from '#/env'
|
||||||
|
|
||||||
export function InitialVerificationAnnouncement() {
|
export function InitialVerificationAnnouncement() {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {gtMobile} = useBreakpoints()
|
const {gtMobile} = useBreakpoints()
|
||||||
const nuxDialogs = useNuxDialogContext()
|
const nuxDialogs = useNuxDialogContext()
|
||||||
const control = Dialog.useDialogControl()
|
const control = Dialog.useDialogControl()
|
||||||
@@ -161,13 +162,9 @@ export function InitialVerificationAnnouncement() {
|
|||||||
color="primary"
|
color="primary"
|
||||||
style={[a.justify_center, a.w_full]}
|
style={[a.justify_center, a.w_full]}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric(
|
ax.metric('verification:learn-more', {
|
||||||
'verification:learn-more',
|
location: 'initialAnnouncementeNux',
|
||||||
{
|
})
|
||||||
location: 'initialAnnouncementeNux',
|
|
||||||
},
|
|
||||||
{statsig: false},
|
|
||||||
)
|
|
||||||
}}>
|
}}>
|
||||||
<ButtonText>
|
<ButtonText>
|
||||||
<Trans>Read blog post</Trans>
|
<Trans>Read blog post</Trans>
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {useLingui} from '@lingui/react'
|
|||||||
|
|
||||||
import {useTranslate} from '#/lib/hooks/useTranslate'
|
import {useTranslate} from '#/lib/hooks/useTranslate'
|
||||||
import {richTextToString} from '#/lib/strings/rich-text-helpers'
|
import {richTextToString} from '#/lib/strings/rich-text-helpers'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useConvoActive} from '#/state/messages/convo'
|
import {useConvoActive} from '#/state/messages/convo'
|
||||||
import {useLanguagePrefs} from '#/state/preferences'
|
import {useLanguagePrefs} from '#/state/preferences'
|
||||||
import {useSession} from '#/state/session'
|
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 {ReportDialog} from '#/components/moderation/ReportDialog'
|
||||||
import * as Prompt from '#/components/Prompt'
|
import * as Prompt from '#/components/Prompt'
|
||||||
import {usePromptControl} from '#/components/Prompt'
|
import {usePromptControl} from '#/components/Prompt'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_NATIVE} from '#/env'
|
import {IS_NATIVE} from '#/env'
|
||||||
import {EmojiReactionPicker} from './EmojiReactionPicker'
|
import {EmojiReactionPicker} from './EmojiReactionPicker'
|
||||||
import {hasReachedReactionLimit} from './util'
|
import {hasReachedReactionLimit} from './util'
|
||||||
@@ -34,6 +34,7 @@ export let MessageContextMenu = ({
|
|||||||
children: TriggerProps['children']
|
children: TriggerProps['children']
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const convo = useConvoActive()
|
const convo = useConvoActive()
|
||||||
const deleteControl = usePromptControl()
|
const deleteControl = usePromptControl()
|
||||||
@@ -60,16 +61,12 @@ export let MessageContextMenu = ({
|
|||||||
const onPressTranslateMessage = useCallback(() => {
|
const onPressTranslateMessage = useCallback(() => {
|
||||||
translate(message.text, langPrefs.primaryLanguage)
|
translate(message.text, langPrefs.primaryLanguage)
|
||||||
|
|
||||||
logger.metric(
|
ax.metric('translate', {
|
||||||
'translate',
|
sourceLanguages: [],
|
||||||
{
|
targetLanguage: langPrefs.primaryLanguage,
|
||||||
sourceLanguages: [],
|
textLength: message.text.length,
|
||||||
targetLanguage: langPrefs.primaryLanguage,
|
})
|
||||||
textLength: message.text.length,
|
}, [ax, langPrefs.primaryLanguage, message.text, translate])
|
||||||
},
|
|
||||||
{statsig: false},
|
|
||||||
)
|
|
||||||
}, [langPrefs.primaryLanguage, message.text, translate])
|
|
||||||
|
|
||||||
const onDelete = useCallback(() => {
|
const onDelete = useCallback(() => {
|
||||||
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
|
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {useOpenLink} from '#/lib/hooks/useOpenLink'
|
|||||||
import {type NavigationProp} from '#/lib/routes/types'
|
import {type NavigationProp} from '#/lib/routes/types'
|
||||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||||
import {toNiceDomain} from '#/lib/strings/url-helpers'
|
import {toNiceDomain} from '#/lib/strings/url-helpers'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {unstableCacheProfileView} from '#/state/queries/profile'
|
import {unstableCacheProfileView} from '#/state/queries/profile'
|
||||||
import {android, atoms as a, platform, tokens, useTheme, web} from '#/alf'
|
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 {useGlobalReportDialogControl} from '#/components/moderation/ReportDialog'
|
||||||
import * as ProfileCard from '#/components/ProfileCard'
|
import * as ProfileCard from '#/components/ProfileCard'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import type * as bsky from '#/types/bsky'
|
import type * as bsky from '#/types/bsky'
|
||||||
import {Globe_Stroke2_Corner0_Rounded} from '../icons/Globe'
|
import {Globe_Stroke2_Corner0_Rounded} from '../icons/Globe'
|
||||||
import {SquareArrowTopRight_Stroke2_Corner0_Rounded as SquareArrowTopRightIcon} from '../icons/SquareArrowTopRight'
|
import {SquareArrowTopRight_Stroke2_Corner0_Rounded as SquareArrowTopRightIcon} from '../icons/SquareArrowTopRight'
|
||||||
@@ -103,6 +103,7 @@ export function LiveStatus({
|
|||||||
padding?: 'lg' | 'xl'
|
padding?: 'lg' | 'xl'
|
||||||
onPressOpenProfile: () => void
|
onPressOpenProfile: () => void
|
||||||
}) {
|
}) {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
@@ -174,11 +175,7 @@ export function LiveStatus({
|
|||||||
color="primary"
|
color="primary"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric(
|
ax.metric('live:card:watch', {subject: profile.did})
|
||||||
'live:card:watch',
|
|
||||||
{subject: profile.did},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
openLink(embed.external.uri, false)
|
openLink(embed.external.uri, false)
|
||||||
}}>
|
}}>
|
||||||
<ButtonText>
|
<ButtonText>
|
||||||
@@ -207,11 +204,7 @@ export function LiveStatus({
|
|||||||
color="secondary"
|
color="secondary"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric(
|
ax.metric('live:card:openProfile', {subject: profile.did})
|
||||||
'live:card:openProfile',
|
|
||||||
{subject: profile.did},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
unstableCacheProfileView(queryClient, profile)
|
unstableCacheProfileView(queryClient, profile)
|
||||||
onPressOpenProfile()
|
onPressOpenProfile()
|
||||||
}}>
|
}}>
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
|||||||
import {uploadBlob} from '#/lib/api'
|
import {uploadBlob} from '#/lib/api'
|
||||||
import {imageToThumb} from '#/lib/api/resolve'
|
import {imageToThumb} from '#/lib/api/resolve'
|
||||||
import {getLinkMeta, type LinkMeta} from '#/lib/link-meta/link-meta'
|
import {getLinkMeta, type LinkMeta} from '#/lib/link-meta/link-meta'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {updateProfileShadow} from '#/state/cache/profile-shadow'
|
import {updateProfileShadow} from '#/state/cache/profile-shadow'
|
||||||
import {useLiveNowConfig} from '#/state/service-config'
|
import {useLiveNowConfig} from '#/state/service-config'
|
||||||
import {useAgent, useSession} from '#/state/session'
|
import {useAgent, useSession} from '#/state/session'
|
||||||
import * as Toast from '#/view/com/util/Toast'
|
import * as Toast from '#/view/com/util/Toast'
|
||||||
import {useDialogContext} from '#/components/Dialog'
|
import {useDialogContext} from '#/components/Dialog'
|
||||||
import {getLiveServiceNames} from '#/components/live/utils'
|
import {getLiveServiceNames} from '#/components/live/utils'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
export function useLiveLinkMetaQuery(url: string | null) {
|
export function useLiveLinkMetaQuery(url: string | null) {
|
||||||
const liveNowConfig = useLiveNowConfig()
|
const liveNowConfig = useLiveNowConfig()
|
||||||
@@ -50,6 +50,7 @@ export function useUpsertLiveStatusMutation(
|
|||||||
linkMeta: LinkMeta | null | undefined,
|
linkMeta: LinkMeta | null | undefined,
|
||||||
createdAt?: string,
|
createdAt?: string,
|
||||||
) {
|
) {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
@@ -77,7 +78,7 @@ export function useUpsertLiveStatusMutation(
|
|||||||
thumb = blob.data.blob
|
thumb = blob.data.blob
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} 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,
|
url: linkMeta.url,
|
||||||
image: linkMeta.image,
|
image: linkMeta.image,
|
||||||
safeMessage: e,
|
safeMessage: e,
|
||||||
@@ -133,7 +134,7 @@ export function useUpsertLiveStatusMutation(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError: (e: any) => {
|
onError: (e: any) => {
|
||||||
logger.error(`Failed to upsert live status`, {
|
ax.logger.error(`Failed to upsert live status`, {
|
||||||
url: linkMeta?.url,
|
url: linkMeta?.url,
|
||||||
image: linkMeta?.image,
|
image: linkMeta?.image,
|
||||||
safeMessage: e,
|
safeMessage: e,
|
||||||
@@ -141,17 +142,9 @@ export function useUpsertLiveStatusMutation(
|
|||||||
},
|
},
|
||||||
onSuccess: ({record, image}) => {
|
onSuccess: ({record, image}) => {
|
||||||
if (createdAt) {
|
if (createdAt) {
|
||||||
logger.metric(
|
ax.metric('live:edit', {duration: record.durationMinutes})
|
||||||
'live:edit',
|
|
||||||
{duration: record.durationMinutes},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
logger.metric(
|
ax.metric('live:create', {duration: record.durationMinutes})
|
||||||
'live:create',
|
|
||||||
{duration: record.durationMinutes},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Toast.show(_(msg`You are now live!`))
|
Toast.show(_(msg`You are now live!`))
|
||||||
@@ -187,6 +180,7 @@ export function useUpsertLiveStatusMutation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useRemoveLiveStatusMutation() {
|
export function useRemoveLiveStatusMutation() {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
@@ -203,12 +197,12 @@ export function useRemoveLiveStatusMutation() {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
onError: (e: any) => {
|
onError: (e: any) => {
|
||||||
logger.error(`Failed to remove live status`, {
|
ax.logger.error(`Failed to remove live status`, {
|
||||||
safeMessage: e,
|
safeMessage: e,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
logger.metric('live:remove', {}, {statsig: true})
|
ax.metric('live:remove', {})
|
||||||
Toast.show(_(msg`You are no longer live`))
|
Toast.show(_(msg`You are no longer live`))
|
||||||
control.close(() => {
|
control.close(() => {
|
||||||
if (!currentAccount) return
|
if (!currentAccount) return
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {useLingui} from '@lingui/react'
|
|||||||
import {wait} from '#/lib/async/wait'
|
import {wait} from '#/lib/async/wait'
|
||||||
import {getLabelingServiceTitle} from '#/lib/moderation'
|
import {getLabelingServiceTitle} from '#/lib/moderation'
|
||||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||||
import {Logger} from '#/logger'
|
|
||||||
import {useMyLabelersQuery} from '#/state/queries/preferences'
|
import {useMyLabelersQuery} from '#/state/queries/preferences'
|
||||||
import {CharProgress} from '#/view/com/composer/char-progress/CharProgress'
|
import {CharProgress} from '#/view/com/composer/char-progress/CharProgress'
|
||||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
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 {createStaticClick, InlineLinkText, Link} from '#/components/Link'
|
||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_NATIVE} from '#/env'
|
import {IS_NATIVE} from '#/env'
|
||||||
import {useSubmitReportMutation} from './action'
|
import {useSubmitReportMutation} from './action'
|
||||||
import {
|
import {
|
||||||
@@ -53,8 +53,6 @@ export function useGlobalReportDialogControl() {
|
|||||||
return useGlobalDialogsControlContext().reportDialogControl
|
return useGlobalDialogsControlContext().reportDialogControl
|
||||||
}
|
}
|
||||||
|
|
||||||
const logger = Logger.create(Logger.Context.ReportDialog)
|
|
||||||
|
|
||||||
export function GlobalReportDialog() {
|
export function GlobalReportDialog() {
|
||||||
const {value, control} = useGlobalReportDialogControl()
|
const {value, control} = useGlobalReportDialogControl()
|
||||||
return <ReportDialog control={control} subject={value?.subject} />
|
return <ReportDialog control={control} subject={value?.subject} />
|
||||||
@@ -65,13 +63,14 @@ export function ReportDialog(
|
|||||||
subject?: ReportSubject
|
subject?: ReportSubject
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
const ax = useAnalytics()
|
||||||
const subject = React.useMemo(
|
const subject = React.useMemo(
|
||||||
() => (props.subject ? parseReportSubject(props.subject) : undefined),
|
() => (props.subject ? parseReportSubject(props.subject) : undefined),
|
||||||
[props.subject],
|
[props.subject],
|
||||||
)
|
)
|
||||||
const onClose = React.useCallback(() => {
|
const onClose = React.useCallback(() => {
|
||||||
logger.metric('reportDialog:close', {}, {statsig: false})
|
ax.metric('reportDialog:close', {})
|
||||||
}, [])
|
}, [ax])
|
||||||
return (
|
return (
|
||||||
<Dialog.Outer control={props.control} onClose={onClose}>
|
<Dialog.Outer control={props.control} onClose={onClose}>
|
||||||
<Dialog.Handle />
|
<Dialog.Handle />
|
||||||
@@ -103,6 +102,8 @@ function Invalid() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Inner(props: ReportDialogProps) {
|
function Inner(props: ReportDialogProps) {
|
||||||
|
const ax = useAnalytics()
|
||||||
|
const logger = ax.logger.useContext(ax.logger.Context.ReportDialog)
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const ref = React.useRef<ScrollView>(null)
|
const ref = React.useRef<ScrollView>(null)
|
||||||
@@ -208,15 +209,11 @@ function Inner(props: ReportDialogProps) {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
setSuccess(true)
|
setSuccess(true)
|
||||||
logger.metric(
|
ax.metric('reportDialog:success', {
|
||||||
'reportDialog:success',
|
reason: state.selectedOption?.reason ?? '',
|
||||||
{
|
labeler: state.selectedLabeler?.creator.handle ?? '',
|
||||||
reason: state.selectedOption?.reason ?? '',
|
details: !!state.details,
|
||||||
labeler: state.selectedLabeler?.creator.handle ?? '',
|
})
|
||||||
details: !!state.details,
|
|
||||||
},
|
|
||||||
{statsig: false},
|
|
||||||
)
|
|
||||||
// give time for user feedback
|
// give time for user feedback
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
props.control.close(() => {
|
props.control.close(() => {
|
||||||
@@ -224,7 +221,7 @@ function Inner(props: ReportDialogProps) {
|
|||||||
})
|
})
|
||||||
}, 1e3)
|
}, 1e3)
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
logger.metric('reportDialog:failure', {}, {statsig: false})
|
ax.metric('reportDialog:failure', {})
|
||||||
logger.error(e, {
|
logger.error(e, {
|
||||||
source: 'ReportDialog',
|
source: 'ReportDialog',
|
||||||
})
|
})
|
||||||
@@ -238,7 +235,7 @@ function Inner(props: ReportDialogProps) {
|
|||||||
}, [_, submitReport, state, dispatch, props, setPending, setSuccess])
|
}, [_, submitReport, state, dispatch, props, setPending, setSuccess])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
logger.metric(
|
ax.metric(
|
||||||
'reportDialog:open',
|
'reportDialog:open',
|
||||||
{
|
{
|
||||||
subjectType: props.subject.type,
|
subjectType: props.subject.type,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import {View} from 'react-native'
|
|||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {type Shadow} from '#/state/cache/types'
|
import {type Shadow} from '#/state/cache/types'
|
||||||
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
||||||
import {Button} from '#/components/Button'
|
import {Button} from '#/components/Button'
|
||||||
@@ -12,6 +11,7 @@ import {type FullVerificationState} from '#/components/verification'
|
|||||||
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
||||||
import {VerificationsDialog} from '#/components/verification/VerificationsDialog'
|
import {VerificationsDialog} from '#/components/verification/VerificationsDialog'
|
||||||
import {VerifierDialog} from '#/components/verification/VerifierDialog'
|
import {VerifierDialog} from '#/components/verification/VerifierDialog'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import type * as bsky from '#/types/bsky'
|
import type * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
export function shouldShowVerificationCheckButton(
|
export function shouldShowVerificationCheckButton(
|
||||||
@@ -77,6 +77,7 @@ export function Badge({
|
|||||||
size: 'lg' | 'md' | 'sm'
|
size: 'lg' | 'md' | 'sm'
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const verificationsDialogControl = useDialogControl()
|
const verificationsDialogControl = useDialogControl()
|
||||||
const verifierDialogControl = useDialogControl()
|
const verifierDialogControl = useDialogControl()
|
||||||
@@ -101,7 +102,7 @@ export function Badge({
|
|||||||
hitSlop={20}
|
hitSlop={20}
|
||||||
onPress={evt => {
|
onPress={evt => {
|
||||||
evt.preventDefault()
|
evt.preventDefault()
|
||||||
logger.metric('verification:badge:click', {}, {statsig: true})
|
ax.metric('verification:badge:click', {})
|
||||||
if (state.profile.role === 'verifier') {
|
if (state.profile.role === 'verifier') {
|
||||||
verifierDialogControl.open()
|
verifierDialogControl.open()
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {useLingui} from '@lingui/react'
|
|||||||
|
|
||||||
import {urls} from '#/lib/constants'
|
import {urls} from '#/lib/constants'
|
||||||
import {getUserDisplayName} from '#/lib/getUserDisplayName'
|
import {getUserDisplayName} from '#/lib/getUserDisplayName'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {useProfileQuery} from '#/state/queries/profile'
|
import {useProfileQuery} from '#/state/queries/profile'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
@@ -20,6 +19,7 @@ import * as ProfileCard from '#/components/ProfileCard'
|
|||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {type FullVerificationState} from '#/components/verification'
|
import {type FullVerificationState} from '#/components/verification'
|
||||||
import {VerificationRemovePrompt} from '#/components/verification/VerificationRemovePrompt'
|
import {VerificationRemovePrompt} from '#/components/verification/VerificationRemovePrompt'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import type * as bsky from '#/types/bsky'
|
import type * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
export {useDialogControl} from '#/components/Dialog'
|
export {useDialogControl} from '#/components/Dialog'
|
||||||
@@ -55,6 +55,7 @@ function Inner({
|
|||||||
verificationState: FullVerificationState
|
verificationState: FullVerificationState
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {gtMobile} = useBreakpoints()
|
const {gtMobile} = useBreakpoints()
|
||||||
|
|
||||||
@@ -158,13 +159,9 @@ function Inner({
|
|||||||
color="secondary"
|
color="secondary"
|
||||||
style={[a.justify_center]}
|
style={[a.justify_center]}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric(
|
ax.metric('verification:learn-more', {
|
||||||
'verification:learn-more',
|
location: 'verificationsDialog',
|
||||||
{
|
})
|
||||||
location: 'verificationsDialog',
|
|
||||||
},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
}}>
|
}}>
|
||||||
<ButtonText>
|
<ButtonText>
|
||||||
<Trans context="english-only-resource">Learn more</Trans>
|
<Trans context="english-only-resource">Learn more</Trans>
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {useLingui} from '@lingui/react'
|
|||||||
|
|
||||||
import {urls} from '#/lib/constants'
|
import {urls} from '#/lib/constants'
|
||||||
import {getUserDisplayName} from '#/lib/getUserDisplayName'
|
import {getUserDisplayName} from '#/lib/getUserDisplayName'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
||||||
import {Button, ButtonText} from '#/components/Button'
|
import {Button, ButtonText} from '#/components/Button'
|
||||||
@@ -14,6 +13,7 @@ import {VerifierCheck} from '#/components/icons/VerifierCheck'
|
|||||||
import {Link} from '#/components/Link'
|
import {Link} from '#/components/Link'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {type FullVerificationState} from '#/components/verification'
|
import {type FullVerificationState} from '#/components/verification'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import type * as bsky from '#/types/bsky'
|
import type * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
export {useDialogControl} from '#/components/Dialog'
|
export {useDialogControl} from '#/components/Dialog'
|
||||||
@@ -49,6 +49,7 @@ function Inner({
|
|||||||
verificationState: FullVerificationState
|
verificationState: FullVerificationState
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {gtMobile} = useBreakpoints()
|
const {gtMobile} = useBreakpoints()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
@@ -126,7 +127,7 @@ function Inner({
|
|||||||
color="primary"
|
color="primary"
|
||||||
style={[a.justify_center]}
|
style={[a.justify_center]}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric(
|
ax.metric(
|
||||||
'verification:learn-more',
|
'verification:learn-more',
|
||||||
{
|
{
|
||||||
location: 'verifierDialog',
|
location: 'verifierDialog',
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import {msg} from '@lingui/macro'
|
|||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {isBskyCustomFeedUrl} from '#/lib/strings/url-helpers'
|
import {isBskyCustomFeedUrl} from '#/lib/strings/url-helpers'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {atoms as a, utils} from '#/alf'
|
import {atoms as a, utils} from '#/alf'
|
||||||
import {Live_Stroke2_Corner0_Rounded as LiveIcon} from '#/components/icons/Live'
|
import {Live_Stroke2_Corner0_Rounded as LiveIcon} from '#/components/icons/Live'
|
||||||
import {Link} from '#/components/Link'
|
import {Link} from '#/components/Link'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {
|
import {
|
||||||
type LiveEventFeed,
|
type LiveEventFeed,
|
||||||
type LiveEventFeedMetricContext,
|
type LiveEventFeedMetricContext,
|
||||||
@@ -26,6 +26,7 @@ export function LiveEventFeedCardCompact({
|
|||||||
metricContext: LiveEventFeedMetricContext
|
metricContext: LiveEventFeedMetricContext
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
|
|
||||||
const layout = feed.layouts.compact
|
const layout = feed.layouts.compact
|
||||||
const overlayColor = layout.overlayColor
|
const overlayColor = layout.overlayColor
|
||||||
@@ -39,7 +40,7 @@ export function LiveEventFeedCardCompact({
|
|||||||
}, [feed.url])
|
}, [feed.url])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
logger.metric('liveEvents:feedBanner:seen', {
|
ax.metric('liveEvents:feedBanner:seen', {
|
||||||
feed: feed.url,
|
feed: feed.url,
|
||||||
context: metricContext,
|
context: metricContext,
|
||||||
})
|
})
|
||||||
@@ -52,7 +53,7 @@ export function LiveEventFeedCardCompact({
|
|||||||
label={_(msg`Live event happening now: ${feed.title}`)}
|
label={_(msg`Live event happening now: ${feed.title}`)}
|
||||||
style={[a.w_full]}
|
style={[a.w_full]}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric('liveEvents:feedBanner:click', {
|
ax.metric('liveEvents:feedBanner:click', {
|
||||||
feed: feed.url,
|
feed: feed.url,
|
||||||
context: metricContext,
|
context: metricContext,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import {msg, Trans} from '@lingui/macro'
|
|||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {isBskyCustomFeedUrl} from '#/lib/strings/url-helpers'
|
import {isBskyCustomFeedUrl} from '#/lib/strings/url-helpers'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {atoms as a, useBreakpoints, utils} from '#/alf'
|
import {atoms as a, useBreakpoints, utils} from '#/alf'
|
||||||
import {Link} from '#/components/Link'
|
import {Link} from '#/components/Link'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {
|
import {
|
||||||
type LiveEventFeed,
|
type LiveEventFeed,
|
||||||
type LiveEventFeedMetricContext,
|
type LiveEventFeedMetricContext,
|
||||||
@@ -24,6 +24,7 @@ export function LiveEventFeedCardWide({
|
|||||||
feed: LiveEventFeed
|
feed: LiveEventFeed
|
||||||
metricContext: LiveEventFeedMetricContext
|
metricContext: LiveEventFeedMetricContext
|
||||||
}) {
|
}) {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {gtPhone} = useBreakpoints()
|
const {gtPhone} = useBreakpoints()
|
||||||
|
|
||||||
@@ -38,8 +39,9 @@ export function LiveEventFeedCardWide({
|
|||||||
return '/'
|
return '/'
|
||||||
}, [feed.url])
|
}, [feed.url])
|
||||||
|
|
||||||
|
// TODO double check this
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
logger.metric('liveEvents:feedBanner:seen', {
|
ax.metric('liveEvents:feedBanner:seen', {
|
||||||
feed: feed.url,
|
feed: feed.url,
|
||||||
context: metricContext,
|
context: metricContext,
|
||||||
})
|
})
|
||||||
@@ -52,7 +54,7 @@ export function LiveEventFeedCardWide({
|
|||||||
label={_(msg`Live event happening now: ${feed.title}`)}
|
label={_(msg`Live event happening now: ${feed.title}`)}
|
||||||
style={[a.w_full]}
|
style={[a.w_full]}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric('liveEvents:feedBanner:click', {
|
ax.metric('liveEvents:feedBanner:click', {
|
||||||
feed: feed.url,
|
feed: feed.url,
|
||||||
context: metricContext,
|
context: metricContext,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ import {useEffect} from 'react'
|
|||||||
import {type Agent, AppBskyActorDefs, asPredicate} from '@atproto/api'
|
import {type Agent, AppBskyActorDefs, asPredicate} from '@atproto/api'
|
||||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {
|
import {
|
||||||
preferencesQueryKey,
|
preferencesQueryKey,
|
||||||
usePreferencesQuery,
|
usePreferencesQuery,
|
||||||
} from '#/state/queries/preferences'
|
} from '#/state/queries/preferences'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAgent} from '#/state/session'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
import * as env from '#/env'
|
import * as env from '#/env'
|
||||||
import {
|
import {
|
||||||
@@ -63,6 +63,7 @@ export function useUpdateLiveEventPreferences(props: {
|
|||||||
undoAction: LiveEventPreferencesAction | null
|
undoAction: LiveEventPreferencesAction | null
|
||||||
}) => void
|
}) => void
|
||||||
}) {
|
}) {
|
||||||
|
const ax = useAnalytics()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
|
|
||||||
@@ -116,7 +117,7 @@ export function useUpdateLiveEventPreferences(props: {
|
|||||||
case 'hideFeed':
|
case 'hideFeed':
|
||||||
case 'unhideFeed': {
|
case 'unhideFeed': {
|
||||||
if (!props.feed) {
|
if (!props.feed) {
|
||||||
logger.error(
|
ax.logger.error(
|
||||||
`useUpdateLiveEventPreferences: feed is missing, but required for hiding/unhiding`,
|
`useUpdateLiveEventPreferences: feed is missing, but required for hiding/unhiding`,
|
||||||
{
|
{
|
||||||
action,
|
action,
|
||||||
@@ -125,7 +126,7 @@ export function useUpdateLiveEventPreferences(props: {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.metric(
|
ax.metric(
|
||||||
action.type === 'hideFeed'
|
action.type === 'hideFeed'
|
||||||
? 'liveEvents:feedBanner:hide'
|
? 'liveEvents:feedBanner:hide'
|
||||||
: 'liveEvents:feedBanner:unhide',
|
: 'liveEvents:feedBanner:unhide',
|
||||||
@@ -138,11 +139,11 @@ export function useUpdateLiveEventPreferences(props: {
|
|||||||
}
|
}
|
||||||
case 'toggleHideAllFeeds': {
|
case 'toggleHideAllFeeds': {
|
||||||
if (prefs!.hideAllFeeds) {
|
if (prefs!.hideAllFeeds) {
|
||||||
logger.metric('liveEvents:hideAllFeedBanners', {
|
ax.metric('liveEvents:hideAllFeedBanners', {
|
||||||
context: props.metricContext,
|
context: props.metricContext,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
logger.metric('liveEvents:unhideAllFeedBanners', {
|
ax.metric('liveEvents:unhideAllFeedBanners', {
|
||||||
context: props.metricContext,
|
context: props.metricContext,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ const called: Record<OnceKey, boolean> = {
|
|||||||
[OnceKey.PreferencesThread]: false,
|
[OnceKey.PreferencesThread]: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO dedupe with runCallbackOnce
|
||||||
export function useCallOnce(key: OnceKey) {
|
export function useCallOnce(key: OnceKey) {
|
||||||
return useCallback(
|
return useCallback(
|
||||||
(cb: () => void) => {
|
(cb: () => void) => {
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import * as WebBrowser from 'expo-web-browser'
|
|||||||
|
|
||||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||||
import {parseLinkingUrl} from '#/lib/parseLinkingUrl'
|
import {parseLinkingUrl} from '#/lib/parseLinkingUrl'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {useCloseAllActiveElements} from '#/state/util'
|
import {useCloseAllActiveElements} from '#/state/util'
|
||||||
import {useIntentDialogs} from '#/components/intents/IntentDialogs'
|
import {useIntentDialogs} from '#/components/intents/IntentDialogs'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_IOS, IS_NATIVE} from '#/env'
|
import {IS_IOS, IS_NATIVE} from '#/env'
|
||||||
import {Referrer} from '../../../modules/expo-bluesky-swiss-army'
|
import {Referrer} from '../../../modules/expo-bluesky-swiss-army'
|
||||||
import {useApplyPullRequestOTAUpdate} from './useOTAUpdates'
|
import {useApplyPullRequestOTAUpdate} from './useOTAUpdates'
|
||||||
@@ -22,6 +22,7 @@ let previousIntentUrl = ''
|
|||||||
|
|
||||||
export function useIntentHandler() {
|
export function useIntentHandler() {
|
||||||
const incomingUrl = Linking.useLinkingURL()
|
const incomingUrl = Linking.useLinkingURL()
|
||||||
|
const ax = useAnalytics()
|
||||||
const composeIntent = useComposeIntent()
|
const composeIntent = useComposeIntent()
|
||||||
const verifyEmailIntent = useVerifyEmailIntent()
|
const verifyEmailIntent = useVerifyEmailIntent()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
@@ -36,7 +37,7 @@ export function useIntentHandler() {
|
|||||||
|
|
||||||
const referrerInfo = Referrer.getReferrerInfo()
|
const referrerInfo = Referrer.getReferrerInfo()
|
||||||
if (referrerInfo && referrerInfo.hostname !== 'bsky.app') {
|
if (referrerInfo && referrerInfo.hostname !== 'bsky.app') {
|
||||||
logger.metric('deepLink:referrerReceived', {
|
ax.metric('deepLink:referrerReceived', {
|
||||||
to: url,
|
to: url,
|
||||||
referrer: referrerInfo?.referrer,
|
referrer: referrerInfo?.referrer,
|
||||||
hostname: referrerInfo?.hostname,
|
hostname: referrerInfo?.hostname,
|
||||||
@@ -95,6 +96,7 @@ export function useIntentHandler() {
|
|||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
incomingUrl,
|
incomingUrl,
|
||||||
|
ax,
|
||||||
composeIntent,
|
composeIntent,
|
||||||
verifyEmailIntent,
|
verifyEmailIntent,
|
||||||
currentAccount,
|
currentAccount,
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ import {useCallback, useEffect} from 'react'
|
|||||||
import {Platform} from 'react-native'
|
import {Platform} from 'react-native'
|
||||||
import * as Notifications from 'expo-notifications'
|
import * as Notifications from 'expo-notifications'
|
||||||
import {getBadgeCountAsync, setBadgeCountAsync} from 'expo-notifications'
|
import {getBadgeCountAsync, setBadgeCountAsync} from 'expo-notifications'
|
||||||
import {type AtpAgent} from '@atproto/api'
|
import {type AppBskyNotificationRegisterPush, type AtpAgent} from '@atproto/api'
|
||||||
import {type AppBskyNotificationRegisterPush} from '@atproto/api'
|
|
||||||
import debounce from 'lodash.debounce'
|
import debounce from 'lodash.debounce'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -16,8 +15,8 @@ import {isNetworkError} from '#/lib/strings/errors'
|
|||||||
import {type SessionAccount, useAgent, useSession} from '#/state/session'
|
import {type SessionAccount, useAgent, useSession} from '#/state/session'
|
||||||
import BackgroundNotificationHandler from '#/../modules/expo-background-notification-handler'
|
import BackgroundNotificationHandler from '#/../modules/expo-background-notification-handler'
|
||||||
import {useAgeAssurance} from '#/ageAssurance'
|
import {useAgeAssurance} from '#/ageAssurance'
|
||||||
import {IS_NATIVE} from '#/env'
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_DEV} from '#/env'
|
import {IS_DEV, IS_NATIVE} from '#/env'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@@ -227,6 +226,7 @@ export function useNotificationsRegistration() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useRequestNotificationsPermission() {
|
export function useRequestNotificationsPermission() {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const getAndRegisterPushToken = useGetAndRegisterPushToken()
|
const getAndRegisterPushToken = useGetAndRegisterPushToken()
|
||||||
|
|
||||||
@@ -251,7 +251,7 @@ export function useRequestNotificationsPermission() {
|
|||||||
|
|
||||||
const res = await Notifications.requestPermissionsAsync()
|
const res = await Notifications.requestPermissionsAsync()
|
||||||
|
|
||||||
notyLogger.metric(`notifications:request`, {
|
ax.metric(`notifications:request`, {
|
||||||
context: context,
|
context: context,
|
||||||
status: res.status,
|
status: res.status,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import {
|
|||||||
type CommonNavigatorParams,
|
type CommonNavigatorParams,
|
||||||
type NativeStackScreenProps,
|
type NativeStackScreenProps,
|
||||||
} from '#/lib/routes/types'
|
} from '#/lib/routes/types'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useBookmarkMutation} from '#/state/queries/bookmarks/useBookmarkMutation'
|
import {useBookmarkMutation} from '#/state/queries/bookmarks/useBookmarkMutation'
|
||||||
import {useBookmarksQuery} from '#/state/queries/bookmarks/useBookmarksQuery'
|
import {useBookmarksQuery} from '#/state/queries/bookmarks/useBookmarksQuery'
|
||||||
import {useSetMinimalShellMode} from '#/state/shell'
|
import {useSetMinimalShellMode} from '#/state/shell'
|
||||||
@@ -37,18 +36,20 @@ import {ListFooter} from '#/components/Lists'
|
|||||||
import * as Skele from '#/components/Skeleton'
|
import * as Skele from '#/components/Skeleton'
|
||||||
import * as toast from '#/components/Toast'
|
import * as toast from '#/components/Toast'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_IOS} from '#/env'
|
import {IS_IOS} from '#/env'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Bookmarks'>
|
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Bookmarks'>
|
||||||
|
|
||||||
export function BookmarksScreen({}: Props) {
|
export function BookmarksScreen({}: Props) {
|
||||||
const setMinimalShellMode = useSetMinimalShellMode()
|
const setMinimalShellMode = useSetMinimalShellMode()
|
||||||
|
const ax = useAnalytics()
|
||||||
|
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
setMinimalShellMode(false)
|
setMinimalShellMode(false)
|
||||||
logger.metric('bookmarks:view', {})
|
ax.metric('bookmarks:view', {})
|
||||||
}, [setMinimalShellMode]),
|
}, [setMinimalShellMode, ax]),
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -144,7 +145,7 @@ function BookmarksInner() {
|
|||||||
key: bookmark.item.uri,
|
key: bookmark.item.uri,
|
||||||
bookmark: {
|
bookmark: {
|
||||||
...bookmark,
|
...bookmark,
|
||||||
item: bookmark.item as $Typed<AppBskyFeedDefs.NotFoundPost>,
|
item: bookmark.item,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -154,7 +155,7 @@ function BookmarksInner() {
|
|||||||
key: bookmark.item.uri,
|
key: bookmark.item.uri,
|
||||||
bookmark: {
|
bookmark: {
|
||||||
...bookmark,
|
...bookmark,
|
||||||
item: bookmark.item as $Typed<AppBskyFeedDefs.PostView>,
|
item: bookmark.item,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -270,6 +271,25 @@ function BookmarkNotFound({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function BookmarkItem({
|
||||||
|
item,
|
||||||
|
hideTopBorder,
|
||||||
|
}: {
|
||||||
|
item: Extract<ListItem, {type: 'bookmark'}>
|
||||||
|
hideTopBorder: boolean
|
||||||
|
}) {
|
||||||
|
const ax = useAnalytics()
|
||||||
|
return (
|
||||||
|
<Post
|
||||||
|
post={item.bookmark.item}
|
||||||
|
hideTopBorder={hideTopBorder}
|
||||||
|
onBeforePress={() => {
|
||||||
|
ax.metric('bookmarks:post-clicked', {})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function BookmarksEmpty() {
|
function BookmarksEmpty() {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
@@ -301,15 +321,7 @@ function renderItem({item, index}: {item: ListItem; index: number}) {
|
|||||||
return <BookmarksEmpty />
|
return <BookmarksEmpty />
|
||||||
}
|
}
|
||||||
case 'bookmark': {
|
case 'bookmark': {
|
||||||
return (
|
return <BookmarkItem item={item} hideTopBorder={index === 0} />
|
||||||
<Post
|
|
||||||
post={item.bookmark.item}
|
|
||||||
hideTopBorder={index === 0}
|
|
||||||
onBeforePress={() => {
|
|
||||||
logger.metric('bookmarks:post-clicked', {})
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
case 'bookmarkNotFound': {
|
case 'bookmarkNotFound': {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import {msg, Trans} from '@lingui/macro'
|
|||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {urls} from '#/lib/constants'
|
import {urls} from '#/lib/constants'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {
|
import {
|
||||||
usePreferencesQuery,
|
usePreferencesQuery,
|
||||||
type UsePreferencesQueryResponse,
|
type UsePreferencesQueryResponse,
|
||||||
@@ -17,9 +16,11 @@ import {CircleCheck_Stroke2_Corner0_Rounded as CircleCheck} from '#/components/i
|
|||||||
import * as Layout from '#/components/Layout'
|
import * as Layout from '#/components/Layout'
|
||||||
import {InlineLinkText} from '#/components/Link'
|
import {InlineLinkText} from '#/components/Link'
|
||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
export function Screen() {
|
export function Screen() {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const gutters = useGutters(['base'])
|
const gutters = useGutters(['base'])
|
||||||
const {data: preferences} = usePreferencesQuery()
|
const {data: preferences} = usePreferencesQuery()
|
||||||
|
|
||||||
@@ -51,13 +52,9 @@ export function Screen() {
|
|||||||
}),
|
}),
|
||||||
)}
|
)}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric(
|
ax.metric('verification:learn-more', {
|
||||||
'verification:learn-more',
|
location: 'verificationSettings',
|
||||||
{
|
})
|
||||||
location: 'verificationSettings',
|
|
||||||
},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
}}>
|
}}>
|
||||||
Learn more here.
|
Learn more here.
|
||||||
</InlineLinkText>
|
</InlineLinkText>
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import {useCallback, useState} from 'react'
|
|||||||
import {LayoutAnimationConfig} from 'react-native-reanimated'
|
import {LayoutAnimationConfig} from 'react-native-reanimated'
|
||||||
import {SafeAreaView} from 'react-native-safe-area-context'
|
import {SafeAreaView} from 'react-native-safe-area-context'
|
||||||
|
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {FindContactsFlow} from '#/components/contacts/FindContactsFlow'
|
import {FindContactsFlow} from '#/components/contacts/FindContactsFlow'
|
||||||
import {type Action, type State} from '#/components/contacts/state'
|
import {type Action, type State} from '#/components/contacts/state'
|
||||||
import {ScreenTransition} from '#/components/ScreenTransition'
|
import {ScreenTransition} from '#/components/ScreenTransition'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {useOnboardingInternalState} from '../state'
|
import {useOnboardingInternalState} from '../state'
|
||||||
|
|
||||||
export function StepFindContacts({
|
export function StepFindContacts({
|
||||||
@@ -16,6 +16,7 @@ export function StepFindContacts({
|
|||||||
flowDispatch: React.ActionDispatch<[Action]>
|
flowDispatch: React.ActionDispatch<[Action]>
|
||||||
}) {
|
}) {
|
||||||
const {dispatch} = useOnboardingInternalState()
|
const {dispatch} = useOnboardingInternalState()
|
||||||
|
const ax = useAnalytics()
|
||||||
|
|
||||||
const [transitionDirection, setTransitionDirection] = useState<
|
const [transitionDirection, setTransitionDirection] = useState<
|
||||||
'Forward' | 'Backward'
|
'Forward' | 'Backward'
|
||||||
@@ -24,10 +25,10 @@ export function StepFindContacts({
|
|||||||
const isFinalStep = flowState.step === '4: view matches'
|
const isFinalStep = flowState.step === '4: view matches'
|
||||||
const onSkip = useCallback(() => {
|
const onSkip = useCallback(() => {
|
||||||
if (!isFinalStep) {
|
if (!isFinalStep) {
|
||||||
logger.metric('onboarding:contacts:skipPressed', {})
|
ax.metric('onboarding:contacts:skipPressed', {})
|
||||||
}
|
}
|
||||||
dispatch({type: 'next'})
|
dispatch({type: 'next'})
|
||||||
}, [dispatch, isFinalStep])
|
}, [dispatch, isFinalStep, ax])
|
||||||
|
|
||||||
const canGoBack = flowState.step === '2: verify number'
|
const canGoBack = flowState.step === '2: verify number'
|
||||||
const onBack = useCallback(() => {
|
const onBack = useCallback(() => {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import * as bcp47Match from 'bcp-47-match'
|
|||||||
import {wait} from '#/lib/async/wait'
|
import {wait} from '#/lib/async/wait'
|
||||||
import {popularInterests, useInterestsDisplayNames} from '#/lib/interests'
|
import {popularInterests, useInterestsDisplayNames} from '#/lib/interests'
|
||||||
import {isBlockedOrBlocking, isMuted} from '#/lib/moderation/blocked-and-muted'
|
import {isBlockedOrBlocking, isMuted} from '#/lib/moderation/blocked-and-muted'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {updateProfileShadow} from '#/state/cache/profile-shadow'
|
import {updateProfileShadow} from '#/state/cache/profile-shadow'
|
||||||
import {useLanguagePrefs} from '#/state/preferences'
|
import {useLanguagePrefs} from '#/state/preferences'
|
||||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
@@ -30,12 +29,14 @@ import {boostInterests, InterestTabs} from '#/components/InterestTabs'
|
|||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import * as ProfileCard from '#/components/ProfileCard'
|
import * as ProfileCard from '#/components/ProfileCard'
|
||||||
import * as toast from '#/components/Toast'
|
import * as toast from '#/components/Toast'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
import type * as bsky from '#/types/bsky'
|
import type * as bsky from '#/types/bsky'
|
||||||
import {bulkWriteFollows} from '../util'
|
import {bulkWriteFollows} from '../util'
|
||||||
|
|
||||||
export function StepSuggestedAccounts() {
|
export function StepSuggestedAccounts() {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {gtMobile} = useBreakpoints()
|
const {gtMobile} = useBreakpoints()
|
||||||
const moderationOpts = useModerationOpts()
|
const moderationOpts = useModerationOpts()
|
||||||
@@ -92,7 +93,7 @@ export function StepSuggestedAccounts() {
|
|||||||
|
|
||||||
const {mutate: followAll, isPending: isFollowingAll} = useMutation({
|
const {mutate: followAll, isPending: isFollowingAll} = useMutation({
|
||||||
onMutate: () => {
|
onMutate: () => {
|
||||||
logger.metric('onboarding:suggestedAccounts:followAllPressed', {
|
ax.metric('onboarding:suggestedAccounts:followAllPressed', {
|
||||||
tab: selectedInterest ?? 'all',
|
tab: selectedInterest ?? 'all',
|
||||||
numAccounts: followableDids.length,
|
numAccounts: followableDids.length,
|
||||||
})
|
})
|
||||||
@@ -132,20 +133,16 @@ export function StepSuggestedAccounts() {
|
|||||||
(did: string, position: number) => {
|
(did: string, position: number) => {
|
||||||
if (!seenProfilesRef.current.has(did)) {
|
if (!seenProfilesRef.current.has(did)) {
|
||||||
seenProfilesRef.current.add(did)
|
seenProfilesRef.current.add(did)
|
||||||
logger.metric(
|
ax.metric('suggestedUser:seen', {
|
||||||
'suggestedUser:seen',
|
logContext: 'Onboarding',
|
||||||
{
|
recId: undefined,
|
||||||
logContext: 'Onboarding',
|
position,
|
||||||
recId: undefined,
|
suggestedDid: did,
|
||||||
position,
|
category: selectedInterest,
|
||||||
suggestedDid: did,
|
})
|
||||||
category: selectedInterest,
|
|
||||||
},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[selectedInterest],
|
[ax, selectedInterest],
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -297,6 +294,7 @@ function TabBar({
|
|||||||
defaultTabLabel?: string
|
defaultTabLabel?: string
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const interestsDisplayNames = useInterestsDisplayNames()
|
const interestsDisplayNames = useInterestsDisplayNames()
|
||||||
const interests = Object.keys(interestsDisplayNames)
|
const interests = Object.keys(interestsDisplayNames)
|
||||||
.sort(boostInterests(popularInterests))
|
.sort(boostInterests(popularInterests))
|
||||||
@@ -309,11 +307,7 @@ function TabBar({
|
|||||||
selectedInterest || (hideDefaultTab ? interests[0] : 'all')
|
selectedInterest || (hideDefaultTab ? interests[0] : 'all')
|
||||||
}
|
}
|
||||||
onSelectTab={tab => {
|
onSelectTab={tab => {
|
||||||
logger.metric(
|
ax.metric('onboarding:suggestedAccounts:tabPressed', {tab: tab})
|
||||||
'onboarding:suggestedAccounts:tabPressed',
|
|
||||||
{tab: tab},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
onSelectInterest(tab === 'all' ? null : tab)
|
onSelectInterest(tab === 'all' ? null : tab)
|
||||||
}}
|
}}
|
||||||
interestsDisplayNames={
|
interestsDisplayNames={
|
||||||
@@ -343,6 +337,7 @@ function SuggestedProfileCard({
|
|||||||
onSeen: (did: string, position: number) => void
|
onSeen: (did: string, position: number) => void
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
const cardRef = useRef<View>(null)
|
const cardRef = useRef<View>(null)
|
||||||
const hasTrackedRef = useRef(false)
|
const hasTrackedRef = useRef(false)
|
||||||
|
|
||||||
@@ -403,18 +398,14 @@ function SuggestedProfileCard({
|
|||||||
withIcon={false}
|
withIcon={false}
|
||||||
logContext="OnboardingSuggestedAccounts"
|
logContext="OnboardingSuggestedAccounts"
|
||||||
onFollow={() => {
|
onFollow={() => {
|
||||||
logger.metric(
|
ax.metric('suggestedUser:follow', {
|
||||||
'suggestedUser:follow',
|
logContext: 'Onboarding',
|
||||||
{
|
location: 'Card',
|
||||||
logContext: 'Onboarding',
|
recId: undefined,
|
||||||
location: 'Card',
|
position,
|
||||||
recId: undefined,
|
suggestedDid: profile.did,
|
||||||
position,
|
category,
|
||||||
suggestedDid: profile.did,
|
})
|
||||||
category,
|
|
||||||
},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</ProfileCard.Header>
|
</ProfileCard.Header>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {Check_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Che
|
|||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import * as Toast from '#/components/Toast'
|
import * as Toast from '#/components/Toast'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import * as bsky from '#/types/bsky'
|
import * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
const IGNORED_ACCOUNT = 'did:plc:pifkcjimdcfwaxkanzhwxufp'
|
const IGNORED_ACCOUNT = 'did:plc:pifkcjimdcfwaxkanzhwxufp'
|
||||||
@@ -30,6 +31,7 @@ export function StarterPackCard({
|
|||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const {gtPhone} = useBreakpoints()
|
const {gtPhone} = useBreakpoints()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
@@ -89,7 +91,7 @@ export function StarterPackCard({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
Toast.show(_(msg`All accounts have been followed!`), {type: 'success'})
|
Toast.show(_(msg`All accounts have been followed!`), {type: 'success'})
|
||||||
logger.metric('starterPack:followAll', {
|
ax.metric('starterPack:followAll', {
|
||||||
logContext: 'Onboarding',
|
logContext: 'Onboarding',
|
||||||
starterPack: view.uri,
|
starterPack: view.uri,
|
||||||
count: dids.length,
|
count: dids.length,
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ import {msg, Trans} from '@lingui/macro'
|
|||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {HITSLOP_10} from '#/lib/constants'
|
import {HITSLOP_10} from '#/lib/constants'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {type ThreadPreferences} from '#/state/queries/preferences/useThreadPreferences'
|
import {type ThreadPreferences} from '#/state/queries/preferences/useThreadPreferences'
|
||||||
import {Button, ButtonIcon} from '#/components/Button'
|
import {Button, ButtonIcon} from '#/components/Button'
|
||||||
import {SettingsSliderVertical_Stroke2_Corner0_Rounded as SettingsSlider} from '#/components/icons/SettingsSlider'
|
import {SettingsSliderVertical_Stroke2_Corner0_Rounded as SettingsSlider} from '#/components/icons/SettingsSlider'
|
||||||
import * as Menu from '#/components/Menu'
|
import * as Menu from '#/components/Menu'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
export function HeaderDropdown({
|
export function HeaderDropdown({
|
||||||
sort,
|
sort,
|
||||||
@@ -17,6 +17,7 @@ export function HeaderDropdown({
|
|||||||
ThreadPreferences,
|
ThreadPreferences,
|
||||||
'sort' | 'setSort' | 'view' | 'setView'
|
'sort' | 'setSort' | 'view' | 'setView'
|
||||||
>): React.ReactNode {
|
>): React.ReactNode {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
return (
|
return (
|
||||||
<Menu.Root>
|
<Menu.Root>
|
||||||
@@ -30,7 +31,7 @@ export function HeaderDropdown({
|
|||||||
shape="round"
|
shape="round"
|
||||||
hitSlop={HITSLOP_10}
|
hitSlop={HITSLOP_10}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric('thread:click:headerMenuOpen', {})
|
ax.metric('thread:click:headerMenuOpen', {})
|
||||||
onPress()
|
onPress()
|
||||||
}}
|
}}
|
||||||
{...props}>
|
{...props}>
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
|||||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||||
import {niceDate} from '#/lib/strings/time'
|
import {niceDate} from '#/lib/strings/time'
|
||||||
import {getTranslatorLink, isPostInLanguage} from '#/locale/helpers'
|
import {getTranslatorLink, isPostInLanguage} from '#/locale/helpers'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {
|
import {
|
||||||
POST_TOMBSTONE,
|
POST_TOMBSTONE,
|
||||||
type Shadow,
|
type Shadow,
|
||||||
@@ -60,6 +59,7 @@ import * as Skele from '#/components/Skeleton'
|
|||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {VerificationCheckButton} from '#/components/verification/VerificationCheckButton'
|
import {VerificationCheckButton} from '#/components/verification/VerificationCheckButton'
|
||||||
import {WhoCanReply} from '#/components/WhoCanReply'
|
import {WhoCanReply} from '#/components/WhoCanReply'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import * as bsky from '#/types/bsky'
|
import * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
export function ThreadItemAnchor({
|
export function ThreadItemAnchor({
|
||||||
@@ -177,6 +177,7 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({
|
|||||||
postSource?: PostSource
|
postSource?: PostSource
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {openComposer} = useOpenComposer()
|
const {openComposer} = useOpenComposer()
|
||||||
const {currentAccount, hasSession} = useSession()
|
const {currentAccount, hasSession} = useSession()
|
||||||
@@ -281,7 +282,7 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({
|
|||||||
])
|
])
|
||||||
|
|
||||||
const onOpenAuthor = () => {
|
const onOpenAuthor = () => {
|
||||||
logger.metric('post:clickthroughAuthor', {
|
ax.metric('post:clickthroughAuthor', {
|
||||||
uri: post.uri,
|
uri: post.uri,
|
||||||
authorDid: post.author.did,
|
authorDid: post.author.did,
|
||||||
logContext: 'PostThreadItem',
|
logContext: 'PostThreadItem',
|
||||||
@@ -298,7 +299,7 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onOpenEmbed = () => {
|
const onOpenEmbed = () => {
|
||||||
logger.metric('post:clickthroughEmbed', {
|
ax.metric('post:clickthroughEmbed', {
|
||||||
uri: post.uri,
|
uri: post.uri,
|
||||||
authorDid: post.author.did,
|
authorDid: post.author.did,
|
||||||
logContext: 'PostThreadItem',
|
logContext: 'PostThreadItem',
|
||||||
@@ -540,6 +541,7 @@ function ExpandedPostDetails({
|
|||||||
isThreadAuthor: boolean
|
isThreadAuthor: boolean
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {_, i18n} = useLingui()
|
const {_, i18n} = useLingui()
|
||||||
const translate = useTranslate()
|
const translate = useTranslate()
|
||||||
const isRootPost = !('reply' in post.record)
|
const isRootPost = !('reply' in post.record)
|
||||||
@@ -565,7 +567,7 @@ function ExpandedPostDetails({
|
|||||||
AppBskyFeedPost.isRecord,
|
AppBskyFeedPost.isRecord,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
logger.metric('translate', {
|
ax.metric('translate', {
|
||||||
sourceLanguages: post.record.langs ?? [],
|
sourceLanguages: post.record.langs ?? [],
|
||||||
targetLanguage: langPrefs.primaryLanguage,
|
targetLanguage: langPrefs.primaryLanguage,
|
||||||
textLength: post.record.text.length,
|
textLength: post.record.text.length,
|
||||||
@@ -574,7 +576,7 @@ function ExpandedPostDetails({
|
|||||||
|
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
[translate, langPrefs, post],
|
[ax, translate, langPrefs, post],
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -2,22 +2,23 @@ import {View} from 'react-native'
|
|||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {Button} from '#/components/Button'
|
import {Button} from '#/components/Button'
|
||||||
import {EyeSlash_Stroke2_Corner0_Rounded as EyeSlash} from '#/components/icons/EyeSlash'
|
import {EyeSlash_Stroke2_Corner0_Rounded as EyeSlash} from '#/components/icons/EyeSlash'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
export function ThreadItemShowOtherReplies({onPress}: {onPress: () => void}) {
|
export function ThreadItemShowOtherReplies({onPress}: {onPress: () => void}) {
|
||||||
const {_} = useLingui()
|
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
|
const {_} = useLingui()
|
||||||
const label = _(msg`Show more replies`)
|
const label = _(msg`Show more replies`)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
onPress()
|
onPress()
|
||||||
logger.metric('thread:click:showOtherReplies', {})
|
ax.metric('thread:click:showOtherReplies', {})
|
||||||
}}
|
}}
|
||||||
label={label}>
|
label={label}>
|
||||||
{({hovered, pressed}) => (
|
{({hovered, pressed}) => (
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import {Trans} from '@lingui/macro'
|
|||||||
import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender'
|
import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender'
|
||||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||||
import {usePostViewTracking} from '#/lib/hooks/usePostViewTracking'
|
import {usePostViewTracking} from '#/lib/hooks/usePostViewTracking'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useFeedFeedback} from '#/state/feed-feedback'
|
import {useFeedFeedback} from '#/state/feed-feedback'
|
||||||
import {type ThreadViewOption} from '#/state/queries/preferences/useThreadPreferences'
|
import {type ThreadViewOption} from '#/state/queries/preferences/useThreadPreferences'
|
||||||
import {
|
import {
|
||||||
@@ -44,11 +43,13 @@ import {
|
|||||||
import {atoms as a, native, platform, useBreakpoints, web} from '#/alf'
|
import {atoms as a, native, platform, useBreakpoints, web} from '#/alf'
|
||||||
import * as Layout from '#/components/Layout'
|
import * as Layout from '#/components/Layout'
|
||||||
import {ListFooter} from '#/components/Lists'
|
import {ListFooter} from '#/components/Lists'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
const PARENT_CHUNK_SIZE = 5
|
const PARENT_CHUNK_SIZE = 5
|
||||||
const CHILDREN_CHUNK_SIZE = 50
|
const CHILDREN_CHUNK_SIZE = 50
|
||||||
|
|
||||||
export function PostThread({uri}: {uri: string}) {
|
export function PostThread({uri}: {uri: string}) {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {gtMobile} = useBreakpoints()
|
const {gtMobile} = useBreakpoints()
|
||||||
const {hasSession} = useSession()
|
const {hasSession} = useSession()
|
||||||
const initialNumToRender = useInitialNumToRender()
|
const initialNumToRender = useInitialNumToRender()
|
||||||
@@ -84,18 +85,14 @@ export function PostThread({uri}: {uri: string}) {
|
|||||||
const post = anchor.value.post
|
const post = anchor.value.post
|
||||||
seenPostUriRef.current = post.uri
|
seenPostUriRef.current = post.uri
|
||||||
|
|
||||||
logger.metric(
|
ax.metric('post:view', {
|
||||||
'post:view',
|
uri: post.uri,
|
||||||
{
|
authorDid: post.author.did,
|
||||||
uri: post.uri,
|
logContext: 'Post',
|
||||||
authorDid: post.author.did,
|
feedDescriptor: feedFeedback.feedDescriptor,
|
||||||
logContext: 'Post',
|
})
|
||||||
feedDescriptor: feedFeedback.feedDescriptor,
|
|
||||||
},
|
|
||||||
{statsig: false},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}, [anchor, feedFeedback.feedDescriptor])
|
}, [ax, anchor, feedFeedback.feedDescriptor])
|
||||||
|
|
||||||
// Track post:view events for parent posts and replies (non-anchor posts)
|
// Track post:view events for parent posts and replies (non-anchor posts)
|
||||||
const trackThreadItemView = usePostViewTracking('PostThreadItem')
|
const trackThreadItemView = usePostViewTracking('PostThreadItem')
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import {useLingui} from '@lingui/react'
|
|||||||
import {MAX_LABELERS} from '#/lib/constants'
|
import {MAX_LABELERS} from '#/lib/constants'
|
||||||
import {useHaptics} from '#/lib/haptics'
|
import {useHaptics} from '#/lib/haptics'
|
||||||
import {isAppLabeler} from '#/lib/moderation'
|
import {isAppLabeler} from '#/lib/moderation'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
||||||
import {type Shadow} from '#/state/cache/types'
|
import {type Shadow} from '#/state/cache/types'
|
||||||
import {useLabelerSubscriptionMutation} from '#/state/queries/labeler'
|
import {useLabelerSubscriptionMutation} from '#/state/queries/labeler'
|
||||||
@@ -34,6 +33,7 @@ import * as Prompt from '#/components/Prompt'
|
|||||||
import {RichText} from '#/components/RichText'
|
import {RichText} from '#/components/RichText'
|
||||||
import * as Toast from '#/components/Toast'
|
import * as Toast from '#/components/Toast'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_IOS} from '#/env'
|
import {IS_IOS} from '#/env'
|
||||||
import {ProfileHeaderDisplayName} from './DisplayName'
|
import {ProfileHeaderDisplayName} from './DisplayName'
|
||||||
import {EditProfileDialog} from './EditProfileDialog'
|
import {EditProfileDialog} from './EditProfileDialog'
|
||||||
@@ -61,6 +61,7 @@ let ProfileHeaderLabeler = ({
|
|||||||
const profile: Shadow<AppBskyActorDefs.ProfileViewDetailed> =
|
const profile: Shadow<AppBskyActorDefs.ProfileViewDetailed> =
|
||||||
useProfileShadow(profileUnshadowed)
|
useProfileShadow(profileUnshadowed)
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {currentAccount, hasSession} = useSession()
|
const {currentAccount, hasSession} = useSession()
|
||||||
const playHaptic = useHaptics()
|
const playHaptic = useHaptics()
|
||||||
@@ -99,9 +100,9 @@ let ProfileHeaderLabeler = ({
|
|||||||
),
|
),
|
||||||
{type: 'error'},
|
{type: 'error'},
|
||||||
)
|
)
|
||||||
logger.error(`Failed to toggle labeler like`, {message: e.message})
|
ax.logger.error(`Failed to toggle labeler like`, {message: e.message})
|
||||||
}
|
}
|
||||||
}, [labeler, playHaptic, likeUri, unlikeMod, likeMod, _])
|
}, [ax, labeler, playHaptic, likeUri, unlikeMod, likeMod, _])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ProfileHeaderShell
|
<ProfileHeaderShell
|
||||||
@@ -233,8 +234,9 @@ export function HeaderLabelerButtons({
|
|||||||
/** disable the subscribe button */
|
/** disable the subscribe button */
|
||||||
minimal?: boolean
|
minimal?: boolean
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
|
const {_} = useLingui()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const requireAuth = useRequireAuth()
|
const requireAuth = useRequireAuth()
|
||||||
const playHaptic = useHaptics()
|
const playHaptic = useHaptics()
|
||||||
@@ -264,12 +266,11 @@ export function HeaderLabelerButtons({
|
|||||||
subscribe,
|
subscribe,
|
||||||
})
|
})
|
||||||
|
|
||||||
logger.metric(
|
ax.metric(
|
||||||
subscribe
|
subscribe
|
||||||
? 'moderation:subscribedToLabeler'
|
? 'moderation:subscribedToLabeler'
|
||||||
: 'moderation:unsubscribedFromLabeler',
|
: 'moderation:unsubscribedFromLabeler',
|
||||||
{},
|
{},
|
||||||
{statsig: true},
|
|
||||||
)
|
)
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
reset()
|
reset()
|
||||||
@@ -277,7 +278,7 @@ export function HeaderLabelerButtons({
|
|||||||
cantSubscribePrompt.open()
|
cantSubscribePrompt.open()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.error(`Failed to subscribe to labeler`, {message: e.message})
|
ax.logger.error(`Failed to subscribe to labeler`, {message: e.message})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import {useActorStatus} from '#/lib/actor-status'
|
|||||||
import {BACK_HITSLOP} from '#/lib/constants'
|
import {BACK_HITSLOP} from '#/lib/constants'
|
||||||
import {useHaptics} from '#/lib/haptics'
|
import {useHaptics} from '#/lib/haptics'
|
||||||
import {type NavigationProp} from '#/lib/routes/types'
|
import {type NavigationProp} from '#/lib/routes/types'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {type Shadow} from '#/state/cache/types'
|
import {type Shadow} from '#/state/cache/types'
|
||||||
import {useLightboxControls} from '#/state/lightbox'
|
import {useLightboxControls} from '#/state/lightbox'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
@@ -34,6 +33,7 @@ import {LiveIndicator} from '#/components/live/LiveIndicator'
|
|||||||
import {LiveStatusDialog} from '#/components/live/LiveStatusDialog'
|
import {LiveStatusDialog} from '#/components/live/LiveStatusDialog'
|
||||||
import {LabelsOnMe} from '#/components/moderation/LabelsOnMe'
|
import {LabelsOnMe} from '#/components/moderation/LabelsOnMe'
|
||||||
import {ProfileHeaderAlerts} from '#/components/moderation/ProfileHeaderAlerts'
|
import {ProfileHeaderAlerts} from '#/components/moderation/ProfileHeaderAlerts'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_IOS} from '#/env'
|
import {IS_IOS} from '#/env'
|
||||||
import {GrowableAvatar} from './GrowableAvatar'
|
import {GrowableAvatar} from './GrowableAvatar'
|
||||||
import {GrowableBanner} from './GrowableBanner'
|
import {GrowableBanner} from './GrowableBanner'
|
||||||
@@ -54,6 +54,7 @@ let ProfileHeaderShell = ({
|
|||||||
isPlaceholderProfile,
|
isPlaceholderProfile,
|
||||||
}: React.PropsWithChildren<Props>): React.ReactNode => {
|
}: React.PropsWithChildren<Props>): React.ReactNode => {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {openLightbox} = useLightboxControls()
|
const {openLightbox} = useLightboxControls()
|
||||||
@@ -116,22 +117,14 @@ let ProfileHeaderShell = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (live.isActive) {
|
if (live.isActive) {
|
||||||
logger.metric(
|
ax.metric('live:view:profile', {subject: profile.did})
|
||||||
'live:view:profile',
|
|
||||||
{subject: profile.did},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}, [live.isActive, profile.did])
|
}, [ax, live.isActive, profile.did])
|
||||||
|
|
||||||
const onPressAvi = useCallback(() => {
|
const onPressAvi = useCallback(() => {
|
||||||
if (live.isActive) {
|
if (live.isActive) {
|
||||||
playHaptic('Light')
|
playHaptic('Light')
|
||||||
logger.metric(
|
ax.metric('live:card:open', {subject: profile.did, from: 'profile'})
|
||||||
'live:card:open',
|
|
||||||
{subject: profile.did, from: 'profile'},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
liveStatusControl.open()
|
liveStatusControl.open()
|
||||||
} else {
|
} else {
|
||||||
const modui = moderation.ui('avatar')
|
const modui = moderation.ui('avatar')
|
||||||
@@ -145,6 +138,7 @@ let ProfileHeaderShell = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
|
ax,
|
||||||
profile,
|
profile,
|
||||||
moderation,
|
moderation,
|
||||||
_openLightbox,
|
_openLightbox,
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ import {msg, Plural, Trans} from '@lingui/macro'
|
|||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {useHaptics} from '#/lib/haptics'
|
import {useHaptics} from '#/lib/haptics'
|
||||||
import {makeProfileLink} from '#/lib/routes/links'
|
import {makeCustomFeedLink, makeProfileLink} from '#/lib/routes/links'
|
||||||
import {makeCustomFeedLink} from '#/lib/routes/links'
|
|
||||||
import {shareUrl} from '#/lib/sharing'
|
import {shareUrl} from '#/lib/sharing'
|
||||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||||
import {toShareUrl} from '#/lib/strings/url-helpers'
|
import {toShareUrl} from '#/lib/strings/url-helpers'
|
||||||
@@ -51,6 +50,7 @@ import {
|
|||||||
} from '#/components/moderation/ReportDialog'
|
} from '#/components/moderation/ReportDialog'
|
||||||
import {RichText} from '#/components/RichText'
|
import {RichText} from '#/components/RichText'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
|
|
||||||
export function ProfileFeedHeaderSkeleton() {
|
export function ProfileFeedHeaderSkeleton() {
|
||||||
@@ -86,6 +86,7 @@ export function ProfileFeedHeaderSkeleton() {
|
|||||||
export function ProfileFeedHeader({info}: {info: FeedSourceFeedInfo}) {
|
export function ProfileFeedHeader({info}: {info: FeedSourceFeedInfo}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_, i18n} = useLingui()
|
const {_, i18n} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {hasSession} = useSession()
|
const {hasSession} = useSession()
|
||||||
const {gtMobile} = useBreakpoints()
|
const {gtMobile} = useBreakpoints()
|
||||||
const infoControl = Dialog.useDialogControl()
|
const infoControl = Dialog.useDialogControl()
|
||||||
@@ -120,7 +121,7 @@ export function ProfileFeedHeader({info}: {info: FeedSourceFeedInfo}) {
|
|||||||
if (savedFeedConfig) {
|
if (savedFeedConfig) {
|
||||||
await removeFeed(savedFeedConfig)
|
await removeFeed(savedFeedConfig)
|
||||||
Toast.show(_(msg`Removed from your feeds`))
|
Toast.show(_(msg`Removed from your feeds`))
|
||||||
logger.metric('feed:unsave', {feedUrl: info.uri})
|
ax.metric('feed:unsave', {feedUrl: info.uri})
|
||||||
} else {
|
} else {
|
||||||
await addSavedFeeds([
|
await addSavedFeeds([
|
||||||
{
|
{
|
||||||
@@ -130,7 +131,7 @@ export function ProfileFeedHeader({info}: {info: FeedSourceFeedInfo}) {
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
Toast.show(_(msg`Saved to your feeds`))
|
Toast.show(_(msg`Saved to your feeds`))
|
||||||
logger.metric('feed:save', {feedUrl: info.uri})
|
ax.metric('feed:save', {feedUrl: info.uri})
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Toast.show(
|
Toast.show(
|
||||||
@@ -158,10 +159,10 @@ export function ProfileFeedHeader({info}: {info: FeedSourceFeedInfo}) {
|
|||||||
|
|
||||||
if (pinned) {
|
if (pinned) {
|
||||||
Toast.show(_(msg`Pinned ${info.displayName} to Home`))
|
Toast.show(_(msg`Pinned ${info.displayName} to Home`))
|
||||||
logger.metric('feed:pin', {feedUrl: info.uri})
|
ax.metric('feed:pin', {feedUrl: info.uri})
|
||||||
} else {
|
} else {
|
||||||
Toast.show(_(msg`Unpinned ${info.displayName} from Home`))
|
Toast.show(_(msg`Unpinned ${info.displayName} from Home`))
|
||||||
logger.metric('feed:unpin', {feedUrl: info.uri})
|
ax.metric('feed:unpin', {feedUrl: info.uri})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await addSavedFeeds([
|
await addSavedFeeds([
|
||||||
@@ -172,7 +173,7 @@ export function ProfileFeedHeader({info}: {info: FeedSourceFeedInfo}) {
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
Toast.show(_(msg`Pinned ${info.displayName} to Home`))
|
Toast.show(_(msg`Pinned ${info.displayName} to Home`))
|
||||||
logger.metric('feed:pin', {feedUrl: info.uri})
|
ax.metric('feed:pin', {feedUrl: info.uri})
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Toast.show(_(msg`There was an issue contacting the server`), 'xmark')
|
Toast.show(_(msg`There was an issue contacting the server`), 'xmark')
|
||||||
@@ -388,6 +389,7 @@ function DialogInner({
|
|||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {hasSession} = useSession()
|
const {hasSession} = useSession()
|
||||||
const playHaptic = useHaptics()
|
const playHaptic = useHaptics()
|
||||||
const control = Dialog.useDialogContext()
|
const control = Dialog.useDialogContext()
|
||||||
@@ -407,11 +409,11 @@ function DialogInner({
|
|||||||
if (isLiked && likeUri) {
|
if (isLiked && likeUri) {
|
||||||
await unlikeFeed({uri: likeUri})
|
await unlikeFeed({uri: likeUri})
|
||||||
setLikeUri('')
|
setLikeUri('')
|
||||||
logger.metric('feed:unlike', {feedUrl: info.uri})
|
ax.metric('feed:unlike', {feedUrl: info.uri})
|
||||||
} else {
|
} else {
|
||||||
const res = await likeFeed({uri: info.uri, cid: info.cid})
|
const res = await likeFeed({uri: info.uri, cid: info.cid})
|
||||||
setLikeUri(res.uri)
|
setLikeUri(res.uri)
|
||||||
logger.metric('feed:like', {feedUrl: info.uri})
|
ax.metric('feed:like', {feedUrl: info.uri})
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Toast.show(
|
Toast.show(
|
||||||
@@ -428,7 +430,7 @@ function DialogInner({
|
|||||||
playHaptic()
|
playHaptic()
|
||||||
const url = toShareUrl(info.route.href)
|
const url = toShareUrl(info.route.href)
|
||||||
shareUrl(url)
|
shareUrl(url)
|
||||||
logger.metric('feed:share', {feedUrl: info.uri})
|
ax.metric('feed:share', {feedUrl: info.uri})
|
||||||
}, [info, playHaptic])
|
}, [info, playHaptic])
|
||||||
|
|
||||||
const onPressReport = React.useCallback(() => {
|
const onPressReport = React.useCallback(() => {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {Pin_Stroke2_Corner0_Rounded as PinIcon} from '#/components/icons/Pin'
|
|||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {RichText} from '#/components/RichText'
|
import {RichText} from '#/components/RichText'
|
||||||
import * as Toast from '#/components/Toast'
|
import * as Toast from '#/components/Toast'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {MoreOptionsMenu} from './MoreOptionsMenu'
|
import {MoreOptionsMenu} from './MoreOptionsMenu'
|
||||||
import {SubscribeMenu} from './SubscribeMenu'
|
import {SubscribeMenu} from './SubscribeMenu'
|
||||||
|
|
||||||
@@ -34,6 +35,7 @@ export function Header({
|
|||||||
preferences: UsePreferencesQueryResponse
|
preferences: UsePreferencesQueryResponse
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const isCurateList = list.purpose === AppBskyGraphDefs.CURATELIST
|
const isCurateList = list.purpose === AppBskyGraphDefs.CURATELIST
|
||||||
const isModList = list.purpose === AppBskyGraphDefs.MODLIST
|
const isModList = list.purpose === AppBskyGraphDefs.MODLIST
|
||||||
@@ -96,11 +98,7 @@ export function Header({
|
|||||||
try {
|
try {
|
||||||
await muteList({uri: list.uri, mute: false})
|
await muteList({uri: list.uri, mute: false})
|
||||||
Toast.show(_(msg({message: 'List unmuted', context: 'toast'})))
|
Toast.show(_(msg({message: 'List unmuted', context: 'toast'})))
|
||||||
logger.metric(
|
ax.metric('moderation:unsubscribedFromList', {listType: 'mute'})
|
||||||
'moderation:unsubscribedFromList',
|
|
||||||
{listType: 'mute'},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
} catch {
|
} catch {
|
||||||
Toast.show(
|
Toast.show(
|
||||||
_(
|
_(
|
||||||
@@ -114,11 +112,7 @@ export function Header({
|
|||||||
try {
|
try {
|
||||||
await blockList({uri: list.uri, block: false})
|
await blockList({uri: list.uri, block: false})
|
||||||
Toast.show(_(msg({message: 'List unblocked', context: 'toast'})))
|
Toast.show(_(msg({message: 'List unblocked', context: 'toast'})))
|
||||||
logger.metric(
|
ax.metric('moderation:unsubscribedFromList', {listType: 'block'})
|
||||||
'moderation:unsubscribedFromList',
|
|
||||||
{listType: 'block'},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
} catch {
|
} catch {
|
||||||
Toast.show(
|
Toast.show(
|
||||||
_(
|
_(
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import {
|
|||||||
} from '#/components/moderation/ReportDialog'
|
} from '#/components/moderation/ReportDialog'
|
||||||
import * as Prompt from '#/components/Prompt'
|
import * as Prompt from '#/components/Prompt'
|
||||||
import * as Toast from '#/components/Toast'
|
import * as Toast from '#/components/Toast'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
|
|
||||||
export function MoreOptionsMenu({
|
export function MoreOptionsMenu({
|
||||||
@@ -43,6 +44,7 @@ export function MoreOptionsMenu({
|
|||||||
savedFeedConfig?: AppBskyActorDefs.SavedFeed
|
savedFeedConfig?: AppBskyActorDefs.SavedFeed
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const editListDialogControl = useDialogControl()
|
const editListDialogControl = useDialogControl()
|
||||||
const deleteListPromptControl = useDialogControl()
|
const deleteListPromptControl = useDialogControl()
|
||||||
@@ -111,11 +113,7 @@ export function MoreOptionsMenu({
|
|||||||
try {
|
try {
|
||||||
await muteList({uri: list.uri, mute: false})
|
await muteList({uri: list.uri, mute: false})
|
||||||
Toast.show(_(msg({message: 'List unmuted', context: 'toast'})))
|
Toast.show(_(msg({message: 'List unmuted', context: 'toast'})))
|
||||||
logger.metric(
|
ax.metric('moderation:unsubscribedFromList', {listType: 'mute'})
|
||||||
'moderation:unsubscribedFromList',
|
|
||||||
{listType: 'mute'},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
} catch {
|
} catch {
|
||||||
Toast.show(
|
Toast.show(
|
||||||
_(
|
_(
|
||||||
@@ -129,11 +127,7 @@ export function MoreOptionsMenu({
|
|||||||
try {
|
try {
|
||||||
await blockList({uri: list.uri, block: false})
|
await blockList({uri: list.uri, block: false})
|
||||||
Toast.show(_(msg({message: 'List unblocked', context: 'toast'})))
|
Toast.show(_(msg({message: 'List unblocked', context: 'toast'})))
|
||||||
logger.metric(
|
ax.metric('moderation:unsubscribedFromList', {listType: 'block'})
|
||||||
'moderation:unsubscribedFromList',
|
|
||||||
{listType: 'block'},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
} catch {
|
} catch {
|
||||||
Toast.show(
|
Toast.show(
|
||||||
_(
|
_(
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import {type AppBskyGraphDefs} from '@atproto/api'
|
|||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useListBlockMutation, useListMuteMutation} from '#/state/queries/list'
|
import {useListBlockMutation, useListMuteMutation} from '#/state/queries/list'
|
||||||
import {atoms as a} from '#/alf'
|
import {atoms as a} from '#/alf'
|
||||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||||
@@ -12,9 +11,11 @@ import {Loader} from '#/components/Loader'
|
|||||||
import * as Menu from '#/components/Menu'
|
import * as Menu from '#/components/Menu'
|
||||||
import * as Prompt from '#/components/Prompt'
|
import * as Prompt from '#/components/Prompt'
|
||||||
import * as Toast from '#/components/Toast'
|
import * as Toast from '#/components/Toast'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
export function SubscribeMenu({list}: {list: AppBskyGraphDefs.ListView}) {
|
export function SubscribeMenu({list}: {list: AppBskyGraphDefs.ListView}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const subscribeMutePromptControl = Prompt.usePromptControl()
|
const subscribeMutePromptControl = Prompt.usePromptControl()
|
||||||
const subscribeBlockPromptControl = Prompt.usePromptControl()
|
const subscribeBlockPromptControl = Prompt.usePromptControl()
|
||||||
|
|
||||||
@@ -29,11 +30,7 @@ export function SubscribeMenu({list}: {list: AppBskyGraphDefs.ListView}) {
|
|||||||
try {
|
try {
|
||||||
await muteList({uri: list.uri, mute: true})
|
await muteList({uri: list.uri, mute: true})
|
||||||
Toast.show(_(msg({message: 'List muted', context: 'toast'})))
|
Toast.show(_(msg({message: 'List muted', context: 'toast'})))
|
||||||
logger.metric(
|
ax.metric('moderation:subscribedToList', {listType: 'mute'})
|
||||||
'moderation:subscribedToList',
|
|
||||||
{listType: 'mute'},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
} catch {
|
} catch {
|
||||||
Toast.show(
|
Toast.show(
|
||||||
_(
|
_(
|
||||||
@@ -48,11 +45,7 @@ export function SubscribeMenu({list}: {list: AppBskyGraphDefs.ListView}) {
|
|||||||
try {
|
try {
|
||||||
await blockList({uri: list.uri, block: true})
|
await blockList({uri: list.uri, block: true})
|
||||||
Toast.show(_(msg({message: 'List blocked', context: 'toast'})))
|
Toast.show(_(msg({message: 'List blocked', context: 'toast'})))
|
||||||
logger.metric(
|
ax.metric('moderation:subscribedToList', {listType: 'block'})
|
||||||
'moderation:subscribedToList',
|
|
||||||
{listType: 'block'},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
} catch {
|
} catch {
|
||||||
Toast.show(
|
Toast.show(
|
||||||
_(
|
_(
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import {type AppBskyFeedDefs, AtUri} from '@atproto/api'
|
|||||||
|
|
||||||
import {PressableScale} from '#/lib/custom-animations/PressableScale'
|
import {PressableScale} from '#/lib/custom-animations/PressableScale'
|
||||||
import {makeCustomFeedLink} from '#/lib/routes/links'
|
import {makeCustomFeedLink} from '#/lib/routes/links'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||||
import {atoms as a, native, useTheme, type ViewStyleProp} from '#/alf'
|
import {atoms as a, native, useTheme, type ViewStyleProp} from '#/alf'
|
||||||
import {Button, ButtonIcon} from '#/components/Button'
|
import {Button, ButtonIcon} from '#/components/Button'
|
||||||
@@ -13,6 +12,7 @@ import {sizes as iconSizes} from '#/components/icons/common'
|
|||||||
import {MagnifyingGlass_Stroke2_Corner0_Rounded as SearchIcon} from '#/components/icons/MagnifyingGlass'
|
import {MagnifyingGlass_Stroke2_Corner0_Rounded as SearchIcon} from '#/components/icons/MagnifyingGlass'
|
||||||
import {Link} from '#/components/Link'
|
import {Link} from '#/components/Link'
|
||||||
import {Text, type TextProps} from '#/components/Typography'
|
import {Text, type TextProps} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
export function Container({
|
export function Container({
|
||||||
style,
|
style,
|
||||||
@@ -126,6 +126,7 @@ export function SearchButton({
|
|||||||
metricsTag: 'suggestedAccounts' | 'suggestedFeeds'
|
metricsTag: 'suggestedAccounts' | 'suggestedFeeds'
|
||||||
onPress?: () => void
|
onPress?: () => void
|
||||||
}) {
|
}) {
|
||||||
|
const ax = useAnalytics()
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
label={label}
|
label={label}
|
||||||
@@ -135,11 +136,7 @@ export function SearchButton({
|
|||||||
shape="round"
|
shape="round"
|
||||||
PressableComponent={native(PressableScale)}
|
PressableComponent={native(PressableScale)}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric(
|
ax.metric('explore:module:searchButtonPress', {module: metricsTag})
|
||||||
'explore:module:searchButtonPress',
|
|
||||||
{module: metricsTag},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
onPress?.()
|
onPress?.()
|
||||||
}}
|
}}
|
||||||
style={[
|
style={[
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import {View} from 'react-native'
|
|||||||
import {type AppBskyUnspeccedDefs} from '@atproto/api'
|
import {type AppBskyUnspeccedDefs} from '@atproto/api'
|
||||||
import {Trans} from '@lingui/macro'
|
import {Trans} from '@lingui/macro'
|
||||||
|
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {
|
import {
|
||||||
DEFAULT_LIMIT as RECOMMENDATIONS_COUNT,
|
DEFAULT_LIMIT as RECOMMENDATIONS_COUNT,
|
||||||
useTrendingTopics,
|
useTrendingTopics,
|
||||||
@@ -16,6 +15,7 @@ import {
|
|||||||
TrendingTopicSkeleton,
|
TrendingTopicSkeleton,
|
||||||
} from '#/components/TrendingTopics'
|
} from '#/components/TrendingTopics'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
|
|
||||||
// Note: This module is not currently used and may be removed in the future.
|
// Note: This module is not currently used and may be removed in the future.
|
||||||
@@ -27,6 +27,7 @@ export function ExploreRecommendations() {
|
|||||||
|
|
||||||
function Inner() {
|
function Inner() {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
const gutters = useGutters([0, 'compact'])
|
const gutters = useGutters([0, 'compact'])
|
||||||
const {data: trending, error, isLoading} = useTrendingTopics()
|
const {data: trending, error, isLoading} = useTrendingTopics()
|
||||||
const noRecs = !isLoading && !error && !trending?.suggested?.length
|
const noRecs = !isLoading && !error && !trending?.suggested?.length
|
||||||
@@ -88,11 +89,7 @@ function Inner() {
|
|||||||
key={topic.link}
|
key={topic.link}
|
||||||
topic={topic}
|
topic={topic}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric(
|
ax.metric('recommendedTopic:click', {context: 'explore'})
|
||||||
'recommendedTopic:click',
|
|
||||||
{context: 'explore'},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
}}>
|
}}>
|
||||||
{({hovered}) => (
|
{({hovered}) => (
|
||||||
<TrendingTopic
|
<TrendingTopic
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ import {popularInterests, useInterestsDisplayNames} from '#/lib/interests'
|
|||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||||
import {BlockDrawerGesture} from '#/view/shell/BlockDrawerGesture'
|
import {BlockDrawerGesture} from '#/view/shell/BlockDrawerGesture'
|
||||||
import {useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {atoms as a} from '#/alf'
|
|
||||||
import {boostInterests, InterestTabs} from '#/components/InterestTabs'
|
import {boostInterests, InterestTabs} from '#/components/InterestTabs'
|
||||||
import * as ProfileCard from '#/components/ProfileCard'
|
import * as ProfileCard from '#/components/ProfileCard'
|
||||||
import {SubtleHover} from '#/components/SubtleHover'
|
import {SubtleHover} from '#/components/SubtleHover'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import type * as bsky from '#/types/bsky'
|
import type * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
export function useLoadEnoughProfiles({
|
export function useLoadEnoughProfiles({
|
||||||
@@ -62,6 +62,7 @@ export function SuggestedAccountsTabBar({
|
|||||||
defaultTabLabel?: string
|
defaultTabLabel?: string
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const interestsDisplayNames = useInterestsDisplayNames()
|
const interestsDisplayNames = useInterestsDisplayNames()
|
||||||
const {data: preferences} = usePreferencesQuery()
|
const {data: preferences} = usePreferencesQuery()
|
||||||
const personalizedInterests = preferences?.interests?.tags
|
const personalizedInterests = preferences?.interests?.tags
|
||||||
@@ -77,11 +78,7 @@ export function SuggestedAccountsTabBar({
|
|||||||
selectedInterest || (hideDefaultTab ? interests[0] : 'all')
|
selectedInterest || (hideDefaultTab ? interests[0] : 'all')
|
||||||
}
|
}
|
||||||
onSelectTab={tab => {
|
onSelectTab={tab => {
|
||||||
logger.metric(
|
ax.metric('explore:suggestedAccounts:tabPressed', {tab: tab})
|
||||||
'explore:suggestedAccounts:tabPressed',
|
|
||||||
{tab: tab},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
onSelectInterest(tab === 'all' ? null : tab)
|
onSelectInterest(tab === 'all' ? null : tab)
|
||||||
}}
|
}}
|
||||||
interestsDisplayNames={
|
interestsDisplayNames={
|
||||||
@@ -112,22 +109,19 @@ let SuggestedProfileCard = ({
|
|||||||
position: number
|
position: number
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
return (
|
return (
|
||||||
<ProfileCard.Link
|
<ProfileCard.Link
|
||||||
profile={profile}
|
profile={profile}
|
||||||
style={[a.flex_1]}
|
style={[a.flex_1]}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric(
|
ax.metric('suggestedUser:press', {
|
||||||
'suggestedUser:press',
|
logContext: 'Explore',
|
||||||
{
|
recId,
|
||||||
logContext: 'Explore',
|
position,
|
||||||
recId,
|
suggestedDid: profile.did,
|
||||||
position,
|
category: null,
|
||||||
suggestedDid: profile.did,
|
})
|
||||||
category: null,
|
|
||||||
},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
}}>
|
}}>
|
||||||
{s => (
|
{s => (
|
||||||
<>
|
<>
|
||||||
@@ -157,18 +151,14 @@ let SuggestedProfileCard = ({
|
|||||||
withIcon={false}
|
withIcon={false}
|
||||||
logContext="ExploreSuggestedAccounts"
|
logContext="ExploreSuggestedAccounts"
|
||||||
onFollow={() => {
|
onFollow={() => {
|
||||||
logger.metric(
|
ax.metric('suggestedUser:follow', {
|
||||||
'suggestedUser:follow',
|
logContext: 'Explore',
|
||||||
{
|
location: 'Card',
|
||||||
logContext: 'Explore',
|
recId,
|
||||||
location: 'Card',
|
position,
|
||||||
recId,
|
suggestedDid: profile.did,
|
||||||
position,
|
category: null,
|
||||||
suggestedDid: profile.did,
|
})
|
||||||
category: null,
|
|
||||||
},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</ProfileCard.Header>
|
</ProfileCard.Header>
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import {type AppBskyUnspeccedDefs, moderateProfile} from '@atproto/api'
|
|||||||
import {msg, plural, Trans} from '@lingui/macro'
|
import {msg, plural, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {useTrendingSettings} from '#/state/preferences/trending'
|
import {useTrendingSettings} from '#/state/preferences/trending'
|
||||||
import {useGetTrendsQuery} from '#/state/queries/trending/useGetTrendsQuery'
|
import {useGetTrendsQuery} from '#/state/queries/trending/useGetTrendsQuery'
|
||||||
@@ -19,6 +18,7 @@ import {Trending3_Stroke2_Corner1_Rounded as TrendingIcon} from '#/components/ic
|
|||||||
import {Link} from '#/components/Link'
|
import {Link} from '#/components/Link'
|
||||||
import {SubtleHover} from '#/components/SubtleHover'
|
import {SubtleHover} from '#/components/SubtleHover'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
const TOPIC_COUNT = 5
|
const TOPIC_COUNT = 5
|
||||||
|
|
||||||
@@ -29,6 +29,7 @@ export function ExploreTrendingTopics() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Inner() {
|
function Inner() {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {data: trending, error, isLoading, isRefetching} = useGetTrendsQuery()
|
const {data: trending, error, isLoading, isRefetching} = useGetTrendsQuery()
|
||||||
const noTopics = !isLoading && !error && !trending?.trends?.length
|
const noTopics = !isLoading && !error && !trending?.trends?.length
|
||||||
|
|
||||||
@@ -44,11 +45,7 @@ function Inner() {
|
|||||||
trend={trend}
|
trend={trend}
|
||||||
rank={index + 1}
|
rank={index + 1}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric(
|
ax.metric('trendingTopic:click', {context: 'explore'})
|
||||||
'trendingTopic:click',
|
|
||||||
{context: 'explore'},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import {useQueryClient} from '@tanstack/react-query'
|
|||||||
|
|
||||||
import {VIDEO_FEED_URI} from '#/lib/constants'
|
import {VIDEO_FEED_URI} from '#/lib/constants'
|
||||||
import {makeCustomFeedLink} from '#/lib/routes/links'
|
import {makeCustomFeedLink} from '#/lib/routes/links'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {RQKEY, usePostFeedQuery} from '#/state/queries/post-feed'
|
import {RQKEY, usePostFeedQuery} from '#/state/queries/post-feed'
|
||||||
import {BlockDrawerGesture} from '#/view/shell/BlockDrawerGesture'
|
import {BlockDrawerGesture} from '#/view/shell/BlockDrawerGesture'
|
||||||
import {atoms as a, tokens, useGutters, useTheme} from '#/alf'
|
import {atoms as a, tokens, useGutters, useTheme} from '#/alf'
|
||||||
@@ -20,6 +19,7 @@ import {
|
|||||||
CompactVideoPostCard,
|
CompactVideoPostCard,
|
||||||
CompactVideoPostCardPlaceholder,
|
CompactVideoPostCardPlaceholder,
|
||||||
} from '#/components/VideoPostCard'
|
} from '#/components/VideoPostCard'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
const CARD_WIDTH = 100
|
const CARD_WIDTH = 100
|
||||||
|
|
||||||
@@ -151,6 +151,7 @@ function VideoCards({
|
|||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const items = useMemo(() => {
|
const items = useMemo(() => {
|
||||||
return data.pages
|
return data.pages
|
||||||
.flatMap(page => page.slices)
|
.flatMap(page => page.slices)
|
||||||
@@ -177,11 +178,7 @@ function VideoCards({
|
|||||||
sourceInterstitial: 'explore',
|
sourceInterstitial: 'explore',
|
||||||
}}
|
}}
|
||||||
onInteract={() => {
|
onInteract={() => {
|
||||||
logger.metric(
|
ax.metric('videoCard:click', {context: 'interstitial:explore'})
|
||||||
'videoCard:click',
|
|
||||||
{context: 'interstitial:explore'},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import {Loader} from '#/components/Loader'
|
|||||||
import * as ProfileCard from '#/components/ProfileCard'
|
import * as ProfileCard from '#/components/ProfileCard'
|
||||||
import * as Toast from '#/components/Toast'
|
import * as Toast from '#/components/Toast'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_NATIVE} from '#/env'
|
import {IS_NATIVE} from '#/env'
|
||||||
import type * as bsky from '#/types/bsky'
|
import type * as bsky from '#/types/bsky'
|
||||||
import {bulkWriteFollows} from '../Onboarding/util'
|
import {bulkWriteFollows} from '../Onboarding/util'
|
||||||
@@ -54,13 +55,14 @@ import {bulkWriteFollows} from '../Onboarding/util'
|
|||||||
type Props = NativeStackScreenProps<AllNavigatorParams, 'FindContactsSettings'>
|
type Props = NativeStackScreenProps<AllNavigatorParams, 'FindContactsSettings'>
|
||||||
export function FindContactsSettingsScreen({}: Props) {
|
export function FindContactsSettingsScreen({}: Props) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
|
|
||||||
const {data, error, refetch} = useContactsSyncStatusQuery()
|
const {data, error, refetch} = useContactsSyncStatusQuery()
|
||||||
|
|
||||||
const isFocused = useIsFocused()
|
const isFocused = useIsFocused()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data && isFocused) {
|
if (data && isFocused) {
|
||||||
logger.metric('contacts:settings:presented', {
|
ax.metric('contacts:settings:presented', {
|
||||||
hasPreviouslySynced: !!data.syncStatus,
|
hasPreviouslySynced: !!data.syncStatus,
|
||||||
matchCount: data.syncStatus?.matchesCount,
|
matchCount: data.syncStatus?.matchesCount,
|
||||||
})
|
})
|
||||||
@@ -197,7 +199,7 @@ function SyncStatus({
|
|||||||
await agent.app.bsky.contact.dismissMatch({subject: did})
|
await agent.app.bsky.contact.dismissMatch({subject: did})
|
||||||
},
|
},
|
||||||
onMutate: async (did: string) => {
|
onMutate: async (did: string) => {
|
||||||
logger.metric('contacts:settings:dismiss', {})
|
ax.metric('contacts:settings:dismiss', {})
|
||||||
optimisticRemoveMatch(queryClient, did)
|
optimisticRemoveMatch(queryClient, did)
|
||||||
},
|
},
|
||||||
onError: err => {
|
onError: err => {
|
||||||
@@ -278,6 +280,7 @@ function MatchItem({
|
|||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const shadow = useProfileShadow(profile)
|
const shadow = useProfileShadow(profile)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -314,7 +317,7 @@ function MatchItem({
|
|||||||
profile={profile}
|
profile={profile}
|
||||||
moderationOpts={moderationOpts}
|
moderationOpts={moderationOpts}
|
||||||
logContext="FindContacts"
|
logContext="FindContacts"
|
||||||
onFollow={() => logger.metric('contacts:settings:follow', {})}
|
onFollow={() => ax.metric('contacts:settings:follow', {})}
|
||||||
/>
|
/>
|
||||||
{!shadow.viewer?.following && (
|
{!shadow.viewer?.following && (
|
||||||
<Button
|
<Button
|
||||||
@@ -343,6 +346,7 @@ function StatusHeader({
|
|||||||
isAnyUnfollowed: boolean
|
isAnyUnfollowed: boolean
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
@@ -374,7 +378,7 @@ function StatusHeader({
|
|||||||
}
|
}
|
||||||
} while (cursor)
|
} while (cursor)
|
||||||
|
|
||||||
logger.metric('contacts:settings:followAll', {
|
ax.metric('contacts:settings:followAll', {
|
||||||
followCount: didsToFollow.length,
|
followCount: didsToFollow.length,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -459,6 +463,7 @@ function StatusHeader({
|
|||||||
function StatusFooter({syncedAt}: {syncedAt: string}) {
|
function StatusFooter({syncedAt}: {syncedAt: string}) {
|
||||||
const {_, i18n} = useLingui()
|
const {_, i18n} = useLingui()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
@@ -466,7 +471,7 @@ function StatusFooter({syncedAt}: {syncedAt: string}) {
|
|||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
await agent.app.bsky.contact.removeData({})
|
await agent.app.bsky.contact.removeData({})
|
||||||
},
|
},
|
||||||
onMutate: () => logger.metric('contacts:settings:removeData', {}),
|
onMutate: () => ax.metric('contacts:settings:removeData', {}),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
Toast.show(_(msg`Contacts removed`))
|
Toast.show(_(msg`Contacts removed`))
|
||||||
queryClient.setQueryData<AppBskyContactGetSyncStatus.OutputSchema>(
|
queryClient.setQueryData<AppBskyContactGetSyncStatus.OutputSchema>(
|
||||||
@@ -520,7 +525,7 @@ function StatusFooter({syncedAt}: {syncedAt: string}) {
|
|||||||
(Date.now() - new Date(syncedAt).getTime()) /
|
(Date.now() - new Date(syncedAt).getTime()) /
|
||||||
(1000 * 60 * 60 * 24),
|
(1000 * 60 * 60 * 24),
|
||||||
)
|
)
|
||||||
logger.metric('contacts:settings:resync', {
|
ax.metric('contacts:settings:resync', {
|
||||||
daysSinceLastSync,
|
daysSinceLastSync,
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import {type AppBskyNotificationDefs} from '@atproto/api'
|
|||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useNotificationSettingsUpdateMutation} from '#/state/queries/notifications/settings'
|
import {useNotificationSettingsUpdateMutation} from '#/state/queries/notifications/settings'
|
||||||
import {atoms as a, platform, useTheme} from '#/alf'
|
import {atoms as a, platform, useTheme} from '#/alf'
|
||||||
import * as Toggle from '#/components/forms/Toggle'
|
import * as Toggle from '#/components/forms/Toggle'
|
||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {Divider} from '../../components/SettingsList'
|
import {Divider} from '../../components/SettingsList'
|
||||||
|
|
||||||
export function PreferenceControls({
|
export function PreferenceControls({
|
||||||
@@ -61,6 +61,7 @@ export function Inner({
|
|||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {mutate} = useNotificationSettingsUpdateMutation()
|
const {mutate} = useNotificationSettingsUpdateMutation()
|
||||||
|
|
||||||
const channels = useMemo(() => {
|
const channels = useMemo(() => {
|
||||||
@@ -77,7 +78,7 @@ export function Inner({
|
|||||||
push: change.includes('push'),
|
push: change.includes('push'),
|
||||||
} satisfies typeof preference
|
} satisfies typeof preference
|
||||||
|
|
||||||
logger.metric('activityPreference:changeChannels', {
|
ax.metric('activityPreference:changeChannels', {
|
||||||
name,
|
name,
|
||||||
push: newPreference.push,
|
push: newPreference.push,
|
||||||
list: newPreference.list,
|
list: newPreference.list,
|
||||||
@@ -98,7 +99,7 @@ export function Inner({
|
|||||||
include: change,
|
include: change,
|
||||||
} satisfies typeof preference
|
} satisfies typeof preference
|
||||||
|
|
||||||
logger.metric('activityPreference:changeFilter', {name, value: change})
|
ax.metric('activityPreference:changeFilter', {name, value: change})
|
||||||
|
|
||||||
mutate({
|
mutate({
|
||||||
[name]: newPreference,
|
[name]: newPreference,
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import {useSignupContext} from '#/screens/Signup/state'
|
|||||||
import {CaptchaWebView} from '#/screens/Signup/StepCaptcha/CaptchaWebView'
|
import {CaptchaWebView} from '#/screens/Signup/StepCaptcha/CaptchaWebView'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {FormError} from '#/components/forms/FormError'
|
import {FormError} from '#/components/forms/FormError'
|
||||||
import {IS_ANDROID, IS_IOS, IS_NATIVE, IS_WEB} from '#/env'
|
import {useAnalytics} from '#/analytics'
|
||||||
import {GCP_PROJECT_ID} from '#/env'
|
import {GCP_PROJECT_ID, IS_ANDROID, IS_IOS, IS_NATIVE, IS_WEB} from '#/env'
|
||||||
import {BackNextButtons} from '../BackNextButtons'
|
import {BackNextButtons} from '../BackNextButtons'
|
||||||
|
|
||||||
const CAPTCHA_PATH =
|
const CAPTCHA_PATH =
|
||||||
@@ -71,6 +71,7 @@ function StepCaptchaInner({
|
|||||||
payload?: string
|
payload?: string
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const {state, dispatch} = useSignupContext()
|
const {state, dispatch} = useSignupContext()
|
||||||
|
|
||||||
@@ -109,13 +110,13 @@ function StepCaptchaInner({
|
|||||||
const onSuccess = React.useCallback(
|
const onSuccess = React.useCallback(
|
||||||
(code: string) => {
|
(code: string) => {
|
||||||
setCompleted(true)
|
setCompleted(true)
|
||||||
logger.metric('signup:captchaSuccess', {}, {statsig: true})
|
ax.metric('signup:captchaSuccess', {})
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'submit',
|
type: 'submit',
|
||||||
task: {verificationCode: code, mutableProcessed: false},
|
task: {verificationCode: code, mutableProcessed: false},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
[dispatch],
|
[ax, dispatch],
|
||||||
)
|
)
|
||||||
|
|
||||||
const onError = React.useCallback(
|
const onError = React.useCallback(
|
||||||
@@ -124,13 +125,13 @@ function StepCaptchaInner({
|
|||||||
type: 'setError',
|
type: 'setError',
|
||||||
value: _(msg`Error receiving captcha response.`),
|
value: _(msg`Error receiving captcha response.`),
|
||||||
})
|
})
|
||||||
logger.metric('signup:captchaFailure', {}, {statsig: true})
|
ax.metric('signup:captchaFailure', {})
|
||||||
logger.error('Signup Flow Error', {
|
logger.error('Signup Flow Error', {
|
||||||
registrationHandle: state.handle,
|
registrationHandle: state.handle,
|
||||||
error,
|
error,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
[_, dispatch, state.handle],
|
[_, ax, dispatch, state.handle],
|
||||||
)
|
)
|
||||||
|
|
||||||
const onBackPress = React.useCallback(() => {
|
const onBackPress = React.useCallback(() => {
|
||||||
|
|||||||
@@ -26,11 +26,13 @@ import {useThrottledValue} from '#/components/hooks/useThrottledValue'
|
|||||||
import {At_Stroke2_Corner0_Rounded as AtIcon} from '#/components/icons/At'
|
import {At_Stroke2_Corner0_Rounded as AtIcon} from '#/components/icons/At'
|
||||||
import {Check_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Check'
|
import {Check_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Check'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {BackNextButtons} from '../BackNextButtons'
|
import {BackNextButtons} from '../BackNextButtons'
|
||||||
import {HandleSuggestions} from './HandleSuggestions'
|
import {HandleSuggestions} from './HandleSuggestions'
|
||||||
|
|
||||||
export function StepHandle() {
|
export function StepHandle() {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {state, dispatch} = useSignupContext()
|
const {state, dispatch} = useSignupContext()
|
||||||
const [draftValue, setDraftValue] = useState(state.handle)
|
const [draftValue, setDraftValue] = useState(state.handle)
|
||||||
@@ -68,16 +70,19 @@ export function StepHandle() {
|
|||||||
const {available: handleAvailable} = await checkHandleAvailability(
|
const {available: handleAvailable} = await checkHandleAvailability(
|
||||||
createFullHandle(handle, state.userDomain),
|
createFullHandle(handle, state.userDomain),
|
||||||
state.serviceDescription?.did ?? 'UNKNOWN',
|
state.serviceDescription?.did ?? 'UNKNOWN',
|
||||||
{typeahead: false},
|
{},
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!handleAvailable) {
|
if (!handleAvailable) {
|
||||||
|
ax.metric('signup:handleTaken', {typeahead: false})
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'setError',
|
type: 'setError',
|
||||||
value: _(msg`That username is already taken`),
|
value: _(msg`That username is already taken`),
|
||||||
field: 'handle',
|
field: 'handle',
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
} else {
|
||||||
|
ax.metric('signup:handleAvailable', {typeahead: false})
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Failed to check handle availability on next press', {
|
logger.error('Failed to check handle availability on next press', {
|
||||||
@@ -88,15 +93,11 @@ export function StepHandle() {
|
|||||||
dispatch({type: 'setIsLoading', value: false})
|
dispatch({type: 'setIsLoading', value: false})
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.metric(
|
ax.metric('signup:nextPressed', {
|
||||||
'signup:nextPressed',
|
activeStep: state.activeStep,
|
||||||
{
|
phoneVerificationRequired:
|
||||||
activeStep: state.activeStep,
|
state.serviceDescription?.phoneVerificationRequired,
|
||||||
phoneVerificationRequired:
|
})
|
||||||
state.serviceDescription?.phoneVerificationRequired,
|
|
||||||
},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
// phoneVerificationRequired is actually whether a captcha is required
|
// phoneVerificationRequired is actually whether a captcha is required
|
||||||
if (!state.serviceDescription?.phoneVerificationRequired) {
|
if (!state.serviceDescription?.phoneVerificationRequired) {
|
||||||
dispatch({
|
dispatch({
|
||||||
@@ -115,11 +116,7 @@ export function StepHandle() {
|
|||||||
value: handle,
|
value: handle,
|
||||||
})
|
})
|
||||||
dispatch({type: 'prev'})
|
dispatch({type: 'prev'})
|
||||||
logger.metric(
|
ax.metric('signup:backPressed', {activeStep: state.activeStep})
|
||||||
'signup:backPressed',
|
|
||||||
{activeStep: state.activeStep},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasDebounceSettled = draftValue === debouncedDraftValue
|
const hasDebounceSettled = draftValue === debouncedDraftValue
|
||||||
@@ -202,7 +199,7 @@ export function StepHandle() {
|
|||||||
state.userDomain.length * -1,
|
state.userDomain.length * -1,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
logger.metric('signup:handleSuggestionSelected', {
|
ax.metric('signup:handleSuggestionSelected', {
|
||||||
method: suggestion.method,
|
method: suggestion.method,
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import {
|
|||||||
MIN_ACCESS_AGE,
|
MIN_ACCESS_AGE,
|
||||||
useAgeAssuranceRegionConfigWithFallback,
|
useAgeAssuranceRegionConfigWithFallback,
|
||||||
} from '#/ageAssurance/util'
|
} from '#/ageAssurance/util'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_NATIVE} from '#/env'
|
import {IS_NATIVE} from '#/env'
|
||||||
import {
|
import {
|
||||||
useDeviceGeolocationApi,
|
useDeviceGeolocationApi,
|
||||||
@@ -59,6 +60,7 @@ export function StepInfo({
|
|||||||
isLoadingStarterPack: boolean
|
isLoadingStarterPack: boolean
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {state, dispatch} = useSignupContext()
|
const {state, dispatch} = useSignupContext()
|
||||||
const preemptivelyCompleteActivePolicyUpdate =
|
const preemptivelyCompleteActivePolicyUpdate =
|
||||||
usePreemptivelyCompleteActivePolicyUpdate()
|
usePreemptivelyCompleteActivePolicyUpdate()
|
||||||
@@ -165,13 +167,9 @@ export function StepInfo({
|
|||||||
dispatch({type: 'setEmail', value: email})
|
dispatch({type: 'setEmail', value: email})
|
||||||
dispatch({type: 'setPassword', value: password})
|
dispatch({type: 'setPassword', value: password})
|
||||||
dispatch({type: 'next'})
|
dispatch({type: 'next'})
|
||||||
logger.metric(
|
ax.metric('signup:nextPressed', {
|
||||||
'signup:nextPressed',
|
activeStep: state.activeStep,
|
||||||
{
|
})
|
||||||
activeStep: state.activeStep,
|
|
||||||
},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ import {
|
|||||||
useSafeAreaFrame,
|
useSafeAreaFrame,
|
||||||
useSafeAreaInsets,
|
useSafeAreaInsets,
|
||||||
} from 'react-native-safe-area-context'
|
} from 'react-native-safe-area-context'
|
||||||
import {useEvent} from 'expo'
|
import {useEvent, useEventListener} from 'expo'
|
||||||
import {useEventListener} from 'expo'
|
|
||||||
import {Image, type ImageStyle} from 'expo-image'
|
import {Image, type ImageStyle} from 'expo-image'
|
||||||
import {LinearGradient} from 'expo-linear-gradient'
|
import {LinearGradient} from 'expo-linear-gradient'
|
||||||
import {createVideoPlayer, type VideoPlayer, VideoView} from 'expo-video'
|
import {createVideoPlayer, type VideoPlayer, VideoView} from 'expo-video'
|
||||||
@@ -66,13 +65,12 @@ import {
|
|||||||
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
||||||
import {
|
import {
|
||||||
FeedFeedbackProvider,
|
FeedFeedbackProvider,
|
||||||
|
useFeedFeedback,
|
||||||
useFeedFeedbackContext,
|
useFeedFeedbackContext,
|
||||||
} from '#/state/feed-feedback'
|
} from '#/state/feed-feedback'
|
||||||
import {useFeedFeedback} from '#/state/feed-feedback'
|
|
||||||
import {useFeedInfo} from '#/state/queries/feed'
|
import {useFeedInfo} from '#/state/queries/feed'
|
||||||
import {usePostLikeMutationQueue} from '#/state/queries/post'
|
import {usePostLikeMutationQueue} from '#/state/queries/post'
|
||||||
import {
|
import {
|
||||||
type AuthorFilter,
|
|
||||||
type FeedPostSliceItem,
|
type FeedPostSliceItem,
|
||||||
usePostFeedQuery,
|
usePostFeedQuery,
|
||||||
} from '#/state/queries/post-feed'
|
} from '#/state/queries/post-feed'
|
||||||
@@ -100,6 +98,7 @@ import * as Hider from '#/components/moderation/Hider'
|
|||||||
import {PostControls} from '#/components/PostControls'
|
import {PostControls} from '#/components/PostControls'
|
||||||
import {RichText} from '#/components/RichText'
|
import {RichText} from '#/components/RichText'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_ANDROID} from '#/env'
|
import {IS_ANDROID} from '#/env'
|
||||||
import * as bsky from '#/types/bsky'
|
import * as bsky from '#/types/bsky'
|
||||||
import {Scrubber, VIDEO_PLAYER_BOTTOM_INSET} from './components/Scrubber'
|
import {Scrubber, VIDEO_PLAYER_BOTTOM_INSET} from './components/Scrubber'
|
||||||
@@ -192,11 +191,9 @@ function Feed() {
|
|||||||
const feedDesc = useMemo(() => {
|
const feedDesc = useMemo(() => {
|
||||||
switch (params.type) {
|
switch (params.type) {
|
||||||
case 'feedgen':
|
case 'feedgen':
|
||||||
return `feedgen|${params.uri as string}` as const
|
return `feedgen|${params.uri}` as const
|
||||||
case 'author':
|
case 'author':
|
||||||
return `author|${params.did as string}|${
|
return `author|${params.did}|${params.filter}` as const
|
||||||
params.filter as AuthorFilter
|
|
||||||
}` as const
|
|
||||||
default:
|
default:
|
||||||
throw new Error(`Invalid video feed params ${JSON.stringify(params)}`)
|
throw new Error(`Invalid video feed params ${JSON.stringify(params)}`)
|
||||||
}
|
}
|
||||||
@@ -490,6 +487,7 @@ let VideoItem = ({
|
|||||||
feedContext: string | undefined
|
feedContext: string | undefined
|
||||||
reqId: string | undefined
|
reqId: string | undefined
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
|
const ax = useAnalytics()
|
||||||
const postShadow = usePostShadow(post)
|
const postShadow = usePostShadow(post)
|
||||||
const {width, height} = useSafeAreaFrame()
|
const {width, height} = useSafeAreaFrame()
|
||||||
const {sendInteraction, feedDescriptor} = useFeedFeedbackContext()
|
const {sendInteraction, feedDescriptor} = useFeedFeedbackContext()
|
||||||
@@ -507,16 +505,12 @@ let VideoItem = ({
|
|||||||
// Track post:view event
|
// Track post:view event
|
||||||
if (!hasTrackedView.current) {
|
if (!hasTrackedView.current) {
|
||||||
hasTrackedView.current = true
|
hasTrackedView.current = true
|
||||||
logger.metric(
|
ax.metric('post:view', {
|
||||||
'post:view',
|
uri: post.uri,
|
||||||
{
|
authorDid: post.author.did,
|
||||||
uri: post.uri,
|
logContext: 'ImmersiveVideo',
|
||||||
authorDid: post.author.did,
|
feedDescriptor,
|
||||||
logContext: 'ImmersiveVideo',
|
})
|
||||||
feedDescriptor,
|
|
||||||
},
|
|
||||||
{statsig: false},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
|||||||
import {PROD_DEFAULT_FEED} from '#/lib/constants'
|
import {PROD_DEFAULT_FEED} from '#/lib/constants'
|
||||||
import {replaceEqualDeep} from '#/lib/functions'
|
import {replaceEqualDeep} from '#/lib/functions'
|
||||||
import {getAge} from '#/lib/strings/time'
|
import {getAge} from '#/lib/strings/time'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {STALE} from '#/state/queries'
|
import {STALE} from '#/state/queries'
|
||||||
import {
|
import {
|
||||||
DEFAULT_HOME_FEED_PREFS,
|
DEFAULT_HOME_FEED_PREFS,
|
||||||
@@ -24,6 +23,7 @@ import {useAgent} from '#/state/session'
|
|||||||
import {saveLabelers} from '#/state/session/agent-config'
|
import {saveLabelers} from '#/state/session/agent-config'
|
||||||
import {useAgeAssurance} from '#/ageAssurance'
|
import {useAgeAssurance} from '#/ageAssurance'
|
||||||
import {makeAgeRestrictedModerationPrefs} from '#/ageAssurance/util'
|
import {makeAgeRestrictedModerationPrefs} from '#/ageAssurance/util'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
export * from '#/state/queries/preferences/const'
|
export * from '#/state/queries/preferences/const'
|
||||||
export * from '#/state/queries/preferences/moderation'
|
export * from '#/state/queries/preferences/moderation'
|
||||||
@@ -110,6 +110,7 @@ export function useClearPreferencesMutation() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function usePreferencesSetContentLabelMutation() {
|
export function usePreferencesSetContentLabelMutation() {
|
||||||
|
const ax = useAnalytics()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
@@ -120,11 +121,7 @@ export function usePreferencesSetContentLabelMutation() {
|
|||||||
>({
|
>({
|
||||||
mutationFn: async ({label, visibility, labelerDid}) => {
|
mutationFn: async ({label, visibility, labelerDid}) => {
|
||||||
await agent.setContentLabelPref(label, visibility, labelerDid)
|
await agent.setContentLabelPref(label, visibility, labelerDid)
|
||||||
logger.metric(
|
ax.metric('moderation:changeLabelPreference', {preference: visibility})
|
||||||
'moderation:changeLabelPreference',
|
|
||||||
{preference: visibility},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
@@ -417,6 +414,7 @@ export function useSetActiveProgressGuideMutation() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useSetVerificationPrefsMutation() {
|
export function useSetVerificationPrefsMutation() {
|
||||||
|
const ax = useAnalytics()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
|
|
||||||
@@ -424,9 +422,9 @@ export function useSetVerificationPrefsMutation() {
|
|||||||
mutationFn: async prefs => {
|
mutationFn: async prefs => {
|
||||||
await agent.setVerificationPrefs(prefs)
|
await agent.setVerificationPrefs(prefs)
|
||||||
if (prefs.hideBadges) {
|
if (prefs.hideBadges) {
|
||||||
logger.metric('verification:settings:hideBadges', {}, {statsig: true})
|
ax.metric('verification:settings:hideBadges', {})
|
||||||
} else {
|
} else {
|
||||||
logger.metric('verification:settings:unHideBadges', {}, {statsig: true})
|
ax.metric('verification:settings:unHideBadges', {})
|
||||||
}
|
}
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ import {type AppBskyUnspeccedGetPostThreadV2} from '@atproto/api'
|
|||||||
import debounce from 'lodash.debounce'
|
import debounce from 'lodash.debounce'
|
||||||
|
|
||||||
import {OnceKey, useCallOnce} from '#/lib/hooks/useCallOnce'
|
import {OnceKey, useCallOnce} from '#/lib/hooks/useCallOnce'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {
|
import {
|
||||||
usePreferencesQuery,
|
usePreferencesQuery,
|
||||||
useSetThreadViewPreferencesMutation,
|
useSetThreadViewPreferencesMutation,
|
||||||
} from '#/state/queries/preferences'
|
} from '#/state/queries/preferences'
|
||||||
import {type ThreadViewPreferences} from '#/state/queries/preferences/types'
|
import {type ThreadViewPreferences} from '#/state/queries/preferences/types'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {type Literal} from '#/types/utils'
|
import {type Literal} from '#/types/utils'
|
||||||
|
|
||||||
export type ThreadSortOption = Literal<
|
export type ThreadSortOption = Literal<
|
||||||
@@ -28,6 +28,7 @@ export type ThreadPreferences = {
|
|||||||
export function useThreadPreferences({
|
export function useThreadPreferences({
|
||||||
save,
|
save,
|
||||||
}: {save?: boolean} = {}): ThreadPreferences {
|
}: {save?: boolean} = {}): ThreadPreferences {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {data: preferences} = usePreferencesQuery()
|
const {data: preferences} = usePreferencesQuery()
|
||||||
const serverPrefs = preferences?.threadViewPrefs
|
const serverPrefs = preferences?.threadViewPrefs
|
||||||
const once = useCallOnce(OnceKey.PreferencesThread)
|
const once = useCallOnce(OnceKey.PreferencesThread)
|
||||||
@@ -61,7 +62,7 @@ export function useThreadPreferences({
|
|||||||
)
|
)
|
||||||
|
|
||||||
once(() => {
|
once(() => {
|
||||||
logger.metric('thread:preferences:load', {
|
ax.metric('thread:preferences:load', {
|
||||||
sort: serverPrefs.sort,
|
sort: serverPrefs.sort,
|
||||||
view: serverPrefs.lab_treeViewEnabled ? 'tree' : 'linear',
|
view: serverPrefs.lab_treeViewEnabled ? 'tree' : 'linear',
|
||||||
})
|
})
|
||||||
@@ -76,12 +77,12 @@ export function useThreadPreferences({
|
|||||||
try {
|
try {
|
||||||
setIsSaving(true)
|
setIsSaving(true)
|
||||||
await mutateAsync(prefs)
|
await mutateAsync(prefs)
|
||||||
logger.metric('thread:preferences:update', {
|
ax.metric('thread:preferences:update', {
|
||||||
sort: prefs.sort,
|
sort: prefs.sort,
|
||||||
view: prefs.lab_treeViewEnabled ? 'tree' : 'linear',
|
view: prefs.lab_treeViewEnabled ? 'tree' : 'linear',
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('useThreadPreferences failed to save', {
|
ax.logger.error('useThreadPreferences failed to save', {
|
||||||
safeMessage: e,
|
safeMessage: e,
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -2,12 +2,13 @@ import {type AppBskyActorGetProfile} from '@atproto/api'
|
|||||||
import {useMutation} from '@tanstack/react-query'
|
import {useMutation} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {until} from '#/lib/async/until'
|
import {until} from '#/lib/async/until'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useUpdateProfileVerificationCache} from '#/state/queries/verification/useUpdateProfileVerificationCache'
|
import {useUpdateProfileVerificationCache} from '#/state/queries/verification/useUpdateProfileVerificationCache'
|
||||||
import {useAgent, useSession} from '#/state/session'
|
import {useAgent, useSession} from '#/state/session'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import type * as bsky from '#/types/bsky'
|
import type * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
export function useVerificationCreateMutation() {
|
export function useVerificationCreateMutation() {
|
||||||
|
const ax = useAnalytics()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const updateProfileVerificationCache = useUpdateProfileVerificationCache()
|
const updateProfileVerificationCache = useUpdateProfileVerificationCache()
|
||||||
@@ -46,7 +47,7 @@ export function useVerificationCreateMutation() {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
async onSuccess(_, {profile}) {
|
async onSuccess(_, {profile}) {
|
||||||
logger.metric('verification:create', {}, {statsig: true})
|
ax.metric('verification:create', {})
|
||||||
await updateProfileVerificationCache({profile})
|
await updateProfileVerificationCache({profile})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,12 +6,13 @@ import {
|
|||||||
import {useMutation} from '@tanstack/react-query'
|
import {useMutation} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {until} from '#/lib/async/until'
|
import {until} from '#/lib/async/until'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useUpdateProfileVerificationCache} from '#/state/queries/verification/useUpdateProfileVerificationCache'
|
import {useUpdateProfileVerificationCache} from '#/state/queries/verification/useUpdateProfileVerificationCache'
|
||||||
import {useAgent, useSession} from '#/state/session'
|
import {useAgent, useSession} from '#/state/session'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import type * as bsky from '#/types/bsky'
|
import type * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
export function useVerificationsRemoveMutation() {
|
export function useVerificationsRemoveMutation() {
|
||||||
|
const ax = useAnalytics()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const updateProfileVerificationCache = useUpdateProfileVerificationCache()
|
const updateProfileVerificationCache = useUpdateProfileVerificationCache()
|
||||||
@@ -56,7 +57,7 @@ export function useVerificationsRemoveMutation() {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
async onSuccess(_, {profile}) {
|
async onSuccess(_, {profile}) {
|
||||||
logger.metric('verification:revoke', {}, {statsig: true})
|
ax.metric('verification:revoke', {})
|
||||||
await updateProfileVerificationCache({profile})
|
await updateProfileVerificationCache({profile})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import {Earth_Stroke2_Corner0_Rounded as EarthIcon} from '#/components/icons/Glo
|
|||||||
import {Group3_Stroke2_Corner0_Rounded as GroupIcon} from '#/components/icons/Group'
|
import {Group3_Stroke2_Corner0_Rounded as GroupIcon} from '#/components/icons/Group'
|
||||||
import * as Tooltip from '#/components/Tooltip'
|
import * as Tooltip from '#/components/Tooltip'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_NATIVE} from '#/env'
|
import {IS_NATIVE} from '#/env'
|
||||||
import {useThreadgateNudged} from '#/storage/hooks/threadgate-nudged'
|
import {useThreadgateNudged} from '#/storage/hooks/threadgate-nudged'
|
||||||
|
|
||||||
@@ -42,6 +43,7 @@ export function ThreadgateBtn({
|
|||||||
style?: StyleProp<AnimatedStyle<ViewStyle>>
|
style?: StyleProp<AnimatedStyle<ViewStyle>>
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const control = Dialog.useDialogControl()
|
const control = Dialog.useDialogControl()
|
||||||
const [threadgateNudged, setThreadgateNudged] = useThreadgateNudged()
|
const [threadgateNudged, setThreadgateNudged] = useThreadgateNudged()
|
||||||
const [showTooltip, setShowTooltip] = useState(false)
|
const [showTooltip, setShowTooltip] = useState(false)
|
||||||
@@ -66,7 +68,7 @@ export function ThreadgateBtn({
|
|||||||
const [persist, setPersist] = useState(false)
|
const [persist, setPersist] = useState(false)
|
||||||
|
|
||||||
const onPress = () => {
|
const onPress = () => {
|
||||||
logger.metric('composer:threadgate:open', {
|
ax.metric('composer:threadgate:open', {
|
||||||
nudged: tooltipWasShown,
|
nudged: tooltipWasShown,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
useVideoLibraryPermission,
|
useVideoLibraryPermission,
|
||||||
} from '#/lib/hooks/usePermissions'
|
} from '#/lib/hooks/usePermissions'
|
||||||
import {openCamera, openUnifiedPicker} from '#/lib/media/picker'
|
import {openCamera, openUnifiedPicker} from '#/lib/media/picker'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useCurrentAccountProfile} from '#/state/queries/useCurrentAccountProfile'
|
import {useCurrentAccountProfile} from '#/state/queries/useCurrentAccountProfile'
|
||||||
import {MAX_IMAGES} from '#/view/com/composer/state/composer'
|
import {MAX_IMAGES} from '#/view/com/composer/state/composer'
|
||||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||||
@@ -21,11 +20,13 @@ import {Camera_Stroke2_Corner0_Rounded as CameraIcon} from '#/components/icons/C
|
|||||||
import {Image_Stroke2_Corner0_Rounded as ImageIcon} from '#/components/icons/Image'
|
import {Image_Stroke2_Corner0_Rounded as ImageIcon} from '#/components/icons/Image'
|
||||||
import {SubtleHover} from '#/components/SubtleHover'
|
import {SubtleHover} from '#/components/SubtleHover'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_NATIVE} from '#/env'
|
import {IS_NATIVE} from '#/env'
|
||||||
|
|
||||||
export function ComposerPrompt() {
|
export function ComposerPrompt() {
|
||||||
const {_} = useLingui()
|
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
|
const {_} = useLingui()
|
||||||
const {openComposer} = useOpenComposer()
|
const {openComposer} = useOpenComposer()
|
||||||
const profile = useCurrentAccountProfile()
|
const profile = useCurrentAccountProfile()
|
||||||
const [hover, setHover] = useState(false)
|
const [hover, setHover] = useState(false)
|
||||||
@@ -35,12 +36,12 @@ export function ComposerPrompt() {
|
|||||||
const sheetWrapper = useSheetWrapper()
|
const sheetWrapper = useSheetWrapper()
|
||||||
|
|
||||||
const onPress = useCallback(() => {
|
const onPress = useCallback(() => {
|
||||||
logger.metric('composerPrompt:press', {})
|
ax.metric('composerPrompt:press', {})
|
||||||
openComposer({})
|
openComposer({})
|
||||||
}, [openComposer])
|
}, [ax, openComposer])
|
||||||
|
|
||||||
const onPressImage = useCallback(async () => {
|
const onPressImage = useCallback(async () => {
|
||||||
logger.metric('composerPrompt:gallery:press', {})
|
ax.metric('composerPrompt:gallery:press', {})
|
||||||
|
|
||||||
// On web, open the composer with the gallery picker auto-opening
|
// On web, open the composer with the gallery picker auto-opening
|
||||||
if (!IS_NATIVE) {
|
if (!IS_NATIVE) {
|
||||||
@@ -87,10 +88,11 @@ export function ComposerPrompt() {
|
|||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
if (!String(err).toLowerCase().includes('cancel')) {
|
if (!String(err).toLowerCase().includes('cancel')) {
|
||||||
logger.warn('Error opening image picker', {error: err})
|
ax.logger.error('Error opening image picker', {error: err})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
|
ax,
|
||||||
openComposer,
|
openComposer,
|
||||||
requestPhotoAccessIfNeeded,
|
requestPhotoAccessIfNeeded,
|
||||||
requestVideoAccessIfNeeded,
|
requestVideoAccessIfNeeded,
|
||||||
@@ -98,7 +100,7 @@ export function ComposerPrompt() {
|
|||||||
])
|
])
|
||||||
|
|
||||||
const onPressCamera = useCallback(async () => {
|
const onPressCamera = useCallback(async () => {
|
||||||
logger.metric('composerPrompt:camera:press', {})
|
ax.metric('composerPrompt:camera:press', {})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!(await requestCameraAccessIfNeeded())) {
|
if (!(await requestCameraAccessIfNeeded())) {
|
||||||
@@ -126,10 +128,10 @@ export function ComposerPrompt() {
|
|||||||
})
|
})
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
if (!String(err).toLowerCase().includes('cancel')) {
|
if (!String(err).toLowerCase().includes('cancel')) {
|
||||||
logger.warn('Error opening camera', {error: err})
|
ax.logger.error('Error opening camera', {error: err})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [openComposer, requestCameraAccessIfNeeded])
|
}, [ax, openComposer, requestCameraAccessIfNeeded])
|
||||||
|
|
||||||
if (!profile) {
|
if (!profile) {
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -12,14 +12,15 @@ import {usePalette} from '#/lib/hooks/usePalette'
|
|||||||
import {MagnifyingGlassIcon} from '#/lib/icons'
|
import {MagnifyingGlassIcon} from '#/lib/icons'
|
||||||
import {type NavigationProp} from '#/lib/routes/types'
|
import {type NavigationProp} from '#/lib/routes/types'
|
||||||
import {s} from '#/lib/styles'
|
import {s} from '#/lib/styles'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
import {Button} from '../util/forms/Button'
|
import {Button} from '../util/forms/Button'
|
||||||
import {Text} from '../util/text/Text'
|
import {Text} from '../util/text/Text'
|
||||||
|
|
||||||
export function CustomFeedEmptyState() {
|
export function CustomFeedEmptyState() {
|
||||||
|
const ax = useAnalytics()
|
||||||
const feedFeedback = useFeedFeedbackContext()
|
const feedFeedback = useFeedFeedbackContext()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const hasLoggedDiscoverEmptyErrorRef = React.useRef(false)
|
const hasLoggedDiscoverEmptyErrorRef = React.useRef(false)
|
||||||
@@ -33,7 +34,7 @@ export function CustomFeedEmptyState() {
|
|||||||
!hasLoggedDiscoverEmptyErrorRef.current
|
!hasLoggedDiscoverEmptyErrorRef.current
|
||||||
) {
|
) {
|
||||||
hasLoggedDiscoverEmptyErrorRef.current = true
|
hasLoggedDiscoverEmptyErrorRef.current = true
|
||||||
logger.metric('feed:discover:emptyError', {
|
ax.metric('feed:discover:emptyError', {
|
||||||
userDid: currentAccount.did,
|
userDid: currentAccount.did,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
|||||||
import {usePalette} from '#/lib/hooks/usePalette'
|
import {usePalette} from '#/lib/hooks/usePalette'
|
||||||
import {makeProfileLink} from '#/lib/routes/links'
|
import {makeProfileLink} from '#/lib/routes/links'
|
||||||
import {countLines} from '#/lib/strings/helpers'
|
import {countLines} from '#/lib/strings/helpers'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {
|
import {
|
||||||
POST_TOMBSTONE,
|
POST_TOMBSTONE,
|
||||||
type Shadow,
|
type Shadow,
|
||||||
@@ -48,6 +47,7 @@ import {PostControls} from '#/components/PostControls'
|
|||||||
import {DiscoverDebug} from '#/components/PostControls/DiscoverDebug'
|
import {DiscoverDebug} from '#/components/PostControls/DiscoverDebug'
|
||||||
import {RichText} from '#/components/RichText'
|
import {RichText} from '#/components/RichText'
|
||||||
import {SubtleHover} from '#/components/SubtleHover'
|
import {SubtleHover} from '#/components/SubtleHover'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import * as bsky from '#/types/bsky'
|
import * as bsky from '#/types/bsky'
|
||||||
import {PostFeedReason} from './PostFeedReason'
|
import {PostFeedReason} from './PostFeedReason'
|
||||||
|
|
||||||
@@ -158,6 +158,7 @@ let FeedItemInner = ({
|
|||||||
rootPost: AppBskyFeedDefs.PostView
|
rootPost: AppBskyFeedDefs.PostView
|
||||||
onShowLess?: (interaction: AppBskyFeedDefs.Interaction) => void
|
onShowLess?: (interaction: AppBskyFeedDefs.Interaction) => void
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
|
const ax = useAnalytics()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const {openComposer} = useOpenComposer()
|
const {openComposer} = useOpenComposer()
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
@@ -198,7 +199,7 @@ let FeedItemInner = ({
|
|||||||
feedContext,
|
feedContext,
|
||||||
reqId,
|
reqId,
|
||||||
})
|
})
|
||||||
logger.metric('post:clickthroughAuthor', {
|
ax.metric('post:clickthroughAuthor', {
|
||||||
uri: post.uri,
|
uri: post.uri,
|
||||||
authorDid: post.author.did,
|
authorDid: post.author.did,
|
||||||
logContext: 'FeedItem',
|
logContext: 'FeedItem',
|
||||||
@@ -222,7 +223,7 @@ let FeedItemInner = ({
|
|||||||
feedContext,
|
feedContext,
|
||||||
reqId,
|
reqId,
|
||||||
})
|
})
|
||||||
logger.metric('post:clickthroughEmbed', {
|
ax.metric('post:clickthroughEmbed', {
|
||||||
uri: post.uri,
|
uri: post.uri,
|
||||||
authorDid: post.author.did,
|
authorDid: post.author.did,
|
||||||
logContext: 'FeedItem',
|
logContext: 'FeedItem',
|
||||||
@@ -237,7 +238,7 @@ let FeedItemInner = ({
|
|||||||
feedContext,
|
feedContext,
|
||||||
reqId,
|
reqId,
|
||||||
})
|
})
|
||||||
logger.metric('post:clickthroughItem', {
|
ax.metric('post:clickthroughItem', {
|
||||||
uri: post.uri,
|
uri: post.uri,
|
||||||
authorDid: post.author.did,
|
authorDid: post.author.did,
|
||||||
logContext: 'FeedItem',
|
logContext: 'FeedItem',
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {useResolveDidQuery} from '#/state/queries/resolve-uri'
|
|||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {PeopleRemove2_Stroke1_Corner0_Rounded as PeopleRemoveIcon} from '#/components/icons/PeopleRemove2'
|
import {PeopleRemove2_Stroke1_Corner0_Rounded as PeopleRemoveIcon} from '#/components/icons/PeopleRemove2'
|
||||||
import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
|
import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {List} from '../util/List'
|
import {List} from '../util/List'
|
||||||
import {ProfileCardWithFollowBtn} from './ProfileCard'
|
import {ProfileCardWithFollowBtn} from './ProfileCard'
|
||||||
|
|
||||||
@@ -41,6 +42,7 @@ function keyExtractor(item: ActorDefs.ProfileViewBasic) {
|
|||||||
|
|
||||||
export function ProfileFollowers({name}: {name: string}) {
|
export function ProfileFollowers({name}: {name: string}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const navigation = useNavigation()
|
const navigation = useNavigation()
|
||||||
const initialNumToRender = useInitialNumToRender()
|
const initialNumToRender = useInitialNumToRender()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
@@ -88,14 +90,14 @@ export function ProfileFollowers({name}: {name: string}) {
|
|||||||
currentPageCount >= 3 &&
|
currentPageCount >= 3 &&
|
||||||
currentPageCount > paginationTrackingRef.current.page
|
currentPageCount > paginationTrackingRef.current.page
|
||||||
) {
|
) {
|
||||||
logger.metric('profile:followers:paginate', {
|
ax.metric('profile:followers:paginate', {
|
||||||
contextProfileDid: resolvedDid,
|
contextProfileDid: resolvedDid,
|
||||||
itemCount: followers.length,
|
itemCount: followers.length,
|
||||||
page: currentPageCount,
|
page: currentPageCount,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
paginationTrackingRef.current.page = currentPageCount
|
paginationTrackingRef.current.page = currentPageCount
|
||||||
}, [data?.pages?.length, resolvedDid, followers.length])
|
}, [ax, data?.pages?.length, resolvedDid, followers.length])
|
||||||
|
|
||||||
const onRefresh = React.useCallback(async () => {
|
const onRefresh = React.useCallback(async () => {
|
||||||
setIsPTRing(true)
|
setIsPTRing(true)
|
||||||
@@ -125,12 +127,12 @@ export function ProfileFollowers({name}: {name: string}) {
|
|||||||
// track pageview
|
// track pageview
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (resolvedDid) {
|
if (resolvedDid) {
|
||||||
logger.metric('profile:followers:view', {
|
ax.metric('profile:followers:view', {
|
||||||
contextProfileDid: resolvedDid,
|
contextProfileDid: resolvedDid,
|
||||||
isOwnProfile: isMe,
|
isOwnProfile: isMe,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, [resolvedDid, isMe])
|
}, [ax, resolvedDid, isMe])
|
||||||
|
|
||||||
// track seen items
|
// track seen items
|
||||||
const seenItemsRef = React.useRef<Set<string>>(new Set())
|
const seenItemsRef = React.useRef<Set<string>>(new Set())
|
||||||
@@ -147,17 +149,13 @@ export function ProfileFollowers({name}: {name: string}) {
|
|||||||
if (position === 0) {
|
if (position === 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.metric(
|
ax.metric('profileCard:seen', {
|
||||||
'profileCard:seen',
|
profileDid: item.did,
|
||||||
{
|
position,
|
||||||
profileDid: item.did,
|
...(resolvedDid !== undefined && {contextProfileDid: resolvedDid}),
|
||||||
position,
|
})
|
||||||
...(resolvedDid !== undefined && {contextProfileDid: resolvedDid}),
|
|
||||||
},
|
|
||||||
{statsig: false},
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
[followers, resolvedDid],
|
[ax, followers, resolvedDid],
|
||||||
)
|
)
|
||||||
|
|
||||||
if (followers.length < 1) {
|
if (followers.length < 1) {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {useSession} from '#/state/session'
|
|||||||
import {FindContactsBannerNUX} from '#/components/contacts/FindContactsBannerNUX'
|
import {FindContactsBannerNUX} from '#/components/contacts/FindContactsBannerNUX'
|
||||||
import {PeopleRemove2_Stroke1_Corner0_Rounded as PeopleRemoveIcon} from '#/components/icons/PeopleRemove2'
|
import {PeopleRemove2_Stroke1_Corner0_Rounded as PeopleRemoveIcon} from '#/components/icons/PeopleRemove2'
|
||||||
import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
|
import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
import {List} from '../util/List'
|
import {List} from '../util/List'
|
||||||
import {ProfileCardWithFollowBtn} from './ProfileCard'
|
import {ProfileCardWithFollowBtn} from './ProfileCard'
|
||||||
@@ -44,6 +45,7 @@ function keyExtractor(item: ActorDefs.ProfileViewBasic) {
|
|||||||
|
|
||||||
export function ProfileFollows({name}: {name: string}) {
|
export function ProfileFollows({name}: {name: string}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const initialNumToRender = useInitialNumToRender()
|
const initialNumToRender = useInitialNumToRender()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const navigation = useNavigation<NavigationProp>()
|
const navigation = useNavigation<NavigationProp>()
|
||||||
@@ -100,14 +102,14 @@ export function ProfileFollows({name}: {name: string}) {
|
|||||||
currentPageCount >= 3 &&
|
currentPageCount >= 3 &&
|
||||||
currentPageCount > paginationTrackingRef.current.page
|
currentPageCount > paginationTrackingRef.current.page
|
||||||
) {
|
) {
|
||||||
logger.metric('profile:following:paginate', {
|
ax.metric('profile:following:paginate', {
|
||||||
contextProfileDid: resolvedDid,
|
contextProfileDid: resolvedDid,
|
||||||
itemCount: follows.length,
|
itemCount: follows.length,
|
||||||
page: currentPageCount,
|
page: currentPageCount,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
paginationTrackingRef.current.page = currentPageCount
|
paginationTrackingRef.current.page = currentPageCount
|
||||||
}, [data?.pages?.length, resolvedDid, follows.length])
|
}, [ax, data?.pages?.length, resolvedDid, follows.length])
|
||||||
|
|
||||||
const onRefresh = React.useCallback(async () => {
|
const onRefresh = React.useCallback(async () => {
|
||||||
setIsPTRing(true)
|
setIsPTRing(true)
|
||||||
@@ -137,12 +139,12 @@ export function ProfileFollows({name}: {name: string}) {
|
|||||||
// track pageview
|
// track pageview
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (resolvedDid) {
|
if (resolvedDid) {
|
||||||
logger.metric('profile:following:view', {
|
ax.metric('profile:following:view', {
|
||||||
contextProfileDid: resolvedDid,
|
contextProfileDid: resolvedDid,
|
||||||
isOwnProfile: isMe,
|
isOwnProfile: isMe,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, [resolvedDid, isMe])
|
}, [ax, resolvedDid, isMe])
|
||||||
|
|
||||||
// track seen items
|
// track seen items
|
||||||
const seenItemsRef = React.useRef<Set<string>>(new Set())
|
const seenItemsRef = React.useRef<Set<string>>(new Set())
|
||||||
@@ -159,17 +161,13 @@ export function ProfileFollows({name}: {name: string}) {
|
|||||||
if (position === 0) {
|
if (position === 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.metric(
|
ax.metric('profileCard:seen', {
|
||||||
'profileCard:seen',
|
profileDid: item.did,
|
||||||
{
|
position,
|
||||||
profileDid: item.did,
|
...(resolvedDid !== undefined && {contextProfileDid: resolvedDid}),
|
||||||
position,
|
})
|
||||||
...(resolvedDid !== undefined && {contextProfileDid: resolvedDid}),
|
|
||||||
},
|
|
||||||
{statsig: false},
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
[follows, resolvedDid],
|
[ax, follows, resolvedDid],
|
||||||
)
|
)
|
||||||
|
|
||||||
if (follows.length < 1) {
|
if (follows.length < 1) {
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {makeProfileLink} from '#/lib/routes/links'
|
|||||||
import {type NavigationProp} from '#/lib/routes/types'
|
import {type NavigationProp} from '#/lib/routes/types'
|
||||||
import {shareText, shareUrl} from '#/lib/sharing'
|
import {shareText, shareUrl} from '#/lib/sharing'
|
||||||
import {toShareUrl} from '#/lib/strings/url-helpers'
|
import {toShareUrl} from '#/lib/strings/url-helpers'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {type Shadow} from '#/state/cache/types'
|
import {type Shadow} from '#/state/cache/types'
|
||||||
import {useModalControls} from '#/state/modals'
|
import {useModalControls} from '#/state/modals'
|
||||||
import {Nux, useNux, useSaveNux} from '#/state/queries/nuxs'
|
import {Nux, useNux, useSaveNux} from '#/state/queries/nuxs'
|
||||||
@@ -60,6 +59,7 @@ import * as Prompt from '#/components/Prompt'
|
|||||||
import {useFullVerificationState} from '#/components/verification'
|
import {useFullVerificationState} from '#/components/verification'
|
||||||
import {VerificationCreatePrompt} from '#/components/verification/VerificationCreatePrompt'
|
import {VerificationCreatePrompt} from '#/components/verification/VerificationCreatePrompt'
|
||||||
import {VerificationRemovePrompt} from '#/components/verification/VerificationRemovePrompt'
|
import {VerificationRemovePrompt} from '#/components/verification/VerificationRemovePrompt'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
import {Dot} from '#/features/nuxs/components/Dot'
|
import {Dot} from '#/features/nuxs/components/Dot'
|
||||||
import {Gradient} from '#/features/nuxs/components/Gradient'
|
import {Gradient} from '#/features/nuxs/components/Gradient'
|
||||||
@@ -71,6 +71,7 @@ let ProfileMenu = ({
|
|||||||
profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>
|
profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {currentAccount, hasSession} = useSession()
|
const {currentAccount, hasSession} = useSession()
|
||||||
const {openModal} = useModalControls()
|
const {openModal} = useModalControls()
|
||||||
@@ -121,7 +122,7 @@ let ProfileMenu = ({
|
|||||||
}, [queryClient, profile.did])
|
}, [queryClient, profile.did])
|
||||||
|
|
||||||
const onPressAddToStarterPacks = React.useCallback(() => {
|
const onPressAddToStarterPacks = React.useCallback(() => {
|
||||||
logger.metric('profile:addToStarterPack', {})
|
ax.metric('profile:addToStarterPack', {})
|
||||||
addToStarterPacksDialogControl.open()
|
addToStarterPacksDialogControl.open()
|
||||||
}, [addToStarterPacksDialogControl])
|
}, [addToStarterPacksDialogControl])
|
||||||
|
|
||||||
@@ -147,7 +148,7 @@ let ProfileMenu = ({
|
|||||||
Toast.show(_(msg({message: 'Account unmuted', context: 'toast'})))
|
Toast.show(_(msg({message: 'Account unmuted', context: 'toast'})))
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e?.name !== 'AbortError') {
|
if (e?.name !== 'AbortError') {
|
||||||
logger.error('Failed to unmute account', {message: e})
|
ax.logger.error('Failed to unmute account', {message: e})
|
||||||
Toast.show(_(msg`There was an issue! ${e.toString()}`), 'xmark')
|
Toast.show(_(msg`There was an issue! ${e.toString()}`), 'xmark')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,12 +158,12 @@ let ProfileMenu = ({
|
|||||||
Toast.show(_(msg({message: 'Account muted', context: 'toast'})))
|
Toast.show(_(msg({message: 'Account muted', context: 'toast'})))
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e?.name !== 'AbortError') {
|
if (e?.name !== 'AbortError') {
|
||||||
logger.error('Failed to mute account', {message: e})
|
ax.logger.error('Failed to mute account', {message: e})
|
||||||
Toast.show(_(msg`There was an issue! ${e.toString()}`), 'xmark')
|
Toast.show(_(msg`There was an issue! ${e.toString()}`), 'xmark')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [profile.viewer?.muted, queueUnmute, _, queueMute])
|
}, [ax, profile.viewer?.muted, queueUnmute, _, queueMute])
|
||||||
|
|
||||||
const blockAccount = React.useCallback(async () => {
|
const blockAccount = React.useCallback(async () => {
|
||||||
if (profile.viewer?.blocking) {
|
if (profile.viewer?.blocking) {
|
||||||
@@ -171,7 +172,7 @@ let ProfileMenu = ({
|
|||||||
Toast.show(_(msg({message: 'Account unblocked', context: 'toast'})))
|
Toast.show(_(msg({message: 'Account unblocked', context: 'toast'})))
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e?.name !== 'AbortError') {
|
if (e?.name !== 'AbortError') {
|
||||||
logger.error('Failed to unblock account', {message: e})
|
ax.logger.error('Failed to unblock account', {message: e})
|
||||||
Toast.show(_(msg`There was an issue! ${e.toString()}`), 'xmark')
|
Toast.show(_(msg`There was an issue! ${e.toString()}`), 'xmark')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,12 +182,12 @@ let ProfileMenu = ({
|
|||||||
Toast.show(_(msg({message: 'Account blocked', context: 'toast'})))
|
Toast.show(_(msg({message: 'Account blocked', context: 'toast'})))
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e?.name !== 'AbortError') {
|
if (e?.name !== 'AbortError') {
|
||||||
logger.error('Failed to block account', {message: e})
|
ax.logger.error('Failed to block account', {message: e})
|
||||||
Toast.show(_(msg`There was an issue! ${e.toString()}`), 'xmark')
|
Toast.show(_(msg`There was an issue! ${e.toString()}`), 'xmark')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [profile.viewer?.blocking, _, queueUnblock, queueBlock])
|
}, [ax, profile.viewer?.blocking, _, queueUnblock, queueBlock])
|
||||||
|
|
||||||
const onPressFollowAccount = React.useCallback(async () => {
|
const onPressFollowAccount = React.useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
@@ -194,11 +195,11 @@ let ProfileMenu = ({
|
|||||||
Toast.show(_(msg({message: 'Account followed', context: 'toast'})))
|
Toast.show(_(msg({message: 'Account followed', context: 'toast'})))
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e?.name !== 'AbortError') {
|
if (e?.name !== 'AbortError') {
|
||||||
logger.error('Failed to follow account', {message: e})
|
ax.logger.error('Failed to follow account', {message: e})
|
||||||
Toast.show(_(msg`There was an issue! ${e.toString()}`), 'xmark')
|
Toast.show(_(msg`There was an issue! ${e.toString()}`), 'xmark')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [_, queueFollow])
|
}, [_, ax, queueFollow])
|
||||||
|
|
||||||
const onPressUnfollowAccount = React.useCallback(async () => {
|
const onPressUnfollowAccount = React.useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
@@ -206,11 +207,11 @@ let ProfileMenu = ({
|
|||||||
Toast.show(_(msg({message: 'Account unfollowed', context: 'toast'})))
|
Toast.show(_(msg({message: 'Account unfollowed', context: 'toast'})))
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e?.name !== 'AbortError') {
|
if (e?.name !== 'AbortError') {
|
||||||
logger.error('Failed to unfollow account', {message: e})
|
ax.logger.error('Failed to unfollow account', {message: e})
|
||||||
Toast.show(_(msg`There was an issue! ${e.toString()}`), 'xmark')
|
Toast.show(_(msg`There was an issue! ${e.toString()}`), 'xmark')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [_, queueUnfollow])
|
}, [_, ax, queueUnfollow])
|
||||||
|
|
||||||
const onPressReportAccount = React.useCallback(() => {
|
const onPressReportAccount = React.useCallback(() => {
|
||||||
reportDialogControl.open()
|
reportDialogControl.open()
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import {LiveStatusDialog} from '#/components/live/LiveStatusDialog'
|
|||||||
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
||||||
import * as Menu from '#/components/Menu'
|
import * as Menu from '#/components/Menu'
|
||||||
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
|
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_ANDROID, IS_NATIVE, IS_WEB, IS_WEB_TOUCH_DEVICE} from '#/env'
|
import {IS_ANDROID, IS_NATIVE, IS_WEB, IS_WEB_TOUCH_DEVICE} from '#/env'
|
||||||
import type * as bsky from '#/types/bsky'
|
import type * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
@@ -530,6 +531,7 @@ let PreviewableUserAvatar = ({
|
|||||||
live,
|
live,
|
||||||
...props
|
...props
|
||||||
}: PreviewableUserAvatarProps): React.ReactNode => {
|
}: PreviewableUserAvatarProps): React.ReactNode => {
|
||||||
|
const ax = useAnalytics()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const status = useActorStatus(profile)
|
const status = useActorStatus(profile)
|
||||||
@@ -543,11 +545,7 @@ let PreviewableUserAvatar = ({
|
|||||||
|
|
||||||
const onOpenLiveStatus = useCallback(() => {
|
const onOpenLiveStatus = useCallback(() => {
|
||||||
playHaptic('Light')
|
playHaptic('Light')
|
||||||
logger.metric(
|
ax.metric('live:card:open', {subject: profile.did, from: 'post'})
|
||||||
'live:card:open',
|
|
||||||
{subject: profile.did, from: 'post'},
|
|
||||||
{statsig: true},
|
|
||||||
)
|
|
||||||
liveControl.open()
|
liveControl.open()
|
||||||
}, [liveControl, playHaptic, profile.did])
|
}, [liveControl, playHaptic, profile.did])
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {useNavigation, useNavigationState} from '@react-navigation/native'
|
|||||||
|
|
||||||
import {getCurrentRoute} from '#/lib/routes/helpers'
|
import {getCurrentRoute} from '#/lib/routes/helpers'
|
||||||
import {type NavigationProp} from '#/lib/routes/types'
|
import {type NavigationProp} from '#/lib/routes/types'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {emitSoftReset} from '#/state/events'
|
import {emitSoftReset} from '#/state/events'
|
||||||
import {
|
import {
|
||||||
type SavedFeedSourceInfo,
|
type SavedFeedSourceInfo,
|
||||||
@@ -19,10 +18,12 @@ import {FilterTimeline_Stroke2_Corner0_Rounded as FilterTimeline} from '#/compon
|
|||||||
import {PlusSmall_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
|
import {PlusSmall_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
|
||||||
import {Link} from '#/components/Link'
|
import {Link} from '#/components/Link'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
export function DesktopFeeds() {
|
export function DesktopFeeds() {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const {data: pinnedFeedInfos, error, isLoading} = usePinnedFeedsInfos()
|
const {data: pinnedFeedInfos, error, isLoading} = usePinnedFeedsInfos()
|
||||||
const selectedFeed = useSelectedFeed()
|
const selectedFeed = useSelectedFeed()
|
||||||
const setSelectedFeed = useSetSelectedFeed()
|
const setSelectedFeed = useSetSelectedFeed()
|
||||||
@@ -86,14 +87,10 @@ export function DesktopFeeds() {
|
|||||||
feedInfo={feedInfo}
|
feedInfo={feedInfo}
|
||||||
current={current}
|
current={current}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric(
|
ax.metric('desktopFeeds:feed:click', {
|
||||||
'desktopFeeds:feed:click',
|
feedUri: feedInfo.uri,
|
||||||
{
|
feedDescriptor: feed,
|
||||||
feedUri: feedInfo.uri,
|
})
|
||||||
feedDescriptor: feed,
|
|
||||||
},
|
|
||||||
{statsig: false},
|
|
||||||
)
|
|
||||||
setSelectedFeed(feed)
|
setSelectedFeed(feed)
|
||||||
navigation.navigate('Home')
|
navigation.navigate('Home')
|
||||||
if (route.name === 'Home' && feed === selectedFeed) {
|
if (route.name === 'Home' && feed === selectedFeed) {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import {View} from 'react-native'
|
|||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {
|
import {
|
||||||
useTrendingSettings,
|
useTrendingSettings,
|
||||||
useTrendingSettingsApi,
|
useTrendingSettingsApi,
|
||||||
@@ -16,6 +15,7 @@ import {Trending3_Stroke2_Corner1_Rounded as TrendingIcon} from '#/components/ic
|
|||||||
import * as Prompt from '#/components/Prompt'
|
import * as Prompt from '#/components/Prompt'
|
||||||
import {TrendingTopicLink} from '#/components/TrendingTopics'
|
import {TrendingTopicLink} from '#/components/TrendingTopics'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useAnalytics} from '#/analytics'
|
||||||
|
|
||||||
const TRENDING_LIMIT = 5
|
const TRENDING_LIMIT = 5
|
||||||
|
|
||||||
@@ -28,13 +28,14 @@ export function SidebarTrendingTopics() {
|
|||||||
function Inner() {
|
function Inner() {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const ax = useAnalytics()
|
||||||
const trendingPrompt = Prompt.usePromptControl()
|
const trendingPrompt = Prompt.usePromptControl()
|
||||||
const {setTrendingDisabled} = useTrendingSettingsApi()
|
const {setTrendingDisabled} = useTrendingSettingsApi()
|
||||||
const {data: trending, error, isLoading} = useTrendingTopics()
|
const {data: trending, error, isLoading} = useTrendingTopics()
|
||||||
const noTopics = !isLoading && !error && !trending?.topics?.length
|
const noTopics = !isLoading && !error && !trending?.topics?.length
|
||||||
|
|
||||||
const onConfirmHide = () => {
|
const onConfirmHide = () => {
|
||||||
logger.metric('trendingTopics:hide', {context: 'sidebar'})
|
ax.metric('trendingTopics:hide', {context: 'sidebar'})
|
||||||
setTrendingDisabled(true)
|
setTrendingDisabled(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ function Inner() {
|
|||||||
topic={topic}
|
topic={topic}
|
||||||
style={[a.self_start]}
|
style={[a.self_start]}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
logger.metric('trendingTopic:click', {context: 'sidebar'})
|
ax.metric('trendingTopic:click', {context: 'sidebar'})
|
||||||
}}>
|
}}>
|
||||||
{({hovered}) => (
|
{({hovered}) => (
|
||||||
<View style={[a.flex_row, a.align_center, a.gap_xs]}>
|
<View style={[a.flex_row, a.align_center, a.gap_xs]}>
|
||||||
|
|||||||
Reference in New Issue
Block a user