Check Analytics (#2106)

* fix sign in event tracking

* add missing analytics events

* add more missing analytics

* fix like and unrepost event tracking

* reset onEndReachedThreshold
This commit is contained in:
Ansh 2023-12-06 11:45:01 -06:00 committed by GitHub
parent 7229cda5a5
commit 8e541d753a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 41 additions and 22 deletions

View file

@ -41,12 +41,6 @@ interface TrackPropertiesMap {
'Post:ThreadMute': {} // CAN BE SERVER 'Post:ThreadMute': {} // CAN BE SERVER
'Post:ThreadUnmute': {} // CAN BE SERVER 'Post:ThreadUnmute': {} // CAN BE SERVER
'Post:Reply': {} // CAN BE SERVER 'Post:Reply': {} // CAN BE SERVER
// FEED ITEM events
'FeedItem:PostReply': {} // CAN BE SERVER
'FeedItem:PostRepost': {} // CAN BE SERVER
'FeedItem:PostLike': {} // CAN BE SERVER
'FeedItem:PostDelete': {} // CAN BE SERVER
'FeedItem:ThreadMute': {} // CAN BE SERVER
// PROFILE events // PROFILE events
'Profile:Follow': { 'Profile:Follow': {
username: string username: string
@ -79,7 +73,6 @@ interface TrackPropertiesMap {
'Settings:AddAccountButtonClicked': {} 'Settings:AddAccountButtonClicked': {}
'Settings:ChangeHandleButtonClicked': {} 'Settings:ChangeHandleButtonClicked': {}
'Settings:InvitecodesButtonClicked': {} 'Settings:InvitecodesButtonClicked': {}
'Settings:ContentfilteringButtonClicked': {}
'Settings:SignOutButtonClicked': {} 'Settings:SignOutButtonClicked': {}
'Settings:ContentlanguagesButtonClicked': {} 'Settings:ContentlanguagesButtonClicked': {}
// MENU events // MENU events
@ -104,6 +97,8 @@ interface TrackPropertiesMap {
'Lists:Unmute': {} // CAN BE SERVER 'Lists:Unmute': {} // CAN BE SERVER
'Lists:Block': {} // CAN BE SERVER 'Lists:Block': {} // CAN BE SERVER
'Lists:Unblock': {} // CAN BE SERVER 'Lists:Unblock': {} // CAN BE SERVER
'Lists:Delete': {} // CAN BE SERVER
'Lists:Share': {} // CAN BE SERVER
// CUSTOM FEED events // CUSTOM FEED events
'CustomFeed:Save': {} 'CustomFeed:Save': {}
'CustomFeed:Unsave': {} 'CustomFeed:Unsave': {}
@ -134,6 +129,7 @@ interface TrackPropertiesMap {
'Onboarding:Skipped': {} 'Onboarding:Skipped': {}
'Onboarding:Reset': {} 'Onboarding:Reset': {}
'Onboarding:SuggestedFollowFollowed': {} 'Onboarding:SuggestedFollowFollowed': {}
'Onboarding:CustomFeedAdded': {}
} }
interface ScreenPropertiesMap { interface ScreenPropertiesMap {

View file

@ -1,5 +1,6 @@
import React from 'react' import React from 'react'
import * as persisted from '#/state/persisted' import * as persisted from '#/state/persisted'
import {track} from '#/lib/analytics/analytics'
type StateContext = persisted.Schema['mutedThreads'] type StateContext = persisted.Schema['mutedThreads']
type ToggleContext = (uri: string) => boolean type ToggleContext = (uri: string) => boolean
@ -19,9 +20,11 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
if (arr.includes(uri)) { if (arr.includes(uri)) {
arr = arr.filter(v => v !== uri) arr = arr.filter(v => v !== uri)
muted = false muted = false
track('Post:ThreadUnmute')
} else { } else {
arr = arr.concat([uri]) arr = arr.concat([uri])
muted = true muted = true
track('Post:ThreadMute')
} }
persisted.write('mutedThreads', arr) persisted.write('mutedThreads', arr)
return arr return arr

View file

@ -4,6 +4,7 @@ import {useQuery, useMutation, useQueryClient} from '@tanstack/react-query'
import {getAgent} from '#/state/session' import {getAgent} from '#/state/session'
import {updatePostShadow} from '#/state/cache/post-shadow' import {updatePostShadow} from '#/state/cache/post-shadow'
import {track} from '#/lib/analytics/analytics'
export const RQKEY = (postUri: string) => ['post', postUri] export const RQKEY = (postUri: string) => ['post', postUri]
@ -73,6 +74,7 @@ export function usePostLikeMutation() {
updatePostShadow(variables.uri, { updatePostShadow(variables.uri, {
likeUri: data.uri, likeUri: data.uri,
}) })
track('Post:Like')
}, },
onError(error, variables) { onError(error, variables) {
// revert the optimistic update // revert the optimistic update
@ -92,6 +94,7 @@ export function usePostUnlikeMutation() {
>({ >({
mutationFn: async ({likeUri}) => { mutationFn: async ({likeUri}) => {
await getAgent().deleteLike(likeUri) await getAgent().deleteLike(likeUri)
track('Post:Unlike')
}, },
onMutate(variables) { onMutate(variables) {
// optimistically update the post-shadow // optimistically update the post-shadow
@ -129,6 +132,7 @@ export function usePostRepostMutation() {
updatePostShadow(variables.uri, { updatePostShadow(variables.uri, {
repostUri: data.uri, repostUri: data.uri,
}) })
track('Post:Repost')
}, },
onError(error, variables) { onError(error, variables) {
// revert the optimistic update // revert the optimistic update
@ -148,6 +152,7 @@ export function usePostUnrepostMutation() {
>({ >({
mutationFn: async ({repostUri}) => { mutationFn: async ({repostUri}) => {
await getAgent().deleteRepost(repostUri) await getAgent().deleteRepost(repostUri)
track('Post:Unrepost')
}, },
onMutate(variables) { onMutate(variables) {
// optimistically update the post-shadow // optimistically update the post-shadow
@ -173,6 +178,7 @@ export function usePostDeleteMutation() {
}, },
onSuccess(data, variables) { onSuccess(data, variables) {
updatePostShadow(variables.uri, {isDeleted: true}) updatePostShadow(variables.uri, {isDeleted: true})
track('Post:Delete')
}, },
}) })
} }

View file

@ -21,6 +21,7 @@ import {useToggleMutationQueue} from '#/lib/hooks/useToggleMutationQueue'
import {RQKEY as RQKEY_MY_MUTED} from './my-muted-accounts' import {RQKEY as RQKEY_MY_MUTED} from './my-muted-accounts'
import {RQKEY as RQKEY_MY_BLOCKED} from './my-blocked-accounts' import {RQKEY as RQKEY_MY_BLOCKED} from './my-blocked-accounts'
import {STALE} from '#/state/queries' import {STALE} from '#/state/queries'
import {track} from '#/lib/analytics/analytics'
export const RQKEY = (did: string) => ['profile', did] export const RQKEY = (did: string) => ['profile', did]
@ -188,6 +189,7 @@ function useProfileFollowMutation() {
updateProfileShadow(variables.did, { updateProfileShadow(variables.did, {
followingUri: data.uri, followingUri: data.uri,
}) })
track('Profile:Follow', {username: variables.did})
} }
}, },
onError(error, variables) { onError(error, variables) {
@ -208,6 +210,7 @@ function useProfileUnfollowMutation() {
{did: string; followUri: string; skipOptimistic?: boolean} {did: string; followUri: string; skipOptimistic?: boolean}
>({ >({
mutationFn: async ({followUri}) => { mutationFn: async ({followUri}) => {
track('Profile:Unfollow', {username: followUri})
return await getAgent().deleteFollow(followUri) return await getAgent().deleteFollow(followUri)
}, },
onMutate(variables) { onMutate(variables) {

View file

@ -10,6 +10,7 @@ import {IS_PROD} from '#/lib/constants'
import {emitSessionLoaded, emitSessionDropped} from '../events' import {emitSessionLoaded, emitSessionDropped} from '../events'
import {useLoggedOutViewControls} from '#/state/shell/logged-out' import {useLoggedOutViewControls} from '#/state/shell/logged-out'
import {useCloseAllActiveElements} from '#/state/util' import {useCloseAllActiveElements} from '#/state/util'
import {track} from '#/lib/analytics/analytics'
let __globalAgent: BskyAgent = PUBLIC_BSKY_AGENT let __globalAgent: BskyAgent = PUBLIC_BSKY_AGENT
@ -270,6 +271,8 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
}, },
logger.DebugContext.session, logger.DebugContext.session,
) )
track('Sign In', {resumedSession: false})
}, },
[upsertAccount, queryClient], [upsertAccount, queryClient],
) )

View file

@ -120,8 +120,6 @@ export const LoginForm = ({
} else { } else {
setError(cleanError(errMsg)) setError(cleanError(errMsg))
} }
} finally {
track('Sign In', {resumedSession: false})
} }
} }

View file

@ -17,6 +17,7 @@ import {
useRemoveFeedMutation, useRemoveFeedMutation,
} from '#/state/queries/preferences' } from '#/state/queries/preferences'
import {logger} from '#/logger' import {logger} from '#/logger'
import {useAnalytics} from '#/lib/analytics/analytics'
export function RecommendedFeedsItem({ export function RecommendedFeedsItem({
item, item,
@ -36,6 +37,7 @@ export function RecommendedFeedsItem({
variables: removedFeed, variables: removedFeed,
reset: resetRemoveFeed, reset: resetRemoveFeed,
} = useRemoveFeedMutation() } = useRemoveFeedMutation()
const {track} = useAnalytics()
if (!item || !preferences) return null if (!item || !preferences) return null
@ -56,6 +58,7 @@ export function RecommendedFeedsItem({
try { try {
await pinFeed({uri: item.uri}) await pinFeed({uri: item.uri})
resetPinFeed() resetPinFeed()
track('Onboarding:CustomFeedAdded')
} catch (e) { } catch (e) {
Toast.show('There was an issue contacting your server') Toast.show('There was an issue contacting your server')
logger.error('Failed to pin feed', {error: e}) logger.error('Failed to pin feed', {error: e})

View file

@ -294,7 +294,7 @@ let Feed = ({
scrollEventThrottle={scrollEventThrottle} scrollEventThrottle={scrollEventThrottle}
indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'} indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'}
onEndReached={onEndReached} onEndReached={onEndReached}
onEndReachedThreshold={2} onEndReachedThreshold={2} // number of posts left to trigger load more
removeClippedSubviews={true} removeClippedSubviews={true}
contentOffset={{x: 0, y: headerOffset * -1}} contentOffset={{x: 0, y: headerOffset * -1}}
extraData={extraData} extraData={extraData}

View file

@ -25,7 +25,6 @@ import {PostSandboxWarning} from '../util/PostSandboxWarning'
import {PreviewableUserAvatar} from '../util/UserAvatar' import {PreviewableUserAvatar} from '../util/UserAvatar'
import {s} from 'lib/styles' import {s} from 'lib/styles'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {useAnalytics} from 'lib/analytics/analytics'
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 {makeProfileLink} from 'lib/routes/links' import {makeProfileLink} from 'lib/routes/links'
@ -102,7 +101,6 @@ let FeedItemInner = ({
}): React.ReactNode => { }): React.ReactNode => {
const {openComposer} = useComposerControls() const {openComposer} = useComposerControls()
const pal = usePalette('default') const pal = usePalette('default')
const {track} = useAnalytics()
const [limitLines, setLimitLines] = useState( const [limitLines, setLimitLines] = useState(
() => countLines(richText.text) >= MAX_POST_LINES, () => countLines(richText.text) >= MAX_POST_LINES,
) )
@ -121,7 +119,6 @@ let FeedItemInner = ({
}, [record?.reply]) }, [record?.reply])
const onPressReply = React.useCallback(() => { const onPressReply = React.useCallback(() => {
track('FeedItem:PostReply')
openComposer({ openComposer({
replyTo: { replyTo: {
uri: post.uri, uri: post.uri,
@ -134,7 +131,7 @@ let FeedItemInner = ({
}, },
}, },
}) })
}, [post, record, track, openComposer]) }, [post, record, openComposer])
const onPressShowMore = React.useCallback(() => { const onPressShowMore = React.useCallback(() => {
setLimitLines(false) setLimitLines(false)

View file

@ -571,7 +571,7 @@ function AboutSection({
const scrollHandler = useAnimatedScrollHandler(onScroll) const scrollHandler = useAnimatedScrollHandler(onScroll)
const [likeUri, setLikeUri] = React.useState(feedInfo.likeUri) const [likeUri, setLikeUri] = React.useState(feedInfo.likeUri)
const {hasSession} = useSession() const {hasSession} = useSession()
const {track} = useAnalytics()
const {mutateAsync: likeFeed, isPending: isLikePending} = useLikeMutation() const {mutateAsync: likeFeed, isPending: isLikePending} = useLikeMutation()
const {mutateAsync: unlikeFeed, isPending: isUnlikePending} = const {mutateAsync: unlikeFeed, isPending: isUnlikePending} =
useUnlikeMutation() useUnlikeMutation()
@ -586,9 +586,11 @@ function AboutSection({
if (isLiked && likeUri) { if (isLiked && likeUri) {
await unlikeFeed({uri: likeUri}) await unlikeFeed({uri: likeUri})
track('CustomFeed:Unlike')
setLikeUri('') setLikeUri('')
} else { } else {
const res = await likeFeed({uri: feedInfo.uri, cid: feedInfo.cid}) const res = await likeFeed({uri: feedInfo.uri, cid: feedInfo.cid})
track('CustomFeed:Like')
setLikeUri(res.uri) setLikeUri(res.uri)
} }
} catch (err) { } catch (err) {
@ -597,7 +599,7 @@ function AboutSection({
) )
logger.error('Failed up toggle like', {error: err}) logger.error('Failed up toggle like', {error: err})
} }
}, [likeUri, isLiked, feedInfo, likeFeed, unlikeFeed]) }, [likeUri, isLiked, feedInfo, likeFeed, unlikeFeed, track])
return ( return (
<ScrollView <ScrollView

View file

@ -62,6 +62,7 @@ import {
useUnpinFeedMutation, useUnpinFeedMutation,
} from '#/state/queries/preferences' } from '#/state/queries/preferences'
import {logger} from '#/logger' import {logger} from '#/logger'
import {useAnalytics} from '#/lib/analytics/analytics'
const SECTION_TITLES_CURATE = ['Posts', 'About'] const SECTION_TITLES_CURATE = ['Posts', 'About']
const SECTION_TITLES_MOD = ['About'] const SECTION_TITLES_MOD = ['About']
@ -267,6 +268,7 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
useUnpinFeedMutation() useUnpinFeedMutation()
const isPending = isPinPending || isUnpinPending const isPending = isPinPending || isUnpinPending
const {data: preferences} = usePreferencesQuery() const {data: preferences} = usePreferencesQuery()
const {track} = useAnalytics()
const isPinned = preferences?.feeds?.pinned?.includes(list.uri) const isPinned = preferences?.feeds?.pinned?.includes(list.uri)
@ -297,6 +299,7 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
try { try {
await listMuteMutation.mutateAsync({uri: list.uri, mute: true}) await listMuteMutation.mutateAsync({uri: list.uri, mute: true})
Toast.show('List muted') Toast.show('List muted')
track('Lists:Mute')
} catch { } catch {
Toast.show( Toast.show(
'There was an issue. Please check your internet connection and try again.', 'There was an issue. Please check your internet connection and try again.',
@ -307,18 +310,19 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
closeModal() closeModal()
}, },
}) })
}, [openModal, closeModal, list, listMuteMutation, _]) }, [openModal, closeModal, list, listMuteMutation, track, _])
const onUnsubscribeMute = useCallback(async () => { const onUnsubscribeMute = useCallback(async () => {
try { try {
await listMuteMutation.mutateAsync({uri: list.uri, mute: false}) await listMuteMutation.mutateAsync({uri: list.uri, mute: false})
Toast.show('List unmuted') Toast.show('List unmuted')
track('Lists:Unmute')
} catch { } catch {
Toast.show( Toast.show(
'There was an issue. Please check your internet connection and try again.', 'There was an issue. Please check your internet connection and try again.',
) )
} }
}, [list, listMuteMutation]) }, [list, listMuteMutation, track])
const onSubscribeBlock = useCallback(() => { const onSubscribeBlock = useCallback(() => {
openModal({ openModal({
@ -332,6 +336,7 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
try { try {
await listBlockMutation.mutateAsync({uri: list.uri, block: true}) await listBlockMutation.mutateAsync({uri: list.uri, block: true})
Toast.show('List blocked') Toast.show('List blocked')
track('Lists:Block')
} catch { } catch {
Toast.show( Toast.show(
'There was an issue. Please check your internet connection and try again.', 'There was an issue. Please check your internet connection and try again.',
@ -342,18 +347,19 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
closeModal() closeModal()
}, },
}) })
}, [openModal, closeModal, list, listBlockMutation, _]) }, [openModal, closeModal, list, listBlockMutation, track, _])
const onUnsubscribeBlock = useCallback(async () => { const onUnsubscribeBlock = useCallback(async () => {
try { try {
await listBlockMutation.mutateAsync({uri: list.uri, block: false}) await listBlockMutation.mutateAsync({uri: list.uri, block: false})
Toast.show('List unblocked') Toast.show('List unblocked')
track('Lists:Unblock')
} catch { } catch {
Toast.show( Toast.show(
'There was an issue. Please check your internet connection and try again.', 'There was an issue. Please check your internet connection and try again.',
) )
} }
}, [list, listBlockMutation]) }, [list, listBlockMutation, track])
const onPressEdit = useCallback(() => { const onPressEdit = useCallback(() => {
openModal({ openModal({
@ -370,6 +376,7 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
async onPressConfirm() { async onPressConfirm() {
await listDeleteMutation.mutateAsync({uri: list.uri}) await listDeleteMutation.mutateAsync({uri: list.uri})
Toast.show('List deleted') Toast.show('List deleted')
track('Lists:Delete')
if (navigation.canGoBack()) { if (navigation.canGoBack()) {
navigation.goBack() navigation.goBack()
} else { } else {
@ -377,7 +384,7 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
} }
}, },
}) })
}, [openModal, list, listDeleteMutation, navigation, _]) }, [openModal, list, listDeleteMutation, navigation, track, _])
const onPressReport = useCallback(() => { const onPressReport = useCallback(() => {
openModal({ openModal({
@ -390,7 +397,8 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
const onPressShare = useCallback(() => { const onPressShare = useCallback(() => {
const url = toShareUrl(`/profile/${list.creator.did}/lists/${rkey}`) const url = toShareUrl(`/profile/${list.creator.did}/lists/${rkey}`)
shareUrl(url) shareUrl(url)
}, [list, rkey]) track('Lists:Share')
}, [list, rkey, track])
const dropdownItems: DropdownItem[] = useMemo(() => { const dropdownItems: DropdownItem[] = useMemo(() => {
let items: DropdownItem[] = [ let items: DropdownItem[] = [