Skip to content

Commit 0866854

Browse files
committed
inline route resolution to reduce diff churn
1 parent 5a83e12 commit 0866854

1 file changed

Lines changed: 53 additions & 58 deletions

File tree

src/hooks/useRestoreWorkspacesTabOnNavigate.ts

Lines changed: 53 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import type {NavigationState, PartialState} from '@react-navigation/native';
21
import {getPreservedNavigatorState} from '@libs/Navigation/AppNavigator/createSplitNavigator/usePreserveNavigatorState';
32
import {isFullScreenName, isWorkspaceNavigatorRouteName} from '@libs/Navigation/helpers/isNavigatorName';
43
import {getWorkspacesTabStateFromSessionStorage} from '@libs/Navigation/helpers/lastVisitedTabPathUtils';
@@ -13,60 +12,16 @@ import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails';
1312
import useOnyx from './useOnyx';
1413
import useResponsiveLayout from './useResponsiveLayout';
1514

16-
type WorkspaceRouteType = NavigationState['routes'][number] | NonNullable<PartialState<NavigationState>['routes']>[number];
17-
type WorkspaceParams = WorkspaceSplitNavigatorParamList[typeof SCREENS.WORKSPACE.INITIAL] | DomainSplitNavigatorParamList[typeof SCREENS.DOMAIN.INITIAL];
18-
19-
/**
20-
* Walks the root nav state to find the last workspace/domain route the user had open.
21-
* Falls back to session storage when no live workspace route exists.
22-
*
23-
* Multiple TAB_NAVIGATOR instances can coexist in the root stack — when navigation from
24-
* inside an RHP targets a tab, linkTo PUSHes a fresh TabNavigator above the modal, and that
25-
* new instance's WORKSPACE_NAVIGATOR slot starts empty. Older instances kept alive by
26-
* ensureTabNavigatorRoutes still hold the previous workspace state, so flatten every
27-
* workspace route from every TabNavigator in stack order and take the most recent one.
28-
*/
29-
function findLastWorkspaceRoute(rootState: NavigationState | undefined): WorkspaceRouteType | undefined {
30-
const topmostFullScreenRoute = rootState?.routes?.findLast((route) => isFullScreenName(route.name));
31-
if (!topmostFullScreenRoute) {
32-
return undefined;
33-
}
34-
35-
const lastWorkspaceRoute = (rootState?.routes ?? [])
36-
.filter((route) => route.name === NAVIGATORS.TAB_NAVIGATOR)
37-
.flatMap((tabNavigatorRoute) => {
38-
const workspaceNavigatorRoute = getTabState(tabNavigatorRoute)?.routes?.find((route) => route.name === NAVIGATORS.WORKSPACE_NAVIGATOR);
39-
const workspaceNavigatorState = workspaceNavigatorRoute?.state ?? (workspaceNavigatorRoute?.key ? getPreservedNavigatorState(workspaceNavigatorRoute.key) : undefined);
40-
return workspaceNavigatorState?.routes?.filter((route) => isWorkspaceNavigatorRouteName(route.name)) ?? [];
41-
})
42-
.at(-1);
43-
44-
if (lastWorkspaceRoute) {
45-
return lastWorkspaceRoute;
46-
}
47-
48-
return getWorkspacesTabStateFromSessionStorage()
49-
?.routes?.findLast((route) => route.name === NAVIGATORS.WORKSPACE_NAVIGATOR)
50-
?.state?.routes?.findLast((route) => isWorkspaceNavigatorRouteName(route.name));
51-
}
52-
53-
function getWorkspacesTabState(route: WorkspaceRouteType | undefined): NavigationState | PartialState<NavigationState> | undefined {
54-
if (!route) {
55-
return undefined;
56-
}
57-
return route.state ?? (route.key ? getPreservedNavigatorState(route.key) : undefined);
58-
}
59-
6015
/**
6116
* The Workspaces tab can show three things: the workspaces list, a specific workspace page,
6217
* or a specific domain page. When the user navigates away and comes back to the tab,
6318
* this hook ensures they return to whichever of those they had open last — not always the list.
6419
*
65-
* Resolves nav state and route IDs at click time inside the returned callback so the hook has
66-
* no reactive subscriptions to nav state — unrelated navigations (e.g. opening a report) don't
67-
* trigger re-renders. The POLICY/DOMAIN collections are subscribed at hook level so the click
68-
* handler can validate the last viewed workspace/domain via closure; these collections rarely
69-
* tick during navigation.
20+
* It resolves the last visited route from navigation state, fetches the matching policy/domain
21+
* 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.
7025
*/
7126
function useRestoreWorkspacesTabOnNavigate() {
7227
const {shouldUseNarrowLayout} = useResponsiveLayout();
@@ -75,27 +30,67 @@ function useRestoreWorkspacesTabOnNavigate() {
7530
const [allDomains] = useOnyx(ONYXKEYS.COLLECTION.DOMAIN);
7631

7732
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.
7835
const rootState = navigationRef.isReady() ? navigationRef.getRootState() : undefined;
79-
const topmostFullScreenRoute = rootState?.routes?.findLast((route) => isFullScreenName(route.name));
80-
const lastWorkspacesTabNavigatorRoute = findLastWorkspaceRoute(rootState);
81-
const workspacesTabState = getWorkspacesTabState(lastWorkspacesTabNavigatorRoute);
36+
const routeState = (() => {
37+
const topmostFullScreenRoute = rootState?.routes?.findLast((route) => isFullScreenName(route.name));
38+
if (!topmostFullScreenRoute) {
39+
return {};
40+
}
41+
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);
55+
56+
if (lastWorkspaceRoute) {
57+
const tabState = lastWorkspaceRoute.state ?? (lastWorkspaceRoute.key ? getPreservedNavigatorState(lastWorkspaceRoute.key) : undefined);
58+
return {lastWorkspacesTabNavigatorRoute: lastWorkspaceRoute, workspacesTabState: tabState, topmostFullScreenRoute};
59+
}
60+
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+
}
68+
69+
return {topmostFullScreenRoute};
70+
})();
71+
72+
const {lastWorkspacesTabNavigatorRoute, workspacesTabState, topmostFullScreenRoute} = routeState;
8273

83-
const params = workspacesTabState?.routes?.at(0)?.params as WorkspaceParams | undefined;
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];
8478
const paramsPolicyID = params && 'policyID' in params ? params.policyID : undefined;
8579
const paramsDomainAccountID = params && 'domainAccountID' in params ? params.domainAccountID : undefined;
8680

87-
const policy =
81+
// Fetch the policy/domain to verify it's still accessible (not deleted/hidden) before restoring
82+
const lastViewedPolicy =
8883
lastWorkspacesTabNavigatorRoute?.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR && paramsPolicyID ? allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${paramsPolicyID}`] : undefined;
89-
const domain =
84+
const lastViewedDomain =
9085
lastWorkspacesTabNavigatorRoute?.name === NAVIGATORS.DOMAIN_SPLIT_NAVIGATOR && paramsDomainAccountID
9186
? allDomains?.[`${ONYXKEYS.COLLECTION.DOMAIN}${paramsDomainAccountID}`]
9287
: undefined;
9388

9489
navigateToWorkspacesPage({
9590
shouldUseNarrowLayout,
9691
currentUserLogin,
97-
policy,
98-
domain,
92+
policy: lastViewedPolicy,
93+
domain: lastViewedDomain,
9994
lastWorkspacesTabNavigatorRoute,
10095
topmostFullScreenRoute,
10196
workspacesTabState,

0 commit comments

Comments
 (0)