Skip to content

[Due for payment 2025-05-22] [$250] Category/Tags URL Pop-Up Persists and Flashes After Click in Safari #61119

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

Open
2 of 16 tasks
m-natarajan opened this issue Apr 29, 2025 · 20 comments
Assignees
Labels
Awaiting Payment Auto-added when associated PR is deployed to production Bug Something is broken. Auto assigns a BugZero manager. External Added to denote the issue can be worked on by a contributor Weekly KSv2

Comments

@m-natarajan
Copy link

m-natarajan commented Apr 29, 2025

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: 9.1.37-2
Reproducible in staging?: Y
Reproducible in production?: Y
If this was caught during regression testing, add the test name, ID and link from TestRail:
Email or phone of affected tester (no customers):
Logs: https://stackoverflow.com/c/expensify/questions/4856
Expensify/Expensify Issue URL:
Issue reported by: @davidcardoza
Slack conversation (hyperlinked to channel name): #Quality

Action Performed:

  1. Open the setup tasks in Safari.
  2. Tap on a category or tags URL.
  3. Observe that the pop-up remains visible and keeps flashing, even though the link has already been followed.

Expected Result:

The URL pop-up should disappear after the link is tapped, indicating that the action has been completed.

Actual Result:

The pop-up lingers and flashes, creating a distracting and possibly confusing user experience.

Workaround:

Unknown

Platforms:

Select the officially supported platforms where the issue was reproduced:

  • Android: App
  • Android: mWeb Chrome
  • iOS: App
  • iOS: mWeb Safari
  • iOS: mWeb Chrome
  • Windows: Chrome
  • MacOS: Safari
  • MacOS: Desktop
Platforms Tested: On which of our officially supported platforms was this issue tested:
  • Android: App
  • Android: mWeb Chrome
  • iOS: App
  • iOS: mWeb Safari
  • iOS: mWeb Chrome
  • Windows: Chrome
  • MacOS: Safari
  • MacOS: Desktop

Screenshots/Videos

Add any screenshot/video evidence
Recording.3187.mp4

View all open jobs on GitHub

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~021917975135639488153
  • Upwork Job ID: 1917975135639488153
  • Last Price Increase: 2025-05-01
  • Automatic offers:
    • suneox | Reviewer | 107226251
    • huult | Contributor | 107226253
Issue OwnerCurrent Issue Owner: @flaviadefaria
@m-natarajan m-natarajan added Bug Something is broken. Auto assigns a BugZero manager. Daily KSv2 labels Apr 29, 2025
Copy link

melvin-bot bot commented Apr 29, 2025

Triggered auto assignment to @flaviadefaria (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.

@flaviadefaria flaviadefaria added the External Added to denote the issue can be worked on by a contributor label May 1, 2025
@melvin-bot melvin-bot bot changed the title Category/Tags URL Pop-Up Persists and Flashes After Click in Safari [$250] Category/Tags URL Pop-Up Persists and Flashes After Click in Safari May 1, 2025
Copy link

melvin-bot bot commented May 1, 2025

Job added to Upwork: https://www.upwork.com/jobs/~021917975135639488153

@melvin-bot melvin-bot bot added the Help Wanted Apply this label when an issue is open to proposals by contributors label May 1, 2025
Copy link

melvin-bot bot commented May 1, 2025

Triggered auto assignment to Contributor-plus team member for initial proposal review - @suneox (External)

@dmkt9
Copy link

dmkt9 commented May 4, 2025

Proposal

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

The pop-up lingers and flashes, creating a distracting and possibly confusing user experience.

What is the root cause of that problem?

  • The openLink function triggers immediate navigation using Navigation.navigate:
    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);
    // 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.
    // Normally, the link would be sent to Link.openOldDotLink() and opened in a new tab, and that's jarring to the user. Since the intention is to link to a specific NewDot chat,
    // the reportID is extracted from the URL and then opened as an internal link, taking the user straight to the chat in the same tab.
    if (hasExpensifyOrigin && href.indexOf('newdotreport?reportID=') > -1) {
    const reportID = href.split('newdotreport?reportID=').pop();
    const reportRoute = ROUTES.REPORT_WITH_ID.getRoute(reportID);
    Navigation.navigate(reportRoute);
    return;
    }
    // If we are handling a New Expensify link then we will assume this should be opened by the app internally. This ensures that the links are opened internally via react-navigation
    // instead of in a new tab or with a page refresh (which is the default behavior of an anchor tag)
    if (internalNewExpensifyPath && hasSameOrigin) {
    if (isAnonymousUser() && !canAnonymousUserAccessRoute(internalNewExpensifyPath)) {
    signOutAndRedirectToSignIn();
    return;
    }
    Navigation.navigate(internalNewExpensifyPath as Route);
    return;
    }
    // If we are handling an old dot Expensify link we need to open it with openOldDotLink() so we can navigate to it with the user already logged in.
    // As attachments also use expensify.com we don't want it working the same as links.
    const isPublicOldDotURL = (Object.values(CONST.OLD_DOT_PUBLIC_URLS) as string[]).includes(href);
    if (internalExpensifyPath && !isAttachment && !isPublicOldDotURL) {
    openOldDotLink(internalExpensifyPath);
    return;
    }
    openExternalLink(href);
    }
  • This prevents the Tooltip component from re-rendering before navigation occurs, causing it to remain visible during the transition.

What changes do we need to make to resolve the problem?

Modify the BaseAnchorForCommentsOnly component to:

  1. Introduce state tracking
const [isPressed, setIsPressed] = React.useState(false);
  1. Defer navigation execution
    Update the link's onPress handler to trigger state change instead of immediate action:
linkProps.onPress = () => setIsPressed(true);
  1. Conditionally render tooltip
<Tooltip text={linkHref} shouldRender={!isPressed}>
  1. Execute navigation post-render
    Use a useEffect hook to handle navigation after state update:
React.useEffect(() => {
    if (isPressed) {
        setIsPressed(false); // Reset state
        onPress?.(); // Trigger navigation
    }
}, [isPressed]);

What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?

N/A

What alternative solutions did you explore? (Optional)

N/A

Reminder: Please use plain English, be brief and avoid jargon. Feel free to use images, charts or pseudo-code if necessary. Do not post large multi-line diffs or write walls of text. Do not create PRs unless you have been hired for this job.

@melvin-bot melvin-bot bot added the Overdue label May 4, 2025
@suneox
Copy link
Contributor

suneox commented May 5, 2025

@dmkt9 Thank you for your proposal. Could you please provide more details about the root cause of why this issue only happens on Safari?

@melvin-bot melvin-bot bot removed the Overdue label May 5, 2025
@dmkt9
Copy link

dmkt9 commented May 5, 2025

@suneox I don't know whether to call this issue a bug or a feature of MacOS (I can reproduce it with Edge/Chrome). Because the root of the problem is that the Tooltip is still in the DOM with the display property preserved after navigation, this happens on Windows too.
But maybe with Chrome/Edge on Windows when the parent element of the Tooltip is no longer in the DOM, the Tooltip will be hidden, but on MacOS it's different, causing this issue.

@suneox
Copy link
Contributor

suneox commented May 5, 2025

@suneox I don't know whether to call this issue a bug or a feature of MacOS (I can reproduce it with Edge/Chrome). Because the root of the problem is that the Tooltip is still in the DOM with the display property preserved after navigation, this happens on Windows too.

@dmkt9 This issue happens on the Tooltip. We need to find the root cause related to the action that hides the tooltip. In your current solution, you only handle it in BaseAnchorForCommentsOnly, which doesn't make sense for addressing the root cause.

@dmkt9
Copy link

dmkt9 commented May 5, 2025

Strange, today I tried to reproduce this issue on Chrome/macOS but couldn’t, even though I previously debugged there. No worries, the issue still persists on Safari.

@suneox I understand your concern that I’m merely "masking" the problem rather than resolving it. Let me explain step by step:

  1. The root cause lies with Safari itself. During navigation, all unmount hooks and "exit" events like onMouseLeave are not processed, and state changes do not trigger re-renders (exactly what I mentioned in the earlier proposal).
    This is easy to verify:
  • Add logging in GenericTooltip:
console.log({isVisible, children: children({isVisible, showTooltip, hideTooltip, updateTargetBounds})})  
  • Add an unmount hook in ActiveHoverable:
useEffect(() => {  
  return () => {  
    handleMouseEvents('leave')();  
  };  
}, []);  
  • Set a breakpoint or add a console.log at onMouseLeave in ActiveHoverable.
  • You’ll observe that isVisible remains true, and neither onMouseLeave nor the unmount hook triggers for the observed Tooltip.
  • None of these issues occur on Chrome.
  1. Thus, the solution is to ensure the component unmounts or re-renders with isVisible=false before navigation completes.
  • To set isVisible=false, we could call hideTooltip from BaseTooltip. However, since BaseTooltip is a wrapper, exposing hideTooltip to the parent would complicate the code.
  • During review, I noticed Tooltip has a shouldRender prop—perfect for this scenario (kudos to the experienced designer of Tooltip).
  • The simplest integration point to handle both onPress and shouldRender is BaseAnchorForCommentsOnly, which is why you only see changes there.
  1. If this explanation is unsatisfactory, I must admit I’ve exhausted my capacity to address this issue further.

@huult
Copy link
Contributor

huult commented May 6, 2025

🚨 Edited by proposal-police: This proposal was edited at 2025-05-06 18:01:08 UTC.

Proposal

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

Category/Tags URL Pop-Up Persists and Flashes After Click in Safari

What is the root cause of that problem?

When a user clicks a linkRef, navigation is triggered (href={linkHref}), which causes the tooltip to lose focus. At that moment, isVisible is set to false, but the update is not applied in time.

Once the new page loads, the tooltip becomes focused again because isVisible not updated yet, causing it to persist unexpectedly.

Here is the video showing my debugging process — it will help you understand more easily:

Screen.Recording.2025-05-07.at.01.05.13.mp4

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

To prevent this issue, we should return early from the tooltip rendering logic if the current screen is not focused. This ensures that the tooltip does not persist during navigation.

add

    if (!isFocused) {
        return children;
    }

Note: This issue occurs only in Safari, but we can apply the fix conditionally for Safari only

Screen.Recording.2025-05-07.at.00.59.57.mov

What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?

None

What alternative solutions did you explore? (Optional)

Reminder: Please use plain English, be brief and avoid jargon. Feel free to use images, charts or pseudo-code if necessary. Do not post large multi-line diffs or write walls of text. Do not create PRs unless you have been hired for this job.

@suneox
Copy link
Contributor

suneox commented May 7, 2025

Thank you for the update. I’ll review the proposal in a few hours

@suneox
Copy link
Contributor

suneox commented May 8, 2025

Since Safari events don't work as expected, and all proposals are just workarounds, the proposal from @huult makes more sense than @dmkt9, as it handles showing the tooltip when the screen is focused LGTM, so we can go with this proposal

🎀 👀 🎀 C+ reviewed

Copy link

melvin-bot bot commented May 8, 2025

Triggered auto assignment to @JS00001, see https://stackoverflow.com/c/expensify/questions/7972 for more details.

@JS00001
Copy link
Contributor

JS00001 commented May 8, 2025

I think that @huult 's proposal makes more sense, rather than introducing more state/useEffects. Assigning to you!

@melvin-bot melvin-bot bot removed the Help Wanted Apply this label when an issue is open to proposals by contributors label May 8, 2025
Copy link

melvin-bot bot commented May 8, 2025

📣 @suneox 🎉 An offer has been automatically sent to your Upwork account for the Reviewer role 🎉 Thanks for contributing to the Expensify app!

Offer link
Upwork job

Copy link

melvin-bot bot commented May 8, 2025

📣 @huult 🎉 An offer has been automatically sent to your Upwork account for the Contributor role 🎉 Thanks for contributing to the Expensify app!

Offer link
Upwork job
Please accept the offer and leave a comment on the Github issue letting us know when we can expect a PR to be ready for review 🧑‍💻
Keep in mind: Code of Conduct | Contributing 📖

@melvin-bot melvin-bot bot added Reviewing Has a PR in review Weekly KSv2 and removed Daily KSv2 labels May 8, 2025
@huult huult mentioned this issue May 13, 2025
50 tasks
@melvin-bot melvin-bot bot added Weekly KSv2 and removed Weekly KSv2 labels May 13, 2025
Copy link

melvin-bot bot commented May 13, 2025

⚠️ Looks like this issue was linked to a Deploy Blocker here

If you are the assigned CME please investigate whether the linked PR caused a regression and leave a comment with the results.

If a regression has occurred and you are the assigned CM follow the instructions here.

If this regression could have been avoided please consider also proposing a recommendation to the PR checklist so that we can avoid it in the future.

Copy link

melvin-bot bot commented May 13, 2025

⚠️ Looks like this issue was linked to a Deploy Blocker here

If you are the assigned CME please investigate whether the linked PR caused a regression and leave a comment with the results.

If a regression has occurred and you are the assigned CM follow the instructions here.

If this regression could have been avoided please consider also proposing a recommendation to the PR checklist so that we can avoid it in the future.

@melvin-bot melvin-bot bot added Weekly KSv2 Awaiting Payment Auto-added when associated PR is deployed to production and removed Weekly KSv2 labels May 15, 2025
@melvin-bot melvin-bot bot changed the title [$250] Category/Tags URL Pop-Up Persists and Flashes After Click in Safari [Due for payment 2025-05-22] [$250] Category/Tags URL Pop-Up Persists and Flashes After Click in Safari May 15, 2025
@melvin-bot melvin-bot bot removed the Reviewing Has a PR in review label May 15, 2025
Copy link

melvin-bot bot commented May 15, 2025

Reviewing label has been removed, please complete the "BugZero Checklist".

Copy link

melvin-bot bot commented May 15, 2025

The solution for this issue has been 🚀 deployed to production 🚀 in version 9.1.45-21 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:

If no regressions arise, payment will be issued on 2025-05-22. 🎊

For reference, here are some details about the assignees on this issue:

Copy link

melvin-bot bot commented May 15, 2025

@suneox @flaviadefaria @suneox The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the BugZero Checklist from here into a new comment on this GH and complete it. If you have the K2 extension, you can simply click: [this button]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting Payment Auto-added when associated PR is deployed to production Bug Something is broken. Auto assigns a BugZero manager. External Added to denote the issue can be worked on by a contributor Weekly KSv2
Projects
Status: LOW
Development

No branches or pull requests

6 participants