Search lists cleanup, pagninate actor search (#9009)
This commit is contained in:
@@ -8,7 +8,7 @@ import {popularInterests, useInterestsDisplayNames} from '#/lib/interests'
|
|||||||
import {logEvent} from '#/lib/statsig/statsig'
|
import {logEvent} from '#/lib/statsig/statsig'
|
||||||
import {isWeb} from '#/platform/detection'
|
import {isWeb} from '#/platform/detection'
|
||||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {useActorSearchPaginated} from '#/state/queries/actor-search'
|
import {useActorSearch} from '#/state/queries/actor-search'
|
||||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||||
import {useGetSuggestedUsersQuery} from '#/state/queries/trending/useGetSuggestedUsersQuery'
|
import {useGetSuggestedUsersQuery} from '#/state/queries/trending/useGetSuggestedUsersQuery'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
@@ -128,7 +128,7 @@ function DialogInner({guide}: {guide: Follow10ProgressGuide}) {
|
|||||||
isFetching: isFetchingSearchResults,
|
isFetching: isFetchingSearchResults,
|
||||||
error: searchResultsError,
|
error: searchResultsError,
|
||||||
isError: isSearchResultsError,
|
isError: isSearchResultsError,
|
||||||
} = useActorSearchPaginated({
|
} = useActorSearch({
|
||||||
enabled: !!searchText,
|
enabled: !!searchText,
|
||||||
query: searchText,
|
query: searchText,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ export const urls = {
|
|||||||
website: {
|
website: {
|
||||||
blog: {
|
blog: {
|
||||||
initialVerificationAnnouncement: `https://bsky.social/about/blog/04-21-2025-verification`,
|
initialVerificationAnnouncement: `https://bsky.social/about/blog/04-21-2025-verification`,
|
||||||
|
searchTipsAndTricks: 'https://bsky.social/about/blog/05-31-2024-search',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {logger} from '#/logger'
|
|||||||
import {type MetricEvents} from '#/logger/metrics'
|
import {type MetricEvents} from '#/logger/metrics'
|
||||||
import {useLanguagePrefs} from '#/state/preferences/languages'
|
import {useLanguagePrefs} from '#/state/preferences/languages'
|
||||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {RQKEY_ROOT_PAGINATED as useActorSearchPaginatedQueryKeyRoot} from '#/state/queries/actor-search'
|
import {RQKEY_ROOT as useActorSearchQueryKeyRoot} from '#/state/queries/actor-search'
|
||||||
import {
|
import {
|
||||||
type FeedPreviewItem,
|
type FeedPreviewItem,
|
||||||
useFeedPreviews,
|
useFeedPreviews,
|
||||||
@@ -308,7 +308,7 @@ export function Explore({
|
|||||||
queryKey: [getSuggestedUsersQueryKeyRoot],
|
queryKey: [getSuggestedUsersQueryKeyRoot],
|
||||||
}),
|
}),
|
||||||
qc.resetQueries({
|
qc.resetQueries({
|
||||||
queryKey: [useActorSearchPaginatedQueryKeyRoot],
|
queryKey: [useActorSearchQueryKeyRoot],
|
||||||
}),
|
}),
|
||||||
qc.resetQueries({
|
qc.resetQueries({
|
||||||
queryKey: createGetSuggestedFeedsQueryKey(),
|
queryKey: createGetSuggestedFeedsQueryKey(),
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import {type AppBskyFeedDefs} from '@atproto/api'
|
|||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {usePalette} from '#/lib/hooks/usePalette'
|
import {urls} from '#/lib/constants'
|
||||||
|
import {cleanError} from '#/lib/strings/errors'
|
||||||
import {augmentSearchQuery} from '#/lib/strings/helpers'
|
import {augmentSearchQuery} from '#/lib/strings/helpers'
|
||||||
import {useActorSearch} from '#/state/queries/actor-search'
|
import {useActorSearch} from '#/state/queries/actor-search'
|
||||||
import {usePopularFeedsSearch} from '#/state/queries/feed'
|
import {usePopularFeedsSearch} from '#/state/queries/feed'
|
||||||
@@ -21,6 +22,7 @@ import {atoms as a, useTheme, web} from '#/alf'
|
|||||||
import * as FeedCard from '#/components/FeedCard'
|
import * as FeedCard from '#/components/FeedCard'
|
||||||
import * as Layout from '#/components/Layout'
|
import * as Layout from '#/components/Layout'
|
||||||
import {InlineLinkText} from '#/components/Link'
|
import {InlineLinkText} from '#/components/Link'
|
||||||
|
import {ListFooter} from '#/components/Lists'
|
||||||
import {SearchError} from '#/components/SearchError'
|
import {SearchError} from '#/components/SearchError'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
|
||||||
@@ -112,11 +114,11 @@ function Loader() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function EmptyState({
|
function EmptyState({
|
||||||
message,
|
messageText,
|
||||||
error,
|
error,
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
message: string
|
messageText: React.ReactNode
|
||||||
error?: string
|
error?: string
|
||||||
children?: React.ReactNode
|
children?: React.ReactNode
|
||||||
}) {
|
}) {
|
||||||
@@ -126,7 +128,7 @@ function EmptyState({
|
|||||||
<Layout.Content>
|
<Layout.Content>
|
||||||
<View style={[a.p_xl]}>
|
<View style={[a.p_xl]}>
|
||||||
<View style={[t.atoms.bg_contrast_25, a.rounded_sm, a.p_lg]}>
|
<View style={[t.atoms.bg_contrast_25, a.rounded_sm, a.p_lg]}>
|
||||||
<Text style={[a.text_md]}>{message}</Text>
|
<Text style={[a.text_md]}>{messageText}</Text>
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<>
|
<>
|
||||||
@@ -155,6 +157,41 @@ function EmptyState({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function NoResultsText({query}: {query: string}) {
|
||||||
|
const t = useTheme()
|
||||||
|
const {_} = useLingui()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Text style={[a.text_lg, t.atoms.text_contrast_high]}>
|
||||||
|
<Trans>
|
||||||
|
No results found for "
|
||||||
|
<Text style={[a.text_lg, t.atoms.text, a.font_medium]}>{query}</Text>
|
||||||
|
".
|
||||||
|
</Trans>
|
||||||
|
</Text>
|
||||||
|
{'\n\n'}
|
||||||
|
<Text style={[a.text_md, a.leading_snug, t.atoms.text_contrast_high]}>
|
||||||
|
<Trans context="english-only-resource">
|
||||||
|
Try a different search term, or{' '}
|
||||||
|
<InlineLinkText
|
||||||
|
label={_(
|
||||||
|
msg({
|
||||||
|
message: 'read about how to use search filters',
|
||||||
|
context: 'english-only-resource',
|
||||||
|
}),
|
||||||
|
)}
|
||||||
|
to={urls.website.blog.searchTipsAndTricks}
|
||||||
|
style={[a.text_md, a.leading_snug]}>
|
||||||
|
read about how to use search filters
|
||||||
|
</InlineLinkText>
|
||||||
|
.
|
||||||
|
</Trans>
|
||||||
|
</Text>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
type SearchResultSlice =
|
type SearchResultSlice =
|
||||||
| {
|
| {
|
||||||
type: 'post'
|
type: 'post'
|
||||||
@@ -176,9 +213,8 @@ let SearchScreenPostResults = ({
|
|||||||
active: boolean
|
active: boolean
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount, hasSession} = useSession()
|
||||||
const [isPTR, setIsPTR] = useState(false)
|
const [isPTR, setIsPTR] = useState(false)
|
||||||
const isLoggedin = Boolean(currentAccount?.did)
|
|
||||||
|
|
||||||
const augmentedQuery = useMemo(() => {
|
const augmentedQuery = useMemo(() => {
|
||||||
return augmentSearchQuery(query || '', {did: currentAccount?.did})
|
return augmentSearchQuery(query || '', {did: currentAccount?.did})
|
||||||
@@ -195,7 +231,6 @@ let SearchScreenPostResults = ({
|
|||||||
hasNextPage,
|
hasNextPage,
|
||||||
} = useSearchPostsQuery({query: augmentedQuery, sort, enabled: active})
|
} = useSearchPostsQuery({query: augmentedQuery, sort, enabled: active})
|
||||||
|
|
||||||
const pal = usePalette('default')
|
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const onPullToRefresh = useCallback(async () => {
|
const onPullToRefresh = useCallback(async () => {
|
||||||
setIsPTR(true)
|
setIsPTR(true)
|
||||||
@@ -249,14 +284,13 @@ let SearchScreenPostResults = ({
|
|||||||
requestSwitchToAccount({requestedAccount: 'new'})
|
requestSwitchToAccount({requestedAccount: 'new'})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isLoggedin) {
|
if (!hasSession) {
|
||||||
return (
|
return (
|
||||||
<SearchError
|
<SearchError
|
||||||
title={_(msg`Search is currently unavailable when logged out`)}>
|
title={_(msg`Search is currently unavailable when logged out`)}>
|
||||||
<Text style={[a.text_md, a.text_center, a.leading_snug]}>
|
<Text style={[a.text_md, a.text_center, a.leading_snug]}>
|
||||||
<Trans>
|
<Trans>
|
||||||
<InlineLinkText
|
<InlineLinkText
|
||||||
style={[pal.link]}
|
|
||||||
label={_(msg`Sign in`)}
|
label={_(msg`Sign in`)}
|
||||||
to={'#'}
|
to={'#'}
|
||||||
onPress={showSignIn}>
|
onPress={showSignIn}>
|
||||||
@@ -264,7 +298,6 @@ let SearchScreenPostResults = ({
|
|||||||
</InlineLinkText>
|
</InlineLinkText>
|
||||||
<Text style={t.atoms.text_contrast_medium}> or </Text>
|
<Text style={t.atoms.text_contrast_medium}> or </Text>
|
||||||
<InlineLinkText
|
<InlineLinkText
|
||||||
style={[pal.link]}
|
|
||||||
label={_(msg`Create an account`)}
|
label={_(msg`Create an account`)}
|
||||||
to={'#'}
|
to={'#'}
|
||||||
onPress={showCreateAccount}>
|
onPress={showCreateAccount}>
|
||||||
@@ -283,10 +316,10 @@ let SearchScreenPostResults = ({
|
|||||||
|
|
||||||
return error ? (
|
return error ? (
|
||||||
<EmptyState
|
<EmptyState
|
||||||
message={_(
|
messageText={_(
|
||||||
msg`We're sorry, but your search could not be completed. Please try again in a few minutes.`,
|
msg`We're sorry, but your search could not be completed. Please try again in a few minutes.`,
|
||||||
)}
|
)}
|
||||||
error={error.toString()}
|
error={cleanError(error)}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
@@ -307,10 +340,15 @@ let SearchScreenPostResults = ({
|
|||||||
onRefresh={onPullToRefresh}
|
onRefresh={onPullToRefresh}
|
||||||
onEndReached={onEndReached}
|
onEndReached={onEndReached}
|
||||||
desktopFixedHeight
|
desktopFixedHeight
|
||||||
contentContainerStyle={{paddingBottom: 100}}
|
ListFooterComponent={
|
||||||
|
<ListFooter
|
||||||
|
isFetchingNextPage={isFetchingNextPage}
|
||||||
|
hasNextPage={hasNextPage}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<EmptyState message={_(msg`No results found for ${query}`)} />
|
<EmptyState messageText={<NoResultsText query={query} />} />
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
@@ -329,24 +367,69 @@ let SearchScreenUserResults = ({
|
|||||||
active: boolean
|
active: boolean
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const {hasSession} = useSession()
|
||||||
|
const [isPTR, setIsPTR] = useState(false)
|
||||||
|
|
||||||
const {data: results, isFetched} = useActorSearch({
|
const {
|
||||||
|
isFetched,
|
||||||
|
data: results,
|
||||||
|
isFetching,
|
||||||
|
error,
|
||||||
|
refetch,
|
||||||
|
fetchNextPage,
|
||||||
|
isFetchingNextPage,
|
||||||
|
hasNextPage,
|
||||||
|
} = useActorSearch({
|
||||||
query,
|
query,
|
||||||
enabled: active,
|
enabled: active,
|
||||||
})
|
})
|
||||||
|
|
||||||
return isFetched && results ? (
|
const onPullToRefresh = useCallback(async () => {
|
||||||
|
setIsPTR(true)
|
||||||
|
await refetch()
|
||||||
|
setIsPTR(false)
|
||||||
|
}, [setIsPTR, refetch])
|
||||||
|
const onEndReached = useCallback(() => {
|
||||||
|
if (!hasSession) return
|
||||||
|
if (isFetching || !hasNextPage || error) return
|
||||||
|
fetchNextPage()
|
||||||
|
}, [isFetching, error, hasNextPage, fetchNextPage, hasSession])
|
||||||
|
|
||||||
|
const profiles = useMemo(() => {
|
||||||
|
return results?.pages.flatMap(page => page.actors) || []
|
||||||
|
}, [results])
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<EmptyState
|
||||||
|
messageText={_(
|
||||||
|
msg`We're sorry, but your search could not be completed. Please try again in a few minutes.`,
|
||||||
|
)}
|
||||||
|
error={error.toString()}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return isFetched && profiles ? (
|
||||||
<>
|
<>
|
||||||
{results.length ? (
|
{profiles.length ? (
|
||||||
<List
|
<List
|
||||||
data={results}
|
data={profiles}
|
||||||
renderItem={({item}) => <ProfileCardWithFollowBtn profile={item} />}
|
renderItem={({item}) => <ProfileCardWithFollowBtn profile={item} />}
|
||||||
keyExtractor={item => item.did}
|
keyExtractor={item => item.did}
|
||||||
|
refreshing={isPTR}
|
||||||
|
onRefresh={onPullToRefresh}
|
||||||
|
onEndReached={onEndReached}
|
||||||
desktopFixedHeight
|
desktopFixedHeight
|
||||||
contentContainerStyle={{paddingBottom: 100}}
|
ListFooterComponent={
|
||||||
|
<ListFooter
|
||||||
|
hasNextPage={hasNextPage && hasSession}
|
||||||
|
isFetchingNextPage={isFetchingNextPage}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<EmptyState message={_(msg`No results found for ${query}`)} />
|
<EmptyState messageText={<NoResultsText query={query} />} />
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
@@ -363,7 +446,6 @@ let SearchScreenFeedsResults = ({
|
|||||||
active: boolean
|
active: boolean
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
|
||||||
|
|
||||||
const {data: results, isFetched} = usePopularFeedsSearch({
|
const {data: results, isFetched} = usePopularFeedsSearch({
|
||||||
query,
|
query,
|
||||||
@@ -378,7 +460,7 @@ let SearchScreenFeedsResults = ({
|
|||||||
renderItem={({item}) => (
|
renderItem={({item}) => (
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
a.border_b,
|
a.border_t,
|
||||||
t.atoms.border_contrast_low,
|
t.atoms.border_contrast_low,
|
||||||
a.px_lg,
|
a.px_lg,
|
||||||
a.py_lg,
|
a.py_lg,
|
||||||
@@ -388,10 +470,10 @@ let SearchScreenFeedsResults = ({
|
|||||||
)}
|
)}
|
||||||
keyExtractor={item => item.uri}
|
keyExtractor={item => item.uri}
|
||||||
desktopFixedHeight
|
desktopFixedHeight
|
||||||
contentContainerStyle={{paddingBottom: 100}}
|
ListFooterComponent={<ListFooter />}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<EmptyState message={_(msg`No results found for ${query}`)} />
|
<EmptyState messageText={<NoResultsText query={query} />} />
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {useMemo} from 'react'
|
import {useMemo} from 'react'
|
||||||
|
|
||||||
import {useInterestsDisplayNames} from '#/lib/interests'
|
import {useInterestsDisplayNames} from '#/lib/interests'
|
||||||
import {useActorSearchPaginated} from '#/state/queries/actor-search'
|
import {useActorSearch} from '#/state/queries/actor-search'
|
||||||
import {useGetSuggestedUsersQuery} from '#/state/queries/trending/useGetSuggestedUsersQuery'
|
import {useGetSuggestedUsersQuery} from '#/state/queries/trending/useGetSuggestedUsersQuery'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,7 +31,7 @@ export function useSuggestedUsers({
|
|||||||
category,
|
category,
|
||||||
overrideInterests,
|
overrideInterests,
|
||||||
})
|
})
|
||||||
const searched = useActorSearchPaginated({
|
const searched = useActorSearch({
|
||||||
enabled: !!search,
|
enabled: !!search,
|
||||||
// use user's app language translation for this value
|
// use user's app language translation for this value
|
||||||
query: category ? interestsDisplayNames[category] : '',
|
query: category ? interestsDisplayNames[category] : '',
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {Trans} from '@lingui/macro'
|
|||||||
import {isNative} from '#/platform/detection'
|
import {isNative} from '#/platform/detection'
|
||||||
import {useA11y} from '#/state/a11y'
|
import {useA11y} from '#/state/a11y'
|
||||||
import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete'
|
import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete'
|
||||||
import {useActorSearchPaginated} from '#/state/queries/actor-search'
|
import {useActorSearch} from '#/state/queries/actor-search'
|
||||||
import {List} from '#/view/com/util/List'
|
import {List} from '#/view/com/util/List'
|
||||||
import {useWizardState} from '#/screens/StarterPack/Wizard/State'
|
import {useWizardState} from '#/screens/StarterPack/Wizard/State'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
@@ -36,7 +36,7 @@ export function StepProfiles({
|
|||||||
data: topPages,
|
data: topPages,
|
||||||
fetchNextPage,
|
fetchNextPage,
|
||||||
isLoading: isLoadingTopPages,
|
isLoading: isLoadingTopPages,
|
||||||
} = useActorSearchPaginated({
|
} = useActorSearch({
|
||||||
query: encodeURIComponent('*'),
|
query: encodeURIComponent('*'),
|
||||||
})
|
})
|
||||||
const topFollowers = topPages?.pages
|
const topFollowers = topPages?.pages
|
||||||
|
|||||||
@@ -1,25 +1,18 @@
|
|||||||
import {
|
import {type AppBskyActorSearchActors} from '@atproto/api'
|
||||||
type AppBskyActorDefs,
|
|
||||||
type AppBskyActorSearchActors,
|
|
||||||
} from '@atproto/api'
|
|
||||||
import {
|
import {
|
||||||
type InfiniteData,
|
type InfiniteData,
|
||||||
keepPreviousData,
|
keepPreviousData,
|
||||||
type QueryClient,
|
type QueryClient,
|
||||||
type QueryKey,
|
type QueryKey,
|
||||||
useInfiniteQuery,
|
useInfiniteQuery,
|
||||||
useQuery,
|
|
||||||
} from '@tanstack/react-query'
|
} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {STALE} from '#/state/queries'
|
import {STALE} from '#/state/queries'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAgent} from '#/state/session'
|
||||||
|
|
||||||
const RQKEY_ROOT = 'actor-search'
|
export const RQKEY_ROOT = 'actor-search'
|
||||||
export const RQKEY = (query: string) => [RQKEY_ROOT, query]
|
export const RQKEY = (query: string, limit?: number) => [
|
||||||
|
RQKEY_ROOT,
|
||||||
export const RQKEY_ROOT_PAGINATED = `${RQKEY_ROOT}_paginated`
|
|
||||||
export const RQKEY_PAGINATED = (query: string, limit?: number) => [
|
|
||||||
RQKEY_ROOT_PAGINATED,
|
|
||||||
query,
|
query,
|
||||||
limit,
|
limit,
|
||||||
]
|
]
|
||||||
@@ -27,27 +20,6 @@ export const RQKEY_PAGINATED = (query: string, limit?: number) => [
|
|||||||
export function useActorSearch({
|
export function useActorSearch({
|
||||||
query,
|
query,
|
||||||
enabled,
|
enabled,
|
||||||
}: {
|
|
||||||
query: string
|
|
||||||
enabled?: boolean
|
|
||||||
}) {
|
|
||||||
const agent = useAgent()
|
|
||||||
return useQuery<AppBskyActorDefs.ProfileView[]>({
|
|
||||||
staleTime: STALE.MINUTES.ONE,
|
|
||||||
queryKey: RQKEY(query || ''),
|
|
||||||
async queryFn() {
|
|
||||||
const res = await agent.searchActors({
|
|
||||||
q: query,
|
|
||||||
})
|
|
||||||
return res.data.actors
|
|
||||||
},
|
|
||||||
enabled: enabled && !!query,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useActorSearchPaginated({
|
|
||||||
query,
|
|
||||||
enabled,
|
|
||||||
maintainData,
|
maintainData,
|
||||||
limit = 25,
|
limit = 25,
|
||||||
}: {
|
}: {
|
||||||
@@ -65,7 +37,7 @@ export function useActorSearchPaginated({
|
|||||||
string | undefined
|
string | undefined
|
||||||
>({
|
>({
|
||||||
staleTime: STALE.MINUTES.FIVE,
|
staleTime: STALE.MINUTES.FIVE,
|
||||||
queryKey: RQKEY_PAGINATED(query, limit),
|
queryKey: RQKEY(query, limit),
|
||||||
queryFn: async ({pageParam}) => {
|
queryFn: async ({pageParam}) => {
|
||||||
const res = await agent.searchActors({
|
const res = await agent.searchActors({
|
||||||
q: query,
|
q: query,
|
||||||
@@ -78,35 +50,38 @@ export function useActorSearchPaginated({
|
|||||||
initialPageParam: undefined,
|
initialPageParam: undefined,
|
||||||
getNextPageParam: lastPage => lastPage.cursor,
|
getNextPageParam: lastPage => lastPage.cursor,
|
||||||
placeholderData: maintainData ? keepPreviousData : undefined,
|
placeholderData: maintainData ? keepPreviousData : undefined,
|
||||||
|
select,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function select(data: InfiniteData<AppBskyActorSearchActors.OutputSchema>) {
|
||||||
|
// enforce uniqueness
|
||||||
|
const dids = new Set()
|
||||||
|
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
pages: data.pages.map(page => ({
|
||||||
|
actors: page.actors.filter(actor => {
|
||||||
|
if (dids.has(actor.did)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
dids.add(actor.did)
|
||||||
|
return true
|
||||||
|
}),
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function* findAllProfilesInQueryData(
|
export function* findAllProfilesInQueryData(
|
||||||
queryClient: QueryClient,
|
queryClient: QueryClient,
|
||||||
did: string,
|
did: string,
|
||||||
) {
|
) {
|
||||||
const queryDatas = queryClient.getQueriesData<AppBskyActorDefs.ProfileView[]>(
|
const queryDatas = queryClient.getQueriesData<
|
||||||
{
|
|
||||||
queryKey: [RQKEY_ROOT],
|
|
||||||
},
|
|
||||||
)
|
|
||||||
for (const [_queryKey, queryData] of queryDatas) {
|
|
||||||
if (!queryData) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for (const actor of queryData) {
|
|
||||||
if (actor.did === did) {
|
|
||||||
yield actor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const queryDatasPaginated = queryClient.getQueriesData<
|
|
||||||
InfiniteData<AppBskyActorSearchActors.OutputSchema>
|
InfiniteData<AppBskyActorSearchActors.OutputSchema>
|
||||||
>({
|
>({
|
||||||
queryKey: [RQKEY_ROOT_PAGINATED],
|
queryKey: [RQKEY_ROOT],
|
||||||
})
|
})
|
||||||
for (const [_queryKey, queryData] of queryDatasPaginated) {
|
for (const [_queryKey, queryData] of queryDatas) {
|
||||||
if (!queryData) {
|
if (!queryData) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user