diff --git a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx index 17e95ed4270f..e065b7393d18 100644 --- a/src/pages/iou/request/MoneyRequestAccountantSelector.tsx +++ b/src/pages/iou/request/MoneyRequestAccountantSelector.tsx @@ -2,41 +2,35 @@ import lodashPick from 'lodash/pick'; import React, {memo, useCallback, useEffect, useMemo} from 'react'; import type {GestureResponderEvent} from 'react-native'; import EmptySelectionListContent from '@components/EmptySelectionListContent'; -import {usePersonalDetails} from '@components/OnyxListItemProvider'; -import {useOptionsList} from '@components/OptionListContextProvider'; import InviteMemberListItem from '@components/SelectionList/ListItem/InviteMemberListItem'; import SelectionListWithSections from '@components/SelectionList/SelectionListWithSections'; +import type {Section} from '@components/SelectionList/SelectionListWithSections/types'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; -import usePrivateIsArchivedMap from '@hooks/usePrivateIsArchivedMap'; -import useReportAttributes from '@hooks/useReportAttributes'; +import usePersonalDetailOptions from '@hooks/usePersonalDetailOptions'; import useScreenWrapperTransitionStatus from '@hooks/useScreenWrapperTransitionStatus'; -import useUserToInviteReports from '@hooks/useUserToInviteReports'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; import memoize from '@libs/memoize'; -import { - filterAndOrderOptions, - formatSectionsFromSearchTerm, - getEmptyOptions, - getHeaderMessage, - getParticipantsOption, - getPolicyExpenseReportOption, - getValidOptions, - isCurrentUser, - orderOptions, -} from '@libs/OptionsListUtils'; -import type {SelectionListSections} from '@libs/OptionsListUtils/types'; +import {getHeaderMessage, getValidOptions} from '@libs/PersonalDetailOptionsListUtils'; +import type {OptionData} from '@libs/PersonalDetailOptionsListUtils/types'; import {searchUserInServer} from '@userActions/Report'; -import type {IOUAction, IOUType} from '@src/CONST'; +import type {IOUType} from '@src/CONST'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Accountant} from '@src/types/onyx/IOU'; const memoizedGetValidOptions = memoize(getValidOptions, {maxSize: 5, monitoringName: 'MoneyRequestAccountantSelector.getValidOptions'}); +const defaultListOptions = { + userToInvite: null, + recentOptions: [] as OptionData[], + personalDetails: [] as OptionData[], + selectedOptions: [] as OptionData[], +}; + type MoneyRequestAccountantSelectorProps = { /** Callback to request parent modal to go to next step */ onFinish: (value?: string) => void; @@ -46,196 +40,71 @@ type MoneyRequestAccountantSelectorProps = { /** The type of IOU report, i.e. split, request, send, track */ iouType: IOUType; - - /** The action of the IOU, i.e. create, split, move */ - action: IOUAction; }; -function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType, action}: MoneyRequestAccountantSelectorProps) { - const {translate} = useLocalize(); +function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType}: MoneyRequestAccountantSelectorProps) { + const {translate, formatPhoneNumber} = useLocalize(); const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(''); const {isOffline} = useNetwork(); - const personalDetails = usePersonalDetails(); const {didScreenTransitionEnd} = useScreenWrapperTransitionStatus(); const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE); - const [betas] = useOnyx(ONYXKEYS.BETAS); const [isSearchingForReports] = useOnyx(ONYXKEYS.RAM_ONLY_IS_SEARCHING_FOR_REPORTS); - const {options, areOptionsInitialized} = useOptionsList({ - shouldInitialize: didScreenTransitionEnd, - }); - const offlineMessage: string = isOffline ? `${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}` : ''; - const reportAttributesDerived = useReportAttributes(); - const [draftComments] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT); - const [nvpDismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const currentUserEmail = currentUserPersonalDetails.email ?? ''; - const currentUserAccountID = currentUserPersonalDetails.accountID; - const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); - const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID); - const privateIsArchivedMap = usePrivateIsArchivedMap(); + const {options: personalDetailOptions} = usePersonalDetailOptions({enabled: didScreenTransitionEnd}); + const areOptionsInitialized = (personalDetailOptions?.length ?? 0) > 0; + const offlineMessage: string = isOffline ? `${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}` : ''; useEffect(() => { searchUserInServer(debouncedSearchTerm.trim()); }, [debouncedSearchTerm]); - const defaultOptions = useMemo(() => { + const optionsList = useMemo(() => { if (!areOptionsInitialized || !didScreenTransitionEnd) { - getEmptyOptions(); + return defaultListOptions; } - const optionList = memoizedGetValidOptions( - { - reports: options.reports, - personalDetails: options.personalDetails, - }, - allPolicies, - draftComments, - nvpDismissedProductTraining, - loginList, - currentUserAccountID, - currentUserEmail, - conciergeReportID, - { - betas, - excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, - action, - personalDetails, - countryCode, - }, - ); - - const orderedOptions = orderOptions(optionList); - - return { - ...optionList, - ...orderedOptions, - }; - }, [ - areOptionsInitialized, - didScreenTransitionEnd, - options.reports, - options.personalDetails, - allPolicies, - draftComments, - nvpDismissedProductTraining, - loginList, - betas, - action, - countryCode, - currentUserAccountID, - currentUserEmail, - conciergeReportID, - personalDetails, - ]); - - const chatOptions = useMemo(() => { - if (!areOptionsInitialized) { - return { - userToInvite: null, - recentReports: [], - personalDetails: [], - currentUserOption: null, - headerMessage: '', - }; - } - const newOptions = filterAndOrderOptions(defaultOptions, debouncedSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, personalDetails, { + return memoizedGetValidOptions(personalDetailOptions ?? [], currentUserEmail, formatPhoneNumber, countryCode, loginList, { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, - maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, + searchString: debouncedSearchTerm, + includeUserToInvite: true, }); - return newOptions; - }, [areOptionsInitialized, defaultOptions, debouncedSearchTerm, countryCode, loginList, currentUserAccountID, currentUserEmail, personalDetails]); - - const {userToInviteExpenseReport} = useUserToInviteReports(chatOptions?.userToInvite); - const userToInviteExpenseReportPolicy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${userToInviteExpenseReport?.policyID}`]; + }, [areOptionsInitialized, didScreenTransitionEnd, personalDetailOptions, currentUserEmail, formatPhoneNumber, countryCode, loginList, debouncedSearchTerm]); - /** - * Returns the sections needed for the OptionsSelector - */ - const [sections, header] = useMemo(() => { - const newSections: SelectionListSections = []; + const sections = useMemo(() => { + const newSections: Array> = []; if (!areOptionsInitialized || !didScreenTransitionEnd) { - return [newSections, '']; + return newSections; } - const fiveRecents = [...chatOptions.recentReports].slice(0, 5); - const restOfRecents = [...chatOptions.recentReports].slice(5); - const contactsWithRestOfRecents = [...restOfRecents, ...chatOptions.personalDetails]; - - const formatResults = formatSectionsFromSearchTerm( - debouncedSearchTerm, - [], - chatOptions.recentReports, - chatOptions.personalDetails, - privateIsArchivedMap, - currentUserAccountID, - allPolicies, - personalDetails, - true, - undefined, - reportAttributesDerived, - ); - newSections.push({...formatResults.section, sectionIndex: 0}); - newSections.push({ - title: translate('common.recents'), - data: fiveRecents, - sectionIndex: 1, - }); + let sectionIndex = 0; - newSections.push({ - title: translate('common.contacts'), - data: contactsWithRestOfRecents, - sectionIndex: 2, - }); + if (optionsList.recentOptions.length > 0) { + newSections.push({ + title: translate('common.recents'), + data: optionsList.recentOptions, + sectionIndex: sectionIndex++, + }); + } - if ( - chatOptions.userToInvite && - !isCurrentUser( - {...chatOptions.userToInvite, accountID: chatOptions.userToInvite?.accountID ?? CONST.DEFAULT_NUMBER_ID, status: chatOptions.userToInvite?.status ?? undefined}, - loginList, - currentUserEmail, - ) - ) { + if (optionsList.personalDetails.length > 0) { newSections.push({ - data: [chatOptions.userToInvite].map((participant) => { - const isPolicyExpenseChat = participant?.isPolicyExpenseChat ?? false; - const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${userToInviteExpenseReport?.reportID}`]; - return isPolicyExpenseChat - ? getPolicyExpenseReportOption(participant, privateIsArchived, personalDetails, userToInviteExpenseReport, userToInviteExpenseReportPolicy, reportAttributesDerived) - : getParticipantsOption(participant, personalDetails); - }), - sectionIndex: 3, + title: translate('common.contacts'), + data: optionsList.personalDetails, + sectionIndex: sectionIndex++, }); } - const headerMessage = getHeaderMessage( - (chatOptions.personalDetails ?? []).length + (chatOptions.recentReports ?? []).length !== 0, - !!chatOptions?.userToInvite, - debouncedSearchTerm.trim(), - countryCode, - false, - ); + if (optionsList.userToInvite) { + newSections.push({ + data: [optionsList.userToInvite], + sectionIndex: sectionIndex++, + }); + } - return [newSections, headerMessage]; - }, [ - areOptionsInitialized, - didScreenTransitionEnd, - chatOptions.recentReports, - chatOptions.personalDetails, - chatOptions.userToInvite, - debouncedSearchTerm, - personalDetails, - userToInviteExpenseReport, - userToInviteExpenseReportPolicy, - reportAttributesDerived, - translate, - loginList, - countryCode, - privateIsArchivedMap, - currentUserAccountID, - currentUserEmail, - allPolicies, - ]); + return newSections; + }, [areOptionsInitialized, didScreenTransitionEnd, optionsList.recentOptions, optionsList.personalDetails, optionsList.userToInvite, translate]); const selectAccountant = useCallback( (option: Accountant) => { @@ -256,6 +125,17 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType [selectAccountant], ); + const getHeaderMessageText = () => { + if (sections.length > 0) { + return ''; + } + const searchValue = debouncedSearchTerm.trim().toLowerCase(); + if (CONST.EXPENSIFY_EMAILS_OBJECT[searchValue]) { + return translate('messages.errorMessageInvalidEmail'); + } + return getHeaderMessage(translate, debouncedSearchTerm, countryCode); + }; + const shouldShowLoadingPlaceholder = useMemo(() => !areOptionsInitialized || !didScreenTransitionEnd, [areOptionsInitialized, didScreenTransitionEnd]); const optionLength = useMemo(() => { @@ -271,7 +151,7 @@ function MoneyRequestAccountantSelector({onFinish, onAccountantSelected, iouType value: searchTerm, label: translate('selectionList.nameEmailOrPhoneNumber'), onChangeText: setSearchTerm, - headerMessage: header, + headerMessage: getHeaderMessageText(), hint: offlineMessage, }; diff --git a/src/pages/iou/request/step/IOURequestStepAccountant.tsx b/src/pages/iou/request/step/IOURequestStepAccountant.tsx index 221b52ec8f54..1156e03c35b0 100644 --- a/src/pages/iou/request/step/IOURequestStepAccountant.tsx +++ b/src/pages/iou/request/step/IOURequestStepAccountant.tsx @@ -78,7 +78,6 @@ function IOURequestStepAccountant({ onFinish={navigateToNextStep} onAccountantSelected={setAccountant} iouType={iouType} - action={action} /> );