11import { Str } from 'expensify-common' ;
2- import React , { useCallback , useEffect , useMemo , useState } from 'react' ;
2+ import React , { useEffect , useState } from 'react' ;
33import type { SectionListData } from 'react-native' ;
44import { View } from 'react-native' ;
55import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView' ;
@@ -8,10 +8,9 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton';
88import { usePersonalDetails } from '@components/OnyxListItemProvider' ;
99import { useOptionsList } from '@components/OptionListContextProvider' ;
1010import ScreenWrapper from '@components/ScreenWrapper' ;
11- // eslint-disable-next-line no-restricted-imports
12- import SelectionList from '@components/SelectionListWithSections' ;
13- import InviteMemberListItem from '@components/SelectionListWithSections/InviteMemberListItem' ;
14- import type { Section } from '@components/SelectionListWithSections/types' ;
11+ import InviteMemberListItem from '@components/SelectionList/ListItem/InviteMemberListItem' ;
12+ import SelectionListWithSections from '@components/SelectionList/SelectionListWithSections' ;
13+ import type { Section } from '@components/SelectionList/SelectionListWithSections/types' ;
1514import withNavigationTransitionEnd from '@components/withNavigationTransitionEnd' ;
1615import type { WithNavigationTransitionEndProps } from '@components/withNavigationTransitionEnd' ;
1716import useAncestors from '@hooks/useAncestors' ;
@@ -78,22 +77,18 @@ function RoomInvitePage({
7877 const allPersonalDetails = usePersonalDetails ( ) ;
7978
8079 // Any existing participants and Expensify emails should not be eligible for invitation
81- const excludedUsers = useMemo ( ( ) => {
82- const res = {
83- ...CONST . EXPENSIFY_EMAILS_OBJECT ,
84- } ;
85- const visibleParticipantAccountIDs = Object . entries ( report . participants ?? { } )
86- . filter ( ( [ , participant ] ) => participant && ! isHiddenForCurrentUser ( participant . notificationPreference ) )
87- . map ( ( [ accountID ] ) => Number ( accountID ) ) ;
88- for ( const participant of getLoginsByAccountIDs ( visibleParticipantAccountIDs ) ) {
89- const smsDomain = addSMSDomainIfPhoneNumber ( participant ) ;
90- res [ smsDomain ] = true ;
91- }
92-
93- return res ;
94- } , [ report . participants ] ) ;
80+ const excludedUsers : Record < string , boolean > = {
81+ ...CONST . EXPENSIFY_EMAILS_OBJECT ,
82+ } ;
83+ const visibleParticipantAccountIDs = Object . entries ( report . participants ?? { } )
84+ . filter ( ( [ , participant ] ) => participant && ! isHiddenForCurrentUser ( participant . notificationPreference ) )
85+ . map ( ( [ accountID ] ) => Number ( accountID ) ) ;
86+ for ( const participant of getLoginsByAccountIDs ( visibleParticipantAccountIDs ) ) {
87+ const smsDomain = addSMSDomainIfPhoneNumber ( participant ) ;
88+ excludedUsers [ smsDomain ] = true ;
89+ }
9590
96- const defaultOptions = useMemo ( ( ) => {
91+ const getDefaultOptions = ( ) => {
9792 if ( ! areOptionsInitialized ) {
9893 return { recentReports : [ ] , personalDetails : [ ] , userToInvite : null , currentUserOption : null } ;
9994 }
@@ -119,27 +114,19 @@ function RoomInvitePage({
119114 recentReports : [ ] ,
120115 currentUserOption : null ,
121116 } ;
122- } , [ areOptionsInitialized , betas , excludedUsers , loginList , nvpDismissedProductTraining , options . personalDetails , selectedOptions , currentUserAccountID , currentUserEmail ] ) ;
123-
124- const inviteOptions = useMemo ( ( ) => {
125- if ( debouncedSearchTerm . trim ( ) === '' ) {
126- return defaultOptions ;
127- }
128- const filteredOptions = filterAndOrderOptions ( defaultOptions , debouncedSearchTerm , countryCode , loginList , currentUserEmail , currentUserAccountID , allPersonalDetails , {
129- excludeLogins : excludedUsers ,
130- } ) ;
131-
132- return filteredOptions ;
133- } , [ debouncedSearchTerm , defaultOptions , countryCode , loginList , excludedUsers , currentUserAccountID , currentUserEmail , allPersonalDetails ] ) ;
134-
135- const sections = useMemo ( ( ) => {
136- const sectionsArr : Sections = [ ] ;
137-
138- const { personalDetails, userToInvite} = inviteOptions ;
139- if ( ! areOptionsInitialized ) {
140- return [ ] ;
141- }
142-
117+ } ;
118+ const defaultOptions = getDefaultOptions ( ) ;
119+
120+ const inviteOptions =
121+ debouncedSearchTerm . trim ( ) === ''
122+ ? defaultOptions
123+ : filterAndOrderOptions ( defaultOptions , debouncedSearchTerm , countryCode , loginList , currentUserEmail , currentUserAccountID , allPersonalDetails , {
124+ excludeLogins : excludedUsers ,
125+ } ) ;
126+
127+ const { personalDetails, userToInvite} = inviteOptions ;
128+ const sections : Sections = [ ] ;
129+ if ( areOptionsInitialized ) {
143130 // Filter all options that is a part of the search term or in the personal details
144131 let filterSelectedOptions = selectedOptions ;
145132 if ( debouncedSearchTerm !== '' ) {
@@ -154,9 +141,10 @@ function RoomInvitePage({
154141 }
155142 const filterSelectedOptionsFormatted = filterSelectedOptions . map ( ( selectedOption ) => formatMemberForList ( selectedOption ) ) ;
156143
157- sectionsArr . push ( {
144+ sections . push ( {
158145 title : undefined ,
159146 data : filterSelectedOptionsFormatted ,
147+ sectionIndex : 0 ,
160148 } ) ;
161149
162150 // Filtering out selected users from the search results
@@ -165,57 +153,50 @@ function RoomInvitePage({
165153 const personalDetailsFormatted = personalDetailsWithoutSelected . map ( ( personalDetail ) => formatMemberForList ( personalDetail ) ) ;
166154 const hasUnselectedUserToInvite = userToInvite && ! selectedLogins . has ( userToInvite . login ) ;
167155
168- sectionsArr . push ( {
156+ sections . push ( {
169157 title : translate ( 'common.contacts' ) ,
170158 data : personalDetailsFormatted ,
159+ sectionIndex : 1 ,
171160 } ) ;
172161
173162 if ( hasUnselectedUserToInvite ) {
174- sectionsArr . push ( {
163+ sections . push ( {
175164 title : undefined ,
176165 data : [ formatMemberForList ( userToInvite ) ] ,
166+ sectionIndex : 2 ,
177167 } ) ;
178168 }
169+ }
179170
180- return sectionsArr ;
181- } , [ inviteOptions , areOptionsInitialized , selectedOptions , debouncedSearchTerm , translate , countryCode ] ) ;
182-
183- const toggleOption = useCallback (
184- ( option : MemberForList ) => {
185- const isOptionInList = selectedOptions . some ( ( selectedOption ) => selectedOption . login === option . login ) ;
186-
187- let newSelectedOptions : OptionData [ ] ;
188- if ( isOptionInList ) {
189- newSelectedOptions = selectedOptions . filter ( ( selectedOption ) => selectedOption . login !== option . login ) ;
190- } else {
191- newSelectedOptions = [ ...selectedOptions , { ...option , isSelected : true } ] ;
192- }
171+ const toggleOption = ( option : MemberForList ) => {
172+ const isOptionInList = selectedOptions . some ( ( selectedOption ) => selectedOption . login === option . login ) ;
193173
194- setSelectedOptions ( newSelectedOptions ) ;
195- } ,
196- [ selectedOptions ] ,
197- ) ;
174+ let newSelectedOptions : OptionData [ ] ;
175+ if ( isOptionInList ) {
176+ newSelectedOptions = selectedOptions . filter ( ( selectedOption ) => selectedOption . login !== option . login ) ;
177+ } else {
178+ newSelectedOptions = [ ...selectedOptions , { ...option , isSelected : true } ] ;
179+ }
198180
199- const validate = useCallback ( ( ) => selectedOptions . length > 0 , [ selectedOptions . length ] ) ;
181+ setSelectedOptions ( newSelectedOptions ) ;
182+ } ;
200183
201184 // Non policy members should not be able to view the participants of a room
202185 const reportID = report ?. reportID ;
203- const isPolicyEmployee = useMemo ( ( ) => isPolicyEmployeeUtil ( report ?. policyID , policy ) , [ report ?. policyID , policy ] ) ;
204- const reportAction = useMemo ( ( ) => getReportAction ( report ?. parentReportID , report ?. parentReportActionID ) , [ report ?. parentReportID , report ?. parentReportActionID ] ) ;
186+ const isPolicyEmployee = isPolicyEmployeeUtil ( report ?. policyID , policy ) ;
187+ const reportAction = getReportAction ( report ?. parentReportID , report ?. parentReportActionID ) ;
205188 const shouldParserToHTML = reportAction ?. actionName !== CONST . REPORT . ACTIONS . TYPE . ADD_COMMENT ;
206- const backRoute = useMemo ( ( ) => {
207- return reportID && ( ! isPolicyEmployee || isReportArchived ? ROUTES . REPORT_WITH_ID_DETAILS . getRoute ( reportID , backTo ) : ROUTES . ROOM_MEMBERS . getRoute ( reportID , backTo ) ) ;
208- } , [ isPolicyEmployee , reportID , backTo , isReportArchived ] ) ;
189+ const backRoute = reportID && ( ! isPolicyEmployee || isReportArchived ? ROUTES . REPORT_WITH_ID_DETAILS . getRoute ( reportID , backTo ) : ROUTES . ROOM_MEMBERS . getRoute ( reportID , backTo ) ) ;
209190
210191 // eslint-disable-next-line @typescript-eslint/no-deprecated
211- const reportName = useMemo ( ( ) => getReportName ( report ) , [ report ] ) ;
192+ const reportName = getReportName ( report ) ;
212193
213194 const ancestors = useAncestors ( report ) ;
214195
215196 const inviteUsers = ( ) => {
216197 HttpUtils . cancelPendingRequests ( READ_COMMANDS . SEARCH_FOR_REPORTS ) ;
217198
218- if ( ! validate ( ) ) {
199+ if ( selectedOptions . length === 0 ) {
219200 return ;
220201 }
221202 const invitedEmailsToAccountIDs : MemberEmailsToAccountIDs = { } ;
@@ -242,11 +223,7 @@ function RoomInvitePage({
242223 }
243224 } ;
244225
245- const goBack = useCallback ( ( ) => {
246- Navigation . goBack ( backRoute ) ;
247- } , [ backRoute ] ) ;
248-
249- const headerMessage = useMemo ( ( ) => {
226+ const getHeaderMessageText = ( ) => {
250227 const searchValue = debouncedSearchTerm . trim ( ) . toLowerCase ( ) ;
251228 const expensifyEmails = CONST . EXPENSIFY_EMAILS ;
252229 if ( ! inviteOptions . userToInvite && expensifyEmails . includes ( searchValue ) ) {
@@ -259,7 +236,7 @@ function RoomInvitePage({
259236 return translate ( 'messages.userIsAlreadyMember' , { login : searchValue , name : reportName } ) ;
260237 }
261238 return getHeaderMessage ( ( inviteOptions . personalDetails ?? [ ] ) . length !== 0 , ! ! inviteOptions . userToInvite , debouncedSearchTerm , countryCode ) ;
262- } , [ debouncedSearchTerm , inviteOptions . userToInvite , inviteOptions . personalDetails , excludedUsers , countryCode , translate , reportName ] ) ;
239+ } ;
263240
264241 useEffect ( ( ) => {
265242 updateUserSearchPhrase ( debouncedSearchTerm ) ;
@@ -271,6 +248,13 @@ function RoomInvitePage({
271248 subtitleKey = isReportArchived ? 'roomMembersPage.roomArchived' : 'roomMembersPage.notAuthorized' ;
272249 }
273250
251+ const textInputOptions = {
252+ value : searchTerm ,
253+ label : translate ( 'selectionList.nameEmailOrPhoneNumber' ) ,
254+ onChangeText : setSearchTerm ,
255+ headerMessage : getHeaderMessageText ( ) ,
256+ } ;
257+
274258 return (
275259 < ScreenWrapper
276260 shouldEnableMaxHeight
@@ -280,29 +264,27 @@ function RoomInvitePage({
280264 < FullPageNotFoundView
281265 shouldShow = { isEmptyObject ( report ) || isReportArchived }
282266 subtitleKey = { subtitleKey }
283- onBackButtonPress = { goBack }
267+ onBackButtonPress = { ( ) => Navigation . goBack ( backRoute ) }
284268 >
285269 < HeaderWithBackButton
286270 title = { translate ( 'workspace.invite.invitePeople' ) }
287271 subtitle = { shouldParserToHTML ? Parser . htmlToText ( reportName ) : reportName }
288- onBackButtonPress = { goBack }
272+ onBackButtonPress = { ( ) => Navigation . goBack ( backRoute ) }
289273 />
290- < SelectionList
291- canSelectMultiple
274+ < SelectionListWithSections
292275 sections = { sections }
293276 ListItem = { InviteMemberListItem }
294- textInputLabel = { translate ( 'selectionList.nameEmailOrPhoneNumber' ) }
295- textInputValue = { searchTerm }
296- onChangeText = { ( value ) => {
297- setSearchTerm ( value ) ;
298- } }
299- headerMessage = { headerMessage }
277+ textInputOptions = { textInputOptions }
300278 onSelectRow = { toggleOption }
301- onConfirm = { inviteUsers }
302- showScrollIndicator
279+ confirmButtonOptions = { {
280+ onConfirm : inviteUsers ,
281+ } }
303282 shouldPreventDefaultFocusOnSelectRow = { ! canUseTouchScreen ( ) }
304283 showLoadingPlaceholder = { ! areOptionsInitialized }
305284 isLoadingNewOptions = { ! ! isSearchingForReports }
285+ disableMaintainingScrollPosition
286+ shouldShowTextInput
287+ canSelectMultiple
306288 />
307289 < View style = { [ styles . flexShrink0 ] } >
308290 < FormAlertWithSubmitButton
0 commit comments