Skip to content

Commit

Permalink
Merge branch 'ideal-nav-merge' into @filip-solecki/ts-workspaceSwitch…
Browse files Browse the repository at this point in the history
…erPage
  • Loading branch information
WojtekBoman committed Feb 1, 2024
2 parents 6a889f1 + 918ae0c commit 4535afc
Show file tree
Hide file tree
Showing 35 changed files with 75 additions and 61 deletions.
2 changes: 2 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ function getUrlWithBackToParam<TUrl extends string>(url: TUrl, backTo?: string):
}

const ROUTES = {
// If the user opens this route, we'll redirect them to the path saved in the last visited path or to the home page if the last visited path is empty.
ROOT: '',

// This route renders the list of reports.
HOME: 'home',

ALL_SETTINGS: 'all-settings',
Expand Down
2 changes: 1 addition & 1 deletion src/components/ContextMenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type ContextMenuItemProps = {
/** Whether the menu item is focused or not */
isFocused?: boolean;

/** Should limit width. */
/** Whether the width should be limited */
shouldLimitWidth?: boolean;
};

Expand Down
8 changes: 4 additions & 4 deletions src/components/FeatureList.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const propTypes = {
ctaAccessibilityLabel: PropTypes.string,

/** Action to call on cta button press */
onCtaPress: PropTypes.func,
onCTAPress: PropTypes.func,

/** A list of menuItems representing the feature list. */
menuItems: PropTypes.arrayOf(PropTypes.shape({...menuItemPropTypes, translationKey: PropTypes.string})).isRequired,
Expand All @@ -48,13 +48,13 @@ const defaultProps = {
ctaText: '',
ctaAccessibilityLabel: '',
subtitle: '',
onCtaPress: () => {},
onCTAPress: () => {},
illustration: null,
illustrationBackgroundColor: '',
illustrationStyle: [],
};

function FeatureList({title, subtitle, ctaText, ctaAccessibilityLabel, onCtaPress, menuItems, illustration, illustrationStyle, illustrationBackgroundColor}) {
function FeatureList({title, subtitle, ctaText, ctaAccessibilityLabel, onCTAPress, menuItems, illustration, illustrationStyle, illustrationBackgroundColor}) {
const styles = useThemeStyles();
const {translate} = useLocalize();

Expand Down Expand Up @@ -91,7 +91,7 @@ function FeatureList({title, subtitle, ctaText, ctaAccessibilityLabel, onCtaPres
</View>
<Button
text={ctaText}
onPress={onCtaPress}
onPress={onCTAPress}
accessibilityLabel={ctaAccessibilityLabel}
style={[styles.w100]}
success
Expand Down
1 change: 1 addition & 0 deletions src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ const AccountSettingsModalStackNavigator = createModalStackNavigator(
},
(styles) => ({cardStyle: styles.navigationScreenCardStyle, headerShown: false}),
);

const WorkspaceSwitcherModalStackNavigator = createModalStackNavigator<WorkspaceSwitcherNavigatorParamList>({
[SCREENS.WORKSPACE_SWITCHER.ROOT]: () => require('../../../pages/WorkspaceSwitcherPage').default as React.ComponentType,
});
Expand Down
2 changes: 1 addition & 1 deletion src/libs/Navigation/AppNavigator/PublicScreens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const RootStack = createStackNavigator<PublicScreensParamList>();
function PublicScreens() {
return (
<RootStack.Navigator>
{/* The structure for the HOME route have to be the same in public and auth screens. That's why we need to wrap the HOME screen with "fake" bottomTabNavigator. */}
{/* The structure for the HOME route has to be the same in public and auth screens. That's why the name for SignInPage is BOTTOM_TAB_NAVIGATOR. */}
<RootStack.Screen
name={NAVIGATORS.BOTTOM_TAB_NAVIGATOR}
options={defaultScreenOptions}
Expand Down
2 changes: 2 additions & 0 deletions src/libs/Navigation/AppNavigator/ReportScreenIDSetter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type ReportScreenIDSetterComponentProps = {
/** The policies which the user has access to */
policies: OnyxCollection<Policy>;

/** Members of all the workspaces the user is member of */
policyMembers: OnyxCollection<PolicyMembers>;

/** Whether user is a new user */
Expand All @@ -25,6 +26,7 @@ type ReportScreenIDSetterComponentProps = {
/** The report metadata */
reportMetadata: OnyxCollection<ReportMetadata>;

/** The accountID of the current user */
accountID?: number;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import interceptAnonymousUser from '@libs/interceptAnonymousUser';
import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute';
import Navigation from '@libs/Navigation/Navigation';
import type {RootStackParamList} from '@libs/Navigation/types';
import {checkIfWorkspaceSettingsTabHasRBR, getChatTabBrickRoad} from '@libs/WorkspacesUtils';
import {checkIfWorkspaceSettingsTabHasRBR, getChatTabBrickRoad} from '@libs/WorkspacesSettingsUtils';
import BottomTabBarFloatingActionButton from '@pages/home/sidebar/BottomTabBarFloatingActionButton';
import variables from '@styles/variables';
import CONST from '@src/CONST';
Expand All @@ -25,7 +25,6 @@ function BottomTabBar() {
const theme = useTheme();
const styles = useThemeStyles();
const {translate} = useLocalize();

const {activeWorkspaceID} = useActiveWorkspace();

// Parent navigator of the bottom tab bar is the root navigator.
Expand All @@ -34,7 +33,7 @@ function BottomTabBar() {
return topmostBottomTabRoute?.name ?? SCREENS.HOME;
});

const showWorkspaceRedBrickRoad = checkIfWorkspaceSettingsTabHasRBR(activeWorkspaceID) && currentTabName === SCREENS.HOME;
const shouldShowWorkspaceRedBrickRoad = checkIfWorkspaceSettingsTabHasRBR(activeWorkspaceID) && currentTabName === SCREENS.HOME;

const chatTabBrickRoad = currentTabName !== SCREENS.HOME ? getChatTabBrickRoad(activeWorkspaceID) : undefined;

Expand Down Expand Up @@ -83,7 +82,7 @@ function BottomTabBar() {
width={variables.iconBottomBar}
height={variables.iconBottomBar}
/>
{showWorkspaceRedBrickRoad && <View style={styles.bottomTabStatusIndicator(theme.danger)} />}
{shouldShowWorkspaceRedBrickRoad && <View style={styles.bottomTabStatusIndicator(theme.danger)} />}
</View>
</PressableWithFeedback>
</Tooltip>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ type CustomNavigatorProps = DefaultNavigatorOptions<ParamListBase, StackNavigati
function getStateToRender(state: StackNavigationState<ParamListBase>): StackNavigationState<ParamListBase> {
const routesToRender = [state.routes.at(-1)] as NavigationStateRoute[];

// We need to render at least one HOME screen to make sure everything load properly.
// We need to render at least one HOME screen to make sure everything load properly. This may be not necessary after changing how IS_SIDEBAR_LOADED is handled.
// Currently this value will be switched only after the first HOME screen is rendered.
if (routesToRender[0].name !== SCREENS.HOME) {
const routeToRender = state.routes.find((route) => route.name === SCREENS.HOME);
if (routeToRender) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function adaptStateIfNecessary(state: StackState) {

// This is necessary for ts to narrow type down to PartialState.
if (state.stale === true) {
// Push the root screen to fill left pane.
// Unshift the root screen to fill left pane.
state.routes.unshift({name: SCREENS.SETTINGS.ROOT});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import SCREENS from '@src/SCREENS';
import CustomFullScreenRouter from './CustomFullScreenRouter';
import type {FullScreenNavigatorProps, FullScreenNavigatorRouterOptions} from './types';

// TODO-IDEAL: Extract to utils with ./createCustomStackNavigator/index.tsx
type Routes = StackNavigationState<ParamListBase>['routes'];
function reduceReportRoutes(routes: Routes): Routes {
const result: Routes = [];
Expand Down Expand Up @@ -60,7 +59,7 @@ function CustomFullScreenNavigator(props: FullScreenNavigatorProps) {
if (!navigationRef.isReady()) {
return;
}
// We need to separetly reset state of this navigator to trigger getRehydratedState.
// We need to separately reset state of this navigator to trigger getRehydratedState.
navigation.reset(navigation.getState());
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isSmallScreenWidth]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ function insertRootRoute(state: State<RootStackParamList>, routeToInsert: Naviga
const nonModalRoutes = state.routes.filter((route) => route.name !== NAVIGATORS.RIGHT_MODAL_NAVIGATOR && route.name !== NAVIGATORS.LEFT_MODAL_NAVIGATOR);
const modalRoutes = state.routes.filter((route) => route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR || route.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR);

// It's safe to modify this state before returning in getRehydratedState.

// @ts-expect-error Updating read only property
// noinspection JSConstantReassignment
state.routes = [...nonModalRoutes, routeToInsert, ...modalRoutes]; // eslint-disable-line
Expand Down Expand Up @@ -48,7 +50,7 @@ function compareAndAdaptState(state: StackNavigationState<RootStackParamList>) {
}

// We will generate a template state and compare the current state with it.
// If there is a differences in the screens that should be visible under the overlay, we will add the screen from templateState to the current state.
// If there is a difference in the screens that should be visible under the overlay, we will add the screen from templateState to the current state.
const pathFromCurrentState = getPathFromState(state, linkingConfig.config);
const {adaptedState: templateState} = getAdaptedStateFromPath(pathFromCurrentState, linkingConfig.config);

Expand Down
10 changes: 10 additions & 0 deletions src/libs/Navigation/AppNavigator/getPartialStateDiff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ type GetPartialStateDiffReturnType = {

/**
* This function returns partial additive diff between the two states.
*
* Example: Let's start with state A on route /r/123. If the screen is wide we will have a HOME opened on bottom tab and REPORT on central pane.
* Now let's say we want to navigate to /workspace/345/overview. We will generate state B from this path.
* State B will have WORKSPACE_INITIAL on the bottom tab and WORKSPACE_OVERVIEW on the central pane.
* Now we will generate partial diff between state A and state B. The diff will tell us that we need to push WORKSPACE_INITIAL on the bottom tab and WORKSPACE_OVERVIEW on the central pane.
*
* Then we can generate actions from this diff and dispatch them to the linkTo function.
*
* It's named partial diff because we don't cover RHP and LHP navigators yet. In the future we can improve this function to handle all navigators to help us clean and simplify the linkTo function.
*
* The partial diff has information which bottom tab, central pane and full screen screens we need to push to go from state to templateState.
* @param state - Current state.
* @param templateState - Desired state generated with getAdaptedStateFromPath.
Expand Down
4 changes: 2 additions & 2 deletions src/libs/Navigation/NavigationRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {updateLastVisitedPath} from '@userActions/App';
import type {Route} from '@src/ROUTES';
import SCREENS from '@src/SCREENS';
import AppNavigator from './AppNavigator';
import getPolicyIdFromState from './getPolicyIdFromState';
import getPolicyIDFromState from './getPolicyIDFromState';
import linkingConfig from './linkingConfig';
import customGetPathFromState from './linkingConfig/customGetPathFromState';
import getAdaptedStateFromPath from './linkingConfig/getAdaptedStateFromPath';
Expand Down Expand Up @@ -118,7 +118,7 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady}: N
if (!state) {
return;
}
const activeWorkspaceID = getPolicyIdFromState(state as NavigationState<RootStackParamList>);
const activeWorkspaceID = getPolicyIDFromState(state as NavigationState<RootStackParamList>);
// Performance optimization to avoid context consumers to delay first render
setTimeout(() => {
currentReportIDValue?.updateCurrentReportID(state);
Expand Down
2 changes: 1 addition & 1 deletion src/libs/Navigation/dismissModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import NAVIGATORS from '@src/NAVIGATORS';
import SCREENS from '@src/SCREENS';
import type {RootStackParamList} from './types';

// This function is in a separate file than Navigation.js to avoid cyclic dependency.
// This function is in a separate file than Navigation.ts to avoid cyclic dependency.

/**
* Dismisses the last modal stack if there is any
Expand Down
8 changes: 4 additions & 4 deletions src/libs/Navigation/dismissModalWithReport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import SCREENS from '@src/SCREENS';
import type {Report} from '@src/types/onyx';
import type {EmptyObject} from '@src/types/utils/EmptyObject';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import getPolicyIdFromState from './getPolicyIdFromState';
import getPolicyIDFromState from './getPolicyIDFromState';
import getStateFromPath from './getStateFromPath';
import getTopmostReportId from './getTopmostReportId';
import linkingConfig from './linkingConfig';
import switchPolicyID from './switchPolicyID';
import type {RootStackParamList, StackNavigationAction, State} from './types';

// This function is in a separate file than Navigation.js to avoid cyclic dependency.
// This function is in a separate file than Navigation.ts to avoid cyclic dependency.

/**
* Dismisses the last modal stack if there is any
Expand All @@ -38,10 +38,10 @@ function dismissModalWithReport(targetReport: Report | EmptyObject, navigationRe
case NAVIGATORS.RIGHT_MODAL_NAVIGATOR:
case SCREENS.NOT_FOUND:
case SCREENS.REPORT_ATTACHMENTS:
// if we are not in the target report, we need to navigate to it after dismissing the modal
// If we are not in the target report, we need to navigate to it after dismissing the modal
if (targetReport.reportID !== getTopmostReportId(state)) {
const reportState = getStateFromPath(ROUTES.REPORT_WITH_ID.getRoute(targetReport.reportID));
const policyID = getPolicyIdFromState(state as State<RootStackParamList>);
const policyID = getPolicyIDFromState(state as State<RootStackParamList>);
const policyMemberAccountIDs = getPolicyMemberAccountIDs(policyID);
const shouldOpenAllWorkspace = isEmptyObject(targetReport) ? true : !doesReportBelongToWorkspace(targetReport, policyMemberAccountIDs, policyID);

Expand Down
8 changes: 4 additions & 4 deletions src/libs/Navigation/getPolicyIdFromState.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import getTopmostBottomTabRoute from './getTopmostBottomTabRoute';
import type {RootStackParamList, State} from './types';

const getPolicyIdFromState = (state: State<RootStackParamList>): string | undefined => {
const getPolicyIDFromState = (state: State<RootStackParamList>): string | undefined => {
const topmostBottomTabRoute = getTopmostBottomTabRoute(state);

const shouldAddPolicyIdToUrl = !!topmostBottomTabRoute && !!topmostBottomTabRoute.params && 'policyID' in topmostBottomTabRoute.params && !!topmostBottomTabRoute.params?.policyID;
const shouldAddPolicyIDToUrl = !!topmostBottomTabRoute && !!topmostBottomTabRoute.params && 'policyID' in topmostBottomTabRoute.params && !!topmostBottomTabRoute.params?.policyID;

if (!shouldAddPolicyIdToUrl) {
if (!shouldAddPolicyIDToUrl) {
return undefined;
}

return topmostBottomTabRoute.params?.policyID as string;
};

export default getPolicyIdFromState;
export default getPolicyIDFromState;
2 changes: 1 addition & 1 deletion src/libs/Navigation/getTopmostReportActionID.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import NAVIGATORS from '@src/NAVIGATORS';
import SCREENS from '@src/SCREENS';
import type {RootStackParamList} from './types';

// This function is in a separate file than Navigation.js to avoid cyclic dependency.
// This function is in a separate file than Navigation.ts to avoid cyclic dependency.

/**
* Find the last visited report screen in the navigation state and get the linked reportActionID of it.
Expand Down
2 changes: 1 addition & 1 deletion src/libs/Navigation/getTopmostReportId.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import NAVIGATORS from '@src/NAVIGATORS';
import SCREENS from '@src/SCREENS';
import type {RootStackParamList} from './types';

// This function is in a separate file than Navigation.js to avoid cyclic dependency.
// This function is in a separate file than Navigation.ts to avoid cyclic dependency.

/**
* Find the last visited report screen in the navigation state and get the id of it.
Expand Down
7 changes: 4 additions & 3 deletions src/libs/Navigation/linkTo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import SCREENS from '@src/SCREENS';
import getActionsFromPartialDiff from './AppNavigator/getActionsFromPartialDiff';
import getPartialStateDiff from './AppNavigator/getPartialStateDiff';
import dismissModal from './dismissModal';
import getPolicyIdFromState from './getPolicyIdFromState';
import getPolicyIDFromState from './getPolicyIDFromState';
import getStateFromPath from './getStateFromPath';
import getTopmostBottomTabRoute from './getTopmostBottomTabRoute';
import getTopmostCentralPaneRoute from './getTopmostCentralPaneRoute';
Expand Down Expand Up @@ -134,8 +134,8 @@ export default function linkTo(navigation: NavigationContainerRef<RootStackParam

// Creating path with /w/ included if necessary.
const extractedPolicyID = extractPolicyIDFromPath(`/${path}`);
const policyIdFromState = getPolicyIdFromState(rootState);
const policyID = extractedPolicyID ?? policyIdFromState;
const policyIDFromState = getPolicyIDFromState(rootState);
const policyID = extractedPolicyID ?? policyIDFromState;

const isWorkspaceSettingsOpened = getTopmostBottomTabRoute(rootState as State<RootStackParamList>)?.name === SCREENS.WORKSPACE.INITIAL && path.includes('workspace');

Expand Down Expand Up @@ -210,6 +210,7 @@ export default function linkTo(navigation: NavigationContainerRef<RootStackParam
}

root.dispatch(actionForBottomTabNavigator);

// If the layout is wide we need to push matching central pane route to the stack.
if (!getIsSmallScreenWidth()) {
// stateFromPath should always include bottom tab navigator state, so getMatchingCentralPaneRouteForState will be always defined.
Expand Down
4 changes: 2 additions & 2 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,9 +466,9 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
[SCREENS.REFERRAL_DETAILS]: ROUTES.REFERRAL_DETAILS_MODAL.route,
},
},
ProcessMoneyRequestHold: {
[SCREENS.RIGHT_MODAL.PROCESS_MONEY_REQUEST_HOLD]: {
screens: {
ProcessMoneyRequestHold_Root: ROUTES.PROCESS_MONEY_REQUEST_HOLD,
[SCREENS.PROCESS_MONEY_REQUEST_HOLD_ROOT]: ROUTES.PROCESS_MONEY_REQUEST_HOLD,
},
},
},
Expand Down
5 changes: 3 additions & 2 deletions src/libs/Navigation/linkingConfig/customGetPathFromState.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {getPathFromState} from '@react-navigation/native';
import _ from 'lodash';
import getPolicyIdFromState from '@libs/Navigation/getPolicyIdFromState';
import getPolicyIDFromState from '@libs/Navigation/getPolicyIDFromState';
import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute';
import type {RootStackParamList, State} from '@libs/Navigation/types';
import SCREENS from '@src/SCREENS';
Expand All @@ -16,9 +16,10 @@ const removePolicyIDParamFromState = (state: State<RootStackParamList>) => {

const customGetPathFromState: typeof getPathFromState = (state, options) => {
const stateWithoutPolicyID = removePolicyIDParamFromState(state as State<RootStackParamList>);

// For the Home page we should remove policyID from the params,
const path = getPathFromState(stateWithoutPolicyID, options);
const policyIDFromState = getPolicyIdFromState(state as State<RootStackParamList>);
const policyIDFromState = getPolicyIDFromState(state as State<RootStackParamList>);
const isWorkspaceSettingsOpened = getTopmostBottomTabRoute(state as State<RootStackParamList>)?.name === SCREENS.WORKSPACE.INITIAL && path.includes('workspace');
return `${policyIDFromState && !isWorkspaceSettingsOpened ? `/w/${policyIDFromState}` : ''}${path}`;
};
Expand Down
Loading

0 comments on commit 4535afc

Please sign in to comment.