Standardize metadata for client events in feeds (#9653)
This commit is contained in:
@@ -8,6 +8,7 @@ import type React from 'react'
|
|||||||
import {useCleanError} from '#/lib/hooks/useCleanError'
|
import {useCleanError} from '#/lib/hooks/useCleanError'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {type Shadow} from '#/state/cache/post-shadow'
|
import {type Shadow} from '#/state/cache/post-shadow'
|
||||||
|
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
||||||
import {useBookmarkMutation} from '#/state/queries/bookmarks/useBookmarkMutation'
|
import {useBookmarkMutation} from '#/state/queries/bookmarks/useBookmarkMutation'
|
||||||
import {useRequireAuth} from '#/state/session'
|
import {useRequireAuth} from '#/state/session'
|
||||||
import {useTheme} from '#/alf'
|
import {useTheme} from '#/alf'
|
||||||
@@ -32,6 +33,7 @@ export const BookmarkButton = memo(function BookmarkButton({
|
|||||||
const {mutateAsync: bookmark} = useBookmarkMutation()
|
const {mutateAsync: bookmark} = useBookmarkMutation()
|
||||||
const cleanError = useCleanError()
|
const cleanError = useCleanError()
|
||||||
const requireAuth = useRequireAuth()
|
const requireAuth = useRequireAuth()
|
||||||
|
const {feedDescriptor} = useFeedFeedbackContext()
|
||||||
|
|
||||||
const {viewer} = post
|
const {viewer} = post
|
||||||
const isBookmarked = !!viewer?.bookmarked
|
const isBookmarked = !!viewer?.bookmarked
|
||||||
@@ -50,7 +52,12 @@ export const BookmarkButton = memo(function BookmarkButton({
|
|||||||
post,
|
post,
|
||||||
})
|
})
|
||||||
|
|
||||||
logger.metric('post:bookmark', {logContext})
|
logger.metric('post:bookmark', {
|
||||||
|
uri: post.uri,
|
||||||
|
authorDid: post.author.did,
|
||||||
|
logContext,
|
||||||
|
feedDescriptor,
|
||||||
|
})
|
||||||
|
|
||||||
toast.show(
|
toast.show(
|
||||||
<toast.Outer>
|
<toast.Outer>
|
||||||
@@ -85,7 +92,12 @@ export const BookmarkButton = memo(function BookmarkButton({
|
|||||||
uri: post.uri,
|
uri: post.uri,
|
||||||
})
|
})
|
||||||
|
|
||||||
logger.metric('post:unbookmark', {logContext})
|
logger.metric('post:unbookmark', {
|
||||||
|
uri: post.uri,
|
||||||
|
authorDid: post.author.did,
|
||||||
|
logContext,
|
||||||
|
feedDescriptor,
|
||||||
|
})
|
||||||
|
|
||||||
toast.show(
|
toast.show(
|
||||||
<toast.Outer>
|
<toast.Outer>
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ let PostMenuItems = ({
|
|||||||
richText,
|
richText,
|
||||||
threadgateRecord,
|
threadgateRecord,
|
||||||
onShowLess,
|
onShowLess,
|
||||||
|
logContext,
|
||||||
}: {
|
}: {
|
||||||
testID: string
|
testID: string
|
||||||
post: Shadow<AppBskyFeedDefs.PostView>
|
post: Shadow<AppBskyFeedDefs.PostView>
|
||||||
@@ -111,6 +112,7 @@ let PostMenuItems = ({
|
|||||||
timestamp: string
|
timestamp: string
|
||||||
threadgateRecord?: AppBskyFeedThreadgate.Record
|
threadgateRecord?: AppBskyFeedThreadgate.Record
|
||||||
onShowLess?: (interaction: AppBskyFeedDefs.Interaction) => void
|
onShowLess?: (interaction: AppBskyFeedDefs.Interaction) => void
|
||||||
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const {hasSession, currentAccount} = useSession()
|
const {hasSession, currentAccount} = useSession()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
@@ -210,9 +212,21 @@ let PostMenuItems = ({
|
|||||||
try {
|
try {
|
||||||
if (isThreadMuted) {
|
if (isThreadMuted) {
|
||||||
unmuteThread()
|
unmuteThread()
|
||||||
|
logger.metric('post:unmute', {
|
||||||
|
uri: postUri,
|
||||||
|
authorDid: postAuthor.did,
|
||||||
|
logContext,
|
||||||
|
feedDescriptor: feedFeedback.feedDescriptor,
|
||||||
|
})
|
||||||
Toast.show(_(msg`You will now receive notifications for this thread`))
|
Toast.show(_(msg`You will now receive notifications for this thread`))
|
||||||
} else {
|
} else {
|
||||||
muteThread()
|
muteThread()
|
||||||
|
logger.metric('post:mute', {
|
||||||
|
uri: postUri,
|
||||||
|
authorDid: postAuthor.did,
|
||||||
|
logContext,
|
||||||
|
feedDescriptor: feedFeedback.feedDescriptor,
|
||||||
|
})
|
||||||
Toast.show(
|
Toast.show(
|
||||||
_(msg`You will no longer receive notifications for this thread`),
|
_(msg`You will no longer receive notifications for this thread`),
|
||||||
)
|
)
|
||||||
@@ -272,6 +286,12 @@ let PostMenuItems = ({
|
|||||||
feedContext: postFeedContext,
|
feedContext: postFeedContext,
|
||||||
reqId: postReqId,
|
reqId: postReqId,
|
||||||
})
|
})
|
||||||
|
logger.metric('post:showMore', {
|
||||||
|
uri: postUri,
|
||||||
|
authorDid: postAuthor.did,
|
||||||
|
logContext,
|
||||||
|
feedDescriptor: feedFeedback.feedDescriptor,
|
||||||
|
})
|
||||||
Toast.show(
|
Toast.show(
|
||||||
_(msg({message: 'Feedback sent to feed operator', context: 'toast'})),
|
_(msg({message: 'Feedback sent to feed operator', context: 'toast'})),
|
||||||
)
|
)
|
||||||
@@ -284,6 +304,12 @@ let PostMenuItems = ({
|
|||||||
feedContext: postFeedContext,
|
feedContext: postFeedContext,
|
||||||
reqId: postReqId,
|
reqId: postReqId,
|
||||||
})
|
})
|
||||||
|
logger.metric('post:showLess', {
|
||||||
|
uri: postUri,
|
||||||
|
authorDid: postAuthor.did,
|
||||||
|
logContext,
|
||||||
|
feedDescriptor: feedFeedback.feedDescriptor,
|
||||||
|
})
|
||||||
if (onShowLess) {
|
if (onShowLess) {
|
||||||
onShowLess({
|
onShowLess({
|
||||||
item: postUri,
|
item: postUri,
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ let PostMenuButton = ({
|
|||||||
threadgateRecord,
|
threadgateRecord,
|
||||||
onShowLess,
|
onShowLess,
|
||||||
hitSlop,
|
hitSlop,
|
||||||
|
logContext,
|
||||||
}: {
|
}: {
|
||||||
testID: string
|
testID: string
|
||||||
post: Shadow<AppBskyFeedDefs.PostView>
|
post: Shadow<AppBskyFeedDefs.PostView>
|
||||||
@@ -41,6 +42,7 @@ let PostMenuButton = ({
|
|||||||
threadgateRecord?: AppBskyFeedThreadgate.Record
|
threadgateRecord?: AppBskyFeedThreadgate.Record
|
||||||
onShowLess?: (interaction: AppBskyFeedDefs.Interaction) => void
|
onShowLess?: (interaction: AppBskyFeedDefs.Interaction) => void
|
||||||
hitSlop?: Insets
|
hitSlop?: Insets
|
||||||
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
|
||||||
@@ -87,6 +89,7 @@ let PostMenuButton = ({
|
|||||||
timestamp={timestamp}
|
timestamp={timestamp}
|
||||||
threadgateRecord={threadgateRecord}
|
threadgateRecord={threadgateRecord}
|
||||||
onShowLess={onShowLess}
|
onShowLess={onShowLess}
|
||||||
|
logContext={logContext}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Menu.Root>
|
</Menu.Root>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {useGate} from '#/lib/statsig/statsig'
|
|||||||
import {toShareUrl} from '#/lib/strings/url-helpers'
|
import {toShareUrl} from '#/lib/strings/url-helpers'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {type Shadow} from '#/state/cache/post-shadow'
|
import {type Shadow} from '#/state/cache/post-shadow'
|
||||||
|
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
||||||
import {EventStopper} from '#/view/com/util/EventStopper'
|
import {EventStopper} from '#/view/com/util/EventStopper'
|
||||||
import {native} from '#/alf'
|
import {native} from '#/alf'
|
||||||
import {ArrowOutOfBoxModified_Stroke2_Corner2_Rounded as ArrowOutOfBoxIcon} from '#/components/icons/ArrowOutOfBox'
|
import {ArrowOutOfBoxModified_Stroke2_Corner2_Rounded as ArrowOutOfBoxIcon} from '#/components/icons/ArrowOutOfBox'
|
||||||
@@ -35,6 +36,7 @@ let ShareMenuButton = ({
|
|||||||
threadgateRecord,
|
threadgateRecord,
|
||||||
onShare,
|
onShare,
|
||||||
hitSlop,
|
hitSlop,
|
||||||
|
logContext,
|
||||||
}: {
|
}: {
|
||||||
testID: string
|
testID: string
|
||||||
post: Shadow<AppBskyFeedDefs.PostView>
|
post: Shadow<AppBskyFeedDefs.PostView>
|
||||||
@@ -45,9 +47,11 @@ let ShareMenuButton = ({
|
|||||||
threadgateRecord?: AppBskyFeedThreadgate.Record
|
threadgateRecord?: AppBskyFeedThreadgate.Record
|
||||||
onShare: () => void
|
onShare: () => void
|
||||||
hitSlop?: Insets
|
hitSlop?: Insets
|
||||||
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const gate = useGate()
|
const gate = useGate()
|
||||||
|
const {feedDescriptor} = useFeedFeedbackContext()
|
||||||
|
|
||||||
const ShareIcon = gate('alt_share_icon')
|
const ShareIcon = gate('alt_share_icon')
|
||||||
? ArrowShareRightIcon
|
? ArrowShareRightIcon
|
||||||
@@ -65,13 +69,27 @@ let ShareMenuButton = ({
|
|||||||
setTimeout(menuControl.open)
|
setTimeout(menuControl.open)
|
||||||
|
|
||||||
logger.metric(
|
logger.metric(
|
||||||
'share:open',
|
'post:share',
|
||||||
{context: big ? 'thread' : 'feed'},
|
{
|
||||||
|
uri: post.uri,
|
||||||
|
authorDid: post.author.did,
|
||||||
|
logContext,
|
||||||
|
feedDescriptor,
|
||||||
|
postContext: big ? 'thread' : 'feed',
|
||||||
|
},
|
||||||
{statsig: true},
|
{statsig: true},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[menuControl, setHasBeenOpen, big],
|
[
|
||||||
|
menuControl,
|
||||||
|
setHasBeenOpen,
|
||||||
|
big,
|
||||||
|
logContext,
|
||||||
|
feedDescriptor,
|
||||||
|
post.uri,
|
||||||
|
post.author.did,
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
const onNativeLongPress = () => {
|
const onNativeLongPress = () => {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {CountWheel} from '#/lib/custom-animations/CountWheel'
|
|||||||
import {AnimatedLikeIcon} from '#/lib/custom-animations/LikeIcon'
|
import {AnimatedLikeIcon} from '#/lib/custom-animations/LikeIcon'
|
||||||
import {useHaptics} from '#/lib/haptics'
|
import {useHaptics} from '#/lib/haptics'
|
||||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||||
|
import {logger} from '#/logger'
|
||||||
import {type Shadow} from '#/state/cache/types'
|
import {type Shadow} from '#/state/cache/types'
|
||||||
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
||||||
import {
|
import {
|
||||||
@@ -174,6 +175,12 @@ let PostControls = ({
|
|||||||
feedContext,
|
feedContext,
|
||||||
reqId,
|
reqId,
|
||||||
})
|
})
|
||||||
|
logger.metric('post:clickQuotePost', {
|
||||||
|
uri: post.uri,
|
||||||
|
authorDid: post.author.did,
|
||||||
|
logContext,
|
||||||
|
feedDescriptor,
|
||||||
|
})
|
||||||
openComposer({
|
openComposer({
|
||||||
quote: post,
|
quote: post,
|
||||||
onPost: onPostReply,
|
onPost: onPostReply,
|
||||||
@@ -217,7 +224,16 @@ let PostControls = ({
|
|||||||
testID="replyBtn"
|
testID="replyBtn"
|
||||||
onPress={
|
onPress={
|
||||||
!replyDisabled
|
!replyDisabled
|
||||||
? () => requireAuth(() => onPressReply())
|
? () =>
|
||||||
|
requireAuth(() => {
|
||||||
|
logger.metric('post:clickReply', {
|
||||||
|
uri: post.uri,
|
||||||
|
authorDid: post.author.did,
|
||||||
|
logContext,
|
||||||
|
feedDescriptor,
|
||||||
|
})
|
||||||
|
onPressReply()
|
||||||
|
})
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
label={_(
|
label={_(
|
||||||
@@ -315,6 +331,7 @@ let PostControls = ({
|
|||||||
left: secondaryControlSpacingStyles.gap / 2,
|
left: secondaryControlSpacingStyles.gap / 2,
|
||||||
right: secondaryControlSpacingStyles.gap / 2,
|
right: secondaryControlSpacingStyles.gap / 2,
|
||||||
}}
|
}}
|
||||||
|
logContext={logContext}
|
||||||
/>
|
/>
|
||||||
<PostMenuButton
|
<PostMenuButton
|
||||||
testID="postDropdownBtn"
|
testID="postDropdownBtn"
|
||||||
@@ -330,6 +347,7 @@ let PostControls = ({
|
|||||||
hitSlop={{
|
hitSlop={{
|
||||||
left: secondaryControlSpacingStyles.gap / 2,
|
left: secondaryControlSpacingStyles.gap / 2,
|
||||||
}}
|
}}
|
||||||
|
logContext={logContext}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
+77
-9
@@ -176,13 +176,19 @@ export type MetricEvents = {
|
|||||||
'feed:suggestion:press': {
|
'feed:suggestion:press': {
|
||||||
feedUrl: string
|
feedUrl: string
|
||||||
}
|
}
|
||||||
'feed:showMore': {
|
'post:showMore': {
|
||||||
feed: string
|
uri: string
|
||||||
feedContext: string
|
authorDid: string
|
||||||
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
|
feedDescriptor?: string
|
||||||
|
position?: number
|
||||||
}
|
}
|
||||||
'feed:showLess': {
|
'post:showLess': {
|
||||||
feed: string
|
uri: string
|
||||||
feedContext: string
|
authorDid: string
|
||||||
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
|
feedDescriptor?: string
|
||||||
|
position?: number
|
||||||
}
|
}
|
||||||
'feed:clickthrough': {
|
'feed:clickthrough': {
|
||||||
feed: string
|
feed: string
|
||||||
@@ -257,15 +263,70 @@ export type MetricEvents = {
|
|||||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
feedDescriptor?: string
|
feedDescriptor?: string
|
||||||
}
|
}
|
||||||
'post:mute': {}
|
'post:mute': {
|
||||||
'post:unmute': {}
|
uri: string
|
||||||
|
authorDid: string
|
||||||
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
|
feedDescriptor?: string
|
||||||
|
position?: number
|
||||||
|
}
|
||||||
|
'post:unmute': {
|
||||||
|
uri: string
|
||||||
|
authorDid: string
|
||||||
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
|
feedDescriptor?: string
|
||||||
|
position?: number
|
||||||
|
}
|
||||||
'post:pin': {}
|
'post:pin': {}
|
||||||
'post:unpin': {}
|
'post:unpin': {}
|
||||||
'post:bookmark': {
|
'post:bookmark': {
|
||||||
|
uri: string
|
||||||
|
authorDid: string
|
||||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
|
feedDescriptor?: string
|
||||||
|
position?: number
|
||||||
}
|
}
|
||||||
'post:unbookmark': {
|
'post:unbookmark': {
|
||||||
|
uri: string
|
||||||
|
authorDid: string
|
||||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
|
feedDescriptor?: string
|
||||||
|
position?: number
|
||||||
|
}
|
||||||
|
'post:clickReply': {
|
||||||
|
uri: string
|
||||||
|
authorDid: string
|
||||||
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
|
feedDescriptor?: string
|
||||||
|
position?: number
|
||||||
|
}
|
||||||
|
'post:clickQuotePost': {
|
||||||
|
uri: string
|
||||||
|
authorDid: string
|
||||||
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
|
feedDescriptor?: string
|
||||||
|
position?: number
|
||||||
|
}
|
||||||
|
'post:clickthroughAuthor': {
|
||||||
|
uri: string
|
||||||
|
authorDid: string
|
||||||
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
|
feedDescriptor?: string
|
||||||
|
position?: number
|
||||||
|
}
|
||||||
|
'post:clickthroughItem': {
|
||||||
|
uri: string
|
||||||
|
authorDid: string
|
||||||
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
|
feedDescriptor?: string
|
||||||
|
position?: number
|
||||||
|
}
|
||||||
|
'post:clickthroughEmbed': {
|
||||||
|
uri: string
|
||||||
|
authorDid: string
|
||||||
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
|
feedDescriptor?: string
|
||||||
|
position?: number
|
||||||
}
|
}
|
||||||
'post:view': {
|
'post:view': {
|
||||||
uri: string
|
uri: string
|
||||||
@@ -565,7 +626,14 @@ export type MetricEvents = {
|
|||||||
'live:view:profile': {subject: string}
|
'live:view:profile': {subject: string}
|
||||||
'live:view:post': {subject: string; feed?: string}
|
'live:view:post': {subject: string; feed?: string}
|
||||||
|
|
||||||
'share:open': {context: 'feed' | 'thread'}
|
'post:share': {
|
||||||
|
uri: string
|
||||||
|
authorDid: string
|
||||||
|
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||||
|
feedDescriptor?: string
|
||||||
|
postContext: 'feed' | 'thread'
|
||||||
|
position?: number
|
||||||
|
}
|
||||||
'share:press:copyLink': {}
|
'share:press:copyLink': {}
|
||||||
'share:press:nativeShare': {}
|
'share:press:nativeShare': {}
|
||||||
'share:press:openDmSearch': {}
|
'share:press:openDmSearch': {}
|
||||||
|
|||||||
@@ -281,6 +281,12 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({
|
|||||||
])
|
])
|
||||||
|
|
||||||
const onOpenAuthor = () => {
|
const onOpenAuthor = () => {
|
||||||
|
logger.metric('post:clickthroughAuthor', {
|
||||||
|
uri: post.uri,
|
||||||
|
authorDid: post.author.did,
|
||||||
|
logContext: 'PostThreadItem',
|
||||||
|
feedDescriptor: feedFeedback.feedDescriptor,
|
||||||
|
})
|
||||||
if (postSource) {
|
if (postSource) {
|
||||||
feedFeedback.sendInteraction({
|
feedFeedback.sendInteraction({
|
||||||
item: post.uri,
|
item: post.uri,
|
||||||
@@ -292,6 +298,12 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onOpenEmbed = () => {
|
const onOpenEmbed = () => {
|
||||||
|
logger.metric('post:clickthroughEmbed', {
|
||||||
|
uri: post.uri,
|
||||||
|
authorDid: post.author.did,
|
||||||
|
logContext: 'PostThreadItem',
|
||||||
|
feedDescriptor: feedFeedback.feedDescriptor,
|
||||||
|
})
|
||||||
if (postSource) {
|
if (postSource) {
|
||||||
feedFeedback.sendInteraction({
|
feedFeedback.sendInteraction({
|
||||||
item: post.uri,
|
item: post.uri,
|
||||||
|
|||||||
@@ -137,7 +137,6 @@ export function useFeedFeedback(
|
|||||||
sendOrAggregateInteractionsForStats(
|
sendOrAggregateInteractionsForStats(
|
||||||
aggregatedStats.current,
|
aggregatedStats.current,
|
||||||
interactionsToSend,
|
interactionsToSend,
|
||||||
feed?.feedDescriptor ?? 'unknown',
|
|
||||||
)
|
)
|
||||||
throttledFlushAggregatedStats()
|
throttledFlushAggregatedStats()
|
||||||
logger.debug('flushed')
|
logger.debug('flushed')
|
||||||
@@ -274,28 +273,10 @@ function createAggregatedStats(): AggregatedStats {
|
|||||||
function sendOrAggregateInteractionsForStats(
|
function sendOrAggregateInteractionsForStats(
|
||||||
stats: AggregatedStats,
|
stats: AggregatedStats,
|
||||||
interactions: AppBskyFeedDefs.Interaction[],
|
interactions: AppBskyFeedDefs.Interaction[],
|
||||||
feed: string,
|
|
||||||
) {
|
) {
|
||||||
for (let interaction of interactions) {
|
for (let interaction of interactions) {
|
||||||
switch (interaction.event) {
|
switch (interaction.event) {
|
||||||
// Pressing "Show more" / "Show less" is relatively uncommon so we won't aggregate them.
|
// The events are aggregated and sent later in batches.
|
||||||
// This lets us send the feed context together with them.
|
|
||||||
case 'app.bsky.feed.defs#requestLess': {
|
|
||||||
logger.metric('feed:showLess', {
|
|
||||||
feed,
|
|
||||||
feedContext: interaction.feedContext ?? '',
|
|
||||||
})
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case 'app.bsky.feed.defs#requestMore': {
|
|
||||||
logger.metric('feed:showMore', {
|
|
||||||
feed,
|
|
||||||
feedContext: interaction.feedContext ?? '',
|
|
||||||
})
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// The rest of the events are aggregated and sent later in batches.
|
|
||||||
case 'app.bsky.feed.defs#clickthroughAuthor':
|
case 'app.bsky.feed.defs#clickthroughAuthor':
|
||||||
case 'app.bsky.feed.defs#clickthroughEmbed':
|
case 'app.bsky.feed.defs#clickthroughEmbed':
|
||||||
case 'app.bsky.feed.defs#clickthroughItem':
|
case 'app.bsky.feed.defs#clickthroughItem':
|
||||||
|
|||||||
@@ -373,7 +373,6 @@ function useThreadMuteMutation() {
|
|||||||
{uri: string} // the root post's uri
|
{uri: string} // the root post's uri
|
||||||
>({
|
>({
|
||||||
mutationFn: ({uri}) => {
|
mutationFn: ({uri}) => {
|
||||||
logger.metric('post:mute', {})
|
|
||||||
return agent.api.app.bsky.graph.muteThread({root: uri})
|
return agent.api.app.bsky.graph.muteThread({root: uri})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -383,7 +382,6 @@ function useThreadUnmuteMutation() {
|
|||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
return useMutation<{}, Error, {uri: string}>({
|
return useMutation<{}, Error, {uri: string}>({
|
||||||
mutationFn: ({uri}) => {
|
mutationFn: ({uri}) => {
|
||||||
logger.metric('post:unmute', {})
|
|
||||||
return agent.api.app.bsky.graph.unmuteThread({root: uri})
|
return agent.api.app.bsky.graph.unmuteThread({root: uri})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {makeProfileLink} from '#/lib/routes/links'
|
|||||||
import {type NavigationProp} from '#/lib/routes/types'
|
import {type NavigationProp} from '#/lib/routes/types'
|
||||||
import {useGate} from '#/lib/statsig/statsig'
|
import {useGate} from '#/lib/statsig/statsig'
|
||||||
import {countLines} from '#/lib/strings/helpers'
|
import {countLines} from '#/lib/strings/helpers'
|
||||||
|
import {logger} from '#/logger'
|
||||||
import {
|
import {
|
||||||
POST_TOMBSTONE,
|
POST_TOMBSTONE,
|
||||||
type Shadow,
|
type Shadow,
|
||||||
@@ -173,7 +174,8 @@ let FeedItemInner = ({
|
|||||||
const urip = new AtUri(post.uri)
|
const urip = new AtUri(post.uri)
|
||||||
return [makeProfileLink(post.author, 'post', urip.rkey), urip.rkey]
|
return [makeProfileLink(post.author, 'post', urip.rkey), urip.rkey]
|
||||||
}, [post.uri, post.author])
|
}, [post.uri, post.author])
|
||||||
const {sendInteraction, feedSourceInfo} = useFeedFeedbackContext()
|
const {sendInteraction, feedSourceInfo, feedDescriptor} =
|
||||||
|
useFeedFeedbackContext()
|
||||||
|
|
||||||
const onPressReply = () => {
|
const onPressReply = () => {
|
||||||
sendInteraction({
|
sendInteraction({
|
||||||
@@ -209,6 +211,12 @@ let FeedItemInner = ({
|
|||||||
feedContext,
|
feedContext,
|
||||||
reqId,
|
reqId,
|
||||||
})
|
})
|
||||||
|
logger.metric('post:clickthroughAuthor', {
|
||||||
|
uri: post.uri,
|
||||||
|
authorDid: post.author.did,
|
||||||
|
logContext: 'FeedItem',
|
||||||
|
feedDescriptor,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const onOpenReposter = () => {
|
const onOpenReposter = () => {
|
||||||
@@ -227,6 +235,12 @@ let FeedItemInner = ({
|
|||||||
feedContext,
|
feedContext,
|
||||||
reqId,
|
reqId,
|
||||||
})
|
})
|
||||||
|
logger.metric('post:clickthroughEmbed', {
|
||||||
|
uri: post.uri,
|
||||||
|
authorDid: post.author.did,
|
||||||
|
logContext: 'FeedItem',
|
||||||
|
feedDescriptor,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const onBeforePress = () => {
|
const onBeforePress = () => {
|
||||||
@@ -236,6 +250,12 @@ let FeedItemInner = ({
|
|||||||
feedContext,
|
feedContext,
|
||||||
reqId,
|
reqId,
|
||||||
})
|
})
|
||||||
|
logger.metric('post:clickthroughItem', {
|
||||||
|
uri: post.uri,
|
||||||
|
authorDid: post.author.did,
|
||||||
|
logContext: 'FeedItem',
|
||||||
|
feedDescriptor,
|
||||||
|
})
|
||||||
unstableCacheProfileView(queryClient, post.author)
|
unstableCacheProfileView(queryClient, post.author)
|
||||||
setUnstablePostSource(buildPostSourceKey(post.uri, post.author.handle), {
|
setUnstablePostSource(buildPostSourceKey(post.uri, post.author.handle), {
|
||||||
feedSourceInfo,
|
feedSourceInfo,
|
||||||
|
|||||||
Reference in New Issue
Block a user