about summary refs log tree commit diff
path: root/src/view/com/posts
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com/posts')
-rw-r--r--src/view/com/posts/Feed.tsx3
-rw-r--r--src/view/com/posts/FeedItem.tsx61
-rw-r--r--src/view/com/posts/FeedSlice.tsx15
3 files changed, 70 insertions, 9 deletions
diff --git a/src/view/com/posts/Feed.tsx b/src/view/com/posts/Feed.tsx
index fb67d35c5..8969f7cd2 100644
--- a/src/view/com/posts/Feed.tsx
+++ b/src/view/com/posts/Feed.tsx
@@ -17,6 +17,7 @@ import {logEvent} from '#/lib/statsig/statsig'
 import {logger} from '#/logger'
 import {isWeb} from '#/platform/detection'
 import {listenPostCreated} from '#/state/events'
+import {useFeedFeedbackContext} from '#/state/feed-feedback'
 import {STALE} from '#/state/queries'
 import {
   FeedDescriptor,
@@ -88,6 +89,7 @@ let Feed = ({
   const queryClient = useQueryClient()
   const {currentAccount} = useSession()
   const initialNumToRender = useInitialNumToRender()
+  const feedFeedback = useFeedFeedbackContext()
   const [isPTRing, setIsPTRing] = React.useState(false)
   const checkForNewRef = React.useRef<(() => void) | null>(null)
   const lastFetchRef = React.useRef<number>(Date.now())
@@ -353,6 +355,7 @@ let Feed = ({
         }
         initialNumToRender={initialNumToRender}
         windowSize={11}
+        onItemSeen={feedFeedback.onItemSeen}
       />
     </View>
   )
diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx
index 605dffde9..5b4efe2af 100644
--- a/src/view/com/posts/FeedItem.tsx
+++ b/src/view/com/posts/FeedItem.tsx
@@ -16,6 +16,7 @@ import {useLingui} from '@lingui/react'
 import {useQueryClient} from '@tanstack/react-query'
 
 import {POST_TOMBSTONE, Shadow, usePostShadow} from '#/state/cache/post-shadow'
+import {useFeedFeedbackContext} from '#/state/feed-feedback'
 import {useComposerControls} from '#/state/shell/composer'
 import {isReasonFeedSource, ReasonFeedSource} from 'lib/api/feed/types'
 import {MAX_POST_LINES} from 'lib/constants'
@@ -45,6 +46,7 @@ export function FeedItem({
   post,
   record,
   reason,
+  feedContext,
   moderation,
   isThreadChild,
   isThreadLastChild,
@@ -53,6 +55,7 @@ export function FeedItem({
   post: AppBskyFeedDefs.PostView
   record: AppBskyFeedPost.Record
   reason: AppBskyFeedDefs.ReasonRepost | ReasonFeedSource | undefined
+  feedContext: string | undefined
   moderation: ModerationDecision
   isThreadChild?: boolean
   isThreadLastChild?: boolean
@@ -78,6 +81,7 @@ export function FeedItem({
         post={postShadowed}
         record={record}
         reason={reason}
+        feedContext={feedContext}
         richText={richText}
         moderation={moderation}
         isThreadChild={isThreadChild}
@@ -93,6 +97,7 @@ let FeedItemInner = ({
   post,
   record,
   reason,
+  feedContext,
   richText,
   moderation,
   isThreadChild,
@@ -102,6 +107,7 @@ let FeedItemInner = ({
   post: Shadow<AppBskyFeedDefs.PostView>
   record: AppBskyFeedPost.Record
   reason: AppBskyFeedDefs.ReasonRepost | ReasonFeedSource | undefined
+  feedContext: string | undefined
   richText: RichTextAPI
   moderation: ModerationDecision
   isThreadChild?: boolean
@@ -116,6 +122,7 @@ let FeedItemInner = ({
     const urip = new AtUri(post.uri)
     return makeProfileLink(post.author, 'post', urip.rkey)
   }, [post.uri, post.author])
+  const {sendInteraction} = useFeedFeedbackContext()
 
   const replyAuthorDid = useMemo(() => {
     if (!record?.reply) {
@@ -126,6 +133,11 @@ let FeedItemInner = ({
   }, [record?.reply])
 
   const onPressReply = React.useCallback(() => {
+    sendInteraction({
+      item: post.uri,
+      event: 'app.bsky.feed.defs#interactionReply',
+      feedContext,
+    })
     openComposer({
       replyTo: {
         uri: post.uri,
@@ -136,11 +148,40 @@ let FeedItemInner = ({
         moderation,
       },
     })
-  }, [post, record, openComposer, moderation])
+  }, [post, record, openComposer, moderation, sendInteraction, feedContext])
+
+  const onOpenAuthor = React.useCallback(() => {
+    sendInteraction({
+      item: post.uri,
+      event: 'app.bsky.feed.defs#clickthroughAuthor',
+      feedContext,
+    })
+  }, [sendInteraction, post, feedContext])
+
+  const onOpenReposter = React.useCallback(() => {
+    sendInteraction({
+      item: post.uri,
+      event: 'app.bsky.feed.defs#clickthroughReposter',
+      feedContext,
+    })
+  }, [sendInteraction, post, feedContext])
+
+  const onOpenEmbed = React.useCallback(() => {
+    sendInteraction({
+      item: post.uri,
+      event: 'app.bsky.feed.defs#clickthroughEmbed',
+      feedContext,
+    })
+  }, [sendInteraction, post, feedContext])
 
   const onBeforePress = React.useCallback(() => {
+    sendInteraction({
+      item: post.uri,
+      event: 'app.bsky.feed.defs#clickthroughItem',
+      feedContext,
+    })
     precacheProfile(queryClient, post.author)
-  }, [queryClient, post.author])
+  }, [queryClient, post, sendInteraction, feedContext])
 
   const outerStyles = [
     styles.outer,
@@ -207,7 +248,8 @@ let FeedItemInner = ({
                 msg`Reposted by ${sanitizeDisplayName(
                   reason.by.displayName || reason.by.handle,
                 )}`,
-              )}>
+              )}
+              onBeforePress={onOpenReposter}>
               <FontAwesomeIcon
                 icon="retweet"
                 style={{
@@ -235,6 +277,7 @@ let FeedItemInner = ({
                         moderation.ui('displayName'),
                       )}
                       href={makeProfileLink(reason.by)}
+                      onBeforePress={onOpenReposter}
                     />
                   </ProfileHoverCard>
                 </Trans>
@@ -251,6 +294,7 @@ let FeedItemInner = ({
             profile={post.author}
             moderation={moderation.ui('avatar')}
             type={post.author.associated?.labeler ? 'labeler' : 'user'}
+            onBeforePress={onOpenAuthor}
           />
           {isThreadParent && (
             <View
@@ -272,6 +316,7 @@ let FeedItemInner = ({
             authorHasWarning={!!post.author.labels?.length}
             timestamp={post.indexedAt}
             postHref={href}
+            onOpenAuthor={onOpenAuthor}
           />
           {!isThreadChild && replyAuthorDid !== '' && (
             <View style={[s.flexRow, s.mb2, s.alignCenter]}>
@@ -308,6 +353,7 @@ let FeedItemInner = ({
             richText={richText}
             postEmbed={post.embed}
             postAuthor={post.author}
+            onOpenEmbed={onOpenEmbed}
           />
           <PostCtrls
             post={post}
@@ -315,6 +361,7 @@ let FeedItemInner = ({
             richText={richText}
             onPressReply={onPressReply}
             logContext="FeedItem"
+            feedContext={feedContext}
           />
         </View>
       </View>
@@ -328,11 +375,13 @@ let PostContent = ({
   richText,
   postEmbed,
   postAuthor,
+  onOpenEmbed,
 }: {
   moderation: ModerationDecision
   richText: RichTextAPI
   postEmbed: AppBskyFeedDefs.PostView['embed']
   postAuthor: AppBskyFeedDefs.PostView['author']
+  onOpenEmbed: () => void
 }): React.ReactNode => {
   const pal = usePalette('default')
   const {_} = useLingui()
@@ -373,7 +422,11 @@ let PostContent = ({
       ) : undefined}
       {postEmbed ? (
         <View style={[a.pb_sm]}>
-          <PostEmbeds embed={postEmbed} moderation={moderation} />
+          <PostEmbeds
+            embed={postEmbed}
+            moderation={moderation}
+            onOpen={onOpenEmbed}
+          />
         </View>
       ) : null}
     </ContentHider>
diff --git a/src/view/com/posts/FeedSlice.tsx b/src/view/com/posts/FeedSlice.tsx
index 49e48aa20..27a9ff8c0 100644
--- a/src/view/com/posts/FeedSlice.tsx
+++ b/src/view/com/posts/FeedSlice.tsx
@@ -1,14 +1,15 @@
 import React, {memo} from 'react'
 import {StyleSheet, View} from 'react-native'
-import {FeedPostSlice} from '#/state/queries/post-feed'
+import Svg, {Circle, Line} from 'react-native-svg'
 import {AtUri} from '@atproto/api'
+import {Trans} from '@lingui/macro'
+
+import {FeedPostSlice} from '#/state/queries/post-feed'
+import {usePalette} from 'lib/hooks/usePalette'
+import {makeProfileLink} from 'lib/routes/links'
 import {Link} from '../util/Link'
 import {Text} from '../util/text/Text'
-import Svg, {Circle, Line} from 'react-native-svg'
 import {FeedItem} from './FeedItem'
-import {usePalette} from 'lib/hooks/usePalette'
-import {makeProfileLink} from 'lib/routes/links'
-import {Trans} from '@lingui/macro'
 
 let FeedSlice = ({slice}: {slice: FeedPostSlice}): React.ReactNode => {
   if (slice.isThread && slice.items.length > 3) {
@@ -20,6 +21,7 @@ let FeedSlice = ({slice}: {slice: FeedPostSlice}): React.ReactNode => {
           post={slice.items[0].post}
           record={slice.items[0].record}
           reason={slice.items[0].reason}
+          feedContext={slice.items[0].feedContext}
           moderation={slice.items[0].moderation}
           isThreadParent={isThreadParentAt(slice.items, 0)}
           isThreadChild={isThreadChildAt(slice.items, 0)}
@@ -29,6 +31,7 @@ let FeedSlice = ({slice}: {slice: FeedPostSlice}): React.ReactNode => {
           post={slice.items[1].post}
           record={slice.items[1].record}
           reason={slice.items[1].reason}
+          feedContext={slice.items[1].feedContext}
           moderation={slice.items[1].moderation}
           isThreadParent={isThreadParentAt(slice.items, 1)}
           isThreadChild={isThreadChildAt(slice.items, 1)}
@@ -39,6 +42,7 @@ let FeedSlice = ({slice}: {slice: FeedPostSlice}): React.ReactNode => {
           post={slice.items[last].post}
           record={slice.items[last].record}
           reason={slice.items[last].reason}
+          feedContext={slice.items[last].feedContext}
           moderation={slice.items[last].moderation}
           isThreadParent={isThreadParentAt(slice.items, last)}
           isThreadChild={isThreadChildAt(slice.items, last)}
@@ -56,6 +60,7 @@ let FeedSlice = ({slice}: {slice: FeedPostSlice}): React.ReactNode => {
           post={slice.items[i].post}
           record={slice.items[i].record}
           reason={slice.items[i].reason}
+          feedContext={slice.items[i].feedContext}
           moderation={slice.items[i].moderation}
           isThreadParent={isThreadParentAt(slice.items, i)}
           isThreadChild={isThreadChildAt(slice.items, i)}