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

@ -5,6 +5,7 @@ import {
View,
StyleSheet,
TouchableOpacity,
ActivityIndicator,
} from 'react-native'
import {useNavigation, StackActions} from '@react-navigation/native'
import {
@ -12,7 +13,6 @@ import {
moderateProfile,
ProfileModeration,
} from '@atproto/api'
import {observer} from 'mobx-react-lite'
import {Trans, msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
@ -84,14 +84,15 @@ export function SearchResultCard({
)
}
export const DesktopSearch = observer(function DesktopSearch() {
export function DesktopSearch() {
const {_} = useLingui()
const pal = usePalette('default')
const navigation = useNavigation<NavigationProp>()
const searchDebounceTimeout = React.useRef<NodeJS.Timeout | undefined>(
undefined,
)
const [isInputFocused, setIsInputFocused] = React.useState<boolean>(false)
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[]
@ -104,7 +105,10 @@ export const DesktopSearch = observer(function DesktopSearch() {
async (text: string) => {
setQuery(text)
if (text.length > 0 && isInputFocused) {
if (text.length > 0) {
setIsFetching(true)
setIsActive(true)
if (searchDebounceTimeout.current)
clearTimeout(searchDebounceTimeout.current)
@ -113,24 +117,34 @@ export const DesktopSearch = observer(function DesktopSearch() {
if (results) {
setSearchResults(results)
setIsFetching(false)
}
}, 300)
} else {
if (searchDebounceTimeout.current)
clearTimeout(searchDebounceTimeout.current)
setSearchResults([])
setIsFetching(false)
setIsActive(false)
}
},
[setQuery, isInputFocused, search, setSearchResults],
[setQuery, search, setSearchResults],
)
const onPressCancelSearch = React.useCallback(() => {
onChangeText('')
}, [onChangeText])
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])
}, [query, navigation, setSearchResults])
return (
<View style={[styles.container, pal.view]}>
@ -149,8 +163,6 @@ export const DesktopSearch = observer(function DesktopSearch() {
returnKeyType="search"
value={query}
style={[pal.textLight, styles.input]}
onFocus={() => setIsInputFocused(true)}
onBlur={() => setIsInputFocused(false)}
onChangeText={onChangeText}
onSubmitEditing={onSubmit}
accessibilityRole="search"
@ -174,29 +186,37 @@ export const DesktopSearch = observer(function DesktopSearch() {
</View>
</View>
{query !== '' && (
{query !== '' && isActive && moderationOpts && (
<View style={[pal.view, pal.borderDark, styles.resultsContainer]}>
{searchResults.length && moderationOpts ? (
searchResults.map((item, i) => (
<SearchResultCard
key={item.did}
profile={item}
moderation={moderateProfile(item, moderationOpts)}
style={i === 0 ? {borderTopWidth: 0} : {}}
/>
))
) : (
<View>
<Text style={[pal.textLight, styles.noResults]}>
<Trans>No results found for {query}</Trans>
</Text>
{isFetching ? (
<View style={{padding: 8}}>
<ActivityIndicator />
</View>
) : (
<>
{searchResults.length ? (
searchResults.map((item, i) => (
<SearchResultCard
key={item.did}
profile={item}
moderation={moderateProfile(item, moderationOpts)}
style={i === 0 ? {borderTopWidth: 0} : {}}
/>
))
) : (
<View>
<Text style={[pal.textLight, styles.noResults]}>
<Trans>No results found for {query}</Trans>
</Text>
</View>
)}
</>
)}
</View>
)}
</View>
)
})
}
const styles = StyleSheet.create({
container: {