From 877d9564cc474a9cfee43682fdff68577d5651a6 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Sat, 8 Mar 2025 22:29:33 +0700 Subject: [PATCH 1/5] fix: opened tab/status is not preserved after switching between pages --- .../Navigation/BottomTabBar/index.tsx | 31 +++++++++++++++++-- src/libs/Navigation/helpers/linkTo/index.ts | 1 + 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/components/Navigation/BottomTabBar/index.tsx b/src/components/Navigation/BottomTabBar/index.tsx index 148a3b3b8338..a826e1869de9 100644 --- a/src/components/Navigation/BottomTabBar/index.tsx +++ b/src/components/Navigation/BottomTabBar/index.tsx @@ -18,14 +18,14 @@ import useThemeStyles from '@hooks/useThemeStyles'; import clearSelectedText from '@libs/clearSelectedText/clearSelectedText'; import getPlatform from '@libs/getPlatform'; import interceptAnonymousUser from '@libs/interceptAnonymousUser'; -import {buildCannedSearchQuery} from '@libs/SearchQueryUtils'; +import {buildCannedSearchQuery, buildSearchQueryJSON, buildSearchQueryString} from '@libs/SearchQueryUtils'; import type {BrickRoad} from '@libs/WorkspacesSettingsUtils'; import {getChatTabBrickRoad} from '@libs/WorkspacesSettingsUtils'; import {getPreservedSplitNavigatorState} from '@navigation/AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState'; import {isFullScreenName} from '@navigation/helpers/isNavigatorName'; import Navigation from '@navigation/Navigation'; import navigationRef from '@navigation/navigationRef'; -import type {WorkspaceSplitNavigatorParamList} from '@navigation/types'; +import type {RootNavigatorParamList, SearchFullscreenNavigatorParamList, State, WorkspaceSplitNavigatorParamList} from '@navigation/types'; import BottomTabAvatar from '@pages/home/sidebar/BottomTabAvatar'; import BottomTabBarFloatingActionButton from '@pages/home/sidebar/BottomTabBarFloatingActionButton'; import variables from '@styles/variables'; @@ -79,6 +79,33 @@ function BottomTabBar({selectedTab, isTooltipAllowed = false}: BottomTabBarProps clearSelectedText(); interceptAnonymousUser(() => { const defaultCannedQuery = buildCannedSearchQuery(); + + const rootState = navigationRef.getRootState() as State; + const lastSearchNavigator = rootState.routes.findLast((route) => route.name === NAVIGATORS.SEARCH_FULLSCREEN_NAVIGATOR); + const lastSearchRoute = lastSearchNavigator?.state?.routes.findLast((route) => route.name === SCREENS.SEARCH.ROOT); + + if (lastSearchRoute) { + const {q, ...rest} = lastSearchRoute.params as SearchFullscreenNavigatorParamList[typeof SCREENS.SEARCH.ROOT]; + const queryJSON = buildSearchQueryJSON(q); + if (queryJSON) { + queryJSON.policyID = activeWorkspaceID; + const query = buildSearchQueryString(queryJSON); + Navigation.navigate( + ROUTES.SEARCH_ROOT.getRoute({ + query, + ...rest, + }), + ); + } else { + Navigation.navigate( + ROUTES.SEARCH_ROOT.getRoute({ + query: q, + ...rest, + }), + ); + } + return; + } // when navigating to search we might have an activePolicyID set from workspace switcher const query = activeWorkspaceID ? `${defaultCannedQuery} ${CONST.SEARCH.SYNTAX_ROOT_KEYS.POLICY_ID}:${activeWorkspaceID}` : defaultCannedQuery; Navigation.navigate(ROUTES.SEARCH_ROOT.getRoute({query})); diff --git a/src/libs/Navigation/helpers/linkTo/index.ts b/src/libs/Navigation/helpers/linkTo/index.ts index 549a507458b2..b8ed9219f252 100644 --- a/src/libs/Navigation/helpers/linkTo/index.ts +++ b/src/libs/Navigation/helpers/linkTo/index.ts @@ -150,6 +150,7 @@ export default function linkTo(navigation: NavigationContainerRef Date: Sat, 8 Mar 2025 22:33:50 +0700 Subject: [PATCH 2/5] remove log --- src/libs/Navigation/helpers/linkTo/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/Navigation/helpers/linkTo/index.ts b/src/libs/Navigation/helpers/linkTo/index.ts index b8ed9219f252..549a507458b2 100644 --- a/src/libs/Navigation/helpers/linkTo/index.ts +++ b/src/libs/Navigation/helpers/linkTo/index.ts @@ -150,7 +150,6 @@ export default function linkTo(navigation: NavigationContainerRef Date: Sat, 8 Mar 2025 22:37:37 +0700 Subject: [PATCH 3/5] fix prettier --- src/components/Navigation/BottomTabBar/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Navigation/BottomTabBar/index.tsx b/src/components/Navigation/BottomTabBar/index.tsx index a826e1869de9..76192681bace 100644 --- a/src/components/Navigation/BottomTabBar/index.tsx +++ b/src/components/Navigation/BottomTabBar/index.tsx @@ -83,7 +83,7 @@ function BottomTabBar({selectedTab, isTooltipAllowed = false}: BottomTabBarProps const rootState = navigationRef.getRootState() as State; const lastSearchNavigator = rootState.routes.findLast((route) => route.name === NAVIGATORS.SEARCH_FULLSCREEN_NAVIGATOR); const lastSearchRoute = lastSearchNavigator?.state?.routes.findLast((route) => route.name === SCREENS.SEARCH.ROOT); - + if (lastSearchRoute) { const {q, ...rest} = lastSearchRoute.params as SearchFullscreenNavigatorParamList[typeof SCREENS.SEARCH.ROOT]; const queryJSON = buildSearchQueryJSON(q); From dff16ed5ed1695dd0f191ea70d68188ff7f96103 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Mon, 10 Mar 2025 14:50:26 +0700 Subject: [PATCH 4/5] remove unused code --- src/components/Navigation/BottomTabBar/index.tsx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/components/Navigation/BottomTabBar/index.tsx b/src/components/Navigation/BottomTabBar/index.tsx index 76192681bace..7deb53ecab00 100644 --- a/src/components/Navigation/BottomTabBar/index.tsx +++ b/src/components/Navigation/BottomTabBar/index.tsx @@ -96,15 +96,8 @@ function BottomTabBar({selectedTab, isTooltipAllowed = false}: BottomTabBarProps ...rest, }), ); - } else { - Navigation.navigate( - ROUTES.SEARCH_ROOT.getRoute({ - query: q, - ...rest, - }), - ); + return; } - return; } // when navigating to search we might have an activePolicyID set from workspace switcher const query = activeWorkspaceID ? `${defaultCannedQuery} ${CONST.SEARCH.SYNTAX_ROOT_KEYS.POLICY_ID}:${activeWorkspaceID}` : defaultCannedQuery; From 7c2970f2a3804ac02d43cc248fd4d7d03fc48a4c Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Mon, 10 Mar 2025 18:02:17 +0700 Subject: [PATCH 5/5] update preserve state for search full navigator --- .../Navigation/BottomTabBar/index.tsx | 7 +++-- .../Navigators/SearchFullscreenNavigator.tsx | 10 +++---- .../createSearchFullscreenNavigator/index.tsx | 2 ++ .../createSplitNavigator/SplitRouter.ts | 6 ++-- .../createSplitNavigator/index.tsx | 4 +-- .../usePreserveNavigatorState.ts | 29 +++++++++++++++++++ .../usePreserveSplitNavigatorState.ts | 29 ------------------- src/libs/Navigation/NavigationRoot.tsx | 4 +-- src/pages/home/sidebar/BaseSidebarScreen.tsx | 4 +-- 9 files changed, 49 insertions(+), 46 deletions(-) create mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/usePreserveNavigatorState.ts delete mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState.ts diff --git a/src/components/Navigation/BottomTabBar/index.tsx b/src/components/Navigation/BottomTabBar/index.tsx index 7deb53ecab00..ec8308a4218e 100644 --- a/src/components/Navigation/BottomTabBar/index.tsx +++ b/src/components/Navigation/BottomTabBar/index.tsx @@ -18,10 +18,10 @@ import useThemeStyles from '@hooks/useThemeStyles'; 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 {buildCannedSearchQuery, buildSearchQueryJSON, buildSearchQueryString} from '@libs/SearchQueryUtils'; import type {BrickRoad} from '@libs/WorkspacesSettingsUtils'; import {getChatTabBrickRoad} from '@libs/WorkspacesSettingsUtils'; -import {getPreservedSplitNavigatorState} from '@navigation/AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState'; import {isFullScreenName} from '@navigation/helpers/isNavigatorName'; import Navigation from '@navigation/Navigation'; import navigationRef from '@navigation/navigationRef'; @@ -82,7 +82,8 @@ function BottomTabBar({selectedTab, isTooltipAllowed = false}: BottomTabBarProps const rootState = navigationRef.getRootState() as State; const lastSearchNavigator = rootState.routes.findLast((route) => route.name === NAVIGATORS.SEARCH_FULLSCREEN_NAVIGATOR); - const lastSearchRoute = lastSearchNavigator?.state?.routes.findLast((route) => route.name === SCREENS.SEARCH.ROOT); + const lastSearchNavigatorState = lastSearchNavigator && lastSearchNavigator.key ? getPreservedNavigatorState(lastSearchNavigator?.key) : undefined; + const lastSearchRoute = lastSearchNavigatorState?.routes.findLast((route) => route.name === SCREENS.SEARCH.ROOT); if (lastSearchRoute) { const {q, ...rest} = lastSearchRoute.params as SearchFullscreenNavigatorParamList[typeof SCREENS.SEARCH.ROOT]; @@ -142,7 +143,7 @@ function BottomTabBar({selectedTab, isTooltipAllowed = false}: BottomTabBarProps return; } - const state = lastSettingsOrWorkspaceNavigatorRoute.state ?? getPreservedSplitNavigatorState(lastSettingsOrWorkspaceNavigatorRoute.key); + const state = lastSettingsOrWorkspaceNavigatorRoute.state ?? 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) { diff --git a/src/libs/Navigation/AppNavigator/Navigators/SearchFullscreenNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/SearchFullscreenNavigator.tsx index 4f8e4478e189..9f06a946c80a 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/SearchFullscreenNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/SearchFullscreenNavigator.tsx @@ -1,10 +1,11 @@ import React from 'react'; -import type {PlatformStackNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types'; -import type {SearchFullscreenNavigatorParamList} from '@libs/Navigation/types'; +import type {PlatformStackNavigationOptions, PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; +import type {AuthScreensParamList, SearchFullscreenNavigatorParamList} from '@libs/Navigation/types'; import * as SearchQueryUtils from '@libs/SearchQueryUtils'; import createSearchFullscreenNavigator from '@navigation/AppNavigator/createSearchFullscreenNavigator'; import FreezeWrapper from '@navigation/AppNavigator/FreezeWrapper'; import useRootNavigatorScreenOptions from '@navigation/AppNavigator/useRootNavigatorScreenOptions'; +import type NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; @@ -13,9 +14,8 @@ const loadSearchMoneyReportPage = () => require('@pages/Se const Stack = createSearchFullscreenNavigator(); -function SearchFullscreenNavigator() { +function SearchFullscreenNavigator({route}: PlatformStackScreenProps) { const rootNavigatorScreenOptions = useRootNavigatorScreenOptions(); - const searchRootScreenOptions: PlatformStackNavigationOptions = { ...rootNavigatorScreenOptions.fullScreen, web: { @@ -23,12 +23,12 @@ function SearchFullscreenNavigator() { cardStyleInterpolator: undefined, }, }; - return ( | PartialState>; @@ -73,7 +73,7 @@ function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralSc const previousSameNavigator = rootState?.routes.filter((route) => route.name === parentRoute.name).at(-2); // If we have optimization for not rendering all split navigators, then last selected option may not be in the state. In this case state has to be read from the preserved state. - const previousSameNavigatorState = previousSameNavigator?.state ?? (previousSameNavigator?.key ? getPreservedSplitNavigatorState(previousSameNavigator.key) : undefined); + const previousSameNavigatorState = previousSameNavigator?.state ?? (previousSameNavigator?.key ? getPreservedNavigatorState(previousSameNavigator.key) : undefined); const previousSelectedCentralScreen = previousSameNavigatorState?.routes && previousSameNavigatorState.routes.length > 1 ? previousSameNavigatorState.routes.at(-1)?.name : undefined; @@ -113,7 +113,7 @@ function SplitRouter(options: SplitNavigatorRouterOptions) { return stackRouter.getStateForAction(state, action, configOptions); }, getInitialState({routeNames, routeParamList, routeGetIdList}: RouterConfigOptions) { - const preservedState = getPreservedSplitNavigatorState(options.parentRoute.key); + const preservedState = getPreservedNavigatorState(options.parentRoute.key); const initialState = preservedState ?? stackRouter.getInitialState({routeNames, routeParamList, routeGetIdList}); adaptStateIfNecessary({ diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx index 8a943b40425a..0771da8c55f4 100644 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx @@ -13,11 +13,11 @@ import type { } from '@libs/Navigation/PlatformStackNavigation/types'; import SidebarSpacerWrapper from './SidebarSpacerWrapper'; import SplitRouter from './SplitRouter'; -import usePreserveSplitNavigatorState from './usePreserveSplitNavigatorState'; +import usePreserveNavigatorState from './usePreserveNavigatorState'; function useCustomEffects(props: CustomEffectsHookProps) { useNavigationResetOnLayoutChange(props); - usePreserveSplitNavigatorState(props.state, props.parentRoute); + usePreserveNavigatorState(props.state, props.parentRoute); } function useCustomSplitNavigatorState({state}: CustomStateHookProps) { diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/usePreserveNavigatorState.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/usePreserveNavigatorState.ts new file mode 100644 index 000000000000..8cbd48f5a98e --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/usePreserveNavigatorState.ts @@ -0,0 +1,29 @@ +import type {NavigationState, ParamListBase, RouteProp, StackNavigationState} from '@react-navigation/native'; +import {useEffect} from 'react'; + +const preservedNavigatorStates: Record> = {}; + +const cleanPreservedNavigatorStates = (state: NavigationState) => { + const currentSplitNavigatorKeys = state.routes.map((route) => route.key); + + for (const key of Object.keys(preservedNavigatorStates)) { + if (!currentSplitNavigatorKeys.includes(key)) { + delete preservedNavigatorStates[key]; + } + } +}; + +const getPreservedNavigatorState = (key: string) => preservedNavigatorStates[key]; + +function usePreserveNavigatorState(state: StackNavigationState, route: RouteProp | undefined) { + useEffect(() => { + if (!route) { + return; + } + preservedNavigatorStates[route.key] = state; + }, [route, state]); +} + +export default usePreserveNavigatorState; + +export {getPreservedNavigatorState, cleanPreservedNavigatorStates}; diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState.ts deleted file mode 100644 index 789fc27d81fe..000000000000 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type {NavigationState, ParamListBase, RouteProp, StackNavigationState} from '@react-navigation/native'; -import {useEffect} from 'react'; - -const preservedSplitNavigatorStates: Record> = {}; - -const cleanPreservedSplitNavigatorStates = (state: NavigationState) => { - const currentSplitNavigatorKeys = state.routes.map((route) => route.key); - - for (const key of Object.keys(preservedSplitNavigatorStates)) { - if (!currentSplitNavigatorKeys.includes(key)) { - delete preservedSplitNavigatorStates[key]; - } - } -}; - -const getPreservedSplitNavigatorState = (key: string) => preservedSplitNavigatorStates[key]; - -function usePreserveSplitNavigatorState(state: StackNavigationState, route: RouteProp | undefined) { - useEffect(() => { - if (!route) { - return; - } - preservedSplitNavigatorStates[route.key] = state; - }, [route, state]); -} - -export default usePreserveSplitNavigatorState; - -export {getPreservedSplitNavigatorState, cleanPreservedSplitNavigatorStates}; diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index 71cddba6b221..e5a878031c8a 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -25,7 +25,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import AppNavigator from './AppNavigator'; -import {cleanPreservedSplitNavigatorStates} from './AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState'; +import {cleanPreservedNavigatorStates} from './AppNavigator/createSplitNavigator/usePreserveNavigatorState'; import customGetPathFromState from './helpers/customGetPathFromState'; import getAdaptedStateFromPath from './helpers/getAdaptedStateFromPath'; import {linkingConfig} from './linkingConfig'; @@ -209,7 +209,7 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady, sh // We want to clean saved scroll offsets for screens that aren't anymore in the state. cleanStaleScrollOffsets(state); - cleanPreservedSplitNavigatorStates(state); + cleanPreservedNavigatorStates(state); }; return ( diff --git a/src/pages/home/sidebar/BaseSidebarScreen.tsx b/src/pages/home/sidebar/BaseSidebarScreen.tsx index 6ee621d321ee..b5c1fbe9ce5b 100644 --- a/src/pages/home/sidebar/BaseSidebarScreen.tsx +++ b/src/pages/home/sidebar/BaseSidebarScreen.tsx @@ -13,7 +13,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import {updateLastAccessedWorkspace} from '@libs/actions/Policy/Policy'; import {isMobile} from '@libs/Browser'; import getInitialSplitNavigatorState from '@libs/Navigation/AppNavigator/createSplitNavigator/getInitialSplitNavigatorState'; -import {getPreservedSplitNavigatorState} from '@libs/Navigation/AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState'; +import {getPreservedNavigatorState} from '@libs/Navigation/AppNavigator/createSplitNavigator/usePreserveNavigatorState'; import getTopmostReportsSplitNavigator from '@libs/Navigation/helpers/getTopmostReportsSplitNavigator'; import Navigation from '@libs/Navigation/Navigation'; import Performance from '@libs/Performance'; @@ -48,7 +48,7 @@ function BaseSidebarScreen() { } // Switching workspace to global should only be performed from the currently opened sidebar screen - const topmostReportSplitState = topmostReportSplit?.state ?? getPreservedSplitNavigatorState(topmostReportSplit?.key); + const topmostReportSplitState = topmostReportSplit?.state ?? getPreservedNavigatorState(topmostReportSplit?.key); const isCurrentSidebar = topmostReportSplitState?.routes.some((route) => currentRoute.key === route.key); if (!isCurrentSidebar) {