Search page (#1912)

* Desktop web work

* Mobile search

* Dedupe suggestions

* Clean up and reorg

* Cleanup

* Cleanup

* Use Pager

* Delete unused code

* Fix conflicts

* Remove search ui model

* Soft reset

* Fix scrollable results, remove observer

* Use correct ScrollView

* Clean up layout

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
This commit is contained in:
Eric Bailey 2023-11-15 17:55:28 -06:00 committed by GitHub
parent d5ea31920c
commit 22b76423a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 742 additions and 991 deletions

View file

@ -1,69 +0,0 @@
import {makeAutoObservable, runInAction} from 'mobx'
import {searchProfiles, searchPosts} from 'lib/api/search'
import {PostThreadModel} from '../content/post-thread'
import {AppBskyActorDefs, AppBskyFeedDefs} from '@atproto/api'
import {RootStoreModel} from '../root-store'
export class SearchUIModel {
isPostsLoading = false
isProfilesLoading = false
query: string = ''
posts: PostThreadModel[] = []
profiles: AppBskyActorDefs.ProfileView[] = []
constructor(public rootStore: RootStoreModel) {
makeAutoObservable(this)
}
async fetch(q: string) {
this.posts = []
this.profiles = []
this.query = q
if (!q.trim()) {
return
}
this.isPostsLoading = true
this.isProfilesLoading = true
const [postsSearch, profilesSearch] = await Promise.all([
searchPosts(q).catch(_e => []),
searchProfiles(q).catch(_e => []),
])
let posts: AppBskyFeedDefs.PostView[] = []
if (postsSearch?.length) {
do {
const res = await this.rootStore.agent.app.bsky.feed.getPosts({
uris: postsSearch
.splice(0, 25)
.map(p => `at://${p.user.did}/${p.tid}`),
})
posts = posts.concat(res.data.posts)
} while (postsSearch.length)
}
runInAction(() => {
this.posts = posts.map(post =>
PostThreadModel.fromPostView(this.rootStore, post),
)
this.isPostsLoading = false
})
let profiles: AppBskyActorDefs.ProfileView[] = []
if (profilesSearch?.length) {
do {
const res = await this.rootStore.agent.getProfiles({
actors: profilesSearch.splice(0, 25).map(p => p.did),
})
profiles = profiles.concat(res.data.profiles)
} while (profilesSearch.length)
}
this.rootStore.me.follows.hydrateMany(profiles)
runInAction(() => {
this.profiles = profiles
this.isProfilesLoading = false
})
}
}

View file

@ -36,7 +36,7 @@ export function useActorAutocompleteFn() {
const {data: follows} = useMyFollowsQuery()
return React.useCallback(
async ({query}: {query: string}) => {
async ({query, limit = 8}: {query: string; limit?: number}) => {
let res
if (query) {
try {
@ -47,7 +47,7 @@ export function useActorAutocompleteFn() {
queryFn: () =>
agent.searchActorsTypeahead({
term: query,
limit: 8,
limit,
}),
})
} catch (e) {

View file

@ -0,0 +1,32 @@
import {AppBskyFeedSearchPosts} from '@atproto/api'
import {useInfiniteQuery, InfiniteData, QueryKey} from '@tanstack/react-query'
import {useSession} from '#/state/session'
const searchPostsQueryKey = ({query}: {query: string}) => [
'search-posts',
query,
]
export function useSearchPostsQuery({query}: {query: string}) {
const {agent} = useSession()
return useInfiniteQuery<
AppBskyFeedSearchPosts.OutputSchema,
Error,
InfiniteData<AppBskyFeedSearchPosts.OutputSchema>,
QueryKey,
string | undefined
>({
queryKey: searchPostsQueryKey({query}),
queryFn: async () => {
const res = await agent.app.bsky.feed.searchPosts({
q: query,
limit: 25,
})
return res.data
},
initialPageParam: undefined,
getNextPageParam: lastPage => lastPage.cursor,
})
}

View file

@ -1,3 +1,4 @@
import React from 'react'
import {
AppBskyActorGetSuggestions,
AppBskyGraphGetSuggestedFollowsByActor,
@ -5,7 +6,7 @@ import {
} from '@atproto/api'
import {
useInfiniteQuery,
useMutation,
useQueryClient,
useQuery,
InfiniteData,
QueryKey,
@ -15,7 +16,7 @@ import {useSession} from '#/state/session'
import {useModerationOpts} from '#/state/queries/preferences'
const suggestedFollowsQueryKey = ['suggested-follows']
const suggestedFollowsByActorQuery = (did: string) => [
const suggestedFollowsByActorQueryKey = (did: string) => [
'suggested-follows-by-actor',
did,
]
@ -73,7 +74,7 @@ export function useSuggestedFollowsByActorQuery({did}: {did: string}) {
const {agent} = useSession()
return useQuery<AppBskyGraphGetSuggestedFollowsByActor.OutputSchema, Error>({
queryKey: suggestedFollowsByActorQuery(did),
queryKey: suggestedFollowsByActorQueryKey(did),
queryFn: async () => {
const res = await agent.app.bsky.graph.getSuggestedFollowsByActor({
actor: did,
@ -83,17 +84,26 @@ export function useSuggestedFollowsByActorQuery({did}: {did: string}) {
})
}
// TODO: Delete and replace usages with the one above.
// TODO refactor onboarding to use above, but this is still used
export function useGetSuggestedFollowersByActor() {
const {agent} = useSession()
const queryClient = useQueryClient()
return useMutation({
mutationFn: async (actor: string) => {
const res = await agent.app.bsky.graph.getSuggestedFollowsByActor({
actor: actor,
return React.useCallback(
async (actor: string) => {
const res = await queryClient.fetchQuery({
staleTime: 60 * 1000,
queryKey: suggestedFollowsByActorQueryKey(actor),
queryFn: async () => {
const res = await agent.app.bsky.graph.getSuggestedFollowsByActor({
actor: actor,
})
return res.data
},
})
return res.data
return res
},
})
[agent, queryClient],
)
}