Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 35 additions & 16 deletions src/components/Search/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {useFocusEffect, useIsFocused, useNavigation} from '@react-navigation/native';
import {findFocusedRoute, useFocusEffect, useIsFocused, useNavigation} from '@react-navigation/native';
import * as Sentry from '@sentry/react-native';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import type {NativeScrollEvent, NativeSyntheticEvent, StyleProp, ViewStyle} from 'react-native';
Expand Down Expand Up @@ -67,16 +67,19 @@ import {
import {cancelSubmitFollowUpActionSpan, getPendingSubmitFollowUpAction} from '@libs/telemetry/submitFollowUpAction';
import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan';
import {isTransactionPendingDelete, shouldShowAttendees} from '@libs/TransactionUtils';
import Navigation from '@navigation/Navigation';
import Navigation, {navigationRef} from '@navigation/Navigation';
import type {SearchFullscreenNavigatorParamList} from '@navigation/types';
import EmptySearchView from '@pages/Search/EmptySearchView';
import CONST from '@src/CONST';
import NAVIGATORS from '@src/NAVIGATORS';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import SCREENS from '@src/SCREENS';
import {hasCompletedGuidedSetupFlowSelector, hasSeenTourSelector} from '@src/selectors/Onboarding';
import type {SaveSearch} from '@src/types/onyx';
import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage';
import type SearchResults from '@src/types/onyx/SearchResults';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import getEmptyArray from '@src/types/utils/getEmptyArray';
import ExpenseFlatSearchView from './ExpenseFlatSearchView';
import useSearchSnapshot from './hooks/useSearchSnapshot';
Expand Down Expand Up @@ -125,6 +128,7 @@ function Search({
const {type, status, sortBy, sortOrder, hash, similarSearchHash, groupBy, view} = queryJSON;

const {isOffline} = useNetwork();
const prevIsOffline = usePrevious(isOffline);
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
const {shouldUseNarrowLayout, isSmallScreenWidth, isLargeScreenWidth, isInLandscapeMode} = useResponsiveLayout();
const styles = useThemeStyles();
Expand Down Expand Up @@ -216,6 +220,7 @@ function Search({
showPendingExpensePlaceholder,
shouldDeferHeavySearchWork,
setShouldDeferHeavySearchWork,
hasPendingWriteOnMountRef,
skipDeferralOnFocusRef,
rearmTracking,
} = useSearchSnapshot({queryJSON, searchResults, newSearchResultKeys, transactions, reportActions});
Expand Down Expand Up @@ -353,29 +358,42 @@ function Search({
const shouldRetrySearchWithTotalsOrGroupedRef = useRef(false);

useEffect(() => {
if (offset === 0 || offset === searchResults?.search?.offset || !isFocused || isOffline || searchResults?.search?.isLoading) {
const focusedRoute = findFocusedRoute(navigationRef.getRootState());
const isMigratedModalDisplayed = focusedRoute?.name === NAVIGATORS.MIGRATED_USER_MODAL_NAVIGATOR || focusedRoute?.name === SCREENS.MIGRATED_USER_WELCOME_MODAL.DYNAMIC_ROOT;

const comingBackOnlineWithNoResults = prevIsOffline && !isOffline && isEmptyObject(searchResults?.data);
if (!comingBackOnlineWithNoResults && ((!isFocused && !isMigratedModalDisplayed) || isOffline)) {
return;
Comment on lines +365 to +366

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add back the error guard before retrying searches

When a failed or invalid search leaves searchResults.errors populated, this guard still falls through and calls handleSearch on mount/reconnect. handleSearchAction clears searchRequestResponseStatusCode before the optimistic Search update clears errors, so the render path sees hasErrors with a null status and briefly shows the generic FullPageErrorView instead of the invalid-query message. Please return while hasErrors is true before retrying.

Useful? React with 👍 / 👎.

}

// When mounting after the pre-insert fast path, the deferred write hasn't
// been flushed yet. Triggering a search now would race with the CREATE
// API call and return stale results that overwrite the optimistic row.
// Skip this call; the optimistic data from flushDeferredWrite will populate
// the list, and the next user-driven search will refresh from the server.
if (hasPendingWriteOnMountRef.current.hasPendingWriteOnMount && hasDeferredWrite(CONST.DEFERRED_LAYOUT_WRITE_KEYS.SEARCH)) {
return;
}

if (searchResults?.search?.isLoading) {
if (validGroupBy || (shouldCalculateTotals && searchResults?.search?.count === undefined)) {
shouldRetrySearchWithTotalsOrGroupedRef.current = true;
}
return;
}

handleSearch({
queryJSON,
searchKey: currentSearchKey,
offset,
shouldCalculateTotals: false,
shouldCalculateTotals,
prevReportsLength: filteredDataLength,
isLoading: false,
isLoading: !!searchResults?.search?.isLoading,
});
}, [currentSearchKey, filteredDataLength, handleSearch, isFocused, isOffline, offset, queryJSON, searchResults?.search?.isLoading, searchResults?.search?.offset]);

useEffect(() => {
if (!searchResults?.search?.isLoading) {
return;
}

if (validGroupBy || (shouldCalculateTotals && searchResults?.search?.count === undefined)) {
shouldRetrySearchWithTotalsOrGroupedRef.current = true;
}
}, [searchResults?.search?.isLoading, searchResults?.search?.count, shouldCalculateTotals, validGroupBy]);
// We don't need to run the effect on change of isFocused.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [handleSearch, isOffline, offset, queryJSON, currentSearchKey, shouldCalculateTotals, validGroupBy]);

useEffect(() => {
if (!shouldRetrySearchWithTotalsOrGroupedRef.current || searchResults?.search?.isLoading || (!shouldCalculateTotals && !validGroupBy)) {
Expand Down Expand Up @@ -768,7 +786,8 @@ function Search({
return;
}

// Re-arm pending expense skeleton for subsequent creations while Search stays mounted.
// Re-arm pending expense skeleton for subsequent creations while Search
// stays mounted (the original hasPendingWriteOnMountRef only covers the first).
if (hasDeferredWrite(CONST.DEFERRED_LAYOUT_WRITE_KEYS.SEARCH) && !showPendingExpensePlaceholder) {
wasRearmedRef.current = true;
rearmTracking();
Expand Down
Loading