diff --git a/src/CONST.ts b/src/CONST.ts
index eba68999cc39..9e1a0ba5d22c 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -3301,6 +3301,13 @@ const CONST = {
SCAN: 'scan',
DISTANCE: 'distance',
},
+ TAB_SEARCH: {
+ ALL: 'all',
+ SENT: 'sent',
+ DRAFTS: 'drafts',
+ WAITING_ON_YOU: 'waitingOnYou',
+ FINISHED: 'finished',
+ },
STATUS_TEXT_MAX_LENGTH: 100,
DROPDOWN_BUTTON_SIZE: {
diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index 59d2cd797f73..a9978c49767c 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -22,6 +22,11 @@ const ROUTES = {
ALL_SETTINGS: 'all-settings',
+ SEARCH: {
+ route: '/search/:query',
+ getRoute: (query: string) => `search/${query}` as const,
+ },
+
// This is a utility route used to go to the user's concierge chat, or the sign-in page if the user's not authenticated
CONCIERGE: 'concierge',
FLAG_COMMENT: {
diff --git a/src/SCREENS.ts b/src/SCREENS.ts
index 5ff8b272e56f..a816103f2f80 100644
--- a/src/SCREENS.ts
+++ b/src/SCREENS.ts
@@ -23,6 +23,10 @@ const SCREENS = {
UNLINK_LOGIN: 'UnlinkLogin',
SETTINGS_CENTRAL_PANE: 'SettingsCentralPane',
WORKSPACES_CENTRAL_PANE: 'WorkspacesCentralPane',
+ SEARCH: {
+ CENTRAL_PANE: 'Search_Central_Pane',
+ BOTTOM_TAB: 'Search_Bottom_Tab',
+ },
SETTINGS: {
ROOT: 'Settings_Root',
SHARE_CODE: 'Settings_Share_Code',
diff --git a/src/components/TestToolMenu.tsx b/src/components/TestToolMenu.tsx
index 5efa9592034f..6827dee44141 100644
--- a/src/components/TestToolMenu.tsx
+++ b/src/components/TestToolMenu.tsx
@@ -10,6 +10,7 @@ import * as Network from '@userActions/Network';
import * as Session from '@userActions/Session';
import * as User from '@userActions/User';
import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {Network as NetworkOnyx, User as UserOnyx} from '@src/types/onyx';
@@ -103,6 +104,16 @@ function TestToolMenu({user = USER_DEFAULT, network}: TestToolMenuProps) {
}}
/>
+ {/* Navigate to the new Search Page. This button is temporary and should be removed after passing QA tests. */}
+
+
>
);
}
diff --git a/src/hooks/useActiveRoute.ts b/src/hooks/useActiveRoute.ts
index 651d00a0c37c..afccc28f8243 100644
--- a/src/hooks/useActiveRoute.ts
+++ b/src/hooks/useActiveRoute.ts
@@ -1,7 +1,8 @@
import {useContext} from 'react';
import ActiveRouteContext from '@libs/Navigation/AppNavigator/Navigators/ActiveRouteContext';
+import type {CentralPaneNavigatorParamList, NavigationPartialRoute} from '@libs/Navigation/types';
-function useActiveRoute(): string {
+function useActiveRoute(): NavigationPartialRoute | undefined {
return useContext(ActiveRouteContext);
}
diff --git a/src/libs/Navigation/AppNavigator/Navigators/ActiveRouteContext.ts b/src/libs/Navigation/AppNavigator/Navigators/ActiveRouteContext.ts
index d1d14d43af1a..6d0de3211e7c 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/ActiveRouteContext.ts
+++ b/src/libs/Navigation/AppNavigator/Navigators/ActiveRouteContext.ts
@@ -1,5 +1,6 @@
import React from 'react';
+import type {CentralPaneNavigatorParamList, NavigationPartialRoute} from '@libs/Navigation/types';
-const ActiveRouteContext = React.createContext('');
+const ActiveRouteContext = React.createContext | undefined>(undefined);
export default ActiveRouteContext;
diff --git a/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx
index 87a441f16ddb..6680ea302441 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx
+++ b/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx
@@ -5,6 +5,7 @@ import createCustomBottomTabNavigator from '@libs/Navigation/AppNavigator/create
import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute';
import type {BottomTabNavigatorParamList} from '@libs/Navigation/types';
import SidebarScreen from '@pages/home/sidebar/SidebarScreen';
+import SearchPageBottomTab from '@pages/Search/SearchPageBottomTab';
import SCREENS from '@src/SCREENS';
import ActiveRouteContext from './ActiveRouteContext';
@@ -21,12 +22,16 @@ function BottomTabNavigator() {
const activeRoute = useNavigationState(getTopmostCentralPaneRoute);
return (
-
+
+
();
@@ -41,6 +42,12 @@ function BaseCentralPaneNavigator() {
initialParams={{openOnAdminRoom: openOnAdminRoom === 'true' || undefined}}
component={ReportScreenWrapper}
/>
+
+
{Object.entries(settingsScreens).map(([screenName, componentGetter]) => (
((state) => {
+ const topmostCentralPaneRoute = getTopmostCentralPaneRoute(state);
+
+ if (topmostCentralPaneRoute && topmostCentralPaneRoute.name === SCREENS.SEARCH.CENTRAL_PANE) {
+ return SCREENS.SEARCH.CENTRAL_PANE;
+ }
+
const topmostBottomTabRoute = getTopmostBottomTabRoute(state);
return topmostBottomTabRoute?.name ?? SCREENS.HOME;
});
@@ -95,7 +102,6 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps
-
diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.native.tsx b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.native.tsx
deleted file mode 100644
index 151dd0a0f893..000000000000
--- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.native.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@react-navigation/native';
-import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native';
-import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack';
-import {StackView} from '@react-navigation/stack';
-import React, {useRef} from 'react';
-import useWindowDimensions from '@hooks/useWindowDimensions';
-import CustomRouter from './CustomRouter';
-import type {ResponsiveStackNavigatorProps, ResponsiveStackNavigatorRouterOptions} from './types';
-
-function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) {
- const {isSmallScreenWidth} = useWindowDimensions();
-
- const isSmallScreenWidthRef = useRef(isSmallScreenWidth);
-
- isSmallScreenWidthRef.current = isSmallScreenWidth;
-
- const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder<
- StackNavigationState,
- ResponsiveStackNavigatorRouterOptions,
- StackActionHelpers,
- StackNavigationOptions,
- StackNavigationEventMap
- >(CustomRouter, {
- children: props.children,
- screenOptions: props.screenOptions,
- initialRouteName: props.initialRouteName,
- });
-
- return (
-
-
-
- );
-}
-
-ResponsiveStackNavigator.displayName = 'ResponsiveStackNavigator';
-
-export default createNavigatorFactory, StackNavigationOptions, StackNavigationEventMap, typeof ResponsiveStackNavigator>(ResponsiveStackNavigator);
diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx
index 2a517c45eb0d..29b9b1072d3d 100644
--- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx
+++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx
@@ -3,21 +3,26 @@ import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/na
import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack';
import {StackView} from '@react-navigation/stack';
import React, {useEffect, useMemo} from 'react';
+import {View} from 'react-native';
+import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
+import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute';
import navigationRef from '@libs/Navigation/navigationRef';
+import type {RootStackParamList, State} from '@libs/Navigation/types';
import NAVIGATORS from '@src/NAVIGATORS';
+import SCREENS from '@src/SCREENS';
import CustomRouter from './CustomRouter';
import type {ResponsiveStackNavigatorProps, ResponsiveStackNavigatorRouterOptions} from './types';
type Routes = StackNavigationState['routes'];
-function reduceReportRoutes(routes: Routes): Routes {
+function reduceCentralPaneRoutes(routes: Routes): Routes {
const result: Routes = [];
let count = 0;
const reverseRoutes = [...routes].reverse();
reverseRoutes.forEach((route) => {
if (route.name === NAVIGATORS.CENTRAL_PANE_NAVIGATOR) {
- // Remove all report routes except the last 3. This will improve performance.
+ // Remove all central pane routes except the last 3. This will improve performance.
if (count < 3) {
result.push(route);
count++;
@@ -32,6 +37,7 @@ function reduceReportRoutes(routes: Routes): Routes {
function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) {
const {isSmallScreenWidth} = useWindowDimensions();
+ const styles = useThemeStyles();
const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder<
StackNavigationState,
@@ -52,15 +58,35 @@ function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) {
navigationRef.resetRoot(navigationRef.getRootState());
}, [isSmallScreenWidth]);
- const stateToRender = useMemo(() => {
- const result = reduceReportRoutes(state.routes);
+ const {stateToRender, searchRoute} = useMemo(() => {
+ const routes = reduceCentralPaneRoutes(state.routes);
+
+ const lastRoute = routes[routes.length - 1];
+ const isLastRouteSearchRoute = getTopmostCentralPaneRoute({routes: [lastRoute]} as State)?.name === SCREENS.SEARCH.CENTRAL_PANE;
+
+ const firstRoute = routes[0];
+
+ // On narrow layout, if we are on /search route we want to hide all central pane routes and show only the bottom tab navigator.
+ if (isSmallScreenWidth && isLastRouteSearchRoute) {
+ return {
+ stateToRender: {
+ ...state,
+ index: 0,
+ routes: [firstRoute],
+ },
+ searchRoute: lastRoute,
+ };
+ }
return {
- ...state,
- index: result.length - 1,
- routes: [...result],
+ stateToRender: {
+ ...state,
+ index: routes.length - 1,
+ routes: [...routes],
+ },
+ searchRoute: undefined,
};
- }, [state]);
+ }, [state, isSmallScreenWidth]);
return (
@@ -71,6 +97,7 @@ function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) {
descriptors={descriptors}
navigation={navigation}
/>
+ {searchRoute && {descriptors[searchRoute.key].render()}}
);
}
diff --git a/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts b/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts
index 5732cb93f19c..4c18e161c9a9 100644
--- a/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts
+++ b/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts
@@ -3,20 +3,9 @@ import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRo
import getTopmostFullScreenRoute from '@libs/Navigation/getTopmostFullScreenRoute';
import type {Metainfo} from '@libs/Navigation/linkingConfig/getAdaptedStateFromPath';
import type {NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types';
+import shallowCompare from '@libs/ObjectUtils';
import NAVIGATORS from '@src/NAVIGATORS';
-// eslint-disable-next-line @typescript-eslint/ban-types
-const shallowCompare = (obj1?: object, obj2?: object) => {
- if (!obj1 && !obj2) {
- return true;
- }
- if (obj1 && obj2) {
- // @ts-expect-error we know that obj1 and obj2 are params of a route.
- return Object.keys(obj1).length === Object.keys(obj2).length && Object.keys(obj1).every((key) => obj1[key] === obj2[key]);
- }
- return false;
-};
-
type GetPartialStateDiffReturnType = {
[NAVIGATORS.BOTTOM_TAB_NAVIGATOR]?: NavigationPartialRoute;
[NAVIGATORS.CENTRAL_PANE_NAVIGATOR]?: NavigationPartialRoute;
diff --git a/src/libs/Navigation/linkTo.ts b/src/libs/Navigation/linkTo.ts
index afa8fb56069a..863cb102add4 100644
--- a/src/libs/Navigation/linkTo.ts
+++ b/src/libs/Navigation/linkTo.ts
@@ -2,6 +2,7 @@ import {getActionFromState} from '@react-navigation/core';
import type {NavigationAction, NavigationContainerRef, NavigationState, PartialState} from '@react-navigation/native';
import type {Writable} from 'type-fest';
import getIsNarrowLayout from '@libs/getIsNarrowLayout';
+import shallowCompare from '@libs/ObjectUtils';
import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils';
import CONST from '@src/CONST';
import NAVIGATORS from '@src/NAVIGATORS';
@@ -13,7 +14,6 @@ import getPolicyIDFromState from './getPolicyIDFromState';
import getStateFromPath from './getStateFromPath';
import getTopmostBottomTabRoute from './getTopmostBottomTabRoute';
import getTopmostCentralPaneRoute from './getTopmostCentralPaneRoute';
-import getTopmostReportId from './getTopmostReportId';
import linkingConfig from './linkingConfig';
import getAdaptedStateFromPath from './linkingConfig/getAdaptedStateFromPath';
import getMatchingBottomTabRouteForState from './linkingConfig/getMatchingBottomTabRouteForState';
@@ -152,16 +152,15 @@ export default function linkTo(navigation: NavigationContainerRef = {
[SCREENS.HOME]: [SCREENS.REPORT],
+ [SCREENS.SEARCH.BOTTOM_TAB]: [SCREENS.SEARCH.CENTRAL_PANE],
[SCREENS.SETTINGS.ROOT]: [
SCREENS.SETTINGS.PROFILE.ROOT,
SCREENS.SETTINGS.PREFERENCES.ROOT,
diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts
index bb9f8a31f48d..add3e42c0177 100644
--- a/src/libs/Navigation/linkingConfig/config.ts
+++ b/src/libs/Navigation/linkingConfig/config.ts
@@ -65,6 +65,7 @@ const config: LinkingOptions['config'] = {
exact: true,
},
[SCREENS.SETTINGS.WORKSPACES]: ROUTES.SETTINGS_WORKSPACES,
+ [SCREENS.SEARCH.CENTRAL_PANE]: ROUTES.SEARCH.route,
[SCREENS.SETTINGS.SAVE_THE_WORLD]: ROUTES.SETTINGS_SAVE_THE_WORLD,
},
},
diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts
index d7bcfbb68952..f18637d8e52e 100644
--- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts
+++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts
@@ -319,7 +319,9 @@ function getAdaptedState(state: PartialState
// Routes
// - found bottom tab
// - matching central pane on desktop layout
- if (isNarrowLayout) {
+
+ // We want to make sure that the bottom tab search page is always pushed with matching central pane page. Even on the narrow layout.
+ if (isNarrowLayout && bottomTabNavigator.state?.routes[0].name !== SCREENS.SEARCH.BOTTOM_TAB) {
return {
adaptedState: state,
metainfo,
diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts
index 61cc5e5e9c3a..5aff6ba1cba5 100644
--- a/src/libs/Navigation/types.ts
+++ b/src/libs/Navigation/types.ts
@@ -61,6 +61,9 @@ type CentralPaneNavigatorParamList = {
[SCREENS.SETTINGS.ABOUT]: undefined;
[SCREENS.SETTINGS.TROUBLESHOOT]: undefined;
[SCREENS.SETTINGS.WORKSPACES]: undefined;
+ [SCREENS.SEARCH.CENTRAL_PANE]: {
+ query: string;
+ };
[SCREENS.SETTINGS.SAVE_THE_WORLD]: undefined;
};
@@ -724,6 +727,7 @@ type WelcomeVideoModalNavigatorParamList = {
type BottomTabNavigatorParamList = {
[SCREENS.HOME]: undefined;
+ [SCREENS.SEARCH.BOTTOM_TAB]: undefined;
[SCREENS.SETTINGS.ROOT]: undefined;
};
diff --git a/src/libs/ObjectUtils.ts b/src/libs/ObjectUtils.ts
new file mode 100644
index 000000000000..9ffa461506c8
--- /dev/null
+++ b/src/libs/ObjectUtils.ts
@@ -0,0 +1,13 @@
+// eslint-disable-next-line @typescript-eslint/ban-types
+const shallowCompare = (obj1?: object, obj2?: object) => {
+ if (!obj1 && !obj2) {
+ return true;
+ }
+ if (obj1 && obj2) {
+ // @ts-expect-error we know that obj1 and obj2 are params of a route.
+ return Object.keys(obj1).length === Object.keys(obj2).length && Object.keys(obj1).every((key) => obj1[key] === obj2[key]);
+ }
+ return false;
+};
+
+export default shallowCompare;
diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx
new file mode 100644
index 000000000000..3f69371841ce
--- /dev/null
+++ b/src/pages/Search/SearchPage.tsx
@@ -0,0 +1,23 @@
+import type {StackScreenProps} from '@react-navigation/stack';
+import React from 'react';
+import ScreenWrapper from '@components/ScreenWrapper';
+import type {CentralPaneNavigatorParamList} from '@libs/Navigation/types';
+import type SCREENS from '@src/SCREENS';
+import SearchResults from './SearchResults';
+import useCustomBackHandler from './useCustomBackHandler';
+
+type SearchPageProps = StackScreenProps;
+
+function SearchPage({route}: SearchPageProps) {
+ useCustomBackHandler();
+
+ return (
+
+
+
+ );
+}
+
+SearchPage.displayName = 'SearchPage';
+
+export default SearchPage;
diff --git a/src/pages/Search/SearchPageBottomTab.tsx b/src/pages/Search/SearchPageBottomTab.tsx
new file mode 100644
index 000000000000..62413d743d76
--- /dev/null
+++ b/src/pages/Search/SearchPageBottomTab.tsx
@@ -0,0 +1,68 @@
+import React from 'react';
+import {View} from 'react-native';
+import MenuItem from '@components/MenuItem';
+import ScreenWrapper from '@components/ScreenWrapper';
+import useActiveRoute from '@hooks/useActiveRoute';
+import useSingleExecution from '@hooks/useSingleExecution';
+import useThemeStyles from '@hooks/useThemeStyles';
+import Navigation from '@libs/Navigation/Navigation';
+import * as Expensicons from '@src/components/Icon/Expensicons';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
+import type IconAsset from '@src/types/utils/IconAsset';
+
+type SearchMenuItem = {
+ title: string;
+ icon: IconAsset;
+ action: () => void;
+};
+
+function SearchPageBottomTab() {
+ const styles = useThemeStyles();
+ const {singleExecution} = useSingleExecution();
+ const activeRoute = useActiveRoute();
+ const currentQuery = activeRoute?.params && 'query' in activeRoute.params ? activeRoute?.params?.query : '';
+
+ const searchMenuItems: SearchMenuItem[] = [
+ {
+ title: 'All',
+ icon: Expensicons.ExpensifyLogoNew,
+ action: singleExecution(() => Navigation.navigate(ROUTES.SEARCH.getRoute(CONST.TAB_SEARCH.ALL))),
+ },
+ {
+ title: 'Sent',
+ icon: Expensicons.ExpensifyLogoNew,
+ action: singleExecution(() => Navigation.navigate(ROUTES.SEARCH.getRoute(CONST.TAB_SEARCH.SENT))),
+ },
+ {
+ title: 'Drafts',
+ icon: Expensicons.ExpensifyLogoNew,
+ action: singleExecution(() => Navigation.navigate(ROUTES.SEARCH.getRoute(CONST.TAB_SEARCH.DRAFTS))),
+ },
+ ];
+
+ return (
+
+
+ {searchMenuItems.map((item) => (
+
+ ))}
+
+
+ );
+}
+
+SearchPageBottomTab.displayName = 'SearchPageBottomTab';
+
+export default SearchPageBottomTab;
diff --git a/src/pages/Search/SearchResults.tsx b/src/pages/Search/SearchResults.tsx
new file mode 100644
index 000000000000..261484bc13ec
--- /dev/null
+++ b/src/pages/Search/SearchResults.tsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import Text from '@components/Text';
+import useThemeStyles from '@hooks/useThemeStyles';
+
+type SearchResultsProps = {
+ query: string;
+};
+
+function SearchResults({query}: SearchResultsProps) {
+ const styles = useThemeStyles();
+
+ return Search results for: |{query}| filter;
+}
+
+SearchResults.displayName = 'SearchResults';
+
+export default SearchResults;
diff --git a/src/pages/Search/useCustomBackHandler/index.android.ts b/src/pages/Search/useCustomBackHandler/index.android.ts
new file mode 100644
index 000000000000..f168cb0b9008
--- /dev/null
+++ b/src/pages/Search/useCustomBackHandler/index.android.ts
@@ -0,0 +1,34 @@
+import {StackActions, useFocusEffect} from '@react-navigation/native';
+import {useCallback} from 'react';
+import {BackHandler} from 'react-native';
+import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute';
+import navigationRef from '@libs/Navigation/navigationRef';
+import type {RootStackParamList, State} from '@libs/Navigation/types';
+import NAVIGATORS from '@src/NAVIGATORS';
+import SCREENS from '@src/SCREENS';
+
+// We need to make sure that the central pane screen and bottom tab won't be desynchronized after using the physical back button on Android.
+// To achieve that we will call additional POP on the bottom tab navigator if the search page would disappear from the central pane.
+function useCustomBackHandler() {
+ useFocusEffect(
+ useCallback(() => {
+ const onBackPress = () => {
+ const rootState = navigationRef.getRootState();
+
+ const bottomTabRoute = rootState.routes.find((route) => route.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR);
+ const centralPaneRouteAfterPop = getTopmostCentralPaneRoute({routes: [rootState.routes.at(-2)]} as State);
+
+ if (bottomTabRoute && bottomTabRoute.state && (!centralPaneRouteAfterPop || centralPaneRouteAfterPop.name !== SCREENS.SEARCH.CENTRAL_PANE)) {
+ navigationRef.dispatch({...StackActions.pop(), target: bottomTabRoute.state.key});
+ }
+ return false;
+ };
+
+ const subscription = BackHandler.addEventListener('hardwareBackPress', onBackPress);
+
+ return () => subscription.remove();
+ }, []),
+ );
+}
+
+export default useCustomBackHandler;
diff --git a/src/pages/Search/useCustomBackHandler/index.ts b/src/pages/Search/useCustomBackHandler/index.ts
new file mode 100644
index 000000000000..be753de818a6
--- /dev/null
+++ b/src/pages/Search/useCustomBackHandler/index.ts
@@ -0,0 +1,3 @@
+function useCustomBackHandler() {}
+
+export default useCustomBackHandler;
diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx
index 212bf93166a1..872a6072527e 100644
--- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx
+++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx
@@ -1,4 +1,4 @@
-import {useIsFocused} from '@react-navigation/native';
+import {useIsFocused as useIsFocusedOriginal, useNavigationState} from '@react-navigation/native';
import type {ImageContentFit} from 'expo-image';
import type {ForwardedRef, RefAttributes} from 'react';
import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react';
@@ -15,6 +15,7 @@ import usePrevious from '@hooks/usePrevious';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import interceptAnonymousUser from '@libs/interceptAnonymousUser';
+import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute';
import * as ReportUtils from '@libs/ReportUtils';
import * as App from '@userActions/App';
import * as IOU from '@userActions/IOU';
@@ -24,10 +25,20 @@ import * as Task from '@userActions/Task';
import CONST from '@src/CONST';
import type {TranslationPaths} from '@src/languages/types';
import ONYXKEYS from '@src/ONYXKEYS';
+import SCREENS from '@src/SCREENS';
import type * as OnyxTypes from '@src/types/onyx';
import type {QuickActionName} from '@src/types/onyx/QuickAction';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
+// On small screen we hide the search page from central pane to show the search bottom tab page with bottom tab bar.
+// We need to take this in consideration when checking if the screen is focused.
+const useIsFocused = () => {
+ const {isSmallScreenWidth} = useWindowDimensions();
+ const isFocused = useIsFocusedOriginal();
+ const topmostCentralPane = useNavigationState(getTopmostCentralPaneRoute);
+ return isFocused || (topmostCentralPane?.name === SCREENS.SEARCH.CENTRAL_PANE && isSmallScreenWidth);
+};
+
type PolicySelector = Pick;
type FloatingActionButtonAndPopoverOnyxProps = {
diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx
index edcdd7a9b565..b4d962c0181a 100755
--- a/src/pages/settings/InitialSettingsPage.tsx
+++ b/src/pages/settings/InitialSettingsPage.tsx
@@ -326,7 +326,9 @@ function InitialSettingsPage({session, userWallet, bankAccountList, fundList, wa
hoverAndPressStyle={styles.hoveredComponentBG}
shouldBlockSelection={Boolean(item.link)}
onSecondaryInteraction={item.link ? (event) => openPopover(item.link, event) : undefined}
- focused={!!activeRoute && !!item.routeName && !!(activeRoute.toLowerCase().replaceAll('_', '') === item.routeName.toLowerCase().replaceAll('/', ''))}
+ focused={
+ !!activeRoute?.name && !!item.routeName && !!(activeRoute?.name.toLowerCase().replaceAll('_', '') === item.routeName.toLowerCase().replaceAll('/', ''))
+ }
isPaneMenu
iconRight={item.iconRight}
shouldShowRightIcon={item.shouldShowRightIcon}