Skip to content
Merged
1 change: 1 addition & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6312,6 +6312,7 @@ const CONST = {
ACTIVE_WORKSPACE_ID: 'ACTIVE_WORKSPACE_ID',
RETRY_LAZY_REFRESHED: 'RETRY_LAZY_REFRESHED',
LAST_REFRESH_TIMESTAMP: 'LAST_REFRESH_TIMESTAMP',
LAST_VISITED_SETTINGS_TAB_PATH: 'LAST_VISITED_SETTINGS_TAB_PATH',
},

RESERVATION_TYPE: {
Expand Down
31 changes: 21 additions & 10 deletions src/components/Navigation/BottomTabBar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ import clearSelectedText from '@libs/clearSelectedText/clearSelectedText';
import getPlatform from '@libs/getPlatform';
import interceptAnonymousUser from '@libs/interceptAnonymousUser';
import {getPreservedNavigatorState} from '@libs/Navigation/AppNavigator/createSplitNavigator/usePreserveNavigatorState';
import {getLastVisitedSettingsPath, getLastVisitedWorkspaceScreen, getSettingsTabStateFromSessionStorage} from '@libs/Navigation/helpers/getLastVisitedWorkspace';
import {buildCannedSearchQuery, buildSearchQueryJSON, buildSearchQueryString} from '@libs/SearchQueryUtils';
import type {BrickRoad} from '@libs/WorkspacesSettingsUtils';
import {getChatTabBrickRoad} from '@libs/WorkspacesSettingsUtils';
import {isFullScreenName} from '@navigation/helpers/isNavigatorName';
import {isFullScreenName, isSettingsTabScreenName} from '@navigation/helpers/isNavigatorName';
import Navigation from '@navigation/Navigation';
import navigationRef from '@navigation/navigationRef';
import type {RootNavigatorParamList, SearchFullscreenNavigatorParamList, State, WorkspaceSplitNavigatorParamList} from '@navigation/types';
Expand Down Expand Up @@ -116,7 +117,6 @@ function BottomTabBar({selectedTab, isTooltipAllowed = false}: BottomTabBarProps
const showSettingsPage = useCallback(() => {
const rootState = navigationRef.getRootState();
const topmostFullScreenRoute = rootState.routes.findLast((route) => isFullScreenName(route.name));

if (!topmostFullScreenRoute) {
return;
}
Expand All @@ -134,37 +134,48 @@ function BottomTabBar({selectedTab, isTooltipAllowed = false}: BottomTabBarProps
}

interceptAnonymousUser(() => {
const lastSettingsOrWorkspaceNavigatorRoute = rootState.routes.findLast(
(rootRoute) => rootRoute.name === NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR || rootRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR,
);

const state = getSettingsTabStateFromSessionStorage() ?? rootState;
const lastSettingsOrWorkspaceNavigatorRoute = state.routes.findLast((route) => isSettingsTabScreenName(route.name));
// If there is no settings or workspace navigator route, then we should open the settings navigator.
if (!lastSettingsOrWorkspaceNavigatorRoute) {
Navigation.navigate(ROUTES.SETTINGS);
return;
}

const state = lastSettingsOrWorkspaceNavigatorRoute.state ?? getPreservedNavigatorState(lastSettingsOrWorkspaceNavigatorRoute.key);
let settingsTabState = lastSettingsOrWorkspaceNavigatorRoute.state;
if (!settingsTabState && lastSettingsOrWorkspaceNavigatorRoute.key) {
settingsTabState = getPreservedNavigatorState(lastSettingsOrWorkspaceNavigatorRoute.key);
}

// If there is a workspace navigator route, then we should open the workspace initial screen as it should be "remembered".
if (lastSettingsOrWorkspaceNavigatorRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) {
const params = state?.routes.at(0)?.params as WorkspaceSplitNavigatorParamList[typeof SCREENS.WORKSPACE.INITIAL];

const params = settingsTabState?.routes.at(0)?.params as WorkspaceSplitNavigatorParamList[typeof SCREENS.WORKSPACE.INITIAL];
// Screens of this navigator should always have policyID
if (params.policyID) {
const workspaceScreenName = !shouldUseNarrowLayout ? getLastVisitedWorkspaceScreen() : SCREENS.WORKSPACE.INITIAL;
// This action will put settings split under the workspace split to make sure that we can swipe back to settings split.
navigationRef.dispatch({
type: CONST.NAVIGATION.ACTION_TYPE.OPEN_WORKSPACE_SPLIT,
payload: {
policyID: params.policyID,
screenName: workspaceScreenName,
},
});
}
return;
}

// If the path stored in the session storage leads to a settings screen, we just navigate to it on a wide layout.
// On a small screen, we want to go to the page containing the bottom tab bar (ROUTES.SETTINGS or ROUTES.SETTINGS_WORKSPACES) when changing tabs
if (settingsTabState && !shouldUseNarrowLayout) {
const lastVisitedSettingsRoute = getLastVisitedSettingsPath(settingsTabState);
if (lastVisitedSettingsRoute) {
Navigation.navigate(lastVisitedSettingsRoute);
return;
}
}
// If there is settings workspace screen in the settings navigator, then we should open the settings workspaces as it should be "remembered".
if (state?.routes?.at(-1)?.name === SCREENS.SETTINGS.WORKSPACES) {
if (settingsTabState?.routes?.at(-1)?.name === SCREENS.SETTINGS.WORKSPACES) {
Navigation.navigate(ROUTES.SETTINGS_WORKSPACES.route);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ function handleOpenWorkspaceSplitAction(
});

const actionToPushWorkspaceSplitNavigator = StackActions.push(NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, {
screen: SCREENS.WORKSPACE.INITIAL,
screen: action.payload.screenName,
params: {
policyID: action.payload.policyID,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type {CommonActions, DefaultNavigatorOptions, ParamListBase, StackActionType, StackNavigationState, StackRouterOptions} from '@react-navigation/native';
import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack';
import type {WorkspaceScreenName} from '@libs/Navigation/types';
import type CONST from '@src/CONST';

type RootStackNavigatorActionType =
Expand All @@ -16,6 +17,7 @@ type RootStackNavigatorActionType =
type: typeof CONST.NAVIGATION.ACTION_TYPE.OPEN_WORKSPACE_SPLIT;
payload: {
policyID: string;
screenName: WorkspaceScreenName;
};
};

Expand Down
7 changes: 6 additions & 1 deletion src/libs/Navigation/NavigationRoot.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type {NavigationState} from '@react-navigation/native';
import {DarkTheme, DefaultTheme, findFocusedRoute, NavigationContainer} from '@react-navigation/native';
import type {NavigationState} from '@react-navigation/native';
import React, {useContext, useEffect, useMemo, useRef} from 'react';
import {useOnyx} from 'react-native-onyx';
import {ScrollOffsetContext} from '@components/ScrollOffsetContextProvider';
Expand Down Expand Up @@ -28,6 +28,8 @@ import AppNavigator from './AppNavigator';
import {cleanPreservedNavigatorStates} from './AppNavigator/createSplitNavigator/usePreserveNavigatorState';
import customGetPathFromState from './helpers/customGetPathFromState';
import getAdaptedStateFromPath from './helpers/getAdaptedStateFromPath';
import {saveSettingsTabPathToSessionStorage} from './helpers/getLastVisitedWorkspace';
import {isSettingsTabScreenName} from './helpers/isNavigatorName';
import {linkingConfig} from './linkingConfig';
import Navigation, {navigationRef} from './Navigation';

Expand Down Expand Up @@ -72,6 +74,9 @@ function parseAndLogRoute(state: NavigationState) {
}

Navigation.setIsNavigationReady();
if (isSettingsTabScreenName(state.routes.at(-1)?.name)) {
saveSettingsTabPathToSessionStorage(currentPath);
}

// Fullstory Page navigation tracking
const focusedRouteName = focusedRoute?.name;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type {NavigationState, PartialState} from '@react-navigation/native';
import type {Route} from '@src/ROUTES';

// eslint-disable-next-line @typescript-eslint/no-unused-vars
function saveSettingsTabPathToSessionStorage(url: string) {}

function getSettingsTabStateFromSessionStorage(): PartialState<NavigationState> | undefined {
return undefined;
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
function getLastVisitedSettingsPath(state: NavigationState | PartialState<NavigationState>): Route | undefined {
return undefined;
}

function getLastVisitedWorkspaceScreen() {
return undefined;
}

export {getLastVisitedWorkspaceScreen, getLastVisitedSettingsPath, saveSettingsTabPathToSessionStorage, getSettingsTabStateFromSessionStorage};
37 changes: 37 additions & 0 deletions src/libs/Navigation/helpers/getLastVisitedWorkspace/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type {NavigationState, PartialState} from '@react-navigation/native';
import {findFocusedRoute} from '@react-navigation/native';
import getStateFromPath from '@libs/Navigation/helpers/getStateFromPath';
import CONST from '@src/CONST';
import type {Route} from '@src/ROUTES';

function saveSettingsTabPathToSessionStorage(url: string) {
sessionStorage.setItem(CONST.SESSION_STORAGE_KEYS.LAST_VISITED_SETTINGS_TAB_PATH, url);
}

function getSettingsTabStateFromSessionStorage(): PartialState<NavigationState> | undefined {
const lastVisitedSettingsPath = sessionStorage.getItem(CONST.SESSION_STORAGE_KEYS.LAST_VISITED_SETTINGS_TAB_PATH);
if (!lastVisitedSettingsPath) {
return undefined;
}
return getStateFromPath(lastVisitedSettingsPath as Route);
}

function getWorkspaceScreenNameFromState(state?: PartialState<NavigationState>) {
return state?.routes.at(-1)?.state?.routes.at(-1)?.name;
}

function getLastVisitedSettingsPath(state: NavigationState | PartialState<NavigationState>): Route | undefined {
const lastVisitedSettingsPath = findFocusedRoute(state)?.path;
if (!lastVisitedSettingsPath) {
return undefined;
}
return lastVisitedSettingsPath as Route;
}

function getLastVisitedWorkspaceScreen() {
const settingsState = getSettingsTabStateFromSessionStorage();
const workspaceScreenName = getWorkspaceScreenNameFromState(settingsState);
return workspaceScreenName ?? undefined;
}

export {getLastVisitedWorkspaceScreen, getLastVisitedSettingsPath, saveSettingsTabPathToSessionStorage, getSettingsTabStateFromSessionStorage};
9 changes: 6 additions & 3 deletions src/libs/Navigation/helpers/isNavigatorName.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {SIDEBAR_TO_SPLIT, SPLIT_TO_SIDEBAR} from '@libs/Navigation/linkingConfig/RELATIONS';
import type {FullScreenName, OnboardingFlowName, SplitNavigatorName, SplitNavigatorSidebarScreen} from '@libs/Navigation/types';
import type {FullScreenName, OnboardingFlowName, SettingsTabScreenName, SplitNavigatorName, SplitNavigatorSidebarScreen} from '@libs/Navigation/types';
import NAVIGATORS from '@src/NAVIGATORS';
import SCREENS from '@src/SCREENS';

Expand All @@ -17,6 +17,7 @@ const FULL_SCREENS_SET = new Set([...Object.values(SIDEBAR_TO_SPLIT), NAVIGATORS
const SIDEBARS_SET = new Set(Object.values(SPLIT_TO_SIDEBAR));
const ONBOARDING_SCREENS_SET = new Set(ONBOARDING_SCREENS);
const SPLIT_NAVIGATORS_SET = new Set(Object.values(SIDEBAR_TO_SPLIT));
const SETTINGS_TAB_SET = new Set(Object.values([NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]));

/**
* Functions defined below are used to check whether a screen belongs to a specific group.
Expand Down Expand Up @@ -45,5 +46,7 @@ function isFullScreenName(screen: string | undefined) {
function isSidebarScreenName(screen: string | undefined) {
return checkIfScreenHasMatchingNameToSetValues<SplitNavigatorSidebarScreen>(screen, SIDEBARS_SET);
}

export {isFullScreenName, isOnboardingFlowName, isSidebarScreenName, isSplitNavigatorName};
function isSettingsTabScreenName(screen: string | undefined) {
return checkIfScreenHasMatchingNameToSetValues<SettingsTabScreenName>(screen, SETTINGS_TAB_SET);
}
export {isFullScreenName, isOnboardingFlowName, isSidebarScreenName, isSplitNavigatorName, isSettingsTabScreenName};
6 changes: 6 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1954,6 +1954,10 @@ type SearchFullscreenNavigatorName = typeof NAVIGATORS.SEARCH_FULLSCREEN_NAVIGAT

type FullScreenName = SplitNavigatorName | SearchFullscreenNavigatorName;

type SettingsTabScreenName = typeof NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR | typeof NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR;

type WorkspaceScreenName = keyof WorkspaceSplitNavigatorParamList;

declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace ReactNavigation {
Expand Down Expand Up @@ -2029,4 +2033,6 @@ export type {
WorkspaceConfirmationNavigatorParamList,
TwoFactorAuthNavigatorParamList,
ConsoleNavigatorParamList,
WorkspaceScreenName,
SettingsTabScreenName,
};
Loading