diff options
Diffstat (limited to 'webapp/components/signup')
-rw-r--r-- | webapp/components/signup/components/signup_email.jsx | 507 | ||||
-rw-r--r-- | webapp/components/signup/components/signup_ldap.jsx | 233 | ||||
-rw-r--r-- | webapp/components/signup/signup_controller.jsx | 333 |
3 files changed, 1073 insertions, 0 deletions
diff --git a/webapp/components/signup/components/signup_email.jsx b/webapp/components/signup/components/signup_email.jsx new file mode 100644 index 000000000..2d4b3f277 --- /dev/null +++ b/webapp/components/signup/components/signup_email.jsx @@ -0,0 +1,507 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import LoadingScreen from 'components/loading_screen.jsx'; + +import * as GlobalActions from 'actions/global_actions.jsx'; +import {track} from 'actions/analytics_actions.jsx'; + +import BrowserStore from 'stores/browser_store.jsx'; + +import * as Utils from 'utils/utils.jsx'; +import Client from 'client/web_client.jsx'; +import Constants from 'utils/constants.jsx'; + +import React from 'react'; +import {FormattedMessage, FormattedHTMLMessage} from 'react-intl'; +import {browserHistory, Link} from 'react-router/es6'; + +import logoImage from 'images/logo.png'; + +export default class SignupEmail extends React.Component { + static get propTypes() { + return { + location: React.PropTypes.object + }; + } + + constructor(props) { + super(props); + + this.handleSubmit = this.handleSubmit.bind(this); + + this.getInviteInfo = this.getInviteInfo.bind(this); + this.renderEmailSignup = this.renderEmailSignup.bind(this); + this.isUserValid = this.isUserValid.bind(this); + + this.state = this.getInviteInfo(); + } + + getInviteInfo() { + let data = this.props.location.query.d; + let hash = this.props.location.query.h; + const inviteId = this.props.location.query.id; + let email = ''; + let teamDisplayName = ''; + let teamName = ''; + let teamId = ''; + let loading = true; + let serverError = ''; + let noOpenServerError = false; + + if (hash && hash.length > 0) { + const parsedData = JSON.parse(data); + email = parsedData.email; + teamDisplayName = parsedData.display_name; + teamName = parsedData.name; + teamId = parsedData.id; + loading = false; + } else if (inviteId && inviteId.length > 0) { + loading = true; + Client.getInviteInfo( + inviteId, + (inviteData) => { + if (!inviteData) { + return; + } + + serverError = ''; + teamDisplayName = inviteData.display_name; + teamName = inviteData.name; + teamId = inviteData.id; + }, + () => { + noOpenServerError = true; + serverError = ( + <FormattedMessage + id='signup_user_completed.invalid_invite' + defaultMessage='The invite link was invalid. Please speak with your Administrator to receive an invitation.' + /> + ); + } + ); + + loading = false; + data = null; + hash = null; + } else { + loading = false; + } + + return { + data, + hash, + email, + teamDisplayName, + teamName, + teamId, + inviteId, + loading, + serverError, + noOpenServerError + }; + } + + finishSignup() { + GlobalActions.emitInitialLoad( + () => { + const query = this.props.location.query; + GlobalActions.loadDefaultLocale(); + if (query.redirect_to) { + browserHistory.push(query.redirect_to); + } else { + browserHistory.push('/select_team'); + } + } + ); + } + + handleSignupSuccess(user, data) { + track('signup', 'signup_user_02_complete'); + Client.loginById( + data.id, + user.password, + '', + () => { + if (this.state.hash > 0) { + BrowserStore.setGlobalItem(this.state.hash, JSON.stringify({usedBefore: true})); + } + + GlobalActions.emitInitialLoad( + () => { + const query = this.props.location.query; + if (query.redirect_to) { + browserHistory.push(query.redirect_to); + } else { + browserHistory.push('/select_team'); + } + } + ); + }, + (err) => { + if (err.id === 'api.user.login.not_verified.app_error') { + browserHistory.push('/should_verify_email?email=' + encodeURIComponent(user.email) + '&teamname=' + encodeURIComponent(this.state.teamName)); + } else { + this.setState({serverError: err.message}); + } + } + ); + } + + isUserValid() { + const providedEmail = this.refs.email.value.trim(); + if (!providedEmail) { + this.setState({ + nameError: '', + emailError: (<FormattedMessage id='signup_user_completed.required'/>), + passwordError: '', + serverError: '' + }); + return false; + } + + if (!Utils.isEmail(providedEmail)) { + this.setState({ + nameError: '', + emailError: (<FormattedMessage id='signup_user_completed.validEmail'/>), + passwordError: '', + serverError: '' + }); + return false; + } + + const providedUsername = this.refs.name.value.trim().toLowerCase(); + if (!providedUsername) { + this.setState({ + nameError: (<FormattedMessage id='signup_user_completed.required'/>), + emailError: '', + passwordError: '', + serverError: '' + }); + return false; + } + + const usernameError = Utils.isValidUsername(providedUsername); + if (usernameError === 'Cannot use a reserved word as a username.') { + this.setState({ + nameError: (<FormattedMessage id='signup_user_completed.reserved'/>), + emailError: '', + passwordError: '', + serverError: '' + }); + return false; + } else if (usernameError) { + this.setState({ + nameError: ( + <FormattedMessage + id='signup_user_completed.usernameLength' + values={{ + min: Constants.MIN_USERNAME_LENGTH, + max: Constants.MAX_USERNAME_LENGTH + }} + /> + ), + emailError: '', + passwordError: '', + serverError: '' + }); + return false; + } + + const providedPassword = this.refs.password.value; + const pwdError = Utils.isValidPassword(providedPassword); + if (pwdError) { + this.setState({ + nameError: '', + emailError: '', + passwordError: pwdError, + serverError: '' + }); + return false; + } + + return true; + } + + handleSubmit(e) { + e.preventDefault(); + + if (this.isUserValid()) { + this.setState({ + nameError: '', + emailError: '', + passwordError: '', + serverError: '' + }); + + const user = { + email: this.refs.email.value.trim(), + username: this.refs.name.value.trim().toLowerCase(), + password: this.refs.password.value, + allow_marketing: true + }; + + Client.createUserWithInvite(user, + this.state.data, + this.state.hash, + this.state.inviteId, + this.handleSignupSuccess.bind(this, user), + (err) => { + this.setState({serverError: err.message}); + } + ); + } + } + + renderEmailSignup() { + let emailError = null; + let emailHelpText = ( + <span className='help-block'> + <FormattedMessage + id='signup_user_completed.emailHelp' + defaultMessage='Valid email required for sign-up' + /> + </span> + ); + let emailDivStyle = 'form-group'; + if (this.state.emailError) { + emailError = (<label className='control-label'>{this.state.emailError}</label>); + emailHelpText = ''; + emailDivStyle += ' has-error'; + } + + let nameError = null; + let nameHelpText = ( + <span className='help-block'> + <FormattedMessage + id='signup_user_completed.userHelp' + defaultMessage="Username must begin with a letter, and contain between {min} to {max} lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'" + values={{ + min: Constants.MIN_USERNAME_LENGTH, + max: Constants.MAX_USERNAME_LENGTH + }} + /> + </span> + ); + let nameDivStyle = 'form-group'; + if (this.state.nameError) { + nameError = <label className='control-label'>{this.state.nameError}</label>; + nameHelpText = ''; + nameDivStyle += ' has-error'; + } + + let passwordError = null; + let passwordDivStyle = 'form-group'; + if (this.state.passwordError) { + passwordError = <label className='control-label'>{this.state.passwordError}</label>; + passwordDivStyle += ' has-error'; + } + + let yourEmailIs = null; + if (this.state.email) { + yourEmailIs = ( + <FormattedHTMLMessage + id='signup_user_completed.emailIs' + defaultMessage="Your email address is <strong>{email}</strong>. You'll use this address to sign in to {siteName}." + values={{ + email: this.state.email, + siteName: global.window.mm_config.SiteName + }} + /> + ); + } + + let emailContainerStyle = 'margin--extra'; + if (this.state.email) { + emailContainerStyle = 'hidden'; + } + + return ( + <form> + <div className='inner__content'> + <div className={emailContainerStyle}> + <h5><strong> + <FormattedMessage + id='signup_user_completed.whatis' + defaultMessage="What's your email address?" + /> + </strong></h5> + <div className={emailDivStyle}> + <input + type='email' + ref='email' + className='form-control' + defaultValue={this.state.email} + placeholder='' + maxLength='128' + autoFocus={true} + spellCheck='false' + autoCapitalize='off' + /> + {emailError} + {emailHelpText} + </div> + </div> + {yourEmailIs} + <div className='margin--extra'> + <h5><strong> + <FormattedMessage + id='signup_user_completed.chooseUser' + defaultMessage='Choose your username' + /> + </strong></h5> + <div className={nameDivStyle}> + <input + type='text' + ref='name' + className='form-control' + placeholder='' + maxLength={Constants.MAX_USERNAME_LENGTH} + spellCheck='false' + autoCapitalize='off' + /> + {nameError} + {nameHelpText} + </div> + </div> + <div className='margin--extra'> + <h5><strong> + <FormattedMessage + id='signup_user_completed.choosePwd' + defaultMessage='Choose your password' + /> + </strong></h5> + <div className={passwordDivStyle}> + <input + type='password' + ref='password' + className='form-control' + placeholder='' + maxLength='128' + spellCheck='false' + /> + {passwordError} + </div> + </div> + <p className='margin--extra'> + <button + type='submit' + onClick={this.handleSubmit} + className='btn-primary btn' + > + <FormattedMessage + id='signup_user_completed.create' + defaultMessage='Create Account' + /> + </button> + </p> + </div> + </form> + ); + } + + render() { + track('signup', 'signup_user_01_welcome'); + + let serverError = null; + if (this.state.serverError) { + serverError = ( + <div className={'form-group has-error'}> + <label className='control-label'>{this.state.serverError}</label> + </div> + ); + } + + if (this.state.loading) { + return (<LoadingScreen/>); + } + + let emailSignup; + if (global.window.mm_config.EnableSignUpWithEmail === 'true') { + emailSignup = this.renderEmailSignup(); + } else { + return null; + } + + let terms = null; + if (!this.state.noOpenServerError && emailSignup) { + terms = ( + <p> + <FormattedHTMLMessage + id='create_team.agreement' + defaultMessage="By proceeding to create your account and use {siteName}, you agree to our <a href='/static/help/terms.html'>Terms of Service</a> and <a href='/static/help/privacy.html'>Privacy Policy</a>. If you do not agree, you cannot use {siteName}." + values={{ + siteName: global.window.mm_config.SiteName + }} + /> + </p> + ); + } + + if (this.state.noOpenServerError) { + emailSignup = null; + } + + let description = null; + if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.CustomBrand === 'true' && global.window.mm_config.EnableCustomBrand === 'true') { + description = global.window.mm_config.CustomDescriptionText; + } else { + description = ( + <FormattedMessage + id='web.root.signup_info' + defaultMessage='All team communication in one place, searchable and accessible anywhere' + /> + ); + } + + return ( + <div> + <div className='signup-header'> + <Link to='/signup_user_complete'> + <span className='fa fa-chevron-left'/> + <FormattedMessage + id='web.header.back' + /> + </Link> + </div> + <div className='col-sm-12'> + <div className='signup-team__container padding--less'> + <img + className='signup-team-logo' + src={logoImage} + /> + <h1>{global.window.mm_config.SiteName}</h1> + <h4 className='color--light'> + {description} + </h4> + <h4 className='color--light'> + <FormattedMessage + id='signup_user_completed.lets' + defaultMessage="Let's create your account" + /> + </h4> + <span className='color--light'> + <FormattedMessage + id='signup_user_completed.haveAccount' + defaultMessage='Already have an account?' + /> + {' '} + <Link + to={'/login'} + query={this.props.location.query} + > + <FormattedMessage + id='signup_user_completed.signIn' + defaultMessage='Click here to sign in.' + /> + </Link> + </span> + {emailSignup} + {serverError} + {terms} + </div> + </div> + </div> + ); + } +} diff --git a/webapp/components/signup/components/signup_ldap.jsx b/webapp/components/signup/components/signup_ldap.jsx new file mode 100644 index 000000000..92089f2f7 --- /dev/null +++ b/webapp/components/signup/components/signup_ldap.jsx @@ -0,0 +1,233 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import FormError from 'components/form_error.jsx'; + +import * as GlobalActions from 'actions/global_actions.jsx'; +import {track} from 'actions/analytics_actions.jsx'; + +import * as Utils from 'utils/utils.jsx'; +import Client from 'client/web_client.jsx'; + +import React from 'react'; +import {FormattedMessage, FormattedHTMLMessage} from 'react-intl'; +import {browserHistory, Link} from 'react-router/es6'; + +import logoImage from 'images/logo.png'; + +export default class SignupLdap extends React.Component { + static get propTypes() { + return { + location: React.PropTypes.object + }; + } + + constructor(props) { + super(props); + + this.handleLdapSignup = this.handleLdapSignup.bind(this); + this.handleLdapSignupSuccess = this.handleLdapSignupSuccess.bind(this); + + this.state = ({ + ldapError: '' + }); + } + + handleLdapSignup(e) { + e.preventDefault(); + + this.setState({ldapError: ''}); + + Client.webLoginByLdap( + this.refs.id.value.trim(), + this.refs.password.value, + null, + this.handleLdapSignupSuccess, + (err) => { + this.setState({ + ldapError: err.message + }); + } + ); + } + + handleLdapSignupSuccess() { + if (this.props.location.query.id || this.props.location.query.h) { + Client.addUserToTeamFromInvite( + this.props.location.query.d, + this.props.location.query.h, + this.props.location.query.id, + () => { + this.finishSignup(); + }, + () => { + // there's not really a good way to deal with this, so just let the user log in like normal + this.finishSignup(); + } + ); + } else { + this.finishSignup(); + } + } + + finishSignup() { + GlobalActions.emitInitialLoad( + () => { + GlobalActions.loadDefaultLocale(); + browserHistory.push('/select_team'); + } + ); + } + + render() { + track('signup', 'signup_user_01_welcome'); + + let ldapIdPlaceholder; + if (global.window.mm_config.LdapLoginFieldName) { + ldapIdPlaceholder = global.window.mm_config.LdapLoginFieldName; + } else { + ldapIdPlaceholder = Utils.localizeMessage('login.ldap_username', 'LDAP Username'); + } + + let errorClass = ''; + if (this.state.ldapError) { + errorClass += ' has-error'; + } + + let ldapSignup; + if (global.window.mm_config.EnableLdap === 'true' && global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.LDAP) { + ldapSignup = ( + <div className='inner__content'> + <h5> + <strong> + <FormattedMessage + id='signup.ldap' + defaultMessage='LDAP Credentials' + /> + </strong> + </h5> + <form + onSubmit={this.handleLdapSignup} + > + <div className='signup__email-container'> + <FormError + error={this.state.ldapError} + margin={true} + /> + <div className={'form-group' + errorClass}> + <input + className='form-control' + name='ldapId' + ref='id' + placeholder={ldapIdPlaceholder} + spellCheck='false' + autoCapitalize='off' + /> + </div> + <div className={'form-group' + errorClass}> + <input + type='password' + className='form-control' + name='password' + ref='password' + placeholder={Utils.localizeMessage('login.password', 'Password')} + spellCheck='false' + /> + </div> + <div className='form-group'> + <button + type='submit' + className='btn btn-primary' + disabled={!this.state.ldapId || !this.state.ldapPassword} + > + <FormattedMessage + id='login.signIn' + defaultMessage='Sign in' + /> + </button> + </div> + </div> + </form> + </div> + ); + } else { + return null; + } + + let terms = null; + if (ldapSignup) { + terms = ( + <p> + <FormattedHTMLMessage + id='create_team.agreement' + defaultMessage="By proceeding to create your account and use {siteName}, you agree to our <a href='/static/help/terms.html'>Terms of Service</a> and <a href='/static/help/privacy.html'>Privacy Policy</a>. If you do not agree, you cannot use {siteName}." + values={{ + siteName: global.window.mm_config.SiteName + }} + /> + </p> + ); + } + + let description = null; + if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.CustomBrand === 'true' && global.window.mm_config.EnableCustomBrand === 'true') { + description = global.window.mm_config.CustomDescriptionText; + } else { + description = ( + <FormattedMessage + id='web.root.signup_info' + defaultMessage='All team communication in one place, searchable and accessible anywhere' + /> + ); + } + + return ( + <div> + <div className='signup-header'> + <Link to='/signup_user_complete'> + <span className='fa fa-chevron-left'/> + <FormattedMessage + id='web.header.back' + /> + </Link> + </div> + <div className='col-sm-12'> + <div className='signup-team__container padding--less'> + <img + className='signup-team-logo' + src={logoImage} + /> + <h1>{global.window.mm_config.SiteName}</h1> + <h4 className='color--light'> + {description} + </h4> + <h4 className='color--light'> + <FormattedMessage + id='signup_user_completed.lets' + defaultMessage="Let's create your account" + /> + </h4> + <span className='color--light'> + <FormattedMessage + id='signup_user_completed.haveAccount' + defaultMessage='Already have an account?' + /> + {' '} + <Link + to={'/login'} + query={this.props.location.query} + > + <FormattedMessage + id='signup_user_completed.signIn' + defaultMessage='Click here to sign in.' + /> + </Link> + </span> + {ldapSignup} + {terms} + </div> + </div> + </div> + ); + } +} diff --git a/webapp/components/signup/signup_controller.jsx b/webapp/components/signup/signup_controller.jsx new file mode 100644 index 000000000..a0587bba9 --- /dev/null +++ b/webapp/components/signup/signup_controller.jsx @@ -0,0 +1,333 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import React from 'react'; + +import FormError from 'components/form_error.jsx'; +import LoadingScreen from 'components/loading_screen.jsx'; + +import UserStore from 'stores/user_store.jsx'; +import BrowserStore from 'stores/browser_store.jsx'; + +import * as AsyncClient from 'utils/async_client.jsx'; +import Client from 'client/web_client.jsx'; +import * as GlobalActions from 'actions/global_actions.jsx'; + +import logoImage from 'images/logo.png'; +import ErrorBar from 'components/error_bar.jsx'; + +import {FormattedMessage} from 'react-intl'; +import {browserHistory, Link} from 'react-router/es6'; + +export default class SignupController extends React.Component { + constructor(props) { + super(props); + + this.renderSignupControls = this.renderSignupControls.bind(this); + + let loading = false; + let serverError = ''; + let noOpenServerError = false; + let usedBefore = false; + + if (props.location.query) { + loading = true; + const hash = props.location.query.h; + + if (hash && hash.length > 0 && !UserStore.getCurrentUser()) { + usedBefore = BrowserStore.getGlobalItem(hash); + loading = false; + } else if (global.window.mm_config.EnableOpenServer !== 'true' && !UserStore.getNoAccounts()) { + noOpenServerError = true; + loading = false; + serverError = ( + <FormattedMessage + id='signup_user_completed.no_open_server' + defaultMessage='This server does not allow open signups. Please speak with your Administrator to receive an invitation.' + /> + ); + } + } + + this.state = { + loading, + serverError, + noOpenServerError, + usedBefore + }; + } + + componentDidMount() { + AsyncClient.checkVersion(); + + if (this.props.location.query) { + const hash = this.props.location.query.h; + const data = this.props.location.query.d; + const inviteId = this.props.location.query.id; + + if ((inviteId && inviteId.length > 0) || (hash && hash.length > 0)) { + if (UserStore.getCurrentUser()) { + Client.addUserToTeamFromInvite( + data, + hash, + inviteId, + (team) => { + GlobalActions.emitInitialLoad( + () => { + browserHistory.push('/' + team.name + '/channels/town-square'); + } + ); + }, + (err) => { + this.setState({ // eslint-disable-line react/no-did-mount-set-state + serverError: err.message + }); + } + ); + } else if (!this.state.usedBefore) { + Client.getInviteInfo( + inviteId, + (inviteData) => { + if (!inviteData) { + return; + } + + this.setState({ // eslint-disable-line react/no-did-mount-set-state + serverError: '', + loading: false + }); + }, + () => { + this.setState({ // eslint-disable-line react/no-did-mount-set-state + noOpenServerError: true, + loading: false, + serverError: ( + <FormattedMessage + id='signup_user_completed.invalid_invite' + defaultMessage='The invite link was invalid. Please speak with your Administrator to receive an invitation.' + /> + ) + }); + } + ); + } + } else if (UserStore.getCurrentUser()) { + browserHistory.push('/select_team'); + } else { + this.setState({ // eslint-disable-line react/no-did-mount-set-state + loading: false + }); + } + } + } + + renderSignupControls() { + let signupControls = []; + + if (global.window.mm_config.EnableSignUpWithEmail === 'true') { + signupControls.push( + <Link + className='btn btn-custom-login btn--full email' + key='email' + to={'/signup_email' + window.location.search} + > + + <span className='icon fa fa-envelope'/> + <span> + <FormattedMessage + id='signup.email' + defaultMessage='Email and Password' + /> + </span> + </Link> + ); + } + + if (global.window.mm_config.EnableSignUpWithGitLab === 'true') { + signupControls.push( + <a + className='btn btn-custom-login btn--full gitlab' + key='gitlab' + href={Client.getOAuthRoute() + '/gitlab/signup' + window.location.search} + > + <span className='icon'/> + <span> + <FormattedMessage + id='signup.gitlab' + defaultMessage='GitLab Single-Sign-On' + /> + </span> + </a> + ); + } + + if (global.window.mm_config.EnableSignUpWithGoogle === 'true') { + signupControls.push( + <a + className='btn btn-custom-login btn--full google' + key='google' + href={Client.getOAuthRoute() + '/google/signup' + window.location.search} + > + <span className='icon'/> + <span> + <FormattedMessage + id='signup.google' + defaultMessage='Google Account' + /> + </span> + </a> + ); + } + + if (global.window.mm_config.EnableSignUpWithOffice365 === 'true') { + signupControls.push( + <a + className='btn btn-custom-login btn--full office365' + key='office365' + href={Client.getOAuthRoute() + '/office365/signup' + window.location.search} + > + <span className='icon'/> + <span> + <FormattedMessage + id='signup.office365' + defaultMessage='Office 365' + /> + </span> + </a> + ); + } + + if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_config.EnableLdap === 'true') { + signupControls.push( + <Link + className='btn btn-custom-login btn--full ldap' + key='ldap' + to={'/signup_ldap'} + > + <span className='icon fa fa-folder-open fa--margin-top'/> + <span> + <FormattedMessage + id='signup.ldap' + defaultMessage='LDAP Credentials' + /> + </span> + </Link> + ); + } + + if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_config.EnableSaml === 'true') { + let query = ''; + if (window.location.search) { + query = '&action=signup'; + } else { + query = '?action=signup'; + } + + signupControls.push( + <a + className='btn btn-custom-login btn--full saml' + key='saml' + href={'/login/sso/saml' + window.location.search + query} + > + <span className='icon fa fa-lock fa--margin-top'/> + <span> + {global.window.mm_config.SamlLoginButtonText} + </span> + </a> + ); + } + + if (signupControls.length === 0) { + const signupDisabledError = ( + <FormattedMessage + id='signup_user_completed.none' + defaultMessage='No user creation method has been enabled. Please contact an administrator for access.' + /> + ); + signupControls = ( + <FormError + error={signupDisabledError} + margin={true} + /> + ); + } + + return signupControls; + } + + render() { + if (this.state.loading) { + return (<LoadingScreen/>); + } + + if (this.state.usedBefore) { + return ( + <div> + <FormattedMessage + id='signup_user_completed.expired' + defaultMessage="You've already completed the signup process for this invitation or this invitation has expired." + /> + </div> + ); + } + + let signupControls = this.renderSignupControls(); + + let serverError = null; + if (this.state.serverError) { + serverError = ( + <div className={'form-group has-error'}> + <label className='control-label'>{this.state.serverError}</label> + </div> + ); + } + + if (this.state.noOpenServerError || this.state.usedBefore) { + signupControls = null; + } + + return ( + <div> + <ErrorBar/> + <div className='signup-header'> + <Link to='/'> + <span className='fa fa-chevron-left'/> + <FormattedMessage + id='web.header.back' + /> + </Link> + </div> + <div className='col-sm-12'> + <div className='signup-team__container'> + <img + className='signup-team-logo' + src={logoImage} + /> + <div className='signup__content'> + <h1>{global.window.mm_config.SiteName}</h1> + <h4 className='color--light'> + <FormattedMessage + id='web.root.signup_info' + /> + </h4> + <div className='margin--extra'> + <h5><strong> + <FormattedMessage + id='signup.title' + defaultMessage='Create an account with:' + /> + </strong></h5> + </div> + {signupControls} + {serverError} + </div> + </div> + </div> + </div> + ); + } +} + +SignupController.propTypes = { + location: React.PropTypes.object +};
\ No newline at end of file |