-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New Contact methods page linked from Profile page #15039
Changes from 17 commits
3211801
9bb6e0f
f44a00e
b33ae5a
e3d13cd
7be6099
667377f
4515a31
836e42b
69cb7f6
944bf6e
aefdc88
0fcd2e1
5b4ca01
b3db92d
5bb4975
a345257
0427126
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import Str from 'expensify-common/lib/str'; | ||
import lodashGet from 'lodash/get'; | ||
import PropTypes from 'prop-types'; | ||
import React, {Component} from 'react'; | ||
import {ScrollView} from 'react-native-gesture-handler'; | ||
import {withOnyx} from 'react-native-onyx'; | ||
import _ from 'underscore'; | ||
import HeaderWithCloseButton from '../../../../components/HeaderWithCloseButton'; | ||
import ScreenWrapper from '../../../../components/ScreenWrapper'; | ||
import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '../../../../components/withCurrentUserPersonalDetails'; | ||
import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize'; | ||
import CONST from '../../../../CONST'; | ||
import compose from '../../../../libs/compose'; | ||
import Navigation from '../../../../libs/Navigation/Navigation'; | ||
import ONYXKEYS from '../../../../ONYXKEYS'; | ||
import ROUTES from '../../../../ROUTES'; | ||
import LoginField from './LoginField'; | ||
|
||
const propTypes = { | ||
/* Onyx Props */ | ||
|
||
/** Login list for the user that is signed in */ | ||
loginList: PropTypes.shape({ | ||
/** Value of partner name */ | ||
partnerName: PropTypes.string, | ||
|
||
/** Phone/Email associated with user */ | ||
partnerUserID: PropTypes.string, | ||
|
||
/** Date of when login was validated */ | ||
validatedDate: PropTypes.string, | ||
}), | ||
|
||
...withLocalizePropTypes, | ||
...withCurrentUserPersonalDetailsPropTypes, | ||
}; | ||
|
||
const defaultProps = { | ||
loginList: {}, | ||
...withCurrentUserPersonalDetailsDefaultProps, | ||
}; | ||
|
||
class ContactMethodsPage extends Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.state = { | ||
logins: this.getLogins(), | ||
}; | ||
|
||
this.getLogins = this.getLogins.bind(this); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unnecessary bindings There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't need to bind here, we need to bind only if we pass a method as the prop to other components. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Beamanator bump! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this is just a copy paste and the component will get redone eventually (taken from here), maybe we don't care about this type of polishing. What do you think @Santhosh-Sellavel ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All right then! |
||
} | ||
|
||
componentDidUpdate(prevProps) { | ||
let stateToUpdate = {}; | ||
|
||
// Recalculate logins if loginList has changed | ||
if (_.keys(this.props.loginList).length !== _.keys(prevProps.loginList).length) { | ||
stateToUpdate = {logins: this.getLogins()}; | ||
} | ||
|
||
if (_.isEmpty(stateToUpdate)) { | ||
return; | ||
} | ||
|
||
// eslint-disable-next-line react/no-did-update-set-state | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if we should be act on this warning instead of just disable it. I see that we have disable it in other places. According to the rule documentation, we should do these There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
🤢 I feel ya... If we end up getting rid of |
||
this.setState(stateToUpdate); | ||
} | ||
|
||
/** | ||
* Get the most validated login of each type | ||
* | ||
* @returns {Object} | ||
*/ | ||
getLogins() { | ||
return _.reduce(_.values(this.props.loginList), (logins, currentLogin) => { | ||
const type = Str.isSMSLogin(currentLogin.partnerUserID) ? CONST.LOGIN_TYPE.PHONE : CONST.LOGIN_TYPE.EMAIL; | ||
const login = Str.removeSMSDomain(currentLogin.partnerUserID); | ||
|
||
// If there's already a login type that's validated and/or currentLogin isn't valid then return early | ||
if ((login !== lodashGet(this.props.currentUserPersonalDetails, 'login')) && !_.isEmpty(logins[type]) | ||
&& (logins[type].validatedDate || !currentLogin.validatedDate)) { | ||
return logins; | ||
} | ||
return { | ||
...logins, | ||
[type]: { | ||
...currentLogin, | ||
type, | ||
partnerUserID: Str.removeSMSDomain(currentLogin.partnerUserID), | ||
}, | ||
}; | ||
}, { | ||
phone: {}, | ||
email: {}, | ||
}); | ||
} | ||
|
||
render() { | ||
return ( | ||
<ScreenWrapper> | ||
<HeaderWithCloseButton | ||
title={this.props.translate('contacts.contactMethods')} | ||
shouldShowBackButton | ||
onBackButtonPress={() => Navigation.navigate(ROUTES.SETTINGS_PROFILE)} | ||
onCloseButtonPress={() => Navigation.dismissModal(true)} | ||
/> | ||
<ScrollView> | ||
<LoginField | ||
label={this.props.translate('profilePage.emailAddress')} | ||
type="email" | ||
login={this.state.logins.email} | ||
defaultValue={this.state.logins.email} | ||
/> | ||
<LoginField | ||
label={this.props.translate('common.phoneNumber')} | ||
type="phone" | ||
login={this.state.logins.phone} | ||
defaultValue={this.state.logins.phone} | ||
/> | ||
</ScrollView> | ||
</ScreenWrapper> | ||
); | ||
} | ||
} | ||
|
||
ContactMethodsPage.propTypes = propTypes; | ||
ContactMethodsPage.defaultProps = defaultProps; | ||
|
||
export default compose( | ||
withLocalize, | ||
withCurrentUserPersonalDetails, | ||
withOnyx({ | ||
loginList: { | ||
key: ONYXKEYS.LOGIN_LIST, | ||
}, | ||
}), | ||
)(ContactMethodsPage); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you know why we copy this to a state instead of just directly calling
this.getLogins()
on render and use what we get there? synchronizing the prop with the state adds more complexity and in this case doesn't seem to serve any purpose.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Def agreed - i have no idea why we did this in the first place, and if we want to take the time to refactor I def agree it makes sense to just directly use what we get from props and not deal with syncing it with state in
componentDidUpdate
👍