Skip to content

[Due for payment 2026-08-31] Expense - Expense added growl does not appear after changing report and creating expense #99262

Closed

Description

@applause-bot

If you haven’t already, check out our contributing guidelines for onboarding. To join our Slack channel, fill out this form.


Version Number: 9.4.59-0
Reproducible in staging?: Yes
Reproducible in production?: N/A - new feature, doesn't exist in prod
If this was caught during regression testing, add the test name, ID and link from BrowserStack: #96496
Email or phone of affected tester (no customers): [email protected]
Issue reported by: Applause Internal Team
Bug source: Exploratory - Significant User Experience Deterioration
Device used: Mac 26.5 / Chrome
App Component: Money Requests

Action Performed:

  1. Go to staging.new.expensify.com
  2. Go to workspace chat.
  3. Create an expense.
  4. Create a new empty report.
  5. Open FAB > Create expense > Manual.
  6. Enter amount > Next.
  7. On confirm page, enter merchant.
  8. Click Report field.
  9. Select the report from Step 3.
  10. Click Create expense.

Expected Result:

Expense added growl will appear after changing report and creating expense.

Actual Result:

Expense added growl does not appear after changing report and creating expense.

Workaround:

Unknown

Platforms:

  • Android: App
  • Android: mWeb Chrome
  • iOS: App
  • iOS: mWeb Safari
  • iOS: mWeb Chrome
  • Windows: Chrome
  • MacOS: Chrome Safari

Screenshots/Videos

Bug7240113_1787411253268.9.mp4

View all open jobs on GitHub

Applause Internal Information
Exported by: Julia Ponikarchuk
Bug ID: 7240113

Issue OwnerCurrent Issue Owner: @situchan

Activity

  1. applause-bot commented on Aug 23, 2026

    @applause-bot
    Author

    While Applause doesn't embed attachments for this bug, here are the links for quick view:
    https://platform.applause.com/services/links/v1/external/6c5a17bb0fcc63e97ec154fbc9a3d79afa1e90c2c5619f3df2ee8f0ef83f3e41

  2. added
    DeployBlockerCashThis issue or pull request should block deployment
    BugSomething is broken. Auto assigns a BugZero manager.
    on Aug 23, 2026
  3. melvin-bot commented on Aug 23, 2026

    @melvin-bot

    @mountiny recently merged #96496, but they are OOO right now, so I'll auto-assign someone else.

  4. melvin-bot commented on Aug 23, 2026

    @melvin-bot

    Triggered auto assignment to @chuckdries (DeployBlockerCash), see https://stackoverflowteams.com/c/expensify/questions/9980/ for more details.

  5. melvin-bot commented on Aug 23, 2026

    @melvin-bot

    @mountiny @situchan you have been assigned to this deploy blocker because you reviewed the offending PR: #96496

  6. melvin-bot commented on Aug 23, 2026

    @melvin-bot

    @mhawryluk you have been assigned to this deploy blocker because you authored the offending PR: #96496

  7. melvin-bot commented on Aug 23, 2026

    @melvin-bot

    💬 A slack conversation has been started in #expensify-open-source

  8. 1 remaining item

  9. MelvinBot commented on Aug 23, 2026

    @MelvinBot
    Contributor

    🔍 Investigation Summary

    Classification: Frontend bug
    Causing PR: #96496 - "Show 'Expense added' growl driven by a single Onyx-signalled component" by @mhawryluk (High confidence)
    Related Issues: #91408 (the feature issue this PR implemented)

    Recommendation: ROLL FORWARD

    PR #96496 is a large refactor (growl feature + Search view changes + highlight removal across ~50 files); a full revert is disproportionate for what is a narrow, one-line suppression-heuristic bug. A targeted fix to the growl's suppression condition is safer and smaller than reverting.

    Assigned: @mhawryluk (PR author), @mountiny and @situchan (approving reviewers) — all already assigned to this issue.
    Labels: No changes. This is a frontend bug, so DeployBlockerCash is correctly kept (App deploy is blocked). No DeployBlocker (Web) label is present, so nothing to remove.

    📋 Detailed Analysis

    Evidence

    • PR Confirm new expenses with a “View” toast instead of scrolling to and highlighting the row #96496 introduced the entire "Expense added" growl feature, including the new src/components/ExpenseAddedGrowl.tsx component and its suppression logic. It is present on the current StagingDeployCash checklist (Deploy Checklist: New Expensify 2026-08-22 #99230), matches the reported version (9.4.59-0), and the bug is staging-only because the feature does not exist in production. This is a genuine regression in the newly-added feature, not a pre-existing bug.
    • The growl is signalled unconditionally for global-create expenses in requestMoney (src/libs/actions/IOU/TrackExpense.ts:1952-1954), so the signal fires in both the working flow and the bug flow. The difference is purely in whether the ExpenseAddedGrowl component decides to show it.

    Verification

    • Affected file: src/components/ExpenseAddedGrowl.tsx, specifically the suppression guard at lines 110-116:
      // Suppress the growl when the user is already viewing the expense's money-request report
      if (Navigation.getTopmostReportId() === transaction.reportID) {
      return;
      }
      nonceRef.current += 1;
      setActive({transactionID: latestTransactionID, dataType, nonce: nonceRef.current});
      }, [signal, active, transaction, setActive]);
      // Suppress the growl when the user is already viewing the expense's money-request report
      if (Navigation.getTopmostReportId() === transaction.reportID) {
          return;
      }
    • Post-create navigation is decided in cleanupAndNavigateAfterExpenseCreate (lines 75-76):
      const finalActiveReportID = navigationReportID ?? backToReport ?? report?.reportID ?? optimisticChatReportID;
      const hasMultipleTransactions = isInvoice ? false : isMoneyRequestReport(finalActiveReportID === report?.reportID ? report : getReportOrDraftReport(finalActiveReportID));
      const finalActiveReportID = navigationReportID ?? backToReport ?? report?.reportID ?? optimisticChatReportID;
      const hasMultipleTransactions = isInvoice ? false : isMoneyRequestReport(finalActiveReportID === report?.reportID ? report : getReportOrDraftReport(finalActiveReportID));
    • The resulting navigation lands on the money-request report itself in dismissModalAndOpenReportInInboxTab (e.g. ROUTES.SEARCH_MONEY_REQUEST_REPORT / dismissModalWithReport({reportID})):
      if (hasMultipleTransactions && reportID) {
      // On small screens, dismiss all modals and then navigate to the right report.
      // On large screens, dismiss to the previous RHP first, then replace the current route with the new report.
      const isNarrowLayout = getIsNarrowLayout();
      if (isNarrowLayout) {
      Navigation.dismissModal();
      } else {
      Navigation.dismissToPreviousRHP();
      }
      setNavigationActionToMicrotaskQueue(() => {
      Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID}), {forceReplace: !isNarrowLayout});
      });
      return;
      }
      Navigation.pop(rhpKey);
      return;
      }
      }
      if (isSearchTopmostFullScreenRoute() || !reportID) {
      if (hasActiveTracking) {
      setPendingSubmitFollowUpAction(CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_ONLY);
      }
      Navigation.dismissModal({
      afterTransition: () => {
      if (!hasActiveTracking) {
      return;
      }
      endSubmitFollowUpActionSpan(CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_ONLY);
      },
      });
      return;
      }
      if (hasActiveTracking) {
      Navigation.dismissModalWithReport({reportID}, undefined, {
      onBeforeNavigate: (willOpenReport: boolean) => {
      setPendingSubmitFollowUpAction(
      willOpenReport ? CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_AND_OPEN_REPORT : CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_ONLY,
      reportID,
      );
      },
      });
      } else {
      Navigation.dismissModalWithReport({reportID});
      }
    • The signal firing site is confirmed at:
      if (!requestMoneyInformation.isRetry && isFromGlobalCreate) {
      signalExpenseAddedGrowl(transaction.transactionID, CONST.SEARCH.DATA_TYPES.EXPENSE);
      }

    Root Cause

    The growl suppression guard bails whenever the report the user lands on after creation equals transaction.reportID. That comparison does not distinguish the parent money-request report (where the new expense is just one row) from the transaction thread (where the expense detail is actually shown).

    • Normal flow (works): The destination report is a chat, so finalActiveReportID is the chat report ID. Post-create navigation opens that chat, whose ID differs from the newly-created expense report ID (transaction.reportID). The guard does not match, so the growl shows.
    • Bug flow (broken): Selecting an existing report via the Report field makes the destination report a money-request report. cleanupAndNavigateAfterExpenseCreate therefore sets finalActiveReportID = report.reportID and hasMultipleTransactions = true, and dismissModalAndOpenReportInInboxTab navigates onto that money-request report. Now Navigation.getTopmostReportId() === transaction.reportID is true, so the suppression guard returns early and the growl never appears — even though the user is viewing the parent report list, not the expense's own thread that "View" would open.

    Suggested Fix

    Narrow the suppression in ExpenseAddedGrowl.tsx so it only suppresses when the user is genuinely viewing the transaction's own context, not merely the parent money-request report. For example, suppress only when the topmost report is the transaction thread report (transaction.transactionThreadReportID / the resolved thread), or explicitly allow the growl when the landed report is a money-request report (isMoneyRequestReport(report)). This keeps the redundant-growl suppression for the "already in the thread" case while restoring the growl when an expense is added to an existing report via the Report field.

  10. m-natarajan commented on Aug 24, 2026

    @m-natarajan

    Not reproducible on macOS 14.6 / Chrome, v9.4.59-1

    Screen.Recording.2026-08-24.at.3.46.18.at.night.mov
  11. added and removed
    DeployBlockerCashThis issue or pull request should block deployment
    on Aug 24, 2026
  12. mhawryluk commented on Aug 24, 2026

    @mhawryluk
    Member

    this is the expected behavior, we don't show the growl when we navigate to the report list view in Inbox, where the row is still highlighted

  13. mountiny commented on Aug 24, 2026

    @mountiny
    Contributor

    Agreed

  14. changed the title [-]Expense - Expense added growl does not appear after changing report and creating expense[/-] [+][Due for payment 2026-08-31] Expense - Expense added growl does not appear after changing report and creating expense[/+] on Aug 24, 2026
  15. melvin-bot commented on Aug 24, 2026

    @melvin-bot

    @situchan

    The solution for this issue has been 🚀 deployed to production 🚀 in version 9.4.59-5 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 2026-08-31. 🎊

    The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the Contributor+ 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]. If no checklist is needed for this issue, you can click: [no checklist button]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

BugSomething is broken. Auto assigns a BugZero manager.DailyKSv2Engineering

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions