Skip to content

Commit 9f1ddc5

Browse files
authored
Revert "Fix: smooth post-submit navigation and rendering on Spend tab"
1 parent cab0b7b commit 9f1ddc5

18 files changed

Lines changed: 154 additions & 524 deletions

File tree

src/CONST/index.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7518,10 +7518,6 @@ const CONST = {
75187518

75197519
DOWNLOADS_PATH: '/Downloads',
75207520
DOWNLOADS_TIMEOUT: 5000,
7521-
7522-
// Max time (ms) to wait for a transaction thread report before falling back to renderable content.
7523-
SKELETON_LOADING_TIMEOUT_MS: 10000,
7524-
75257521
NEW_EXPENSIFY_PATH: '/New Expensify',
75267522
RECEIPTS_UPLOAD_PATH: '/Receipts-Upload',
75277523

src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import useThemeStyles from '@hooks/useThemeStyles';
2626
import useWindowDimensions from '@hooks/useWindowDimensions';
2727
import {isConsecutiveChronosAutomaticTimerAction} from '@libs/ChronosUtils';
2828
import DateUtils from '@libs/DateUtils';
29-
import {hasDeferredWrite} from '@libs/deferredLayoutWrite';
3029
import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
3130
import {getAllNonDeletedTransactions, isActionVisibleOnMoneyRequestReport} from '@libs/MoneyRequestReportUtils';
3231
import Navigation from '@libs/Navigation/Navigation';
@@ -666,14 +665,6 @@ function MoneyRequestReportActionsList({onLayout}: MoneyRequestReportListProps)
666665
return numToRender || undefined;
667666
}, [styles.chatItem.paddingBottom, styles.chatItem.paddingTop, windowHeight, linkedReportActionID]);
668667

669-
const isReportEmpty = isEmpty(visibleReportActions) && isEmpty(transactions) && !showReportActionsLoadingState;
670-
// hasDeferredWrite is non-reactive (reads a module-level Map, not tracked by React).
671-
// This is intentional: we only check on the initial render after the RHP dismisses.
672-
// Once the deferred write flushes and createTransaction runs, Onyx updates make
673-
// transactions non-empty, which drives the transition away from the skeleton.
674-
const isAwaitingDeferredTransaction = isReportEmpty && hasDeferredWrite(CONST.DEFERRED_LAYOUT_WRITE_KEYS.DISMISS_MODAL);
675-
const showEmptyState = isReportEmpty && !isAwaitingDeferredTransaction;
676-
677668
if (!report) {
678669
return null;
679670
}
@@ -694,12 +685,7 @@ function MoneyRequestReportActionsList({onLayout}: MoneyRequestReportListProps)
694685
isActive={isFloatingMessageCounterVisible}
695686
onClick={scrollToBottomAndMarkReportAsRead}
696687
/>
697-
{/* Exactly one of these three branches is active at a time:
698-
1. isAwaitingDeferredTransaction — skeleton while dismiss-first creates the transaction
699-
2. showEmptyState — genuinely empty report
700-
3. !isReportEmpty — report has data, render the FlatList */}
701-
{isAwaitingDeferredTransaction && <ReportActionsListLoadingSkeleton reasonAttributes={skeletonReasonAttributes} />}
702-
{showEmptyState && (
688+
{isEmpty(visibleReportActions) && isEmpty(transactions) && !showReportActionsLoadingState ? (
703689
<ScrollView contentContainerStyle={styles.flexGrow1}>
704690
<MoneyRequestViewReportFields
705691
report={report}
@@ -711,8 +697,7 @@ function MoneyRequestReportActionsList({onLayout}: MoneyRequestReportListProps)
711697
policy={policy}
712698
/>
713699
</ScrollView>
714-
)}
715-
{!isReportEmpty && (
700+
) : (
716701
<FlatListWithScrollKey
717702
initialNumToRender={initialNumToRender}
718703
accessibilityLabel={translate('sidebarScreen.listOfChatMessages')}

src/components/Search/SearchPageHeader/useSearchFiltersBar.tsx

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
2525
import {close} from '@libs/actions/Modal';
2626
import Navigation from '@libs/Navigation/Navigation';
2727
import {buildFilterQueryWithSortDefaults, isAmountFilterKey} from '@libs/SearchQueryUtils';
28-
import {
29-
FILTER_GROUP_MAP,
30-
FILTER_LABEL_MAP,
31-
filterValidHasValues,
32-
getMultiSelectFilterOptions,
33-
getSingleSelectFilterOptions,
34-
mapFiltersFormToLabelValueList,
35-
SKIPPED_SEARCH_FILTERS,
36-
} from '@libs/SearchUIUtils';
28+
import {FILTER_GROUP_MAP, FILTER_LABEL_MAP, filterValidHasValues, getMultiSelectFilterOptions, getSingleSelectFilterOptions, mapFiltersFormToLabelValueList} from '@libs/SearchUIUtils';
3729
import type {SearchFilter} from '@libs/SearchUIUtils';
3830
import CONST from '@src/CONST';
3931
import type {TranslationPaths} from '@src/languages/types';
@@ -61,6 +53,18 @@ type UseSearchFiltersBarResult = {
6153
translate: ReturnType<typeof useLocalize>['translate'];
6254
};
6355

56+
const SKIPPED_FILTERS = new Set<SearchAdvancedFiltersKey>([
57+
FILTER_KEYS.GROUP_BY,
58+
FILTER_KEYS.GROUP_CURRENCY,
59+
FILTER_KEYS.LIMIT,
60+
FILTER_KEYS.TYPE,
61+
FILTER_KEYS.VIEW,
62+
FILTER_KEYS.PAYER,
63+
FILTER_KEYS.ACTION,
64+
FILTER_KEYS.COLUMNS,
65+
FILTER_KEYS.KEYWORD,
66+
]);
67+
6468
function getFilterSentryLabel(filterKey: SearchAdvancedFiltersKey | SearchFilterKey | ReportFieldKey) {
6569
return `Search-Filter-${filterKey}`;
6670
}
@@ -202,7 +206,7 @@ function useSearchFiltersBar(queryJSON: SearchQueryJSON): UseSearchFiltersBarRes
202206
});
203207
};
204208

205-
const filters = mapFiltersFormToLabelValueList<FilterItem>(searchAdvancedFiltersForm, queryJSON.policyID, SKIPPED_SEARCH_FILTERS, translate, localeCompare, (filterKey) => {
209+
const filters = mapFiltersFormToLabelValueList<FilterItem>(searchAdvancedFiltersForm, queryJSON.policyID, SKIPPED_FILTERS, translate, localeCompare, (filterKey) => {
206210
const groupConfig = FILTER_GROUP_MAP[filterKey];
207211
if (groupConfig) {
208212
if (isAmountFilterKey(groupConfig.syntax)) {
@@ -426,4 +430,4 @@ function useSearchFiltersBar(queryJSON: SearchQueryJSON): UseSearchFiltersBarRes
426430

427431
export default useSearchFiltersBar;
428432
export type {FilterItem};
429-
export {typeOptionsPoliciesSelector};
433+
export {typeOptionsPoliciesSelector, SKIPPED_FILTERS};

src/components/Search/index.tsx

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ import {
5656
isTransactionGroupListItemType,
5757
isTransactionListItemType,
5858
isTransactionReportGroupListItemType,
59-
isTransactionSearchType,
6059
shouldShowEmptyState,
6160
shouldShowYear as shouldShowYearUtil,
6261
} from '@libs/SearchUIUtils';
@@ -84,6 +83,7 @@ import {useSearchActionsContext, useSearchStateContext} from './SearchContext';
8483
import SearchList from './SearchList';
8584
import type {ReportActionListItemType, SearchListItem, TransactionGroupListItemType, TransactionListItemType, TransactionReportGroupListItemType} from './SearchList/ListItem/types';
8685
import {SearchScopeProvider} from './SearchScopeProvider';
86+
import SearchStaticList from './SearchStaticList';
8787
import SearchTableHeader from './SearchTableHeader';
8888
import type {SearchColumnType, SearchParams, SearchQueryJSON, SelectedTransactionInfo, SelectedTransactions, SortOrder} from './types';
8989

@@ -1462,21 +1462,14 @@ function Search({
14621462
searchResults?.data,
14631463
]);
14641464

1465-
const onLayoutBase = useCallback(() => {
1465+
const onLayout = useCallback(() => {
14661466
hasHadFirstLayout.current = true;
14671467
onDestinationVisible?.(isSearchResultsEmptyRef.current, 'layout');
14681468
endSpanWithAttributes(CONST.TELEMETRY.SPAN_NAVIGATE_TO_REPORTS, {[CONST.TELEMETRY.ATTRIBUTE_IS_WARM]: true});
1469-
flushDeferredWrite(CONST.DEFERRED_LAYOUT_WRITE_KEYS.SEARCH);
1470-
}, [onDestinationVisible]);
1471-
1472-
// Deferred layout only needs the base work (no scroll handling, no content-ready signal).
1473-
const onDeferredLayout = onLayoutBase;
1474-
1475-
const onLayout = useCallback(() => {
1476-
onLayoutBase();
14771469
handleSelectionListScroll(stableSortedData, searchListRef.current);
1470+
flushDeferredWrite(CONST.DEFERRED_LAYOUT_WRITE_KEYS.SEARCH);
14781471
onContentReady?.();
1479-
}, [onLayoutBase, handleSelectionListScroll, stableSortedData, onContentReady]);
1472+
}, [handleSelectionListScroll, stableSortedData, onContentReady, onDestinationVisible]);
14801473

14811474
// Must be a ref, not state: cancelNavigationSpans is called during render
14821475
// (inside conditional returns), so using setState would trigger infinite re-renders.
@@ -1572,14 +1565,25 @@ function Search({
15721565
);
15731566

15741567
// When heavy work is deferred (e.g. during the RHP dismiss animation after
1575-
// submitting an expense), skip the expensive render below. The ancestor
1576-
// SearchPage (via SearchPageNarrow / SearchPageWide) renders a SearchStaticList
1577-
// overlay that covers this component, so the user sees real-looking content.
1578-
// The minimal View fires onLayout to flush the deferred API write and set
1579-
// hasHadFirstLayout.
1580-
if (isDeferringHeavyWork && searchResults?.data && isTransactionSearchType(type)) {
1581-
// Zero-sized View - onLayout still fires on RN, which is all we need here.
1582-
return <View onLayout={onDeferredLayout} />;
1568+
// submitting an expense), show a lightweight static list instead of the skeleton.
1569+
// This gives the user real-looking content during the animation while avoiding
1570+
// the expensive hooks and renders of the full Search component.
1571+
// Restricted to transaction-based search types (expense/invoice) because
1572+
// SearchStaticList only renders rows with a transactionID - non-transaction
1573+
// types (chat, task, report) would render empty/blank during the deferral.
1574+
const isTransactionSearchType = type === CONST.SEARCH.DATA_TYPES.EXPENSE || type === CONST.SEARCH.DATA_TYPES.INVOICE;
1575+
if (isDeferringHeavyWork && searchResults?.data && isTransactionSearchType) {
1576+
return (
1577+
<SearchStaticList
1578+
searchResults={searchResults}
1579+
queryJSON={queryJSON}
1580+
shouldUseNarrowLayout={shouldUseNarrowLayout}
1581+
canSelectMultiple={canSelectMultiple}
1582+
columns={currentColumns}
1583+
contentContainerStyle={shouldUseNarrowLayout ? styles.searchListContentContainerStyles(!!hasFilterBars) : undefined}
1584+
onLayout={onLayout}
1585+
/>
1586+
);
15831587
}
15841588

15851589
// This is a performance optimization for the submit-expense->search path only.

src/hooks/useSearchOverlay.tsx

Lines changed: 0 additions & 125 deletions
This file was deleted.

src/libs/MoneyRequestReportUtils.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import type {TransactionListItemType} from '@components/Search/SearchList/ListIt
44
import type {CurrencyListActionsContextType} from '@hooks/useCurrencyList';
55
import CONST from '@src/CONST';
66
import type {OriginalMessageIOU, Policy, Report, ReportAction, ReportLoadingState, Transaction} from '@src/types/onyx';
7-
import {hasDeferredWrite} from './deferredLayoutWrite';
87
import {isPaidGroupPolicy} from './PolicyUtils';
98
import {getIOUActionForTransactionID, getOriginalMessage, isDeletedAction, isDeletedParentAction, isMoneyRequestAction} from './ReportActionsUtils';
109
import {
@@ -137,10 +136,7 @@ function shouldWaitForTransactions(report: OnyxEntry<Report>, transactions: Tran
137136

138137
const isTransactionDataReady = transactions !== undefined;
139138
const isTransactionThreadView = isReportTransactionThread(report);
140-
const hasPendingDismissWrite = hasDeferredWrite(CONST.DEFERRED_LAYOUT_WRITE_KEYS.DISMISS_MODAL);
141-
const isStillLoadingData =
142-
transactions?.length === 0 &&
143-
((!!reportLoadingState?.isLoadingInitialReportActions && !reportLoadingState.hasOnceLoadedReportActions) || report?.total !== 0 || hasPendingDismissWrite);
139+
const isStillLoadingData = transactions?.length === 0 && ((!!reportLoadingState?.isLoadingInitialReportActions && !reportLoadingState.hasOnceLoadedReportActions) || report?.total !== 0);
144140
return (
145141
(isMoneyRequestReport(report) || isInvoiceReport(report)) &&
146142
(!isTransactionDataReady || isStillLoadingData) &&

src/libs/SearchUIUtils.ts

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -597,18 +597,6 @@ type GetSectionsParams = {
597597
*/
598598
const GENERIC_SEARCH_KEYS: ReadonlySet<SearchKey> = new Set([CONST.SEARCH.SEARCH_KEYS.EXPENSES, CONST.SEARCH.SEARCH_KEYS.REPORTS]);
599599

600-
const SKIPPED_SEARCH_FILTERS = new Set<SearchAdvancedFiltersKey>([
601-
FILTER_KEYS.GROUP_BY,
602-
FILTER_KEYS.GROUP_CURRENCY,
603-
FILTER_KEYS.LIMIT,
604-
FILTER_KEYS.TYPE,
605-
FILTER_KEYS.VIEW,
606-
FILTER_KEYS.PAYER,
607-
FILTER_KEYS.ACTION,
608-
FILTER_KEYS.COLUMNS,
609-
FILTER_KEYS.KEYWORD,
610-
]);
611-
612600
function doesSearchItemMatchSort(key: SearchKey, itemSortBy: string | undefined, itemSortOrder: string | undefined, currentSortBy: string | undefined, currentSortOrder: string | undefined) {
613601
return GENERIC_SEARCH_KEYS.has(key) || (itemSortBy === currentSortBy && itemSortOrder === currentSortOrder);
614602
}
@@ -4189,10 +4177,6 @@ function isCorrectSearchUserName(displayName?: string) {
41894177
return displayName && displayName.toUpperCase() !== CONST.REPORT.OWNER_EMAIL_FAKE;
41904178
}
41914179

4192-
function isTransactionSearchType(type: string | undefined): boolean {
4193-
return type === CONST.SEARCH.DATA_TYPES.EXPENSE || type === CONST.SEARCH.DATA_TYPES.INVOICE;
4194-
}
4195-
41964180
function isTodoSearch(recentSearchHash: number, suggestedSearches: Record<string, SearchTypeMenuItem>) {
41974181
const matchedSearchKey = Object.values(suggestedSearches).find((search) => search.recentSearchHash === recentSearchHash)?.key;
41984182
return !!matchedSearchKey && TODO_SEARCH_KEYS.has(matchedSearchKey);
@@ -5855,8 +5839,6 @@ export {
58555839
FILTER_LABEL_MAP,
58565840
doesSearchItemMatchSort,
58575841
isPolicyEligibleForSpendOverTime,
5858-
isTransactionSearchType,
5859-
SKIPPED_SEARCH_FILTERS,
58605842
};
58615843
export type {
58625844
SavedSearchMenuItem,

src/libs/telemetry/middlewares/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@ import type {EventHint, Log, TransactionEvent} from '@sentry/core';
22
import copyTagsToChildSpans from './copyTagsToChildSpans';
33
import emailDomainFilter from './emailDomainFilter';
44
import httpClientCancelledFilter from './httpClientCancelledFilter';
5-
import maxDurationFilter from './maxDurationFilter';
65
import minDurationFilter from './minDurationFilter';
76
import onyxLogFilter from './onyxLogFilter';
87

98
type TelemetryBeforeSend = (event: TransactionEvent, hint: EventHint) => TransactionEvent | null | Promise<TransactionEvent | null>;
109
type TelemetryBeforeSendLog = (log: Log) => Log | null;
1110

12-
const middlewares: TelemetryBeforeSend[] = [emailDomainFilter, minDurationFilter, maxDurationFilter, httpClientCancelledFilter, copyTagsToChildSpans];
11+
const middlewares: TelemetryBeforeSend[] = [emailDomainFilter, minDurationFilter, httpClientCancelledFilter, copyTagsToChildSpans];
1312
const logMiddlewares: TelemetryBeforeSendLog[] = [onyxLogFilter];
1413

1514
function processBeforeSendTransactions(event: TransactionEvent, hint: EventHint): Promise<TransactionEvent | null> {

0 commit comments

Comments
 (0)