11import { isUserValidatedSelector } from '@selectors/Account' ;
2- import { Str } from 'expensify-common' ;
3- import React , { useCallback , useContext } from 'react' ;
2+ import React , { useCallback , useContext , useMemo } from 'react' ;
43import { View } from 'react-native' ;
54import Button from '@components/Button' ;
65import CopyTextToClipboard from '@components/CopyTextToClipboard' ;
@@ -19,77 +18,26 @@ import useThemeStyles from '@hooks/useThemeStyles';
1918import Navigation from '@libs/Navigation/Navigation' ;
2019import type { PlatformStackScreenProps } from '@libs/Navigation/PlatformStackNavigation/types' ;
2120import type { SettingsNavigatorParamList } from '@libs/Navigation/types' ;
21+ import { getContactMethodsOptions } from '@libs/UserUtils' ;
2222import CONST from '@src/CONST' ;
2323import ONYXKEYS from '@src/ONYXKEYS' ;
2424import ROUTES from '@src/ROUTES' ;
2525import type SCREENS from '@src/SCREENS' ;
26- import { isEmptyObject } from '@src/types/utils/EmptyObject' ;
2726
2827type ContactMethodsPageProps = PlatformStackScreenProps < SettingsNavigatorParamList , typeof SCREENS . SETTINGS . PROFILE . CONTACT_METHODS > ;
2928
3029function ContactMethodsPage ( { route} : ContactMethodsPageProps ) {
3130 const styles = useThemeStyles ( ) ;
32- const { formatPhoneNumber , translate} = useLocalize ( ) ;
31+ const { translate} = useLocalize ( ) ;
3332 const [ loginList ] = useOnyx ( ONYXKEYS . LOGIN_LIST , { canBeMissing : false } ) ;
3433 const [ session ] = useOnyx ( ONYXKEYS . SESSION , { canBeMissing : false } ) ;
35- const loginNames = Object . keys ( loginList ?? { } ) ;
3634 const navigateBackTo = route ?. params ?. backTo ;
3735
3836 const { isActingAsDelegate, showDelegateNoAccessModal} = useContext ( DelegateNoAccessContext ) ;
3937 const [ isUserValidated ] = useOnyx ( ONYXKEYS . ACCOUNT , { selector : isUserValidatedSelector , canBeMissing : false } ) ;
4038 const { isAccountLocked, showLockedAccountModal} = useContext ( LockedAccountContext ) ;
4139
42- // Sort the login names by placing the one corresponding to the default contact method as the first item before displaying the contact methods.
43- // The default contact method is determined by checking against the session email (the current login).
44- const sortedLoginNames = loginNames . sort ( ( loginName ) => ( loginList ?. [ loginName ] . partnerUserID === session ?. email ? - 1 : 1 ) ) ;
45- const loginMenuItems = sortedLoginNames . map ( ( loginName ) => {
46- const login = loginList ?. [ loginName ] ;
47- const isDefaultContactMethod = session ?. email === login ?. partnerUserID ;
48- const pendingAction = login ?. pendingFields ?. deletedLogin ?? login ?. pendingFields ?. addedLogin ?? undefined ;
49- if ( ! login ?. partnerUserID && ! pendingAction ) {
50- return null ;
51- }
52-
53- let description = '' ;
54- if ( session ?. email === login ?. partnerUserID ) {
55- description = translate ( 'contacts.getInTouch' ) ;
56- } else if ( login ?. errorFields ?. addedLogin ) {
57- description = translate ( 'contacts.failedNewContact' ) ;
58- } else if ( ! login ?. validatedDate ) {
59- description = translate ( 'contacts.pleaseVerify' ) ;
60- }
61- let indicator ;
62- if ( Object . values ( login ?. errorFields ?? { } ) . some ( ( errorField ) => ! isEmptyObject ( errorField ) ) ) {
63- indicator = CONST . BRICK_ROAD_INDICATOR_STATUS . ERROR ;
64- } else if ( ! login ?. validatedDate && ! isDefaultContactMethod ) {
65- indicator = CONST . BRICK_ROAD_INDICATOR_STATUS . INFO ;
66- } else if ( ! login ?. validatedDate && isDefaultContactMethod && loginNames . length > 1 ) {
67- indicator = CONST . BRICK_ROAD_INDICATOR_STATUS . INFO ;
68- }
69-
70- // Default to using login key if we deleted login.partnerUserID optimistically
71- // but still need to show the pending login being deleted while offline.
72- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
73- const partnerUserID = login ?. partnerUserID || loginName ;
74- const menuItemTitle = Str . isSMSLogin ( partnerUserID ) ? formatPhoneNumber ( partnerUserID ) : partnerUserID ;
75-
76- return (
77- < OfflineWithFeedback
78- pendingAction = { pendingAction }
79- key = { partnerUserID }
80- >
81- < MenuItem
82- title = { menuItemTitle }
83- description = { description }
84- onPress = { ( ) => Navigation . navigate ( ROUTES . SETTINGS_CONTACT_METHOD_DETAILS . getRoute ( partnerUserID , navigateBackTo ) ) }
85- brickRoadIndicator = { indicator }
86- shouldShowBasicTitle
87- shouldShowRightIcon
88- disabled = { ! ! pendingAction }
89- />
90- </ OfflineWithFeedback >
91- ) ;
92- } ) ;
40+ const options = useMemo ( ( ) => getContactMethodsOptions ( loginList , session ?. email ) , [ loginList , session ?. email ] ) ;
9341
9442 const onNewContactMethodButtonPress = useCallback ( ( ) => {
9543 if ( isActingAsDelegate ) {
@@ -129,7 +77,25 @@ function ContactMethodsPage({route}: ContactMethodsPageProps) {
12977 < Text > { translate ( 'contacts.helpTextAfterEmail' ) } </ Text >
13078 </ Text >
13179 </ View >
132- { loginMenuItems }
80+ { options . map (
81+ ( option ) =>
82+ ! ! option && (
83+ < OfflineWithFeedback
84+ pendingAction = { option . pendingAction }
85+ key = { option . partnerUserID }
86+ >
87+ < MenuItem
88+ title = { option . menuItemTitle }
89+ description = { option . description }
90+ onPress = { ( ) => Navigation . navigate ( ROUTES . SETTINGS_CONTACT_METHOD_DETAILS . getRoute ( option . partnerUserID , navigateBackTo ) ) }
91+ brickRoadIndicator = { option . indicator }
92+ shouldShowBasicTitle
93+ shouldShowRightIcon
94+ disabled = { ! ! option . pendingAction }
95+ />
96+ </ OfflineWithFeedback >
97+ ) ,
98+ ) }
13399 < FixedFooter style = { [ styles . mtAuto , styles . pt5 ] } >
134100 < Button
135101 large
0 commit comments