about summary refs log tree commit diff
path: root/src/view/shell/desktop/Search.tsx
diff options
context:
space:
mode:
authorHailey <me@haileyok.com>2024-04-26 20:34:53 -0700
committerGitHub <noreply@github.com>2024-04-27 04:34:53 +0100
commit5f9136479b6dbcaaa9def57e0308326a00259e8b (patch)
tree55d660675e37508ed003654b31690b8b7ffcb674 /src/view/shell/desktop/Search.tsx
parentd81a373d21af605db43c2076bfe486aa16e01de3 (diff)
downloadvoidsky-5f9136479b6dbcaaa9def57e0308326a00259e8b.tar.zst
Improve usability of search on web (#3663)
* dont select the text on web

* TODO REVERT THESE CHANGES

* use `usethrottledvalue` for autocomplete

* use `isFetching` from query

* rm setTimeout

* getting there

* improve functionality of cancel button

* rm todo

* add comment back

* encode `searchText` rather than `queryTerm`

* use "back" on web in some cases

* don't flash results in autocomplete

* remove unnecesary usestate

* rename everything to `query` temporarily

* revert accidental lint

* rm todo

* rm comment

* use `useFocusEffect` to update the query term on back navigation

* `searchText` is always defined here

* Fix race

* remove back functionality

* use `keepPreviousData` for query

* rename `q` to `queryParam`

* remove hack

* remove `q=` on cancel

* blur on submit

* use `setParams` instead of `replace`

* use `replace` on web still

* clear the search input when we clear `q` on native

* onPress dismiss attempt

* Adjustments

* Fix search history

* Always hide autocomplete

* Clear right pane search on select

* `blur` on autosuggestion press

* Rename to reduce diff

* Fixes

* Unify codepaths

* Fixes

* precache the autosuggestion

* do the cache in the link card

* Revert "precache the autosuggestion"

This reverts commit 79c433e984621ba4231a2a4c4b3f4690b0516b4d.

* use `throttledValue` and `keepPreviousData` in sidebar search

* show spinner when fetching pt 1

* show spinner when fetching pt 2

* show spinner properly for autocomplete

* Fix extra border

* Position fixed

* TS

* Revert "TS"

This reverts commit df187ea2d7a96d0f1832bc2392215f4d969a87c9.

* Revert "Position fixed"

This reverts commit 9c721c952b0fa4e5e4a23de38cab916ab13397e6.

* Maybe fix iPad

* Revert "TODO REVERT THESE CHANGES"

This reverts commit 279f717f3091c9df8c73ba35f9a038e12f5a1122.

* Rename var

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
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}
                 />
               ))}
             </>