Skip to content

[$250] Reports-RHP loads infinitely after deleting expense in report that has deleted expense with reply #60624

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
6 of 8 tasks
jponikarchuk opened this issue Apr 22, 2025 · 64 comments
Assignees
Labels
Bug Something is broken. Auto assigns a BugZero manager. Daily KSv2 External Added to denote the issue can be worked on by a contributor

Comments

@jponikarchuk
Copy link

jponikarchuk commented Apr 22, 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.31-0
Reproducible in staging?: Yes
Reproducible in production?: Yes
If this was caught on HybridApp, is this reproducible on New Expensify Standalone?: No, reproducible on hybrid only
If this was caught during regression testing, add the test name, ID and link from TestRail: Exp
Email or phone of affected tester (no customers): [email protected]
Issue reported by: Applause Internal Team
Device used: Mac 15.3 / Chrome
App Component: Search

Action Performed:

  1. Go to staging.new.expensify.com
  2. Create a workspace.
  3. Go to workspace chat.
  4. Submit two expenses.
  5. Go to transaction thread of the second expense.
  6. Send a message.
  7. Delete the expense that has message in Step 6.
  8. Go to Reports.
  9. Go to Expense Reports.
  10. Click on the remaining expense from Step 4.
  11. Right click on the expense preview.
  12. Click Delete expense.
  13. Delete the expense.

Expected Result:

RHP will dismiss after the expense is deleted.

Actual Result:

RHP loads infinitely after deleting the expense.

Workaround:

Unknown

Platforms:

  • Android: Standalone
  • Android: HybridApp
  • Android: mWeb Chrome
  • iOS: Standalone
  • iOS: HybridApp
  • iOS: mWeb Safari
  • MacOS: Chrome / Safari
  • MacOS: Desktop

Screenshots/Videos

bandicam.2025-04-22.11-44-46-776.mp4

View all open jobs on GitHub

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~021914766250605962251
  • Upwork Job ID: 1914766250605962251
  • Last Price Increase: 2025-04-29
  • Automatic offers:
    • ishakakkad | Contributor | 107374739
Issue OwnerCurrent Issue Owner: @
@jponikarchuk jponikarchuk added Bug Something is broken. Auto assigns a BugZero manager. Daily KSv2 labels Apr 22, 2025
Copy link

melvin-bot bot commented Apr 22, 2025

Triggered auto assignment to @Christinadobrzyn (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.

@Eskalifer1
Copy link
Contributor

@jponikarchuk I think you sent a video that is related to another bug

@jponikarchuk
Copy link
Author

@Eskalifer1 Just edited, sorry

@nabi-ebrahimi
Copy link
Contributor

nabi-ebrahimi commented Apr 22, 2025

Proposal

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

When a user deletes all expenses from a report—especially one where a previous expense had a message associated with it—the Right Hand Panel (RHP) does not dismiss as expected. Instead, it enters an infinite loading state.

What is the root cause of that problem?

After deleting the last remaining expense from a report, the reportOnyx object becomes empty. However, there is no logic in place to handle this edge case in ReportScreen.tsx, so the RHP continues trying to render a report that no longer exists, resulting in infinite loading.

This is especially problematic when:

  • An expense had messages tied to it (e.g., from a transaction thread).
  • The user navigates through multiple steps, including deleting expenses directly from the RHP.

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

We should monitor changes to reportOnyx, and when:

  • reportOnyx becomes an empty object, and
  • the Onyx data status is loaded,
const [reportOnyx, reportOnyxResult] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportIDFromRoute}`, {allowStaleData: true});
const handleBackButtonPress = useCallback(() => {
    if (isInNarrowPaneModal && backTo !== SCREENS.SEARCH.REPORT_RHP) {
        Navigation.dismissModal();
        return;
    }
    if (backTo) {
        Navigation.goBack(backTo as Route, {shouldPopToTop: true});
        return;
    }
    Navigation.goBack(undefined, {shouldPopToTop: true});
}, [isInNarrowPaneModal, backTo]);

Inside useEffect

useEffect(() => {
     if ((reportOnyx && Object.keys(reportOnyx).length > 0) ?? reportOnyxResult.status === 'loading') {
            return;
        }

    handleBackButtonPress();
}, [reportOnyx, reportOnyxResult]);

we should trigger dismissal of the RHP. This will ensure that the user isn’t left staring at a loading spinner for a report that no longer exists.

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)

@Christinadobrzyn
Copy link
Contributor

I can reproduce based on the steps in the OP - I'm not sure if this needs to be internal - we'll start external

@Christinadobrzyn Christinadobrzyn added the External Added to denote the issue can be worked on by a contributor label Apr 22, 2025
@melvin-bot melvin-bot bot changed the title Reports-RHP loads infinitely after deleting expense in report that has deleted expense with reply [$250] Reports-RHP loads infinitely after deleting expense in report that has deleted expense with reply Apr 22, 2025
Copy link

melvin-bot bot commented Apr 22, 2025

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

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

melvin-bot bot commented Apr 22, 2025

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

@thelullabyy
Copy link
Contributor

thelullabyy commented Apr 23, 2025

Proposal

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

  • The Report History Panel (RHP) enters an infinite loading state after deleting an expense.

What is the root cause of that problem?

  • When a user deletes the latest expense in a report, the backend sets the associated expense report to null. We already have logic in place to navigate users away from inaccessible reports here. However, this logic does not apply when the report is accessed via the search page.
  • As a result, if a user opens a report from the search page and that report becomes inaccessible (e.g., after deleting its only expense), the screen shows an infinite loading indicator instead of dismissing the modal.

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

  • We should extend the existing navigation logic to also handle the scenario where the report is accessed from the search page. Specifically, if a report is opened in a modal and becomes inaccessible, we should dismiss the modal to avoid the infinite loading state.
if (!isFocused && !isReportDetailOpenInRHP) {
    return;
}
if (isInNarrowPaneModal) {
    if (isExpenseReport(prevReport)) { // Can be updated so that it can handle other report types)
        Navigation.dismissModal();
        return;
    } else {
        return;
    }
}

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)

  • We can also set the iouReport to null optimistically in here + the main solution.

@ishakakkad
Copy link
Contributor

ishakakkad commented Apr 23, 2025

🚨 Edited by proposal-police: This proposal was edited at 2025-04-23 10:47:57 UTC.

Proposal

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

Reports-RHP loads infinitely after deleting expense in report that has deleted expense with reply

What is the root cause of that problem?

When the report will delete it sets to empty and we show the loading state in case of report is not present here. We already have logic to navigate away from the report page when we delete the report but that will not execute for the narrowPanelModal. Because we early return from here

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

To fix this issue we should close the modal if the report is deleted. We need to do following changes.

  1. Add below block after this line here
if (isInNarrowPaneModal) {
    if (isRemovalExpectedForReportType) {
        Navigation.dismissModal();
    }
    return; 
}

We already have logic to check if isRemovalExpectedForReportType so we can leverage that logic to check if we should dismiss model or not. Also we don't need to execute all this logic in case of isInNarrowPaneModal to moving above code out side this if block will simply logic and readability of code.

  1. Now isInNarrowPaneModal check is redundant because of above changes so we can remove it from here.
if (!isFocused && !isReportDetailOpenInRHP) {
  return;
}

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

NA UI changes

What alternative solutions did you explore? (Optional)

If we don't want to change the existing placement of logic then we can add below code after this line here so all unnecessary code will not execute.

if (isInNarrowPaneModal) {
    if (isRemovalExpectedForReportType) {
        Navigation.dismissModal();
    }
    return; 
}

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.

@Christinadobrzyn
Copy link
Contributor

@alitoshmatov, can you please review these proposals when you have a moment? TY!

@Nick4dawin
Copy link

Proposal

Please re-state the problem that we are trying to solve in this issue.
When a user deletes all expenses from a report that was previously accessed via search (RHP), the Right Hand Panel (RHP) enters an infinite loading state instead of dismissing properly.

What is the root cause of that problem?
When a report is emptied by deleting all of its expenses, the backend sets the report to an empty object, but the RHP modal isn't dismissed when this happens in a narrowPaneModal context. The current code has a condition that prevents navigation away from the report if we're in a narrow pane modal:

if ((!isFocused && !isReportDetailOpenInRHP) || isInNarrowPaneModal) {
    return;
}

This early return prevents the modal dismissal logic from executing when viewing the report in a narrow pane modal.

What changes do you think we should make in order to solve the problem?
We should modify the condition to handle the special case where a report becomes empty due to deleting all expenses while being viewed in a narrow pane modal. Specifically:

  1. Extract the isInNarrowPaneModal check into a separate condition block
  2. When in a narrow pane modal, check if isRemovalExpectedForReportType is true
  3. If it is, dismiss the modal and return
  4. Otherwise, maintain the early return behavior

By separating these conditions, we maintain the existing navigation behavior while adding special handling for the empty report case.

if (isInNarrowPaneModal) {
    if (isRemovalExpectedForReportType) {
        Navigation.dismissModal();
    }
    return;
}
if (!isFocused && !isReportDetailOpenInRHP) {
    return;
}

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)
I considered other approaches:

  1. Monitoring reportOnyx to detect when it becomes empty and dismissing the modal in a separate useEffect hook - this would add more complexity than needed.
  2. Changing the logic in other parts of the app that handle transaction deletion - this would be more invasive and could affect other workflows.
  3. Adding a check in the render method to detect empty reports - this would still require modifying navigation logic.

Copy link

melvin-bot bot commented Apr 24, 2025

📣 @Nick4dawin! 📣
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>

@Nick4dawin
Copy link

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

Copy link

melvin-bot bot commented Apr 24, 2025

✅ Contributor details stored successfully. Thank you for contributing to Expensify!

Copy link

melvin-bot bot commented Apr 28, 2025

@alitoshmatov Eep! 4 days overdue now. Issues have feelings too...

@melvin-bot melvin-bot bot added the Overdue label Apr 28, 2025
@alitoshmatov
Copy link
Contributor

Reviewing

@mallenexpensify
Copy link
Contributor

Starting at LOW based on the below. Please update or comment if you think this should be a higher priority.

  • CRITICAL - UX Reliability, API Reliability and Performance bugs that are noticeable for a majority of users
  • HIGH -  UX Reliability, API Reliability and Performance issues that are part of main flows and affect a subset of users
  • MEDIUM - Debugging Tools to help make fixing existing bugs easier and getting fixes to customers faster and Architectural Improvements to the underlying framework and design of the app to improve performance, scalability, and maintainability
  • LOW - Not very noticeable UX Reliability, API Reliability or Performance issues that only affect a single user or subset of users

Copy link

melvin-bot bot commented Apr 29, 2025

📣 It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? 💸

@Christinadobrzyn
Copy link
Contributor

hi @alitoshmatov do you have an update?

Copy link

melvin-bot bot commented May 12, 2025

@techievivek, @Christinadobrzyn, @alitoshmatov Whoops! This issue is 2 days overdue. Let's get this updated quick!

@techievivek
Copy link
Contributor

Gentle bump @alitoshmatov, can you look at the above comments?

@melvin-bot melvin-bot bot removed the Overdue label May 12, 2025
@Christinadobrzyn
Copy link
Contributor

Christinadobrzyn commented May 13, 2025

Nudged @alitoshmatov in Slack DM in the C+ channel https://expensify.slack.com/archives/C02NK2DQWUX/p1747166268674319

@alitoshmatov
Copy link
Contributor

Okay, this two proposals are very similar but I still think @ishakakkad 's proposal is better choice because it is isolated only to report deletion. I believe this eliminates potential regressions, since the conditions here cover other different cases.

C+ reviewed 🎀 👀 🎀

Copy link

melvin-bot bot commented May 14, 2025

Current assignee @techievivek is eligible for the choreEngineerContributorManagement assigner, not assigning anyone new.

@thelullabyy
Copy link
Contributor

@alitoshmatov Thanks for your review!

I believe this eliminates potential regressions

Could you clarify which specific regressions might be introduced by my proposed solution?

From my perspective, choosing one solution over another solely because it’s “isolated to one case” isn’t a strong enough reason—unless we can clearly identify what regressions the other solution would cause. If you have any examples or scenarios in mind where my solution could lead to unintended behavior, I’d really appreciate it if you could share them. That would help ensure we're making the most robust choice. cc @techievivek

@alitoshmatov
Copy link
Contributor

If you have any examples or scenarios in mind where my solution could lead to unintended behavior, I’d really appreciate it if you could share them.

I don't have one. My reasoning is that the other conditions like
(!prevUserLeavingStatus && !!userLeavingStatus) || didReportClose || isClosedTopLevelPolicyRoom || (prevDeletedParentAction && !deletedParentAction)
might be working fine with current logic and change when we introduce closing modal in narrow layout.

I do want to say that both solutions are correct and very similar and it is hard to choose one over another. The above is my subjective reasoning.

@techievivek I would appreciate your input. I am not sure which is the best approach here.

@thelullabyy
Copy link
Contributor

do want to say that both solutions are correct and very similar and it is hard to choose one over another

@techievivek I think in your case, the rule below would be considered and in this case, my solution comes first:

Note: Before submitting a proposal on an issue, be sure to read any other existing proposals. ALL NEW PROPOSALS MUST BE DIFFERENT FROM EXISTING PROPOSALS. The difference should be important, meaningful or considerable.

@ishakakkad
Copy link
Contributor

@techievivek I’d like to clarify that my approach is not the same as @thelullabyy’s proposal. Here are the key differences for your consideration:

  • My proposal leverages the existing isRemovalExpectedForReportType logic to determine when to dismiss the modal. This avoids redundant logic and adheres to the DRY (Don't Repeat Yourself) principle, unlike @thelullabyy’s approach which involves checking conditions for each report type explicitly.
  • I propose moving the logic outside the this block. This ensures unnecessary checks are avoided entirely, improving performance and reducing cognitive overhead in that section of the code.

@thelullabyy
Copy link
Contributor

thelullabyy commented May 19, 2025

@techievivek Whenever you get a chance, could you please take a look at this comment? Your feedback would be much appreciated. Thanks!

@alitoshmatov Also, do you have any feedback on my response? It addresses your earlier question regarding the root cause of the issue. Let me know if anything is unclear or needs further clarification.

I also think this is an important factor to consider when evaluating the selected proposal, especially since this other anwser appears to be incorrect in my opinion.

@melvin-bot melvin-bot bot added the Overdue label May 19, 2025
Copy link

melvin-bot bot commented May 19, 2025

@techievivek, @Christinadobrzyn, @alitoshmatov Whoops! This issue is 2 days overdue. Let's get this updated quick!

@techievivek
Copy link
Contributor

I went through both proposals carefully, and I agree with @alitoshmatov’s assessment. @ishakakkad’s proposal stood out for me for having a clear RCA, along with a well-scoped solution that not only addresses the issue but also simplifies and refactors the code in a meaningful way, making it easier to follow and maintain.

For example, in the RCA, @thelullabyy, your proposal mentioned:

"However, this logic does not apply when the report is accessed via the search page."

But it wasn't entirely clear why the logic differs in that context. What specifically changes when accessing the report from the search page?

On the other hand, @ishakakkad’s RCA clearly identified the root of the problem:

"...that will not execute for the narrowPanelModal because we early return from here."

This level of specificity really helped in understanding both the problem and the fix.

@melvin-bot melvin-bot bot removed the Overdue label May 19, 2025
@techievivek
Copy link
Contributor

I really appreciate the time, thought, and effort you put into it. These kinds of head-to-head contributions are what make the review process so valuable. Please let me know if you have any other questions or if you would like to clarify anything, thanks.

@thelullabyy
Copy link
Contributor

But it wasn't entirely clear why the logic differs in that context. What specifically changes when accessing the report from the search page?

@techievivek You're right—that's my mistake for not clearly outlining what specifically changes when accessing the report from the search page. However, I believe it's explained more clearly via the code change in the "What changes do you think we should make in order to solve the problem?" section of my proposal.

During the discussion, C+ raised a question about the root cause in this comment, specifically asking why isInNarrowPaneModal was added in:

// Prevent auto navigation for report in RHP
if ((!isFocused && !isReportDetailOpenInRHP) || isInNarrowPaneModal) {

In response, @ishakakkad provided an answer, but I believe it's incorrect.

My answer is here, and I think it correctly identifies the PR where isInNarrowPaneModal was introduced. Based on that context, we can consider removing the isInNarrowPaneModal condition as part of the solution to this issue.

@techievivek
Copy link
Contributor

My answer is #60624 (comment), and I think it correctly identifies the PR where isInNarrowPaneModal was introduced. Based on that context, we can consider removing the isInNarrowPaneModal condition as part of the solution to this issue.

I don’t see isInNarrowPaneModal being added in that PR, no? Initially, we added a check for isReportOpenInRHP in that PR, but later refined it to be more specific—using isReportDetailOpenInRHP along with an additional condition for isInNarrowPaneModal.

As I mentioned before, we really appreciate the effort and quick turnaround you provided to help the C+. That said, after reviewing the proposals, we felt @ishakakkad's solution addressed the issue more precisely, so we decided to move forward with hers.

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

melvin-bot bot commented May 20, 2025

📣 @ishakakkad 🎉 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 📖

Copy link

melvin-bot bot commented May 20, 2025

@techievivek @Christinadobrzyn @alitoshmatov this issue is now 4 weeks old, please consider:

  • Finding a contributor to fix the bug
  • Closing the issue if BZ has been unable to add the issue to a VIP or Wave project
  • If you have any questions, don't hesitate to start a discussion in #expensify-open-source

Thanks!

@Christinadobrzyn
Copy link
Contributor

@ishakakkad can you please provide an update on the PR when you have a moment?

@Christinadobrzyn
Copy link
Contributor

Just a heads up that I'm going to be ooo May 21st - May 27th. Back on the 28th.

I'm not going to assign another BZ teammate but if you need someone while I'm gone, please remove and add the Bug label.

@ishakakkad
Copy link
Contributor

@Christinadobrzyn PR will be created by tomorrow.

@ishakakkad
Copy link
Contributor

@alitoshmatov I am not able to reproduced the issue. Are you able to reproduced the issue? Seems now we are not showing deleted messages when we open RHP.

@techievivek
Copy link
Contributor

Let me confirm with the QA.

@techievivek
Copy link
Contributor

This is no longer reproducible, just confirmed with the QA https://expensify.slack.com/archives/C9YU7BX5M/p1747886520835639?thread_ts=1747836381.235709&cid=C9YU7BX5M

@techievivek
Copy link
Contributor

Based on our internal guidelines for handling bounties in situations like this, I believe both C/C+ would qualify for a 50% payout here.

CC @Christinadobrzyn — more details here: https://stackoverflowteams.com/c/expensify/questions/8719

@IuliiaHerets
Copy link

@techievivek Issue is not reproducible anymore

20250522_133900.mp4

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

No branches or pull requests