Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
22 changes: 22 additions & 0 deletions src/libs/Navigation/helpers/willRouteNavigateToRHP.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import NAVIGATORS from '@src/NAVIGATORS';
import type {Route} from '@src/ROUTES';
import getStateFromPath from './getStateFromPath';

/**
* Check if a route will navigate to a screen in the RightModalNavigator
*/
function willRouteNavigateToRHP(route: Route): boolean {
try {
const state = getStateFromPath(route);
if (!state) {
return false;
}

const lastRoute = state?.routes?.at(-1);
return lastRoute?.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR;
} catch {
return false;
}
}

export default willRouteNavigateToRHP;
36 changes: 36 additions & 0 deletions src/libs/actions/Link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import type {GenerateSpotnanaTokenParams} from '@libs/API/parameters';
import {SIDE_EFFECT_REQUEST_COMMANDS} from '@libs/API/types';
import asyncOpenURL from '@libs/asyncOpenURL';
import * as Environment from '@libs/Environment/Environment';
import getIsNarrowLayout from '@libs/getIsNarrowLayout';
import isPublicScreenRoute from '@libs/isPublicScreenRoute';
import {isOnboardingFlowName} from '@libs/Navigation/helpers/isNavigatorName';
import normalizePath from '@libs/Navigation/helpers/normalizePath';
import shouldOpenOnAdminRoom from '@libs/Navigation/helpers/shouldOpenOnAdminRoom';
import willRouteNavigateToRHP from '@libs/Navigation/helpers/willRouteNavigateToRHP';
import Navigation from '@libs/Navigation/Navigation';
import navigationRef from '@libs/Navigation/navigationRef';
import type {NetworkStatus} from '@libs/NetworkConnection';
Expand Down Expand Up @@ -186,12 +188,40 @@ function getInternalExpensifyPath(href: string) {
return attrPath;
}

/**
* Normalizes a route by replacing route path variables with a generic placeholder(:id). For example /report/12345 becomes /report/:id
*/
function getNormalizedRoute(route: string) {
Comment thread
Burhan-Rashid marked this conversation as resolved.
const routeWithoutParams = route.split('?').at(0) ?? '';
const segments = routeWithoutParams.split('/').filter((segment) => segment !== '');
const normalizedSegments = segments.map((segment) => {
// Check if segment is a number, UUID, or likely a dynamic ID and return :id for that
if (/^[\d]+$/.test(segment) || /^[a-f0-9-]{20,}$/i.test(segment) || /^[A-Z0-9]{8,}$/i.test(segment)) {
return ':id';
}
return segment;
});

return normalizedSegments.join('/');
}

function openLink(href: string, environmentURL: string, isAttachment = false) {
const hasSameOrigin = Url.hasSameExpensifyOrigin(href, environmentURL);
const hasExpensifyOrigin = Url.hasSameExpensifyOrigin(href, CONFIG.EXPENSIFY.EXPENSIFY_URL) || Url.hasSameExpensifyOrigin(href, CONFIG.EXPENSIFY.STAGING_API_ROOT);
const internalNewExpensifyPath = getInternalNewExpensifyPath(href);
const internalExpensifyPath = getInternalExpensifyPath(href);

const isNarrowLayout = getIsNarrowLayout();
const currentState = navigationRef.getRootState();
const isRHPOpen = currentState?.routes?.at(-1)?.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR;
let shouldCloseRHP = false;
if (!isNarrowLayout && isRHPOpen) {
const willOpenInRHP = willRouteNavigateToRHP(internalNewExpensifyPath as Route);
const currentRoute = Navigation.getActiveRoute();
const willOpenSameRoute = getNormalizedRoute(currentRoute) === getNormalizedRoute(internalNewExpensifyPath);
shouldCloseRHP = !willOpenInRHP || !willOpenSameRoute;
Comment thread
Burhan-Rashid marked this conversation as resolved.
}

// There can be messages from Concierge with links to specific NewDot reports. Those URLs look like this:
// https://www.expensify.com.dev/newdotreport?reportID=3429600449838908 and they have a target="_blank" attribute. This is so that when a user is on OldDot,
// clicking on the link will open the chat in NewDot. However, when a user is in NewDot and clicks on the concierge link, the link needs to be handled differently.
Expand All @@ -200,6 +230,9 @@ function openLink(href: string, environmentURL: string, isAttachment = false) {
if (hasExpensifyOrigin && href.indexOf('newdotreport?reportID=') > -1) {
const reportID = href.split('newdotreport?reportID=').pop();
const reportRoute = ROUTES.REPORT_WITH_ID.getRoute(reportID);
if (shouldCloseRHP) {
Navigation.closeRHPFlow();
}
Navigation.navigate(reportRoute);
return;
}
Expand All @@ -211,6 +244,9 @@ function openLink(href: string, environmentURL: string, isAttachment = false) {
signOutAndRedirectToSignIn();
return;
}
if (shouldCloseRHP) {
Navigation.closeRHPFlow();
}
Navigation.navigate(internalNewExpensifyPath as Route);
return;
}
Expand Down
Loading