Skip to content
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

Poc/set policy id in url #111

Merged
merged 3 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import pick from 'lodash/pick';
import getIsNarrowLayout from '@libs/getIsNarrowLayout';
import getParamsFromRoute from '@libs/Navigation/linkingConfig/getParamsFromRoute';
import navigationRef from '@libs/Navigation/navigationRef';
import SCREENS from '@src/SCREENS';
import type {SplitStackNavigatorRouterOptions} from './types';
import {getPreservedSplitNavigatorState} from './usePreserveSplitNavigatorState';

Expand All @@ -26,6 +27,16 @@ function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralSc
// - defaultCentralScreen to cover central pane.
if (!isAtLeastOneInState(state, sidebarScreen) && !isNarrowLayout) {
const paramsFromRoute = getParamsFromRoute(sidebarScreen);
let params = pick(lastRoute?.params, paramsFromRoute);

// On a wide screen the backTo param has to be passed to the sidebar screen (SCREENS.WORKSPACE.INITIAL), because the back action is performed from this page
if (lastRoute?.name === SCREENS.WORKSPACE.PROFILE) {
const hasRouteBackToParam = lastRoute?.params && 'backTo' in lastRoute.params;

if (hasRouteBackToParam) {
params = {...params, backTo: lastRoute.params.backTo};
}
}

// @ts-expect-error Updating read only property
// noinspection JSConstantReassignment
Expand All @@ -37,7 +48,7 @@ function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralSc
state.routes.unshift({
name: sidebarScreen,
// This handles the case where the sidebar should have params included in the central screen e.g. policyID for workspace initial.
params: pick(lastRoute?.params, paramsFromRoute),
params,
});
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/libs/Navigation/Navigation.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import {getActionFromState} from '@react-navigation/core';
import type {EventArg, NavigationAction, NavigationContainerEventMap} from '@react-navigation/native';
import {CommonActions, getPathFromState, StackActions} from '@react-navigation/native';
import lodashOmit from 'lodash/omit';

Check failure on line 4 in src/libs/Navigation/Navigation.ts

View workflow job for this annotation

GitHub Actions / ESLint check

Import from 'lodash/omit' detected. Consider using the native {a, b, c, ...notOmittedValues}

Check failure on line 4 in src/libs/Navigation/Navigation.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Import from 'lodash/omit' detected. Consider using the native {a, b, c, ...notOmittedValues}
import type {OnyxEntry} from 'react-native-onyx';
import type {Writable} from 'type-fest';
import getIsNarrowLayout from '@libs/getIsNarrowLayout';
import Log from '@libs/Log';
import {isSplitNavigatorRoute} from '@libs/NavigationUtils';
import {shallowCompare} from '@libs/ObjectUtils';
import getPolicyEmployeeAccountIDs from '@libs/PolicyEmployeeListUtils';
import * as ReportConnection from '@libs/ReportConnection';
Expand Down Expand Up @@ -276,7 +277,7 @@
* @param shouldEnforceFallback - Enforces navigation to fallback route
* @param shouldPopToTop - Should we navigate to LHN on back press
*/
function goBack(fallbackRoute?: Route, shouldEnforceFallback = false, shouldPopToTop = false) {

Check failure on line 280 in src/libs/Navigation/Navigation.ts

View workflow job for this annotation

GitHub Actions / ESLint check

'shouldEnforceFallback' is assigned a value but never used

Check failure on line 280 in src/libs/Navigation/Navigation.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

'shouldEnforceFallback' is assigned a value but never used
if (!canNavigate('goBack')) {
return;
}
Expand All @@ -299,7 +300,7 @@

const canGoBack = navigationRef.current?.canGoBack();

if (!canGoBack && lastRoute?.name.endsWith('SplitNavigator') && lastRoute?.state?.routes?.length === 1) {
if (!canGoBack && isSplitNavigatorRoute(lastRoute as NavigationPartialRoute) && lastRoute?.state?.routes?.length === 1) {
const splitNavigatorName = lastRoute?.name as keyof SplitNavigatorParamListType;
const name = SPLIT_NAVIGATOR_TO_SIDEBAR_MAP[splitNavigatorName];
const params = getSidebarScreenParams(lastRoute);
Expand Down
2 changes: 1 addition & 1 deletion src/libs/Navigation/linkingConfig/createSplitNavigator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const getRoutesWithIndex = (routes: NavigationPartialRoute[]): PartialState<Navi
function createSplitNavigator<T extends SplitNavigatorLHNScreen>(
splitNavigatorLHN: NavigationPartialRoute<T>,
route?: NavigationPartialRoute<ExtractRouteType<T>>,
splitNavigatorParams?: SplitNavigatorParamListType[SplitNavigatorByLHN<T>],
splitNavigatorParams?: Record<string, string>,
): NavigationPartialRoute<SplitNavigatorByLHN<T>> {
const routes = [];

Expand Down
10 changes: 5 additions & 5 deletions src/libs/Navigation/linkingConfig/customGetPathFromState.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import {getPathFromState} from '@react-navigation/native';
import type {RootStackParamList, State} from '@libs/Navigation/types';
import {removePolicyIDParamFromState} from '@libs/NavigationUtils';
import type {NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types';
import {isFullScreenRoute, removePolicyIDParamFromState} from '@libs/NavigationUtils';
import NAVIGATORS from '@src/NAVIGATORS';

const customGetPathFromState: typeof getPathFromState = (state, options) => {
// For the Home page we should remove policyID from the params, because on small screens it's displayed twice in the URL
const stateWithoutPolicyID = removePolicyIDParamFromState(state as State<RootStackParamList>);
const path = getPathFromState(stateWithoutPolicyID, options);
const topmostRoute = state.routes.at(-1);
const topmostSplitOrSearchRoute = state.routes.findLast((route) => isFullScreenRoute(route as NavigationPartialRoute));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe FullScreen to be consistent? But not a blocker


const shouldAddPolicyID = !!topmostRoute && topmostRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR;
const shouldAddPolicyID = topmostSplitOrSearchRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR;

if (!shouldAddPolicyID) {
return path;
}

const policyID = topmostRoute.params && `policyID` in topmostRoute.params ? (topmostRoute.params.policyID as string) : undefined;
const policyID = topmostSplitOrSearchRoute.params && `policyID` in topmostSplitOrSearchRoute.params ? (topmostSplitOrSearchRoute.params.policyID as string) : undefined;

return `${policyID ? `/w/${policyID}` : ''}${path}`;
};
Expand Down
31 changes: 17 additions & 14 deletions src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {findFocusedRoute, getStateFromPath} from '@react-navigation/native';
import pick from 'lodash/pick';
import {isAnonymousUser} from '@libs/actions/Session';
import type {NavigationPartialRoute, RootStackParamList, SettingsSplitNavigatorParamList, WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types';
import {isFullScreenRoute} from '@libs/NavigationUtils';
import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils';
import * as ReportConnection from '@libs/ReportConnection';
import extractPolicyIDFromQuery from '@navigation/extractPolicyIDFromQuery';
Expand Down Expand Up @@ -32,9 +33,11 @@ function isRouteWithReportID(route: NavigationPartialRoute): route is Route<stri
return route.params !== undefined && 'reportID' in route.params && typeof route.params.reportID === 'string';
}

function getMatchingFullScreenRouteForState(state: PartialState<NavigationState<RootStackParamList>>) {
function getMatchingFullScreenRouteForState(state: PartialState<NavigationState<RootStackParamList>>, policyID?: string) {
const focusedRoute = findFocusedRoute(state);

const reportSplitParams = policyID ? {policyID} : undefined;

if (!focusedRoute) {
return undefined;
}
Expand All @@ -57,7 +60,7 @@ function getMatchingFullScreenRouteForState(state: PartialState<NavigationState<
}

// If not, get the matching full screen route for the back to state.
return getMatchingFullScreenRouteForState(stateForBackTo as PartialState<NavigationState<RootStackParamList>>);
return getMatchingFullScreenRouteForState(stateForBackTo as PartialState<NavigationState<RootStackParamList>>, policyID);
}

if (RELATIONS.SEARCH_TO_RHP.includes(focusedRoute.name)) {
Expand All @@ -71,9 +74,13 @@ function getMatchingFullScreenRouteForState(state: PartialState<NavigationState<

if (RELATIONS.RHP_TO_SIDEBAR[focusedRoute.name]) {
// @TODO: Figure out better types for this.
return createSplitNavigator({
name: RELATIONS.RHP_TO_SIDEBAR[focusedRoute.name] as typeof SCREENS.HOME,
});
return createSplitNavigator(
{
name: RELATIONS.RHP_TO_SIDEBAR[focusedRoute.name] as typeof SCREENS.HOME,
},
undefined,
reportSplitParams,
);
}

// @TODO We can think about handling it in one condition.
Expand Down Expand Up @@ -129,18 +136,13 @@ function getMatchingFullScreenRouteForState(state: PartialState<NavigationState<
...pick(focusedRoute.params, paramsFromRoute),
},
},
reportSplitParams,
);
}

return undefined;
}

const FULL_SCREEN_ROUTES: string[] = [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, SCREENS.SEARCH.CENTRAL_PANE];

function isFullScreenRoute(route: NavigationPartialRoute): boolean {
return FULL_SCREEN_ROUTES.includes(route.name);
}

function getAdaptedState(state: PartialState<NavigationState<RootStackParamList>>, policyID?: string): GetAdaptedStateReturnType {
const fullScreenRoute = state.routes.find(isFullScreenRoute);
const reportsSplitNavigator = state.routes.find((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR);
Expand All @@ -159,18 +161,19 @@ function getAdaptedState(state: PartialState<NavigationState<RootStackParamList>

// If there is no full screen route in the root, we want to add it.
if (!fullScreenRoute) {
const matchingRootRoute = getMatchingFullScreenRouteForState(state);

const matchingRootRoute = getMatchingFullScreenRouteForState(state, policyID);
// If there is a matching root route, add it to the state.
if (matchingRootRoute) {
return {
adaptedState: getRoutesWithIndex([matchingRootRoute, ...state.routes]),
};
}

const reportSplitParams = policyID ? {policyID} : undefined;

// If not, add the default full screen route.
return {
adaptedState: getRoutesWithIndex([{name: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR}, ...state.routes]),
adaptedState: getRoutesWithIndex([{name: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, params: reportSplitParams}, ...state.routes]),
};
}

Expand Down
6 changes: 6 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1581,8 +1581,12 @@ type CentralPaneName = keyof CentralPaneScreensParamList;

type OnboardingFlowName = keyof OnboardingModalNavigatorParamList;

type SplitNavigatorName = keyof SplitNavigatorParamListType;

type SplitNavigatorScreenName = keyof (WorkspaceSplitNavigatorParamList & SettingsSplitNavigatorParamList & ReportsSplitNavigatorParamList);

type FullScreenName = SplitNavigatorName | typeof SCREENS.SEARCH.CENTRAL_PANE;

type SwitchPolicyIDParams = {
policyID?: string;
route?: Routes;
Expand Down Expand Up @@ -1657,7 +1661,9 @@ export type {
RestrictedActionParamList,
MissingPersonalDetailsParamList,
DebugParamList,
SplitNavigatorName,
SplitNavigatorScreenName,
FullScreenName,
SplitNavigatorLHNScreen,
SplitNavigatorParamListType,
SplitNavigatorByLHN,
Expand Down
27 changes: 25 additions & 2 deletions src/libs/NavigationUtils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import cloneDeep from 'lodash/cloneDeep';
import NAVIGATORS from '@src/NAVIGATORS';
import SCREENS from '@src/SCREENS';
import getTopmostBottomTabRoute from './Navigation/getTopmostBottomTabRoute';
import type {CentralPaneName, OnboardingFlowName, RootStackParamList, State} from './Navigation/types';
import type {CentralPaneName, FullScreenName, NavigationPartialRoute, OnboardingFlowName, RootStackParamList, SplitNavigatorName, State} from './Navigation/types';

const SPLIT_NAVIGATORS = [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR];

const SPLIT_NAVIGATORS_SET = new Set(SPLIT_NAVIGATORS);

const FULL_SCREEN_ROUTES_SET = new Set([...SPLIT_NAVIGATORS, SCREENS.SEARCH.CENTRAL_PANE]);

const CENTRAL_PANE_SCREEN_NAMES = new Set([
SCREENS.SETTINGS.WORKSPACES,
Expand Down Expand Up @@ -43,4 +50,20 @@ function isOnboardingFlowName(screen: string | undefined): screen is OnboardingF
return ONBOARDING_SCREEN_NAMES.has(screen as OnboardingFlowName);
}

export {isCentralPaneName, removePolicyIDParamFromState, isOnboardingFlowName};
function isSplitNavigatorRoute(route: NavigationPartialRoute | undefined): route is NavigationPartialRoute<SplitNavigatorName> {
if (!route?.name) {
return false;
}

return SPLIT_NAVIGATORS_SET.has(route.name as SplitNavigatorName);
}

function isFullScreenRoute(route: NavigationPartialRoute | undefined): route is NavigationPartialRoute<FullScreenName> {
if (!route?.name) {
return false;
}

return FULL_SCREEN_ROUTES_SET.has(route.name as FullScreenName);
}

export {isCentralPaneName, removePolicyIDParamFromState, isOnboardingFlowName, isFullScreenRoute, isSplitNavigatorRoute};
Loading