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