Add pagination to feed search (#11475)
This commit is contained in:
@@ -1175,11 +1175,6 @@
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"src/screens/StarterPack/Wizard/StepFeeds.tsx": {
|
||||
"typescript/no-misused-promises": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"src/screens/StarterPack/Wizard/index.tsx": {
|
||||
"typescript/no-floating-promises": {
|
||||
"count": 2
|
||||
|
||||
@@ -648,26 +648,41 @@ let SearchScreenFeedsResults = ({
|
||||
const ax = useAnalytics()
|
||||
const t = useTheme()
|
||||
|
||||
const {data: results, isFetched} = usePopularFeedsSearch({
|
||||
const {
|
||||
data: results,
|
||||
isFetched,
|
||||
isFetching,
|
||||
error,
|
||||
fetchNextPage,
|
||||
isFetchingNextPage,
|
||||
hasNextPage,
|
||||
} = usePopularFeedsSearch({
|
||||
query,
|
||||
enabled: active,
|
||||
})
|
||||
const feeds = useMemo(() => {
|
||||
return results?.pages.flatMap(page => page.feeds) || []
|
||||
}, [results])
|
||||
const onEndReached = useCallback(() => {
|
||||
if (isFetching || !hasNextPage || error) return
|
||||
void fetchNextPage()
|
||||
}, [isFetching, error, hasNextPage, fetchNextPage])
|
||||
|
||||
const fireTracking = useCallOnce(() => {
|
||||
ax.metric('search:results:loaded', {
|
||||
tab: 'feeds',
|
||||
initialCount: results?.length ?? 0,
|
||||
initialCount: feeds.length,
|
||||
})
|
||||
})
|
||||
if (isFetched) {
|
||||
fireTracking()
|
||||
}
|
||||
|
||||
return isFetched && results ? (
|
||||
return isFetched ? (
|
||||
<>
|
||||
{results.length ? (
|
||||
{feeds.length || hasNextPage ? (
|
||||
<List
|
||||
data={results}
|
||||
data={feeds}
|
||||
renderItem={({
|
||||
item,
|
||||
index,
|
||||
@@ -686,8 +701,14 @@ let SearchScreenFeedsResults = ({
|
||||
</View>
|
||||
)}
|
||||
keyExtractor={(item: app.bsky.feed.defs.GeneratorView) => item.uri}
|
||||
onEndReached={onEndReached}
|
||||
desktopFixedHeight
|
||||
ListFooterComponent={<ListFooter />}
|
||||
ListFooterComponent={
|
||||
<ListFooter
|
||||
hasNextPage={hasNextPage}
|
||||
isFetchingNextPage={isFetchingNextPage}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<EmptyState messageText={<NoResultsText query={query} />} />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {useState} from 'react'
|
||||
import {useMemo, useState} from 'react'
|
||||
import {type ListRenderItemInfo, View} from 'react-native'
|
||||
import {KeyboardAwareScrollView} from 'react-native-keyboard-controller'
|
||||
import {type ModerationOpts} from '@bsky/sdk/moderation'
|
||||
@@ -16,6 +16,7 @@ import {useWizardState} from '#/screens/StarterPack/Wizard/State'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {SearchInput} from '#/components/forms/SearchInput'
|
||||
import {useThrottledValue} from '#/components/hooks/useThrottledValue'
|
||||
import {ListFooter} from '#/components/Lists'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {ScreenTransition} from '#/components/ScreenTransition'
|
||||
import {WizardFeedCard} from '#/components/StarterPack/Wizard/WizardListCard'
|
||||
@@ -59,8 +60,16 @@ export function StepFeeds({moderationOpts}: {moderationOpts: ModerationOpts}) {
|
||||
: savedFeeds
|
||||
: undefined
|
||||
|
||||
const {data: searchedFeeds, isFetching: isFetchingSearchedFeeds} =
|
||||
usePopularFeedsSearch({query: throttledQuery})
|
||||
const {
|
||||
data: searchedFeedsPages,
|
||||
fetchNextPage: fetchNextSearchedFeedsPage,
|
||||
hasNextPage: hasNextSearchedFeedsPage,
|
||||
isFetching: isFetchingSearchedFeeds,
|
||||
isFetchingNextPage: isFetchingNextSearchedFeedsPage,
|
||||
} = usePopularFeedsSearch({query: throttledQuery})
|
||||
const searchedFeeds = useMemo(() => {
|
||||
return searchedFeedsPages?.pages.flatMap(page => page.feeds) ?? []
|
||||
}, [searchedFeedsPages])
|
||||
|
||||
const isLoading =
|
||||
!isFetchedSavedFeeds || isLoadingPopularFeeds || isFetchingSearchedFeeds
|
||||
@@ -98,7 +107,17 @@ export function StepFeeds({moderationOpts}: {moderationOpts: ModerationOpts}) {
|
||||
renderItem={renderItem}
|
||||
keyExtractor={keyExtractor}
|
||||
onEndReached={
|
||||
!query && !screenReaderEnabled ? () => fetchNextPage() : undefined
|
||||
!screenReaderEnabled
|
||||
? () => {
|
||||
if (query) {
|
||||
if (hasNextSearchedFeedsPage) {
|
||||
void fetchNextSearchedFeedsPage()
|
||||
}
|
||||
} else {
|
||||
void fetchNextPage()
|
||||
}
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
onEndReachedThreshold={2}
|
||||
keyboardDismissMode="on-drag"
|
||||
@@ -107,6 +126,14 @@ export function StepFeeds({moderationOpts}: {moderationOpts: ModerationOpts}) {
|
||||
disableFullWindowScroll={true}
|
||||
sideBorders={false}
|
||||
style={{flex: 1}}
|
||||
ListFooterComponent={
|
||||
query ? (
|
||||
<ListFooter
|
||||
hasNextPage={hasNextSearchedFeedsPage}
|
||||
isFetchingNextPage={isFetchingNextSearchedFeedsPage}
|
||||
/>
|
||||
) : undefined
|
||||
}
|
||||
ListEmptyComponent={
|
||||
<View style={[a.flex_1, a.align_center, a.mt_lg, a.px_lg]}>
|
||||
{isLoading ? (
|
||||
|
||||
@@ -380,26 +380,35 @@ export function usePopularFeedsSearch({
|
||||
const moderationOpts = useModerationOpts()
|
||||
const enabledInner = enabled ?? Boolean(moderationOpts)
|
||||
|
||||
return useQuery({
|
||||
return useInfiniteQuery({
|
||||
enabled: enabledInner,
|
||||
queryKey: createPopularFeedsSearchQueryKey(query),
|
||||
queryFn: async () => {
|
||||
queryFn: async ({pageParam}) => {
|
||||
const data = await client.call(
|
||||
app.bsky.unspecced.getPopularFeedGenerators,
|
||||
{
|
||||
limit: 15,
|
||||
query: query,
|
||||
cursor: pageParam,
|
||||
},
|
||||
)
|
||||
|
||||
return data.feeds
|
||||
return data
|
||||
},
|
||||
initialPageParam: undefined as string | undefined,
|
||||
getNextPageParam: lastPage => lastPage.cursor,
|
||||
placeholderData: keepPreviousData,
|
||||
select(data) {
|
||||
return data.filter(feed => {
|
||||
const decision = moderateFeedGenerator(feed, moderationOpts!)
|
||||
return !decision.ui('contentMedia').blur
|
||||
})
|
||||
return {
|
||||
...data,
|
||||
pages: data.pages.map(page => ({
|
||||
...page,
|
||||
feeds: page.feeds.filter(feed => {
|
||||
const decision = moderateFeedGenerator(feed, moderationOpts!)
|
||||
return !decision.ui('contentMedia').blur
|
||||
}),
|
||||
})),
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user