Skip to content
Open
Show file tree
Hide file tree
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
191 changes: 80 additions & 111 deletions src/components/Search/SearchFiltersChatsSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import reportsSelector from '@selectors/Attributes';
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import React, {useEffect, useState} from 'react';
import {usePersonalDetails} from '@components/OnyxListItemProvider';
import {useOptionsList} from '@components/OptionListContextProvider';
// eslint-disable-next-line no-restricted-imports
import SelectionList from '@components/SelectionListWithSections';
import InviteMemberListItem from '@components/SelectionListWithSections/InviteMemberListItem';
import InviteMemberListItem from '@components/SelectionList/ListItem/InviteMemberListItem';
import SelectionListWithSections from '@components/SelectionList/SelectionListWithSections';
import useArchivedReportsIdSet from '@hooks/useArchivedReportsIdSet';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useDebouncedState from '@hooks/useDebouncedState';
Expand All @@ -13,7 +12,8 @@ import useOnyx from '@hooks/useOnyx';
import useScreenWrapperTransitionStatus from '@hooks/useScreenWrapperTransitionStatus';
import {canUseTouchScreen} from '@libs/DeviceCapabilities';
import {createOptionFromReport, filterAndOrderOptions, formatSectionsFromSearchTerm, getAlternateText, getSearchOptions} from '@libs/OptionsListUtils';
import type {Option, Section} from '@libs/OptionsListUtils';
import type {Option} from '@libs/OptionsListUtils';
import type {OptionWithKey, SelectionListSections} from '@libs/OptionsListUtils/types';
import type {OptionData} from '@libs/ReportUtils';
import Navigation from '@navigation/Navigation';
import {searchInServer} from '@userActions/Report';
Expand Down Expand Up @@ -59,53 +59,44 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen
const [reportAttributesDerived] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {canBeMissing: true, selector: reportsSelector});
const [selectedReportIDs, setSelectedReportIDs] = useState<string[]>(initialReportIDs);
const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState('');
const cleanSearchTerm = useMemo(() => searchTerm.trim().toLowerCase(), [searchTerm]);
const cleanSearchTerm = searchTerm.trim().toLowerCase();
const [draftComments] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true});
const archivedReportsIdSet = useArchivedReportsIdSet();
const [nvpDismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true});

const selectedOptions = useMemo<OptionData[]>(() => {
return selectedReportIDs.map((id) => {
const report = getSelectedOptionData(
createOptionFromReport({...reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`], reportID: id}, personalDetails, currentUserAccountID, reportAttributesDerived),
);
const isReportArchived = archivedReportsIdSet.has(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report.reportID}`);
const alternateText = getAlternateText(report, {}, isReportArchived, currentUserAccountID, {});
return {...report, alternateText};
});
}, [archivedReportsIdSet, personalDetails, reportAttributesDerived, reports, selectedReportIDs, currentUserAccountID]);

const defaultOptions = useMemo(() => {
if (!areOptionsInitialized || !isScreenTransitionEnd) {
return defaultListOptions;
}
return getSearchOptions({
options,
draftComments,
nvpDismissedProductTraining,
betas: undefined,
isUsedInChatFinder: false,
countryCode,
loginList,
currentUserAccountID,
currentUserEmail,
personalDetails,
});
}, [areOptionsInitialized, isScreenTransitionEnd, options, draftComments, nvpDismissedProductTraining, countryCode, loginList, currentUserAccountID, currentUserEmail, personalDetails]);
const selectedOptions: OptionData[] = selectedReportIDs.map((id) => {
const report = getSelectedOptionData(
createOptionFromReport({...reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`], reportID: id}, personalDetails, currentUserAccountID, reportAttributesDerived),
);
const isReportArchived = archivedReportsIdSet.has(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report.reportID}`);
const alternateText = getAlternateText(report, {}, isReportArchived, currentUserAccountID, {});
return {...report, alternateText};
});

const chatOptions = useMemo(() => {
return filterAndOrderOptions(defaultOptions, cleanSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, personalDetails, {
selectedOptions,
excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT,
});
}, [defaultOptions, cleanSearchTerm, countryCode, loginList, selectedOptions, currentUserAccountID, currentUserEmail, personalDetails]);
const defaultOptions =
!areOptionsInitialized || !isScreenTransitionEnd
? defaultListOptions
: getSearchOptions({
options,
draftComments,
nvpDismissedProductTraining,
betas: undefined,
isUsedInChatFinder: false,
countryCode,
loginList,
currentUserAccountID,
currentUserEmail,
personalDetails,
});

const chatOptions = filterAndOrderOptions(defaultOptions, cleanSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, personalDetails, {
selectedOptions,
excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT,
});

const {sections, headerMessage} = useMemo(() => {
const newSections: Section[] = [];
if (!areOptionsInitialized) {
return {sections: [], headerMessage: undefined};
}
const sections: SelectionListSections = [];

if (areOptionsInitialized) {
const formattedResults = formatSectionsFromSearchTerm(
cleanSearchTerm,
selectedOptions,
Expand All @@ -118,102 +109,80 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen
reportAttributesDerived,
);

newSections.push(formattedResults.section);
sections.push(formattedResults.section);

const visibleReportsWhenSearchTermNonEmpty = chatOptions.recentReports.map((report) => (selectedReportIDs.includes(report.reportID) ? getSelectedOptionData(report) : report));
const visibleReportsWhenSearchTermEmpty = chatOptions.recentReports.filter((report) => !selectedReportIDs.includes(report.reportID));
const reportsFiltered = cleanSearchTerm === '' ? visibleReportsWhenSearchTermEmpty : visibleReportsWhenSearchTermNonEmpty;

newSections.push({
sections.push({
title: undefined,
data: reportsFiltered,
shouldShow: chatOptions.recentReports.length > 0,
sectionIndex: 1,
});

const areResultsFound = didScreenTransitionEnd && formattedResults.section.data.length === 0 && reportsFiltered.length === 0;
const message = areResultsFound ? translate('common.noResultsFound') : undefined;

return {
sections: newSections,
headerMessage: message,
};
}, [
areOptionsInitialized,
chatOptions.personalDetails,
chatOptions.recentReports,
cleanSearchTerm,
didScreenTransitionEnd,
personalDetails,
reportAttributesDerived,
selectedOptions,
selectedReportIDs,
translate,
currentUserAccountID,
]);
}
const noResultsFound = didScreenTransitionEnd && sections.at(0)?.data.length === 0 && sections.at(1)?.data.length === 0;
const headerMessage = noResultsFound ? translate('common.noResultsFound') : undefined;

useEffect(() => {
searchInServer(debouncedSearchTerm.trim());
}, [debouncedSearchTerm]);

const handleParticipantSelection = useCallback(
(selectedOption: Option) => {
const optionReportID = selectedOption.reportID;
if (!optionReportID) {
return;
}
const foundOptionIndex = selectedReportIDs.findIndex((reportID: string) => {
return reportID && reportID !== '' && selectedOption.reportID === reportID;
});

if (foundOptionIndex < 0) {
setSelectedReportIDs([...selectedReportIDs, optionReportID]);
} else {
const newSelectedReports = [...selectedReportIDs.slice(0, foundOptionIndex), ...selectedReportIDs.slice(foundOptionIndex + 1)];
setSelectedReportIDs(newSelectedReports);
}
},
[selectedReportIDs],
);
const handleParticipantSelection = (selectedOption: OptionWithKey) => {
const optionReportID = selectedOption.reportID;
if (!optionReportID) {
return;
}
const foundOptionIndex = selectedReportIDs.findIndex((reportID: string) => {
return reportID && reportID !== '' && selectedOption.reportID === reportID;
});

const applyChanges = useCallback(() => {
if (foundOptionIndex < 0) {
setSelectedReportIDs([...selectedReportIDs, optionReportID]);
} else {
const newSelectedReports = [...selectedReportIDs.slice(0, foundOptionIndex), ...selectedReportIDs.slice(foundOptionIndex + 1)];
setSelectedReportIDs(newSelectedReports);
}
};

const applyChanges = () => {
onFiltersUpdate(selectedReportIDs);
Navigation.goBack(ROUTES.SEARCH_ADVANCED_FILTERS.getRoute());
}, [onFiltersUpdate, selectedReportIDs]);
};

const resetChanges = useCallback(() => {
const resetChanges = () => {
setSelectedReportIDs([]);
}, []);

const footerContent = useMemo(
() => (
<SearchFilterPageFooterButtons
applyChanges={applyChanges}
resetChanges={resetChanges}
/>
),
[resetChanges, applyChanges],
};

const footerContent = (
<SearchFilterPageFooterButtons
applyChanges={applyChanges}
resetChanges={resetChanges}
/>
);

const isLoadingNewOptions = !!isSearchingForReports;
const showLoadingPlaceholder = !didScreenTransitionEnd || !areOptionsInitialized || !initialReportIDs || !personalDetails;

const textInputOptions = {
value: searchTerm,
label: translate('selectionList.nameEmailOrPhoneNumber'),
onChangeText: setSearchTerm,
headerMessage,
};

return (
<SelectionList
canSelectMultiple
<SelectionListWithSections
sections={sections}
onSelectRow={handleParticipantSelection}
ListItem={InviteMemberListItem}
textInputLabel={translate('selectionList.nameEmailOrPhoneNumber')}
headerMessage={headerMessage}
textInputValue={searchTerm}
footerContent={footerContent}
showScrollIndicator
canSelectMultiple
shouldPreventDefaultFocusOnSelectRow={!canUseTouchScreen()}
onChangeText={(value) => {
setSearchTerm(value);
}}
onSelectRow={handleParticipantSelection}
textInputOptions={textInputOptions}
isLoadingNewOptions={isLoadingNewOptions}
showLoadingPlaceholder={showLoadingPlaceholder}
shouldShowTextInput
/>
);
}
Expand Down
39 changes: 22 additions & 17 deletions src/components/Search/SearchFiltersParticipantsSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ import reportsSelector from '@selectors/Attributes';
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {usePersonalDetails} from '@components/OnyxListItemProvider';
import {useOptionsList} from '@components/OptionListContextProvider';
// eslint-disable-next-line no-restricted-imports
import SelectionList from '@components/SelectionListWithSections';
import UserSelectionListItem from '@components/SelectionListWithSections/Search/UserSelectionListItem';
import UserSelectionListItem from '@components/SelectionList/ListItem/UserSelectionListItem';
import SelectionListWithSections from '@components/SelectionList/SelectionListWithSections';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import useScreenWrapperTransitionStatus from '@hooks/useScreenWrapperTransitionStatus';
import {canUseTouchScreen} from '@libs/DeviceCapabilities';
import memoize from '@libs/memoize';
import {filterAndOrderOptions, filterSelectedOptions, formatSectionsFromSearchTerm, getFilteredRecentAttendees, getValidOptions} from '@libs/OptionsListUtils';
import type {Option, Section} from '@libs/OptionsListUtils';
import type {Option} from '@libs/OptionsListUtils';
import type {SelectionListSections} from '@libs/OptionsListUtils/types';
import type {OptionData} from '@libs/ReportUtils';
import {getDisplayNameForParticipant} from '@libs/ReportUtils';
import Navigation from '@navigation/Navigation';
Expand Down Expand Up @@ -193,7 +193,7 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate,
}, [unselectedOptions, cleanSearchTerm, countryCode, loginList, selectedOptions, shouldAllowNameOnlyOptions, searchTerm, currentUserEmail, currentUserAccountID, personalDetails]);

const {sections, headerMessage} = useMemo(() => {
const newSections: Section[] = [];
const newSections: SelectionListSections = [];
if (!areOptionsInitialized) {
return {sections: [], headerMessage: undefined};
}
Expand Down Expand Up @@ -231,7 +231,7 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate,
newSections.push({
title: '',
data: [chatOptions.currentUserOption],
shouldShow: true,
sectionIndex: 0,
});
}

Expand All @@ -247,13 +247,13 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate,
newSections.push({
title: '',
data: filteredRecentReports,
shouldShow: filteredRecentReports.length > 0,
sectionIndex: 1,
});

newSections.push({
title: '',
data: chatOptions.personalDetails,
shouldShow: chatOptions.personalDetails.length > 0,
sectionIndex: 2,
});

const noResultsFound = chatOptions.personalDetails.length === 0 && chatOptions.recentReports.length === 0 && !chatOptions.currentUserOption;
Expand Down Expand Up @@ -406,23 +406,28 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate,
const isLoadingNewOptions = !!isSearchingForReports;
const showLoadingPlaceholder = !didScreenTransitionEnd || !areOptionsInitialized || !initialAccountIDs || !personalDetails;

const textInputOptions = useMemo(
() => ({
value: searchTerm,
label: translate('selectionList.nameEmailOrPhoneNumber'),
onChangeText: setSearchTerm,
headerMessage,
}),
[searchTerm, translate, setSearchTerm, headerMessage],
);

return (
<SelectionList
canSelectMultiple
<SelectionListWithSections
sections={sections}
ListItem={UserSelectionListItem}
textInputLabel={translate('selectionList.nameEmailOrPhoneNumber')}
headerMessage={headerMessage}
textInputValue={searchTerm}
textInputOptions={textInputOptions}
shouldShowTextInput
footerContent={footerContent}
showScrollIndicator
shouldPreventDefaultFocusOnSelectRow={!canUseTouchScreen()}
onChangeText={(value) => {
setSearchTerm(value);
}}
onSelectRow={handleParticipantSelection}
isLoadingNewOptions={isLoadingNewOptions}
showLoadingPlaceholder={showLoadingPlaceholder}
canSelectMultiple
/>
);
}
Expand Down
Loading
Loading