summaryrefslogtreecommitdiffstats
path: root/web/react/components
diff options
context:
space:
mode:
Diffstat (limited to 'web/react/components')
-rw-r--r--web/react/components/change_url_modal.jsx177
-rw-r--r--web/react/components/file_upload.jsx2
-rw-r--r--web/react/components/new_channel.jsx211
-rw-r--r--web/react/components/new_channel_flow.jsx206
-rw-r--r--web/react/components/new_channel_modal.jsx198
-rw-r--r--web/react/components/sidebar.jsx24
6 files changed, 598 insertions, 220 deletions
diff --git a/web/react/components/change_url_modal.jsx b/web/react/components/change_url_modal.jsx
new file mode 100644
index 000000000..28fa70c1f
--- /dev/null
+++ b/web/react/components/change_url_modal.jsx
@@ -0,0 +1,177 @@
+// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+var Modal = ReactBootstrap.Modal;
+var Utils = require('../utils/utils.jsx');
+
+export default class ChangeUrlModal extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.onURLChanged = this.onURLChanged.bind(this);
+ this.doSubmit = this.doSubmit.bind(this);
+ this.doCancel = this.doCancel.bind(this);
+
+ this.state = {
+ currentURL: props.currentURL,
+ urlError: '',
+ userEdit: false
+ };
+ }
+ componentWillReceiveProps(nextProps) {
+ // This check prevents the url being deleted when we re-render
+ // because of user status check
+ if (!this.state.userEdit) {
+ this.setState({
+ currentURL: nextProps.currentURL
+ });
+ }
+ }
+ componentDidUpdate(prevProps) {
+ if (this.props.show === true && prevProps.show === false) {
+ React.findDOMNode(this.refs.urlinput).select();
+ }
+ }
+ onURLChanged(e) {
+ const url = e.target.value.trim();
+ this.setState({currentURL: url.replace(/[^A-Za-z0-9-_]/g, '').toLowerCase(), userEdit: true});
+ }
+ getURLError(url) {
+ let error = []; //eslint-disable-line prefer-const
+ if (url.length < 2) {
+ error.push(<span key='error1'>{'Must be longer than two characters'}<br/></span>);
+ }
+ if (url.charAt(0) === '-' || url.charAt(0) === '_') {
+ error.push(<span key='error2'>{'Must start with a letter or number'}<br/></span>);
+ }
+ if (url.length > 1 && (url.charAt(url.length - 1) === '-' || url.charAt(url.length - 1) === '_')) {
+ error.push(<span key='error3'>{'Must end with a letter or number'}<br/></span>);
+ }
+ if (url.indexOf('__') > -1) {
+ error.push(<span key='error4'>{'Can not contain two underscores in a row.'}<br/></span>);
+ }
+
+ // In case of error we don't detect
+ if (error.length === 0) {
+ error.push(<span key='errorlast'>{'Invalid URL'}<br/></span>);
+ }
+ return error;
+ }
+ doSubmit(e) {
+ e.preventDefault();
+
+ const url = React.findDOMNode(this.refs.urlinput).value;
+ const cleanedURL = Utils.cleanUpUrlable(url);
+ if (cleanedURL !== url || url.length < 2 || url.indexOf('__') > -1) {
+ this.setState({urlError: this.getURLError(url)});
+ return;
+ }
+ this.setState({urlError: '', userEdit: false});
+ this.props.onModalSubmit(url);
+ }
+ doCancel() {
+ this.setState({urlError: '', userEdit: false});
+ this.props.onModalDismissed();
+ }
+ render() {
+ let urlClass = 'input-group input-group--limit';
+ let urlError = null;
+ let serverError = null;
+
+ if (this.state.urlError) {
+ urlClass += ' has-error';
+ urlError = (<p className='input__help error'>{this.state.urlError}</p>);
+ }
+
+ if (this.props.serverError) {
+ serverError = <div className='form-group has-error'><p className='input__help error'>{this.props.serverError}</p></div>;
+ }
+
+ const fullTeamUrl = Utils.getTeamURLFromAddressBar();
+ const teamURL = Utils.getShortenedTeamURL();
+
+ return (
+ <Modal
+ show={this.props.show}
+ onHide={this.doCancel}
+ >
+ <Modal.Header closeButton={true}>
+ <Modal.Title>{this.props.title}</Modal.Title>
+ </Modal.Header>
+ <form
+ role='form'
+ className='form-horizontal'
+ >
+ <Modal.Body>
+ <div className='modal-intro'>{this.props.description}</div>
+ <div className='form-group'>
+ <label className='col-sm-2 form__label control-label'>{this.props.urlLabel}</label>
+ <div className='col-sm-10'>
+ <div className={urlClass}>
+ <span
+ data-toggle='tooltip'
+ title={fullTeamUrl}
+ className='input-group-addon'
+ >
+ {teamURL}
+ </span>
+ <input
+ type='text'
+ ref='urlinput'
+ className='form-control'
+ maxLength='22'
+ onChange={this.onURLChanged}
+ value={this.state.currentURL}
+ autoFocus={true}
+ tabIndex='1'
+ />
+ </div>
+ {urlError}
+ {serverError}
+ </div>
+ </div>
+ </Modal.Body>
+ <Modal.Footer>
+ <button
+ type='button'
+ className='btn btn-default'
+ onClick={this.doCancel}
+ >
+ {'Close'}
+ </button>
+ <button
+ onClick={this.doSubmit}
+ type='submit'
+ className='btn btn-primary'
+ tabIndex='2'
+ >
+ {this.props.submitButtonText}
+ </button>
+ </Modal.Footer>
+ </form>
+ </Modal>
+ );
+ }
+}
+
+ChangeUrlModal.defaultProps = {
+ show: false,
+ title: 'Change URL',
+ desciption: '',
+ urlLabel: 'URL',
+ submitButtonText: 'Submit',
+ currentURL: '',
+ serverError: ''
+};
+
+ChangeUrlModal.propTypes = {
+ show: React.PropTypes.bool.isRequired,
+ title: React.PropTypes.string,
+ description: React.PropTypes.string,
+ urlLabel: React.PropTypes.string,
+ submitButtonText: React.PropTypes.string,
+ currentURL: React.PropTypes.string,
+ serverError: React.PropTypes.string,
+ onModalSubmit: React.PropTypes.func.isRequired,
+ onModalDismissed: React.PropTypes.func.isRequired
+};
diff --git a/web/react/components/file_upload.jsx b/web/react/components/file_upload.jsx
index bd8945878..3cb284171 100644
--- a/web/react/components/file_upload.jsx
+++ b/web/react/components/file_upload.jsx
@@ -52,7 +52,7 @@ export default class FileUpload extends React.Component {
}
// generate a unique id that can be used by other components to refer back to this upload
- var clientId = utils.generateId();
+ let clientId = utils.generateId();
// prepare data to be uploaded
var formData = new FormData();
diff --git a/web/react/components/new_channel.jsx b/web/react/components/new_channel.jsx
deleted file mode 100644
index 1a11fc652..000000000
--- a/web/react/components/new_channel.jsx
+++ /dev/null
@@ -1,211 +0,0 @@
-// 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 asyncClient = require('../utils/async_client.jsx');
-var UserStore = require('../stores/user_store.jsx');
-
-export default class NewChannelModal extends React.Component {
- constructor() {
- super();
-
- this.handleSubmit = this.handleSubmit.bind(this);
- this.displayNameKeyUp = this.displayNameKeyUp.bind(this);
- this.handleClose = this.handleClose.bind(this);
-
- this.state = {channelType: ''};
- }
- handleSubmit(e) {
- e.preventDefault();
-
- var channel = {};
- var state = {serverError: ''};
-
- channel.display_name = React.findDOMNode(this.refs.display_name).value.trim();
- if (!channel.display_name) {
- state.displayNameError = 'This field is required';
- state.inValid = true;
- } else if (channel.display_name.length > 22) {
- state.displayNameError = 'This field must be less than 22 characters';
- state.inValid = true;
- } else {
- state.displayNameError = '';
- }
-
- channel.name = React.findDOMNode(this.refs.channel_name).value.trim();
- if (!channel.name) {
- state.nameError = 'This field is required';
- state.inValid = true;
- } else if (channel.name.length > 22) {
- state.nameError = 'This field must be less than 22 characters';
- state.inValid = true;
- } else {
- var cleanedName = utils.cleanUpUrlable(channel.name);
- if (cleanedName !== channel.name) {
- state.nameError = "Must be lowercase alphanumeric characters, allowing '-' but not starting or ending with '-'";
- state.inValid = true;
- } else {
- state.nameError = '';
- }
- }
-
- this.setState(state);
-
- if (state.inValid) {
- return;
- }
-
- var cu = UserStore.getCurrentUser();
- channel.team_id = cu.team_id;
-
- channel.description = React.findDOMNode(this.refs.channel_desc).value.trim();
- channel.type = this.state.channelType;
-
- client.createChannel(channel,
- function success(data) {
- $(React.findDOMNode(this.refs.modal)).modal('hide');
-
- asyncClient.getChannel(data.id);
- utils.switchChannel(data);
-
- React.findDOMNode(this.refs.display_name).value = '';
- React.findDOMNode(this.refs.channel_name).value = '';
- React.findDOMNode(this.refs.channel_desc).value = '';
- }.bind(this),
- function error(err) {
- state.serverError = err.message;
- state.inValid = true;
- this.setState(state);
- }.bind(this)
- );
- }
- displayNameKeyUp() {
- var displayName = React.findDOMNode(this.refs.display_name).value.trim();
- var channelName = utils.cleanUpUrlable(displayName);
- React.findDOMNode(this.refs.channel_name).value = channelName;
- }
- componentDidMount() {
- var self = this;
- $(React.findDOMNode(this.refs.modal)).on('show.bs.modal', function onModalShow(e) {
- var button = e.relatedTarget;
- self.setState({channelType: $(button).attr('data-channeltype')});
- });
- $(React.findDOMNode(this.refs.modal)).on('hidden.bs.modal', this.handleClose);
- }
- componentWillUnmount() {
- $(React.findDOMNode(this.refs.modal)).off('hidden.bs.modal', this.handleClose);
- }
- handleClose() {
- $(React.findDOMNode(this)).find('.form-control').each(function clearForms() {
- this.value = '';
- });
-
- this.setState({channelType: '', displayNameError: '', nameError: '', serverError: '', inValid: false});
- }
- render() {
- var displayNameError = null;
- var nameError = null;
- var serverError = null;
- var displayNameClass = 'form-group';
- var nameClass = 'form-group';
-
- if (this.state.displayNameError) {
- displayNameError = <label className='control-label'>{this.state.displayNameError}</label>;
- displayNameClass += ' has-error';
- }
- if (this.state.nameError) {
- nameError = <label className='control-label'>{this.state.nameError}</label>;
- nameClass += ' has-error';
- }
- if (this.state.serverError) {
- serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
- }
-
- var channelTerm = 'Channel';
- if (this.state.channelType === 'P') {
- channelTerm = 'Group';
- }
-
- return (
- <div
- className='modal fade'
- id='new_channel'
- ref='modal'
- tabIndex='-1'
- role='dialog'
- aria-hidden='true'
- >
- <div className='modal-dialog'>
- <div className='modal-content'>
- <div className='modal-header'>
- <button
- type='button'
- className='close'
- data-dismiss='modal'
- >
- <span aria-hidden='true'>&times;</span>
- <span className='sr-only'>Cancel</span>
- </button>
- <h4 className='modal-title'>New {channelTerm}</h4>
- </div>
- <form role='form'>
- <div className='modal-body'>
- <div className={displayNameClass}>
- <label className='control-label'>Display Name</label>
- <input
- onKeyUp={this.displayNameKeyUp}
- type='text'
- ref='display_name'
- className='form-control'
- placeholder='Enter display name'
- maxLength='22'
- />
- {displayNameError}
- </div>
- <div className={nameClass}>
- <label className='control-label'>Handle</label>
- <input
- type='text'
- className='form-control'
- ref='channel_name'
- placeholder="lowercase alphanumeric's only"
- maxLength='22'
- />
- {nameError}
- </div>
- <div className='form-group'>
- <label className='control-label'>Description</label>
- <textarea
- className='form-control no-resize'
- ref='channel_desc'
- rows='3'
- placeholder='Description'
- maxLength='1024'
- />
- </div>
- {serverError}
- </div>
- <div className='modal-footer'>
- <button
- type='button'
- className='btn btn-default'
- data-dismiss='modal'
- >
- Cancel
- </button>
- <button
- onClick={this.handleSubmit}
- type='submit'
- className='btn btn-primary'
- >
- Create New {channelTerm}
- </button>
- </div>
- </form>
- </div>
- </div>
- </div>
- );
- }
-}
diff --git a/web/react/components/new_channel_flow.jsx b/web/react/components/new_channel_flow.jsx
new file mode 100644
index 000000000..df6a119d5
--- /dev/null
+++ b/web/react/components/new_channel_flow.jsx
@@ -0,0 +1,206 @@
+// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+var Utils = require('../utils/utils.jsx');
+var AsyncClient = require('../utils/async_client.jsx');
+var Client = require('../utils/client.jsx');
+var UserStore = require('../stores/user_store.jsx');
+
+var NewChannelModal = require('./new_channel_modal.jsx');
+var ChangeURLModal = require('./change_url_modal.jsx');
+
+const SHOW_NEW_CHANNEL = 1;
+const SHOW_EDIT_URL = 2;
+const SHOW_EDIT_URL_THEN_COMPLETE = 3;
+
+export default class NewChannelFlow extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.doSubmit = this.doSubmit.bind(this);
+ this.typeSwitched = this.typeSwitched.bind(this);
+ this.urlChangeRequested = this.urlChangeRequested.bind(this);
+ this.urlChangeSubmitted = this.urlChangeSubmitted.bind(this);
+ this.urlChangeDismissed = this.urlChangeDismissed.bind(this);
+ this.channelDataChanged = this.channelDataChanged.bind(this);
+
+ this.state = {
+ serverError: '',
+ channelType: 'O',
+ flowState: SHOW_NEW_CHANNEL,
+ channelDisplayName: '',
+ channelName: '',
+ channelDescription: '',
+ nameModified: false
+ };
+ }
+ componentWillReceiveProps(nextProps) {
+ // If we are being shown, grab channel type from props and clear
+ if (nextProps.show === true && this.props.show === false) {
+ this.setState({
+ serverError: '',
+ channelType: nextProps.channelType,
+ flowState: SHOW_NEW_CHANNEL,
+ channelDisplayName: '',
+ channelName: '',
+ channelDescription: '',
+ nameModified: false
+ });
+ }
+ }
+ doSubmit() {
+ var channel = {};
+
+ channel.display_name = this.state.channelDisplayName;
+ if (!channel.display_name) {
+ this.setState({serverError: 'Invalid Channel Name'});
+ return;
+ }
+
+ channel.name = this.state.channelName;
+ if (channel.name.length < 2) {
+ this.setState({flowState: SHOW_EDIT_URL_THEN_COMPLETE});
+ return;
+ }
+
+ const cu = UserStore.getCurrentUser();
+ channel.team_id = cu.team_id;
+ channel.description = this.state.channelDescription;
+ channel.type = this.state.channelType;
+
+ Client.createChannel(channel,
+ (data) => {
+ this.props.onModalDismissed();
+ AsyncClient.getChannel(data.id);
+ Utils.switchChannel(data);
+ },
+ (err) => {
+ if (err.message === 'Name must be 2 or more lowercase alphanumeric characters') {
+ this.setState({flowState: SHOW_EDIT_URL_THEN_COMPLETE});
+ }
+ if (err.message === 'A channel with that handle already exists') {
+ this.setState({serverError: 'A channel with that URL already exists'});
+ return;
+ }
+ this.setState({serverError: err.message});
+ }
+ );
+ }
+ typeSwitched() {
+ if (this.state.channelType === 'P') {
+ this.setState({channelType: 'O'});
+ } else {
+ this.setState({channelType: 'P'});
+ }
+ }
+ urlChangeRequested() {
+ this.setState({flowState: SHOW_EDIT_URL});
+ }
+ urlChangeSubmitted(newURL) {
+ if (this.state.flowState === SHOW_EDIT_URL_THEN_COMPLETE) {
+ this.setState({channelName: newURL, nameModified: true}, this.doSubmit);
+ } else {
+ this.setState({flowState: SHOW_NEW_CHANNEL, serverError: '', channelName: newURL, nameModified: true});
+ }
+ }
+ urlChangeDismissed() {
+ this.setState({flowState: SHOW_NEW_CHANNEL});
+ }
+ channelDataChanged(data) {
+ this.setState({
+ channelDisplayName: data.displayName,
+ channelDescription: data.description
+ });
+ if (!this.state.nameModified) {
+ this.setState({channelName: Utils.cleanUpUrlable(data.displayName.trim())});
+ }
+ }
+ render() {
+ const channelData = {
+ name: this.state.channelName,
+ displayName: this.state.channelDisplayName,
+ description: this.state.channelDescription
+ };
+
+ let showChannelModal = false;
+ let showGroupModal = false;
+ let showChangeURLModal = false;
+
+ let changeURLTitle = '';
+ let changeURLSubmitButtonText = '';
+ let channelTerm = '';
+
+ // Only listen to flow state if we are being shown
+ if (this.props.show) {
+ switch (this.state.flowState) {
+ case SHOW_NEW_CHANNEL:
+ if (this.state.channelType === 'O') {
+ showChannelModal = true;
+ channelTerm = 'Channel';
+ } else {
+ showGroupModal = true;
+ channelTerm = 'Group';
+ }
+ break;
+ case SHOW_EDIT_URL:
+ showChangeURLModal = true;
+ changeURLTitle = 'Change ' + channelTerm + ' URL';
+ changeURLSubmitButtonText = 'Change ' + channelTerm + ' URL';
+ break;
+ case SHOW_EDIT_URL_THEN_COMPLETE:
+ showChangeURLModal = true;
+ changeURLTitle = 'Set ' + channelTerm + ' URL';
+ changeURLSubmitButtonText = 'Create ' + channelTerm;
+ break;
+ }
+ }
+ return (
+ <span>
+ <NewChannelModal
+ show={showChannelModal}
+ channelType={'O'}
+ channelData={channelData}
+ serverError={this.state.serverError}
+ onSubmitChannel={this.doSubmit}
+ onModalDismissed={this.props.onModalDismissed}
+ onTypeSwitched={this.typeSwitched}
+ onChangeURLPressed={this.urlChangeRequested}
+ onDataChanged={this.channelDataChanged}
+ />
+ <NewChannelModal
+ show={showGroupModal}
+ channelType={'P'}
+ channelData={channelData}
+ serverError={this.state.serverError}
+ onSubmitChannel={this.doSubmit}
+ onModalDismissed={this.props.onModalDismissed}
+ onTypeSwitched={this.typeSwitched}
+ onChangeURLPressed={this.urlChangeRequested}
+ onDataChanged={this.channelDataChanged}
+ />
+ <ChangeURLModal
+ show={showChangeURLModal}
+ title={changeURLTitle}
+ description={'Some characters are not allowed in URLs and may be removed.'}
+ urlLabel={channelTerm + ' URL'}
+ submitButtonText={changeURLSubmitButtonText}
+ currentURL={this.state.channelName}
+ serverError={this.state.serverError}
+ onModalSubmit={this.urlChangeSubmitted}
+ onModalDismissed={this.urlChangeDismissed}
+ />
+ </span>
+ );
+ }
+}
+
+NewChannelFlow.defaultProps = {
+ show: false,
+ channelType: 'O'
+};
+
+NewChannelFlow.propTypes = {
+ show: React.PropTypes.bool.isRequired,
+ channelType: React.PropTypes.string.isRequired,
+ onModalDismissed: React.PropTypes.func.isRequired
+};
diff --git a/web/react/components/new_channel_modal.jsx b/web/react/components/new_channel_modal.jsx
new file mode 100644
index 000000000..2bf645dc5
--- /dev/null
+++ b/web/react/components/new_channel_modal.jsx
@@ -0,0 +1,198 @@
+// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+const Utils = require('../utils/utils.jsx');
+var Modal = ReactBootstrap.Modal;
+
+export default class NewChannelModal extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.handleSubmit = this.handleSubmit.bind(this);
+ this.handleChange = this.handleChange.bind(this);
+
+ this.state = {
+ displayNameError: ''
+ };
+ }
+ componentWillReceiveProps(nextProps) {
+ if (nextProps.show === true && this.props.show === false) {
+ this.setState({
+ displayNameError: ''
+ });
+ }
+ }
+ handleSubmit(e) {
+ e.preventDefault();
+
+ const displayName = React.findDOMNode(this.refs.display_name).value.trim();
+ if (displayName.length < 1) {
+ this.setState({displayNameError: 'This field is required'});
+ return;
+ }
+
+ this.props.onSubmitChannel();
+ }
+ handleChange() {
+ const newData = {
+ displayName: React.findDOMNode(this.refs.display_name).value,
+ description: React.findDOMNode(this.refs.channel_desc).value
+ };
+ this.props.onDataChanged(newData);
+ }
+ render() {
+ var displayNameError = null;
+ var serverError = null;
+ var displayNameClass = 'form-group';
+
+ if (this.state.displayNameError) {
+ displayNameError = <p className='input__help error'>{this.state.displayNameError}</p>;
+ displayNameClass += ' has-error';
+ }
+
+ if (this.props.serverError) {
+ serverError = <div className='form-group has-error'><p className='input__help error'>{this.props.serverError}</p></div>;
+ }
+
+ var channelTerm = '';
+ var channelSwitchText = '';
+ switch (this.props.channelType) {
+ case 'P':
+ channelTerm = 'Group';
+ channelSwitchText = (
+ <div className='modal-intro'>
+ {'Create a new private group with restricted membership. '}
+ <a
+ href='#'
+ onClick={this.props.onTypeSwitched}
+ >
+ {'Create a public channel'}
+ </a>
+ </div>
+ );
+ break;
+ case 'O':
+ channelTerm = 'Channel';
+ channelSwitchText = (
+ <div className='modal-intro'>
+ {'Create a new public channel anyone can join. '}
+ <a
+ href='#'
+ onClick={this.props.onTypeSwitched}
+ >
+ {'Create a private group'}
+ </a>
+ </div>
+ );
+ break;
+ }
+
+ const prettyTeamURL = Utils.getShortenedTeamURL();
+
+ return (
+ <span>
+ <Modal
+ show={this.props.show}
+ onHide={this.props.onModalDismissed}
+ >
+ <Modal.Header closeButton={true}>
+ <Modal.Title>{'New ' + channelTerm}</Modal.Title>
+ </Modal.Header>
+ <form
+ role='form'
+ className='form-horizontal'
+ >
+ <Modal.Body>
+ <div>
+ {channelSwitchText}
+ </div>
+ <div className={displayNameClass}>
+ <label className='col-sm-2 form__label control-label'>{'Name'}</label>
+ <div className='col-sm-10'>
+ <input
+ onChange={this.handleChange}
+ type='text'
+ ref='display_name'
+ className='form-control'
+ placeholder='Ex: "Bugs", "Marketing", "办公室恋情"'
+ maxLength='22'
+ value={this.props.channelData.displayName}
+ autoFocus={true}
+ tabIndex='1'
+ />
+ {displayNameError}
+ <p className='input__help'>
+ {'Channel URL: ' + prettyTeamURL + this.props.channelData.name + ' ('}
+ <a
+ href='#'
+ onClick={this.props.onChangeURLPressed}
+ >
+ {'change this URL'}
+ </a>
+ {')'}
+ </p>
+ </div>
+ </div>
+ <div className='form-group less'>
+ <div className='col-sm-2'>
+ <label className='form__label control-label'>{'Description'}</label>
+ <label className='form__label light'>{'(optional)'}</label>
+ </div>
+ <div className='col-sm-10'>
+ <textarea
+ className='form-control no-resize'
+ ref='channel_desc'
+ rows='4'
+ placeholder='Description'
+ maxLength='1024'
+ value={this.props.channelData.description}
+ onChange={this.handleChange}
+ tabIndex='2'
+ />
+ <p className='input__help'>
+ {'The purpose of your channel. To help others decide whether to join.'}
+ </p>
+ {serverError}
+ </div>
+ </div>
+ </Modal.Body>
+ <Modal.Footer>
+ <button
+ type='button'
+ className='btn btn-default'
+ onClick={this.props.onModalDismissed}
+ >
+ {'Cancel'}
+ </button>
+ <button
+ onClick={this.handleSubmit}
+ type='submit'
+ className='btn btn-primary'
+ tabIndex='3'
+ >
+ {'Create New ' + channelTerm}
+ </button>
+ </Modal.Footer>
+ </form>
+ </Modal>
+ </span>
+ );
+ }
+}
+
+NewChannelModal.defaultProps = {
+ show: false,
+ channelType: 'O',
+ serverError: ''
+};
+NewChannelModal.propTypes = {
+ show: React.PropTypes.bool.isRequired,
+ channelType: React.PropTypes.string.isRequired,
+ channelData: React.PropTypes.object.isRequired,
+ serverError: React.PropTypes.string,
+ onSubmitChannel: React.PropTypes.func.isRequired,
+ onModalDismissed: React.PropTypes.func.isRequired,
+ onTypeSwitched: React.PropTypes.func.isRequired,
+ onChangeURLPressed: React.PropTypes.func.isRequired,
+ onDataChanged: React.PropTypes.func.isRequired
+};
diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx
index ad934d271..977fecb5c 100644
--- a/web/react/components/sidebar.jsx
+++ b/web/react/components/sidebar.jsx
@@ -12,6 +12,7 @@ var Utils = require('../utils/utils.jsx');
var SidebarHeader = require('./sidebar_header.jsx');
var SearchBox = require('./search_bar.jsx');
var Constants = require('../utils/constants.jsx');
+var NewChannelFlow = require('./new_channel_flow.jsx');
export default class Sidebar extends React.Component {
constructor(props) {
@@ -28,6 +29,7 @@ export default class Sidebar extends React.Component {
this.createChannelElement = this.createChannelElement.bind(this);
this.state = this.getStateFromStores();
+ this.state.modal = '';
this.state.loadingDMChannel = -1;
}
getStateFromStores() {
@@ -473,8 +475,18 @@ export default class Sidebar extends React.Component {
);
}
+ let showChannelModal = false;
+ if (this.state.modal !== '') {
+ showChannelModal = true;
+ }
+
return (
<div>
+ <NewChannelFlow
+ show={showChannelModal}
+ channelType={this.state.modal}
+ onModalDismissed={() => this.setState({modal: ''})}
+ />
<SidebarHeader
teamDisplayName={this.props.teamDisplayName}
teamType={this.props.teamType}
@@ -508,11 +520,9 @@ export default class Sidebar extends React.Component {
<a
className='add-channel-btn'
href='#'
- data-toggle='modal'
- data-target='#new_channel'
- data-channeltype='O'
+ onClick={() => this.setState({modal: 'O'})}
>
- +
+ {'+'}
</a>
</h4>
</li>
@@ -537,11 +547,9 @@ export default class Sidebar extends React.Component {
<a
className='add-channel-btn'
href='#'
- data-toggle='modal'
- data-target='#new_channel'
- data-channeltype='P'
+ onClick={() => this.setState({modal: 'P'})}
>
- +
+ {'+'}
</a>
</h4>
</li>