diff --git a/webapp/components/new_channel_flow.jsx b/webapp/components/new_channel_flow.jsx index 91dd04c0ce..69c2f1c4ce 100644 --- a/webapp/components/new_channel_flow.jsx +++ b/webapp/components/new_channel_flow.jsx @@ -5,7 +5,7 @@ import * as Utils from 'utils/utils.jsx'; import TeamStore from 'stores/team_store.jsx'; import {cleanUpUrlable} from 'utils/url.jsx'; -import NewChannelModal from './new_channel_modal.jsx'; +import NewChannelModal from 'components/new_channel_modal'; import ChangeURLModal from './change_url_modal.jsx'; import {FormattedMessage} from 'react-intl'; diff --git a/webapp/components/new_channel_modal/index.js b/webapp/components/new_channel_modal/index.js new file mode 100644 index 0000000000..770084fbb4 --- /dev/null +++ b/webapp/components/new_channel_modal/index.js @@ -0,0 +1,21 @@ +// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import {connect} from 'react-redux'; +import {getBool} from 'mattermost-redux/selectors/entities/preferences'; +import {isCurrentUserSystemAdmin} from 'mattermost-redux/selectors/entities/users'; +import {isCurrentUserCurrentTeamAdmin} from 'mattermost-redux/selectors/entities/teams'; +import {Preferences} from 'mattermost-redux/constants'; + +import NewChannelModal from './new_channel_modal.jsx'; + +function mapStateToProps(state, ownProps) { + return { + ...ownProps, + ctrlSend: getBool(state, Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter'), + isTeamAdmin: isCurrentUserCurrentTeamAdmin(state), + isSystemAdmin: isCurrentUserSystemAdmin(state) + }; +} + +export default connect(mapStateToProps)(NewChannelModal); diff --git a/webapp/components/new_channel_modal.jsx b/webapp/components/new_channel_modal/new_channel_modal.jsx similarity index 86% rename from webapp/components/new_channel_modal.jsx rename to webapp/components/new_channel_modal/new_channel_modal.jsx index 49103b7a86..48c2ddd152 100644 --- a/webapp/components/new_channel_modal.jsx +++ b/webapp/components/new_channel_modal/new_channel_modal.jsx @@ -10,26 +10,88 @@ import * as Utils from 'utils/utils.jsx'; import * as ChannelUtils from 'utils/channel_utils.jsx'; import Constants from 'utils/constants.jsx'; -import UserStore from 'stores/user_store.jsx'; -import TeamStore from 'stores/team_store.jsx'; -import PreferenceStore from 'stores/preference_store.jsx'; - import {FormattedMessage} from 'react-intl'; import {Modal} from 'react-bootstrap'; import React from 'react'; +import PropTypes from 'prop-types'; + +export default class NewChannelModal extends React.PureComponent { + static propTypes = { + + /** + * Set whether to show the modal or not + */ + show: PropTypes.bool.isRequired, + + /** + * The type of channel to create, 'O' or 'P' + */ + channelType: PropTypes.string.isRequired, + + /** + * The data needed to create the channel + */ + channelData: PropTypes.object.isRequired, + + /** + * Set to force form submission on CTRL/CMD + ENTER instead of ENTER + */ + ctrlSend: PropTypes.bool, + + /** + * Set to show options available to team admins + */ + isTeamAdmin: PropTypes.bool, + + /** + * Set to show options available to system admins + */ + isSystemAdmin: PropTypes.bool, + + /** + * Server error from failed channel creation + */ + serverError: PropTypes.node, + + /** + * Function used to submit the channel + */ + onSubmitChannel: PropTypes.func.isRequired, + + /** + * Function to call when modal is dimissed + */ + onModalDismissed: PropTypes.func.isRequired, + + /** + * Function to call when modal has exited + */ + onModalExited: PropTypes.func, + + /** + * Function to call to switch channel type + */ + onTypeSwitched: PropTypes.func.isRequired, + + /** + * Function to call when edit URL button is pressed + */ + onChangeURLPressed: PropTypes.func.isRequired, + + /** + * Function to call when channel data is modified + */ + onDataChanged: PropTypes.func.isRequired + } -export default class NewChannelModal extends React.Component { constructor(props) { super(props); this.handleSubmit = this.handleSubmit.bind(this); this.handleChange = this.handleChange.bind(this); this.onEnterKeyDown = this.onEnterKeyDown.bind(this); - this.onPreferenceChange = this.onPreferenceChange.bind(this); - - this.ctrlSend = PreferenceStore.getBool(Constants.Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter'); this.state = { displayNameError: '' @@ -53,22 +115,12 @@ export default class NewChannelModal extends React.Component { if (UserAgent.isInternetExplorer()) { $('body').addClass('browser--ie'); } - - PreferenceStore.addChangeListener(this.onPreferenceChange); - } - - componentWillUnmount() { - PreferenceStore.removeChangeListener(this.onPreferenceChange); - } - - onPreferenceChange() { - this.ctrlSend = PreferenceStore.getBool(Constants.Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter'); } onEnterKeyDown(e) { - if (this.ctrlSend && e.keyCode === Constants.KeyCodes.ENTER && e.ctrlKey) { + if (this.props.ctrlSend && e.keyCode === Constants.KeyCodes.ENTER && e.ctrlKey) { this.handleSubmit(e); - } else if (!this.ctrlSend && e.keyCode === Constants.KeyCodes.ENTER && !e.shiftKey && !e.altKey) { + } else if (!this.props.ctrlSend && e.keyCode === Constants.KeyCodes.ENTER && !e.shiftKey && !e.altKey) { this.handleSubmit(e); } } @@ -140,14 +192,13 @@ export default class NewChannelModal extends React.Component { ); - const isAdmin = TeamStore.isTeamAdminForCurrentTeam() || UserStore.isSystemAdminForCurrentUser(); - const isSystemAdmin = UserStore.isSystemAdminForCurrentUser(); + const isAdmin = this.props.isTeamAdmin || this.props.isSystemAdmin; - if (!ChannelUtils.showCreateOption(Constants.OPEN_CHANNEL, isAdmin, isSystemAdmin)) { + if (!ChannelUtils.showCreateOption(Constants.OPEN_CHANNEL, isAdmin, this.props.isSystemAdmin)) { createPublicChannelLink = null; } - if (!ChannelUtils.showCreateOption(Constants.PRIVATE_CHANNEL, isAdmin, isSystemAdmin)) { + if (!ChannelUtils.showCreateOption(Constants.PRIVATE_CHANNEL, isAdmin, this.props.isSystemAdmin)) { createPrivateChannelLink = null; } @@ -338,22 +389,3 @@ export default class NewChannelModal extends React.Component { ); } } - -NewChannelModal.defaultProps = { - show: false, - channelType: 'O', - serverError: null -}; -NewChannelModal.propTypes = { - show: React.PropTypes.bool.isRequired, - channelType: React.PropTypes.string.isRequired, - channelData: React.PropTypes.object.isRequired, - serverError: React.PropTypes.node, - onSubmitChannel: React.PropTypes.func.isRequired, - onModalDismissed: React.PropTypes.func.isRequired, - onModalExited: React.PropTypes.func, - onTypeSwitched: React.PropTypes.func.isRequired, - onChangeURLPressed: React.PropTypes.func.isRequired, - onDataChanged: React.PropTypes.func.isRequired -}; - diff --git a/webapp/package.json b/webapp/package.json index 44f1d9386e..84f012c55a 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -26,6 +26,7 @@ "object-assign": "4.1.1", "pdfjs-dist": "1.7.363", "perfect-scrollbar": "0.6.16", + "prop-types": "15.5.9", "react": "15.4.2", "react-addons-pure-render-mixin": "15.4.2", "react-bootstrap": "0.30.8", diff --git a/webapp/tests/components/__snapshots__/new_channel_modal.test.jsx.snap b/webapp/tests/components/__snapshots__/new_channel_modal.test.jsx.snap new file mode 100644 index 0000000000..67194d3215 --- /dev/null +++ b/webapp/tests/components/__snapshots__/new_channel_modal.test.jsx.snap @@ -0,0 +1,733 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/NewChannelModal should match snapshot, modal not showing 1`] = ` + + + + + + + +
+ +
+
+ + + + +
+
+
+ +
+ +

+ URL: /testchannel ( + + + + ) +

+
+
+
+
+ + +
+
+