Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Search v1] Implement Search navigation logic #40280

Merged
merged 30 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c96e516
migrate search page to find page v1
adamgrzybowski Apr 5, 2024
1e5150b
add new search tab
adamgrzybowski Apr 5, 2024
eef26cc
Add search page template components
WojtekBoman Apr 8, 2024
3c74507
Add new search pages
WojtekBoman Apr 9, 2024
a707c28
remove native.tsx for createCustomStackNavigator
adamgrzybowski Apr 10, 2024
3afd0b9
add check for search page in getAdaptedStateFromPath
adamgrzybowski Apr 10, 2024
2206c1d
Handle passing params to useActiveRoute
WojtekBoman Apr 10, 2024
e7de7ea
Merge branch 'new-search-tab' into new-search-tab-poc
WojtekBoman Apr 10, 2024
b9d88d9
Merge pull request #85 from software-mansion-labs/new-search-tab-poc
WojtekBoman Apr 10, 2024
a1b228a
Adjust getAdaptedStateFromPath to new search routes
WojtekBoman Apr 10, 2024
a72d221
fix linnkTo
adamgrzybowski Apr 10, 2024
633d881
remove waitForNavigation and OnyxTabNavigator from SearchPageBottomTab
adamgrzybowski Apr 10, 2024
2d78c11
remove waitForNavigation and OnyxTabNavigator from SearchPageBottomTa…
adamgrzybowski Apr 10, 2024
b57d456
add customBackHandler
adamgrzybowski Apr 10, 2024
2fcae18
remove unused imports
adamgrzybowski Apr 10, 2024
18ed94f
Merge branch 'main' into new-search-tab
WojtekBoman Apr 16, 2024
1de5ce3
Add a tooltip for the search icon in the bottom tab
WojtekBoman Apr 16, 2024
f84911b
Add SEARCH_QUERIES consts, hide new features
WojtekBoman Apr 16, 2024
8ea25e3
Remove SEARCH_QUERIES const
WojtekBoman Apr 16, 2024
5ea4a9f
Remove test page
WojtekBoman Apr 16, 2024
2e38d66
add comment for useCustomBackHandler
adamgrzybowski Apr 16, 2024
f724761
Exclude shallowCompare function
WojtekBoman Apr 16, 2024
f28c388
Merge branch 'main' into search-v1/nav-logic
WojtekBoman Apr 17, 2024
1b33065
Remove redundant const
WojtekBoman Apr 17, 2024
39a308a
Remove test code from TabSelector
WojtekBoman Apr 17, 2024
0c538bb
Refactor createCustomStackNavigator
WojtekBoman Apr 17, 2024
3cb9dbe
Refactor search pages
WojtekBoman Apr 17, 2024
faf9a69
Remove unused code
WojtekBoman Apr 17, 2024
87a4076
Remove unused code
WojtekBoman Apr 17, 2024
3b7a83d
Handle displaying FAB on the new search page
WojtekBoman Apr 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
10 changes: 10 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ const ROUTES = {

ALL_SETTINGS: 'all-settings',

SEARCH: {
route: '/search/:query',
getRoute: (query: string) => `search/${query}` as const,
},

SEARCH_REPORT: {
route: '/search/:query/view/:reportID',
getRoute: (query: string, reportID: string) => `search/${query}/view/${reportID}` 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: {
Expand Down
6 changes: 6 additions & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ const SCREENS = {
UNLINK_LOGIN: 'UnlinkLogin',
SETTINGS_CENTRAL_PANE: 'SettingsCentralPane',
WORKSPACES_CENTRAL_PANE: 'WorkspacesCentralPane',
SEARCH: {
CENTRAL_PANE: 'Search_Central_Pane',
REPORT: 'Search_Report',
BOTTOM_TAB: 'Search_Bottom_Tab',
},
SETTINGS: {
ROOT: 'Settings_Root',
SHARE_CODE: 'Settings_Share_Code',
Expand Down Expand Up @@ -127,6 +132,7 @@ const SCREENS = {
ROOM_INVITE: 'RoomInvite',
REFERRAL: 'Referral',
PROCESS_MONEY_REQUEST_HOLD: 'ProcessMoneyRequestHold',
SEARCH_REPORT: 'Search_Report',
},
ONBOARDING_MODAL: {
ONBOARDING: 'Onboarding',
Expand Down
10 changes: 10 additions & 0 deletions src/components/TabSelector/TabSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ function getIconAndTitle(route: string, translate: LocaleContextProps['translate
return {icon: Expensicons.Hashtag, title: translate('tabSelector.room')};
case CONST.TAB_REQUEST.DISTANCE:
return {icon: Expensicons.Car, title: translate('common.distance')};
case CONST.TAB_SEARCH.ALL:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was only for the POC with onyxTab I assume

return {icon: Expensicons.ExpensifyLogoNew, title: 'All'};
case CONST.TAB_SEARCH.SENT:
return {icon: Expensicons.ExpensifyLogoNew, title: 'Sent'};
case CONST.TAB_SEARCH.DRAFTS:
return {icon: Expensicons.ExpensifyLogoNew, title: 'Drafts'};
case CONST.TAB_SEARCH.WAITING_ON_YOU:
return {icon: Expensicons.ExpensifyLogoNew, title: 'Waiting on you'};
case CONST.TAB_SEARCH.FINISHED:
return {icon: Expensicons.ExpensifyLogoNew, title: 'Finished'};
default:
throw new Error(`Route ${route} has no icon nor title set.`);
}
Expand Down
11 changes: 11 additions & 0 deletions src/components/TestToolMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -103,6 +104,16 @@ function TestToolMenu({user = USER_DEFAULT, network}: TestToolMenuProps) {
}}
/>
</TestToolRow>
{/* Navigate to the new Search Page. This button is temporary and should be removed after passing QA tests. */}
<TestToolRow title="New Search Page">
<Button
small
text="Navigate"
onPress={() => {
Navigation.navigate(ROUTES.SEARCH.getRoute(CONST.TAB_SEARCH.ALL));
}}
/>
</TestToolRow>
</>
);
}
Expand Down
3 changes: 2 additions & 1 deletion src/hooks/useActiveRoute.ts
Original file line number Diff line number Diff line change
@@ -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<keyof CentralPaneNavigatorParamList> | undefined {
return useContext(ActiveRouteContext);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import type {
ReportSettingsNavigatorParamList,
RoomInviteNavigatorParamList,
RoomMembersNavigatorParamList,
SearchReportParamList,
SettingsNavigatorParamList,
SignInNavigatorParamList,
SplitDetailsNavigatorParamList,
Expand Down Expand Up @@ -147,6 +148,10 @@ const RoomInviteModalStackNavigator = createModalStackNavigator<RoomInviteNaviga
[SCREENS.ROOM_INVITE_ROOT]: () => require('../../../../pages/RoomInvitePage').default as React.ComponentType,
});

const SearchReportModalStackNavigator = createModalStackNavigator<SearchReportParamList>({
[SCREENS.SEARCH.REPORT]: () => require('../../../../pages/home/ReportScreen').default as React.ComponentType,
});

const ChatFinderModalStackNavigator = createModalStackNavigator<ChatFinderNavigatorParamList>({
[SCREENS.CHAT_FINDER_ROOT]: () => require('../../../../pages/ChatFinderPage').default as React.ComponentType,
});
Expand Down Expand Up @@ -350,4 +355,5 @@ export {
WalletStatementStackNavigator,
ProcessMoneyRequestHoldStackNavigator,
WorkspaceSettingsModalStackNavigator,
SearchReportModalStackNavigator,
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import type {CentralPaneNavigatorParamList, NavigationPartialRoute} from '@libs/Navigation/types';

const ActiveRouteContext = React.createContext('');
const ActiveRouteContext = React.createContext<NavigationPartialRoute<keyof CentralPaneNavigatorParamList> | undefined>(undefined);

export default ActiveRouteContext;
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -21,12 +22,16 @@ function BottomTabNavigator() {
const activeRoute = useNavigationState(getTopmostCentralPaneRoute);

return (
<ActiveRouteContext.Provider value={activeRoute?.name ?? ''}>
<ActiveRouteContext.Provider value={activeRoute}>
<Tab.Navigator screenOptions={screenOptions}>
<Tab.Screen
name={SCREENS.HOME}
component={SidebarScreen}
/>
<Tab.Screen
name={SCREENS.SEARCH.BOTTOM_TAB}
component={SearchPageBottomTab}
/>
<Tab.Screen
name={SCREENS.SETTINGS.ROOT}
getComponent={loadInitialSettingsPage}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
import ReportScreenWrapper from '@libs/Navigation/AppNavigator/ReportScreenWrapper';
import getCurrentUrl from '@libs/Navigation/currentUrl';
import type {CentralPaneNavigatorParamList} from '@navigation/types';
import SearchPage from '@pages/Search/SearchPage';
import SCREENS from '@src/SCREENS';

const Stack = createStackNavigator<CentralPaneNavigatorParamList>();
Expand Down Expand Up @@ -41,6 +42,12 @@ function BaseCentralPaneNavigator() {
initialParams={{openOnAdminRoom: openOnAdminRoom === 'true' || undefined}}
component={ReportScreenWrapper}
/>
<Stack.Screen
name={SCREENS.SEARCH.CENTRAL_PANE}
// We do it this way to avoid adding the url params to url
component={SearchPage}
/>

{Object.entries(settingsScreens).map(([screenName, componentGetter]) => (
<Stack.Screen
key={screenName}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ function RightModalNavigator({navigation}: RightModalNavigatorProps) {
name="ProcessMoneyRequestHold"
component={ModalStackNavigators.ProcessMoneyRequestHoldStackNavigator}
/>
<Stack.Screen
name={SCREENS.RIGHT_MODAL.SEARCH_REPORT}
component={ModalStackNavigators.SearchReportModalStackNavigator}
/>
</Stack.Navigator>
</View>
</NoDropZone>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import * as Session from '@libs/actions/Session';
import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute';
import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute';
import Navigation from '@libs/Navigation/Navigation';
import type {RootStackParamList, State} from '@libs/Navigation/types';
import {getChatTabBrickRoad} from '@libs/WorkspacesSettingsUtils';
Expand Down Expand Up @@ -64,6 +65,12 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps

// Parent navigator of the bottom tab bar is the root navigator.
const currentTabName = useNavigationState<RootStackParamList, string | undefined>((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;
});
Expand Down Expand Up @@ -95,7 +102,27 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps
</View>
</PressableWithFeedback>
</Tooltip>

{/** @TODO: Uncomment this code and change order of the items according to the designs once the new search tab is ready */}
{/* <Tooltip text={translate('common.search')}>
<PressableWithFeedback
onPress={() => {
Navigation.navigate(ROUTES.SEARCH.getRoute(CONST.TAB_SEARCH.ALL));
}}
role={CONST.ROLE.BUTTON}
accessibilityLabel={translate('common.search')}
wrapperStyle={styles.flex1}
style={styles.bottomTabBarItem}
>
<View>
<Icon
src={Expensicons.ReceiptSearch}
fill={currentTabName === SCREENS.SEARCH.CENTRAL_PANE ? theme.iconMenu : theme.icon}
width={variables.iconBottomBar}
height={variables.iconBottomBar}
/>
</View>
</PressableWithFeedback>
</Tooltip> */}
<BottomTabBarFloatingActionButton />
<BottomTabAvatar isSelected={currentTabName === SCREENS.SETTINGS.ROOT} />
</View>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,25 @@ 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 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<ParamListBase>['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++;
Expand Down Expand Up @@ -52,15 +56,34 @@ 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<RootStackParamList>)?.name === SCREENS.SEARCH.CENTRAL_PANE;

const firstRoute = routes[0];

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's add comment here

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 (
<NavigationContent>
Expand All @@ -71,6 +94,7 @@ function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) {
descriptors={descriptors}
navigation={navigation}
/>
{searchRoute && <View style={{display: 'none'}}>{descriptors[searchRoute.key].render()}</View>}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's extract this style

</NavigationContent>
);
}
Expand Down
13 changes: 1 addition & 12 deletions src/libs/Navigation/AppNavigator/getPartialStateDiff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading
Loading