Skip to content

Commit

Permalink
Refactor login, claim and create_team into views and add actions (#3110)
Browse files Browse the repository at this point in the history
  • Loading branch information
jwilander authored and hmhealey committed May 26, 2016
1 parent 9c0caaa commit 6fecfcc
Show file tree
Hide file tree
Showing 44 changed files with 162 additions and 148 deletions.
12 changes: 12 additions & 0 deletions webapp/actions/analytics_actions.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

import Client from 'utils/web_client.jsx';

export function track(category, action, label, property, value) {
Client.track(category, action, label, property, value);
}

export function trackPage() {
Client.trackPage();
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import * as Utils from 'utils/utils.jsx';
import * as Websockets from './websocket_actions.jsx';
import * as I18n from 'i18n/i18n.jsx';

import {trackPage} from 'actions/analytics_actions.jsx';

import {browserHistory} from 'react-router';

import en from 'i18n/en.json';
Expand All @@ -40,7 +42,7 @@ export function emitChannelClickEvent(channel) {
AsyncClient.getChannelExtraInfo(chan.id);
AsyncClient.updateLastViewedAt(chan.id);
AsyncClient.getPosts(chan.id);
Client.trackPage();
trackPage();

AppDispatcher.handleViewAction({
type: ActionTypes.CLICK_CHANNEL,
Expand Down
38 changes: 38 additions & 0 deletions webapp/actions/team_actions.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

import UserStore from 'stores/user_store.jsx';

import Constants from 'utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;

import * as AsyncClient from 'utils/async_client.jsx';
import Client from 'utils/web_client.jsx';
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';

import {browserHistory} from 'react-router';

export function checkIfTeamExists(teamName, onSuccess, onError) {
Client.findTeamByName(teamName, onSuccess, onError);
}

export function createTeam(team, onSuccess, onError) {
Client.createTeam(team,
(rteam) => {
AsyncClient.getDirectProfiles();

AppDispatcher.handleServerAction({
type: ActionTypes.CREATED_TEAM,
team: rteam,
member: {team_id: rteam.id, user_id: UserStore.getCurrentId(), roles: 'admin'}
});

browserHistory.push('/' + rteam.name + '/channels/town-square');

if (onSuccess) {
onSuccess(rteam);
}
},
onError
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import NotificationStore from 'stores/notification_store.jsx'; //eslint-disable-
import Client from 'utils/web_client.jsx';
import * as Utils from 'utils/utils.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import * as GlobalActions from 'action_creators/global_actions.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';

import Constants from 'utils/constants.jsx';
const SocketEvents = Constants.SocketEvents;
Expand Down
2 changes: 1 addition & 1 deletion webapp/components/admin_console/admin_navbar_dropdown.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import ReactDOM from 'react-dom';

import TeamStore from 'stores/team_store.jsx';
import Constants from 'utils/constants.jsx';
import * as GlobalActions from 'action_creators/global_actions.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';

import {FormattedMessage} from 'react-intl';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {Link} from 'react-router';

import logoImage from 'images/logo.png';

export default class Claim extends React.Component {
export default class ClaimController extends React.Component {
constructor(props) {
super(props);

Expand Down Expand Up @@ -51,9 +51,9 @@ export default class Claim extends React.Component {
}
}

Claim.defaultProps = {
ClaimController.defaultProps = {
};
Claim.propTypes = {
ClaimController.propTypes = {
location: React.PropTypes.object.isRequired,
children: React.PropTypes.node
};
2 changes: 1 addition & 1 deletion webapp/components/create_comment.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import MsgTyping from './msg_typing.jsx';
import FileUpload from './file_upload.jsx';
import FilePreview from './file_preview.jsx';
import * as Utils from 'utils/utils.jsx';
import * as GlobalActions from 'action_creators/global_actions.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';

import Constants from 'utils/constants.jsx';

Expand Down
2 changes: 1 addition & 1 deletion webapp/components/create_post.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import PostDeletedModal from './post_deleted_modal.jsx';
import TutorialTip from './tutorial/tutorial_tip.jsx';

import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import * as GlobalActions from 'action_creators/global_actions.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';
import Client from 'utils/web_client.jsx';
import * as Utils from 'utils/utils.jsx';

Expand Down
38 changes: 12 additions & 26 deletions webapp/components/create_team/components/display_name.jsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,19 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

import ReactDOM from 'react-dom';
import * as utils from 'utils/utils.jsx';
import Client from 'utils/web_client.jsx';
import {Link} from 'react-router';
import {track} from 'actions/analytics_actions.jsx';

import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'react-intl';
import * as Utils from 'utils/utils.jsx';
import Constants from 'utils/constants.jsx';

import logoImage from 'images/logo.png';

const holders = defineMessages({
required: {
id: 'create_team.display_name.required',
defaultMessage: 'This field is required'
},
charLength: {
id: 'create_team.display_name.charLength',
defaultMessage: 'Name must be 4 or more characters up to a maximum of 15'
}
});

import React from 'react';
import ReactDOM from 'react-dom';
import {Link} from 'react-router';
import {FormattedMessage} from 'react-intl';

class TeamSignupDisplayNamePage extends React.Component {
export default class TeamSignupDisplayNamePage extends React.Component {
constructor(props) {
super(props);

Expand All @@ -35,19 +25,18 @@ class TeamSignupDisplayNamePage extends React.Component {
submitNext(e) {
e.preventDefault();

const {formatMessage} = this.props.intl;
var displayName = ReactDOM.findDOMNode(this.refs.name).value.trim();
if (!displayName) {
this.setState({nameError: formatMessage(holders.required)});
this.setState({nameError: Utils.localizeMessage('create_team.display_name.required', 'This field is required')});
return;
} else if (displayName.length < 4 || displayName.length > 15) {
this.setState({nameError: formatMessage(holders.charLength)});
} else if (displayName.length < Constants.MIN_TEAMNAME_LENGTH || displayName.length > Constants.MAX_TEAMNAME_LENGTH) {
this.setState({nameError: Utils.localizeMessage('create_team.display_name.charLength', 'Name must be 4 or more characters up to a maximum of 15')});
return;
}

this.props.state.wizard = 'team_url';
this.props.state.team.display_name = displayName;
this.props.state.team.name = utils.cleanUpUrlable(displayName);
this.props.state.team.name = Utils.cleanUpUrlable(displayName);
this.props.updateParent(this.props.state);
}

Expand All @@ -57,7 +46,7 @@ class TeamSignupDisplayNamePage extends React.Component {
}

render() {
Client.track('signup', 'signup_team_02_name');
track('signup', 'signup_team_02_name');

var nameError = null;
var nameDivClass = 'form-group';
Expand Down Expand Up @@ -128,9 +117,6 @@ class TeamSignupDisplayNamePage extends React.Component {
}

TeamSignupDisplayNamePage.propTypes = {
intl: intlShape.isRequired,
state: React.PropTypes.object,
updateParent: React.PropTypes.func
};

export default injectIntl(TeamSignupDisplayNamePage);
95 changes: 31 additions & 64 deletions webapp/components/create_team/components/team_url.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,20 @@
// See License.txt for license information.

import $ from 'jquery';
import ReactDOM from 'react-dom';

import * as Utils from 'utils/utils.jsx';
import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import TeamStore from 'stores/team_store.jsx';
import UserStore from 'stores/user_store.jsx';
import Constants from 'utils/constants.jsx';
import {browserHistory} from 'react-router';

import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'react-intl';
import {checkIfTeamExists, createTeam} from 'actions/team_actions.jsx';
import {track} from 'actions/analytics_actions.jsx';
import Constants from 'utils/constants.jsx';

import logoImage from 'images/logo.png';

const holders = defineMessages({
required: {
id: 'create_team.team_url.required',
defaultMessage: 'This field is required'
},
regex: {
id: 'create_team.team_url.regex',
defaultMessage: "Use only lower case letters, numbers and dashes. Must start with a letter and can't end in a dash."
},
charLength: {
id: 'create_team.team_url.charLength',
defaultMessage: 'Name must be 4 or more characters up to a maximum of 15'
},
taken: {
id: 'create_team.team_url.taken',
defaultMessage: 'URL is taken or contains a reserved word'
},
unavailable: {
id: 'create_team.team_url.unavailable',
defaultMessage: 'This URL is unavailable. Please try another.'
}
});

import React from 'react';
import ReactDOM from 'react-dom';
import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';

class TeamUrl extends React.Component {
export default class TeamUrl extends React.Component {
constructor(props) {
super(props);

Expand All @@ -58,28 +33,27 @@ class TeamUrl extends React.Component {
submitNext(e) {
e.preventDefault();

const {formatMessage} = this.props.intl;
const name = ReactDOM.findDOMNode(this.refs.name).value.trim();
if (!name) {
this.setState({nameError: formatMessage(holders.required)});
this.setState({nameError: Utils.localizeMessage('create_team.team_url.required', 'This field is required')});
return;
}

const cleanedName = Utils.cleanUpUrlable(name);

const urlRegex = /^[a-z]+([a-z\-0-9]+|(__)?)[a-z0-9]+$/g;
if (cleanedName !== name || !urlRegex.test(name)) {
this.setState({nameError: formatMessage(holders.regex)});
this.setState({nameError: Utils.localizeMessage('create_team.team_url.regex', "Use only lower case letters, numbers and dashes. Must start with a letter and can't end in a dash.")});
return;
} else if (cleanedName.length < 4 || cleanedName.length > 15) {
this.setState({nameError: formatMessage(holders.charLength)});
} else if (cleanedName.length < Constants.MIN_TEAMNAME_LENGTH || cleanedName.length > Constants.MAX_TEAMNAME_LENGTH) {
this.setState({nameError: Utils.localizeMessage('create_team.team_url.charLength', 'Name must be 4 or more characters up to a maximum of 15')});
return;
}

if (global.window.mm_config.RestrictTeamNames === 'true') {
for (let index = 0; index < Constants.RESERVED_TEAM_NAMES.length; index++) {
if (cleanedName.indexOf(Constants.RESERVED_TEAM_NAMES[index]) === 0) {
this.setState({nameError: formatMessage(holders.taken)});
this.setState({nameError: Utils.localizeMessage('create_team.team_url.taken', 'URL is taken or contains a reserved word')});
return;
}
}
Expand All @@ -90,46 +64,42 @@ class TeamUrl extends React.Component {
teamSignup.team.type = 'O';
teamSignup.team.name = name;

Client.findTeamByName(name,
(findTeam) => {
if (findTeam) {
this.setState({nameError: formatMessage(holders.unavailable)});
$('#finish-button').button('reset');
} else {
Client.createTeam(teamSignup.team,
(team) => {
Client.track('signup', 'signup_team_08_complete');
$('#sign-up-button').button('reset');
AsyncClient.getDirectProfiles();
TeamStore.saveTeam(team);
TeamStore.appendTeamMember({team_id: team.id, user_id: UserStore.getCurrentId(), roles: 'admin'});
TeamStore.emitChange();
browserHistory.push('/' + team.name + '/channels/town-square');
},
(err) => {
this.setState({nameError: err.message});
$('#finish-button').button('reset');
}
);

checkIfTeamExists(name,
(foundTeam) => {
if (foundTeam) {
this.setState({nameError: Utils.localizeMessage('create_team.team_url.unavailable', 'This URL is unavailable. Please try another.')});
$('#finish-button').button('reset');
return;
}

createTeam(teamSignup.team,
() => {
track('signup', 'signup_team_08_complete');
$('#sign-up-button').button('reset');
},
(err) => {
this.setState({nameError: err.message});
$('#finish-button').button('reset');
}
);
},
(err) => {
this.setState({nameError: err.message});
$('#finish-button').button('reset');
}
);
}

handleFocus(e) {
e.preventDefault();

e.currentTarget.select();
}

render() {
$('body').tooltip({selector: '[data-toggle=tooltip]', trigger: 'hover click'});

Client.track('signup', 'signup_team_03_url');
track('signup', 'signup_team_03_url');

let nameError = null;
let nameDivClass = 'form-group';
Expand Down Expand Up @@ -223,9 +193,6 @@ class TeamUrl extends React.Component {
}

TeamUrl.propTypes = {
intl: intlShape.isRequired,
state: React.PropTypes.object,
updateParent: React.PropTypes.func
};

export default injectIntl(TeamUrl);
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {browserHistory, Link} from 'react-router';

import React from 'react';

export default class CreateTeam extends React.Component {
export default class CreateTeamController extends React.Component {
constructor(props) {
super(props);

Expand Down Expand Up @@ -67,6 +67,6 @@ export default class CreateTeam extends React.Component {
}
}

CreateTeam.propTypes = {
CreateTeamController.propTypes = {
children: React.PropTypes.node
};
2 changes: 1 addition & 1 deletion webapp/components/edit_post_modal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import $ from 'jquery';
import ReactDOM from 'react-dom';
import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import * as GlobalActions from 'action_creators/global_actions.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';
import Textbox from './textbox.jsx';
import BrowserStore from 'stores/browser_store.jsx';
import PostStore from 'stores/post_store.jsx';
Expand Down

0 comments on commit 6fecfcc

Please sign in to comment.