mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

[Statsig] Track like/follow metadata (#3435)

* Track becoming mutuals

* Track poster/liker status

* Track post and followee clout

* Track follower and liker clout

* Extract utility

authored by danabra.mov and committed by

GitHub 887fedab 8188f61e

+75 -11
+7
src/lib/statsig/events.ts
··· 67 67 logContext: 'Composer' 68 68 } 69 69 'post:like': { 70 + doesLikerFollowPoster: boolean | undefined 71 + doesPosterFollowLiker: boolean | undefined 72 + likerClout: number | undefined 73 + postClout: number | undefined 70 74 logContext: 'FeedItem' | 'PostThreadItem' | 'Post' 71 75 } 72 76 'post:repost': { ··· 79 83 logContext: 'FeedItem' | 'PostThreadItem' | 'Post' 80 84 } 81 85 'profile:follow': { 86 + didBecomeMutual: boolean | undefined 87 + followeeClout: number | undefined 88 + followerClout: number | undefined 82 89 logContext: 83 90 | 'RecommendedFollowsItem' 84 91 | 'PostThreadItem'
+8
src/lib/statsig/statsig.tsx
··· 43 43 getCurrentRouteName = getRouteName 44 44 } 45 45 46 + export function toClout(n: number | null | undefined): number | undefined { 47 + if (n == null) { 48 + return undefined 49 + } else { 50 + return Math.max(0, Math.round(Math.log(n))) 51 + } 52 + } 53 + 46 54 export function logEvent<E extends keyof LogEvents>( 47 55 eventName: E & string, 48 56 rawMetadata: LogEvents[E] & FlatJSONRecord,
+34 -8
src/state/queries/post.ts
··· 1 1 import {useCallback} from 'react' 2 - import {AppBskyFeedDefs, AtUri} from '@atproto/api' 2 + import {AppBskyActorDefs, AppBskyFeedDefs, AtUri} from '@atproto/api' 3 3 import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query' 4 4 5 5 import {track} from '#/lib/analytics/analytics' 6 6 import {useToggleMutationQueue} from '#/lib/hooks/useToggleMutationQueue' 7 - import {logEvent, LogEvents} from '#/lib/statsig/statsig' 7 + import {logEvent, LogEvents, toClout} from '#/lib/statsig/statsig' 8 8 import {updatePostShadow} from '#/state/cache/post-shadow' 9 9 import {Shadow} from '#/state/cache/types' 10 - import {getAgent} from '#/state/session' 10 + import {getAgent, useSession} from '#/state/session' 11 + import {findProfileQueryData} from './profile' 11 12 12 13 const RQKEY_ROOT = 'post' 13 14 export const RQKEY = (postUri: string) => [RQKEY_ROOT, postUri] ··· 68 69 const postUri = post.uri 69 70 const postCid = post.cid 70 71 const initialLikeUri = post.viewer?.like 71 - const likeMutation = usePostLikeMutation(logContext) 72 + const likeMutation = usePostLikeMutation(logContext, post) 72 73 const unlikeMutation = usePostUnlikeMutation(logContext) 73 74 74 75 const queueToggle = useToggleMutationQueue({ ··· 117 118 return [queueLike, queueUnlike] 118 119 } 119 120 120 - function usePostLikeMutation(logContext: LogEvents['post:like']['logContext']) { 121 + function usePostLikeMutation( 122 + logContext: LogEvents['post:like']['logContext'], 123 + post: Shadow<AppBskyFeedDefs.PostView>, 124 + ) { 125 + const {currentAccount} = useSession() 126 + const queryClient = useQueryClient() 127 + const postAuthor = post.author 121 128 return useMutation< 122 129 {uri: string}, // responds with the uri of the like 123 130 Error, 124 131 {uri: string; cid: string} // the post's uri and cid 125 132 >({ 126 - mutationFn: post => { 127 - logEvent('post:like', {logContext}) 128 - return getAgent().like(post.uri, post.cid) 133 + mutationFn: ({uri, cid}) => { 134 + let ownProfile: AppBskyActorDefs.ProfileViewDetailed | undefined 135 + if (currentAccount) { 136 + ownProfile = findProfileQueryData(queryClient, currentAccount.did) 137 + } 138 + logEvent('post:like', { 139 + logContext, 140 + doesPosterFollowLiker: postAuthor.viewer 141 + ? Boolean(postAuthor.viewer.followedBy) 142 + : undefined, 143 + doesLikerFollowPoster: postAuthor.viewer 144 + ? Boolean(postAuthor.viewer.following) 145 + : undefined, 146 + likerClout: toClout(ownProfile?.followersCount), 147 + postClout: 148 + post.likeCount != null && 149 + post.repostCount != null && 150 + post.replyCount != null 151 + ? toClout(post.likeCount + post.repostCount + post.replyCount) 152 + : undefined, 153 + }) 154 + return getAgent().like(uri, cid) 129 155 }, 130 156 onSuccess() { 131 157 track('Post:Like')
+26 -3
src/state/queries/profile.ts
··· 20 20 import {uploadBlob} from '#/lib/api' 21 21 import {until} from '#/lib/async/until' 22 22 import {useToggleMutationQueue} from '#/lib/hooks/useToggleMutationQueue' 23 - import {logEvent, LogEvents} from '#/lib/statsig/statsig' 23 + import {logEvent, LogEvents, toClout} from '#/lib/statsig/statsig' 24 24 import {Shadow} from '#/state/cache/types' 25 25 import {STALE} from '#/state/queries' 26 26 import {resetProfilePostsQueries} from '#/state/queries/post-feed' ··· 202 202 const queryClient = useQueryClient() 203 203 const did = profile.did 204 204 const initialFollowingUri = profile.viewer?.following 205 - const followMutation = useProfileFollowMutation(logContext) 205 + const followMutation = useProfileFollowMutation(logContext, profile) 206 206 const unfollowMutation = useProfileUnfollowMutation(logContext) 207 207 208 208 const queueToggle = useToggleMutationQueue({ ··· 252 252 253 253 function useProfileFollowMutation( 254 254 logContext: LogEvents['profile:follow']['logContext'], 255 + profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>, 255 256 ) { 257 + const {currentAccount} = useSession() 258 + const queryClient = useQueryClient() 256 259 return useMutation<{uri: string; cid: string}, Error, {did: string}>({ 257 260 mutationFn: async ({did}) => { 258 - logEvent('profile:follow', {logContext}) 261 + let ownProfile: AppBskyActorDefs.ProfileViewDetailed | undefined 262 + if (currentAccount) { 263 + ownProfile = findProfileQueryData(queryClient, currentAccount.did) 264 + } 265 + logEvent('profile:follow', { 266 + logContext, 267 + didBecomeMutual: profile.viewer 268 + ? Boolean(profile.viewer.followedBy) 269 + : undefined, 270 + followeeClout: toClout(profile.followersCount), 271 + followerClout: toClout(ownProfile?.followersCount), 272 + }) 259 273 return await getAgent().follow(did) 260 274 }, 261 275 onSuccess(data, variables) { ··· 530 544 } 531 545 } 532 546 } 547 + 548 + export function findProfileQueryData( 549 + queryClient: QueryClient, 550 + did: string, 551 + ): AppBskyActorDefs.ProfileViewDetailed | undefined { 552 + return queryClient.getQueryData<AppBskyActorDefs.ProfileViewDetailed>( 553 + RQKEY(did), 554 + ) 555 + }