From 87c5d6d939c631a155b34105ad05695c6ccee05a Mon Sep 17 00:00:00 2001 From: jakubstec Date: Mon, 18 May 2026 14:42:22 +0200 Subject: [PATCH 1/2] fix: remove skeleton loader in the report after creating expense and update comments --- .../MoneyRequestReportActionsList.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx index 7a607051dfe4..26b6c43a7f50 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx @@ -658,9 +658,13 @@ function MoneyRequestReportActionsList({onLayout}: MoneyRequestReportListProps) // This is intentional: we only check on the initial render after the RHP dismisses. // Once the deferred write flushes and createTransaction runs, Onyx updates make // transactions non-empty, which drives the transition away from the skeleton. + // isEmpty(reportActions) prevents the skeleton from showing for already-initialised reports + // (those with a CREATED action): the CREATED action is always present but filtered from + // visibleReportActions, so without this guard isReportEmpty would be true even for reports + // that already have server-side content. // Scoping to `report.reportID` ensures an unrelated submit flow's pending dismiss doesn't keep // *this* report stuck on the skeleton. - const isAwaitingDeferredTransaction = isReportEmpty && hasDeferredWriteForReport(CONST.DEFERRED_LAYOUT_WRITE_KEYS.DISMISS_MODAL, report?.reportID); + const isAwaitingDeferredTransaction = isReportEmpty && isEmpty(reportActions) && hasDeferredWriteForReport(CONST.DEFERRED_LAYOUT_WRITE_KEYS.DISMISS_MODAL, report?.reportID); const showEmptyState = isReportEmpty && !isAwaitingDeferredTransaction; if (!report) { @@ -684,7 +688,7 @@ function MoneyRequestReportActionsList({onLayout}: MoneyRequestReportListProps) onClick={scrollToBottomAndMarkReportAsRead} /> {/* Exactly one of these three branches is active at a time: - 1. isAwaitingDeferredTransaction — skeleton while dismiss-first creates the transaction + 1. isAwaitingDeferredTransaction — skeleton while dismiss-first creates the first transaction on a report with no reportActions yet 2. showEmptyState — genuinely empty report 3. !isReportEmpty — report has data, render the FlatList */} {isAwaitingDeferredTransaction && } From a896d3121fc0f338a34fd985cac23749cd6a2e07 Mon Sep 17 00:00:00 2001 From: jakubstec Date: Mon, 18 May 2026 14:48:56 +0200 Subject: [PATCH 2/2] fix: refactor, remove dead code --- .../MoneyRequestReportActionsList.tsx | 22 ++++--------------- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx index 26b6c43a7f50..336674915180 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx @@ -26,7 +26,6 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import {isConsecutiveChronosAutomaticTimerAction} from '@libs/ChronosUtils'; import DateUtils from '@libs/DateUtils'; -import {hasDeferredWriteForReport} from '@libs/deferredLayoutWrite'; import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; import {getAllNonDeletedTransactions, isActionVisibleOnMoneyRequestReport} from '@libs/MoneyRequestReportUtils'; import Navigation from '@libs/Navigation/Navigation'; @@ -654,18 +653,7 @@ function MoneyRequestReportActionsList({onLayout}: MoneyRequestReportListProps) }, [styles.chatItem.paddingBottom, styles.chatItem.paddingTop, windowHeight, linkedReportActionID]); const isReportEmpty = isEmpty(visibleReportActions) && isEmpty(transactions) && !showReportActionsLoadingState; - // hasDeferredWriteForReport is non-reactive (reads a module-level Map, not tracked by React). - // This is intentional: we only check on the initial render after the RHP dismisses. - // Once the deferred write flushes and createTransaction runs, Onyx updates make - // transactions non-empty, which drives the transition away from the skeleton. - // isEmpty(reportActions) prevents the skeleton from showing for already-initialised reports - // (those with a CREATED action): the CREATED action is always present but filtered from - // visibleReportActions, so without this guard isReportEmpty would be true even for reports - // that already have server-side content. - // Scoping to `report.reportID` ensures an unrelated submit flow's pending dismiss doesn't keep - // *this* report stuck on the skeleton. - const isAwaitingDeferredTransaction = isReportEmpty && isEmpty(reportActions) && hasDeferredWriteForReport(CONST.DEFERRED_LAYOUT_WRITE_KEYS.DISMISS_MODAL, report?.reportID); - const showEmptyState = isReportEmpty && !isAwaitingDeferredTransaction; + const showEmptyState = isReportEmpty; if (!report) { return null; @@ -687,11 +675,9 @@ function MoneyRequestReportActionsList({onLayout}: MoneyRequestReportListProps) isActive={isFloatingMessageCounterVisible} onClick={scrollToBottomAndMarkReportAsRead} /> - {/* Exactly one of these three branches is active at a time: - 1. isAwaitingDeferredTransaction — skeleton while dismiss-first creates the first transaction on a report with no reportActions yet - 2. showEmptyState — genuinely empty report - 3. !isReportEmpty — report has data, render the FlatList */} - {isAwaitingDeferredTransaction && } + {/* Exactly one of these two branches is active at a time: + 1. showEmptyState — genuinely empty report + 2. !isReportEmpty — report has data, render the FlatList */} {showEmptyState && (