// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. // See License.txt for license information. import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; import {intlShape} from 'react-intl'; import {View} from 'react-native'; import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view'; import Loading from 'app/components/loading'; import ErrorText from 'app/components/error_text'; import StatusBar from 'app/components/status_bar/index'; import ProfilePicture from 'app/components/profile_picture/index'; import AttachmentButton from 'app/components/attachment_button'; import {emptyFunction} from 'app/utils/general'; import {preventDoubleTap} from 'app/utils/tap'; import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; import EditProfileItem from './edit_profile_item'; const holders = { firstName: { id: 'user.settings.general.firstName', defaultMessage: 'First Name', }, lastName: { id: 'user.settings.general.lastName', defaultMessage: 'Last Name', }, username: { id: 'user.settings.general.username', defaultMessage: 'Username', }, nickname: { id: 'user.settings.general.nickname', defaultMessage: 'Nickname', }, position: { id: 'user.settings.general.position', defaultMessage: 'Position', }, email: { id: 'user.settings.general.email', defaultMessage: 'Email', }, }; export default class EditProfile extends PureComponent { static propTypes = { actions: PropTypes.shape({ handleUploadProfileImage: PropTypes.func.isRequired, updateUser: PropTypes.func.isRequired, }).isRequired, config: PropTypes.object.isRequired, currentUser: PropTypes.object.isRequired, navigator: PropTypes.object.isRequired, theme: PropTypes.object.isRequired, }; static contextTypes = { intl: intlShape, }; rightButton = { id: 'update-profile', disabled: true, showAsAction: 'always', }; constructor(props, context) { super(props); const {email, first_name: firstName, last_name: lastName, nickname, position, username} = props.currentUser; const buttons = { rightButtons: [this.rightButton], }; this.rightButton.title = context.intl.formatMessage({id: 'mobile.account.settings.save', defaultMessage: 'Save'}); props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); props.navigator.setButtons(buttons); this.state = { email, firstName, lastName, nickname, position, username, }; } canUpdate = (updatedField) => { const {currentUser} = this.props; const keys = Object.keys(this.state); const newState = {...this.state, ...(updatedField || {})}; Reflect.deleteProperty(newState, 'error'); Reflect.deleteProperty(newState, 'updating'); for (let i = 0; i < keys.length; i++) { const key = keys[i]; let userKey; switch (key) { case 'firstName': userKey = 'first_name'; break; case 'lastName': userKey = 'last_name'; break; default: userKey = key; break; } if (currentUser[userKey] !== newState[key]) { return true; } } return false; }; close = () => { this.props.navigator.dismissModal({ animationType: 'slide-down', }); }; emitCanUpdateAccount = (enabled) => { const buttons = { rightButtons: [{...this.rightButton, disabled: !enabled}], }; this.props.navigator.setButtons(buttons); }; handleRequestError = (error) => { this.setState({error, updating: false}); this.emitCanUpdateAccount(true); if (this.scrollView) { this.scrollView.props.scrollToPosition(0, 0); } }; submitUser = preventDoubleTap(async () => { this.emitCanUpdateAccount(false); this.setState({error: null, updating: true}); const { profileImage, firstName, lastName, username, nickname, position, email, } = this.state; const user = { first_name: firstName, last_name: lastName, username, nickname, position, email, }; if (profileImage) { const {error} = await this.props.actions.handleUploadProfileImage(profileImage, this.props.currentUser.id); if (error) { this.handleRequestError(error); return; } } if (this.canUpdate()) { const {error} = await this.props.actions.updateUser(user); if (error) { this.handleRequestError(error); return; } } this.close(); }); handleUploadProfileImage = (images) => { const image = images && images.length > 0 && images[0]; this.setState({profileImage: image}); this.emitCanUpdateAccount(true); }; updateField = (field) => { this.setState(field, () => { this.emitCanUpdateAccount(this.canUpdate(field)); }); }; onNavigatorEvent = (event) => { if (event.type === 'NavBarButtonPress') { switch (event.id) { case 'update-profile': this.submitUser(); break; case 'close-settings': this.close(); break; } } }; renderFirstNameSettings = () => { const {formatMessage} = this.context.intl; const {config, currentUser, theme} = this.props; const {firstName} = this.state; const {auth_service: service} = currentUser; const disabled = (service === 'ldap' && config.LdapFristNameAttributeSet === 'true') || (service === 'saml' && config.SamlFirstNameAttributeSet === 'true'); return ( ); }; renderLastNameSettings = () => { const {formatMessage} = this.context.intl; const {config, currentUser, theme} = this.props; const {lastName} = this.state; const {auth_service: service} = currentUser; const disabled = (service === 'ldap' && config.LdapLastNameAttributeSet === 'true') || (service === 'saml' && config.SamlLastNameAttributeSet === 'true'); return ( ); }; renderUsernameSettings = () => { const {formatMessage} = this.context.intl; const {currentUser, theme} = this.props; const {username} = this.state; const disabled = currentUser.auth_service !== ''; return ( ); }; renderEmailSettings = () => { const {formatMessage} = this.context.intl; const {config, currentUser, theme} = this.props; const {email} = this.state; let helpText; let disabled = false; if (config.SendEmailNotifications !== 'true') { disabled = true; helpText = formatMessage({ id: 'user.settings.general.emailHelp1', defaultMessage: 'Email is used for sign-in, notifications, and password reset. Email requires verification if changed.', }); } else if (currentUser.auth_service !== '') { disabled = true; switch (currentUser.auth_service) { case 'gitlab': helpText = formatMessage({ id: 'user.settings.general.emailGitlabCantUpdate', defaultMessage: 'Login occurs through GitLab. Email cannot be updated. Email address used for notifications is {email}.', }, {email}); break; case 'google': helpText = formatMessage({ id: 'user.settings.general.emailGoogleCantUpdate', defaultMessage: 'Login occurs through Google Apps. Email cannot be updated. Email address used for notifications is {email}.', }, {email}); break; case 'office365': helpText = formatMessage({ id: 'user.settings.general.emailOffice365CantUpdate', defaultMessage: 'Login occurs through Office 365. Email cannot be updated. Email address used for notifications is {email}.', }, {email}); break; case 'ldap': helpText = formatMessage({ id: 'user.settings.general.emailLdapCantUpdate', defaultMessage: 'Login occurs through AD/LDAP. Email cannot be updated. Email address used for notifications is {email}.', }, {email}); break; case 'saml': helpText = formatMessage({ id: 'user.settings.general.emailSamlCantUpdate', defaultMessage: 'Login occurs through SAML. Email cannot be updated. Email address used for notifications is {email}.', }, {email}); break; } } return ( ); }; renderNicknameSettings = () => { const {formatMessage} = this.context.intl; const {config, currentUser, theme} = this.props; const {nickname} = this.state; const {auth_service: service} = currentUser; const disabled = (service === 'ldap' && config.LdapNicknameAttributeSet === 'true') || (service === 'saml' && config.SamlNicknameAttributeSet === 'true'); return ( ); }; renderPositionSettings = () => { const {formatMessage} = this.context.intl; const {config, currentUser, theme} = this.props; const {position} = this.state; const {auth_service: service} = currentUser; const disabled = (service === 'ldap' || service === 'saml') && config.PositionAttribute === 'true'; return ( ); }; scrollViewRef = (ref) => { this.scrollView = ref; }; render() { const { currentUser, theme, navigator, } = this.props; const { profileImage, error, updating, } = this.state; const style = getStyleSheet(theme); const uri = profileImage ? profileImage.uri : null; if (updating) { return ( ); } let displayError; if (error) { displayError = ( ); } return ( {displayError} {this.renderFirstNameSettings()} {this.renderLastNameSettings()} {this.renderUsernameSettings()} {this.renderEmailSettings()} {this.renderNicknameSettings()} {this.renderPositionSettings()} ); } } const getStyleSheet = makeStyleSheetFromTheme((theme) => { return { flex: { flex: 1, }, container: { backgroundColor: theme.centerChannelBg, }, scrollView: { flex: 1, backgroundColor: changeOpacity(theme.centerChannelColor, 0.03), paddingTop: 10, }, top: { padding: 25, alignItems: 'center', justifyContent: 'center', }, errorContainer: { backgroundColor: changeOpacity(theme.centerChannelColor, 0.03), width: '100%', }, errorWrapper: { justifyContent: 'center', alignItems: 'center', }, errorText: { fontSize: 14, }, separator: { height: 15, }, footer: { height: 40, width: '100%', }, }; });