Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
dd90569
revert change back to calling handle scroll on ref
FitseTLT Jun 12, 2025
ed708c4
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Jun 13, 2025
7727465
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Jun 17, 2025
d5f8689
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Jun 20, 2025
c8d3323
added data as a dependency
FitseTLT Jun 20, 2025
88f1666
gave a bit delay to scroll to last item
FitseTLT Jun 20, 2025
70b80dd
increase delay
FitseTLT Jun 20, 2025
04e1b92
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Jun 25, 2025
cbdebc3
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Jun 30, 2025
ea15c3d
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Jul 1, 2025
54d1709
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Jul 2, 2025
bacb913
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Jul 2, 2025
d8cfb93
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Jul 16, 2025
13bf564
minor fixes
FitseTLT Jul 16, 2025
601fc12
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Jul 31, 2025
fefadee
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Aug 26, 2025
2e72ccd
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Aug 27, 2025
162eeaf
fix hasNewItemsRef resetting logic
FitseTLT Aug 27, 2025
981a4a6
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Aug 29, 2025
55d168e
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Sep 3, 2025
d1bc826
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Sep 3, 2025
f2c9625
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Sep 4, 2025
7a39e46
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Sep 5, 2025
23bd44b
fix scrollToIndex viewOffset
FitseTLT Sep 5, 2025
b16dd53
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Sep 5, 2025
f6a223b
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Sep 12, 2025
ee40b97
minor update
FitseTLT Sep 12, 2025
0f3cf03
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Sep 12, 2025
3f72dfc
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Sep 16, 2025
5c596dd
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Sep 24, 2025
41c3a89
fix bug of old items being highlighted
FitseTLT Sep 24, 2025
f296398
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Sep 26, 2025
8996805
Merge branch 'main' into fix-scroll-to-new-item-search
FitseTLT Oct 10, 2025
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
3 changes: 1 addition & 2 deletions src/components/Search/SearchList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
import useThemeStyles from '@hooks/useThemeStyles';
import {turnOnMobileSelectionMode} from '@libs/actions/MobileSelectionMode';
import navigationRef from '@libs/Navigation/navigationRef';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Transaction, TransactionViolations} from '@src/types/onyx';
Expand Down Expand Up @@ -268,7 +267,7 @@ function SearchList({
return;
}

listRef.current.scrollToIndex({index, animated, viewOffset: variables.contentHeaderHeight});
listRef.current.scrollToIndex({index, animated, viewPosition: 0});
},
[data],
);
Expand Down
16 changes: 11 additions & 5 deletions src/components/Search/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {findFocusedRoute, useFocusEffect, useIsFocused, useNavigation} from '@react-navigation/native';
import {accountIDSelector} from '@selectors/Session';
import React, {useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';
import React, {useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState} from 'react';
import type {NativeScrollEvent, NativeSyntheticEvent, StyleProp, ViewStyle} from 'react-native';
import {View} from 'react-native';
import Animated, {FadeIn, FadeOut, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
Expand Down Expand Up @@ -288,7 +288,6 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS
[reportActions],
);
const {translate, localeCompare, formatPhoneNumber} = useLocalize();
const searchListRef = useRef<SelectionListHandle | null>(null);

const clearTransactionsAndSetHashAndKey = useCallback(() => {
clearSelectedTransactions(hash);
Expand Down Expand Up @@ -732,6 +731,16 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS
[type, status, data, sortBy, sortOrder, groupBy, isChat, newSearchResultKey, selectedTransactions, canSelectMultiple, localeCompare, hash],
);

const searchListRef = useRef<SelectionListHandle | null>(null);

useLayoutEffect(() => {
handleSelectionListScroll(sortedSelectedData, searchListRef.current);

// We only need to run the effect on change of newSearchResultKey to scroll to the new item.
// eslint-disable-next-line react-compiler/react-compiler
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [newSearchResultKey]);

const hasErrors = Object.keys(searchResults?.errors ?? {}).length > 0 && !isOffline;

useEffect(() => {
Expand Down Expand Up @@ -790,8 +799,6 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS
);
}, [clearSelectedTransactions, data, groupBy, reportActionsArray, selectedTransactions, setSelectedTransactions, outstandingReportsByPolicyID]);

const onLayout = useCallback(() => handleSelectionListScroll(sortedSelectedData, searchListRef.current), [handleSelectionListScroll, sortedSelectedData]);

const areAllOptionalColumnsHidden = useMemo(() => {
const canBeMissingColumns = expenseHeaders.filter((header) => header.canBeMissing).map((header) => header.columnName);
return canBeMissingColumns.every((column) => !columnsToShow.includes(column));
Expand Down Expand Up @@ -905,7 +912,6 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS
columns={columnsToShow}
areAllOptionalColumnsHidden={areAllOptionalColumnsHidden}
violations={violations}
onLayout={onLayout}
isMobileSelectionModeEnabled={isMobileSelectionModeEnabled}
shouldAnimate={type === CONST.SEARCH.DATA_TYPES.EXPENSE}
newTransactions={newTransactions}
Expand Down
18 changes: 12 additions & 6 deletions src/hooks/useSearchHighlightAndScroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ function useSearchHighlightAndScroll({
// Ref to track if the search was triggered by this hook
const triggeredByHookRef = useRef(false);
const searchTriggeredRef = useRef(false);
const hasNewItemsRef = useRef(false);
const newTransactionIDsRef = useRef<string[]>([]);
const previousSearchResults = usePrevious(searchResults?.data);
const [newSearchResultKey, setNewSearchResultKey] = useState<string | null>(null);
const highlightedIDs = useRef<Set<string>>(new Set());
Expand Down Expand Up @@ -126,7 +126,9 @@ function useSearchHighlightAndScroll({
// We only want to highlight new items if the addition of transactions or report actions triggered the search.
// This is because, on deletion of items, the backend sometimes returns old items in place of the deleted ones.
// We don't want to highlight these old items, even if they appear new in the current search results.
hasNewItemsRef.current = isChat ? reportActionsIDs.length > previousReportActionsIDs.length : transactionsIDs.length > previousTransactionsIDs.length;
if (!isChat && hasTransactionsIDsChange) {
newTransactionIDsRef.current.push(...transactionsIDs.filter((id) => !previousTransactionsIDs.includes(id)).map((id) => id.replace(ONYXKEYS.COLLECTION.TRANSACTION, '')));
}

// Set the flag indicating the search is triggered by the hook
triggeredByHookRef.current = true;
Expand Down Expand Up @@ -178,7 +180,7 @@ function useSearchHighlightAndScroll({
// Find new report action IDs that are not in the previousReportActionIDs and not already highlighted
const newReportActionIDs = currentReportActionIDs.filter((id) => !previousReportActionIDs.includes(id) && !highlightedIDs.current.has(id));

if (!triggeredByHookRef.current || newReportActionIDs.length === 0 || !hasNewItemsRef.current) {
if (!triggeredByHookRef.current || newReportActionIDs.length === 0) {
return;
}

Expand All @@ -192,12 +194,16 @@ function useSearchHighlightAndScroll({
const currentTransactionIDs = extractTransactionIDsFromSearchResults(searchResults.data);

// Find new transaction IDs that are not in the previousTransactionIDs and not already highlighted
const newTransactionIDs = currentTransactionIDs.filter((id) => !previousTransactionIDs.includes(id) && !highlightedIDs.current.has(id));
const newTransactionIDs = currentTransactionIDs.filter(
(id) => !previousTransactionIDs.includes(id) && !highlightedIDs.current.has(id) && newTransactionIDsRef.current.includes(id),
);

if (!triggeredByHookRef.current || newTransactionIDs.length === 0 || !hasNewItemsRef.current) {
if (!triggeredByHookRef.current || newTransactionIDs.length === 0) {
return;
}

// As the new transactions are going to be highlighted below, which would make them obsolete, we will remove them from newTransactionIDsRef.
newTransactionIDsRef.current = newTransactionIDsRef.current.filter((id) => !newTransactionIDs.includes(id));
const newTransactionID = newTransactionIDs.at(0) ?? '';
const newTransactionKey = `${ONYXKEYS.COLLECTION.TRANSACTION}${newTransactionID}`;

Expand Down Expand Up @@ -255,7 +261,7 @@ function useSearchHighlightAndScroll({
});

// Early return if the new item is not found in the data array
if (indexOfNewItem <= 0) {
if (indexOfNewItem < 0) {
return;
}

Expand Down
Loading