// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. // See License.txt for license information. var utils = require('../utils/utils.jsx'); var client = require('../utils/client.jsx'); var UserStore = require('../stores/user_store.jsx'); var BrowserStore = require('../stores/browser_store.jsx'); var constants = require('../utils/constants.jsx'); WelcomePage = React.createClass({ submitNext: function (e) { if (!BrowserStore.isLocalStorageSupported()) { this.setState({storageError: 'This service requires local storage to be enabled. Please enable it or exit private browsing.'}); return; } e.preventDefault(); this.props.state.wizard = 'team_display_name'; this.props.updateParent(this.props.state); }, handleDiffEmail: function (e) { e.preventDefault(); this.setState({useDiff: true}); }, handleDiffSubmit: function (e) { e.preventDefault(); var state = {useDiff: true, serverError: ''}; var email = this.refs.email.getDOMNode().value.trim().toLowerCase(); if (!email || !utils.isEmail(email)) { state.emailError = 'Please enter a valid email address'; this.setState(state); return; } else if (!BrowserStore.isLocalStorageSupported()) { state.emailError = 'This service requires local storage to be enabled. Please enable it or exit private browsing.'; this.setState(state); return; } else { state.emailError = ''; } client.signupTeam(email, function(data) { if (data['follow_link']) { window.location.href = data['follow_link']; } else { this.props.state.wizard = 'finished'; this.props.updateParent(this.props.state); window.location.href = '/signup_team_confirm/?email=' + encodeURIComponent(team.email); } }.bind(this), function(err) { this.state.serverError = err.message; this.setState(this.state); }.bind(this) ); }, getInitialState: function() { return {useDiff: false}; }, handleKeyPress: function(event) { if (event.keyCode === 13) { this.submitNext(event); } }, componentWillMount: function() { document.addEventListener('keyup', this.handleKeyPress, false); }, componentWillUnmount: function() { document.removeEventListener('keyup', this.handleKeyPress, false); }, render: function() { client.track('signup', 'signup_team_01_welcome'); var storageError = null; if (this.state.storageError) { storageError = ; } var emailError = null; var emailDivClass = 'form-group'; if (this.state.emailError) { emailError = ; emailDivClass += ' has-error'; } var serverError = null; if (this.state.serverError) { serverError = (
); } var differentEmailLinkClass = ''; var emailDivContainerClass = 'hidden'; if (this.state.useDiff) { differentEmailLinkClass = 'hidden'; emailDivContainerClass = ''; } return (

Welcome to:

{config.SiteName}

Let's set up your new team

Please confirm your email address:

{this.props.state.team.email}

Your account will administer the new team site.
You can add other administrators later.

{storageError}

{emailError}
{serverError}
Use a different email
); } }); TeamDisplayNamePage = React.createClass({ submitBack: function (e) { e.preventDefault(); this.props.state.wizard = 'welcome'; this.props.updateParent(this.props.state); }, submitNext: function (e) { e.preventDefault(); var display_name = this.refs.name.getDOMNode().value.trim(); if (!display_name) { this.setState({nameError: 'This field is required'}); return; } this.props.state.wizard = 'team_url'; this.props.state.team.display_name = display_name; this.props.state.team.name = utils.cleanUpUrlable(display_name); this.props.updateParent(this.props.state); }, getInitialState: function() { return {}; }, handleFocus: function(e) { e.preventDefault(); e.currentTarget.select(); }, render: function() { client.track('signup', 'signup_team_02_name'); var nameError = null; var nameDivClass = 'form-group'; if (this.state.nameError) { nameError = ; nameDivClass += ' has-error'; } return (

{utils.toTitleCase(strings.Team) + ' Name'}

{nameError}
{'Name your ' + strings.Team + ' in any language. Your ' + strings.Team + ' name shows in menus and headings.'}
Back to previous step
); } }); TeamURLPage = React.createClass({ submitBack: function (e) { e.preventDefault(); this.props.state.wizard = 'team_display_name'; this.props.updateParent(this.props.state); }, submitNext: function (e) { e.preventDefault(); var name = this.refs.name.getDOMNode().value.trim(); if (!name) { this.setState({nameError: 'This field is required'}); return; } var cleanedName = utils.cleanUpUrlable(name); var urlRegex = /^[a-z0-9]+([a-z\-0-9]+|(__)?)[a-z0-9]+$/g; if (cleanedName !== name || !urlRegex.test(name)) { this.setState({nameError: 'Must be lowercase alphanumeric characters'}); return; } else if (cleanedName.length <= 3 || cleanedName.length > 15) { this.setState({nameError: 'Name must be 4 or more characters up to a maximum of 15'}); return; } for (var index = 0; index < constants.RESERVED_TEAM_NAMES.length; index++) { if (cleanedName.indexOf(constants.RESERVED_TEAM_NAMES[index]) === 0) { this.setState({nameError: 'This team name is unavailable'}); return; } } client.findTeamByName(name, function(data) { if (!data) { if (config.AllowSignupDomainsWizard) { this.props.state.wizard = 'allowed_domains'; } else { this.props.state.wizard = 'send_invites'; this.props.state.team.type = 'O'; } this.props.state.team.name = name; this.props.updateParent(this.props.state); } else { this.state.nameError = 'This URL is unavailable. Please try another.'; this.setState(this.state); } }.bind(this), function(err) { this.state.nameError = err.message; this.setState(this.state); }.bind(this) ); }, getInitialState: function() { return {}; }, handleFocus: function(e) { e.preventDefault(); e.currentTarget.select(); }, render: function() { $('body').tooltip( {selector: '[data-toggle=tooltip]', trigger: 'hover click'} ); client.track('signup', 'signup_team_03_url'); var nameError = null; var nameDivClass = 'form-group'; if (this.state.nameError) { nameError = ; nameDivClass += ' has-error'; } return (

{utils.toTitleCase(strings.Team) + ' URL'}

{utils.getWindowLocationOrigin() + '/'}
{nameError}

{'Choose the web address of your new ' + strings.Team + ':'}

Back to previous step
); } }); AllowedDomainsPage = React.createClass({ submitBack: function (e) { e.preventDefault(); this.props.state.wizard = 'team_url'; this.props.updateParent(this.props.state); }, submitNext: function (e) { e.preventDefault(); if (this.refs.open_network.getDOMNode().checked) { this.props.state.wizard = 'send_invites'; this.props.state.team.type = 'O'; this.props.updateParent(this.props.state); return; } if (this.refs.allow.getDOMNode().checked) { var name = this.refs.name.getDOMNode().value.trim(); var domainRegex = /^\w+\.\w+$/; if (!name) { this.setState({nameError: 'This field is required'}); return; } if (!name.trim().match(domainRegex)) { this.setState({nameError: 'The domain doesn\'t appear valid'}); return; } this.props.state.wizard = 'send_invites'; this.props.state.team.allowed_domains = name; this.props.state.team.type = 'I'; this.props.updateParent(this.props.state); } else { this.props.state.wizard = 'send_invites'; this.props.state.team.type = 'I'; this.props.updateParent(this.props.state); } }, getInitialState: function() { return {}; }, render: function() { client.track('signup', 'signup_team_04_allow_domains'); var nameError = null; var nameDivClass = 'form-group'; if (this.state.nameError) { nameError = ; nameDivClass += ' has-error'; } return (

Email Domain

{'Check this box to allow your ' + strings.Team + ' members to sign up using their ' + strings.Company + ' email addresses if you share the same domain--otherwise, you need to invite everyone yourself.'}

{'Your ' + strings.Team + '\'s domain for emails'}

@
{nameError}

To allow signups from multiple domains, separate each with a comma.

 
); } }); EmailItem = React.createClass({ getInitialState: function() { return {}; }, getValue: function() { return this.refs.email.getDOMNode().value.trim(); }, validate: function(teamEmail) { var email = this.refs.email.getDOMNode().value.trim().toLowerCase(); if (!email) { return true; } if (!utils.isEmail(email)) { this.state.emailError = 'Please enter a valid email address'; this.setState(this.state); return false; } else if (email === teamEmail) { this.state.emailError = 'Please use a different email than the one used at signup'; this.setState(this.state); return false; } else { this.state.emailError = ''; this.setState(this.state); return true; } }, render: function() { var emailError = null; var emailDivClass = 'form-group'; if (this.state.emailError) { emailError = ; emailDivClass += ' has-error'; } return (
{emailError}
); } }); SendInivtesPage = React.createClass({ submitBack: function (e) { e.preventDefault(); if (config.AllowSignupDomainsWizard) { this.props.state.wizard = 'allowed_domains'; } else { this.props.state.wizard = 'team_url'; } this.props.updateParent(this.props.state); }, submitNext: function (e) { e.preventDefault(); var valid = true; if (this.state.emailEnabled) { var emails = []; for (var i = 0; i < this.props.state.invites.length; i++) { if (!this.refs['email_' + i].validate(this.props.state.team.email)) { valid = false; } else { emails.push(this.refs['email_' + i].getValue()); } } if (valid) { this.props.state.invites = emails; } } if (valid) { this.props.state.wizard = 'username'; this.props.updateParent(this.props.state); } }, submitAddInvite: function (e) { e.preventDefault(); this.props.state.wizard = 'send_invites'; if (!this.props.state.invites) { this.props.state.invites = []; } this.props.state.invites.push(''); this.props.updateParent(this.props.state); }, submitSkip: function (e) { e.preventDefault(); this.props.state.wizard = 'username'; this.props.updateParent(this.props.state); }, getInitialState: function() { return { emailEnabled: client.isEmailEnabledSynchronous() }; }, render: function() { client.track('signup', 'signup_team_05_send_invites'); var content = null; var bottomContent = null; if (this.state.emailEnabled) { var emails = []; for (var i = 0; i < this.props.state.invites.length; i++) { if (i === 0) { emails.push(); } else { emails.push(); } } content = (
{emails}
Add Invitation
); bottomContent = (

{'if you prefer, you can invite ' + strings.Team + ' members later'}
and skip this step for now.

); } else { content = (
Email is currently disabled for your team, and emails cannot be sent. Contact your system administrator to enable email and email invitations.
); } return (

{'Invite ' + utils.toTitleCase(strings.Team) + ' Members'}

{content}
{bottomContent}
Back to previous step
); } }); UsernamePage = React.createClass({ submitBack: function(e) { e.preventDefault(); this.props.state.wizard = 'send_invites'; this.props.updateParent(this.props.state); }, submitNext: function(e) { e.preventDefault(); var name = this.refs.name.getDOMNode().value.trim(); var usernameError = utils.isValidUsername(name); if (usernameError === 'Cannot use a reserved word as a username.') { this.setState({nameError: 'This username is reserved, please choose a new one.'}); return; } else if (usernameError) { this.setState({nameError: 'Username must begin with a letter, and contain 3 to 15 characters in total, which may be numbers, lowercase letters, or any of the symbols \'.\', \'-\', or \'_\''}); return; } this.props.state.wizard = 'password'; this.props.state.user.username = name; this.props.updateParent(this.props.state); }, getInitialState: function() { return {}; }, render: function() { client.track('signup', 'signup_team_06_username'); var nameError = null; var nameDivClass = 'form-group'; if (this.state.nameError) { nameError = ; nameDivClass += ' has-error'; } return (

Your username

{'Select a memorable username that makes it easy for ' + strings.Team + 'mates to identify you:'}
Choose your username
Usernames must begin with a letter and contain 3 to 15 characters made up of lowercase letters, numbers, and the symbols '.', '-' and '_'
{nameError}
Back to previous step
); } }); PasswordPage = React.createClass({ submitBack: function (e) { e.preventDefault(); this.props.state.wizard = 'username'; this.props.updateParent(this.props.state); }, submitNext: function (e) { e.preventDefault(); var password = this.refs.password.getDOMNode().value.trim(); if (!password || password.length < 5) { this.setState({passwordError: 'Please enter at least 5 characters'}); return; } this.setState({passwordError: null, serverError: null}); $('#finish-button').button('loading'); var teamSignup = JSON.parse(JSON.stringify(this.props.state)); teamSignup.user.password = password; teamSignup.user.allow_marketing = true; delete teamSignup.wizard; var ctl = this; client.createTeamFromSignup(teamSignup, function(data) { client.track('signup', 'signup_team_08_complete'); var props = this.props; $('#sign-up-button').button('reset'); props.state.wizard = 'finished'; props.updateParent(props.state, true); window.location.href = utils.getWindowLocationOrigin() + '/' + props.state.team.name + '/login?email=' + encodeURIComponent(teamSignup.team.email); // client.loginByEmail(teamSignup.team.domain, teamSignup.team.email, teamSignup.user.password, // function(data) { // TeamStore.setLastName(teamSignup.team.domain); // UserStore.setLastEmail(teamSignup.team.email); // UserStore.setCurrentUser(data); // window.location.href = '/channels/town-square'; // }.bind(ctl), // function(err) { // this.setState({nameError: err.message}); // }.bind(ctl) // ); }.bind(this), function(err) { this.setState({serverError: err.message}); $('#sign-up-button').button('reset'); }.bind(this) ); }, getInitialState: function() { return {}; }, render: function() { client.track('signup', 'signup_team_07_password'); var passwordError = null; var passwordDivStyle = 'form-group'; if (this.state.passwordError) { passwordError =
; passwordDivStyle = ' has-error'; } var serverError = null; if (this.state.serverError) { serverError =
; } return (

Your password

Select a password that you'll use to login with your email address:
Email
{this.props.state.team.email}
Choose your password
Passwords must contain 5 to 50 characters. Your password will be strongest if it contains a mix of symbols, numbers, and upper and lowercase characters.
{passwordError} {serverError}

By proceeding to create your account and use {config.SiteName}, you agree to our Terms of Service and Privacy Policy. If you do not agree, you cannot use {config.SiteName}.

Back to previous step
); } }); module.exports = React.createClass({ updateParent: function(state, skipSet) { BrowserStore.setGlobalItem(this.props.hash, state); if (!skipSet) { this.setState(state); } }, getInitialState: function() { var props = BrowserStore.getGlobalItem(this.props.hash); if (!props) { props = {}; props.wizard = 'welcome'; props.team = {}; props.team.email = this.props.email; props.team.allowed_domains = ''; props.invites = []; props.invites.push(''); props.invites.push(''); props.invites.push(''); props.user = {}; props.hash = this.props.hash; props.data = this.props.data; } return props; }, render: function() { if (this.state.wizard === 'welcome') { return ; } if (this.state.wizard === 'team_display_name') { return ; } if (this.state.wizard === 'team_url') { return ; } if (this.state.wizard === 'allowed_domains') { return ; } if (this.state.wizard === 'send_invites') { return ; } if (this.state.wizard === 'username') { return ; } if (this.state.wizard === 'password') { return ; } return (
You've already completed the signup process for this invitation or this invitation has expired.
); } });