Log additional context for post:* events (#11035)
This commit is contained in:
@@ -14,7 +14,11 @@ import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender'
|
||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||
import {usePostViewTracking} from '#/lib/hooks/usePostViewTracking'
|
||||
import {useFeedFeedback} from '#/state/feed-feedback'
|
||||
import {
|
||||
FeedFeedbackProvider,
|
||||
type StateContext as FeedFeedbackStateContext,
|
||||
useFeedFeedback,
|
||||
} from '#/state/feed-feedback'
|
||||
import {type ThreadViewOption} from '#/state/queries/preferences/useThreadPreferences'
|
||||
import {
|
||||
PostThreadContextProvider,
|
||||
@@ -56,6 +60,9 @@ import {IS_NATIVE} from '#/env'
|
||||
|
||||
const PARENT_CHUNK_SIZE = IS_NATIVE ? 5 : 20
|
||||
const CHILDREN_CHUNK_SIZE = 50
|
||||
const analyticsOnlyOnItemSeen: FeedFeedbackStateContext['onItemSeen'] = () => {}
|
||||
const analyticsOnlySendInteraction: FeedFeedbackStateContext['sendInteraction'] =
|
||||
() => {}
|
||||
|
||||
export function PostThread({uri}: {uri: string}) {
|
||||
const ax = useAnalytics()
|
||||
@@ -569,68 +576,71 @@ export function PostThread({uri}: {uri: string}) {
|
||||
onRetry={thread.actions.refetch}
|
||||
/>
|
||||
) : (
|
||||
<List
|
||||
ref={listRef}
|
||||
data={deferredSlices}
|
||||
renderItem={renderItem}
|
||||
keyExtractor={keyExtractor}
|
||||
onContentSizeChange={platform({
|
||||
web: onContentSizeChangeWebOnly,
|
||||
default: onContentSizeChangeNativeOnly,
|
||||
})}
|
||||
onStartReached={onStartReached}
|
||||
onEndReached={onEndReached}
|
||||
onEndReachedThreshold={4}
|
||||
onStartReachedThreshold={1}
|
||||
onItemSeen={item => {
|
||||
// Track post:view for parent posts and replies (non-anchor posts)
|
||||
if (item.type === 'threadPost' && item.depth !== 0) {
|
||||
trackThreadItemView(item.value.post)
|
||||
<AnalyticsOnlyFeedFeedbackProvider
|
||||
feedDescriptor={feedFeedback.feedDescriptor}>
|
||||
<List
|
||||
ref={listRef}
|
||||
data={deferredSlices}
|
||||
renderItem={renderItem}
|
||||
keyExtractor={keyExtractor}
|
||||
onContentSizeChange={platform({
|
||||
web: onContentSizeChangeWebOnly,
|
||||
default: onContentSizeChangeNativeOnly,
|
||||
})}
|
||||
onStartReached={onStartReached}
|
||||
onEndReached={onEndReached}
|
||||
onEndReachedThreshold={4}
|
||||
onStartReachedThreshold={1}
|
||||
onItemSeen={item => {
|
||||
// Track post:view for parent posts and replies (non-anchor posts)
|
||||
if (item.type === 'threadPost' && item.depth !== 0) {
|
||||
trackThreadItemView(item.value.post)
|
||||
}
|
||||
}}
|
||||
/**
|
||||
* NATIVE ONLY
|
||||
* {@link https://reactnative.dev/docs/scrollview#maintainvisiblecontentposition}
|
||||
*/
|
||||
maintainVisibleContentPosition={{minIndexForVisible: 0}}
|
||||
desktopFixedHeight
|
||||
sideBorders={false}
|
||||
ListFooterComponent={
|
||||
<ListFooter
|
||||
/*
|
||||
* On native, if `deferParents` is true, we need some extra buffer to
|
||||
* account for the `on*ReachedThreshold` values.
|
||||
*
|
||||
* Otherwise, and on web, this value needs to be the height of
|
||||
* the viewport _minus_ a sensible min-post height e.g. 200, so
|
||||
* that there's enough scroll remaining to get the anchor post
|
||||
* back to the top of the screen when handling scroll.
|
||||
*/
|
||||
height={platform({
|
||||
web: defaultListFooterHeight,
|
||||
default: deferParents
|
||||
? windowHeight * 2
|
||||
: defaultListFooterHeight,
|
||||
})}
|
||||
style={isTombstoneView ? {borderTopWidth: 0} : undefined}
|
||||
/>
|
||||
}
|
||||
}}
|
||||
/**
|
||||
* NATIVE ONLY
|
||||
* {@link https://reactnative.dev/docs/scrollview#maintainvisiblecontentposition}
|
||||
*/
|
||||
maintainVisibleContentPosition={{minIndexForVisible: 0}}
|
||||
desktopFixedHeight
|
||||
sideBorders={false}
|
||||
ListFooterComponent={
|
||||
<ListFooter
|
||||
/*
|
||||
* On native, if `deferParents` is true, we need some extra buffer to
|
||||
* account for the `on*ReachedThreshold` values.
|
||||
*
|
||||
* Otherwise, and on web, this value needs to be the height of
|
||||
* the viewport _minus_ a sensible min-post height e.g. 200, so
|
||||
* that there's enough scroll remaining to get the anchor post
|
||||
* back to the top of the screen when handling scroll.
|
||||
*/
|
||||
height={platform({
|
||||
web: defaultListFooterHeight,
|
||||
default: deferParents
|
||||
? windowHeight * 2
|
||||
: defaultListFooterHeight,
|
||||
})}
|
||||
style={isTombstoneView ? {borderTopWidth: 0} : undefined}
|
||||
/>
|
||||
}
|
||||
initialNumToRender={initialNumToRender}
|
||||
/**
|
||||
* Default: 21
|
||||
*
|
||||
* Smaller for placeholder data so we don't waste time rendering skeletons
|
||||
*/
|
||||
windowSize={thread.state.isPlaceholderData ? 1 : 7}
|
||||
/**
|
||||
* Default: 10
|
||||
*/
|
||||
maxToRenderPerBatch={5}
|
||||
/**
|
||||
* Default: 50
|
||||
*/
|
||||
updateCellsBatchingPeriod={100}
|
||||
/>
|
||||
initialNumToRender={initialNumToRender}
|
||||
/**
|
||||
* Default: 21
|
||||
*
|
||||
* Smaller for placeholder data so we don't waste time rendering skeletons
|
||||
*/
|
||||
windowSize={thread.state.isPlaceholderData ? 1 : 7}
|
||||
/**
|
||||
* Default: 10
|
||||
*/
|
||||
maxToRenderPerBatch={5}
|
||||
/**
|
||||
* Default: 50
|
||||
*/
|
||||
updateCellsBatchingPeriod={100}
|
||||
/>
|
||||
</AnalyticsOnlyFeedFeedbackProvider>
|
||||
)}
|
||||
|
||||
{!gtMobile && canReply && hasSession && (
|
||||
@@ -640,6 +650,36 @@ export function PostThread({uri}: {uri: string}) {
|
||||
)
|
||||
}
|
||||
|
||||
function AnalyticsOnlyFeedFeedbackProvider({
|
||||
children,
|
||||
feedDescriptor,
|
||||
}: React.PropsWithChildren<{
|
||||
feedDescriptor: FeedFeedbackStateContext['feedDescriptor']
|
||||
}>) {
|
||||
/*
|
||||
* Non-anchor posts (parents and replies) are not the post the user tapped
|
||||
* from a feed, so they should not report feed interactions. But they should
|
||||
* still carry the originating feedDescriptor for analytics, so events like
|
||||
* post:clickQuotePost can be attributed to the feed the thread was opened
|
||||
* from. This inert context value provides feedDescriptor while keeping
|
||||
* interaction reporting disabled (enabled: false makes sendInteraction and
|
||||
* onItemSeen no-ops). The anchor renders its own full provider that nests
|
||||
* inside and overrides this for its subtree.
|
||||
*/
|
||||
const value = useMemo<FeedFeedbackStateContext>(
|
||||
() => ({
|
||||
enabled: false,
|
||||
onItemSeen: analyticsOnlyOnItemSeen,
|
||||
sendInteraction: analyticsOnlySendInteraction,
|
||||
feedDescriptor,
|
||||
feedSourceInfo: undefined,
|
||||
}),
|
||||
[feedDescriptor],
|
||||
)
|
||||
|
||||
return <FeedFeedbackProvider value={value}>{children}</FeedFeedbackProvider>
|
||||
}
|
||||
|
||||
function MobileComposePrompt({onPressReply}: {onPressReply: () => unknown}) {
|
||||
const {footerHeight} = useShellLayout()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user