diff --git a/src/screens/VideoFeed/index.tsx b/src/screens/VideoFeed/index.tsx index 495b3bc622..49c758ba3d 100644 --- a/src/screens/VideoFeed/index.tsx +++ b/src/screens/VideoFeed/index.tsx @@ -70,6 +70,7 @@ import { useFeedFeedbackContext, } from '#/state/feed-feedback' import {useFeedFeedback} from '#/state/feed-feedback' +import {useFeedInfo} from '#/state/queries/feed' import {usePostLikeMutationQueue} from '#/state/queries/post' import { type AuthorFilter, @@ -199,7 +200,9 @@ function Feed() { throw new Error(`Invalid video feed params ${JSON.stringify(params)}`) } }, [params]) - const feedFeedback = useFeedFeedback(feedDesc, hasSession) + const feedUri = params.type === 'feedgen' ? params.uri : undefined + const {data: feedInfo} = useFeedInfo(feedUri) + const feedFeedback = useFeedFeedback(feedInfo, hasSession) const {data, error, hasNextPage, isFetchingNextPage, fetchNextPage} = usePostFeedQuery( feedDesc, diff --git a/src/state/feed-feedback.tsx b/src/state/feed-feedback.tsx index 76d2116ff7..d8f72d0d02 100644 --- a/src/state/feed-feedback.tsx +++ b/src/state/feed-feedback.tsx @@ -16,11 +16,14 @@ import { FEEDBACK_FEEDS, type FeedbackInteraction, isFeedbackInteraction, - STAGING_FEEDS, } from '#/lib/constants' import {logEvent} from '#/lib/statsig/statsig' import {Logger} from '#/logger' -import {type FeedSourceInfo} from '#/state/queries/feed' +import { + type FeedSourceFeedInfo, + type FeedSourceInfo, + isFeedSourceFeedInfo, +} from '#/state/queries/feed' import { type FeedDescriptor, type FeedPostSliceItem, @@ -46,24 +49,21 @@ const stateContext = createContext({ feedSourceInfo: undefined, }) -// All info needed to send feedback to a feed -type FeedInfo = { - feedDescriptor: FeedDescriptor - acceptsInteractions: boolean - isDiscover: boolean - proxyDid: string -} - export function useFeedFeedback( - feed: FeedSourceInfo | FeedDescriptor | undefined, + feedSourceInfo: FeedSourceInfo | undefined, hasSession: boolean, ) { const agent = useAgent() - const feedInfo = feed ? buildFeedInfo(feed) : null - const enabled = !!feedInfo && feedInfo.acceptsInteractions && hasSession + const feed = + !!feedSourceInfo && isFeedSourceFeedInfo(feedSourceInfo) + ? feedSourceInfo + : undefined - const enabledInteractions = getEnabledInteractions(enabled, feedInfo) + const isDiscover = isDiscoverFeed(feed?.feedDescriptor) + const acceptsInteractions = isDiscover || (feed?.acceptsInteractions ?? false) + const enabled = !!feed && acceptsInteractions && hasSession + const enabledInteractions = getEnabledInteractions(enabled, feed, isDiscover) const queue = useRef>(new Set()) const history = useRef< @@ -97,6 +97,8 @@ export function useFeedFeedback( return } + const proxyDid = feed?.view?.did + // Send to the feed agent.app.bsky.feed .sendInteractions( @@ -104,7 +106,7 @@ export function useFeedFeedback( { encoding: 'application/json', headers: { - 'atproto-proxy': `${feedInfo?.proxyDid}#bsky_fg`, + 'atproto-proxy': `${proxyDid}#bsky_fg`, }, }, ) @@ -122,7 +124,7 @@ export function useFeedFeedback( ) throttledFlushAggregatedStats() logger.debug('flushed') - }, [agent, throttledFlushAggregatedStats, feedInfo, enabledInteractions]) + }, [agent, throttledFlushAggregatedStats, feed, enabledInteractions]) const sendToFeed = useMemo( () => @@ -194,10 +196,10 @@ export function useFeedFeedback( // call on various events // queues the event to be sent with the throttled sendToFeed call sendInteraction, - feedDescriptor: feedInfo?.feedDescriptor, + feedDescriptor: feed?.feedDescriptor, feedSourceInfo: typeof feed === 'object' ? feed : undefined, } - }, [enabled, onItemSeen, sendInteraction, feedInfo, feed]) + }, [enabled, onItemSeen, sendInteraction, feed]) } export const FeedFeedbackProvider = stateContext.Provider @@ -215,60 +217,15 @@ function isDiscoverFeed(feed?: FeedDescriptor) { return !!feed && FEEDBACK_FEEDS.includes(feed) } -function buildFeedInfo(feed: FeedSourceInfo | FeedDescriptor): FeedInfo | null { - // Build FeedInfo object from either a feed source info object or a feed descriptor string - // Only discover feeds are supported for feed descriptor strings - if (typeof feed === 'object') { - if (feed.type !== 'feed') { - // Don't send feedback to non-feed sources - return null - } - const feedDescriptor = feed.feedDescriptor - const isDiscover = isDiscoverFeed(feed.feedDescriptor) - const proxyDid = feed.view?.did - if (!proxyDid) { - logger.warn(`No proxy did found for feed: ${feedDescriptor}.`) - return null - } - let acceptsInteractions = feed.acceptsInteractions ?? false - if (isDiscover) { - // Discover feed doesn't have acceptsInteractions: true, so hardcode this for now - acceptsInteractions = true - } - return { - feedDescriptor, - isDiscover, - proxyDid, - acceptsInteractions, - } - } else { - const feedDescriptor = feed - const isDiscover = isDiscoverFeed(feedDescriptor) - if (!isDiscover) { - return null - } - const proxyDid = STAGING_FEEDS.includes(feedDescriptor) - ? 'did:web:algo.pop2.bsky.app' - : 'did:web:discover.bsky.app' - return { - feedDescriptor, - isDiscover, - proxyDid, - acceptsInteractions: true, - } - } -} - function getEnabledInteractions( enabled: boolean, - feedInfo: FeedInfo | null, + feed: FeedSourceFeedInfo | undefined, + isDiscover: boolean, ): readonly FeedbackInteraction[] { - if (!enabled || !feedInfo) { + if (!enabled || !feed) { return [] } - return feedInfo.isDiscover - ? ALL_FEEDBACK_INTERACTIONS - : DIRECT_FEEDBACK_INTERACTIONS + return isDiscover ? ALL_FEEDBACK_INTERACTIONS : DIRECT_FEEDBACK_INTERACTIONS } function toString(interaction: AppBskyFeedDefs.Interaction): string { diff --git a/src/state/queries/feed.ts b/src/state/queries/feed.ts index bd5dcfcd53..e6e3e82fb5 100644 --- a/src/state/queries/feed.ts +++ b/src/state/queries/feed.ts @@ -74,6 +74,12 @@ export type FeedSourceListInfo = { export type FeedSourceInfo = FeedSourceFeedInfo | FeedSourceListInfo +export function isFeedSourceFeedInfo( + feed: FeedSourceInfo, +): feed is FeedSourceFeedInfo { + return feed.type === 'feed' +} + const feedSourceInfoQueryKeyRoot = 'getFeedSourceInfo' export const feedSourceInfoQueryKey = ({uri}: {uri: string}) => [ feedSourceInfoQueryKeyRoot, @@ -621,6 +627,29 @@ export function useSavedFeeds() { }) } +const feedInfoQueryKeyRoot = 'feedInfo' + +export function useFeedInfo(feedUri: string | undefined) { + const agent = useAgent() + + return useQuery({ + staleTime: STALE.INFINITY, + queryKey: [feedInfoQueryKeyRoot, feedUri], + queryFn: async () => { + if (!feedUri) { + return undefined + } + + const res = await agent.app.bsky.feed.getFeedGenerator({ + feed: feedUri, + }) + + const feedSourceInfo = hydrateFeedGenerator(res.data.view) + return feedSourceInfo + }, + }) +} + function precacheFeed(queryClient: QueryClient, hydratedFeed: FeedSourceInfo) { precacheResolvedUri( queryClient,