Skip to content

[Navigation] Settings - The last visited screen in the settings tab is not saved after refresh #59331

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

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