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>
This commit is contained in:
Paul Frazee 2024-05-06 19:08:33 -07:00 committed by GitHub
parent e264dfbb87
commit 4fad18b2fa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 516 additions and 64 deletions

View file

@ -23,6 +23,7 @@ import {toShareUrl} from '#/lib/strings/url-helpers'
import {s} from '#/lib/styles'
import {useTheme} from '#/lib/ThemeContext'
import {Shadow} from '#/state/cache/types'
import {useFeedFeedbackContext} from '#/state/feed-feedback'
import {useModalControls} from '#/state/modals'
import {
usePostLikeMutationQueue,
@ -43,6 +44,7 @@ let PostCtrls = ({
post,
record,
richText,
feedContext,
style,
onPressReply,
logContext,
@ -51,6 +53,7 @@ let PostCtrls = ({
post: Shadow<AppBskyFeedDefs.PostView>
record: AppBskyFeedPost.Record
richText: RichTextAPI
feedContext?: string | undefined
style?: StyleProp<ViewStyle>
onPressReply: () => void
logContext: 'FeedItem' | 'PostThreadItem' | 'Post'
@ -66,6 +69,7 @@ let PostCtrls = ({
)
const requireAuth = useRequireAuth()
const loggedOutWarningPromptControl = useDialogControl()
const {sendInteraction} = useFeedFeedbackContext()
const playHaptic = useHaptics()
const shouldShowLoggedOutWarning = React.useMemo(() => {
@ -85,6 +89,11 @@ let PostCtrls = ({
try {
if (!post.viewer?.like) {
playHaptic()
sendInteraction({
item: post.uri,
event: 'app.bsky.feed.defs#interactionLike',
feedContext,
})
await queueLike()
} else {
await queueUnlike()
@ -94,13 +103,26 @@ let PostCtrls = ({
throw e
}
}
}, [playHaptic, post.viewer?.like, queueLike, queueUnlike])
}, [
playHaptic,
post.uri,
post.viewer?.like,
queueLike,
queueUnlike,
sendInteraction,
feedContext,
])
const onRepost = useCallback(async () => {
closeModal()
try {
if (!post.viewer?.repost) {
playHaptic()
sendInteraction({
item: post.uri,
event: 'app.bsky.feed.defs#interactionRepost',
feedContext,
})
await queueRepost()
} else {
await queueUnrepost()
@ -110,10 +132,24 @@ let PostCtrls = ({
throw e
}
}
}, [closeModal, post.viewer?.repost, playHaptic, queueRepost, queueUnrepost])
}, [
closeModal,
post.uri,
post.viewer?.repost,
playHaptic,
queueRepost,
queueUnrepost,
sendInteraction,
feedContext,
])
const onQuote = useCallback(() => {
closeModal()
sendInteraction({
item: post.uri,
event: 'app.bsky.feed.defs#interactionQuote',
feedContext,
})
openComposer({
quote: {
uri: post.uri,
@ -133,6 +169,8 @@ let PostCtrls = ({
post.indexedAt,
record.text,
playHaptic,
sendInteraction,
feedContext,
])
const onShare = useCallback(() => {
@ -140,7 +178,12 @@ let PostCtrls = ({
const href = makeProfileLink(post.author, 'post', urip.rkey)
const url = toShareUrl(href)
shareUrl(url)
}, [post.uri, post.author])
sendInteraction({
item: post.uri,
event: 'app.bsky.feed.defs#interactionShare',
feedContext,
})
}, [post.uri, post.author, sendInteraction, feedContext])
return (
<View style={[styles.ctrls, style]}>
@ -268,6 +311,7 @@ let PostCtrls = ({
postAuthor={post.author}
postCid={post.cid}
postUri={post.uri}
postFeedContext={feedContext}
record={record}
richText={richText}
style={styles.btnPad}