Screen for searching user's posts (#7622)
* search user's posts screen * custom placeholder copy if self * navigate to /profile/:handle * add name to title * show header on desktop
This commit is contained in:
@@ -17,7 +17,7 @@ import {
|
||||
} from '@fortawesome/react-native-fontawesome'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useFocusEffect, useNavigation} from '@react-navigation/native'
|
||||
import {useFocusEffect, useNavigation, useRoute} from '@react-navigation/native'
|
||||
|
||||
import {APP_LANGUAGES, LANGUAGES} from '#/lib/../locale/languages'
|
||||
import {createHitslop, HITSLOP_20} from '#/lib/constants'
|
||||
@@ -55,7 +55,7 @@ import {List} from '#/view/com/util/List'
|
||||
import {Text} from '#/view/com/util/text/Text'
|
||||
import {Explore} from '#/view/screens/Search/Explore'
|
||||
import {SearchLinkCard, SearchProfileCard} from '#/view/shell/desktop/Search'
|
||||
import {makeSearchQuery, parseSearchQuery} from '#/screens/Search/utils'
|
||||
import {makeSearchQuery, Params, parseSearchQuery} from '#/screens/Search/utils'
|
||||
import {
|
||||
atoms as a,
|
||||
native,
|
||||
@@ -419,7 +419,13 @@ function SearchLanguageDropdown({
|
||||
)
|
||||
}
|
||||
|
||||
function useQueryManager({initialQuery}: {initialQuery: string}) {
|
||||
function useQueryManager({
|
||||
initialQuery,
|
||||
fixedParams,
|
||||
}: {
|
||||
initialQuery: string
|
||||
fixedParams?: Params
|
||||
}) {
|
||||
const {query, params: initialParams} = React.useMemo(() => {
|
||||
return parseSearchQuery(initialQuery || '')
|
||||
}, [initialQuery])
|
||||
@@ -438,8 +444,9 @@ function useQueryManager({initialQuery}: {initialQuery: string}) {
|
||||
...initialParams,
|
||||
// managed stuff
|
||||
lang,
|
||||
...fixedParams,
|
||||
}),
|
||||
[lang, initialParams],
|
||||
[lang, initialParams, fixedParams],
|
||||
)
|
||||
const handlers = React.useMemo(
|
||||
() => ({
|
||||
@@ -588,16 +595,34 @@ SearchScreenInner = React.memo(SearchScreenInner)
|
||||
export function SearchScreen(
|
||||
props: NativeStackScreenProps<SearchTabNavigatorParams, 'Search'>,
|
||||
) {
|
||||
const queryParam = props.route?.params?.q ?? ''
|
||||
|
||||
return <SearchScreenShell queryParam={queryParam} testID="searchScreen" />
|
||||
}
|
||||
|
||||
export function SearchScreenShell({
|
||||
queryParam,
|
||||
testID,
|
||||
fixedParams,
|
||||
navButton = 'menu',
|
||||
inputPlaceholder,
|
||||
}: {
|
||||
queryParam: string
|
||||
testID: string
|
||||
fixedParams?: Params
|
||||
navButton?: 'back' | 'menu'
|
||||
inputPlaceholder?: string
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const {gtMobile} = useBreakpoints()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const route = useRoute()
|
||||
const textInput = React.useRef<TextInput>(null)
|
||||
const {_} = useLingui()
|
||||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
const {currentAccount} = useSession()
|
||||
|
||||
// Query terms
|
||||
const queryParam = props.route?.params?.q ?? ''
|
||||
const [searchText, setSearchText] = React.useState<string>(queryParam)
|
||||
const {data: autocompleteData, isFetching: isAutocompleteFetching} =
|
||||
useActorAutocompleteQuery(searchText, true)
|
||||
@@ -656,6 +681,7 @@ export function SearchScreen(
|
||||
|
||||
const {params, query, queryWithParams} = useQueryManager({
|
||||
initialQuery: queryParam,
|
||||
fixedParams,
|
||||
})
|
||||
const showFilters = Boolean(queryWithParams && !showAutocomplete)
|
||||
|
||||
@@ -696,13 +722,14 @@ export function SearchScreen(
|
||||
updateSearchHistory(item)
|
||||
|
||||
if (isWeb) {
|
||||
navigation.push('Search', {q: item})
|
||||
// @ts-expect-error route is not typesafe
|
||||
navigation.push(route.name, {...route.params, q: item})
|
||||
} else {
|
||||
textInput.current?.blur()
|
||||
navigation.setParams({q: item})
|
||||
}
|
||||
},
|
||||
[updateSearchHistory, navigation],
|
||||
[updateSearchHistory, navigation, route],
|
||||
)
|
||||
|
||||
const onPressCancelSearch = React.useCallback(() => {
|
||||
@@ -751,13 +778,18 @@ export function SearchScreen(
|
||||
const onSoftReset = React.useCallback(() => {
|
||||
if (isWeb) {
|
||||
// Empty params resets the URL to be /search rather than /search?q=
|
||||
navigation.replace('Search', {})
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const {q: _q, ...parameters} = (route.params ?? {}) as {
|
||||
[key: string]: string
|
||||
}
|
||||
// @ts-expect-error route is not typesafe
|
||||
navigation.replace(route.name, parameters)
|
||||
} else {
|
||||
setSearchText('')
|
||||
navigation.setParams({q: ''})
|
||||
textInput.current?.focus()
|
||||
}
|
||||
}, [navigation])
|
||||
}, [navigation, route])
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
@@ -778,8 +810,10 @@ export function SearchScreen(
|
||||
}
|
||||
}, [setShowAutocomplete])
|
||||
|
||||
const showHeader = !gtMobile || navButton !== 'menu'
|
||||
|
||||
return (
|
||||
<Layout.Screen testID="searchScreen">
|
||||
<Layout.Screen testID={testID}>
|
||||
<View
|
||||
ref={headerRef}
|
||||
onLayout={evt => {
|
||||
@@ -794,14 +828,18 @@ export function SearchScreen(
|
||||
}),
|
||||
]}>
|
||||
<Layout.Center style={t.atoms.bg}>
|
||||
{!gtMobile && (
|
||||
{showHeader && (
|
||||
<View
|
||||
// HACK: shift up search input. we can't remove the top padding
|
||||
// on the search input because it messes up the layout animation
|
||||
// if we add it only when the header is hidden
|
||||
style={{marginBottom: tokens.space.xs * -1}}>
|
||||
<Layout.Header.Outer noBottomBorder>
|
||||
<Layout.Header.MenuButton />
|
||||
{navButton === 'menu' ? (
|
||||
<Layout.Header.MenuButton />
|
||||
) : (
|
||||
<Layout.Header.BackButton />
|
||||
)}
|
||||
<Layout.Header.Content align="left">
|
||||
<Layout.Header.TitleText>
|
||||
<Trans>Search</Trans>
|
||||
@@ -829,7 +867,10 @@ export function SearchScreen(
|
||||
onChangeText={onChangeText}
|
||||
onClearText={onPressClearQuery}
|
||||
onSubmitEditing={onSubmit}
|
||||
placeholder={_(msg`Search for posts, users, or feeds`)}
|
||||
placeholder={
|
||||
inputPlaceholder ??
|
||||
_(msg`Search for posts, users, or feeds`)
|
||||
}
|
||||
hitSlop={{...HITSLOP_20, top: 0}}
|
||||
/>
|
||||
</View>
|
||||
@@ -849,7 +890,7 @@ export function SearchScreen(
|
||||
)}
|
||||
</View>
|
||||
|
||||
{showFilters && gtMobile && (
|
||||
{showFilters && !showHeader && (
|
||||
<View
|
||||
style={[
|
||||
a.flex_row,
|
||||
@@ -870,7 +911,7 @@ export function SearchScreen(
|
||||
|
||||
<View
|
||||
style={{
|
||||
display: showAutocomplete ? 'flex' : 'none',
|
||||
display: showAutocomplete && !fixedParams ? 'flex' : 'none',
|
||||
flex: 1,
|
||||
}}>
|
||||
{searchText.length > 0 ? (
|
||||
|
||||
Reference in New Issue
Block a user