From f3dfee81dad755fbb54940e4fb77121650c2d039 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 7 May 2025 21:34:15 +0800 Subject: [PATCH 1/2] fix after invite user, invite page still on the stack --- src/pages/InviteReportParticipantsPage.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/pages/InviteReportParticipantsPage.tsx b/src/pages/InviteReportParticipantsPage.tsx index 8570261a1bee..1bd469d6f174 100644 --- a/src/pages/InviteReportParticipantsPage.tsx +++ b/src/pages/InviteReportParticipantsPage.tsx @@ -171,8 +171,12 @@ function InviteReportParticipantsPage({betas, report, didScreenTransitionEnd}: I const validate = useCallback(() => selectedOptions.length > 0, [selectedOptions]); const reportID = report.reportID; - const backRoute = useMemo(() => ROUTES.REPORT_PARTICIPANTS.getRoute(reportID, route.params.backTo), [reportID, route.params.backTo]); const reportName = useMemo(() => ReportUtils.getGroupChatName(undefined, true, report), [report]); + + const goBack = useCallback(() => { + Navigation.goBack(ROUTES.REPORT_PARTICIPANTS.getRoute(reportID, route.params.backTo)); + }, [reportID, route.params.backTo]); + const inviteUsers = useCallback(() => { if (!validate()) { return; @@ -187,8 +191,8 @@ function InviteReportParticipantsPage({betas, report, didScreenTransitionEnd}: I invitedEmailsToAccountIDs[login] = accountID; }); Report.inviteToGroupChat(reportID, invitedEmailsToAccountIDs); - Navigation.navigate(backRoute); - }, [selectedOptions, backRoute, reportID, validate]); + goBack(); + }, [selectedOptions, goBack, reportID, validate]); const headerMessage = useMemo(() => { const processedLogin = debouncedSearchTerm.trim().toLowerCase(); @@ -233,9 +237,7 @@ function InviteReportParticipantsPage({betas, report, didScreenTransitionEnd}: I { - Navigation.goBack(backRoute); - }} + onBackButtonPress={goBack} /> Date: Thu, 8 May 2025 00:17:29 +0800 Subject: [PATCH 2/2] lint --- src/pages/InviteReportParticipantsPage.tsx | 89 +++++++++++----------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/src/pages/InviteReportParticipantsPage.tsx b/src/pages/InviteReportParticipantsPage.tsx index 1bd469d6f174..6db5b0b84db2 100644 --- a/src/pages/InviteReportParticipantsPage.tsx +++ b/src/pages/InviteReportParticipantsPage.tsx @@ -14,17 +14,27 @@ import type {WithNavigationTransitionEndProps} from '@components/withNavigationT import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as UserSearchPhraseActions from '@libs/actions/RoomMembersUserSearchPhrase'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; -import * as LoginUtils from '@libs/LoginUtils'; +import {inviteToGroupChat, searchInServer} from '@libs/actions/Report'; +import {clearUserSearchPhrase, updateUserSearchPhrase} from '@libs/actions/RoomMembersUserSearchPhrase'; +import {canUseTouchScreen} from '@libs/DeviceCapabilities'; +import {appendCountryCode} from '@libs/LoginUtils'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import type {ParticipantsNavigatorParamList} from '@libs/Navigation/types'; -import * as OptionsListUtils from '@libs/OptionsListUtils'; -import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; -import * as PhoneNumber from '@libs/PhoneNumber'; -import * as ReportUtils from '@libs/ReportUtils'; -import * as Report from '@userActions/Report'; +import { + filterAndOrderOptions, + formatMemberForList, + getEmptyOptions, + getHeaderMessage, + getMemberInviteOptions, + getSearchValueForPhoneOrEmail, + isPersonalDetailsReady, +} from '@libs/OptionsListUtils'; +import type {MemberForList} from '@libs/OptionsListUtils'; +import {getLoginsByAccountIDs} from '@libs/PersonalDetailsUtils'; +import {addSMSDomainIfPhoneNumber, parsePhoneNumber} from '@libs/PhoneNumber'; +import {getGroupChatName, getParticipantsAccountIDsForDisplay} from '@libs/ReportUtils'; +import type {OptionData} from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -35,7 +45,7 @@ import withReportOrNotFound from './home/report/withReportOrNotFound'; type InviteReportParticipantsPageProps = WithReportOrNotFoundProps & WithNavigationTransitionEndProps; -type Sections = Array>>; +type Sections = Array>>; function InviteReportParticipantsPage({betas, report, didScreenTransitionEnd}: InviteReportParticipantsPageProps) { const route = useRoute>(); @@ -45,14 +55,14 @@ function InviteReportParticipantsPage({betas, report, didScreenTransitionEnd}: I const styles = useThemeStyles(); const {translate} = useLocalize(); - const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST); - const [userSearchPhrase] = useOnyx(ONYXKEYS.ROOM_MEMBERS_USER_SEARCH_PHRASE); + const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {canBeMissing: false}); + const [userSearchPhrase] = useOnyx(ONYXKEYS.ROOM_MEMBERS_USER_SEARCH_PHRASE, {canBeMissing: true}); const [searchValue, debouncedSearchTerm, setSearchValue] = useDebouncedState(userSearchPhrase ?? ''); - const [selectedOptions, setSelectedOptions] = useState([]); + const [selectedOptions, setSelectedOptions] = useState([]); useEffect(() => { - UserSearchPhraseActions.updateUserSearchPhrase(debouncedSearchTerm); - Report.searchInServer(debouncedSearchTerm); + updateUserSearchPhrase(debouncedSearchTerm); + searchInServer(debouncedSearchTerm); }, [debouncedSearchTerm]); // Any existing participants and Expensify emails should not be eligible for invitation @@ -60,8 +70,8 @@ function InviteReportParticipantsPage({betas, report, didScreenTransitionEnd}: I const res = { ...CONST.EXPENSIFY_EMAILS_OBJECT, }; - const participantsAccountIDs = ReportUtils.getParticipantsAccountIDsForDisplay(report, false, true); - const loginsByAccountIDs = PersonalDetailsUtils.getLoginsByAccountIDs(participantsAccountIDs); + const participantsAccountIDs = getParticipantsAccountIDsForDisplay(report, false, true); + const loginsByAccountIDs = getLoginsByAccountIDs(participantsAccountIDs); for (const login of loginsByAccountIDs) { res[login] = true; } @@ -70,27 +80,24 @@ function InviteReportParticipantsPage({betas, report, didScreenTransitionEnd}: I const defaultOptions = useMemo(() => { if (!areOptionsInitialized) { - return OptionsListUtils.getEmptyOptions(); + return getEmptyOptions(); } - return OptionsListUtils.getMemberInviteOptions(options.personalDetails, betas ?? [], excludedUsers, false, options.reports, true); + return getMemberInviteOptions(options.personalDetails, betas ?? [], excludedUsers, false, options.reports, true); }, [areOptionsInitialized, betas, excludedUsers, options.personalDetails, options.reports]); - const inviteOptions = useMemo( - () => OptionsListUtils.filterAndOrderOptions(defaultOptions, debouncedSearchTerm, {excludeLogins: excludedUsers}), - [debouncedSearchTerm, defaultOptions, excludedUsers], - ); + const inviteOptions = useMemo(() => filterAndOrderOptions(defaultOptions, debouncedSearchTerm, {excludeLogins: excludedUsers}), [debouncedSearchTerm, defaultOptions, excludedUsers]); useEffect(() => { // Update selectedOptions with the latest personalDetails information - const detailsMap: Record = {}; + const detailsMap: Record = {}; inviteOptions.personalDetails.forEach((detail) => { if (!detail.login) { return; } - detailsMap[detail.login] = OptionsListUtils.formatMemberForList(detail); + detailsMap[detail.login] = formatMemberForList(detail); }); - const newSelectedOptions: ReportUtils.OptionData[] = []; + const newSelectedOptions: OptionData[] = []; selectedOptions.forEach((option) => { newSelectedOptions.push(option.login && option.login in detailsMap ? {...detailsMap[option.login], isSelected: true} : option); }); @@ -112,12 +119,12 @@ function InviteReportParticipantsPage({betas, report, didScreenTransitionEnd}: I filterSelectedOptions = selectedOptions.filter((option) => { const accountID = option?.accountID; const isOptionInPersonalDetails = inviteOptions.personalDetails.some((personalDetail) => accountID && personalDetail?.accountID === accountID); - const processedSearchValue = OptionsListUtils.getSearchValueForPhoneOrEmail(debouncedSearchTerm); + const processedSearchValue = getSearchValueForPhoneOrEmail(debouncedSearchTerm); const isPartOfSearchTerm = !!option.text?.toLowerCase().includes(processedSearchValue) || !!option.login?.toLowerCase().includes(processedSearchValue); return isPartOfSearchTerm || isOptionInPersonalDetails; }); } - const filterSelectedOptionsFormatted = filterSelectedOptions.map((selectedOption) => OptionsListUtils.formatMemberForList(selectedOption)); + const filterSelectedOptionsFormatted = filterSelectedOptions.map((selectedOption) => formatMemberForList(selectedOption)); sectionsArr.push({ title: undefined, @@ -127,9 +134,9 @@ function InviteReportParticipantsPage({betas, report, didScreenTransitionEnd}: I // Filtering out selected users from the search results const selectedLogins = selectedOptions.map(({login}) => login); const recentReportsWithoutSelected = inviteOptions.recentReports.filter(({login}) => !selectedLogins.includes(login)); - const recentReportsFormatted = recentReportsWithoutSelected.map((reportOption) => OptionsListUtils.formatMemberForList(reportOption)); + const recentReportsFormatted = recentReportsWithoutSelected.map((reportOption) => formatMemberForList(reportOption)); const personalDetailsWithoutSelected = inviteOptions.personalDetails.filter(({login}) => !selectedLogins.includes(login)); - const personalDetailsFormatted = personalDetailsWithoutSelected.map((personalDetail) => OptionsListUtils.formatMemberForList(personalDetail)); + const personalDetailsFormatted = personalDetailsWithoutSelected.map((personalDetail) => formatMemberForList(personalDetail)); const hasUnselectedUserToInvite = inviteOptions.userToInvite && !selectedLogins.includes(inviteOptions.userToInvite.login); sectionsArr.push({ @@ -145,7 +152,7 @@ function InviteReportParticipantsPage({betas, report, didScreenTransitionEnd}: I if (hasUnselectedUserToInvite) { sectionsArr.push({ title: undefined, - data: inviteOptions.userToInvite ? [OptionsListUtils.formatMemberForList(inviteOptions.userToInvite)] : [], + data: inviteOptions.userToInvite ? [formatMemberForList(inviteOptions.userToInvite)] : [], }); } @@ -153,10 +160,10 @@ function InviteReportParticipantsPage({betas, report, didScreenTransitionEnd}: I }, [areOptionsInitialized, selectedOptions, debouncedSearchTerm, inviteOptions.recentReports, inviteOptions.personalDetails, inviteOptions.userToInvite, translate]); const toggleOption = useCallback( - (option: OptionsListUtils.MemberForList) => { + (option: MemberForList) => { const isOptionInList = selectedOptions.some((selectedOption) => selectedOption.login === option.login); - let newSelectedOptions: ReportUtils.OptionData[]; + let newSelectedOptions: OptionData[]; if (isOptionInList) { newSelectedOptions = selectedOptions.filter((selectedOption) => selectedOption.login !== option.login); } else { @@ -171,7 +178,7 @@ function InviteReportParticipantsPage({betas, report, didScreenTransitionEnd}: I const validate = useCallback(() => selectedOptions.length > 0, [selectedOptions]); const reportID = report.reportID; - const reportName = useMemo(() => ReportUtils.getGroupChatName(undefined, true, report), [report]); + const reportName = useMemo(() => getGroupChatName(undefined, true, report), [report]); const goBack = useCallback(() => { Navigation.goBack(ROUTES.REPORT_PARTICIPANTS.getRoute(reportID, route.params.backTo)); @@ -190,7 +197,7 @@ function InviteReportParticipantsPage({betas, report, didScreenTransitionEnd}: I } invitedEmailsToAccountIDs[login] = accountID; }); - Report.inviteToGroupChat(reportID, invitedEmailsToAccountIDs); + inviteToGroupChat(reportID, invitedEmailsToAccountIDs); goBack(); }, [selectedOptions, goBack, reportID, validate]); @@ -202,15 +209,11 @@ function InviteReportParticipantsPage({betas, report, didScreenTransitionEnd}: I } if ( !inviteOptions.userToInvite && - excludedUsers[ - PhoneNumber.parsePhoneNumber(LoginUtils.appendCountryCode(processedLogin)).possible - ? PhoneNumber.addSMSDomainIfPhoneNumber(LoginUtils.appendCountryCode(processedLogin)) - : processedLogin - ] + excludedUsers[parsePhoneNumber(appendCountryCode(processedLogin)).possible ? addSMSDomainIfPhoneNumber(appendCountryCode(processedLogin)) : processedLogin] ) { return translate('messages.userIsAlreadyMember', {login: processedLogin, name: reportName ?? ''}); } - return OptionsListUtils.getHeaderMessage(inviteOptions.recentReports.length + inviteOptions.personalDetails.length !== 0, !!inviteOptions.userToInvite, processedLogin); + return getHeaderMessage(inviteOptions.recentReports.length + inviteOptions.personalDetails.length !== 0, !!inviteOptions.userToInvite, processedLogin); }, [debouncedSearchTerm, inviteOptions.userToInvite, inviteOptions.recentReports.length, inviteOptions.personalDetails.length, excludedUsers, translate, reportName]); const footerContent = useMemo( @@ -219,7 +222,7 @@ function InviteReportParticipantsPage({betas, report, didScreenTransitionEnd}: I isDisabled={!selectedOptions.length} buttonText={translate('common.invite')} onSubmit={() => { - UserSearchPhraseActions.clearUserSearchPhrase(); + clearUserSearchPhrase(); inviteUsers(); }} containerStyles={[styles.flexReset, styles.flexGrow0, styles.flexShrink0, styles.flexBasisAuto]} @@ -253,8 +256,8 @@ function InviteReportParticipantsPage({betas, report, didScreenTransitionEnd}: I onSelectRow={toggleOption} onConfirm={inviteUsers} showScrollIndicator - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} - showLoadingPlaceholder={!didScreenTransitionEnd || !OptionsListUtils.isPersonalDetailsReady(personalDetails)} + shouldPreventDefaultFocusOnSelectRow={!canUseTouchScreen()} + showLoadingPlaceholder={!didScreenTransitionEnd || !isPersonalDetailsReady(personalDetails)} footerContent={footerContent} />