about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authordan <dan.abramov@gmail.com>2024-04-08 18:38:51 +0100
committerGitHub <noreply@github.com>2024-04-08 18:38:51 +0100
commit887fedabeaa3470615199642870494df2784b280 (patch)
tree0b702fe146e55bceae6b5e213887e565f23cd54a /src
parent8188f61e7dae70742f05d7a9535983dec8ddee8c (diff)
downloadvoidsky-887fedabeaa3470615199642870494df2784b280.tar.zst
[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
Diffstat (limited to 'src')
-rw-r--r--src/lib/statsig/events.ts7
-rw-r--r--src/lib/statsig/statsig.tsx8
-rw-r--r--src/state/queries/post.ts42
-rw-r--r--src/state/queries/profile.ts29
4 files changed, 75 insertions, 11 deletions
diff --git a/src/lib/statsig/events.ts b/src/lib/statsig/events.ts
index 98d633194..73e9876ac 100644
--- a/src/lib/statsig/events.ts
+++ b/src/lib/statsig/events.ts
@@ -67,6 +67,10 @@ export type LogEvents = {
     logContext: 'Composer'
   }
   'post:like': {
+    doesLikerFollowPoster: boolean | undefined
+    doesPosterFollowLiker: boolean | undefined
+    likerClout: number | undefined
+    postClout: number | undefined
     logContext: 'FeedItem' | 'PostThreadItem' | 'Post'
   }
   'post:repost': {
@@ -79,6 +83,9 @@ export type LogEvents = {
     logContext: 'FeedItem' | 'PostThreadItem' | 'Post'
   }
   'profile:follow': {
+    didBecomeMutual: boolean | undefined
+    followeeClout: number | undefined
+    followerClout: number | undefined
     logContext:
       | 'RecommendedFollowsItem'
       | 'PostThreadItem'
diff --git a/src/lib/statsig/statsig.tsx b/src/lib/statsig/statsig.tsx
index d0ef2408e..c16461621 100644
--- a/src/lib/statsig/statsig.tsx
+++ b/src/lib/statsig/statsig.tsx
@@ -43,6 +43,14 @@ export function attachRouteToLogEvents(
   getCurrentRouteName = getRouteName
 }
 
+export function toClout(n: number | null | undefined): number | undefined {
+  if (n == null) {
+    return undefined
+  } else {
+    return Math.max(0, Math.round(Math.log(n)))
+  }
+}
+
 export function logEvent<E extends keyof LogEvents>(
   eventName: E & string,
   rawMetadata: LogEvents[E] & FlatJSONRecord,
diff --git a/src/state/queries/post.ts b/src/state/queries/post.ts
index 746dedad2..77497f6ba 100644
--- a/src/state/queries/post.ts
+++ b/src/state/queries/post.ts
@@ -1,13 +1,14 @@
 import {useCallback} from 'react'
-import {AppBskyFeedDefs, AtUri} from '@atproto/api'
+import {AppBskyActorDefs, AppBskyFeedDefs, AtUri} from '@atproto/api'
 import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
 
 import {track} from '#/lib/analytics/analytics'
 import {useToggleMutationQueue} from '#/lib/hooks/useToggleMutationQueue'
-import {logEvent, LogEvents} from '#/lib/statsig/statsig'
+import {logEvent, LogEvents, toClout} from '#/lib/statsig/statsig'
 import {updatePostShadow} from '#/state/cache/post-shadow'
 import {Shadow} from '#/state/cache/types'
-import {getAgent} from '#/state/session'
+import {getAgent, useSession} from '#/state/session'
+import {findProfileQueryData} from './profile'
 
 const RQKEY_ROOT = 'post'
 export const RQKEY = (postUri: string) => [RQKEY_ROOT, postUri]
@@ -68,7 +69,7 @@ export function usePostLikeMutationQueue(
   const postUri = post.uri
   const postCid = post.cid
   const initialLikeUri = post.viewer?.like
-  const likeMutation = usePostLikeMutation(logContext)
+  const likeMutation = usePostLikeMutation(logContext, post)
   const unlikeMutation = usePostUnlikeMutation(logContext)
 
   const queueToggle = useToggleMutationQueue({
@@ -117,15 +118,40 @@ export function usePostLikeMutationQueue(
   return [queueLike, queueUnlike]
 }
 
-function usePostLikeMutation(logContext: LogEvents['post:like']['logContext']) {
+function usePostLikeMutation(
+  logContext: LogEvents['post:like']['logContext'],
+  post: Shadow<AppBskyFeedDefs.PostView>,
+) {
+  const {currentAccount} = useSession()
+  const queryClient = useQueryClient()
+  const postAuthor = post.author
   return useMutation<
     {uri: string}, // responds with the uri of the like
     Error,
     {uri: string; cid: string} // the post's uri and cid
   >({
-    mutationFn: post => {
-      logEvent('post:like', {logContext})
-      return getAgent().like(post.uri, post.cid)
+    mutationFn: ({uri, cid}) => {
+      let ownProfile: AppBskyActorDefs.ProfileViewDetailed | undefined
+      if (currentAccount) {
+        ownProfile = findProfileQueryData(queryClient, currentAccount.did)
+      }
+      logEvent('post:like', {
+        logContext,
+        doesPosterFollowLiker: postAuthor.viewer
+          ? Boolean(postAuthor.viewer.followedBy)
+          : undefined,
+        doesLikerFollowPoster: postAuthor.viewer
+          ? Boolean(postAuthor.viewer.following)
+          : undefined,
+        likerClout: toClout(ownProfile?.followersCount),
+        postClout:
+          post.likeCount != null &&
+          post.repostCount != null &&
+          post.replyCount != null
+            ? toClout(post.likeCount + post.repostCount + post.replyCount)
+            : undefined,
+      })
+      return getAgent().like(uri, cid)
     },
     onSuccess() {
       track('Post:Like')
diff --git a/src/state/queries/profile.ts b/src/state/queries/profile.ts
index 2094e0c3a..a962fecff 100644
--- a/src/state/queries/profile.ts
+++ b/src/state/queries/profile.ts
@@ -20,7 +20,7 @@ import {track} from '#/lib/analytics/analytics'
 import {uploadBlob} from '#/lib/api'
 import {until} from '#/lib/async/until'
 import {useToggleMutationQueue} from '#/lib/hooks/useToggleMutationQueue'
-import {logEvent, LogEvents} from '#/lib/statsig/statsig'
+import {logEvent, LogEvents, toClout} from '#/lib/statsig/statsig'
 import {Shadow} from '#/state/cache/types'
 import {STALE} from '#/state/queries'
 import {resetProfilePostsQueries} from '#/state/queries/post-feed'
@@ -202,7 +202,7 @@ export function useProfileFollowMutationQueue(
   const queryClient = useQueryClient()
   const did = profile.did
   const initialFollowingUri = profile.viewer?.following
-  const followMutation = useProfileFollowMutation(logContext)
+  const followMutation = useProfileFollowMutation(logContext, profile)
   const unfollowMutation = useProfileUnfollowMutation(logContext)
 
   const queueToggle = useToggleMutationQueue({
@@ -252,10 +252,24 @@ export function useProfileFollowMutationQueue(
 
 function useProfileFollowMutation(
   logContext: LogEvents['profile:follow']['logContext'],
+  profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>,
 ) {
+  const {currentAccount} = useSession()
+  const queryClient = useQueryClient()
   return useMutation<{uri: string; cid: string}, Error, {did: string}>({
     mutationFn: async ({did}) => {
-      logEvent('profile:follow', {logContext})
+      let ownProfile: AppBskyActorDefs.ProfileViewDetailed | undefined
+      if (currentAccount) {
+        ownProfile = findProfileQueryData(queryClient, currentAccount.did)
+      }
+      logEvent('profile:follow', {
+        logContext,
+        didBecomeMutual: profile.viewer
+          ? Boolean(profile.viewer.followedBy)
+          : undefined,
+        followeeClout: toClout(profile.followersCount),
+        followerClout: toClout(ownProfile?.followersCount),
+      })
       return await getAgent().follow(did)
     },
     onSuccess(data, variables) {
@@ -530,3 +544,12 @@ export function* findAllProfilesInQueryData(
     }
   }
 }
+
+export function findProfileQueryData(
+  queryClient: QueryClient,
+  did: string,
+): AppBskyActorDefs.ProfileViewDetailed | undefined {
+  return queryClient.getQueryData<AppBskyActorDefs.ProfileViewDetailed>(
+    RQKEY(did),
+  )
+}