mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
* Add pop-up asking if user wants to reset status * Update test snapshot * Update prop name for old uses of confirm modal * Updating checkbox (#6586) * Updating style for checkbox (#6596)
538 lines
20 KiB
JavaScript
538 lines
20 KiB
JavaScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See License.txt for license information.
|
|
|
|
import ReactDOM from 'react-dom';
|
|
import * as utils from 'utils/utils.jsx';
|
|
import Constants from 'utils/constants.jsx';
|
|
const ActionTypes = Constants.ActionTypes;
|
|
import * as GlobalActions from 'actions/global_actions.jsx';
|
|
import ModalStore from 'stores/modal_store.jsx';
|
|
import UserStore from 'stores/user_store.jsx';
|
|
import ChannelStore from 'stores/channel_store.jsx';
|
|
import TeamStore from 'stores/team_store.jsx';
|
|
import ConfirmModal from './confirm_modal.jsx';
|
|
import {inviteMembers} from 'actions/team_actions.jsx';
|
|
|
|
import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'react-intl';
|
|
|
|
import {Modal} from 'react-bootstrap';
|
|
|
|
const holders = defineMessages({
|
|
emailError: {
|
|
id: 'invite_member.emailError',
|
|
defaultMessage: 'Please enter a valid email address'
|
|
},
|
|
firstname: {
|
|
id: 'invite_member.firstname',
|
|
defaultMessage: 'First name'
|
|
},
|
|
lastname: {
|
|
id: 'invite_member.lastname',
|
|
defaultMessage: 'Last name'
|
|
},
|
|
modalTitle: {
|
|
id: 'invite_member.modalTitle',
|
|
defaultMessage: 'Discard Invitations?'
|
|
},
|
|
modalMessage: {
|
|
id: 'invite_member.modalMessage',
|
|
defaultMessage: 'You have unsent invitations, are you sure you want to discard them?'
|
|
},
|
|
modalButton: {
|
|
id: 'invite_member.modalButton',
|
|
defaultMessage: 'Yes, Discard'
|
|
}
|
|
});
|
|
|
|
import React from 'react';
|
|
|
|
class InviteMemberModal extends React.Component {
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
this.teamChange = this.teamChange.bind(this);
|
|
this.handleToggle = this.handleToggle.bind(this);
|
|
this.handleSubmit = this.handleSubmit.bind(this);
|
|
this.handleHide = this.handleHide.bind(this);
|
|
this.addInviteFields = this.addInviteFields.bind(this);
|
|
this.clearFields = this.clearFields.bind(this);
|
|
this.removeInviteFields = this.removeInviteFields.bind(this);
|
|
this.showGetTeamInviteLinkModal = this.showGetTeamInviteLinkModal.bind(this);
|
|
this.handleKeyDown = this.handleKeyDown.bind(this);
|
|
|
|
const team = TeamStore.getCurrent();
|
|
|
|
this.state = {
|
|
show: false,
|
|
inviteIds: [0],
|
|
idCount: 0,
|
|
emailErrors: {},
|
|
firstNameErrors: {},
|
|
lastNameErrors: {},
|
|
emailEnabled: global.window.mm_config.SendEmailNotifications === 'true',
|
|
userCreationEnabled: global.window.mm_config.EnableUserCreation === 'true',
|
|
showConfirmModal: false,
|
|
isSendingEmails: false,
|
|
teamType: team ? team.type : null
|
|
};
|
|
}
|
|
|
|
teamChange() {
|
|
const team = TeamStore.getCurrent();
|
|
const teamType = team ? team.type : null;
|
|
this.setState({
|
|
teamType
|
|
});
|
|
}
|
|
|
|
componentDidMount() {
|
|
ModalStore.addModalListener(ActionTypes.TOGGLE_INVITE_MEMBER_MODAL, this.handleToggle);
|
|
TeamStore.addChangeListener(this.teamChange);
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
ModalStore.removeModalListener(ActionTypes.TOGGLE_INVITE_MEMBER_MODAL, this.handleToggle);
|
|
TeamStore.removeChangeListener(this.teamChange);
|
|
}
|
|
|
|
handleToggle(value) {
|
|
this.setState({
|
|
show: value
|
|
});
|
|
}
|
|
|
|
handleSubmit() {
|
|
if (!this.state.emailEnabled) {
|
|
return;
|
|
}
|
|
|
|
var inviteIds = this.state.inviteIds;
|
|
var count = inviteIds.length;
|
|
var invites = [];
|
|
var emailErrors = this.state.emailErrors;
|
|
var firstNameErrors = this.state.firstNameErrors;
|
|
var lastNameErrors = this.state.lastNameErrors;
|
|
var valid = true;
|
|
|
|
for (var i = 0; i < count; i++) {
|
|
var invite = {};
|
|
var index = inviteIds[i];
|
|
invite.email = ReactDOM.findDOMNode(this.refs['email' + index]).value.trim();
|
|
invite.firstName = ReactDOM.findDOMNode(this.refs['first_name' + index]).value.trim();
|
|
invite.lastName = ReactDOM.findDOMNode(this.refs['last_name' + index]).value.trim();
|
|
if (invite.email !== '' || index === 0) {
|
|
if (!invite.email || !utils.isEmail(invite.email)) {
|
|
emailErrors[index] = this.props.intl.formatMessage(holders.emailError);
|
|
valid = false;
|
|
} else {
|
|
emailErrors[index] = '';
|
|
}
|
|
invites.push(invite);
|
|
}
|
|
}
|
|
|
|
this.setState({emailErrors, firstNameErrors, lastNameErrors});
|
|
|
|
if (!valid || invites.length === 0) {
|
|
return;
|
|
}
|
|
|
|
var data = {};
|
|
data.invites = invites;
|
|
|
|
this.setState({isSendingEmails: true});
|
|
|
|
inviteMembers(
|
|
data,
|
|
() => {
|
|
this.handleHide(false);
|
|
this.setState({isSendingEmails: false});
|
|
},
|
|
(err) => {
|
|
if (err.id === 'api.team.invite_members.already.app_error') {
|
|
emailErrors[err.detailed_error] = err.message;
|
|
this.setState({emailErrors});
|
|
} else {
|
|
this.setState({serverError: err.message});
|
|
}
|
|
|
|
this.setState({isSendingEmails: false});
|
|
}
|
|
);
|
|
}
|
|
|
|
handleHide(requireConfirm) {
|
|
if (requireConfirm) {
|
|
var notEmpty = false;
|
|
for (var i = 0; i < this.state.inviteIds.length; i++) {
|
|
var index = this.state.inviteIds[i];
|
|
if (ReactDOM.findDOMNode(this.refs['email' + index]).value.trim() !== '') {
|
|
notEmpty = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (notEmpty) {
|
|
this.setState({
|
|
showConfirmModal: true
|
|
});
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
this.clearFields();
|
|
|
|
this.setState({
|
|
show: false,
|
|
showConfirmModal: false
|
|
});
|
|
}
|
|
|
|
addInviteFields() {
|
|
var count = this.state.idCount + 1;
|
|
var inviteIds = this.state.inviteIds;
|
|
inviteIds.push(count);
|
|
this.setState({inviteIds, idCount: count});
|
|
}
|
|
|
|
clearFields() {
|
|
var inviteIds = this.state.inviteIds;
|
|
|
|
for (var i = 0; i < inviteIds.length; i++) {
|
|
var index = inviteIds[i];
|
|
ReactDOM.findDOMNode(this.refs['email' + index]).value = '';
|
|
ReactDOM.findDOMNode(this.refs['first_name' + index]).value = '';
|
|
ReactDOM.findDOMNode(this.refs['last_name' + index]).value = '';
|
|
}
|
|
|
|
this.setState({
|
|
inviteIds: [0],
|
|
idCount: 0,
|
|
emailErrors: {},
|
|
firstNameErrors: {},
|
|
lastNameErrors: {}
|
|
});
|
|
}
|
|
|
|
removeInviteFields(index) {
|
|
var count = this.state.idCount;
|
|
var inviteIds = this.state.inviteIds;
|
|
var i = inviteIds.indexOf(index);
|
|
if (i > -1) {
|
|
inviteIds.splice(i, 1);
|
|
}
|
|
if (!inviteIds.length) {
|
|
inviteIds.push(++count);
|
|
}
|
|
this.setState({inviteIds, idCount: count});
|
|
}
|
|
|
|
showGetTeamInviteLinkModal() {
|
|
this.handleHide(false);
|
|
|
|
GlobalActions.showGetTeamInviteLinkModal();
|
|
}
|
|
|
|
handleKeyDown(e) {
|
|
if (e.keyCode === Constants.KeyCodes.ENTER) {
|
|
e.preventDefault();
|
|
this.handleSubmit();
|
|
}
|
|
}
|
|
|
|
render() {
|
|
var currentUser = UserStore.getCurrentUser();
|
|
const {formatMessage} = this.props.intl;
|
|
|
|
if (currentUser != null && this.state.teamType != null) {
|
|
var inviteSections = [];
|
|
var inviteIds = this.state.inviteIds;
|
|
for (var i = 0; i < inviteIds.length; i++) {
|
|
var index = inviteIds[i];
|
|
var emailError = null;
|
|
if (this.state.emailErrors[index]) {
|
|
emailError = <label className='control-label'>{this.state.emailErrors[index]}</label>;
|
|
}
|
|
var firstNameError = null;
|
|
if (this.state.firstNameErrors[index]) {
|
|
firstNameError = <label className='control-label'>{this.state.firstNameErrors[index]}</label>;
|
|
}
|
|
var lastNameError = null;
|
|
if (this.state.lastNameErrors[index]) {
|
|
lastNameError = <label className='control-label'>{this.state.lastNameErrors[index]}</label>;
|
|
}
|
|
|
|
var removeButton = null;
|
|
if (index) {
|
|
removeButton = (
|
|
<div>
|
|
<button
|
|
type='button'
|
|
className='btn btn-link remove__member'
|
|
onClick={this.removeInviteFields.bind(this, index)}
|
|
>
|
|
<span className='fa fa-trash'/>
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|
|
var emailClass = 'form-group invite';
|
|
if (emailError) {
|
|
emailClass += ' has-error';
|
|
}
|
|
|
|
var nameFields = null;
|
|
|
|
var firstNameClass = 'form-group';
|
|
if (firstNameError) {
|
|
firstNameClass += ' has-error';
|
|
}
|
|
var lastNameClass = 'form-group';
|
|
if (lastNameError) {
|
|
lastNameClass += ' has-error';
|
|
}
|
|
nameFields = (
|
|
<div className='row row--invite'>
|
|
<div className='col-sm-6'>
|
|
<div className={firstNameClass}>
|
|
<input
|
|
onKeyDown={this.handleKeyDown}
|
|
type='text'
|
|
className='form-control'
|
|
ref={'first_name' + index}
|
|
placeholder={formatMessage(holders.firstname)}
|
|
maxLength='64'
|
|
disabled={!this.state.emailEnabled || !this.state.userCreationEnabled}
|
|
spellCheck='false'
|
|
/>
|
|
{firstNameError}
|
|
</div>
|
|
</div>
|
|
<div className='col-sm-6'>
|
|
<div className={lastNameClass}>
|
|
<input
|
|
onKeyDown={this.handleKeyDown}
|
|
type='text'
|
|
className='form-control'
|
|
ref={'last_name' + index}
|
|
placeholder={formatMessage(holders.lastname)}
|
|
maxLength='64'
|
|
disabled={!this.state.emailEnabled || !this.state.userCreationEnabled}
|
|
spellCheck='false'
|
|
/>
|
|
{lastNameError}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
inviteSections[index] = (
|
|
<div key={'key' + index}>
|
|
{removeButton}
|
|
<div className={emailClass}>
|
|
<input
|
|
onKeyUp={this.displayNameKeyUp}
|
|
onKeyDown={this.handleKeyDown}
|
|
type='text'
|
|
ref={'email' + index}
|
|
className='form-control'
|
|
placeholder='email@domain.com'
|
|
maxLength='64'
|
|
disabled={!this.state.emailEnabled || !this.state.userCreationEnabled}
|
|
spellCheck='false'
|
|
/>
|
|
{emailError}
|
|
</div>
|
|
{nameFields}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
var serverError = null;
|
|
if (this.state.serverError) {
|
|
serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
|
|
}
|
|
|
|
var content = null;
|
|
var sendButton = null;
|
|
|
|
var defaultChannelName = '';
|
|
if (ChannelStore.getByName(Constants.DEFAULT_CHANNEL)) {
|
|
defaultChannelName = ChannelStore.getByName(Constants.DEFAULT_CHANNEL).display_name;
|
|
}
|
|
|
|
if (this.state.emailEnabled && this.state.userCreationEnabled) {
|
|
content = (
|
|
<div>
|
|
{serverError}
|
|
<button
|
|
type='button'
|
|
className='btn btn-default'
|
|
onClick={this.addInviteFields}
|
|
>
|
|
<FormattedMessage
|
|
id='invite_member.addAnother'
|
|
defaultMessage='Add another'
|
|
/>
|
|
</button>
|
|
<br/>
|
|
<br/>
|
|
<span>
|
|
<FormattedHTMLMessage
|
|
id='invite_member.autoJoin'
|
|
defaultMessage='People invited automatically join the <strong>{channel}</strong> channel.'
|
|
values={{
|
|
channel: defaultChannelName
|
|
}}
|
|
/>
|
|
</span>
|
|
</div>
|
|
);
|
|
|
|
var sendButtonLabel = (
|
|
<FormattedMessage
|
|
id='invite_member.send'
|
|
defaultMessage='Send Invitation'
|
|
/>
|
|
);
|
|
if (this.state.isSendingEmails) {
|
|
sendButtonLabel = (
|
|
<span><i className='fa fa-spinner fa-spin'/>
|
|
<FormattedMessage
|
|
id='invite_member.sending'
|
|
defaultMessage=' Sending'
|
|
/>
|
|
</span>
|
|
);
|
|
} else if (this.state.inviteIds.length > 1) {
|
|
sendButtonLabel = (
|
|
<FormattedMessage
|
|
id='invite_member.send2'
|
|
defaultMessage='Send Invitations'
|
|
/>
|
|
);
|
|
}
|
|
|
|
sendButton = (
|
|
<button
|
|
onClick={this.handleSubmit}
|
|
type='button'
|
|
className='btn btn-primary'
|
|
disabled={this.state.isSendingEmails}
|
|
>
|
|
{sendButtonLabel}
|
|
</button>
|
|
);
|
|
} else if (this.state.userCreationEnabled) {
|
|
var teamInviteLink = null;
|
|
if (currentUser && this.state.teamType === 'O') {
|
|
var link = (
|
|
<a
|
|
href='#'
|
|
onClick={this.showGetTeamInviteLinkModal}
|
|
>
|
|
<FormattedMessage
|
|
id='invite_member.inviteLink'
|
|
defaultMessage='Team Invite Link'
|
|
/>
|
|
</a>
|
|
);
|
|
|
|
teamInviteLink = (
|
|
<p>
|
|
<FormattedMessage
|
|
id='invite_member.teamInviteLink'
|
|
defaultMessage='You can also invite people using the {link}.'
|
|
values={{
|
|
link
|
|
}}
|
|
/>
|
|
</p>
|
|
);
|
|
}
|
|
|
|
content = (
|
|
<div>
|
|
<p>
|
|
<FormattedMessage
|
|
id='invite_member.content'
|
|
defaultMessage='Email is currently disabled for your team, and email invitations cannot be sent. Contact your System Administrator to enable email and email invitations.'
|
|
/>
|
|
</p>
|
|
{teamInviteLink}
|
|
</div>
|
|
);
|
|
} else {
|
|
content = (
|
|
<div>
|
|
<p>
|
|
<FormattedMessage
|
|
id='invite_member.disabled'
|
|
defaultMessage='User creation has been disabled for your team. Please ask your Team Administrator for details.'
|
|
/>
|
|
</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<Modal
|
|
dialogClassName='modal-invite-member'
|
|
show={this.state.show}
|
|
onHide={this.handleHide.bind(this, true)}
|
|
enforceFocus={!this.state.showConfirmModal}
|
|
backdrop={this.state.isSendingEmails ? 'static' : true}
|
|
>
|
|
<Modal.Header closeButton={!this.state.isSendingEmails}>
|
|
<Modal.Title>
|
|
<FormattedMessage
|
|
id='invite_member.newMember'
|
|
defaultMessage='Send Email Invite'
|
|
/>
|
|
</Modal.Title>
|
|
</Modal.Header>
|
|
<Modal.Body ref='modalBody'>
|
|
<form role='form'>
|
|
{inviteSections}
|
|
</form>
|
|
{content}
|
|
</Modal.Body>
|
|
<Modal.Footer>
|
|
<button
|
|
type='button'
|
|
className='btn btn-default'
|
|
onClick={this.handleHide.bind(this, true)}
|
|
disabled={this.state.isSendingEmails}
|
|
>
|
|
<FormattedMessage
|
|
id='invite_member.cancel'
|
|
defaultMessage='Cancel'
|
|
/>
|
|
</button>
|
|
{sendButton}
|
|
</Modal.Footer>
|
|
</Modal>
|
|
<ConfirmModal
|
|
title={formatMessage(holders.modalTitle)}
|
|
message={formatMessage(holders.modalMessage)}
|
|
confirmButtonText={formatMessage(holders.modalButton)}
|
|
show={this.state.showConfirmModal}
|
|
onConfirm={this.handleHide.bind(this, false)}
|
|
onCancel={() => this.setState({showConfirmModal: false})}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
InviteMemberModal.propTypes = {
|
|
intl: intlShape.isRequired
|
|
};
|
|
|
|
export default injectIntl(InviteMemberModal);
|