diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index b95fe2a7e32a..961aad46c5cf 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -24,8 +24,8 @@ import originalGetTopmostReportId from './getTopmostReportId'; import isReportOpenInRHP from './isReportOpenInRHP'; import linkingConfig from './linkingConfig'; import getMatchingBottomTabRouteForState from './linkingConfig/getMatchingBottomTabRouteForState'; +import linkTo from './linkTo'; import navigationRef from './navigationRef'; -import linkTo from './newLinkTo'; import setNavigationActionToMicrotaskQueue from './setNavigationActionToMicrotaskQueue'; import type {NavigationStateRoute, RootStackParamList, State, StateOrRoute} from './types'; diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index 872a64d3cc8d..f8ac74d6e61f 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -1,223 +1,61 @@ import {getActionFromState} from '@react-navigation/core'; import type {NavigationContainerRef, NavigationState, PartialState} from '@react-navigation/native'; import {findFocusedRoute} from '@react-navigation/native'; -import omitBy from 'lodash/omitBy'; -import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import isReportOpenInRHP from '@libs/Navigation/isReportOpenInRHP'; -import {isCentralPaneName} from '@libs/NavigationUtils'; -import shallowCompare from '@libs/ObjectUtils'; -import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; -import getActionsFromPartialDiff from '@navigation/AppNavigator/getActionsFromPartialDiff'; -import getPartialStateDiff from '@navigation/AppNavigator/getPartialStateDiff'; -import dismissModal from '@navigation/dismissModal'; -import extractPolicyIDFromQuery from '@navigation/extractPolicyIDFromQuery'; -import extrapolateStateFromParams from '@navigation/extrapolateStateFromParams'; -import getPolicyIDFromState from '@navigation/getPolicyIDFromState'; +import {shallowCompare} from '@libs/ObjectUtils'; +import {getPathWithoutPolicyID} from '@libs/PolicyUtils'; import getStateFromPath from '@navigation/getStateFromPath'; -import getTopmostBottomTabRoute from '@navigation/getTopmostBottomTabRoute'; -import getTopmostCentralPaneRoute from '@navigation/getTopmostCentralPaneRoute'; -import getTopmostReportId from '@navigation/getTopmostReportId'; -import isSideModalNavigator from '@navigation/isSideModalNavigator'; import linkingConfig from '@navigation/linkingConfig'; -import getAdaptedStateFromPath from '@navigation/linkingConfig/getAdaptedStateFromPath'; -import getMatchingBottomTabRouteForState from '@navigation/linkingConfig/getMatchingBottomTabRouteForState'; -import getMatchingCentralPaneRouteForState from '@navigation/linkingConfig/getMatchingCentralPaneRouteForState'; -import replacePathInNestedState from '@navigation/linkingConfig/replacePathInNestedState'; -import type {NavigationRoot, RootStackParamList, StackNavigationAction, State} from '@navigation/types'; +import type {RootStackParamList, StackNavigationAction} from '@navigation/types'; import CONST from '@src/CONST'; -import NAVIGATORS from '@src/NAVIGATORS'; import type {Route} from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; -import getActionForBottomTabNavigator from './getActionForBottomTabNavigator'; import getMinimalAction from './getMinimalAction'; -import type {ActionPayloadParams} from './types'; -export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: string, isActiveRoute?: boolean) { - if (!navigation) { - throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); - } - let root: NavigationRoot = navigation; - let current: NavigationRoot | undefined; - // Traverse up to get the root navigation - // eslint-disable-next-line no-cond-assign - while ((current = root.getParent())) { - root = current; - } - - const pathWithoutPolicyID = getPathWithoutPolicyID(`/${path}`) as Route; - const rootState = navigation.getRootState() as NavigationState; - const stateFromPath = getStateFromPath(pathWithoutPolicyID) as PartialState>; - // Creating path with /w/ included if necessary. - const topmostCentralPaneRoute = getTopmostCentralPaneRoute(rootState); - - const extractedPolicyID = extractPolicyIDFromPath(`/${path}`); - const policyIDFromState = getPolicyIDFromState(rootState); - const policyID = extractedPolicyID ?? policyIDFromState; - const lastRoute = rootState?.routes?.at(-1); +function shouldDispatchAction(currentState: NavigationState, stateFromPath: PartialState>) { + const currentFocusedRoute = findFocusedRoute(currentState); + const targetFocusedRoute = findFocusedRoute(stateFromPath); - const isNarrowLayout = getIsNarrowLayout(); + const areNamesEqual = currentFocusedRoute?.name === targetFocusedRoute?.name; + const areParamsEqual = shallowCompare(currentFocusedRoute?.params as Record | undefined, targetFocusedRoute?.params as Record | undefined); - const isWorkspaceScreenOnTop = lastRoute?.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR; - - // policyID on SCREENS.SEARCH.CENTRAL_PANE can be present only as part of SearchQuery, while on other pages it's stored in the url in the format: /w/:policyID/ - if (policyID && !isWorkspaceScreenOnTop && !policyIDFromState) { - // The stateFromPath doesn't include proper path if there is a policy passed with /w/id. - // We need to replace the path in the state with the proper one. - // To avoid this hacky solution we may want to create custom getActionFromState function in the future. - replacePathInNestedState(stateFromPath, `/w/${policyID}${pathWithoutPolicyID}`); + if (areNamesEqual && areParamsEqual) { + return false; } - const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); - - const isReportInRhpOpened = isReportOpenInRHP(rootState); - - // If action type is different than NAVIGATE we can't change it to the PUSH safely - if (action?.type === CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { - const actionPayloadParams = action.payload.params as ActionPayloadParams; - - const topRouteName = lastRoute?.name; - - // CentralPane screens aren't nested in any navigator, if actionPayloadParams?.screen is undefined, it means the screen name and parameters have to be read directly from action.payload - const targetName = actionPayloadParams?.screen ?? action.payload.name; - const targetParams = actionPayloadParams?.params ?? actionPayloadParams; - const isTargetNavigatorOnTop = topRouteName === action.payload.name; - - const isTargetScreenDifferentThanCurrent = !!(!topmostCentralPaneRoute || topmostCentralPaneRoute.name !== targetName); - const areParamsDifferent = - targetName === SCREENS.REPORT - ? getTopmostReportId(rootState) !== getTopmostReportId(stateFromPath) - : !shallowCompare( - omitBy(topmostCentralPaneRoute?.params as Record | undefined, (value) => value === undefined), - omitBy(targetParams as Record | undefined, (value) => value === undefined), - ); - - // If this action is navigating to the report screen and the top most navigator is different from the one we want to navigate - PUSH the new screen to the top of the stack by default - if (isCentralPaneName(action.payload.name) && (isTargetScreenDifferentThanCurrent || areParamsDifferent)) { - // We need to push a tab if the tab doesn't match the central pane route that we are going to push. - const topmostBottomTabRoute = getTopmostBottomTabRoute(rootState); - - const focusedRoute = findFocusedRoute(stateFromPath); - const policyIDFromQuery = extractPolicyIDFromQuery(focusedRoute); - const matchingBottomTabRoute = getMatchingBottomTabRouteForState(stateFromPath, policyID ?? policyIDFromQuery); - const isOpeningSearch = matchingBottomTabRoute.name === SCREENS.SEARCH.BOTTOM_TAB; - const isNewPolicyID = - ((topmostBottomTabRoute?.params as Record)?.policyID ?? '') !== - ((matchingBottomTabRoute?.params as Record)?.policyID ?? ''); - - if (topmostBottomTabRoute && (topmostBottomTabRoute.name !== matchingBottomTabRoute.name || isNewPolicyID || isOpeningSearch)) { - root.dispatch({ - type: CONST.NAVIGATION.ACTION_TYPE.PUSH, - payload: matchingBottomTabRoute, - }); - } - - if (type === CONST.NAVIGATION.TYPE.UP) { - action.type = CONST.NAVIGATION.ACTION_TYPE.REPLACE; - } else { - action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; - } - - // If the type is UP, we deeplinked into one of the RHP flows and we want to replace the current screen with the previous one in the flow - // and at the same time we want the back button to go to the page we were before the deeplink - } else if (type === CONST.NAVIGATION.TYPE.UP) { - if (!areParamsDifferent && isSideModalNavigator(lastRoute?.name) && topmostCentralPaneRoute?.name === targetName) { - dismissModal(navigation); - return; - } - action.type = CONST.NAVIGATION.ACTION_TYPE.REPLACE; - - // If this action is navigating to ModalNavigator or WorkspaceNavigator and the last route on the root navigator is not already opened Navigator then push - } else if ((action.payload.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR || isSideModalNavigator(action.payload.name)) && !isTargetNavigatorOnTop) { - if (isSideModalNavigator(topRouteName)) { - dismissModal(navigation); - } - - // If this RHP has mandatory central pane and bottom tab screens defined we need to push them. - const {adaptedState, metainfo} = getAdaptedStateFromPath(path, linkingConfig.config); - if (adaptedState && (metainfo.isCentralPaneAndBottomTabMandatory || metainfo.isWorkspaceNavigatorMandatory)) { - const diff = getPartialStateDiff(rootState, adaptedState as State, metainfo); - const diffActions = getActionsFromPartialDiff(diff); - for (const diffAction of diffActions) { - root.dispatch(diffAction); - } - } - // All actions related to FullScreenNavigator on wide screen are pushed when comparing differences between rootState and adaptedState. - if (action.payload.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { - return; - } - action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; + return true; +} - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - } else if (action.payload.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR) { - // If path contains a policyID, we should invoke the navigate function - const shouldNavigate = !!extractedPolicyID; - const actionForBottomTabNavigator = getActionForBottomTabNavigator(action, rootState, policyID, shouldNavigate); +export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: typeof CONST.NAVIGATION.ACTION_TYPE.REPLACE) { + if (!navigation) { + throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); + } - if (!actionForBottomTabNavigator) { - return; - } + const pathWithoutPolicyID = getPathWithoutPolicyID(`/${path}`) as Route; - root.dispatch(actionForBottomTabNavigator); + // This is the state generated with the default getStateFromPath function. + // It won't include the whole state that will be generated for this path but the focused route will be correct. + // It is necessary because getActionFromState will generate RESET action for whole state generated with our custom getStateFromPath function. + const stateFromPath = getStateFromPath(pathWithoutPolicyID) as PartialState>; + const currentState = navigation.getRootState() as NavigationState; + const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); - // If the layout is wide we need to push matching central pane route to the stack. - if (!isNarrowLayout) { - // stateFromPath should always include bottom tab navigator state, so getMatchingCentralPaneRouteForState will be always defined. - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const matchingCentralPaneRoute = getMatchingCentralPaneRouteForState(stateFromPath, rootState)!; - if (matchingCentralPaneRoute && 'name' in matchingCentralPaneRoute) { - root.dispatch({ - type: CONST.NAVIGATION.ACTION_TYPE.PUSH, - payload: { - name: matchingCentralPaneRoute.name, - params: matchingCentralPaneRoute.params, - }, - }); - } - } else { - // If the layout is small we need to pop everything from the central pane so the bottom tab navigator is visible. - root.dispatch({ - type: 'POP_TO_TOP', - target: rootState.key, - }); - } - return; - } + // We don't want to dispatch action to push/replace with exactly the same route that is already focused. + if (!shouldDispatchAction(currentState, stateFromPath)) { + return; } - if (action && 'payload' in action && action.payload && 'name' in action.payload && isSideModalNavigator(action.payload.name)) { - // Information about the state may be in the params. - const currentFocusedRoute = findFocusedRoute(extrapolateStateFromParams(rootState)); - const targetFocusedRoute = findFocusedRoute(stateFromPath); - - // If the current focused route is the same as the target focused route, we don't want to navigate. - if ( - currentFocusedRoute?.name === targetFocusedRoute?.name && - shallowCompare(currentFocusedRoute?.params as Record, targetFocusedRoute?.params as Record) - ) { - return; - } - - const minimalAction = getMinimalAction(action, navigation.getRootState()); - if (minimalAction) { - // There are situations where a route already exists on the current navigation stack - // But we want to push the same route instead of going back in the stack - // Which would break the user navigation history - if (!isActiveRoute && type === CONST.NAVIGATION.ACTION_TYPE.PUSH) { - minimalAction.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; - } - root.dispatch(minimalAction); - return; - } + // If there is no action, just reset the whole state. + if (!action) { + navigation.resetRoot(stateFromPath); + return; } - // When we navigate from the ReportScreen opened in RHP, this page shouldn't be removed from the navigation state to allow users to go back to it. - if (isReportInRhpOpened && action) { + if (type === CONST.NAVIGATION.ACTION_TYPE.REPLACE) { + action.type = CONST.NAVIGATION.ACTION_TYPE.REPLACE; + } else if (action.type === CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { + // We want to PUSH by default to add entries to the browser history. action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; } - if (action !== undefined) { - root.dispatch(action); - } else { - root.reset(stateFromPath); - } + const minimalAction = getMinimalAction(action, navigation.getRootState()); + navigation.dispatch(minimalAction); } diff --git a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/RELATIONS/CENTRAL_PANE_TO_RHP_MAPPING.ts similarity index 100% rename from src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts rename to src/libs/Navigation/linkingConfig/RELATIONS/CENTRAL_PANE_TO_RHP_MAPPING.ts diff --git a/src/libs/Navigation/linkingConfig/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts b/src/libs/Navigation/linkingConfig/RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts similarity index 100% rename from src/libs/Navigation/linkingConfig/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts rename to src/libs/Navigation/linkingConfig/RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts diff --git a/src/libs/Navigation/linkingConfig/SEARCH_RHP_SCREENS.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_RHP_SCREENS.ts similarity index 100% rename from src/libs/Navigation/linkingConfig/SEARCH_RHP_SCREENS.ts rename to src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_RHP_SCREENS.ts diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_TO_RHP.ts new file mode 100644 index 000000000000..9d50f1735d94 --- /dev/null +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_TO_RHP.ts @@ -0,0 +1,25 @@ +import SCREENS from '@src/SCREENS'; + +const SEARCH_TO_RHP: string[] = [ + SCREENS.SEARCH.REPORT_RHP, + SCREENS.SEARCH.TRANSACTION_HOLD_REASON_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_CURRENCY_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_DATE_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_DESCRIPTION_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_MERCHANT_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_REPORT_ID_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_AMOUNT_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_CATEGORY_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_KEYWORD_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_TAX_RATE_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_EXPENSE_TYPE_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_TAG_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_FROM_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_TO_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_IN_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_CARD_RHP, + SCREENS.SEARCH.SAVED_SEARCH_RENAME_RHP, +]; + +export default SEARCH_TO_RHP; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts new file mode 100755 index 000000000000..824fc072d686 --- /dev/null +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts @@ -0,0 +1,62 @@ +import SCREENS from '@src/SCREENS'; + +// const CENTRAL_PANE_TO_RHP_MAPPING: Partial> = { +const CENTRAL_PANE_TO_RHP_MAPPING: Record = { + [SCREENS.SETTINGS.PROFILE.ROOT]: [ + SCREENS.SETTINGS.PROFILE.DISPLAY_NAME, + SCREENS.SETTINGS.PROFILE.CONTACT_METHODS, + SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_DETAILS, + SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_VALIDATE_ACTION, + SCREENS.SETTINGS.PROFILE.NEW_CONTACT_METHOD, + SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER, + SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_DATE, + SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_TIME, + SCREENS.SETTINGS.PROFILE.STATUS, + SCREENS.SETTINGS.PROFILE.PRONOUNS, + SCREENS.SETTINGS.PROFILE.TIMEZONE, + SCREENS.SETTINGS.PROFILE.TIMEZONE_SELECT, + SCREENS.SETTINGS.PROFILE.LEGAL_NAME, + SCREENS.SETTINGS.PROFILE.DATE_OF_BIRTH, + SCREENS.SETTINGS.PROFILE.ADDRESS, + SCREENS.SETTINGS.PROFILE.ADDRESS_COUNTRY, + SCREENS.SETTINGS.SHARE_CODE, + SCREENS.SETTINGS.EXIT_SURVEY.REASON, + SCREENS.SETTINGS.EXIT_SURVEY.RESPONSE, + SCREENS.SETTINGS.EXIT_SURVEY.CONFIRM, + ], + [SCREENS.SETTINGS.PREFERENCES.ROOT]: [SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE, SCREENS.SETTINGS.PREFERENCES.LANGUAGE, SCREENS.SETTINGS.PREFERENCES.THEME], + [SCREENS.SETTINGS.WALLET.ROOT]: [ + SCREENS.SETTINGS.WALLET.DOMAIN_CARD, + SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.NAME, + SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.PHONE, + SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.ADDRESS, + SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.CONFIRM, + SCREENS.SETTINGS.WALLET.TRANSFER_BALANCE, + SCREENS.SETTINGS.WALLET.CHOOSE_TRANSFER_ACCOUNT, + SCREENS.SETTINGS.WALLET.ENABLE_PAYMENTS, + SCREENS.SETTINGS.WALLET.CARD_ACTIVATE, + SCREENS.SETTINGS.WALLET.REPORT_VIRTUAL_CARD_FRAUD, + SCREENS.SETTINGS.WALLET.CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS, + ], + [SCREENS.SETTINGS.SECURITY]: [ + SCREENS.SETTINGS.TWO_FACTOR_AUTH, + SCREENS.SETTINGS.CLOSE, + SCREENS.SETTINGS.DELEGATE.ADD_DELEGATE, + SCREENS.SETTINGS.DELEGATE.DELEGATE_ROLE, + SCREENS.SETTINGS.DELEGATE.DELEGATE_CONFIRM, + SCREENS.SETTINGS.DELEGATE.DELEGATE_MAGIC_CODE, + ], + [SCREENS.SETTINGS.ABOUT]: [SCREENS.SETTINGS.APP_DOWNLOAD_LINKS], + [SCREENS.SETTINGS.SAVE_THE_WORLD]: [SCREENS.I_KNOW_A_TEACHER, SCREENS.INTRO_SCHOOL_PRINCIPAL, SCREENS.I_AM_A_TEACHER], + [SCREENS.SETTINGS.TROUBLESHOOT]: [SCREENS.SETTINGS.CONSOLE], + [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: [ + SCREENS.SETTINGS.SUBSCRIPTION.ADD_PAYMENT_CARD, + SCREENS.SETTINGS.SUBSCRIPTION.SIZE, + SCREENS.SETTINGS.SUBSCRIPTION.DISABLE_AUTO_RENEW_SURVEY, + SCREENS.SETTINGS.SUBSCRIPTION.REQUEST_EARLY_CANCELLATION, + SCREENS.SETTINGS.SUBSCRIPTION.CHANGE_BILLING_CURRENCY, + SCREENS.SETTINGS.SUBSCRIPTION.CHANGE_PAYMENT_CURRENCY, + ], +}; + +export default CENTRAL_PANE_TO_RHP_MAPPING; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts new file mode 100644 index 000000000000..ba006376940e --- /dev/null +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts @@ -0,0 +1,17 @@ +import SCREENS from '@src/SCREENS'; + +const SIDEBAR_TO_RHP: Record = { + // @TODO are those really all to home? + [SCREENS.HOME]: [ + SCREENS.SETTINGS.SHARE_CODE, + SCREENS.SETTINGS.PROFILE.STATUS, + SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE, + SCREENS.MONEY_REQUEST.CREATE, + SCREENS.SETTINGS.EXIT_SURVEY.REASON, + SCREENS.SETTINGS.EXIT_SURVEY.RESPONSE, + SCREENS.SETTINGS.EXIT_SURVEY.CONFIRM, + SCREENS.HOME, + ], +}; + +export default SIDEBAR_TO_RHP; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT.ts new file mode 100644 index 000000000000..597f6dcd4ccb --- /dev/null +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT.ts @@ -0,0 +1,10 @@ +import NAVIGATORS from '@src/NAVIGATORS'; +import SCREENS from '@src/SCREENS'; + +const SIDEBAR_TO_SPLIT = { + [SCREENS.SETTINGS.ROOT]: NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, + [SCREENS.HOME]: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, + [SCREENS.WORKSPACE.INITIAL]: NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, +}; + +export default SIDEBAR_TO_SPLIT; diff --git a/src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts b/src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts similarity index 100% rename from src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts rename to src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts diff --git a/src/libs/Navigation/linkingConfig/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts similarity index 100% rename from src/libs/Navigation/linkingConfig/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts rename to src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts new file mode 100755 index 000000000000..51c8642bd7cb --- /dev/null +++ b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts @@ -0,0 +1,217 @@ +import type {WorkspaceScreenName} from '@libs/Navigation/types'; +import SCREENS from '@src/SCREENS'; + +const WORKSPACE_TO_RHP: Partial> = { + [SCREENS.WORKSPACE.PROFILE]: [SCREENS.WORKSPACE.NAME, SCREENS.WORKSPACE.ADDRESS, SCREENS.WORKSPACE.CURRENCY, SCREENS.WORKSPACE.DESCRIPTION, SCREENS.WORKSPACE.SHARE], + [SCREENS.WORKSPACE.MEMBERS]: [ + SCREENS.WORKSPACE.INVITE, + SCREENS.WORKSPACE.INVITE_MESSAGE, + SCREENS.WORKSPACE.MEMBER_DETAILS, + SCREENS.WORKSPACE.MEMBER_NEW_CARD, + SCREENS.WORKSPACE.OWNER_CHANGE_CHECK, + SCREENS.WORKSPACE.OWNER_CHANGE_SUCCESS, + SCREENS.WORKSPACE.OWNER_CHANGE_ERROR, + SCREENS.WORKSPACE.OWNER_CHANGE_ERROR, + SCREENS.WORKSPACE.MEMBERS_IMPORT, + SCREENS.WORKSPACE.MEMBERS_IMPORTED, + ], + [SCREENS.WORKSPACE.WORKFLOWS]: [ + SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_NEW, + SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_EDIT, + SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_EXPENSES_FROM, + SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_APPROVER, + SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_FREQUENCY, + SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_MONTHLY_OFFSET, + SCREENS.WORKSPACE.WORKFLOWS_PAYER, + ], + [SCREENS.WORKSPACE.ACCOUNTING.ROOT]: [ + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_IMPORT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CHART_OF_ACCOUNTS, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CLASSES, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_TAXES, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_LOCATIONS, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CUSTOMERS, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_DATE_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_INVOICE_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_COMPANY_CARD_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_PREFERRED_EXPORTER, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_NON_REIMBURSABLE_DEFAULT_VENDOR_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_ADVANCED, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_ACCOUNT_SELECTOR, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR, + SCREENS.WORKSPACE.ACCOUNTING.XERO_IMPORT, + SCREENS.WORKSPACE.ACCOUNTING.XERO_CHART_OF_ACCOUNTS, + SCREENS.WORKSPACE.ACCOUNTING.XERO_ORGANIZATION, + SCREENS.WORKSPACE.ACCOUNTING.XERO_CUSTOMER, + SCREENS.WORKSPACE.ACCOUNTING.XERO_TAXES, + SCREENS.WORKSPACE.ACCOUNTING.XERO_TRACKING_CATEGORIES, + SCREENS.WORKSPACE.ACCOUNTING.XERO_MAP_TRACKING_CATEGORY, + SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT, + SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT_PURCHASE_BILL_DATE_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.XERO_ADVANCED, + SCREENS.WORKSPACE.ACCOUNTING.XERO_BILL_STATUS_SELECTOR, + SCREENS.WORKSPACE.ACCOUNTING.XERO_INVOICE_ACCOUNT_SELECTOR, + SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT_PREFERRED_EXPORTER_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.XERO_BILL_PAYMENT_ACCOUNT_SELECTOR, + SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT_BANK_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_SUBSIDIARY_SELECTOR, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_REUSE_EXISTING_CONNECTIONS, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_TOKEN_INPUT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_MAPPING, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_VIEW, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_EDIT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_LIST_ADD, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_SEGMENT_ADD, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_PREFERRED_EXPORTER_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_DATE_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_DESTINATION_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_VENDOR_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_PAYABLE_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_JOURNAL_POSTING_PREFERENCE_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_RECEIVABLE_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_INVOICE_ITEM_PREFERENCE_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_INVOICE_ITEM_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_TAX_POSTING_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_PROVINCIAL_TAX_POSTING_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_ADVANCED, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_REIMBURSEMENT_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_COLLECTION_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPENSE_REPORT_APPROVAL_LEVEL_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_VENDOR_BILL_APPROVAL_LEVEL_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_JOURNAL_ENTRY_APPROVAL_LEVEL_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_APPROVAL_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_CUSTOM_FORM_ID, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_PREREQUISITES, + SCREENS.WORKSPACE.ACCOUNTING.ENTER_SAGE_INTACCT_CREDENTIALS, + SCREENS.WORKSPACE.ACCOUNTING.EXISTING_SAGE_INTACCT_CONNECTIONS, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_ENTITY, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_IMPORT, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_MAPPING_TYPE, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_TOGGLE_MAPPING, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_USER_DIMENSIONS, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_ADD_USER_DIMENSION, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_EDIT_USER_DIMENSION, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_EXPORT, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_PREFERRED_EXPORTER, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_EXPORT_DATE, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_REIMBURSABLE_EXPENSES, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_NON_REIMBURSABLE_EXPENSES, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_REIMBURSABLE_DESTINATION, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_NON_REIMBURSABLE_DESTINATION, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_DEFAULT_VENDOR, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_NON_REIMBURSABLE_CREDIT_CARD_ACCOUNT, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_ADVANCED, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_PAYMENT_ACCOUNT, + SCREENS.WORKSPACE.ACCOUNTING.CARD_RECONCILIATION, + SCREENS.WORKSPACE.ACCOUNTING.RECONCILIATION_ACCOUNT_SETTINGS, + ], + [SCREENS.WORKSPACE.TAXES]: [ + SCREENS.WORKSPACE.TAXES_SETTINGS, + SCREENS.WORKSPACE.TAX_CREATE, + SCREENS.WORKSPACE.TAXES_SETTINGS_CUSTOM_TAX_NAME, + SCREENS.WORKSPACE.TAXES_SETTINGS_FOREIGN_CURRENCY_DEFAULT, + SCREENS.WORKSPACE.TAXES_SETTINGS_WORKSPACE_CURRENCY_DEFAULT, + SCREENS.WORKSPACE.TAX_CREATE, + SCREENS.WORKSPACE.TAX_EDIT, + SCREENS.WORKSPACE.TAX_NAME, + SCREENS.WORKSPACE.TAX_VALUE, + SCREENS.WORKSPACE.TAX_CODE, + ], + [SCREENS.WORKSPACE.TAGS]: [ + SCREENS.WORKSPACE.TAGS_SETTINGS, + SCREENS.WORKSPACE.TAGS_EDIT, + SCREENS.WORKSPACE.TAG_CREATE, + SCREENS.WORKSPACE.TAG_SETTINGS, + SCREENS.WORKSPACE.TAG_EDIT, + SCREENS.WORKSPACE.TAG_LIST_VIEW, + SCREENS.WORKSPACE.TAG_GL_CODE, + SCREENS.WORKSPACE.TAG_APPROVER, + SCREENS.WORKSPACE.TAGS_IMPORT, + SCREENS.WORKSPACE.TAGS_IMPORTED, + ], + [SCREENS.WORKSPACE.CATEGORIES]: [ + SCREENS.WORKSPACE.CATEGORY_CREATE, + SCREENS.WORKSPACE.CATEGORY_SETTINGS, + SCREENS.WORKSPACE.CATEGORIES_IMPORT, + SCREENS.WORKSPACE.CATEGORIES_IMPORTED, + SCREENS.WORKSPACE.CATEGORIES_SETTINGS, + SCREENS.WORKSPACE.CATEGORY_EDIT, + SCREENS.WORKSPACE.CATEGORY_GL_CODE, + SCREENS.WORKSPACE.CATEGORY_PAYROLL_CODE, + SCREENS.WORKSPACE.CATEGORY_DEFAULT_TAX_RATE, + SCREENS.WORKSPACE.CATEGORY_FLAG_AMOUNTS_OVER, + SCREENS.WORKSPACE.CATEGORY_DESCRIPTION_HINT, + SCREENS.WORKSPACE.CATEGORY_APPROVER, + SCREENS.WORKSPACE.CATEGORY_REQUIRE_RECEIPTS_OVER, + ], + [SCREENS.WORKSPACE.DISTANCE_RATES]: [ + SCREENS.WORKSPACE.CREATE_DISTANCE_RATE, + SCREENS.WORKSPACE.DISTANCE_RATES_SETTINGS, + SCREENS.WORKSPACE.DISTANCE_RATE_EDIT, + SCREENS.WORKSPACE.DISTANCE_RATE_TAX_RECLAIMABLE_ON_EDIT, + SCREENS.WORKSPACE.DISTANCE_RATE_TAX_RATE_EDIT, + SCREENS.WORKSPACE.DISTANCE_RATE_DETAILS, + ], + [SCREENS.WORKSPACE.REPORT_FIELDS]: [ + SCREENS.WORKSPACE.REPORT_FIELDS_CREATE, + SCREENS.WORKSPACE.REPORT_FIELDS_SETTINGS, + SCREENS.WORKSPACE.REPORT_FIELDS_LIST_VALUES, + SCREENS.WORKSPACE.REPORT_FIELDS_ADD_VALUE, + SCREENS.WORKSPACE.REPORT_FIELDS_VALUE_SETTINGS, + SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_VALUE, + SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE, + ], + [SCREENS.WORKSPACE.INVOICES]: [SCREENS.WORKSPACE.INVOICES_COMPANY_NAME, SCREENS.WORKSPACE.INVOICES_COMPANY_WEBSITE], + [SCREENS.WORKSPACE.COMPANY_CARDS]: [ + SCREENS.WORKSPACE.COMPANY_CARDS_SELECT_FEED, + SCREENS.WORKSPACE.COMPANY_CARDS_ADD_NEW, + SCREENS.WORKSPACE.COMPANY_CARDS_TYPE, + SCREENS.WORKSPACE.COMPANY_CARDS_INSTRUCTIONS, + SCREENS.WORKSPACE.COMPANY_CARDS_NAME, + SCREENS.WORKSPACE.COMPANY_CARDS_DETAILS, + SCREENS.WORKSPACE.COMPANY_CARDS_SELECT_FEED, + SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS, + SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS_FEED_NAME, + SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS, + SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS_FEED_NAME, + SCREENS.WORKSPACE.COMPANY_CARDS_ASSIGN_CARD, + SCREENS.WORKSPACE.COMPANY_CARD_DETAILS, + SCREENS.WORKSPACE.COMPANY_CARD_NAME, + SCREENS.WORKSPACE.COMPANY_CARD_EXPORT, + ], + [SCREENS.WORKSPACE.EXPENSIFY_CARD]: [ + SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW, + SCREENS.WORKSPACE.EXPENSIFY_CARD_BANK_ACCOUNT, + SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS, + SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS_ACCOUNT, + SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS_FREQUENCY, + SCREENS.WORKSPACE.EXPENSIFY_CARD_DETAILS, + SCREENS.WORKSPACE.EXPENSIFY_CARD_NAME, + SCREENS.WORKSPACE.EXPENSIFY_CARD_LIMIT, + SCREENS.WORKSPACE.EXPENSIFY_CARD_LIMIT_TYPE, + ], + [SCREENS.WORKSPACE.RULES]: [ + SCREENS.WORKSPACE.RULES_CUSTOM_NAME, + SCREENS.WORKSPACE.RULES_AUTO_APPROVE_REPORTS_UNDER, + SCREENS.WORKSPACE.RULES_RANDOM_REPORT_AUDIT, + SCREENS.WORKSPACE.RULES_AUTO_PAY_REPORTS_UNDER, + SCREENS.WORKSPACE.RULES_RECEIPT_REQUIRED_AMOUNT, + SCREENS.WORKSPACE.RULES_MAX_EXPENSE_AMOUNT, + SCREENS.WORKSPACE.RULES_MAX_EXPENSE_AGE, + SCREENS.WORKSPACE.RULES_BILLABLE_DEFAULT, + ], +}; + +export default WORKSPACE_TO_RHP; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/index.ts b/src/libs/Navigation/linkingConfig/RELATIONS/index.ts new file mode 100644 index 000000000000..4e3e6d7543e2 --- /dev/null +++ b/src/libs/Navigation/linkingConfig/RELATIONS/index.ts @@ -0,0 +1,29 @@ +import SEARCH_TO_RHP from './SEARCH_TO_RHP'; +import SETTINGS_TO_RHP from './SETTINGS_TO_RHP'; +import SIDEBAR_TO_RHP from './SIDEBAR_TO_RHP'; +import SIDEBAR_TO_SPLIT from './SIDEBAR_TO_SPLIT'; +import WORKSPACE_TO_RHP from './WORKSPACE_TO_RHP'; + +// @TODO: fix types +function createInverseRelation(relations: Record): Record { + const reversedRelations = {} as Record; + + Object.entries(relations).forEach(([key, values]) => { + const valuesWithType = values as K[]; + valuesWithType.forEach((value: K) => { + reversedRelations[value] = key as T; + }); + }); + return reversedRelations; +} + +export default { + SETTINGS_TO_RHP, + RHP_TO_SETTINGS: createInverseRelation(SETTINGS_TO_RHP), + RHP_TO_WORKSPACE: createInverseRelation(WORKSPACE_TO_RHP), + RHP_TO_SIDEBAR: createInverseRelation(SIDEBAR_TO_RHP), + SEARCH_TO_RHP, + SIDEBAR_TO_RHP, + WORKSPACE_TO_RHP, + SIDEBAR_TO_SPLIT, +}; diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 210db4ef6fad..aa541bf12f5b 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -10,7 +10,7 @@ import createNormalizedConfigs from './createNormalizedConfigs'; // Moved to a separate file to avoid cyclic dependencies. const config: LinkingOptions['config'] = { // initialRouteName: NAVIGATORS.BOTTOM_TAB_NAVIGATOR, - initialRouteName: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, + // initialRouteName: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, screens: { // Main Routes [SCREENS.VALIDATE_LOGIN]: ROUTES.VALIDATE_LOGIN, diff --git a/src/libs/Navigation/linkingConfig/createSplitNavigator.ts b/src/libs/Navigation/linkingConfig/createSplitNavigator.ts index b016e535052e..aa1a1bef6760 100644 --- a/src/libs/Navigation/linkingConfig/createSplitNavigator.ts +++ b/src/libs/Navigation/linkingConfig/createSplitNavigator.ts @@ -1,6 +1,6 @@ import type {NavigationState, PartialState} from '@react-navigation/native'; import type {NavigationPartialRoute, SplitNavigatorByLHN, SplitNavigatorLHNScreen, SplitNavigatorParamListType} from '@libs/Navigation/types'; -import LHN_TO_SPLIT_NAVIGATOR_NAME from './LHN_TO_SPLIT_NAVIGATOR_MAPPING'; +import LHN_TO_SPLIT_NAVIGATOR_NAME from './RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING'; type ExtractRouteType = Extract; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index e127eaea11d0..07dc2863c3ca 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -1,62 +1,26 @@ import type {NavigationState, PartialState, Route} from '@react-navigation/native'; import {findFocusedRoute, getStateFromPath} from '@react-navigation/native'; import pick from 'lodash/pick'; -import type {TupleToUnion} from 'type-fest'; import {isAnonymousUser} from '@libs/actions/Session'; -import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import type {NavigationPartialRoute, RootStackParamList} from '@libs/Navigation/types'; +import type {NavigationPartialRoute, RootStackParamList, SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import * as ReportConnection from '@libs/ReportConnection'; import extractPolicyIDFromQuery from '@navigation/extractPolicyIDFromQuery'; -import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Screen} from '@src/SCREENS'; import SCREENS from '@src/SCREENS'; -import CENTRAL_PANE_TO_RHP_MAPPING from './CENTRAL_PANE_TO_RHP_MAPPING'; import config, {normalizedConfigs} from './config'; import createSplitNavigator from './createSplitNavigator'; +import RELATIONS from './RELATIONS'; import replacePathInNestedState from './replacePathInNestedState'; -import SEARCH_RHP_SCREENS from './SEARCH_RHP_SCREENS'; -import {CENTRAL_PANE_TO_TAB_MAPPING} from './TAB_TO_CENTRAL_PANE_MAPPING'; - -const RHP_SCREENS_OPENED_FROM_LHN = [ - SCREENS.SETTINGS.SHARE_CODE, - SCREENS.SETTINGS.PROFILE.STATUS, - SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE, - SCREENS.MONEY_REQUEST.CREATE, - SCREENS.SETTINGS.EXIT_SURVEY.REASON, - SCREENS.SETTINGS.EXIT_SURVEY.RESPONSE, - SCREENS.SETTINGS.EXIT_SURVEY.CONFIRM, -] satisfies Screen[]; - -const mapLhnToSplitNavigatorName = { - [SCREENS.SETTINGS.ROOT]: NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, - [SCREENS.HOME]: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, - [SCREENS.WORKSPACE.INITIAL]: NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, -}; - -type RHPScreenOpenedFromLHN = TupleToUnion; - -type Metainfo = { - // Sometimes modal screens don't have information about what should be visible under the overlay. - // That means such screen can have different screens under the overlay depending on what was already in the state. - // If the screens in the bottom tab and central pane are not mandatory for this state, we want to have this information. - // It will help us later with creating proper diff betwen current and desired state. - isCentralPaneAndBottomTabMandatory: boolean; - isWorkspaceNavigatorMandatory: boolean; -}; type GetAdaptedStateReturnType = { adaptedState: ReturnType; - // metainfo: Metainfo; }; type GetAdaptedStateFromPath = (...args: [...Parameters, shouldReplacePathInNestedState?: boolean]) => GetAdaptedStateReturnType; -type SplitNavigatorLHNScreen = keyof typeof mapLhnToSplitNavigatorName; -type SplitNavigator = (typeof mapLhnToSplitNavigatorName)[SplitNavigatorLHNScreen]; - // The function getPathFromState that we are using in some places isn't working correctly without defined index. const getRoutesWithIndex = (routes: NavigationPartialRoute[]): PartialState => ({routes, index: routes.length - 1}); @@ -68,222 +32,154 @@ function getParamsFromRoute(screenName: string): string[] { return route.match(/(?<=[:?&])(\w+)(?=[/=?&]|$)/g) ?? []; } -// This function will return CentralPaneNavigator route or WorkspaceNavigator route. -function getMatchingRootRouteForRHPRoute(route: NavigationPartialRoute): NavigationPartialRoute | NavigationPartialRoute<'Search_Central_Pane'> | undefined { - // Check for backTo param. One screen with different backTo value may need diferent screens visible under the overlay. - if (route.params && 'backTo' in route.params && typeof route.params.backTo === 'string') { - const stateForBackTo = getStateFromPath(route.params.backTo, config); - if (stateForBackTo) { - // If there is rhpNavigator in the state generated for backTo url, we want to get root route matching to this rhp screen. - const rhpNavigator = stateForBackTo.routes.find((rt) => rt.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR); - if (rhpNavigator && rhpNavigator.state) { - const isRHPinState = stateForBackTo.routes.at(0)?.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR; - - if (isRHPinState) { - return getMatchingRootRouteForRHPRoute(findFocusedRoute(stateForBackTo) as NavigationPartialRoute); - } - } - - const splitNavigator = stateForBackTo.routes.find( - // eslint-disable-next-line @typescript-eslint/no-shadow - (route) => route.name.endsWith('SplitNavigator'), - ); - - // If we know that backTo targets the root route (central pane or full screen) we want to use it. - if (splitNavigator && splitNavigator.state) { - return splitNavigator as NavigationPartialRoute; - } - } +function isRouteWithBackToParam(route: NavigationPartialRoute): route is Route { + return route.params !== undefined && 'backTo' in route.params && typeof route.params.backTo === 'string'; +} + +function isRouteWithReportID(route: NavigationPartialRoute): route is Route { + return route.params !== undefined && 'reportID' in route.params && typeof route.params.reportID === 'string'; +} + +function getMatchingFullScreenRouteForState(state: PartialState>) { + const focusedRoute = findFocusedRoute(state); + + if (!focusedRoute) { + return undefined; } - // Check for CentralPaneNavigator - for (const [centralPaneName, RHPNames] of Object.entries(CENTRAL_PANE_TO_RHP_MAPPING)) { - if (RHPNames.includes(route.name)) { - const paramsFromRoute = getParamsFromRoute(centralPaneName); - return createSplitNavigator( - {name: CENTRAL_PANE_TO_TAB_MAPPING[centralPaneName as SplitNavigatorScreenName] as SplitNavigatorLHNScreen, params: pick(route.params, paramsFromRoute)}, - { - name: centralPaneName, - params: pick(route.params, paramsFromRoute), - }, - ); + // Check for backTo param. One screen with different backTo value may need different screens visible under the overlay. + if (isRouteWithBackToParam(focusedRoute)) { + const stateForBackTo = getStateFromPath(focusedRoute.params.backTo, config); + + // This may happen if the backTo url is invalid. + const lastRoute = stateForBackTo?.routes.at(-1); + if (!stateForBackTo || !lastRoute || lastRoute.name === SCREENS.NOT_FOUND) { + return undefined; + } + + const isLastRouteFullScreen = isFullScreenRoute(lastRoute); + + // If the state for back to last route is a full screen route, we can use it + if (isLastRouteFullScreen) { + return lastRoute; } + + // If not, get the matching full screen route for the back to state. + return getMatchingFullScreenRouteForState(stateForBackTo as PartialState>); } - if (SEARCH_RHP_SCREENS.includes(route.name)) { + if (RELATIONS.SEARCH_TO_RHP.includes(focusedRoute.name)) { const paramsFromRoute = getParamsFromRoute(SCREENS.SEARCH.CENTRAL_PANE); return { name: SCREENS.SEARCH.CENTRAL_PANE, - params: pick(route.params, paramsFromRoute), + params: pick(focusedRoute.params, paramsFromRoute), }; } - // check for valid reportID in the route params - // if the reportID is valid, we should navigate back to screen report in CPN - const reportID = (route.params as Record)?.reportID; - if (ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.reportID) { - return createSplitNavigator({name: SCREENS.HOME}, {name: SCREENS.REPORT, params: {reportID}}); + 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, + }); } -} - -function getAdaptedState(state: PartialState>, policyID?: string): GetAdaptedStateReturnType { - const isNarrowLayout = getIsNarrowLayout(); - // const metainfo = { - // isCentralPaneAndBottomTabMandatory: true, - // isWorkspaceNavigatorMandatory: true, - // }; - - // We need to check what is defined to know what we need to add. - const workspaceNavigator = state.routes.find((route) => route.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR); - const reportNavigator = state.routes.find((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); - const rhpNavigator = state.routes.find((route) => route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR); - const lhpNavigator = state.routes.find((route) => route.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR); - const onboardingModalNavigator = state.routes.find((route) => route.name === NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR); - const welcomeVideoModalNavigator = state.routes.find((route) => route.name === NAVIGATORS.WELCOME_VIDEO_MODAL_NAVIGATOR); - const attachmentsScreen = state.routes.find((route) => route.name === SCREENS.ATTACHMENTS); - const featureTrainingModalNavigator = state.routes.find((route) => route.name === NAVIGATORS.FEATURE_TRANING_MODAL_NAVIGATOR); - - if (rhpNavigator) { - // Routes - // - matching bottom tab - // - matching root route for rhp - // - found rhp - - // This one will be defined because rhpNavigator is defined. - const focusedRHPRoute = findFocusedRoute(state); - const routes = []; - if (focusedRHPRoute) { - let matchingRootRoute = getMatchingRootRouteForRHPRoute(focusedRHPRoute); - const isRHPScreenOpenedFromLHN = focusedRHPRoute?.name && RHP_SCREENS_OPENED_FROM_LHN.includes(focusedRHPRoute?.name as RHPScreenOpenedFromLHN); - // This may happen if this RHP doesn't have a route that should be under the overlay defined. - if (!matchingRootRoute || isRHPScreenOpenedFromLHN) { - // metainfo.isCentralPaneAndBottomTabMandatory = false; - // metainfo.isWorkspaceNavigatorMandatory = false; - // If matchingRootRoute is undefined and it's a narrow layout, don't add a report screen under the RHP. - matchingRootRoute = matchingRootRoute ?? (!isNarrowLayout ? createSplitNavigator({name: SCREENS.HOME}, {name: SCREENS.REPORT}) : createSplitNavigator({name: SCREENS.HOME})); - } - - // When we open a screen in RHP from WorkspaceNavigator, we need to add the appropriate screen in CentralPane. - // Then, when we close WorkspaceNavigator, we will be redirected to the correct page in CentralPane. - if (matchingRootRoute?.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { - routes.push(createSplitNavigator({name: SCREENS.SETTINGS.ROOT}, {name: SCREENS.SETTINGS.WORKSPACES})); - } - - if (matchingRootRoute && (!isNarrowLayout || !isRHPScreenOpenedFromLHN)) { - routes.push(matchingRootRoute); - } - } + // @TODO We can think about handling it in one condition. + if (RELATIONS.RHP_TO_WORKSPACE[focusedRoute.name]) { + const paramsFromRoute = getParamsFromRoute(SCREENS.SEARCH.CENTRAL_PANE); - routes.push(rhpNavigator); - return { - adaptedState: getRoutesWithIndex(routes), - // metainfo, - }; + return createSplitNavigator( + { + name: SCREENS.WORKSPACE.INITIAL, + }, + { + name: RELATIONS.RHP_TO_WORKSPACE[focusedRoute.name], + params: { + ...pick(focusedRoute.params, paramsFromRoute), + }, + }, + ); } - if (lhpNavigator ?? onboardingModalNavigator ?? welcomeVideoModalNavigator ?? featureTrainingModalNavigator) { - // Routes - // - default bottom tab - // - default central pane on desktop layout - // - found lhp / onboardingModalNavigator - - // There is no screen in these navigators that would have mandatory central pane, bottom tab or workspace navigator. - // metainfo.isCentralPaneAndBottomTabMandatory = false; - // metainfo.isWorkspaceNavigatorMandatory = false; - const routes = []; - const splitNavigatorMainScreen = !isNarrowLayout - ? { - name: SCREENS.REPORT, - } - : undefined; + if (RELATIONS.RHP_TO_SETTINGS[focusedRoute.name]) { + const paramsFromRoute = getParamsFromRoute(SCREENS.SEARCH.CENTRAL_PANE); + + return createSplitNavigator( + { + name: SCREENS.SETTINGS.ROOT, + }, + { + name: RELATIONS.RHP_TO_SETTINGS[focusedRoute.name] as keyof SettingsSplitNavigatorParamList, + params: { + ...pick(focusedRoute.params, paramsFromRoute), + }, + }, + ); + } - routes.push(createSplitNavigator({name: SCREENS.HOME}, splitNavigatorMainScreen)); + // @TODO should we push this route on narrow layout? + // @TODO maybe we can handle this with regular flow. + if (isRouteWithReportID(focusedRoute)) { + const reportID = focusedRoute.params.reportID; + const paramsFromRoute = getParamsFromRoute(SCREENS.REPORT); - // Separate ifs are necessary for typescript to see that we are not pushing undefined to the array. - if (lhpNavigator) { - routes.push(lhpNavigator); + if (!ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.reportID) { + return; } - if (onboardingModalNavigator) { - routes.push(onboardingModalNavigator); - } + return createSplitNavigator( + { + name: SCREENS.HOME, + }, + { + name: SCREENS.REPORT, + params: { + reportID: '-1', + ...pick(focusedRoute.params, paramsFromRoute), + }, + }, + ); + } - if (welcomeVideoModalNavigator) { - routes.push(welcomeVideoModalNavigator); - } + return undefined; +} - if (featureTrainingModalNavigator) { - routes.push(featureTrainingModalNavigator); - } +const FULL_SCREEN_ROUTES: string[] = [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, SCREENS.SEARCH.CENTRAL_PANE]; - return { - adaptedState: getRoutesWithIndex(routes), - }; - } - if (workspaceNavigator) { - // Routes - // - default bottom tab - // - default central pane on desktop layout - // - found workspace navigator +function isFullScreenRoute(route: NavigationPartialRoute): boolean { + return FULL_SCREEN_ROUTES.includes(route.name); +} - const routes = []; - routes.push( - createSplitNavigator( - {name: SCREENS.SETTINGS.ROOT}, - { - name: SCREENS.SETTINGS.WORKSPACES, - params: { - policyID, - }, - }, - ), - ); +function getAdaptedState(state: PartialState>, policyID?: string): GetAdaptedStateReturnType { + const fullScreenRoute = state.routes.find(isFullScreenRoute); + const reportsSplitNavigator = state.routes.find((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); - routes.push(workspaceNavigator); + // If policyID is defined, it should be passed to the reportNavigator params. + if (reportsSplitNavigator && policyID) { + const routes = []; + const reportNavigatorWithPolicyID = {...reportsSplitNavigator}; + reportNavigatorWithPolicyID.params = {...reportNavigatorWithPolicyID.params, policyID}; + routes.push(reportNavigatorWithPolicyID); return { adaptedState: getRoutesWithIndex(routes), }; } - if (attachmentsScreen) { - // Routes - // - matching bottom tab - // - central pane (report screen) of the attachment - // - found report attachments - const routes = []; - const reportAttachments = attachmentsScreen as Route<'Attachments', RootStackParamList['Attachments']>; - - if (reportAttachments.params?.type === CONST.ATTACHMENT_TYPE.REPORT) { - const splitNavigatorMainScreen = !isNarrowLayout - ? { - name: SCREENS.REPORT, - params: {reportID: reportAttachments.params?.reportID ?? '-1'}, - } - : undefined; - - routes.push(createSplitNavigator({name: SCREENS.HOME}, splitNavigatorMainScreen)); - routes.push(reportAttachments); + // If there is no full screen route in the root, we want to add it. + if (!fullScreenRoute) { + const matchingRootRoute = getMatchingFullScreenRouteForState(state); + // If there is a matching root route, add it to the state. + if (matchingRootRoute) { return { - adaptedState: getRoutesWithIndex(routes), + adaptedState: getRoutesWithIndex([matchingRootRoute, ...state.routes]), }; } - } - - // We need to make sure that this if only handles states where we deeplink to the bottom tab directly - - // If policyID is defined, it should be passed to the reportNavigator params. - if (reportNavigator && policyID) { - const routes = []; - const reportNavigatorWithPolicyID = {...reportNavigator}; - reportNavigatorWithPolicyID.params = {...reportNavigatorWithPolicyID.params, policyID}; - routes.push(reportNavigatorWithPolicyID); + // If not, add the default full screen route. return { - adaptedState: getRoutesWithIndex(routes), + adaptedState: getRoutesWithIndex([{name: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR}, ...state.routes]), }; } @@ -317,4 +213,3 @@ const getAdaptedStateFromPath: GetAdaptedStateFromPath = (path, options, shouldR }; export default getAdaptedStateFromPath; -export type {Metainfo}; diff --git a/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts b/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts index 0645a45e0924..7dc6093d7942 100644 --- a/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts +++ b/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts @@ -2,7 +2,7 @@ import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRo import type {BottomTabName, NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; -import {CENTRAL_PANE_TO_TAB_MAPPING} from './TAB_TO_CENTRAL_PANE_MAPPING'; +import {CENTRAL_PANE_TO_TAB_MAPPING} from './RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING'; // Get the route that matches the topmost central pane route in the navigation stack. e.g REPORT -> HOME function getMatchingBottomTabRouteForState(state: State, policyID?: string): NavigationPartialRoute { diff --git a/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts b/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts index cec00f705127..7ce8cd5daac8 100644 --- a/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts +++ b/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts @@ -2,7 +2,7 @@ import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute' import type {AuthScreensParamList, CentralPaneName, NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; -import TAB_TO_CENTRAL_PANE_MAPPING from './TAB_TO_CENTRAL_PANE_MAPPING'; +import TAB_TO_CENTRAL_PANE_MAPPING from './RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING'; /** * @param state - react-navigation state diff --git a/src/libs/Navigation/newLinkTo/getActionForBottomTabNavigator.ts b/src/libs/Navigation/newLinkTo/getActionForBottomTabNavigator.ts deleted file mode 100644 index 85580d068ad7..000000000000 --- a/src/libs/Navigation/newLinkTo/getActionForBottomTabNavigator.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type {NavigationAction, NavigationState} from '@react-navigation/native'; -import type {Writable} from 'type-fest'; -import type {RootStackParamList, StackNavigationAction} from '@libs/Navigation/types'; -import getTopmostBottomTabRoute from '@navigation/getTopmostBottomTabRoute'; -import CONST from '@src/CONST'; -import type {ActionPayloadParams} from './types'; - -// Because we need to change the type to push, we also need to set target for this action to the bottom tab navigator. -function getActionForBottomTabNavigator( - action: StackNavigationAction, - state: NavigationState, - policyID?: string, - shouldNavigate?: boolean, -): Writable | undefined { - const bottomTabNavigatorRoute = state.routes.at(0); - if (!bottomTabNavigatorRoute || bottomTabNavigatorRoute.state === undefined || !action || action.type !== CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { - return; - } - - const params = action.payload.params as ActionPayloadParams; - let payloadParams = params.params as Record; - const screen = params.screen; - - if (policyID && !payloadParams?.policyID) { - payloadParams = {...payloadParams, policyID}; - } else if (!policyID) { - delete payloadParams?.policyID; - } - - // Check if the current bottom tab is the same as the one we want to navigate to. If it is, we don't need to do anything. - const bottomTabCurrentTab = getTopmostBottomTabRoute(state); - const bottomTabParams = bottomTabCurrentTab?.params as Record; - - // Verify if the policyID is different than the one we are currently on. If it is, we need to navigate to the new policyID. - const isNewPolicy = bottomTabParams?.policyID !== payloadParams?.policyID; - if (bottomTabCurrentTab?.name === screen && !shouldNavigate && !isNewPolicy) { - return; - } - - return { - type: CONST.NAVIGATION.ACTION_TYPE.PUSH, - payload: { - name: screen, - params: payloadParams, - }, - target: bottomTabNavigatorRoute.state.key, - }; -} - -export default getActionForBottomTabNavigator; diff --git a/src/libs/Navigation/newLinkTo/getMinimalAction.ts b/src/libs/Navigation/newLinkTo/getMinimalAction.ts deleted file mode 100644 index ff01b3b8333b..000000000000 --- a/src/libs/Navigation/newLinkTo/getMinimalAction.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type {NavigationAction, NavigationState} from '@react-navigation/native'; -import type {Writable} from 'type-fest'; -import type {State} from '@navigation/types'; -import type {ActionPayload} from './types'; - -/** - * Motivation for this function is described in NAVIGATION.md - * - * @param action action generated by getActionFromState - * @param state The root state - * @returns minimalAction minimal action is the action that we should dispatch - */ -function getMinimalAction(action: NavigationAction, state: NavigationState): Writable { - let currentAction: NavigationAction = action; - let currentState: State | undefined = state; - let currentTargetKey: string | undefined; - - while (currentAction.payload && 'name' in currentAction.payload && currentState?.routes[currentState.index ?? -1].name === currentAction.payload.name) { - if (!currentState?.routes[currentState.index ?? -1].state) { - break; - } - - currentState = currentState?.routes[currentState.index ?? -1].state; - currentTargetKey = currentState?.key; - - const payload = currentAction.payload as ActionPayload; - - // Creating new smaller action - currentAction = { - type: currentAction.type, - payload: { - name: payload?.params?.screen, - params: payload?.params?.params, - path: payload?.params?.path, - }, - target: currentTargetKey, - }; - } - return currentAction; -} - -export default getMinimalAction; diff --git a/src/libs/Navigation/newLinkTo/index.ts b/src/libs/Navigation/newLinkTo/index.ts deleted file mode 100644 index f8ac74d6e61f..000000000000 --- a/src/libs/Navigation/newLinkTo/index.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {getActionFromState} from '@react-navigation/core'; -import type {NavigationContainerRef, NavigationState, PartialState} from '@react-navigation/native'; -import {findFocusedRoute} from '@react-navigation/native'; -import {shallowCompare} from '@libs/ObjectUtils'; -import {getPathWithoutPolicyID} from '@libs/PolicyUtils'; -import getStateFromPath from '@navigation/getStateFromPath'; -import linkingConfig from '@navigation/linkingConfig'; -import type {RootStackParamList, StackNavigationAction} from '@navigation/types'; -import CONST from '@src/CONST'; -import type {Route} from '@src/ROUTES'; -import getMinimalAction from './getMinimalAction'; - -function shouldDispatchAction(currentState: NavigationState, stateFromPath: PartialState>) { - const currentFocusedRoute = findFocusedRoute(currentState); - const targetFocusedRoute = findFocusedRoute(stateFromPath); - - const areNamesEqual = currentFocusedRoute?.name === targetFocusedRoute?.name; - const areParamsEqual = shallowCompare(currentFocusedRoute?.params as Record | undefined, targetFocusedRoute?.params as Record | undefined); - - if (areNamesEqual && areParamsEqual) { - return false; - } - - return true; -} - -export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: typeof CONST.NAVIGATION.ACTION_TYPE.REPLACE) { - if (!navigation) { - throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); - } - - const pathWithoutPolicyID = getPathWithoutPolicyID(`/${path}`) as Route; - - // This is the state generated with the default getStateFromPath function. - // It won't include the whole state that will be generated for this path but the focused route will be correct. - // It is necessary because getActionFromState will generate RESET action for whole state generated with our custom getStateFromPath function. - const stateFromPath = getStateFromPath(pathWithoutPolicyID) as PartialState>; - const currentState = navigation.getRootState() as NavigationState; - const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); - - // We don't want to dispatch action to push/replace with exactly the same route that is already focused. - if (!shouldDispatchAction(currentState, stateFromPath)) { - return; - } - - // If there is no action, just reset the whole state. - if (!action) { - navigation.resetRoot(stateFromPath); - return; - } - - if (type === CONST.NAVIGATION.ACTION_TYPE.REPLACE) { - action.type = CONST.NAVIGATION.ACTION_TYPE.REPLACE; - } else if (action.type === CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { - // We want to PUSH by default to add entries to the browser history. - action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; - } - - const minimalAction = getMinimalAction(action, navigation.getRootState()); - navigation.dispatch(minimalAction); -} diff --git a/src/libs/Navigation/newLinkTo/types.ts b/src/libs/Navigation/newLinkTo/types.ts deleted file mode 100644 index 254a4cdef2a5..000000000000 --- a/src/libs/Navigation/newLinkTo/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -type ActionPayloadParams = { - screen?: string; - params?: unknown; - path?: string; -}; - -type ActionPayload = { - params?: ActionPayloadParams; -}; - -export type {ActionPayload, ActionPayloadParams}; diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 926d288d9a61..6e2e2526e8de 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -21,7 +21,7 @@ import type {HybridAppRoute, Route as Routes} from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type EXIT_SURVEY_REASON_FORM_INPUT_IDS from '@src/types/form/ExitSurveyReasonForm'; import type {ConnectionName, SageIntacctMappingName} from '@src/types/onyx/Policy'; -import type LHN_TO_SPLIT_NAVIGATOR_NAME from './linkingConfig/LHN_TO_SPLIT_NAVIGATOR_MAPPING'; +import type LHN_TO_SPLIT_NAVIGATOR_NAME from './linkingConfig/RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING'; type NavigationRef = NavigationContainerRefWithCurrent;