1- import { useCallback } from 'react' ;
2- import type { OnyxCollection } from 'react-native-onyx' ;
31import { getPreservedNavigatorState } from '@libs/Navigation/AppNavigator/createSplitNavigator/usePreserveNavigatorState' ;
42import { isFullScreenName , isWorkspaceNavigatorRouteName } from '@libs/Navigation/helpers/isNavigatorName' ;
53import { getWorkspacesTabStateFromSessionStorage } from '@libs/Navigation/helpers/lastVisitedTabPathUtils' ;
64import navigateToWorkspacesPage from '@libs/Navigation/helpers/navigateToWorkspacesPage' ;
75import { getTabState } from '@libs/Navigation/helpers/tabNavigatorUtils' ;
6+ import navigationRef from '@libs/Navigation/navigationRef' ;
87import type { DomainSplitNavigatorParamList , WorkspaceSplitNavigatorParamList } from '@libs/Navigation/types' ;
98import NAVIGATORS from '@src/NAVIGATORS' ;
109import ONYXKEYS from '@src/ONYXKEYS' ;
1110import type SCREENS from '@src/SCREENS' ;
12- import type { Domain , Policy } from '@src/types/onyx' ;
1311import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails' ;
1412import useOnyx from './useOnyx' ;
1513import useResponsiveLayout from './useResponsiveLayout' ;
16- import useRootNavigationState from './useRootNavigationState' ;
1714
1815/**
1916 * The Workspaces tab can show three things: the workspaces list, a specific workspace page,
@@ -22,82 +19,73 @@ import useRootNavigationState from './useRootNavigationState';
2219 *
2320 * It resolves the last visited route from navigation state, fetches the matching policy/domain
2421 * from Onyx (to verify it's still accessible), and returns a callback that performs the navigation.
22+ *
23+ * Nav state is resolved at click time so the hook has no reactive subscriptions to navigation
24+ * — unrelated navigations (e.g. opening a report) don't trigger re-renders.
2525 */
2626function useRestoreWorkspacesTabOnNavigate ( ) {
2727 const { shouldUseNarrowLayout} = useResponsiveLayout ( ) ;
2828 const { login : currentUserLogin } = useCurrentUserPersonalDetails ( ) ;
29+ const [ allPolicies ] = useOnyx ( ONYXKEYS . COLLECTION . POLICY ) ;
30+ const [ allDomains ] = useOnyx ( ONYXKEYS . COLLECTION . DOMAIN ) ;
2931
30- // Find the last route the user had open in the Workspaces tab (workspace, domain, or list).
31- // Priority: live nav state (root level) -> inside TabNavigator -> preserved state -> session storage.
32- const routeState = useRootNavigationState ( ( rootState ) => {
33- const topmostFullScreenRoute = rootState ?. routes ?. findLast ( ( route ) => isFullScreenName ( route . name ) ) ;
34- if ( ! topmostFullScreenRoute ) {
35- return { } ;
36- }
37-
38- // Multiple TAB_NAVIGATOR instances can coexist in the root stack — when navigation from
39- // inside an RHP targets a tab, linkTo PUSHes a fresh TabNavigator above the modal, and that
40- // new instance's WORKSPACE_NAVIGATOR slot starts empty. Older instances kept alive by
41- // ensureTabNavigatorRoutes still hold the previous workspace state, so flatten every
42- // workspace route from every TabNavigator in stack order and take the most recent one.
43- const lastWorkspaceRoute = ( rootState ?. routes ?? [ ] )
44- . filter ( ( route ) => route . name === NAVIGATORS . TAB_NAVIGATOR )
45- . flatMap ( ( tabNavigatorRoute ) => {
46- const workspaceNavigatorRoute = getTabState ( tabNavigatorRoute ) ?. routes ?. find ( ( route ) => route . name === NAVIGATORS . WORKSPACE_NAVIGATOR ) ;
47- const workspaceNavigatorState = workspaceNavigatorRoute ?. state ?? ( workspaceNavigatorRoute ?. key ? getPreservedNavigatorState ( workspaceNavigatorRoute . key ) : undefined ) ;
48- return workspaceNavigatorState ?. routes ?. filter ( ( route ) => isWorkspaceNavigatorRouteName ( route . name ) ) ?? [ ] ;
49- } )
50- . at ( - 1 ) ;
32+ return ( ) => {
33+ // Find the last route the user had open in the Workspaces tab (workspace, domain, or list).
34+ // Priority: live nav state (root level) -> inside TabNavigator -> preserved state -> session storage.
35+ const rootState = navigationRef . isReady ( ) ? navigationRef . getRootState ( ) : undefined ;
36+ const routeState = ( ( ) => {
37+ const topmostFullScreenRoute = rootState ?. routes ?. findLast ( ( route ) => isFullScreenName ( route . name ) ) ;
38+ if ( ! topmostFullScreenRoute ) {
39+ return { } ;
40+ }
5141
52- if ( lastWorkspaceRoute ) {
53- const tabState = lastWorkspaceRoute . state ?? ( lastWorkspaceRoute . key ? getPreservedNavigatorState ( lastWorkspaceRoute . key ) : undefined ) ;
54- return { lastWorkspacesTabNavigatorRoute : lastWorkspaceRoute , workspacesTabState : tabState , topmostFullScreenRoute} ;
55- }
42+ // Multiple TAB_NAVIGATOR instances can coexist in the root stack — when navigation from
43+ // inside an RHP targets a tab, linkTo PUSHes a fresh TabNavigator above the modal, and that
44+ // new instance's WORKSPACE_NAVIGATOR slot starts empty. Older instances kept alive by
45+ // ensureTabNavigatorRoutes still hold the previous workspace state, so flatten every
46+ // workspace route from every TabNavigator in stack order and take the most recent one.
47+ const lastWorkspaceRoute = ( rootState ?. routes ?? [ ] )
48+ . filter ( ( route ) => route . name === NAVIGATORS . TAB_NAVIGATOR )
49+ . flatMap ( ( tabNavigatorRoute ) => {
50+ const workspaceNavigatorRoute = getTabState ( tabNavigatorRoute ) ?. routes ?. find ( ( route ) => route . name === NAVIGATORS . WORKSPACE_NAVIGATOR ) ;
51+ const workspaceNavigatorState = workspaceNavigatorRoute ?. state ?? ( workspaceNavigatorRoute ?. key ? getPreservedNavigatorState ( workspaceNavigatorRoute . key ) : undefined ) ;
52+ return workspaceNavigatorState ?. routes ?. filter ( ( route ) => isWorkspaceNavigatorRouteName ( route . name ) ) ?? [ ] ;
53+ } )
54+ . at ( - 1 ) ;
5655
57- // Fall back to session storage when no workspace route exists anywhere in the navigation tree.
58- const sessionRoute = getWorkspacesTabStateFromSessionStorage ( )
59- ?. routes ?. findLast ( ( route ) => route . name === NAVIGATORS . WORKSPACE_NAVIGATOR )
60- ?. state ?. routes ?. findLast ( ( route ) => isWorkspaceNavigatorRouteName ( route . name ) ) ;
61- if ( sessionRoute ) {
62- return { lastWorkspacesTabNavigatorRoute : sessionRoute , workspacesTabState : sessionRoute . state , topmostFullScreenRoute} ;
63- }
56+ if ( lastWorkspaceRoute ) {
57+ const tabState = lastWorkspaceRoute . state ?? ( lastWorkspaceRoute . key ? getPreservedNavigatorState ( lastWorkspaceRoute . key ) : undefined ) ;
58+ return { lastWorkspacesTabNavigatorRoute : lastWorkspaceRoute , workspacesTabState : tabState , topmostFullScreenRoute} ;
59+ }
6460
65- return { topmostFullScreenRoute} ;
66- } ) ;
61+ // Fall back to session storage when no workspace route exists anywhere in the navigation tree.
62+ const sessionRoute = getWorkspacesTabStateFromSessionStorage ( )
63+ ?. routes ?. findLast ( ( route ) => route . name === NAVIGATORS . WORKSPACE_NAVIGATOR )
64+ ?. state ?. routes ?. findLast ( ( route ) => isWorkspaceNavigatorRouteName ( route . name ) ) ;
65+ if ( sessionRoute ) {
66+ return { lastWorkspacesTabNavigatorRoute : sessionRoute , workspacesTabState : sessionRoute . state , topmostFullScreenRoute} ;
67+ }
6768
68- const { lastWorkspacesTabNavigatorRoute, workspacesTabState, topmostFullScreenRoute} = routeState ;
69+ return { topmostFullScreenRoute} ;
70+ } ) ( ) ;
6971
70- // If the last route was a specific workspace or domain, extract its ID from params
71- const params = workspacesTabState ?. routes ?. at ( 0 ) ?. params as
72- | WorkspaceSplitNavigatorParamList [ typeof SCREENS . WORKSPACE . INITIAL ]
73- | DomainSplitNavigatorParamList [ typeof SCREENS . DOMAIN . INITIAL ] ;
74- const paramsPolicyID = params && 'policyID' in params ? params . policyID : undefined ;
75- const paramsDomainAccountID = params && 'domainAccountID' in params ? params . domainAccountID : undefined ;
72+ const { lastWorkspacesTabNavigatorRoute, workspacesTabState, topmostFullScreenRoute} = routeState ;
7673
77- // Fetch the policy/domain to verify it's still accessible (not deleted/hidden) before restoring
78- const lastViewedPolicySelector = useCallback (
79- ( policies : OnyxCollection < Policy > ) => {
80- if ( lastWorkspacesTabNavigatorRoute ?. name !== NAVIGATORS . WORKSPACE_SPLIT_NAVIGATOR || ! paramsPolicyID ) {
81- return undefined ;
82- }
83- return policies ?. [ `${ ONYXKEYS . COLLECTION . POLICY } ${ paramsPolicyID } ` ] ;
84- } ,
85- [ lastWorkspacesTabNavigatorRoute ?. name , paramsPolicyID ] ,
86- ) ;
87- const [ lastViewedPolicy ] = useOnyx ( ONYXKEYS . COLLECTION . POLICY , { selector : lastViewedPolicySelector } ) ;
74+ // If the last route was a specific workspace or domain, extract its ID from params
75+ const params = workspacesTabState ?. routes ?. at ( 0 ) ?. params as
76+ | WorkspaceSplitNavigatorParamList [ typeof SCREENS . WORKSPACE . INITIAL ]
77+ | DomainSplitNavigatorParamList [ typeof SCREENS . DOMAIN . INITIAL ] ;
78+ const paramsPolicyID = params && 'policyID' in params ? params . policyID : undefined ;
79+ const paramsDomainAccountID = params && 'domainAccountID' in params ? params . domainAccountID : undefined ;
8880
89- const lastViewedDomainSelector = useCallback (
90- ( domains : OnyxCollection < Domain > ) => {
91- if ( lastWorkspacesTabNavigatorRoute ?. name !== NAVIGATORS . DOMAIN_SPLIT_NAVIGATOR || ! paramsDomainAccountID ) {
92- return undefined ;
93- }
94- return domains ?. [ `${ ONYXKEYS . COLLECTION . DOMAIN } ${ paramsDomainAccountID } ` ] ;
95- } ,
96- [ lastWorkspacesTabNavigatorRoute ?. name , paramsDomainAccountID ] ,
97- ) ;
98- const [ lastViewedDomain ] = useOnyx ( ONYXKEYS . COLLECTION . DOMAIN , { selector : lastViewedDomainSelector } ) ;
81+ // Fetch the policy/domain to verify it's still accessible (not deleted/hidden) before restoring
82+ const lastViewedPolicy =
83+ lastWorkspacesTabNavigatorRoute ?. name === NAVIGATORS . WORKSPACE_SPLIT_NAVIGATOR && paramsPolicyID ? allPolicies ?. [ `${ ONYXKEYS . COLLECTION . POLICY } ${ paramsPolicyID } ` ] : undefined ;
84+ const lastViewedDomain =
85+ lastWorkspacesTabNavigatorRoute ?. name === NAVIGATORS . DOMAIN_SPLIT_NAVIGATOR && paramsDomainAccountID
86+ ? allDomains ?. [ `${ ONYXKEYS . COLLECTION . DOMAIN } ${ paramsDomainAccountID } ` ]
87+ : undefined ;
9988
100- return useCallback ( ( ) => {
10189 navigateToWorkspacesPage ( {
10290 shouldUseNarrowLayout,
10391 currentUserLogin,
@@ -107,7 +95,7 @@ function useRestoreWorkspacesTabOnNavigate() {
10795 topmostFullScreenRoute,
10896 workspacesTabState,
10997 } ) ;
110- } , [ shouldUseNarrowLayout , currentUserLogin , lastViewedPolicy , lastViewedDomain , lastWorkspacesTabNavigatorRoute , topmostFullScreenRoute , workspacesTabState ] ) ;
98+ } ;
11199}
112100
113101export default useRestoreWorkspacesTabOnNavigate ;
0 commit comments