diff options
author | Paul Frazee <pfrazee@gmail.com> | 2024-05-06 19:08:33 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-07 03:08:33 +0100 |
commit | 4fad18b2fa3c12ffdf1d49afac5228f7df658bc2 (patch) | |
tree | 8fa8df48dcf544c288bc0618127fcead58014962 /src/view/com/posts/FeedItem.tsx | |
parent | e264dfbb875118036d5b155f46f2b0b71261e1ff (diff) | |
download | voidsky-4fad18b2fa3c12ffdf1d49afac5228f7df658bc2.tar.zst |
Implement FeedFeedback API (#3498)
* Implement onViewableItemsChanged on List.web.tsx * Introduce onItemSeen to List API * Add FeedFeedback tracker * Add clickthrough interaction tracking * Add engagement interaction tracking * Reduce duplicate sends, introduce a flushAndReset to be triggered on refreshes, and modify the api design a bit * Wire up SDK types and feedContext * Avoid needless function allocations * Fix schema usage * Add show more / show less buttons * Fix minor rendering issue on mobile menu * Wire up sendInteractions() * Fix logic error * Fix: it's item not uri * Update 'seen' to mean 3 seconds on-screen with some significant portion visible * Fix non-reactive debounce * Move methods out * Use a WeakSet for deduping * Reset timeout * 3 -> 2 seconds * Oopsie * Throttle instead * Fix divider * Remove explicit flush calls * Rm unused --------- Co-authored-by: dan <dan.abramov@gmail.com>
Diffstat (limited to 'src/view/com/posts/FeedItem.tsx')
-rw-r--r-- | src/view/com/posts/FeedItem.tsx | 61 |
1 files changed, 57 insertions, 4 deletions
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> |