Auto-select search results tab (#9159)
When the user clicks the search button next to "Discover New Feeds" or "Suggested Accounts" on the Explore page, we'll auto-select the respective search results tab (feeds or users).
This commit is contained in:
@@ -67,7 +67,7 @@ export type CommonNavigatorParams = {
|
|||||||
InterestsSettings: undefined
|
InterestsSettings: undefined
|
||||||
AboutSettings: undefined
|
AboutSettings: undefined
|
||||||
AppIconSettings: undefined
|
AppIconSettings: undefined
|
||||||
Search: {q?: string}
|
Search: {q?: string; tab?: 'user' | 'profile' | 'feed'}
|
||||||
Hashtag: {tag: string; author?: string}
|
Hashtag: {tag: string; author?: string}
|
||||||
Topic: {topic: string}
|
Topic: {topic: string}
|
||||||
MessagesConversation: {conversation: string; embed?: string; accept?: true}
|
MessagesConversation: {conversation: string; embed?: string; accept?: true}
|
||||||
@@ -102,7 +102,7 @@ export type HomeTabNavigatorParams = CommonNavigatorParams & {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type SearchTabNavigatorParams = CommonNavigatorParams & {
|
export type SearchTabNavigatorParams = CommonNavigatorParams & {
|
||||||
Search: {q?: string}
|
Search: {q?: string; tab?: 'user' | 'profile' | 'feed'}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NotificationsTabNavigatorParams = CommonNavigatorParams & {
|
export type NotificationsTabNavigatorParams = CommonNavigatorParams & {
|
||||||
@@ -119,7 +119,7 @@ export type MessagesTabNavigatorParams = CommonNavigatorParams & {
|
|||||||
|
|
||||||
export type FlatNavigatorParams = CommonNavigatorParams & {
|
export type FlatNavigatorParams = CommonNavigatorParams & {
|
||||||
Home: undefined
|
Home: undefined
|
||||||
Search: {q?: string}
|
Search: {q?: string; tab?: 'user' | 'profile' | 'feed'}
|
||||||
Feeds: undefined
|
Feeds: undefined
|
||||||
Notifications: undefined
|
Notifications: undefined
|
||||||
Messages: {pushToConversation?: string; animation?: 'push' | 'pop'}
|
Messages: {pushToConversation?: string; animation?: 'push' | 'pop'}
|
||||||
@@ -129,7 +129,7 @@ export type AllNavigatorParams = CommonNavigatorParams & {
|
|||||||
HomeTab: undefined
|
HomeTab: undefined
|
||||||
Home: undefined
|
Home: undefined
|
||||||
SearchTab: undefined
|
SearchTab: undefined
|
||||||
Search: {q?: string}
|
Search: {q?: string; tab?: 'user' | 'profile' | 'feed'}
|
||||||
Feeds: undefined
|
Feeds: undefined
|
||||||
NotificationsTab: undefined
|
NotificationsTab: undefined
|
||||||
Notifications: undefined
|
Notifications: undefined
|
||||||
|
|||||||
@@ -726,7 +726,12 @@ export function Explore({
|
|||||||
<ModuleHeader.SearchButton
|
<ModuleHeader.SearchButton
|
||||||
{...item.searchButton}
|
{...item.searchButton}
|
||||||
onPress={() =>
|
onPress={() =>
|
||||||
focusSearchInput(item.searchButton?.tab || 'user')
|
focusSearchInput(
|
||||||
|
(item.searchButton?.tab || 'user') as
|
||||||
|
| 'user'
|
||||||
|
| 'profile'
|
||||||
|
| 'feed',
|
||||||
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -743,7 +748,12 @@ export function Explore({
|
|||||||
<ModuleHeader.SearchButton
|
<ModuleHeader.SearchButton
|
||||||
{...item.searchButton}
|
{...item.searchButton}
|
||||||
onPress={() =>
|
onPress={() =>
|
||||||
focusSearchInput(item.searchButton?.tab || 'user')
|
focusSearchInput(
|
||||||
|
(item.searchButton?.tab || 'user') as
|
||||||
|
| 'user'
|
||||||
|
| 'profile'
|
||||||
|
| 'feed',
|
||||||
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -30,12 +30,14 @@ let SearchResults = ({
|
|||||||
activeTab,
|
activeTab,
|
||||||
onPageSelected,
|
onPageSelected,
|
||||||
headerHeight,
|
headerHeight,
|
||||||
|
initialPage = 0,
|
||||||
}: {
|
}: {
|
||||||
query: string
|
query: string
|
||||||
queryWithParams: string
|
queryWithParams: string
|
||||||
activeTab: number
|
activeTab: number
|
||||||
onPageSelected: (page: number) => void
|
onPageSelected: (page: number) => void
|
||||||
headerHeight: number
|
headerHeight: number
|
||||||
|
initialPage?: number
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
|
||||||
@@ -89,7 +91,7 @@ let SearchResults = ({
|
|||||||
<TabBar items={sections.map(section => section.title)} {...props} />
|
<TabBar items={sections.map(section => section.title)} {...props} />
|
||||||
</Layout.Center>
|
</Layout.Center>
|
||||||
)}
|
)}
|
||||||
initialPage={0}>
|
initialPage={initialPage}>
|
||||||
{sections.map((section, i) => (
|
{sections.map((section, i) => (
|
||||||
<View key={i}>{section.component}</View>
|
<View key={i}>{section.component}</View>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -190,15 +190,19 @@ export function SearchScreenShell({
|
|||||||
setShowAutocomplete(false)
|
setShowAutocomplete(false)
|
||||||
if (isWeb) {
|
if (isWeb) {
|
||||||
// Empty params resets the URL to be /search rather than /search?q=
|
// Empty params resets the URL to be /search rather than /search?q=
|
||||||
|
// Also clear the tab parameter
|
||||||
const {q: _q, ...parameters} = (route.params ?? {}) as {
|
const {
|
||||||
|
q: _q,
|
||||||
|
tab: _tab,
|
||||||
|
...parameters
|
||||||
|
} = (route.params ?? {}) as {
|
||||||
[key: string]: string
|
[key: string]: string
|
||||||
}
|
}
|
||||||
// @ts-expect-error route is not typesafe
|
// @ts-expect-error route is not typesafe
|
||||||
navigation.replace(route.name, parameters)
|
navigation.replace(route.name, parameters)
|
||||||
} else {
|
} else {
|
||||||
setSearchText('')
|
setSearchText('')
|
||||||
navigation.setParams({q: ''})
|
navigation.setParams({q: '', tab: undefined})
|
||||||
}
|
}
|
||||||
}, [setShowAutocomplete, setSearchText, navigation, route.params, route.name])
|
}, [setShowAutocomplete, setSearchText, navigation, route.params, route.name])
|
||||||
|
|
||||||
@@ -236,15 +240,19 @@ export function SearchScreenShell({
|
|||||||
const onSoftReset = useCallback(() => {
|
const onSoftReset = useCallback(() => {
|
||||||
if (isWeb) {
|
if (isWeb) {
|
||||||
// Empty params resets the URL to be /search rather than /search?q=
|
// Empty params resets the URL to be /search rather than /search?q=
|
||||||
|
// Also clear the tab parameter when soft resetting
|
||||||
const {q: _q, ...parameters} = (route.params ?? {}) as {
|
const {
|
||||||
|
q: _q,
|
||||||
|
tab: _tab,
|
||||||
|
...parameters
|
||||||
|
} = (route.params ?? {}) as {
|
||||||
[key: string]: string
|
[key: string]: string
|
||||||
}
|
}
|
||||||
// @ts-expect-error route is not typesafe
|
// @ts-expect-error route is not typesafe
|
||||||
navigation.replace(route.name, parameters)
|
navigation.replace(route.name, parameters)
|
||||||
} else {
|
} else {
|
||||||
setSearchText('')
|
setSearchText('')
|
||||||
navigation.setParams({q: ''})
|
navigation.setParams({q: '', tab: undefined})
|
||||||
textInput.current?.focus()
|
textInput.current?.focus()
|
||||||
}
|
}
|
||||||
}, [navigation, route])
|
}, [navigation, route])
|
||||||
@@ -268,9 +276,21 @@ export function SearchScreenShell({
|
|||||||
}
|
}
|
||||||
}, [setShowAutocomplete])
|
}, [setShowAutocomplete])
|
||||||
|
|
||||||
const focusSearchInput = useCallback(() => {
|
const focusSearchInput = useCallback(
|
||||||
textInput.current?.focus()
|
(tab?: 'user' | 'profile' | 'feed') => {
|
||||||
}, [])
|
textInput.current?.focus()
|
||||||
|
|
||||||
|
// If a tab is specified, set the tab parameter
|
||||||
|
if (tab) {
|
||||||
|
if (isWeb) {
|
||||||
|
navigation.setParams({...route.params, tab})
|
||||||
|
} else {
|
||||||
|
navigation.setParams({tab})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[navigation, route],
|
||||||
|
)
|
||||||
|
|
||||||
const showHeader = !gtMobile || navButton !== 'menu'
|
const showHeader = !gtMobile || navButton !== 'menu'
|
||||||
|
|
||||||
@@ -421,13 +441,42 @@ let SearchScreenInner = ({
|
|||||||
query: string
|
query: string
|
||||||
queryWithParams: string
|
queryWithParams: string
|
||||||
headerHeight: number
|
headerHeight: number
|
||||||
focusSearchInput: () => void
|
focusSearchInput: (tab?: 'user' | 'profile' | 'feed') => void
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const setMinimalShellMode = useSetMinimalShellMode()
|
const setMinimalShellMode = useSetMinimalShellMode()
|
||||||
const {hasSession} = useSession()
|
const {hasSession} = useSession()
|
||||||
const {gtTablet} = useBreakpoints()
|
const {gtTablet} = useBreakpoints()
|
||||||
const [activeTab, setActiveTab] = useState(0)
|
const route = useRoute()
|
||||||
|
|
||||||
|
// Get tab parameter from route params
|
||||||
|
const tabParam = (
|
||||||
|
route.params as {q?: string; tab?: 'user' | 'profile' | 'feed'}
|
||||||
|
)?.tab
|
||||||
|
|
||||||
|
// Map tab parameter to tab index
|
||||||
|
const getInitialTabIndex = useCallback(() => {
|
||||||
|
if (!tabParam) return 0
|
||||||
|
switch (tabParam) {
|
||||||
|
case 'user':
|
||||||
|
case 'profile':
|
||||||
|
return 2 // People tab
|
||||||
|
case 'feed':
|
||||||
|
return 3 // Feeds tab
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}, [tabParam])
|
||||||
|
|
||||||
|
const [activeTab, setActiveTab] = useState(getInitialTabIndex())
|
||||||
|
|
||||||
|
// Update activeTab when tabParam changes
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
const newTabIndex = getInitialTabIndex()
|
||||||
|
if (newTabIndex !== activeTab) {
|
||||||
|
setActiveTab(newTabIndex)
|
||||||
|
}
|
||||||
|
}, [tabParam, activeTab, getInitialTabIndex])
|
||||||
|
|
||||||
const onPageSelected = useCallback(
|
const onPageSelected = useCallback(
|
||||||
(index: number) => {
|
(index: number) => {
|
||||||
@@ -444,6 +493,7 @@ let SearchScreenInner = ({
|
|||||||
activeTab={activeTab}
|
activeTab={activeTab}
|
||||||
headerHeight={headerHeight}
|
headerHeight={headerHeight}
|
||||||
onPageSelected={onPageSelected}
|
onPageSelected={onPageSelected}
|
||||||
|
initialPage={activeTab}
|
||||||
/>
|
/>
|
||||||
) : hasSession ? (
|
) : hasSession ? (
|
||||||
<Explore focusSearchInput={focusSearchInput} headerHeight={headerHeight} />
|
<Explore focusSearchInput={focusSearchInput} headerHeight={headerHeight} />
|
||||||
|
|||||||
Reference in New Issue
Block a user