add metrics
This commit is contained in:
@@ -72,11 +72,13 @@ let PostControls = ({
|
|||||||
const [queueLike, queueUnlike] = usePostLikeMutationQueue(
|
const [queueLike, queueUnlike] = usePostLikeMutationQueue(
|
||||||
post,
|
post,
|
||||||
viaRepost,
|
viaRepost,
|
||||||
|
feedContext,
|
||||||
logContext,
|
logContext,
|
||||||
)
|
)
|
||||||
const [queueRepost, queueUnrepost] = usePostRepostMutationQueue(
|
const [queueRepost, queueUnrepost] = usePostRepostMutationQueue(
|
||||||
post,
|
post,
|
||||||
viaRepost,
|
viaRepost,
|
||||||
|
feedContext,
|
||||||
logContext,
|
logContext,
|
||||||
)
|
)
|
||||||
const requireAuth = useRequireAuth()
|
const requireAuth = useRequireAuth()
|
||||||
|
|||||||
@@ -130,6 +130,27 @@ export type MetricEvents = {
|
|||||||
feedType: string
|
feedType: string
|
||||||
reason: 'pull-to-refresh' | 'soft-reset' | 'load-latest'
|
reason: 'pull-to-refresh' | 'soft-reset' | 'load-latest'
|
||||||
}
|
}
|
||||||
|
'feed:save': {
|
||||||
|
feedUrl: string
|
||||||
|
}
|
||||||
|
'feed:unsave': {
|
||||||
|
feedUrl: string
|
||||||
|
}
|
||||||
|
'feed:pin': {
|
||||||
|
feedUrl: string
|
||||||
|
}
|
||||||
|
'feed:unpin': {
|
||||||
|
feedUrl: string
|
||||||
|
}
|
||||||
|
'feed:like': {
|
||||||
|
feedUrl: string
|
||||||
|
}
|
||||||
|
'feed:unlike': {
|
||||||
|
feedUrl: string
|
||||||
|
}
|
||||||
|
'feed:share': {
|
||||||
|
feedUrl: string
|
||||||
|
}
|
||||||
'discover:showMore': {
|
'discover:showMore': {
|
||||||
feedContext: string
|
feedContext: string
|
||||||
}
|
}
|
||||||
@@ -175,15 +196,19 @@ export type MetricEvents = {
|
|||||||
likerClout: number | undefined
|
likerClout: number | undefined
|
||||||
postClout: number | undefined
|
postClout: number | undefined
|
||||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
|
feedContext?: string
|
||||||
}
|
}
|
||||||
'post:repost': {
|
'post:repost': {
|
||||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
|
feedContext?: string
|
||||||
}
|
}
|
||||||
'post:unlike': {
|
'post:unlike': {
|
||||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
|
feedContext?: string
|
||||||
}
|
}
|
||||||
'post:unrepost': {
|
'post:unrepost': {
|
||||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
|
feedContext?: string
|
||||||
}
|
}
|
||||||
'post:mute': {}
|
'post:mute': {}
|
||||||
'post:unmute': {}
|
'post:unmute': {}
|
||||||
|
|||||||
@@ -113,13 +113,14 @@ export function ProfileFeedHeader({info}: {info: FeedSourceFeedInfo}) {
|
|||||||
const isSaved = Boolean(savedFeedConfig)
|
const isSaved = Boolean(savedFeedConfig)
|
||||||
const isPinned = Boolean(savedFeedConfig?.pinned)
|
const isPinned = Boolean(savedFeedConfig?.pinned)
|
||||||
|
|
||||||
const onToggleSaved = React.useCallback(async () => {
|
const onToggleSaved = async () => {
|
||||||
try {
|
try {
|
||||||
playHaptic()
|
playHaptic()
|
||||||
|
|
||||||
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})
|
||||||
} else {
|
} else {
|
||||||
await addSavedFeeds([
|
await addSavedFeeds([
|
||||||
{
|
{
|
||||||
@@ -129,6 +130,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})
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Toast.show(
|
Toast.show(
|
||||||
@@ -139,9 +141,9 @@ export function ProfileFeedHeader({info}: {info: FeedSourceFeedInfo}) {
|
|||||||
)
|
)
|
||||||
logger.error('Failed to update feeds', {message: err})
|
logger.error('Failed to update feeds', {message: err})
|
||||||
}
|
}
|
||||||
}, [_, playHaptic, info, removeFeed, addSavedFeeds, savedFeedConfig])
|
}
|
||||||
|
|
||||||
const onTogglePinned = React.useCallback(async () => {
|
const onTogglePinned = async () => {
|
||||||
try {
|
try {
|
||||||
playHaptic()
|
playHaptic()
|
||||||
|
|
||||||
@@ -156,8 +158,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})
|
||||||
} 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})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await addSavedFeeds([
|
await addSavedFeeds([
|
||||||
@@ -168,12 +172,13 @@ 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})
|
||||||
}
|
}
|
||||||
} 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')
|
||||||
logger.error('Failed to toggle pinned feed', {message: e})
|
logger.error('Failed to toggle pinned feed', {message: e})
|
||||||
}
|
}
|
||||||
}, [playHaptic, info, _, savedFeedConfig, updateSavedFeeds, addSavedFeeds])
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -394,16 +399,18 @@ function DialogInner({
|
|||||||
const isLiked = !!likeUri
|
const isLiked = !!likeUri
|
||||||
const feedRkey = React.useMemo(() => new AtUri(info.uri).rkey, [info.uri])
|
const feedRkey = React.useMemo(() => new AtUri(info.uri).rkey, [info.uri])
|
||||||
|
|
||||||
const onToggleLiked = React.useCallback(async () => {
|
const onToggleLiked = async () => {
|
||||||
try {
|
try {
|
||||||
playHaptic()
|
playHaptic()
|
||||||
|
|
||||||
if (isLiked && likeUri) {
|
if (isLiked && likeUri) {
|
||||||
await unlikeFeed({uri: likeUri})
|
await unlikeFeed({uri: likeUri})
|
||||||
setLikeUri('')
|
setLikeUri('')
|
||||||
|
logger.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})
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Toast.show(
|
Toast.show(
|
||||||
@@ -414,12 +421,13 @@ function DialogInner({
|
|||||||
)
|
)
|
||||||
logger.error('Failed to toggle like', {message: err})
|
logger.error('Failed to toggle like', {message: err})
|
||||||
}
|
}
|
||||||
}, [playHaptic, isLiked, likeUri, unlikeFeed, setLikeUri, likeFeed, info, _])
|
}
|
||||||
|
|
||||||
const onPressShare = React.useCallback(() => {
|
const onPressShare = React.useCallback(() => {
|
||||||
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})
|
||||||
}, [info, playHaptic])
|
}, [info, playHaptic])
|
||||||
|
|
||||||
const onPressReport = React.useCallback(() => {
|
const onPressReport = React.useCallback(() => {
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ export function ExploreTrendingVideos() {
|
|||||||
label={_(msg`Pin`)}
|
label={_(msg`Pin`)}
|
||||||
size="small"
|
size="small"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
color="secondary"
|
color="secondary
|
||||||
onPress={pinFeed}>
|
onPress={pinFeed}>
|
||||||
<ButtonText>{_(msg`Pin`)}</ButtonText>
|
<ButtonText>{_(msg`Pin`)}</ButtonText>
|
||||||
<ButtonIcon icon={Pin} position="right" />
|
<ButtonIcon icon={Pin} position="right" />
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
|||||||
|
|
||||||
import {useToggleMutationQueue} from '#/lib/hooks/useToggleMutationQueue'
|
import {useToggleMutationQueue} from '#/lib/hooks/useToggleMutationQueue'
|
||||||
import {logEvent, type LogEvents, toClout} from '#/lib/statsig/statsig'
|
import {logEvent, type LogEvents, toClout} from '#/lib/statsig/statsig'
|
||||||
|
import {logger} from '#/logger'
|
||||||
import {updatePostShadow} from '#/state/cache/post-shadow'
|
import {updatePostShadow} from '#/state/cache/post-shadow'
|
||||||
import {type Shadow} from '#/state/cache/types'
|
import {type Shadow} from '#/state/cache/types'
|
||||||
import {useAgent, useSession} from '#/state/session'
|
import {useAgent, useSession} from '#/state/session'
|
||||||
@@ -99,6 +100,7 @@ export function useGetPosts() {
|
|||||||
export function usePostLikeMutationQueue(
|
export function usePostLikeMutationQueue(
|
||||||
post: Shadow<AppBskyFeedDefs.PostView>,
|
post: Shadow<AppBskyFeedDefs.PostView>,
|
||||||
viaRepost: {uri: string; cid: string} | undefined,
|
viaRepost: {uri: string; cid: string} | undefined,
|
||||||
|
feedContext: string | undefined,
|
||||||
logContext: LogEvents['post:like']['logContext'] &
|
logContext: LogEvents['post:like']['logContext'] &
|
||||||
LogEvents['post:unlike']['logContext'],
|
LogEvents['post:unlike']['logContext'],
|
||||||
) {
|
) {
|
||||||
@@ -106,8 +108,8 @@ export function usePostLikeMutationQueue(
|
|||||||
const postUri = post.uri
|
const postUri = post.uri
|
||||||
const postCid = post.cid
|
const postCid = post.cid
|
||||||
const initialLikeUri = post.viewer?.like
|
const initialLikeUri = post.viewer?.like
|
||||||
const likeMutation = usePostLikeMutation(logContext, post)
|
const likeMutation = usePostLikeMutation(feedContext, logContext, post)
|
||||||
const unlikeMutation = usePostUnlikeMutation(logContext)
|
const unlikeMutation = usePostUnlikeMutation(feedContext, logContext)
|
||||||
|
|
||||||
const queueToggle = useToggleMutationQueue({
|
const queueToggle = useToggleMutationQueue({
|
||||||
initialState: initialLikeUri,
|
initialState: initialLikeUri,
|
||||||
@@ -159,6 +161,7 @@ export function usePostLikeMutationQueue(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function usePostLikeMutation(
|
function usePostLikeMutation(
|
||||||
|
feedContext: string | undefined,
|
||||||
logContext: LogEvents['post:like']['logContext'],
|
logContext: LogEvents['post:like']['logContext'],
|
||||||
post: Shadow<AppBskyFeedDefs.PostView>,
|
post: Shadow<AppBskyFeedDefs.PostView>,
|
||||||
) {
|
) {
|
||||||
@@ -176,7 +179,7 @@ function usePostLikeMutation(
|
|||||||
if (currentAccount) {
|
if (currentAccount) {
|
||||||
ownProfile = findProfileQueryData(queryClient, currentAccount.did)
|
ownProfile = findProfileQueryData(queryClient, currentAccount.did)
|
||||||
}
|
}
|
||||||
logEvent('post:like', {
|
logger.metric('post:like', {
|
||||||
logContext,
|
logContext,
|
||||||
doesPosterFollowLiker: postAuthor.viewer
|
doesPosterFollowLiker: postAuthor.viewer
|
||||||
? Boolean(postAuthor.viewer.followedBy)
|
? Boolean(postAuthor.viewer.followedBy)
|
||||||
@@ -191,6 +194,7 @@ function usePostLikeMutation(
|
|||||||
post.replyCount != null
|
post.replyCount != null
|
||||||
? toClout(post.likeCount + post.repostCount + post.replyCount)
|
? toClout(post.likeCount + post.repostCount + post.replyCount)
|
||||||
: undefined,
|
: undefined,
|
||||||
|
feedContext: feedContext,
|
||||||
})
|
})
|
||||||
return agent.like(uri, cid, via)
|
return agent.like(uri, cid, via)
|
||||||
},
|
},
|
||||||
@@ -198,12 +202,13 @@ function usePostLikeMutation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function usePostUnlikeMutation(
|
function usePostUnlikeMutation(
|
||||||
|
feedContext: string | undefined,
|
||||||
logContext: LogEvents['post:unlike']['logContext'],
|
logContext: LogEvents['post:unlike']['logContext'],
|
||||||
) {
|
) {
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
return useMutation<void, Error, {postUri: string; likeUri: string}>({
|
return useMutation<void, Error, {postUri: string; likeUri: string}>({
|
||||||
mutationFn: ({likeUri}) => {
|
mutationFn: ({likeUri}) => {
|
||||||
logEvent('post:unlike', {logContext})
|
logger.metric('post:unlike', {logContext, feedContext: feedContext})
|
||||||
return agent.deleteLike(likeUri)
|
return agent.deleteLike(likeUri)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -212,6 +217,7 @@ function usePostUnlikeMutation(
|
|||||||
export function usePostRepostMutationQueue(
|
export function usePostRepostMutationQueue(
|
||||||
post: Shadow<AppBskyFeedDefs.PostView>,
|
post: Shadow<AppBskyFeedDefs.PostView>,
|
||||||
viaRepost: {uri: string; cid: string} | undefined,
|
viaRepost: {uri: string; cid: string} | undefined,
|
||||||
|
feedContext: string | undefined,
|
||||||
logContext: LogEvents['post:repost']['logContext'] &
|
logContext: LogEvents['post:repost']['logContext'] &
|
||||||
LogEvents['post:unrepost']['logContext'],
|
LogEvents['post:unrepost']['logContext'],
|
||||||
) {
|
) {
|
||||||
@@ -219,8 +225,8 @@ export function usePostRepostMutationQueue(
|
|||||||
const postUri = post.uri
|
const postUri = post.uri
|
||||||
const postCid = post.cid
|
const postCid = post.cid
|
||||||
const initialRepostUri = post.viewer?.repost
|
const initialRepostUri = post.viewer?.repost
|
||||||
const repostMutation = usePostRepostMutation(logContext)
|
const repostMutation = usePostRepostMutation(feedContext, logContext)
|
||||||
const unrepostMutation = usePostUnrepostMutation(logContext)
|
const unrepostMutation = usePostUnrepostMutation(feedContext, logContext)
|
||||||
|
|
||||||
const queueToggle = useToggleMutationQueue({
|
const queueToggle = useToggleMutationQueue({
|
||||||
initialState: initialRepostUri,
|
initialState: initialRepostUri,
|
||||||
@@ -270,6 +276,7 @@ export function usePostRepostMutationQueue(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function usePostRepostMutation(
|
function usePostRepostMutation(
|
||||||
|
feedContext: string | undefined,
|
||||||
logContext: LogEvents['post:repost']['logContext'],
|
logContext: LogEvents['post:repost']['logContext'],
|
||||||
) {
|
) {
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
@@ -279,19 +286,20 @@ function usePostRepostMutation(
|
|||||||
{uri: string; cid: string; via?: {uri: string; cid: string}} // the post's uri and cid, and the repost uri/cid if present
|
{uri: string; cid: string; via?: {uri: string; cid: string}} // the post's uri and cid, and the repost uri/cid if present
|
||||||
>({
|
>({
|
||||||
mutationFn: ({uri, cid, via}) => {
|
mutationFn: ({uri, cid, via}) => {
|
||||||
logEvent('post:repost', {logContext})
|
logEvent('post:repost', {logContext, feedContext: feedContext})
|
||||||
return agent.repost(uri, cid, via)
|
return agent.repost(uri, cid, via)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function usePostUnrepostMutation(
|
function usePostUnrepostMutation(
|
||||||
|
feedContext: string | undefined,
|
||||||
logContext: LogEvents['post:unrepost']['logContext'],
|
logContext: LogEvents['post:unrepost']['logContext'],
|
||||||
) {
|
) {
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
return useMutation<void, Error, {postUri: string; repostUri: string}>({
|
return useMutation<void, Error, {postUri: string; repostUri: string}>({
|
||||||
mutationFn: ({repostUri}) => {
|
mutationFn: ({repostUri}) => {
|
||||||
logEvent('post:unrepost', {logContext})
|
logEvent('post:unrepost', {logContext, feedContext: feedContext})
|
||||||
return agent.deleteRepost(repostUri)
|
return agent.deleteRepost(repostUri)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user