about summary refs log tree commit diff
path: root/src/view/shell/desktop/Search.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/shell/desktop/Search.tsx')
-rw-r--r--src/view/shell/desktop/Search.tsx106
1 files changed, 47 insertions, 59 deletions
diff --git a/src/view/shell/desktop/Search.tsx b/src/view/shell/desktop/Search.tsx
index 0c5bd452f..52f28cc63 100644
--- a/src/view/shell/desktop/Search.tsx
+++ b/src/view/shell/desktop/Search.tsx
@@ -1,33 +1,35 @@
 import React from 'react'
 import {
-  ViewStyle,
-  TextInput,
-  View,
+  ActivityIndicator,
   StyleSheet,
+  TextInput,
   TouchableOpacity,
-  ActivityIndicator,
+  View,
+  ViewStyle,
 } from 'react-native'
-import {useNavigation, StackActions} from '@react-navigation/native'
 import {
   AppBskyActorDefs,
   moderateProfile,
   ModerationDecision,
 } from '@atproto/api'
-import {Trans, msg} from '@lingui/macro'
+import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
+import {StackActions, useNavigation} from '@react-navigation/native'
+import {useQueryClient} from '@tanstack/react-query'
 
-import {s} from '#/lib/styles'
+import {makeProfileLink} from '#/lib/routes/links'
 import {sanitizeDisplayName} from '#/lib/strings/display-names'
 import {sanitizeHandle} from '#/lib/strings/handles'
-import {makeProfileLink} from '#/lib/routes/links'
-import {Link} from '#/view/com/util/Link'
+import {s} from '#/lib/styles'
+import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete'
+import {useModerationOpts} from '#/state/queries/preferences'
 import {usePalette} from 'lib/hooks/usePalette'
 import {MagnifyingGlassIcon2} from 'lib/icons'
 import {NavigationProp} from 'lib/routes/types'
-import {Text} from 'view/com/util/text/Text'
+import {precacheProfile} from 'state/queries/profile'
+import {Link} from '#/view/com/util/Link'
 import {UserAvatar} from '#/view/com/util/UserAvatar'
-import {useActorAutocompleteFn} from '#/state/queries/actor-autocomplete'
-import {useModerationOpts} from '#/state/queries/preferences'
+import {Text} from 'view/com/util/text/Text'
 
 export const MATCH_HANDLE =
   /@?([a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*(?:\.[a-zA-Z]{2,}))/
@@ -84,11 +86,19 @@ export function SearchLinkCard({
 export function SearchProfileCard({
   profile,
   moderation,
+  onPress: onPressInner,
 }: {
   profile: AppBskyActorDefs.ProfileViewBasic
   moderation: ModerationDecision
+  onPress: () => void
 }) {
   const pal = usePalette('default')
+  const queryClient = useQueryClient()
+
+  const onPress = React.useCallback(() => {
+    precacheProfile(queryClient, profile)
+    onPressInner()
+  }, [queryClient, profile, onPressInner])
 
   return (
     <Link
@@ -96,7 +106,8 @@ export function SearchProfileCard({
       href={makeProfileLink(profile)}
       title={profile.handle}
       asAnchor
-      anchorNoUnderline>
+      anchorNoUnderline
+      onBeforePress={onPress}>
       <View
         style={[
           pal.border,
@@ -138,63 +149,35 @@ export function DesktopSearch() {
   const {_} = useLingui()
   const pal = usePalette('default')
   const navigation = useNavigation<NavigationProp>()
-  const searchDebounceTimeout = React.useRef<NodeJS.Timeout | undefined>(
-    undefined,
-  )
   const [isActive, setIsActive] = React.useState<boolean>(false)
-  const [isFetching, setIsFetching] = React.useState<boolean>(false)
   const [query, setQuery] = React.useState<string>('')
-  const [searchResults, setSearchResults] = React.useState<
-    AppBskyActorDefs.ProfileViewBasic[]
-  >([])
+  const {data: autocompleteData, isFetching} = useActorAutocompleteQuery(
+    query,
+    true,
+  )
 
   const moderationOpts = useModerationOpts()
-  const search = useActorAutocompleteFn()
-
-  const onChangeText = React.useCallback(
-    async (text: string) => {
-      setQuery(text)
-
-      if (text.length > 0) {
-        setIsFetching(true)
-        setIsActive(true)
 
-        if (searchDebounceTimeout.current)
-          clearTimeout(searchDebounceTimeout.current)
-
-        searchDebounceTimeout.current = setTimeout(async () => {
-          const results = await search({query: text})
-
-          if (results) {
-            setSearchResults(results)
-            setIsFetching(false)
-          }
-        }, 300)
-      } else {
-        if (searchDebounceTimeout.current)
-          clearTimeout(searchDebounceTimeout.current)
-        setSearchResults([])
-        setIsFetching(false)
-        setIsActive(false)
-      }
-    },
-    [setQuery, search, setSearchResults],
-  )
+  const onChangeText = React.useCallback((text: string) => {
+    setQuery(text)
+    setIsActive(text.length > 0)
+  }, [])
 
   const onPressCancelSearch = React.useCallback(() => {
     setQuery('')
     setIsActive(false)
-    if (searchDebounceTimeout.current)
-      clearTimeout(searchDebounceTimeout.current)
   }, [setQuery])
+
   const onSubmit = React.useCallback(() => {
     setIsActive(false)
     if (!query.length) return
-    setSearchResults([])
-    if (searchDebounceTimeout.current)
-      clearTimeout(searchDebounceTimeout.current)
     navigation.dispatch(StackActions.push('Search', {q: query}))
-  }, [query, navigation, setSearchResults])
+  }, [query, navigation])
+
+  const onSearchProfileCardPress = React.useCallback(() => {
+    setQuery('')
+    setIsActive(false)
+  }, [])
 
   const queryMaybeHandle = React.useMemo(() => {
     const match = MATCH_HANDLE.exec(query)
@@ -246,7 +229,7 @@ export function DesktopSearch() {
 
       {query !== '' && isActive && moderationOpts && (
         <View style={[pal.view, pal.borderDark, styles.resultsContainer]}>
-          {isFetching ? (
+          {isFetching && !autocompleteData?.length ? (
             <View style={{padding: 8}}>
               <ActivityIndicator />
             </View>
@@ -255,7 +238,11 @@ export function DesktopSearch() {
               <SearchLinkCard
                 label={_(msg`Search for "${query}"`)}
                 to={`/search?q=${encodeURIComponent(query)}`}
-                style={{borderBottomWidth: 1}}
+                style={
+                  queryMaybeHandle || (autocompleteData?.length ?? 0) > 0
+                    ? {borderBottomWidth: 1}
+                    : undefined
+                }
               />
 
               {queryMaybeHandle ? (
@@ -265,11 +252,12 @@ export function DesktopSearch() {
                 />
               ) : null}
 
-              {searchResults.map(item => (
+              {autocompleteData?.map(item => (
                 <SearchProfileCard
                   key={item.did}
                   profile={item}
                   moderation={moderateProfile(item, moderationOpts)}
+                  onPress={onSearchProfileCardPress}
                 />
               ))}
             </>