From 78314c7d4d1417fd42ab48cbe41d360f80915453 Mon Sep 17 00:00:00 2001
From: Elias Nahum <nahumhbl@gmail.com>
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}<br />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'
                 >
-                    <label className='col-sm-5 control-label'>{'First Name'}</label>
+                    <label className='col-sm-5 control-label'>
+                        <FormattedMessage
+                            id='user.settings.general.firstName'
+                            defaultMessage='First Name'
+                        />
+                    </label>
                     <div className='col-sm-7'>
                         <input
                             className='form-control'
@@ -261,7 +347,12 @@ export default class UserSettingsGeneralTab extends React.Component {
                     key='lastNameSetting'
                     className='form-group'
                 >
-                    <label className='col-sm-5 control-label'>{'Last Name'}</label>
+                    <label className='col-sm-5 control-label'>
+                        <FormattedMessage
+                            id='user.settings.general.lastName'
+                            defaultMessage='Last Name'
+                        />
+                    </label>
                     <div className='col-sm-7'>
                         <input
                             className='form-control'
@@ -284,20 +375,36 @@ export default class UserSettingsGeneralTab extends React.Component {
                     href='#'
                     onClick={notifClick.bind(this)}
                 >
-                    {'Notifications'}
+                    <FormattedMessage
+                        id='user.settings.general.notificationsLink'
+                        defaultMessage='Notifications'
+                    />
                 </a>
             );
 
             const extraInfo = (
                 <span>
-                    {'By default, you will receive mention notifications when someone types your first name. '}
-                    {'Go to '} {notifLink} {'settings to change this default.'}
+                    <FormattedMessage
+                        id='user.settings.general.notificationsExtra1'
+                        defaultMessage='By default, you will receive mention notifications when someone types your first name. Go to '
+                    >
+                        {(intro) => (
+                            <span key='intro'>
+                                {intro}
+                                {notifLink}
+                                <FormattedMessage
+                                    id='user.settings.general.notificationsExtra2'
+                                    defaultMessage=' settings to change this default.'
+                                />
+                            </span>
+                        )}
+                    </FormattedMessage>
                 </span>
             );
 
             nameSection = (
                 <SettingItemMax
-                    title='Full Name'
+                    title={formatMessage(holders.fullName)}
                     inputs={inputs}
                     submit={this.submitName}
                     server_error={serverError}
@@ -322,7 +429,7 @@ export default class UserSettingsGeneralTab extends React.Component {
 
             nameSection = (
                 <SettingItemMin
-                    title='Full Name'
+                    title={formatMessage(holders.fullName)}
                     describe={fullName}
                     updateSection={() => {
                         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 = (
+                <FormattedMessage
+                    id='user.settings.general.nickname'
+                    defaultMessage='Nickname'
+                />
+            );
             if (Utils.isMobile()) {
                 nicknameLabel = '';
             }
@@ -357,13 +469,16 @@ export default class UserSettingsGeneralTab extends React.Component {
 
             const extraInfo = (
                 <span>
-                    {'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.'}
+                    <FormattedMessage
+                        id='user.settings.general.nicknameExtra'
+                        defaultMessage='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.'
+                    />
                 </span>
             );
 
             nicknameSection = (
                 <SettingItemMax
-                    title='Nickname'
+                    title={formatMessage(holders.nickname)}
                     inputs={inputs}
                     submit={this.submitNickname}
                     server_error={serverError}
@@ -378,7 +493,7 @@ export default class UserSettingsGeneralTab extends React.Component {
         } else {
             nicknameSection = (
                 <SettingItemMin
-                    title='Nickname'
+                    title={formatMessage(holders.nickname)}
                     describe={UserStore.getCurrentUser().nickname}
                     updateSection={() => {
                         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 = (
+                <FormattedMessage
+                    id='user.settings.general.username'
+                    defaultMessage='Username'
+                />
+            );
             if (Utils.isMobile()) {
                 usernameLabel = '';
             }
@@ -411,11 +531,18 @@ export default class UserSettingsGeneralTab extends React.Component {
                 </div>
             );
 
-            const extraInfo = (<span>{'Pick something easy for teammates to recognize and recall.'}</span>);
+            const extraInfo = (
+                <span>
+                    <FormattedMessage
+                        id='user.settings.general.usernameInfo'
+                        defaultMessage='Pick something easy for teammates to recognize and recall.'
+                    />
+                </span>
+            );
 
             usernameSection = (
                 <SettingItemMax
-                    title='Username'
+                    title={formatMessage(holders.username)}
                     inputs={inputs}
                     submit={this.submitUsername}
                     server_error={serverError}
@@ -430,7 +557,7 @@ export default class UserSettingsGeneralTab extends React.Component {
         } else {
             usernameSection = (
                 <SettingItemMin
-                    title='Username'
+                    title={formatMessage(holders.username)}
                     describe={UserStore.getCurrentUser().username}
                     updateSection={() => {
                         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 = (
+                <FormattedMessage
+                    id='user.settings.general.emailHelp1'
+                    defaultMessage='Email is used for sign-in, notifications, and password reset. Email requires verification if changed.'
+                />
+            );
 
             if (!emailEnabled) {
-                helpText = <div className='setting-list__hint text-danger'>{'Email has been disabled by your system administrator. No notification emails will be sent until it is enabled.'}</div>;
+                helpText = (
+                    <div className='setting-list__hint text-danger'>
+                        <FormattedMessage
+                            id='user.settings.general.emailHelp2'
+                            defaultMessage='Email has been disabled by your system administrator. No notification emails will be sent until it is enabled.'
+                        />
+                    </div>
+                );
             } else if (!emailVerificationEnabled) {
-                helpText = 'Email is used for sign-in, notifications, and password reset.';
+                helpText = (
+                    <FormattedMessage
+                        id='user.settings.general.emailHelp3'
+                        defaultMessage='Email is used for sign-in, notifications, and password reset.'
+                    />
+                );
             } else if (this.state.emailChangeInProgress) {
                 const newEmail = UserStore.getCurrentUser().email;
                 if (newEmail) {
-                    helpText = 'A verification email was sent to ' + newEmail + '.';
+                    helpText = (
+                        <FormattedMessage
+                            id='user.settings.general.emailHelp4'
+                            defaultMessage='A verification email was sent to {email}.'
+                            values={{
+                                email: newEmail
+                            }}
+                        />
+                    );
                 }
             }
 
@@ -462,7 +614,12 @@ export default class UserSettingsGeneralTab extends React.Component {
                 inputs.push(
                     <div key='emailSetting'>
                         <div className='form-group'>
-                            <label className='col-sm-5 control-label'>{'Primary Email'}</label>
+                            <label className='col-sm-5 control-label'>
+                                <FormattedMessage
+                                    id='user.settings.general.primaryEmail'
+                                    defaultMessage='Primary Email'
+                                />
+                            </label>
                             <div className='col-sm-7'>
                                 <input
                                     className='form-control'
@@ -478,7 +635,12 @@ export default class UserSettingsGeneralTab extends React.Component {
                 inputs.push(
                     <div key='confirmEmailSetting'>
                         <div className='form-group'>
-                            <label className='col-sm-5 control-label'>{'Confirm Email'}</label>
+                            <label className='col-sm-5 control-label'>
+                                <FormattedMessage
+                                    id='user.settings.general.confirmEmail'
+                                    defaultMessage='Confirm Email'
+                                />
+                            </label>
                             <div className='col-sm-7'>
                                 <input
                                     className='form-control'
@@ -499,7 +661,12 @@ export default class UserSettingsGeneralTab extends React.Component {
                         key='oauthEmailInfo'
                         className='form-group'
                     >
-                        <div className='setting-list__hint'>{'Log in occurs through GitLab. Email cannot be updated.'}</div>
+                        <div className='setting-list__hint'>
+                            <FormattedMessage
+                                id='user.settings.general.emailCantUpdate'
+                                defaultMessage='Log in occurs through GitLab. Email cannot be updated.'
+                            />
+                        </div>
                         {helpText}
                     </div>
                 );
@@ -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 = (
                 <SettingItemMin
-                    title='Email'
+                    title={formatMessage(holders.email)}
                     describe={describe}
                     updateSection={() => {
                         this.updateSection('email');
@@ -550,7 +717,7 @@ export default class UserSettingsGeneralTab extends React.Component {
         if (this.props.activeSection === 'picture') {
             pictureSection = (
                 <SettingPicture
-                    title='Profile Picture'
+                    title={formatMessage(holders.profilePicture)}
                     submit={this.submitPicture}
                     src={'/api/v1/users/' + user.id + '/image?time=' + user.last_picture_update + '&' + Utils.getSessionIndex()}
                     server_error={serverError}
@@ -566,13 +733,15 @@ export default class UserSettingsGeneralTab extends React.Component {
                 />
             );
         } 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 = (
                 <SettingItemMin
-                    title='Profile Picture'
+                    title={formatMessage(holders.profilePicture)}
                     describe={minMessage}
                     updateSection={() => {
                         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}
                     >
                         <span aria-hidden='true'>{'×'}</span>
@@ -601,11 +770,19 @@ export default class UserSettingsGeneralTab extends React.Component {
                             className='modal-back'
                             onClick={this.props.collapseModal}
                         />
-                        {'General Settings'}
+                        <FormattedMessage
+                            id='user.settings.general.title'
+                            defaultMessage='General Settings'
+                        />
                     </h4>
                 </div>
                 <div className='user-settings'>
-                    <h3 className='tab-header'>{'General Settings'}</h3>
+                    <h3 className='tab-header'>
+                        <FormattedMessage
+                            id='user.settings.general.title'
+                            defaultMessage='General Settings'
+                        />
+                    </h3>
                     <div className='divider-dark first'/>
                     {nameSection}
                     <div className='divider-light'/>
@@ -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 <nahumhbl@gmail.com>
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 = (
                 <span>
                     <FormattedMessage
-                        id='user.settings.general.notificationsExtra1'
-                        defaultMessage='By default, you will receive mention notifications when someone types your first name. Go to '
-                    >
-                        {(intro) => (
-                            <span key='intro'>
-                                {intro}
-                                {notifLink}
-                                <FormattedMessage
-                                    id='user.settings.general.notificationsExtra2'
-                                    defaultMessage=' settings to change this default.'
-                                />
-                            </span>
-                        )}
-                    </FormattedMessage>
+                        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)
+                        }}
+                    />
                 </span>
             );
 
-- 
cgit v1.2.3-1-g7c22

