Skip to content

Commit

Permalink
Merge pull request Expensify#42582 from software-mansion-labs/nav/fla…
Browse files Browse the repository at this point in the history
…tten-central-pane

Simplify the RootNavigator structure
  • Loading branch information
mountiny authored Jun 25, 2024
2 parents 65709a2 + becff51 commit 0bcd005
Show file tree
Hide file tree
Showing 43 changed files with 314 additions and 318 deletions.
4 changes: 2 additions & 2 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type {ValueOf} from 'type-fest';
import type CONST from './CONST';
import type {IOUAction, IOUType} from './CONST';
import type {IOURequestType} from './libs/actions/IOU';
import type {CentralPaneNavigatorParamList} from './libs/Navigation/types';
import type {AuthScreensParamList} from './libs/Navigation/types';
import type {SearchQuery} from './types/onyx/SearchResults';
import type AssertTypesNotEqual from './types/utils/AssertTypesNotEqual';

Expand Down Expand Up @@ -37,7 +37,7 @@ const ROUTES = {

SEARCH: {
route: '/search/:query',
getRoute: (searchQuery: SearchQuery, queryParams?: CentralPaneNavigatorParamList['Search_Central_Pane']) => {
getRoute: (searchQuery: SearchQuery, queryParams?: AuthScreensParamList['Search_Central_Pane']) => {
const {sortBy, sortOrder} = queryParams ?? {};

if (!sortBy && !sortOrder) {
Expand Down
4 changes: 2 additions & 2 deletions src/components/ScreenWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import useTackInputFocus from '@hooks/useTackInputFocus';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as Browser from '@libs/Browser';
import type {CentralPaneNavigatorParamList, RootStackParamList} from '@libs/Navigation/types';
import type {AuthScreensParamList, RootStackParamList} from '@libs/Navigation/types';
import toggleTestToolsModal from '@userActions/TestTool';
import CONST from '@src/CONST';
import CustomDevMenu from './CustomDevMenu';
Expand Down Expand Up @@ -95,7 +95,7 @@ type ScreenWrapperProps = {
*
* This is required because transitionEnd event doesn't trigger in the testing environment.
*/
navigation?: StackNavigationProp<RootStackParamList> | StackNavigationProp<CentralPaneNavigatorParamList>;
navigation?: StackNavigationProp<RootStackParamList> | StackNavigationProp<AuthScreensParamList>;

/** Whether to show offline indicator on wide screens */
shouldShowOfflineIndicatorInWideScreen?: boolean;
Expand Down
4 changes: 2 additions & 2 deletions src/components/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import * as ReportUtils from '@libs/ReportUtils';
import * as SearchUtils from '@libs/SearchUtils';
import type {SearchColumnType, SortOrder} from '@libs/SearchUtils';
import Navigation from '@navigation/Navigation';
import type {CentralPaneNavigatorParamList} from '@navigation/types';
import type {AuthScreensParamList} from '@navigation/types';
import EmptySearchView from '@pages/Search/EmptySearchView';
import variables from '@styles/variables';
import CONST from '@src/CONST';
Expand Down Expand Up @@ -50,7 +50,7 @@ function Search({query, policyIDs, sortBy, sortOrder}: SearchProps) {
const {isOffline} = useNetwork();
const styles = useThemeStyles();
const {isLargeScreenWidth} = useWindowDimensions();
const navigation = useNavigation<StackNavigationProp<CentralPaneNavigatorParamList>>();
const navigation = useNavigation<StackNavigationProp<AuthScreensParamList>>();
const lastSearchResultsRef = useRef<OnyxEntry<SearchResults>>();

const getItemHeight = useCallback(
Expand Down
27 changes: 27 additions & 0 deletions src/components/withPrepareCentralPaneScreen/index.native.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type {ComponentType, ForwardedRef, RefAttributes} from 'react';
import React from 'react';
import getComponentDisplayName from '@libs/getComponentDisplayName';
import FreezeWrapper from '@libs/Navigation/FreezeWrapper';

/**
* This HOC is dependent on the platform. On native platforms, screens that aren't already displayed in the navigation stack should be frozen to prevent unnecessary rendering.
* It's handled this way only on mobile platforms because on the web, more than one screen is displayed in a wide layout, so these screens shouldn't be frozen.
*/
export default function withPrepareCentralPaneScreen<TProps, TRef>(
WrappedComponent: ComponentType<TProps & RefAttributes<TRef>>,
): (props: TProps & React.RefAttributes<TRef>) => React.ReactElement | null {
function WithPrepareCentralPaneScreen(props: TProps, ref: ForwardedRef<TRef>) {
return (
<FreezeWrapper>
<WrappedComponent
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
ref={ref}
/>
</FreezeWrapper>
);
}

WithPrepareCentralPaneScreen.displayName = `WithPrepareCentralPaneScreen(${getComponentDisplayName(WrappedComponent)})`;
return React.forwardRef(WithPrepareCentralPaneScreen);
}
9 changes: 9 additions & 0 deletions src/components/withPrepareCentralPaneScreen/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type {ComponentType} from 'react';

/**
* This HOC is dependent on the platform. On native platforms, screens that aren't already displayed in the navigation stack should be frozen to prevent unnecessary rendering.
* It's handled this way only on mobile platforms because on the web, more than one screen is displayed in a wide layout, so these screens shouldn't be frozen.
*/
export default function withPrepareCentralPaneScreen(WrappedComponent: ComponentType) {
return WrappedComponent;
}
4 changes: 2 additions & 2 deletions src/hooks/useActiveRoute.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {useContext} from 'react';
import ActiveRouteContext from '@libs/Navigation/AppNavigator/Navigators/ActiveRouteContext';
import type {CentralPaneNavigatorParamList, NavigationPartialRoute} from '@libs/Navigation/types';
import type {AuthScreensParamList, NavigationPartialRoute} from '@libs/Navigation/types';

function useActiveRoute(): NavigationPartialRoute<keyof CentralPaneNavigatorParamList> | undefined {
function useActiveRoute(): NavigationPartialRoute<keyof AuthScreensParamList> | undefined {
return useContext(ActiveRouteContext);
}

Expand Down
50 changes: 42 additions & 8 deletions src/libs/Navigation/AppNavigator/AuthScreens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, {memo, useEffect, useMemo, useRef} from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import Onyx, {withOnyx} from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import OptionsListContextProvider from '@components/OptionListContextProvider';
import useOnboardingLayout from '@hooks/useOnboardingLayout';
import useStyleUtils from '@hooks/useStyleUtils';
Expand All @@ -14,7 +15,7 @@ import Log from '@libs/Log';
import getCurrentUrl from '@libs/Navigation/currentUrl';
import getOnboardingModalScreenOptions from '@libs/Navigation/getOnboardingModalScreenOptions';
import Navigation from '@libs/Navigation/Navigation';
import type {AuthScreensParamList} from '@libs/Navigation/types';
import type {AuthScreensParamList, CentralPaneName, CentralPaneScreensParamList} from '@libs/Navigation/types';
import NetworkConnection from '@libs/NetworkConnection';
import * as Pusher from '@libs/Pusher/pusher';
import PusherConnectionManager from '@libs/PusherConnectionManager';
Expand Down Expand Up @@ -42,11 +43,11 @@ import SCREENS from '@src/SCREENS';
import type * as OnyxTypes from '@src/types/onyx';
import type {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails';
import type ReactComponentModule from '@src/types/utils/ReactComponentModule';
import CENTRAL_PANE_SCREENS from './CENTRAL_PANE_SCREENS';
import createCustomStackNavigator from './createCustomStackNavigator';
import defaultScreenOptions from './defaultScreenOptions';
import getRootNavigatorScreenOptions from './getRootNavigatorScreenOptions';
import BottomTabNavigator from './Navigators/BottomTabNavigator';
import CentralPaneNavigator from './Navigators/CentralPaneNavigator';
import FeatureTrainingModalNavigator from './Navigators/FeatureTrainingModalNavigator';
import FullScreenNavigator from './Navigators/FullScreenNavigator';
import LeftModalNavigator from './Navigators/LeftModalNavigator';
Expand Down Expand Up @@ -75,6 +76,21 @@ const loadReportAvatar = () => require<ReactComponentModule>('../../../pages/Rep
const loadReceiptView = () => require<ReactComponentModule>('../../../pages/TransactionReceiptPage').default;
const loadWorkspaceJoinUser = () => require<ReactComponentModule>('@pages/workspace/WorkspaceJoinUserPage').default;

function getCentralPaneScreenInitialParams(screenName: CentralPaneName): Partial<ValueOf<CentralPaneScreensParamList>> {
const url = getCurrentUrl();
const openOnAdminRoom = url ? new URL(url).searchParams.get('openOnAdminRoom') : undefined;

if (screenName === SCREENS.SEARCH.CENTRAL_PANE) {
return {sortBy: CONST.SEARCH.TABLE_COLUMNS.DATE, sortOrder: CONST.SEARCH.SORT_ORDER.DESC};
}

if (screenName === SCREENS.REPORT && openOnAdminRoom === 'true') {
return {openOnAdminRoom: true};
}

return undefined;
}

let timezone: Timezone | null;
let currentAccountID = -1;
let isLoadingApp = false;
Expand Down Expand Up @@ -298,20 +314,26 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const CentralPaneScreenOptions = {
headerShown: false,
title: 'New Expensify',

// Prevent unnecessary scrolling
cardStyle: styles.cardStyleNavigator,
};

return (
<OptionsListContextProvider>
<View style={styles.rootNavigatorContainerStyles(isSmallScreenWidth)}>
<RootStack.Navigator isSmallScreenWidth={isSmallScreenWidth}>
<RootStack.Navigator
screenOptions={screenOptions.centralPaneNavigator}
isSmallScreenWidth={isSmallScreenWidth}
>
<RootStack.Screen
name={NAVIGATORS.BOTTOM_TAB_NAVIGATOR}
options={screenOptions.bottomTab}
component={BottomTabNavigator}
/>
<RootStack.Screen
name={NAVIGATORS.CENTRAL_PANE_NAVIGATOR}
options={screenOptions.centralPaneNavigator}
component={CentralPaneNavigator}
/>
<RootStack.Screen
name={SCREENS.VALIDATE_LOGIN}
options={{
Expand Down Expand Up @@ -433,6 +455,18 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie
options={defaultScreenOptions}
component={ConnectionCompletePage}
/>
{Object.entries(CENTRAL_PANE_SCREENS).map(([screenName, componentGetter]) => {
const centralPaneName = screenName as CentralPaneName;
return (
<RootStack.Screen
key={centralPaneName}
name={centralPaneName}
initialParams={getCentralPaneScreenInitialParams(centralPaneName)}
getComponent={componentGetter}
options={CentralPaneScreenOptions}
/>
);
})}
</RootStack.Navigator>
</View>
</OptionsListContextProvider>
Expand Down
22 changes: 22 additions & 0 deletions src/libs/Navigation/AppNavigator/CENTRAL_PANE_SCREENS.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type {CentralPaneName} from '@libs/Navigation/types';
import withPrepareCentralPaneScreen from '@src/components/withPrepareCentralPaneScreen';
import SCREENS from '@src/SCREENS';
import type ReactComponentModule from '@src/types/utils/ReactComponentModule';

type Screens = Partial<Record<CentralPaneName, () => React.ComponentType>>;

const CENTRAL_PANE_SCREENS = {
[SCREENS.SETTINGS.WORKSPACES]: () => withPrepareCentralPaneScreen(require<ReactComponentModule>('../../../pages/workspace/WorkspacesListPage').default),
[SCREENS.SETTINGS.PREFERENCES.ROOT]: () => withPrepareCentralPaneScreen(require<ReactComponentModule>('../../../pages/settings/Preferences/PreferencesPage').default),
[SCREENS.SETTINGS.SECURITY]: () => withPrepareCentralPaneScreen(require<ReactComponentModule>('../../../pages/settings/Security/SecuritySettingsPage').default),
[SCREENS.SETTINGS.PROFILE.ROOT]: () => withPrepareCentralPaneScreen(require<ReactComponentModule>('../../../pages/settings/Profile/ProfilePage').default),
[SCREENS.SETTINGS.WALLET.ROOT]: () => withPrepareCentralPaneScreen(require<ReactComponentModule>('../../../pages/settings/Wallet/WalletPage').default),
[SCREENS.SETTINGS.ABOUT]: () => withPrepareCentralPaneScreen(require<ReactComponentModule>('../../../pages/settings/AboutPage/AboutPage').default),
[SCREENS.SETTINGS.TROUBLESHOOT]: () => withPrepareCentralPaneScreen(require<ReactComponentModule>('../../../pages/settings/Troubleshoot/TroubleshootPage').default),
[SCREENS.SETTINGS.SAVE_THE_WORLD]: () => withPrepareCentralPaneScreen(require<ReactComponentModule>('../../../pages/TeachersUnite/SaveTheWorldPage').default),
[SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: () => withPrepareCentralPaneScreen(require<ReactComponentModule>('../../../pages/settings/Subscription/SubscriptionSettingsPage').default),
[SCREENS.SEARCH.CENTRAL_PANE]: () => withPrepareCentralPaneScreen(require<ReactComponentModule>('../../../pages/Search/SearchPage').default),
[SCREENS.REPORT]: () => withPrepareCentralPaneScreen(require<ReactComponentModule>('./ReportScreenWrapper').default),
} satisfies Screens;

export default CENTRAL_PANE_SCREENS;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import type {CentralPaneNavigatorParamList, NavigationPartialRoute} from '@libs/Navigation/types';
import type {AuthScreensParamList, NavigationPartialRoute} from '@libs/Navigation/types';

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

export default ActiveRouteContext;

This file was deleted.

This file was deleted.

This file was deleted.

4 changes: 2 additions & 2 deletions src/libs/Navigation/AppNavigator/ReportScreenWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type {StackScreenProps} from '@react-navigation/stack';
import React from 'react';
import type {CentralPaneNavigatorParamList} from '@navigation/types';
import type {AuthScreensParamList} from '@navigation/types';
import ReportScreen from '@pages/home/ReportScreen';
import type SCREENS from '@src/SCREENS';
import ReportScreenIDSetter from './ReportScreenIDSetter';

type ReportScreenWrapperProps = StackScreenProps<CentralPaneNavigatorParamList, typeof SCREENS.REPORT>;
type ReportScreenWrapperProps = StackScreenProps<AuthScreensParamList, typeof SCREENS.REPORT>;

function ReportScreenWrapper({route, navigation}: ReportScreenWrapperProps) {
// The ReportScreen without the reportID set will display a skeleton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ 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 isCentralPaneName from '@libs/NavigationUtils';
import {getChatTabBrickRoad} from '@libs/WorkspacesSettingsUtils';
import BottomTabAvatar from '@pages/home/sidebar/BottomTabAvatar';
import BottomTabBarFloatingActionButton from '@pages/home/sidebar/BottomTabBarFloatingActionButton';
Expand Down Expand Up @@ -47,7 +48,7 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps
const currentRoute = routes?.[navigationState?.index ?? 0];
// When we are redirected to the Settings tab from the OldDot, we don't want to call the Welcome.show() method.
// To prevent this, the value of the bottomTabRoute?.name is checked here
if (!!(currentRoute && currentRoute.name !== NAVIGATORS.BOTTOM_TAB_NAVIGATOR && currentRoute.name !== NAVIGATORS.CENTRAL_PANE_NAVIGATOR) || Session.isAnonymousUser()) {
if (!!(currentRoute && currentRoute.name !== NAVIGATORS.BOTTOM_TAB_NAVIGATOR && !isCentralPaneName(currentRoute.name)) || Session.isAnonymousUser()) {
return;
}

Expand Down
Loading

0 comments on commit 0bcd005

Please sign in to comment.