From 78314c7d4d1417fd42ab48cbe41d360f80915453 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Sat, 30 Jan 2016 18:10:04 -0300 Subject: PLT-7: Refactoring frontend (chunk 6) - User settings --- .../user_settings/user_settings_general.jsx | 262 +++++++++++++++++---- 1 file changed, 221 insertions(+), 41 deletions(-) (limited to 'web/react/components/user_settings/user_settings_general.jsx') diff --git a/web/react/components/user_settings/user_settings_general.jsx b/web/react/components/user_settings/user_settings_general.jsx index df7ae4a25..8052347a0 100644 --- a/web/react/components/user_settings/user_settings_general.jsx +++ b/web/react/components/user_settings/user_settings_general.jsx @@ -13,7 +13,84 @@ import Constants from '../../utils/constants.jsx'; import * as AsyncClient from '../../utils/async_client.jsx'; import * as Utils from '../../utils/utils.jsx'; -export default class UserSettingsGeneralTab extends React.Component { +import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl'; + +const holders = defineMessages({ + usernameReserved: { + id: 'user.settings.general.usernameReserved', + defaultMessage: 'This username is reserved, please choose a new one.' + }, + usernameRestrictions: { + id: 'user.settings.general.usernameRestrictions', + defaultMessage: "'Username must begin with a letter, and contain between {min} to {max} lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'." + }, + validEmail: { + id: 'user.settings.general.validEmail', + defaultMessage: 'Please enter a valid email address' + }, + emailMatch: { + id: 'user.settings.general.emailMatch', + defaultMessage: 'The new emails you entered do not match.' + }, + checkEmail: { + id: 'user.settings.general.checkEmail', + defaultMessage: 'Check your email at {email} to verify the address.' + }, + newAddress: { + id: 'user.settings.general.newAddress', + defaultMessage: 'New Address: {email}
Check your email to verify the above address.' + }, + checkEmailNoAddress: { + id: 'user.settings.general.checkEmailNoAddress', + defaultMessage: 'Check your email to verify your new address' + }, + loginGitlab: { + id: 'user.settings.general.loginGitlab', + defaultMessage: 'Log in done through GitLab' + }, + validImage: { + id: 'user.settings.general.validImage', + defaultMessage: 'Only JPG or PNG images may be used for profile pictures' + }, + imageTooLarge: { + id: 'user.settings.general.imageTooLarge', + defaultMessage: 'Unable to upload profile image. File is too large.' + }, + uploadImage: { + id: 'user.settings.general.uploadImage', + defaultMessage: "Click 'Edit' to upload an image." + }, + imageUpdated: { + id: 'user.settings.general.imageUpdated', + defaultMessage: 'Image last updated {date}' + }, + fullName: { + id: 'user.settings.general.fullName', + defaultMessage: 'Full Name' + }, + nickname: { + id: 'user.settings.general.nickname', + defaultMessage: 'Nickname' + }, + username: { + id: 'user.settings.general.username', + defaultMessage: 'Username' + }, + email: { + id: 'user.settings.general.email', + defaultMessage: 'Email' + }, + profilePicture: { + id: 'user.settings.general.profilePicture', + defaultMessage: 'Profile Picture' + }, + close: { + id: 'user.settings.general.close', + defaultMessage: 'Close' + } +}); + +class UserSettingsGeneralTab extends React.Component { constructor(props) { super(props); this.submitActive = false; @@ -42,12 +119,13 @@ export default class UserSettingsGeneralTab extends React.Component { const user = Object.assign({}, this.props.user); const username = this.state.username.trim().toLowerCase(); + const {formatMessage} = this.props.intl; const usernameError = Utils.isValidUsername(username); if (usernameError === 'Cannot use a reserved word as a username.') { - this.setState({clientError: 'This username is reserved, please choose a new one.'}); + this.setState({clientError: formatMessage(holders.usernameReserved)}); return; } else if (usernameError) { - this.setState({clientError: 'Username must begin with a letter, and contain between ' + Constants.MIN_USERNAME_LENGTH + ' to ' + Constants.MAX_USERNAME_LENGTH + " lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'."}); + this.setState({clientError: formatMessage(holders.usernameRestrictions, {min: Constants.MIN_USERNAME_LENGTH, max: Constants.MAX_USERNAME_LENGTH})}); return; } @@ -99,13 +177,14 @@ export default class UserSettingsGeneralTab extends React.Component { const email = this.state.email.trim().toLowerCase(); const confirmEmail = this.state.confirmEmail.trim().toLowerCase(); + const {formatMessage} = this.props.intl; if (email === '' || !Utils.isEmail(email)) { - this.setState({emailError: 'Please enter a valid email address.', clientError: '', serverError: ''}); + this.setState({emailError: formatMessage(holders.validEmail), clientError: '', serverError: ''}); return; } if (email !== confirmEmail) { - this.setState({emailError: 'The new emails you entered do not match.', clientError: '', serverError: ''}); + this.setState({emailError: formatMessage(holders.emailMatch), clientError: '', serverError: ''}); return; } @@ -125,7 +204,7 @@ export default class UserSettingsGeneralTab extends React.Component { const verificationEnabled = global.window.mm_config.SendEmailNotifications === 'true' && global.window.mm_config.RequireEmailVerification === 'true' && emailUpdated; if (verificationEnabled) { - ErrorStore.storeLastError({message: 'Check your email at ' + user.email + ' to verify the address.'}); + ErrorStore.storeLastError({message: this.props.intl.formatMessage(holders.checkEmail, {email: user.email})}); ErrorStore.emitChange(); this.setState({emailChangeInProgress: true}); } @@ -152,13 +231,14 @@ export default class UserSettingsGeneralTab extends React.Component { return; } + const {formatMessage} = this.props.intl; const picture = this.state.picture; if (picture.type !== 'image/jpeg' && picture.type !== 'image/png') { - this.setState({clientError: 'Only JPG or PNG images may be used for profile pictures.'}); + this.setState({clientError: formatMessage(holders.validImage)}); return; } else if (picture.size > Constants.MAX_FILE_SIZE) { - this.setState({clientError: 'Unable to upload profile image. File is too large.'}); + this.setState({clientError: formatMessage(holders.imageTooLarge)}); return; } @@ -221,6 +301,7 @@ export default class UserSettingsGeneralTab extends React.Component { } render() { const user = this.props.user; + const {formatMessage, formatHTMLMessage} = this.props.intl; let clientError = null; if (this.state.clientError) { @@ -244,7 +325,12 @@ export default class UserSettingsGeneralTab extends React.Component { key='firstNameSetting' className='form-group' > - +
- +
- {'Notifications'} + ); const extraInfo = ( - {'By default, you will receive mention notifications when someone types your first name. '} - {'Go to '} {notifLink} {'settings to change this default.'} + + {(intro) => ( + + {intro} + {notifLink} + + + )} + ); nameSection = ( { this.updateSection('name'); @@ -333,7 +440,12 @@ export default class UserSettingsGeneralTab extends React.Component { let nicknameSection; if (this.props.activeSection === 'nickname') { - let nicknameLabel = 'Nickname'; + let nicknameLabel = ( + + ); if (Utils.isMobile()) { nicknameLabel = ''; } @@ -357,13 +469,16 @@ export default class UserSettingsGeneralTab extends React.Component { const extraInfo = ( - {'Use Nickname for a name you might be called that is different from your first name and username. This is most often used when two or more people have similar sounding names and usernames.'} + ); nicknameSection = ( { this.updateSection('nickname'); @@ -389,7 +504,12 @@ export default class UserSettingsGeneralTab extends React.Component { let usernameSection; if (this.props.activeSection === 'username') { - let usernameLabel = 'Username'; + let usernameLabel = ( + + ); if (Utils.isMobile()) { usernameLabel = ''; } @@ -411,11 +531,18 @@ export default class UserSettingsGeneralTab extends React.Component {
); - const extraInfo = ({'Pick something easy for teammates to recognize and recall.'}); + const extraInfo = ( + + + + ); usernameSection = ( { this.updateSection('username'); @@ -443,16 +570,41 @@ export default class UserSettingsGeneralTab extends React.Component { if (this.props.activeSection === 'email') { const emailEnabled = global.window.mm_config.SendEmailNotifications === 'true'; const emailVerificationEnabled = global.window.mm_config.RequireEmailVerification === 'true'; - let helpText = 'Email is used for sign-in, notifications, and password reset. Email requires verification if changed.'; + let helpText = ( + + ); if (!emailEnabled) { - helpText =
{'Email has been disabled by your system administrator. No notification emails will be sent until it is enabled.'}
; + helpText = ( +
+ +
+ ); } else if (!emailVerificationEnabled) { - helpText = 'Email is used for sign-in, notifications, and password reset.'; + helpText = ( + + ); } else if (this.state.emailChangeInProgress) { const newEmail = UserStore.getCurrentUser().email; if (newEmail) { - helpText = 'A verification email was sent to ' + newEmail + '.'; + helpText = ( + + ); } } @@ -462,7 +614,12 @@ export default class UserSettingsGeneralTab extends React.Component { inputs.push(
- +
- +
-
{'Log in occurs through GitLab. Email cannot be updated.'}
+
+ +
{helpText}
); @@ -524,20 +691,20 @@ export default class UserSettingsGeneralTab extends React.Component { if (this.state.emailChangeInProgress) { const newEmail = UserStore.getCurrentUser().email; if (newEmail) { - describe = 'New Address: ' + newEmail + '\nCheck your email to verify the above address.'; + describe = formatHTMLMessage(holders.newAddress, {email: newEmail}); } else { - describe = 'Check your email to verify your new address'; + describe = formatMessage(holders.checkEmailNoAddress); } } else { describe = UserStore.getCurrentUser().email; } } else if (this.props.user.auth_service === Constants.GITLAB_SERVICE) { - describe = 'Log in done through GitLab'; + describe = formatMessage(holders.loginGitlab); } emailSection = ( { this.updateSection('email'); @@ -550,7 +717,7 @@ export default class UserSettingsGeneralTab extends React.Component { if (this.props.activeSection === 'picture') { pictureSection = ( ); } else { - let minMessage = 'Click \'Edit\' to upload an image.'; + let minMessage = formatMessage(holders.uploadImage); if (user.last_picture_update) { - minMessage = 'Image last updated ' + Utils.displayDate(user.last_picture_update); + minMessage = formatMessage(holders.imageUpdated, { + date: new Date(user.last_picture_update).toLocaleDateString(global.window.mm_locale, {month: 'short', day: '2-digit', year: 'numeric'}) + }); } pictureSection = ( { this.updateSection('picture'); @@ -588,7 +757,7 @@ export default class UserSettingsGeneralTab extends React.Component { type='button' className='close' data-dismiss='modal' - aria-label='Close' + aria-label={formatMessage(holders.close)} onClick={this.props.closeModal} > @@ -601,11 +770,19 @@ export default class UserSettingsGeneralTab extends React.Component { className='modal-back' onClick={this.props.collapseModal} /> - {'General Settings'} +
-

{'General Settings'}

+

+ +

{nameSection}
@@ -624,6 +801,7 @@ export default class UserSettingsGeneralTab extends React.Component { } UserSettingsGeneralTab.propTypes = { + intl: intlShape.isRequired, user: React.PropTypes.object.isRequired, updateSection: React.PropTypes.func.isRequired, updateTab: React.PropTypes.func.isRequired, @@ -631,3 +809,5 @@ UserSettingsGeneralTab.propTypes = { closeModal: React.PropTypes.func.isRequired, collapseModal: React.PropTypes.func.isRequired }; + +export default injectIntl(UserSettingsGeneralTab); \ No newline at end of file -- cgit v1.2.3-1-g7c22 From 5be57bc970ebe72ecae3d421e75e3e418c479bc7 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Sun, 31 Jan 2016 12:23:16 -0300 Subject: PLT-7: Refactoring frontend (chunk 7) - Elegant way to include react Component into FormattedMessage --- .../user_settings/user_settings_general.jsx | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'web/react/components/user_settings/user_settings_general.jsx') diff --git a/web/react/components/user_settings/user_settings_general.jsx b/web/react/components/user_settings/user_settings_general.jsx index 8052347a0..f20b4b807 100644 --- a/web/react/components/user_settings/user_settings_general.jsx +++ b/web/react/components/user_settings/user_settings_general.jsx @@ -385,20 +385,12 @@ class UserSettingsGeneralTab extends React.Component { const extraInfo = ( - {(intro) => ( - - {intro} - {notifLink} - - - )} - + id='user.settings.general.notificationsExtra' + defaultMessage='By default, you will receive mention notifications when someone types your first name. Go to {notify} settings to change this default.' + values={{ + notify: (notifLink) + }} + /> ); -- cgit v1.2.3-1-g7c22