App icon indicating copy to clipboard operation
App copied to clipboard

Onboarding - RHP Opens Multiple Concierge Pages Instead of Existing Tab

Open jponikarchuk opened this issue 1 month ago β€’ 9 comments

If you haven’t already, check out our contributing guidelines for onboarding and email [email protected] to request to join our Slack channel!


Version Number: v9.2.87-0 Reproducible in staging?: Yes Reproducible in production?: No If this was caught during regression testing, add the test name, ID and link from BrowserStack: https://github.com/Expensify/App/pull/78352 Email or phone of affected tester (no customers): [email protected] Issue reported by: Applause Internal Team Bug source: Exploratory - Critical User Impact Device used: Windows 10 /Chrome App Component: Other

Action Performed:

  1. Navigate to http://staging.new.expensify.com/r/6177391126570771
  2. Click Concierge.
  3. Sign in.
  4. Click Concierge in header again.
  5. Click RHP Sign in again.
  6. Click RHP back arrow 2 times.

Expected Result:

When RHP is clicked, it should open the first existing Concierge tab/page.

Actual Result:

When RHP is clicked, multiple Concierge pages open repeatedly instead of returning to the first open Concierge page.

Workaround:

Unknown

Platforms:

  • [ ] Android: App
  • [ ] Android: mWeb Chrome
  • [ ] iOS: App
  • [ ] iOS: mWeb Safari
  • [ ] iOS: mWeb Chrome
  • [x] Windows: Chrome
  • [ ] MacOS: Chrome / Safari

Screenshots/Videos

https://github.com/user-attachments/assets/4a2fc1df-2375-4e09-bdb1-4c05e224a253

View all open jobs on GitHub

jponikarchuk avatar Dec 25 '25 05:12 jponikarchuk

You have been assigned to this deploy blocker because you recently merged this PR: https://github.com/Expensify/App/pull/78352

melvin-bot[bot] avatar Dec 25 '25 05:12 melvin-bot[bot]

πŸ’¬ A slack conversation has been started in #expensify-open-source

melvin-bot[bot] avatar Dec 25 '25 05:12 melvin-bot[bot]

:wave: Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:

  1. Identify the pull request that introduced this issue and revert it.
  2. Find someone who can quickly fix the issue.
  3. Fix the issue yourself.

github-actions[bot] avatar Dec 25 '25 05:12 github-actions[bot]

Everybody was OOO, so I assigned 10 random eligible people.

melvin-bot[bot] avatar Dec 25 '25 05:12 melvin-bot[bot]

Proposal

Please re-state the problem that we are trying to solve in this issue.

In the Help/Concierge right-hand panel, alternating between different entry points (e.g., Concierge profile area β†’ Sign In β†’ Concierge profile area β†’ Sign In) causes the right-hand panel history to grow unnecessarily. Users then need to press Back many times to return to the prior panel(s).

What is the root cause of that problem?

Each click navigates to a new right-hand panel destination by adding a new entry to the panel stack, even if that destination is already present in the current panel history. Alternating between two destinations therefore creates repeated duplicates (A β†’ B β†’ A β†’ B).

What changes do you think we should make in order to solve the problem?

  • Add a navigation helper in src/libs/Navigation/Navigation.ts (e.g., navigateOrPopToExisting(route)) that:
    • checks whether the destination route already exists in the currently active nested navigator state (the right-hand panel stack),
    • if it exists, pops back to that existing instance,
    • otherwise navigates normally (so Back still works within the right-hand panel flow).

For example:

/**
 * Navigate to a route, but if that route already exists in the currently active nested navigator state,
 * pop back to the existing instance instead of pushing a duplicate.
 *
 * This is primarily useful for RHP flows (e.g. Search ↔ Sign In ↔ Profile) to keep back navigation intact
 * while avoiding stacked duplicates when users tap entry points repeatedly.
 */
function navigateOrPopToExisting(route: Route, options?: GoBackOptions) {
    if (!canNavigate('navigateOrPopToExisting', {route}) || !navigationRef.current) {
        return;
    }

    const compareParams = options?.compareParams ?? defaultGoBackOptions.compareParams;
    const rootState = navigationRef.current.getRootState();
    const stateFromPath = getStateFromPath(route);
    const action = getActionFromState(stateFromPath, linkingConfig.config);

    if (!action) {
        navigate(route);
        return;
    }

    const {action: minimalAction, targetState} = getMinimalAction(action, rootState);

    // If we can't identify a nested target state, fall back to normal navigation.
    // In particular, we never want to pop within the root navigator to avoid removing full-screen routes.
    if (minimalAction.type !== CONST.NAVIGATION.ACTION_TYPE.NAVIGATE || !targetState || isRootNavigatorState(targetState)) {
        navigate(route);
        return;
    }

    const indexOfTargetRoute = targetState.routes.findLastIndex((r) => doesRouteMatchToMinimalActionPayload(r, minimalAction, compareParams));
    if (indexOfTargetRoute === -1) {
        navigate(route);
        return;
    }

    const distanceToPop = targetState.routes.length - indexOfTargetRoute - 1;
    if (distanceToPop <= 0) {
        return;
    }

    if (!compareParams) {
        navigationRef.current.dispatch({...minimalAction, type: CONST.NAVIGATION.ACTION_TYPE.POP_TO});
        return;
    }

    navigationRef.current.dispatch({...StackActions.pop(distanceToPop), target: targetState.key});
}
  • Update the following entry points to use that helper:
    • Anonymous Sign In button path: signOutAndRedirectToSignIn() in src/libs/actions/Session/index.ts (route ROUTES.SIGN_IN_MODAL)
      • https://github.com/Expensify/App/blob/54c7eb47b7e774379769129367bc930dbdfb976f/src/libs/actions/Session/index.ts#L299
    • Concierge profile/details path: navigateToDetailsPage() in src/libs/ReportUtils.ts (routes ROUTES.PROFILE... / ROUTES.REPORT_WITH_ID_DETAILS...)
      • https://github.com/Expensify/App/blob/54c7eb47b7e774379769129367bc930dbdfb976f/src/libs/ReportUtils.ts#L6344
      • https://github.com/Expensify/App/blob/54c7eb47b7e774379769129367bc930dbdfb976f/src/libs/ReportUtils.ts#L6349

What alternative solutions did you explore? (Optional)

N/A

ubaidsk avatar Dec 25 '25 19:12 ubaidsk

πŸ“£ @ubaidsk! πŸ“£ Hey, it seems we don’t have your contributor details yet! You'll only have to do this once, and this is how we'll hire you on Upwork. Please follow these steps:

  1. Make sure you've read and understood the contributing guidelines.
  2. Get the email address used to login to your Expensify account. If you don't already have an Expensify account, create one here. If you have multiple accounts (e.g. one for testing), please use your main account email.
  3. Get the link to your Upwork profile. It's necessary because we only pay via Upwork. You can access it by logging in, and then clicking on your name. It'll look like this. If you don't already have an account, sign up for one here.
  4. Copy the format below and paste it in a comment on this issue. Replace the placeholder text with your actual details. Screen Shot 2022-11-16 at 4 42 54 PM Format:
Contributor details
Your Expensify account email: <REPLACE EMAIL HERE>
Upwork Profile Link: <REPLACE LINK HERE>

melvin-bot[bot] avatar Dec 25 '25 19:12 melvin-bot[bot]

Contributor details Your Expensify account email: [email protected] Upwork Profile Link: https://www.upwork.com/freelancers/~01eb90b457e55ca9a4

ubaidsk avatar Dec 25 '25 20:12 ubaidsk

βœ… Contributor details stored successfully. Thank you for contributing to Expensify!

melvin-bot[bot] avatar Dec 25 '25 20:12 melvin-bot[bot]

ah, I think this is not a deploy blocker because it should not appear on production yet, right @marcochavezf ?

marcaaron avatar Dec 25 '25 21:12 marcaaron

Yup, exactly not a blocker because it's hidden in production

marcochavezf avatar Dec 25 '25 22:12 marcochavezf