diff --git a/src/pages/NewChatPage.tsx b/src/pages/NewChatPage.tsx index bcf0c917e80b..e2df8ceda5c9 100755 --- a/src/pages/NewChatPage.tsx +++ b/src/pages/NewChatPage.tsx @@ -25,13 +25,22 @@ import useSafeAreaInsets from '@hooks/useSafeAreaInsets'; import useScreenWrapperTranstionStatus from '@hooks/useScreenWrapperTransitionStatus'; import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; +import {navigateToAndOpenReport, searchInServer, setGroupDraft} from '@libs/actions/Report'; +import {canUseTouchScreen} from '@libs/DeviceCapabilities'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; -import * as OptionsListUtils from '@libs/OptionsListUtils'; +import type {Option, Section} from '@libs/OptionsListUtils'; +import { + filterAndOrderOptions, + formatSectionsFromSearchTerm, + getFirstKeyForList, + getHeaderMessage, + getPersonalDetailSearchTerms, + getUserToInviteOption, + getValidOptions, +} from '@libs/OptionsListUtils'; import type {OptionData} from '@libs/ReportUtils'; import variables from '@styles/variables'; -import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -51,7 +60,7 @@ function useOptions() { }); const defaultOptions = useMemo(() => { - const filteredOptions = OptionsListUtils.getValidOptions( + const filteredOptions = getValidOptions( { reports: listOptions.reports ?? [], personalDetails: listOptions.personalDetails ?? [], @@ -66,7 +75,7 @@ function useOptions() { }, [betas, listOptions.personalDetails, listOptions.reports, selectedOptions]); const options = useMemo(() => { - const filteredOptions = OptionsListUtils.filterAndOrderOptions(defaultOptions, debouncedSearchTerm, { + const filteredOptions = filterAndOrderOptions(defaultOptions, debouncedSearchTerm, { selectedOptions, maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, }); @@ -75,11 +84,11 @@ function useOptions() { }, [debouncedSearchTerm, defaultOptions, selectedOptions]); const cleanSearchTerm = useMemo(() => debouncedSearchTerm.trim().toLowerCase(), [debouncedSearchTerm]); const headerMessage = useMemo(() => { - return OptionsListUtils.getHeaderMessage( + return getHeaderMessage( options.personalDetails.length + options.recentReports.length !== 0, !!options.userToInvite, debouncedSearchTerm.trim(), - selectedOptions.some((participant) => OptionsListUtils.getPersonalDetailSearchTerms(participant).join(' ').toLowerCase?.().includes(cleanSearchTerm)), + selectedOptions.some((participant) => getPersonalDetailSearchTerms(participant).join(' ').toLowerCase?.().includes(cleanSearchTerm)), ); }, [cleanSearchTerm, debouncedSearchTerm, options.personalDetails.length, options.recentReports.length, options.userToInvite, selectedOptions]); @@ -88,7 +97,7 @@ function useOptions() { return; } - Report.searchInServer(debouncedSearchTerm); + searchInServer(debouncedSearchTerm); }, [debouncedSearchTerm]); useEffect(() => { @@ -102,7 +111,7 @@ function useOptions() { } let participantOption: OptionData | undefined | null = listOptions.personalDetails.find((option) => option.accountID === participant.accountID); if (!participantOption) { - participantOption = OptionsListUtils.getUserToInviteOption({ + participantOption = getUserToInviteOption({ searchValue: participant?.login, }); } @@ -146,23 +155,23 @@ function NewChatPage() { useOptions(); const [sections, firstKeyForList] = useMemo(() => { - const sectionsList: OptionsListUtils.Section[] = []; + const sectionsList: Section[] = []; let firstKey = ''; - const formatResults = OptionsListUtils.formatSectionsFromSearchTerm(debouncedSearchTerm, selectedOptions, recentReports, personalDetails); + const formatResults = formatSectionsFromSearchTerm(debouncedSearchTerm, selectedOptions, recentReports, personalDetails); sectionsList.push(formatResults.section); if (!firstKey) { - firstKey = OptionsListUtils.getFirstKeyForList(formatResults.section.data); + firstKey = getFirstKeyForList(formatResults.section.data); } sectionsList.push({ title: translate('common.recents'), - data: recentReports, + data: selectedOptions.length ? recentReports.filter((option) => !option.isSelfDM) : recentReports, shouldShow: !isEmpty(recentReports), }); if (!firstKey) { - firstKey = OptionsListUtils.getFirstKeyForList(recentReports); + firstKey = getFirstKeyForList(recentReports); } sectionsList.push({ @@ -171,7 +180,7 @@ function NewChatPage() { shouldShow: !isEmpty(personalDetails), }); if (!firstKey) { - firstKey = OptionsListUtils.getFirstKeyForList(personalDetails); + firstKey = getFirstKeyForList(personalDetails); } if (userToInvite) { @@ -181,7 +190,7 @@ function NewChatPage() { shouldShow: true, }); if (!firstKey) { - firstKey = OptionsListUtils.getFirstKeyForList([userToInvite]); + firstKey = getFirstKeyForList([userToInvite]); } } @@ -189,15 +198,44 @@ function NewChatPage() { }, [debouncedSearchTerm, selectedOptions, recentReports, personalDetails, translate, userToInvite]); /** - * Creates a new 1:1 chat with the option and the current user, + * Removes a selected option from list if already selected. If not already selected add this option to the list. + */ + const toggleOption = useCallback( + (option: ListItem & Partial) => { + const isOptionInList = !!option.isSelected; + + let newSelectedOptions; + + if (isOptionInList) { + newSelectedOptions = reject(selectedOptions, (selectedOption) => selectedOption.login === option.login); + } else { + newSelectedOptions = [...selectedOptions, {...option, isSelected: true, selected: true, reportID: option.reportID ?? `${CONST.DEFAULT_NUMBER_ID}`}]; + } + + selectionListRef?.current?.clearInputAfterSelect?.(); + selectionListRef.current?.focusTextInput(); + selectionListRef?.current?.scrollToIndex(Math.max(newSelectedOptions.length - 1, 0), true); + setSelectedOptions(newSelectedOptions); + }, + [selectedOptions, setSelectedOptions], + ); + + /** + * If there are selected options already then it will toggle the option otherwise + * creates a new 1:1 chat with the option and the current user, * or navigates to the existing chat if one with those participants already exists. */ - const createChat = useCallback( - (option?: OptionsListUtils.Option) => { + const selectOption = useCallback( + (option?: Option) => { if (option?.isSelfDM) { Navigation.dismissModal(option.reportID); return; } + if (selectedOptions.length && option) { + toggleOption(option); + return; + } + let login = ''; if (option?.login) { @@ -209,37 +247,16 @@ function NewChatPage() { Log.warn('Tried to create chat with empty login'); return; } - Report.navigateToAndOpenReport([login]); + navigateToAndOpenReport([login]); }, - [selectedOptions], + [selectedOptions, toggleOption], ); const itemRightSideComponent = useCallback( - (item: ListItem & OptionsListUtils.Option, isFocused?: boolean) => { + (item: ListItem & Option, isFocused?: boolean) => { if (!!item.isSelfDM || (item.login && excludedGroupEmails.includes(item.login))) { return null; } - /** - * Removes a selected option from list if already selected. If not already selected add this option to the list. - * @param option - */ - function toggleOption(option: ListItem & Partial) { - const isOptionInList = !!option.isSelected; - - let newSelectedOptions; - - if (isOptionInList) { - newSelectedOptions = reject(selectedOptions, (selectedOption) => selectedOption.login === option.login); - } else { - newSelectedOptions = [...selectedOptions, {...option, isSelected: true, selected: true, reportID: option.reportID ?? `${CONST.DEFAULT_NUMBER_ID}`}]; - } - - selectionListRef?.current?.clearInputAfterSelect?.(); - - selectionListRef.current?.focusTextInput(); - selectionListRef?.current?.scrollToIndex(Math.max(newSelectedOptions.length - 1, 0), true); - setSelectedOptions(newSelectedOptions); - } if (item.isSelected) { return ( @@ -268,7 +285,7 @@ function NewChatPage() { /> ); }, - [selectedOptions, setSelectedOptions, styles.alignItemsCenter, styles.buttonDefaultHovered, styles.flexRow, styles.ml0, styles.ml5, styles.optionSelectCircle, styles.pl2, translate], + [toggleOption, styles.alignItemsCenter, styles.buttonDefaultHovered, styles.flexRow, styles.ml0, styles.ml5, styles.optionSelectCircle, styles.pl2, translate], ); const createGroup = useCallback(() => { @@ -280,7 +297,7 @@ function NewChatPage() { accountID: option.accountID ?? CONST.DEFAULT_NUMBER_ID, })); const logins = [...selectedParticipants, {login: personalData.login, accountID: personalData.accountID}]; - Report.setGroupDraft({participants: logins}); + setGroupDraft({participants: logins}); Keyboard.dismiss(); Navigation.navigate(ROUTES.NEW_CHAT_CONFIRM); }, [selectedOptions, personalData]); @@ -327,7 +344,7 @@ function NewChatPage() { // This is because when wrapping whole screen the screen was freezing when changing Tabs. keyboardVerticalOffset={variables.contentHeaderHeight + top + variables.tabSelectorButtonHeight + variables.tabSelectorButtonPadding} > - + ref={selectionListRef} ListItem={UserListItem} sections={areOptionsInitialized ? sections : CONST.EMPTY_ARRAY} @@ -336,13 +353,13 @@ function NewChatPage() { onChangeText={setSearchTerm} textInputLabel={translate('selectionList.nameEmailOrPhoneNumber')} headerMessage={headerMessage} - onSelectRow={createChat} + onSelectRow={selectOption} shouldSingleExecuteRowSelect - onConfirm={(e, option) => (selectedOptions.length > 0 ? createGroup() : createChat(option))} + onConfirm={(e, option) => (selectedOptions.length > 0 ? createGroup() : selectOption(option))} rightHandSideComponent={itemRightSideComponent} footerContent={footerContent} showLoadingPlaceholder={!areOptionsInitialized} - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} + shouldPreventDefaultFocusOnSelectRow={!canUseTouchScreen()} isLoadingNewOptions={!!isSearchingForReports} initiallyFocusedOptionKey={firstKeyForList} shouldTextInputInterceptSwipe