From 069754eaa5e69a6bff296a3bb1af8fb6caa798a2 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Thu, 1 Jan 2026 00:07:02 +0100 Subject: [PATCH 1/5] chore: Add SearchForUsersParams type and integrate into API parameters --- src/libs/API/parameters/SearchForUsersParams.ts | 5 +++++ src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 2 ++ 3 files changed, 8 insertions(+) create mode 100644 src/libs/API/parameters/SearchForUsersParams.ts diff --git a/src/libs/API/parameters/SearchForUsersParams.ts b/src/libs/API/parameters/SearchForUsersParams.ts new file mode 100644 index 000000000000..aaa13b37911a --- /dev/null +++ b/src/libs/API/parameters/SearchForUsersParams.ts @@ -0,0 +1,5 @@ +type SearchForUsersParams = { + searchInput: string; +}; + +export default SearchForUsersParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index f27feccfaf62..91bccdbe9b9c 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -77,6 +77,7 @@ export type {default as ResolveActionableReportMentionWhisperParams} from './Res export type {default as RevealExpensifyCardDetailsParams} from './RevealExpensifyCardDetailsParams'; export type {default as SearchForReportsParams} from './SearchForReportsParams'; export type {default as SearchForRoomsToMentionParams} from './SearchForRoomsToMentionParams'; +export type {default as SearchForUsersParams} from './SearchForUsersParams'; export type {default as SendPerformanceTimingParams} from './SendPerformanceTimingParams'; export type {default as GraphiteParams} from './GraphiteParams'; export type {default as SetContactMethodAsDefaultParams} from './SetContactMethodAsDefaultParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 2da2814ba411..47dd003d1469 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -1106,6 +1106,7 @@ const READ_COMMANDS = { OPEN_ROOM_MEMBERS_PAGE: 'OpenRoomMembersPage', SEARCH_FOR_REPORTS: 'SearchForReports', SEARCH_FOR_ROOMS_TO_MENTION: 'SearchForRoomsToMention', + SEARCH_FOR_USERS: 'SearchForUsers', SEND_PERFORMANCE_TIMING: 'SendPerformanceTiming', GRAPHITE: 'Graphite', GET_ROUTE: 'GetRoute', @@ -1186,6 +1187,7 @@ type ReadCommandParameters = { [READ_COMMANDS.OPEN_ROOM_MEMBERS_PAGE]: Parameters.OpenRoomMembersPageParams; [READ_COMMANDS.SEARCH_FOR_REPORTS]: Parameters.SearchForReportsParams; [READ_COMMANDS.SEARCH_FOR_ROOMS_TO_MENTION]: Parameters.SearchForRoomsToMentionParams; + [READ_COMMANDS.SEARCH_FOR_USERS]: Parameters.SearchForUsersParams; [READ_COMMANDS.SEND_PERFORMANCE_TIMING]: Parameters.SendPerformanceTimingParams; [READ_COMMANDS.GRAPHITE]: Parameters.GraphiteParams; [READ_COMMANDS.GET_ROUTE]: Parameters.GetRouteParams; From a38c7badb4ab8bbdd7a459a93bc4cdec20229a8f Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Thu, 1 Jan 2026 00:24:52 +0100 Subject: [PATCH 2/5] feat: Implement searchUserInServer function and update related API calls --- .../API/parameters/SearchForUsersParams.ts | 1 + src/libs/HttpUtils.ts | 2 ++ src/libs/actions/Report.ts | 30 +++++++++++++++---- tests/actions/ReportTest.ts | 10 +++++++ 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/libs/API/parameters/SearchForUsersParams.ts b/src/libs/API/parameters/SearchForUsersParams.ts index aaa13b37911a..6259cfafd86e 100644 --- a/src/libs/API/parameters/SearchForUsersParams.ts +++ b/src/libs/API/parameters/SearchForUsersParams.ts @@ -1,5 +1,6 @@ type SearchForUsersParams = { searchInput: string; + canCancel?: boolean; }; export default SearchForUsersParams; diff --git a/src/libs/HttpUtils.ts b/src/libs/HttpUtils.ts index b36d68ddbf12..6562fbc8cd68 100644 --- a/src/libs/HttpUtils.ts +++ b/src/libs/HttpUtils.ts @@ -18,6 +18,7 @@ let shouldForceOffline = false; const ABORT_COMMANDS = { All: 'All', [READ_COMMANDS.SEARCH_FOR_REPORTS]: READ_COMMANDS.SEARCH_FOR_REPORTS, + [READ_COMMANDS.SEARCH_FOR_USERS]: READ_COMMANDS.SEARCH_FOR_USERS, } as const; type AbortCommand = keyof typeof ABORT_COMMANDS; @@ -38,6 +39,7 @@ Onyx.connectWithoutView({ const abortControllerMap = new Map(); abortControllerMap.set(ABORT_COMMANDS.All, new AbortController()); abortControllerMap.set(ABORT_COMMANDS.SearchForReports, new AbortController()); +abortControllerMap.set(ABORT_COMMANDS.SearchForUsers, new AbortController()); /** * The API commands that require the skew calculation diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index baa920755cbd..d1c11ecf824c 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -43,6 +43,7 @@ import type { ResolveActionableReportMentionWhisperParams, SearchForReportsParams, SearchForRoomsToMentionParams, + SearchForUsersParams, TogglePinnedChatParams, TransactionThreadInfo, UpdateChatNameParams, @@ -4456,7 +4457,7 @@ function savePrivateNotesDraft(reportID: string, note: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.PRIVATE_NOTES_DRAFT}${reportID}`, note); } -function searchForReports(searchInput: string, policyID?: string) { +function searchForReports(searchInput: string, policyID?: string, isUserSearch = false) { // We do not try to make this request while offline because it sets a loading indicator optimistically if (isNetworkOffline) { Onyx.set(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, false); @@ -4480,14 +4481,20 @@ function searchForReports(searchInput: string, policyID?: string) { ]; const searchForRoomToMentionParams: SearchForRoomsToMentionParams = {query: searchInput.toLowerCase(), policyID}; - const searchForReportsParams: SearchForReportsParams = {searchInput: searchInput.toLowerCase(), canCancel: true}; + const searchForReportsOrUsersParams: SearchForReportsParams | SearchForUsersParams = {searchInput: searchInput.toLowerCase(), canCancel: true}; // We want to cancel all pending SearchForReports API calls before making another one if (!policyID) { - HttpUtils.cancelPendingRequests(READ_COMMANDS.SEARCH_FOR_REPORTS); - } + if (isUserSearch) { + HttpUtils.cancelPendingRequests(READ_COMMANDS.SEARCH_FOR_USERS); + } else { + HttpUtils.cancelPendingRequests(READ_COMMANDS.SEARCH_FOR_REPORTS); + } + } + + const searchForReportsOrUsersCommand = isUserSearch ? READ_COMMANDS.SEARCH_FOR_USERS : READ_COMMANDS.SEARCH_FOR_REPORTS; - API.read(policyID ? READ_COMMANDS.SEARCH_FOR_ROOMS_TO_MENTION : READ_COMMANDS.SEARCH_FOR_REPORTS, policyID ? searchForRoomToMentionParams : searchForReportsParams, { + API.read(policyID ? READ_COMMANDS.SEARCH_FOR_ROOMS_TO_MENTION : searchForReportsOrUsersCommand, policyID ? searchForRoomToMentionParams : searchForReportsOrUsersParams, { successData, failureData, }); @@ -4506,6 +4513,18 @@ function searchInServer(searchInput: string, policyID?: string) { searchForReports(searchInput, policyID); } +function searchUserInServer(searchInput: string) { + if (isNetworkOffline || !searchInput.trim().length) { + Onyx.set(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, false); + return; + } + + // Why not set this in optimistic data? It won't run until the API request happens and while the API request is debounced + // we want to show the loading state right away. Otherwise, we will see a flashing UI where the client options are sorted and + // tell the user there are no options, then we start searching, and tell them there are no options again. + Onyx.set(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, true); + searchForReports(searchInput, undefined, true); +} function updateLastVisitTime(reportID: string) { if (!isValidReportIDFromPath(reportID)) { return; @@ -6320,6 +6339,7 @@ export { saveReportActionDraft, saveReportDraftComment, searchInServer, + searchUserInServer, setDeleteTransactionNavigateBackUrl, setGroupDraft, setIsComposerFullSize, diff --git a/tests/actions/ReportTest.ts b/tests/actions/ReportTest.ts index 2e8f0aae252f..72c4bc3936e3 100644 --- a/tests/actions/ReportTest.ts +++ b/tests/actions/ReportTest.ts @@ -2565,6 +2565,16 @@ describe('actions/Report', () => { }); }); + describe('searchUserInServer', () => { + it('should return the same result with or without uppercase input.', () => { + Report.searchUserInServer('test'); + Report.searchUserInServer('TEST'); + const upperCaseRequest = PersistedRequests.getAll().at(0); + const lowerCaseRequest = PersistedRequests.getAll().at(1); + expect(upperCaseRequest?.data?.searchInput).toBe(lowerCaseRequest?.data?.searchInput); + }); + }); + it('should not overwrite testDriveModalDismissed when it is already true', async () => { const TEST_USER_ACCOUNT_ID = 1; const TEST_USER_LOGIN = 'test@test.com'; From 82e0633789aaebf868239af9b600baee4fbdd7e1 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Thu, 1 Jan 2026 00:32:52 +0100 Subject: [PATCH 3/5] feat: Replace searchInServer with searchUserInServer across multiple components --- src/pages/InviteReportParticipantsPage.tsx | 4 ++-- .../BaseOnboardingWorkspaceInvite.tsx | 4 ++-- src/pages/RoomInvitePage.tsx | 4 ++-- src/pages/iou/request/MoneyRequestAccountantSelector.tsx | 4 ++-- src/pages/iou/request/MoneyRequestAttendeeSelector.tsx | 4 ++-- src/pages/iou/request/MoneyRequestParticipantsSelector.tsx | 4 ++-- src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx | 4 ++-- src/pages/tasks/TaskAssigneeSelectorModal.tsx | 4 ++-- src/pages/workspace/WorkspaceInvitePage.tsx | 4 ++-- src/pages/workspace/companyCards/assignCard/AssigneeStep.tsx | 4 ++-- src/pages/workspace/expensifyCard/issueNew/AssigneeStep.tsx | 4 ++-- 11 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/pages/InviteReportParticipantsPage.tsx b/src/pages/InviteReportParticipantsPage.tsx index c52e91aeae14..e08bc41bc091 100644 --- a/src/pages/InviteReportParticipantsPage.tsx +++ b/src/pages/InviteReportParticipantsPage.tsx @@ -13,7 +13,7 @@ import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useSearchSelector from '@hooks/useSearchSelector'; import useThemeStyles from '@hooks/useThemeStyles'; -import {inviteToGroupChat, searchInServer} from '@libs/actions/Report'; +import {inviteToGroupChat, searchUserInServer} from '@libs/actions/Report'; import {clearUserSearchPhrase, updateUserSearchPhrase} from '@libs/actions/RoomMembersUserSearchPhrase'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; import {appendCountryCode} from '@libs/LoginUtils'; @@ -69,7 +69,7 @@ function InviteReportParticipantsPage({report}: InviteReportParticipantsPageProp useEffect(() => { updateUserSearchPhrase(searchTerm); - searchInServer(searchTerm); + searchUserInServer(searchTerm); }, [searchTerm]); const sections = useMemo(() => { diff --git a/src/pages/OnboardingWorkspaceInvite/BaseOnboardingWorkspaceInvite.tsx b/src/pages/OnboardingWorkspaceInvite/BaseOnboardingWorkspaceInvite.tsx index c2bd2080561b..14ca8efb0004 100644 --- a/src/pages/OnboardingWorkspaceInvite/BaseOnboardingWorkspaceInvite.tsx +++ b/src/pages/OnboardingWorkspaceInvite/BaseOnboardingWorkspaceInvite.tsx @@ -19,7 +19,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useSearchSelector from '@hooks/useSearchSelector'; import useThemeStyles from '@hooks/useThemeStyles'; import {addMembersToWorkspace} from '@libs/actions/Policy/Member'; -import {searchInServer} from '@libs/actions/Report'; +import {searchUserInServer} from '@libs/actions/Report'; import {READ_COMMANDS} from '@libs/API/types'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; import HttpUtils from '@libs/HttpUtils'; @@ -84,7 +84,7 @@ function BaseOnboardingWorkspaceInvite({shouldUseNativeStyles}: BaseOnboardingWo const welcomeNote = useMemo(() => translate('workspace.common.welcomeNote'), [translate]); useEffect(() => { - searchInServer(searchTerm); + searchUserInServer(searchTerm); }, [searchTerm]); const sections: Sections[] = useMemo(() => { diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index 34a35aef7fd6..74f0fc3a5ce3 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -19,7 +19,7 @@ import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReportIsArchived from '@hooks/useReportIsArchived'; import useThemeStyles from '@hooks/useThemeStyles'; -import {inviteToRoomAction, searchInServer} from '@libs/actions/Report'; +import {inviteToRoomAction, searchUserInServer} from '@libs/actions/Report'; import {clearUserSearchPhrase, updateUserSearchPhrase} from '@libs/actions/RoomMembersUserSearchPhrase'; import {READ_COMMANDS} from '@libs/API/types'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; @@ -247,7 +247,7 @@ function RoomInvitePage({ useEffect(() => { updateUserSearchPhrase(debouncedSearchTerm); - searchInServer(debouncedSearchTerm); + searchUserInServer(debouncedSearchTerm); }, [debouncedSearchTerm]); let subtitleKey: '' | TranslationPaths | undefined; diff --git a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx index f8ed6db7d243..b91acdf82c6c 100644 --- a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx @@ -26,7 +26,7 @@ import { isCurrentUser, orderOptions, } from '@libs/OptionsListUtils'; -import {searchInServer} from '@userActions/Report'; +import {searchUserInServer} from '@userActions/Report'; import type {IOUAction, IOUType} from '@src/CONST'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -66,7 +66,7 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType const [nvpDismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true}); useEffect(() => { - searchInServer(debouncedSearchTerm.trim()); + searchUserInServer(debouncedSearchTerm.trim()); }, [debouncedSearchTerm]); const defaultOptions = useMemo(() => { diff --git a/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx b/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx index e74f62ccad17..30ebaf8fc52d 100644 --- a/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAttendeeSelector.tsx @@ -16,7 +16,7 @@ import usePolicy from '@hooks/usePolicy'; import useScreenWrapperTransitionStatus from '@hooks/useScreenWrapperTransitionStatus'; import useSearchSelector from '@hooks/useSearchSelector'; import useThemeStyles from '@hooks/useThemeStyles'; -import {searchInServer} from '@libs/actions/Report'; +import {searchUserInServer} from '@libs/actions/Report'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; import { formatSectionsFromSearchTerm, @@ -119,7 +119,7 @@ function MoneyRequestAttendeeSelector({attendees = [], onFinish, onAttendeesAdde }); useEffect(() => { - searchInServer(debouncedSearchTerm.trim()); + searchUserInServer(debouncedSearchTerm.trim()); }, [debouncedSearchTerm]); const orderedAvailableOptions = useMemo(() => { diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index 99e3beb101d9..4e95760c6bd8 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -40,7 +40,7 @@ import type {OptionData} from '@libs/ReportUtils'; import {isInvoiceRoom} from '@libs/ReportUtils'; import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; import {getInvoicePrimaryWorkspace} from '@userActions/Policy/Policy'; -import {searchInServer} from '@userActions/Report'; +import {searchUserInServer} from '@userActions/Report'; import type {IOUAction, IOUType} from '@src/CONST'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -237,7 +237,7 @@ function MoneyRequestParticipantsSelector({ const cleanSearchTerm = useMemo(() => searchTerm.trim().toLowerCase(), [searchTerm]); useEffect(() => { - searchInServer(searchTerm.trim()); + searchUserInServer(searchTerm.trim()); }, [searchTerm]); const inputHelperText = useMemo( diff --git a/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx b/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx index 6bac4a726280..56bdadfd7812 100644 --- a/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx +++ b/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx @@ -9,7 +9,7 @@ import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useSearchSelector from '@hooks/useSearchSelector'; import useThemeStyles from '@hooks/useThemeStyles'; -import {searchInServer} from '@libs/actions/Report'; +import {searchUserInServer} from '@libs/actions/Report'; import Navigation from '@libs/Navigation/Navigation'; import {getHeaderMessage} from '@libs/OptionsListUtils'; import CONST from '@src/CONST'; @@ -94,7 +94,7 @@ function AddDelegatePage() { }, [availableOptions.recentReports, availableOptions.personalDetails, availableOptions.userToInvite, translate]); useEffect(() => { - searchInServer(debouncedSearchTerm); + searchUserInServer(debouncedSearchTerm); }, [debouncedSearchTerm]); return ( diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.tsx b/src/pages/tasks/TaskAssigneeSelectorModal.tsx index 5cc16ed768b2..945890ea6904 100644 --- a/src/pages/tasks/TaskAssigneeSelectorModal.tsx +++ b/src/pages/tasks/TaskAssigneeSelectorModal.tsx @@ -19,7 +19,7 @@ import useOnyx from '@hooks/useOnyx'; import useReportIsArchived from '@hooks/useReportIsArchived'; import useSearchSelector from '@hooks/useSearchSelector'; import useThemeStyles from '@hooks/useThemeStyles'; -import {searchInServer} from '@libs/actions/Report'; +import {searchUserInServer} from '@libs/actions/Report'; import {canModifyTask, editTaskAssignee, setAssigneeValue} from '@libs/actions/Task'; import {READ_COMMANDS} from '@libs/API/types'; import HttpUtils from '@libs/HttpUtils'; @@ -213,7 +213,7 @@ function TaskAssigneeSelectorModal() { const isTaskNonEditable = isTaskReport(report) && (!isTaskModifiable || !isOpen); useEffect(() => { - searchInServer(debouncedSearchTerm); + searchUserInServer(debouncedSearchTerm); }, [debouncedSearchTerm]); return ( diff --git a/src/pages/workspace/WorkspaceInvitePage.tsx b/src/pages/workspace/WorkspaceInvitePage.tsx index 9bd325534bd0..2892a253ef93 100644 --- a/src/pages/workspace/WorkspaceInvitePage.tsx +++ b/src/pages/workspace/WorkspaceInvitePage.tsx @@ -15,7 +15,7 @@ import useSearchSelector from '@hooks/useSearchSelector'; import useThemeStyles from '@hooks/useThemeStyles'; import {setWorkspaceInviteMembersDraft} from '@libs/actions/Policy/Member'; import {clearErrors, openWorkspaceInvitePage as policyOpenWorkspaceInvitePage, setWorkspaceErrors} from '@libs/actions/Policy/Policy'; -import {searchInServer} from '@libs/actions/Report'; +import {searchUserInServer} from '@libs/actions/Report'; import {READ_COMMANDS} from '@libs/API/types'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; import HttpUtils from '@libs/HttpUtils'; @@ -218,7 +218,7 @@ function WorkspaceInvitePage({route, policy}: WorkspaceInvitePageProps) { ); useEffect(() => { - searchInServer(searchTerm); + searchUserInServer(searchTerm); }, [searchTerm]); return ( diff --git a/src/pages/workspace/companyCards/assignCard/AssigneeStep.tsx b/src/pages/workspace/companyCards/assignCard/AssigneeStep.tsx index b435955b4877..d52381ac86cd 100644 --- a/src/pages/workspace/companyCards/assignCard/AssigneeStep.tsx +++ b/src/pages/workspace/companyCards/assignCard/AssigneeStep.tsx @@ -16,7 +16,7 @@ import useOnyx from '@hooks/useOnyx'; import useSearchSelector from '@hooks/useSearchSelector'; import useThemeStyles from '@hooks/useThemeStyles'; import {setDraftInviteAccountID} from '@libs/actions/Card'; -import {searchInServer} from '@libs/actions/Report'; +import {searchUserInServer} from '@libs/actions/Report'; import {getDefaultCardName, getFilteredCardList, hasOnlyOneCardToAssign} from '@libs/CardUtils'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; @@ -204,7 +204,7 @@ function AssigneeStep({policy, feed, route}: AssigneeStepProps) { ]); useEffect(() => { - searchInServer(searchTerm); + searchUserInServer(searchTerm); }, [searchTerm]); const headerMessage = useMemo(() => { diff --git a/src/pages/workspace/expensifyCard/issueNew/AssigneeStep.tsx b/src/pages/workspace/expensifyCard/issueNew/AssigneeStep.tsx index 2156dd12fa56..dfcb2c14d939 100644 --- a/src/pages/workspace/expensifyCard/issueNew/AssigneeStep.tsx +++ b/src/pages/workspace/expensifyCard/issueNew/AssigneeStep.tsx @@ -12,7 +12,7 @@ import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; import useSearchSelector from '@hooks/useSearchSelector'; import useThemeStyles from '@hooks/useThemeStyles'; -import {searchInServer} from '@libs/actions/Report'; +import {searchUserInServer} from '@libs/actions/Report'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; import {getHeaderMessage, getSearchValueForPhoneOrEmail, sortAlphabetically} from '@libs/OptionsListUtils'; @@ -187,7 +187,7 @@ function AssigneeStep({policy, stepNames, startStepIndex, route}: AssigneeStepPr ]); useEffect(() => { - searchInServer(searchTerm); + searchUserInServer(searchTerm); }, [searchTerm]); const headerMessage = useMemo(() => { From 623ef4fbf3b12eeac14be74e7d8d77873114e84d Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Thu, 1 Jan 2026 00:52:07 +0100 Subject: [PATCH 4/5] feat: Refactor search functions to unify server search logic and improve parameter handling --- src/libs/actions/Report.ts | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 85a3cdd1fad1..b3b49c15b02f 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -4526,7 +4526,7 @@ function searchForReports(isOffline: boolean, searchInput: string, policyID?: st }); } -function searchInServer(searchInput: string, policyID?: string) { +function performServerSearch(searchInput: string, policyID?: string, isUserSearch = false) { // We are not getting isOffline from components as useEffect change will re-trigger the search on network change const isOffline = NetworkStore.isOffline(); if (isOffline || !searchInput.trim().length) { @@ -4538,21 +4538,17 @@ function searchInServer(searchInput: string, policyID?: string) { // we want to show the loading state right away. Otherwise, we will see a flashing UI where the client options are sorted and // tell the user there are no options, then we start searching, and tell them there are no options again. Onyx.set(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, true); - searchForReports(isOffline, searchInput, policyID); + searchForReports(isOffline, searchInput, policyID, isUserSearch); } -function searchUserInServer(searchInput: string) { - if (isNetworkOffline || !searchInput.trim().length) { - Onyx.set(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, false); - return; - } +function searchInServer(searchInput: string, policyID?: string) { + performServerSearch(searchInput, policyID); +} - // Why not set this in optimistic data? It won't run until the API request happens and while the API request is debounced - // we want to show the loading state right away. Otherwise, we will see a flashing UI where the client options are sorted and - // tell the user there are no options, then we start searching, and tell them there are no options again. - Onyx.set(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, true); - searchForReports(searchInput, undefined, true); +function searchUserInServer(searchInput: string) { + performServerSearch(searchInput, undefined, true); } + function updateLastVisitTime(reportID: string) { if (!isValidReportIDFromPath(reportID)) { return; From e1354e27c22921e88db5c138ec5c18be5e27ff58 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Thu, 1 Jan 2026 00:57:19 +0100 Subject: [PATCH 5/5] fix: Style formatting --- src/libs/actions/Report.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index b3b49c15b02f..094f38e87e0c 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -4516,7 +4516,7 @@ function searchForReports(isOffline: boolean, searchInput: string, policyID?: st } else { HttpUtils.cancelPendingRequests(READ_COMMANDS.SEARCH_FOR_REPORTS); } - } + } const searchForReportsOrUsersCommand = isUserSearch ? READ_COMMANDS.SEARCH_FOR_USERS : READ_COMMANDS.SEARCH_FOR_REPORTS;