Merge pull request #553 from mattermost/MM-2065
MM-2065 Cosmetic refactoring for ESLint
Этот коммит содержится в:
@@ -3,57 +3,86 @@
|
||||
|
||||
var ChannelStore = require('../stores/channel_store.jsx');
|
||||
|
||||
module.exports = React.createClass({
|
||||
componentDidMount: function() {
|
||||
export default class CommandList extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
channel_id: ChannelStore.getCurrentId()
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
var self = this;
|
||||
if(this.refs.modal) {
|
||||
$(this.refs.modal.getDOMNode()).on('show.bs.modal', function(e) {
|
||||
var button = e.relatedTarget;
|
||||
self.setState({ channel_id: $(button).attr('data-channelid') });
|
||||
});
|
||||
if (this.refs.modal) {
|
||||
$(this.refs.modal.getDOMNode()).on('show.bs.modal', function show(e) {
|
||||
var button = e.relatedTarget;
|
||||
self.setState({channel_id: $(button).attr('data-channelid')});
|
||||
});
|
||||
}
|
||||
},
|
||||
getInitialState: function() {
|
||||
return { channel_id: ChannelStore.getCurrentId() };
|
||||
},
|
||||
render: function() {
|
||||
}
|
||||
|
||||
render() {
|
||||
var channel = ChannelStore.get(this.state.channel_id);
|
||||
|
||||
if (!channel) {
|
||||
channel = {};
|
||||
channel.display_name = "No Channel Found";
|
||||
channel.name = "No Channel Found";
|
||||
channel.id = "No Channel Found";
|
||||
channel.display_name = 'No Channel Found';
|
||||
channel.name = 'No Channel Found';
|
||||
channel.id = 'No Channel Found';
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="modal fade" ref="modal" id="channel_info" 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" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 className="modal-title" id="myModalLabel"><span className="name">{channel.display_name}</span></h4>
|
||||
<div
|
||||
className='modal fade'
|
||||
ref='modal'
|
||||
id='channel_info'
|
||||
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'
|
||||
aria-label='Close'
|
||||
>
|
||||
<span aria-hidden='true'>×</span>
|
||||
</button>
|
||||
<h4
|
||||
className='modal-title'
|
||||
id='myModalLabel'
|
||||
>
|
||||
<span className='name'>{channel.display_name}</span>
|
||||
</h4>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<div className="row form-group">
|
||||
<div className="col-sm-3 info__label">Channel Name: </div>
|
||||
<div className="col-sm-9">{channel.display_name}</div>
|
||||
<div className='modal-body'>
|
||||
<div className='row form-group'>
|
||||
<div className='col-sm-3 info__label'>Channel Name: </div>
|
||||
<div className='col-sm-9'>{channel.display_name}</div>
|
||||
</div>
|
||||
<div className="row form-group">
|
||||
<div className="col-sm-3 info__label">Channel Handle:</div>
|
||||
<div className="col-sm-9">{channel.name}</div>
|
||||
<div className='row form-group'>
|
||||
<div className='col-sm-3 info__label'>Channel Handle:</div>
|
||||
<div className='col-sm-9'>{channel.name}</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-sm-3 info__label">Channel ID:</div>
|
||||
<div className="col-sm-9">{channel.id}</div>
|
||||
<div className='row'>
|
||||
<div className='col-sm-3 info__label'>Channel ID:</div>
|
||||
<div className='col-sm-9'>{channel.id}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
<button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
|
||||
<div className='modal-footer'>
|
||||
<button
|
||||
type='button'
|
||||
className='btn btn-default'
|
||||
data-dismiss='modal'
|
||||
>Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ var utils = require('../utils/utils.jsx');
|
||||
var client = require('../utils/client.jsx');
|
||||
var AsyncClient = require('../utils/async_client.jsx');
|
||||
|
||||
|
||||
export default class ChannelInviteModal extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
@@ -129,15 +128,37 @@ export default class ChannelInviteModal extends React.Component {
|
||||
if (this.state.loading) {
|
||||
content = (<LoadingScreen />);
|
||||
} else {
|
||||
content = (<MemberList memberList={this.state.nonmembers} isAdmin={isAdmin} handleInvite={this.handleInvite} />);
|
||||
content = (
|
||||
<MemberList
|
||||
memberList={this.state.nonmembers}
|
||||
isAdmin={isAdmin}
|
||||
handleInvite={this.handleInvite}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='modal fade' id='channel_invite' tabIndex='-1' role='dialog' aria-hidden='true'>
|
||||
<div className='modal-dialog' role='document'>
|
||||
<div
|
||||
className='modal fade'
|
||||
id='channel_invite'
|
||||
tabIndex='-1'
|
||||
role='dialog'
|
||||
aria-hidden='true'
|
||||
>
|
||||
<div
|
||||
className='modal-dialog'
|
||||
role='document'
|
||||
>
|
||||
<div className='modal-content'>
|
||||
<div className='modal-header'>
|
||||
<button type='button' className='close' data-dismiss='modal' aria-label='Close'><span aria-hidden='true'>×</span></button>
|
||||
<button
|
||||
type='button'
|
||||
className='close'
|
||||
data-dismiss='modal'
|
||||
aria-label='Close'
|
||||
>
|
||||
<span aria-hidden='true'>×</span>
|
||||
</button>
|
||||
<h4 className='modal-title'>Add New Members to <span className='name'>{this.state.channelName}</span></h4>
|
||||
</div>
|
||||
<div className='modal-body'>
|
||||
@@ -145,7 +166,11 @@ export default class ChannelInviteModal extends React.Component {
|
||||
{content}
|
||||
</div>
|
||||
<div className='modal-footer'>
|
||||
<button type='button' className='btn btn-default' data-dismiss='modal'>Close</button>
|
||||
<button
|
||||
type='button'
|
||||
className='btn btn-default'
|
||||
data-dismiss='modal'
|
||||
>Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -153,4 +178,3 @@ export default class ChannelInviteModal extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
ChannelInviteModal.displayName = 'ChannelInviteModal';
|
||||
|
||||
@@ -3,25 +3,40 @@
|
||||
|
||||
var client = require('../utils/client.jsx');
|
||||
|
||||
module.exports = React.createClass({
|
||||
getInitialState: function() {
|
||||
return { suggestions: [ ], cmd: "" };
|
||||
},
|
||||
handleClick: function(i) {
|
||||
this.props.addCommand(this.state.suggestions[i].suggestion)
|
||||
this.setState({ suggestions: [ ], cmd: "" });
|
||||
},
|
||||
addFirstCommand: function() {
|
||||
if (this.state.suggestions.length == 0) return;
|
||||
this.handleClick(0);
|
||||
},
|
||||
isEmpty: function() {
|
||||
return this.state.suggestions.length == 0;
|
||||
},
|
||||
getSuggestedCommands: function(cmd) {
|
||||
export default class CommandList extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
if (!cmd || cmd.charAt(0) != '/') {
|
||||
this.setState({ suggestions: [ ], cmd: "" });
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
this.addFirstCommand = this.addFirstCommand.bind(this);
|
||||
this.isEmpty = this.isEmpty.bind(this);
|
||||
this.getSuggestedCommands = this.getSuggestedCommands.bind(this);
|
||||
|
||||
this.state = {
|
||||
suggestions: [ ],
|
||||
cmd: ''
|
||||
};
|
||||
}
|
||||
|
||||
handleClick(i) {
|
||||
this.props.addCommand(this.state.suggestions[i].suggestion);
|
||||
this.setState({suggestions: [ ], cmd: ''});
|
||||
}
|
||||
|
||||
addFirstCommand() {
|
||||
if (this.state.suggestions.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.handleClick(0);
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
return this.state.suggestions.length === 0;
|
||||
}
|
||||
|
||||
getSuggestedCommands(cmd) {
|
||||
if (!cmd || cmd.charAt(0) !== '/') {
|
||||
this.setState({suggestions: [ ], cmd: ''});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -29,36 +44,56 @@ module.exports = React.createClass({
|
||||
this.props.channelId,
|
||||
cmd,
|
||||
true,
|
||||
function(data) {
|
||||
function success(data) {
|
||||
if (data.suggestions.length === 1 && data.suggestions[0].suggestion === cmd) {
|
||||
data.suggestions = [];
|
||||
}
|
||||
this.setState({ suggestions: data.suggestions, cmd: cmd });
|
||||
this.setState({suggestions: data.suggestions, cmd: cmd});
|
||||
}.bind(this),
|
||||
function(err){
|
||||
}
|
||||
function fail() {
|
||||
}
|
||||
);
|
||||
},
|
||||
render: function() {
|
||||
if (this.state.suggestions.length == 0) return (<div/>);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.suggestions.length === 0) {
|
||||
return (<div/>);
|
||||
}
|
||||
|
||||
var suggestions = [];
|
||||
|
||||
for (var i = 0; i < this.state.suggestions.length; i++) {
|
||||
if (this.state.suggestions[i].suggestion != this.state.cmd) {
|
||||
if (this.state.suggestions[i].suggestion !== this.state.cmd) {
|
||||
suggestions.push(
|
||||
<div key={i} className="command-name" onClick={this.handleClick.bind(this, i)}>
|
||||
<div className="command__title"><strong>{ this.state.suggestions[i].suggestion }</strong></div>
|
||||
<div className="command__desc">{ this.state.suggestions[i].description }</div>
|
||||
<div
|
||||
key={i}
|
||||
className='command-name'
|
||||
onClick={this.handleClick.bind(this, i)}
|
||||
>
|
||||
<div className='command__title'><strong>{this.state.suggestions[i].suggestion}</strong></div>
|
||||
<div className='command__desc'>{this.state.suggestions[i].description}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref="mentionlist" className="command-box" style={{height:(this.state.suggestions.length*56)+2}}>
|
||||
{ suggestions }
|
||||
<div
|
||||
ref='mentionlist'
|
||||
className='command-box'
|
||||
style={{height: (this.state.suggestions.length * 56) + 2}}
|
||||
>
|
||||
{suggestions}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
CommandList.defaultProps = {
|
||||
channelId: null
|
||||
};
|
||||
|
||||
CommandList.propTypes = {
|
||||
addCommand: React.PropTypes.func,
|
||||
channelId: React.PropTypes.string
|
||||
};
|
||||
@@ -6,20 +6,19 @@ var Constants = require('../utils/constants.jsx');
|
||||
var ChannelStore = require('../stores/channel_store.jsx');
|
||||
var utils = require('../utils/utils.jsx');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'FileUpload',
|
||||
propTypes: {
|
||||
onUploadError: React.PropTypes.func,
|
||||
getFileCount: React.PropTypes.func,
|
||||
onFileUpload: React.PropTypes.func,
|
||||
onUploadStart: React.PropTypes.func,
|
||||
channelId: React.PropTypes.string,
|
||||
postType: React.PropTypes.string
|
||||
},
|
||||
getInitialState: function() {
|
||||
return {requests: {}};
|
||||
},
|
||||
handleChange: function() {
|
||||
export default class FileUpload extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.handleDrop = this.handleDrop.bind(this);
|
||||
|
||||
this.state = {
|
||||
requests: {}
|
||||
};
|
||||
}
|
||||
|
||||
handleChange() {
|
||||
var element = $(this.refs.fileInput.getDOMNode());
|
||||
var files = element.prop('files');
|
||||
|
||||
@@ -30,7 +29,7 @@ module.exports = React.createClass({
|
||||
// This looks redundant, but must be done this way due to
|
||||
// setState being an asynchronous call
|
||||
var numFiles = 0;
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
if (files[i].size <= Constants.MAX_FILE_SIZE) {
|
||||
numFiles++;
|
||||
}
|
||||
@@ -42,7 +41,7 @@ module.exports = React.createClass({
|
||||
this.props.onUploadError('Uploads limited to ' + Constants.MAX_UPLOAD_FILES + ' files maximum. Please use additional posts for more files.');
|
||||
}
|
||||
|
||||
for (var i = 0; i < files.length && i < numToUpload; i++) {
|
||||
for (let i = 0; i < files.length && i < numToUpload; i++) {
|
||||
if (files[i].size > Constants.MAX_FILE_SIZE) {
|
||||
this.props.onUploadError('Files must be no more than ' + Constants.MAX_FILE_SIZE / 1000000 + ' MB');
|
||||
continue;
|
||||
@@ -58,7 +57,7 @@ module.exports = React.createClass({
|
||||
formData.append('client_ids', clientId);
|
||||
|
||||
var request = client.uploadFile(formData,
|
||||
function(data) {
|
||||
function success(data) {
|
||||
var parsedData = $.parseJSON(data);
|
||||
this.props.onFileUpload(parsedData.filenames, parsedData.client_ids, channelId);
|
||||
|
||||
@@ -68,7 +67,7 @@ module.exports = React.createClass({
|
||||
}
|
||||
this.setState({requests: requests});
|
||||
}.bind(this),
|
||||
function(err) {
|
||||
function fail(err) {
|
||||
this.props.onUploadError(err, clientId);
|
||||
}.bind(this)
|
||||
);
|
||||
@@ -87,9 +86,12 @@ module.exports = React.createClass({
|
||||
element[0].type = 'text';
|
||||
element[0].type = 'file';
|
||||
}
|
||||
} catch(e) {}
|
||||
},
|
||||
handleDrop: function(e) {
|
||||
} catch(e) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
handleDrop(e) {
|
||||
this.props.onUploadError(null);
|
||||
|
||||
var files = e.originalEvent.dataTransfer.files;
|
||||
@@ -120,7 +122,7 @@ module.exports = React.createClass({
|
||||
formData.append('client_ids', clientId);
|
||||
|
||||
var request = client.uploadFile(formData,
|
||||
function(data) {
|
||||
function success(data) {
|
||||
var parsedData = $.parseJSON(data);
|
||||
this.props.onFileUpload(parsedData.filenames, parsedData.client_ids, channelId);
|
||||
|
||||
@@ -130,7 +132,7 @@ module.exports = React.createClass({
|
||||
}
|
||||
this.setState({requests: requests});
|
||||
}.bind(this),
|
||||
function(err) {
|
||||
function fail(err) {
|
||||
this.props.onUploadError(err, clientId);
|
||||
}.bind(this)
|
||||
);
|
||||
@@ -144,40 +146,41 @@ module.exports = React.createClass({
|
||||
} else {
|
||||
this.props.onUploadError('Invalid file upload', -1);
|
||||
}
|
||||
},
|
||||
componentDidMount: function() {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
var inputDiv = this.refs.input.getDOMNode();
|
||||
var self = this;
|
||||
|
||||
if (this.props.postType === 'post') {
|
||||
$('.row.main').dragster({
|
||||
enter: function() {
|
||||
enter() {
|
||||
$('.center-file-overlay').removeClass('hidden');
|
||||
},
|
||||
leave: function() {
|
||||
leave() {
|
||||
$('.center-file-overlay').addClass('hidden');
|
||||
},
|
||||
drop: function(dragsterEvent, e) {
|
||||
drop(dragsterEvent, e) {
|
||||
$('.center-file-overlay').addClass('hidden');
|
||||
self.handleDrop(e);
|
||||
}
|
||||
});
|
||||
} else if (this.props.postType === 'comment') {
|
||||
$('.post-right__container').dragster({
|
||||
enter: function() {
|
||||
enter() {
|
||||
$('.right-file-overlay').removeClass('hidden');
|
||||
},
|
||||
leave: function() {
|
||||
leave() {
|
||||
$('.right-file-overlay').addClass('hidden');
|
||||
},
|
||||
drop: function(dragsterEvent, e) {
|
||||
drop(dragsterEvent, e) {
|
||||
$('.right-file-overlay').addClass('hidden');
|
||||
self.handleDrop(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('paste', function(e) {
|
||||
document.addEventListener('paste', function handlePaste(e) {
|
||||
var textarea = $(inputDiv.parentNode.parentNode).find('.custom-textarea')[0];
|
||||
|
||||
if (textarea !== e.target && !$.contains(textarea, e.target)) {
|
||||
@@ -191,7 +194,7 @@ module.exports = React.createClass({
|
||||
var items = e.clipboardData.items;
|
||||
var numItems = 0;
|
||||
if (items) {
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (items[i].type.indexOf('image') !== -1) {
|
||||
var testExt = items[i].type.split('/')[1].toLowerCase();
|
||||
|
||||
@@ -269,8 +272,9 @@ module.exports = React.createClass({
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
cancelUpload: function(clientId) {
|
||||
}
|
||||
|
||||
cancelUpload(clientId) {
|
||||
var requests = this.state.requests;
|
||||
var request = requests[clientId];
|
||||
|
||||
@@ -280,15 +284,33 @@ module.exports = React.createClass({
|
||||
delete requests[clientId];
|
||||
this.setState({requests: requests});
|
||||
}
|
||||
},
|
||||
render: function() {
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span ref='input' className='btn btn-file'>
|
||||
<span
|
||||
ref='input'
|
||||
className='btn btn-file'
|
||||
>
|
||||
<span>
|
||||
<i className='glyphicon glyphicon-paperclip' />
|
||||
</span>
|
||||
<input ref='fileInput' type='file' onChange={this.handleChange} multiple/>
|
||||
<input
|
||||
ref='fileInput'
|
||||
type='file'
|
||||
onChange={this.handleChange}
|
||||
multiple='true'
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
FileUpload.propTypes = {
|
||||
onUploadError: React.PropTypes.func,
|
||||
getFileCount: React.PropTypes.func,
|
||||
onFileUpload: React.PropTypes.func,
|
||||
onUploadStart: React.PropTypes.func,
|
||||
channelId: React.PropTypes.string,
|
||||
postType: React.PropTypes.string
|
||||
};
|
||||
|
||||
@@ -1,53 +1,57 @@
|
||||
// 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');
|
||||
|
||||
module.exports = React.createClass({
|
||||
handleSubmit: function(e) {
|
||||
export default class FindTeam extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
}
|
||||
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var state = { };
|
||||
|
||||
var email = this.refs.email.getDOMNode().value.trim().toLowerCase();
|
||||
if (!email || !utils.isEmail(email)) {
|
||||
state.email_error = "Please enter a valid email address";
|
||||
state.email_error = 'Please enter a valid email address';
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
state.email_error = "";
|
||||
}
|
||||
|
||||
state.email_error = '';
|
||||
|
||||
client.findTeamsSendEmail(email,
|
||||
function(data) {
|
||||
function success() {
|
||||
state.sent = true;
|
||||
this.setState(state);
|
||||
}.bind(this),
|
||||
function(err) {
|
||||
function fail(err) {
|
||||
state.email_error = err.message;
|
||||
this.setState(state);
|
||||
}.bind(this)
|
||||
);
|
||||
},
|
||||
getInitialState: function() {
|
||||
return { };
|
||||
},
|
||||
render: function() {
|
||||
}
|
||||
|
||||
var email_error = this.state.email_error ? <label className='control-label'>{ this.state.email_error }</label> : null;
|
||||
render() {
|
||||
var emailError = null;
|
||||
var emailErrorClass = 'form-group';
|
||||
|
||||
var divStyle = {
|
||||
"marginTop": "50px",
|
||||
if (this.state.email_error) {
|
||||
emailError = <label className='control-label'>{this.state.email_error}</label>;
|
||||
emailErrorClass = 'form-group has-error';
|
||||
}
|
||||
|
||||
if (this.state.sent) {
|
||||
return (
|
||||
<div>
|
||||
<h4>{"Find Your " + utils.toTitleCase(strings.Team)}</h4>
|
||||
<p>{"An email was sent with links to any " + strings.TeamPlural + " to which you are a member."}</p>
|
||||
<h4>{'Find Your ' + utils.toTitleCase(strings.Team)}</h4>
|
||||
<p>{'An email was sent with links to any ' + strings.TeamPlural + ' to which you are a member.'}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -56,17 +60,25 @@ module.exports = React.createClass({
|
||||
<div>
|
||||
<h4>Find Your Team</h4>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<p>{"Get an email with links to any " + strings.TeamPlural + " to which you are a member."}</p>
|
||||
<div className="form-group">
|
||||
<p>{'Get an email with links to any ' + strings.TeamPlural + ' to which you are a member.'}</p>
|
||||
<div className='form-group'>
|
||||
<label className='control-label'>Email</label>
|
||||
<div className={ email_error ? "form-group has-error" : "form-group" }>
|
||||
<input type="text" ref="email" className="form-control" placeholder="you@domain.com" maxLength="128" />
|
||||
{ email_error }
|
||||
<div className={emailErrorClass}>
|
||||
<input
|
||||
type='text'
|
||||
ref='email'
|
||||
className='form-control'
|
||||
placeholder='you@domain.com'
|
||||
maxLength='128'
|
||||
/>
|
||||
{emailError}
|
||||
</div>
|
||||
</div>
|
||||
<button className="btn btn-md btn-primary" type="submit">Send</button>
|
||||
<button
|
||||
className='btn btn-md btn-primary'
|
||||
type='submit'>Send</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,10 +7,28 @@ var Client = require('../utils/client.jsx');
|
||||
var UserStore = require('../stores/user_store.jsx');
|
||||
var ConfirmModal = require('./confirm_modal.jsx');
|
||||
|
||||
module.exports = React.createClass({
|
||||
componentDidMount: function() {
|
||||
export default class InviteMemberModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
this.addInviteFields = this.addInviteFields.bind(this);
|
||||
this.clearFields = this.clearFields.bind(this);
|
||||
this.removeInviteFields = this.removeInviteFields.bind(this);
|
||||
|
||||
this.state = {
|
||||
inviteIds: [0],
|
||||
idCount: 0,
|
||||
emailErrors: {},
|
||||
firstNameErrors: {},
|
||||
lastNameErrors: {},
|
||||
emailEnabled: !ConfigStore.getSettingAsBoolean('ByPassEmail', false)
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
var self = this;
|
||||
$('#invite_member').on('hide.bs.modal', function(e) {
|
||||
$('#invite_member').on('hide.bs.modal', function hide(e) {
|
||||
if ($('#invite_member').attr('data-confirm') === 'true') {
|
||||
$('#invite_member').attr('data-confirm', 'false');
|
||||
return;
|
||||
@@ -31,11 +49,12 @@ module.exports = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
$('#invite_member').on('hidden.bs.modal', function() {
|
||||
$('#invite_member').on('hidden.bs.modal', function show() {
|
||||
self.clearFields();
|
||||
});
|
||||
},
|
||||
handleSubmit: function(e) {
|
||||
}
|
||||
|
||||
handleSubmit() {
|
||||
if (!this.state.emailEnabled) {
|
||||
return;
|
||||
}
|
||||
@@ -90,11 +109,11 @@ module.exports = React.createClass({
|
||||
data.invites = invites;
|
||||
|
||||
Client.inviteMembers(data,
|
||||
function() {
|
||||
function success() {
|
||||
$(this.refs.modal.getDOMNode()).attr('data-confirm', 'true');
|
||||
$(this.refs.modal.getDOMNode()).modal('hide');
|
||||
}.bind(this),
|
||||
function(err) {
|
||||
function fail(err) {
|
||||
if (err.message === 'This person is already on your team') {
|
||||
emailErrors[err.detailed_error] = err.message;
|
||||
this.setState({emailErrors: emailErrors});
|
||||
@@ -103,18 +122,21 @@ module.exports = React.createClass({
|
||||
}
|
||||
}.bind(this)
|
||||
);
|
||||
},
|
||||
componentDidUpdate: function() {
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
$(this.refs.modalBody.getDOMNode()).css('max-height', $(window).height() - 200);
|
||||
$(this.refs.modalBody.getDOMNode()).css('overflow-y', 'scroll');
|
||||
},
|
||||
addInviteFields: function() {
|
||||
}
|
||||
|
||||
addInviteFields() {
|
||||
var count = this.state.idCount + 1;
|
||||
var inviteIds = this.state.inviteIds;
|
||||
inviteIds.push(count);
|
||||
this.setState({inviteIds: inviteIds, idCount: count});
|
||||
},
|
||||
clearFields: function() {
|
||||
}
|
||||
|
||||
clearFields() {
|
||||
var inviteIds = this.state.inviteIds;
|
||||
|
||||
for (var i = 0; i < inviteIds.length; i++) {
|
||||
@@ -133,8 +155,9 @@ module.exports = React.createClass({
|
||||
firstNameErrors: {},
|
||||
lastNameErrors: {}
|
||||
});
|
||||
},
|
||||
removeInviteFields: function(index) {
|
||||
}
|
||||
|
||||
removeInviteFields(index) {
|
||||
var count = this.state.idCount;
|
||||
var inviteIds = this.state.inviteIds;
|
||||
var i = inviteIds.indexOf(index);
|
||||
@@ -145,24 +168,10 @@ module.exports = React.createClass({
|
||||
inviteIds.push(++count);
|
||||
}
|
||||
this.setState({inviteIds: inviteIds, idCount: count});
|
||||
},
|
||||
getInitialState: function() {
|
||||
return {
|
||||
inviteIds: [0],
|
||||
idCount: 0,
|
||||
emailErrors: {},
|
||||
firstNameErrors: {},
|
||||
lastNameErrors: {},
|
||||
emailEnabled: !ConfigStore.getSettingAsBoolean('ByPassEmail', false)
|
||||
};
|
||||
},
|
||||
render: function() {
|
||||
var currentUser = UserStore.getCurrentUser();
|
||||
}
|
||||
|
||||
var inputDisabled = '';
|
||||
if (!this.state.emailEnabled) {
|
||||
inputDisabled = 'disabled';
|
||||
}
|
||||
render() {
|
||||
var currentUser = UserStore.getCurrentUser();
|
||||
|
||||
if (currentUser != null) {
|
||||
var inviteSections = [];
|
||||
@@ -185,7 +194,13 @@ module.exports = React.createClass({
|
||||
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'></span></button>
|
||||
<button
|
||||
type='button'
|
||||
className='btn btn-link remove__member'
|
||||
onClick={this.removeInviteFields.bind(this, index)}
|
||||
>
|
||||
<span className='fa fa-trash'></span>
|
||||
</button>
|
||||
</div>);
|
||||
}
|
||||
var emailClass = 'form-group invite';
|
||||
@@ -206,13 +221,27 @@ module.exports = React.createClass({
|
||||
nameFields = (<div className='row--invite'>
|
||||
<div className='col-sm-6'>
|
||||
<div className={firstNameClass}>
|
||||
<input type='text' className='form-control' ref={'first_name' + index} placeholder='First name' maxLength='64' disabled={!this.state.emailEnabled}/>
|
||||
<input
|
||||
type='text'
|
||||
className='form-control'
|
||||
ref={'first_name' + index}
|
||||
placeholder='First name'
|
||||
maxLength='64'
|
||||
disabled={!this.state.emailEnabled}
|
||||
/>
|
||||
{firstNameError}
|
||||
</div>
|
||||
</div>
|
||||
<div className='col-sm-6'>
|
||||
<div className={lastNameClass}>
|
||||
<input type='text' className='form-control' ref={'last_name' + index} placeholder='Last name' maxLength='64' disabled={!this.state.emailEnabled}/>
|
||||
<input
|
||||
type='text'
|
||||
className='form-control'
|
||||
ref={'last_name' + index}
|
||||
placeholder='Last name'
|
||||
maxLength='64'
|
||||
disabled={!this.state.emailEnabled}
|
||||
/>
|
||||
{lastNameError}
|
||||
</div>
|
||||
</div>
|
||||
@@ -223,7 +252,15 @@ module.exports = React.createClass({
|
||||
<div key={'key' + index}>
|
||||
{removeButton}
|
||||
<div className={emailClass}>
|
||||
<input onKeyUp={this.displayNameKeyUp} type='text' ref={'email' + index} className='form-control' placeholder='email@domain.com' maxLength='64' disabled={!this.state.emailEnabled}/>
|
||||
<input
|
||||
onKeyUp={this.displayNameKeyUp}
|
||||
type='text'
|
||||
ref={'email' + index}
|
||||
className='form-control'
|
||||
placeholder='email@domain.com'
|
||||
maxLength='64'
|
||||
disabled={!this.state.emailEnabled}
|
||||
/>
|
||||
{emailError}
|
||||
</div>
|
||||
{nameFields}
|
||||
@@ -242,23 +279,44 @@ module.exports = React.createClass({
|
||||
content = (
|
||||
<div>
|
||||
{serverError}
|
||||
<button type='button' className='btn btn-default' onClick={this.addInviteFields}>Add another</button>
|
||||
<button
|
||||
type='button'
|
||||
className='btn btn-default'
|
||||
onClick={this.addInviteFields}
|
||||
>Add another</button>
|
||||
<br/>
|
||||
<br/>
|
||||
<span>People invited automatically join Town Square channel.</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
sendButton = <button onClick={this.handleSubmit} type='button' className='btn btn-primary'>Send Invitations</button>
|
||||
sendButton =
|
||||
(
|
||||
<button
|
||||
onClick={this.handleSubmit}
|
||||
type='button'
|
||||
className='btn btn-primary'
|
||||
>Send Invitations</button>
|
||||
);
|
||||
} else {
|
||||
var teamInviteLink = null;
|
||||
if (currentUser && this.props.teamType === 'O') {
|
||||
var linkUrl = utils.getWindowLocationOrigin() + '/signup_user_complete/?id=' + currentUser.team_id;
|
||||
var link = <a href='#' data-toggle='modal' data-target='#get_link' data-title='Team Invite' data-value={linkUrl} onClick={
|
||||
function() {
|
||||
$('#invite_member').modal('hide');
|
||||
}
|
||||
}>Team Invite Link</a>;
|
||||
var link =
|
||||
(
|
||||
<a
|
||||
href='#'
|
||||
data-toggle='modal'
|
||||
data-target='#get_link'
|
||||
data-title='Team Invite'
|
||||
data-value={linkUrl}
|
||||
onClick={
|
||||
function click() {
|
||||
$('#invite_member').modal('hide');
|
||||
}
|
||||
}
|
||||
>Team Invite Link</a>
|
||||
);
|
||||
|
||||
teamInviteLink = (
|
||||
<p>
|
||||
@@ -277,22 +335,46 @@ module.exports = React.createClass({
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='modal fade' ref='modal' id='invite_member' tabIndex='-1' role='dialog' aria-hidden='true'>
|
||||
<div
|
||||
className='modal fade'
|
||||
ref='modal'
|
||||
id='invite_member'
|
||||
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' aria-label='Close' data-reactid='.5.0.0.0.0'><span aria-hidden='true' data-reactid='.5.0.0.0.0.0'>×</span></button>
|
||||
<h4 className='modal-title' id='myModalLabel'>Invite New Member</h4>
|
||||
<button
|
||||
type='button'
|
||||
className='close'
|
||||
data-dismiss='modal'
|
||||
aria-label='Close'
|
||||
>
|
||||
<span aria-hidden='true'>×</span>
|
||||
</button>
|
||||
<h4
|
||||
className='modal-title'
|
||||
id='myModalLabel'
|
||||
>Invite New Member</h4>
|
||||
</div>
|
||||
<div ref='modalBody' className='modal-body'>
|
||||
<div
|
||||
ref='modalBody'
|
||||
className='modal-body'
|
||||
>
|
||||
<form role='form'>
|
||||
{inviteSections}
|
||||
</form>
|
||||
{content}
|
||||
</div>
|
||||
<div className='modal-footer'>
|
||||
<button type='button' className='btn btn-default' data-dismiss='modal'>Cancel</button>
|
||||
{sendButton}
|
||||
<button
|
||||
type='button'
|
||||
className='btn btn-default'
|
||||
data-dismiss='modal'
|
||||
>Cancel</button>
|
||||
{sendButton}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -309,4 +391,8 @@ module.exports = React.createClass({
|
||||
}
|
||||
return <div/>;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
InviteMemberModal.propTypes = {
|
||||
teamType: React.PropTypes.string
|
||||
};
|
||||
|
||||
@@ -3,32 +3,45 @@
|
||||
|
||||
var MemberListItem = require('./member_list_item.jsx');
|
||||
|
||||
module.exports = React.createClass({
|
||||
render: function() {
|
||||
export default class MemberList extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
var members = [];
|
||||
|
||||
if (this.props.memberList != null) {
|
||||
if (this.props.memberList !== null) {
|
||||
members = this.props.memberList;
|
||||
}
|
||||
|
||||
var message = "";
|
||||
if (members.length === 0)
|
||||
var message = '';
|
||||
if (members.length === 0) {
|
||||
message = <span>No users to add.</span>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="member-list-holder">
|
||||
{members.map(function(member) {
|
||||
return <MemberListItem
|
||||
<div className='member-list-holder'>
|
||||
{members.map(function mymembers(member) {
|
||||
return (<MemberListItem
|
||||
key={member.id}
|
||||
member={member}
|
||||
isAdmin={this.props.isAdmin}
|
||||
handleInvite={this.props.handleInvite}
|
||||
handleRemove={this.props.handleRemove}
|
||||
handleMakeAdmin={this.props.handleMakeAdmin}
|
||||
/>;
|
||||
/>);
|
||||
}, this)}
|
||||
{message}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
MemberList.propTypes = {
|
||||
memberList: React.PropTypes.array,
|
||||
isAdmin: React.PropTypes.bool,
|
||||
handleInvite: React.PropTypes.func,
|
||||
handleRemove: React.PropTypes.func,
|
||||
handleMakeAdmin: React.PropTypes.func
|
||||
};
|
||||
|
||||
@@ -7,19 +7,22 @@ var Client = require('../utils/client.jsx');
|
||||
var AsyncClient = require('../utils/async_client.jsx');
|
||||
var utils = require('../utils/utils.jsx');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'MoreDirectChannels',
|
||||
componentDidMount: function() {
|
||||
export default class MoreDirectChannels extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {channels: [], loadingDMChannel: -1};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
var self = this;
|
||||
$(this.refs.modal.getDOMNode()).on('show.bs.modal', function showModal(e) {
|
||||
var button = e.relatedTarget;
|
||||
self.setState({channels: $(button).data('channels')});
|
||||
});
|
||||
},
|
||||
getInitialState: function() {
|
||||
return {channels: [], loadingDMChannel: -1};
|
||||
},
|
||||
render: function() {
|
||||
}
|
||||
|
||||
render() {
|
||||
var self = this;
|
||||
|
||||
var directMessageItems = this.state.channels.map(function mapActivityToChannel(channel, index) {
|
||||
@@ -48,7 +51,12 @@ module.exports = React.createClass({
|
||||
var otherUserId = utils.getUserIdFromChannelName(channel);
|
||||
|
||||
if (self.state.loadingDMChannel === index) {
|
||||
badge = <img className='channel-loading-gif pull-right' src='/static/images/load.gif'/>;
|
||||
badge = (
|
||||
<img
|
||||
className='channel-loading-gif pull-right'
|
||||
src='/static/images/load.gif'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (self.state.loadingDMChannel === -1) {
|
||||
@@ -73,16 +81,36 @@ module.exports = React.createClass({
|
||||
}
|
||||
|
||||
return (
|
||||
<li key={channel.name} className={active}><a className={'sidebar-channel ' + titleClass} href='#' onClick={handleClick}>{badge}{channel.display_name}</a></li>
|
||||
<li
|
||||
key={channel.name}
|
||||
className={active}
|
||||
>
|
||||
<a
|
||||
className={'sidebar-channel ' + titleClass}
|
||||
href='#'
|
||||
onClick={handleClick}
|
||||
>{badge}{channel.display_name}</a>
|
||||
</li>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className='modal fade' id='more_direct_channels' ref='modal' tabIndex='-1' role='dialog' aria-hidden='true'>
|
||||
<div
|
||||
className='modal fade'
|
||||
id='more_direct_channels'
|
||||
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'>
|
||||
<button
|
||||
type='button'
|
||||
className='close'
|
||||
data-dismiss='modal'
|
||||
>
|
||||
<span aria-hidden='true'>×</span>
|
||||
<span className='sr-only'>Close</span>
|
||||
</button>
|
||||
@@ -94,11 +122,15 @@ module.exports = React.createClass({
|
||||
</ul>
|
||||
</div>
|
||||
<div className='modal-footer'>
|
||||
<button type='button' className='btn btn-default' data-dismiss='modal'>Close</button>
|
||||
<button
|
||||
type='button'
|
||||
className='btn btn-default'
|
||||
data-dismiss='modal'
|
||||
>Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,57 +1,70 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
|
||||
var SocketStore = require('../stores/socket_store.jsx');
|
||||
var UserStore = require('../stores/user_store.jsx');
|
||||
|
||||
module.exports = React.createClass({
|
||||
timer: null,
|
||||
lastTime: 0,
|
||||
componentDidMount: function() {
|
||||
SocketStore.addChangeListener(this._onChange);
|
||||
},
|
||||
componentWillReceiveProps: function(newProps) {
|
||||
if(this.props.channelId !== newProps.channelId) {
|
||||
this.setState({text:""});
|
||||
}
|
||||
},
|
||||
componentWillUnmount: function() {
|
||||
SocketStore.removeChangeListener(this._onChange);
|
||||
},
|
||||
_onChange: function(msg) {
|
||||
if (msg.action == "typing" &&
|
||||
this.props.channelId == msg.channel_id &&
|
||||
this.props.parentId == msg.props.parent_id) {
|
||||
export default class MsgTyping extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.timer = null;
|
||||
this.lastTime = 0;
|
||||
|
||||
this.onChange = this.onChange.bind(this);
|
||||
|
||||
this.state = {
|
||||
text: ''
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
SocketStore.addChangeListener(this.onChange);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(newProps) {
|
||||
if (this.props.channelId !== newProps.channelId) {
|
||||
this.setState({text: ''});
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
SocketStore.removeChangeListener(this.onChange);
|
||||
}
|
||||
|
||||
onChange(msg) {
|
||||
if (msg.action === 'typing' &&
|
||||
this.props.channelId === msg.channel_id &&
|
||||
this.props.parentId === msg.props.parent_id) {
|
||||
this.lastTime = new Date().getTime();
|
||||
|
||||
var username = "Someone";
|
||||
var username = 'Someone';
|
||||
if (UserStore.hasProfile(msg.user_id)) {
|
||||
username = UserStore.getProfile(msg.user_id).username;
|
||||
}
|
||||
|
||||
this.setState({ text: username + " is typing..." });
|
||||
this.setState({text: username + ' is typing...'});
|
||||
|
||||
if (!this.timer) {
|
||||
var outer = this;
|
||||
outer.timer = setInterval(function() {
|
||||
if ((new Date().getTime() - outer.lastTime) > 8000) {
|
||||
outer.setState({ text: "" });
|
||||
this.timer = setInterval(function myTimer() {
|
||||
if ((new Date().getTime() - this.lastTime) > 8000) {
|
||||
this.setState({text: ''});
|
||||
}
|
||||
}, 3000);
|
||||
}.bind(this), 3000);
|
||||
}
|
||||
} else if (msg.action === 'posted' && msg.channel_id === this.props.channelId) {
|
||||
this.setState({text: ''});
|
||||
}
|
||||
else if (msg.action == "posted" && msg.channel_id === this.props.channelId) {
|
||||
this.setState({text:""})
|
||||
}
|
||||
},
|
||||
getInitialState: function() {
|
||||
return { text: "" };
|
||||
},
|
||||
render: function() {
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span className="msg-typing">{ this.state.text }</span>
|
||||
<span className='msg-typing'>{this.state.text}</span>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
MsgTyping.propTypes = {
|
||||
channelId: React.PropTypes.string,
|
||||
parentId: React.PropTypes.string
|
||||
};
|
||||
|
||||
@@ -51,8 +51,10 @@ export default class PostList extends React.Component {
|
||||
|
||||
if (deletedPosts && Object.keys(deletedPosts).length > 0) {
|
||||
for (var pid in deletedPosts) {
|
||||
postList.posts[pid] = deletedPosts[pid];
|
||||
postList.order.unshift(pid);
|
||||
if (deletedPosts.hasOwnProperty(pid)) {
|
||||
postList.posts[pid] = deletedPosts[pid];
|
||||
postList.order.unshift(pid);
|
||||
}
|
||||
}
|
||||
|
||||
postList.order.sort(function postSort(a, b) {
|
||||
@@ -71,7 +73,9 @@ export default class PostList extends React.Component {
|
||||
if (pendingPostList) {
|
||||
postList.order = pendingPostList.order.concat(postList.order);
|
||||
for (var ppid in pendingPostList.posts) {
|
||||
postList.posts[ppid] = pendingPostList.posts[ppid];
|
||||
if (pendingPostList.posts.hasOwnProperty(ppid)) {
|
||||
postList.posts[ppid] = pendingPostList.posts[ppid];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -267,7 +271,6 @@ export default class PostList extends React.Component {
|
||||
}
|
||||
}
|
||||
onSocketChange(msg) {
|
||||
var postList;
|
||||
var post;
|
||||
if (msg.action === 'posted' || msg.action === 'post_edited') {
|
||||
post = JSON.parse(msg.props.post);
|
||||
@@ -280,7 +283,6 @@ export default class PostList extends React.Component {
|
||||
}
|
||||
|
||||
post = JSON.parse(msg.props.post);
|
||||
postList = this.state.postList;
|
||||
|
||||
PostStore.storeUnseenDeletedPost(post);
|
||||
PostStore.removePost(post, true);
|
||||
@@ -644,11 +646,18 @@ export default class PostList extends React.Component {
|
||||
if (posts && this.state.isFirstLoadComplete) {
|
||||
postCtls = this.createPosts(posts, order);
|
||||
} else {
|
||||
postCtls.push(<LoadingScreen position='absolute' />);
|
||||
postCtls.push(
|
||||
<LoadingScreen
|
||||
position='absolute'
|
||||
key='loading'
|
||||
/>);
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref='postlist' className='post-list-holder-by-time'>
|
||||
<div
|
||||
ref='postlist'
|
||||
className='post-list-holder-by-time'
|
||||
>
|
||||
<div className='post-list__table'>
|
||||
<div className='post-list__content'>
|
||||
{moreMessages}
|
||||
|
||||
@@ -3,62 +3,99 @@
|
||||
|
||||
var ChannelStore = require('../stores/channel_store.jsx');
|
||||
var UserStore = require('../stores/user_store.jsx');
|
||||
var BrowserStore = require('../stores/browser_store.jsx')
|
||||
var BrowserStore = require('../stores/browser_store.jsx');
|
||||
var utils = require('../utils/utils.jsx');
|
||||
|
||||
module.exports = React.createClass({
|
||||
handleShow: function() {
|
||||
var newState = {};
|
||||
if(BrowserStore.getItem("channel-removed-state")) {
|
||||
newState = BrowserStore.getItem("channel-removed-state");
|
||||
BrowserStore.removeItem("channel-removed-state");
|
||||
}
|
||||
export default class RemovedFromChannelModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.setState(newState);
|
||||
},
|
||||
handleClose: function() {
|
||||
var townSquare = ChannelStore.getByName("town-square");
|
||||
utils.switchChannel(townSquare);
|
||||
this.handleShow = this.handleShow.bind(this);
|
||||
this.handleClose = this.handleClose.bind(this);
|
||||
|
||||
this.setState({channelName: "", remover: ""});
|
||||
},
|
||||
componentDidMount: function() {
|
||||
$(this.getDOMNode()).on('show.bs.modal',this.handleShow);
|
||||
$(this.getDOMNode()).on('hidden.bs.modal',this.handleClose);
|
||||
},
|
||||
componentWillUnmount: function() {
|
||||
$(this.getDOMNode()).off('show.bs.modal',this.handleShow);
|
||||
$(this.getDOMNode()).off('hidden.bs.modal',this.handleClose);
|
||||
},
|
||||
getInitialState: function() {
|
||||
return {channelName: "", remover: ""}
|
||||
},
|
||||
render: function() {
|
||||
this.state = {
|
||||
channelName: '',
|
||||
remover: ''
|
||||
};
|
||||
}
|
||||
|
||||
handleShow() {
|
||||
var newState = {};
|
||||
if (BrowserStore.getItem('channel-removed-state')) {
|
||||
newState = BrowserStore.getItem('channel-removed-state');
|
||||
BrowserStore.removeItem('channel-removed-state');
|
||||
}
|
||||
|
||||
this.setState(newState);
|
||||
}
|
||||
|
||||
handleClose() {
|
||||
var townSquare = ChannelStore.getByName('town-square');
|
||||
utils.switchChannel(townSquare);
|
||||
|
||||
this.setState({channelName: '', remover: ''});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
$(React.findDOMNode(this)).on('show.bs.modal', this.handleShow);
|
||||
$(React.findDOMNode(this)).on('hidden.bs.modal', this.handleClose);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
$(React.findDOMNode(this)).off('show.bs.modal', this.handleShow);
|
||||
$(React.findDOMNode(this)).off('hidden.bs.modal', this.handleClose);
|
||||
}
|
||||
|
||||
render() {
|
||||
var currentUser = UserStore.getCurrentUser();
|
||||
var channelName = this.state.channelName ? this.state.channelName : "the channel"
|
||||
var remover = this.state.remover ? this.state.remover : "Someone"
|
||||
|
||||
var channelName = 'the channel';
|
||||
if (this.state.channelName) {
|
||||
channelName = this.state.channelName;
|
||||
}
|
||||
|
||||
var remover = 'Someone';
|
||||
if (this.state.remover) {
|
||||
remover = this.state.remover;
|
||||
}
|
||||
|
||||
if (currentUser != null) {
|
||||
return (
|
||||
<div className='modal fade' ref='modal' id='removed_from_channel' 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' aria-label='Close'><span aria-hidden='true'>×</span></button>
|
||||
<h4 className='modal-title'>Removed from <span className='name'>{channelName}</span></h4>
|
||||
<div
|
||||
className='modal fade'
|
||||
ref='modal'
|
||||
id='removed_from_channel'
|
||||
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'
|
||||
aria-label='Close'
|
||||
><span aria-hidden='true'>×</span></button>
|
||||
<h4 className='modal-title'>Removed from <span className='name'>{channelName}</span></h4>
|
||||
</div>
|
||||
<div className='modal-body'>
|
||||
<p>{remover} removed you from {channelName}</p>
|
||||
</div>
|
||||
<div className='modal-footer'>
|
||||
<button
|
||||
type='button'
|
||||
className='btn btn-primary'
|
||||
data-dismiss='modal'
|
||||
>Okay</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className='modal-body'>
|
||||
<p>{remover} removed you from {channelName}</p>
|
||||
</div>
|
||||
<div className='modal-footer'>
|
||||
<button type='button' className='btn btn-primary' data-dismiss='modal'>Okay</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return <div/>;
|
||||
}
|
||||
|
||||
return <div/>;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -33,7 +33,9 @@ export default class RhsThread extends React.Component {
|
||||
|
||||
if (pendingPostList) {
|
||||
for (var pid in pendingPostList.posts) {
|
||||
postList.posts[pid] = pendingPostList.posts[pid];
|
||||
if (pendingPostList.posts.hasOwnProperty(pid)) {
|
||||
postList.posts[pid] = pendingPostList.posts[pid];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +83,9 @@ export default class RhsThread extends React.Component {
|
||||
if (currentPosts.posts[currentPosts.order[0]].channel_id === currentSelected.posts[currentSelected.order[0]].channel_id) {
|
||||
currentSelected.posts = {};
|
||||
for (var postId in currentPosts.posts) {
|
||||
currentSelected.posts[postId] = currentPosts.posts[postId];
|
||||
if (currentPosts.posts.hasOwnProperty(postId)) {
|
||||
currentSelected.posts[postId] = currentPosts.posts[postId];
|
||||
}
|
||||
}
|
||||
|
||||
PostStore.storeSelectedPost(currentSelected);
|
||||
@@ -128,9 +132,11 @@ export default class RhsThread extends React.Component {
|
||||
var postsArray = [];
|
||||
|
||||
for (var postId in postList.posts) {
|
||||
var cpost = postList.posts[postId];
|
||||
if (cpost.root_id === rootPost.id) {
|
||||
postsArray.push(cpost);
|
||||
if (postList.posts.hasOwnProperty(postId)) {
|
||||
var cpost = postList.posts[postId];
|
||||
if (cpost.root_id === rootPost.id) {
|
||||
postsArray.push(cpost);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,6 +215,7 @@ RhsThread.defaultProps = {
|
||||
fromSearch: '',
|
||||
isMentionSearch: false
|
||||
};
|
||||
|
||||
RhsThread.propTypes = {
|
||||
fromSearch: React.PropTypes.string,
|
||||
isMentionSearch: React.PropTypes.bool
|
||||
|
||||
@@ -1,181 +1,109 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
|
||||
var PostStore = require('../stores/post_store.jsx');
|
||||
var ChannelStore = require('../stores/channel_store.jsx');
|
||||
var UserStore = require('../stores/user_store.jsx');
|
||||
var UserProfile = require( './user_profile.jsx' );
|
||||
var SearchBox =require('./search_bar.jsx');
|
||||
var SearchBox = require('./search_bar.jsx');
|
||||
var utils = require('../utils/utils.jsx');
|
||||
var client = require('../utils/client.jsx');
|
||||
var AsyncClient = require('../utils/async_client.jsx');
|
||||
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
|
||||
var Constants = require('../utils/constants.jsx');
|
||||
var ActionTypes = Constants.ActionTypes;
|
||||
|
||||
var RhsHeaderSearch = React.createClass({
|
||||
handleClose: function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECIEVED_SEARCH,
|
||||
results: null
|
||||
});
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECIEVED_SEARCH_TERM,
|
||||
term: null,
|
||||
do_search: false,
|
||||
is_mention_search: false
|
||||
});
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECIEVED_POST_SELECTED,
|
||||
results: null
|
||||
});
|
||||
},
|
||||
render: function() {
|
||||
var title = this.props.isMentionSearch ? "Recent Mentions" : "Search Results";
|
||||
return (
|
||||
<div className="sidebar--right__header">
|
||||
<span className="sidebar--right__title">{title}</span>
|
||||
<button type="button" className="sidebar--right__close" aria-label="Close" title="Close" onClick={this.handleClose}></button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var SearchItem = React.createClass({
|
||||
handleClick: function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var self = this;
|
||||
|
||||
client.getPost(
|
||||
this.props.post.channel_id,
|
||||
this.props.post.id,
|
||||
function(data) {
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECIEVED_POST_SELECTED,
|
||||
post_list: data,
|
||||
from_search: PostStore.getSearchTerm()
|
||||
});
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECIEVED_SEARCH,
|
||||
results: null,
|
||||
is_mention_search: self.props.isMentionSearch
|
||||
});
|
||||
},
|
||||
function(err) {
|
||||
AsyncClient.dispatchError(err, "getPost");
|
||||
}
|
||||
);
|
||||
|
||||
var postChannel = ChannelStore.get(this.props.post.channel_id);
|
||||
var teammate = postChannel.type === 'D' ? utils.getDirectTeammate(this.props.post.channel_id).username : "";
|
||||
|
||||
utils.switchChannel(postChannel, teammate);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
||||
var message = utils.textToJsx(this.props.post.message, {searchTerm: this.props.term, noMentionHighlight: !this.props.isMentionSearch});
|
||||
var channelName = "";
|
||||
var channel = ChannelStore.get(this.props.post.channel_id);
|
||||
var timestamp = UserStore.getCurrentUser().update_at;
|
||||
|
||||
if (channel) {
|
||||
channelName = (channel.type === 'D') ? "Private Message" : channel.display_name;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="search-item-container post" onClick={this.handleClick}>
|
||||
<div className="search-channel__name">{ channelName }</div>
|
||||
<div className="post-profile-img__container">
|
||||
<img className="post-profile-img" src={"/api/v1/users/" + this.props.post.user_id + "/image?time=" + timestamp} height="36" width="36" />
|
||||
</div>
|
||||
<div className="post__content">
|
||||
<ul className="post-header">
|
||||
<li className="post-header-col"><strong><UserProfile userId={this.props.post.user_id} /></strong></li>
|
||||
<li className="post-header-col">
|
||||
<time className="search-item-time">
|
||||
{ utils.displayDate(this.props.post.create_at) + ' ' + utils.displayTime(this.props.post.create_at) }
|
||||
</time>
|
||||
</li>
|
||||
</ul>
|
||||
<div className="search-item-snippet"><span>{message}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var SearchResultsHeader = require('./search_results_header.jsx');
|
||||
var SearchResultsItem = require('./search_results_item.jsx');
|
||||
|
||||
function getStateFromStores() {
|
||||
return { results: PostStore.getSearchResults() };
|
||||
return {results: PostStore.getSearchResults()};
|
||||
}
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'SearchResults',
|
||||
componentDidMount: function() {
|
||||
PostStore.addSearchChangeListener(this._onChange);
|
||||
export default class SearchResults extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.mounted = false;
|
||||
|
||||
this.onChange = this.onChange.bind(this);
|
||||
this.resize = this.resize.bind(this);
|
||||
|
||||
this.state = getStateFromStores();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.mounted = true;
|
||||
PostStore.addSearchChangeListener(this.onChange);
|
||||
this.resize();
|
||||
var self = this;
|
||||
$(window).resize(function(){
|
||||
$(window).resize(function resize() {
|
||||
self.resize();
|
||||
});
|
||||
},
|
||||
componentDidUpdate: function() {
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.resize();
|
||||
},
|
||||
componentWillUnmount: function() {
|
||||
PostStore.removeSearchChangeListener(this._onChange);
|
||||
},
|
||||
_onChange: function() {
|
||||
if (this.isMounted()) {
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
PostStore.removeSearchChangeListener(this.onChange);
|
||||
this.mounted = false;
|
||||
}
|
||||
|
||||
onChange() {
|
||||
if (this.mounted) {
|
||||
var newState = getStateFromStores();
|
||||
if (!utils.areStatesEqual(newState, this.state)) {
|
||||
this.setState(newState);
|
||||
}
|
||||
}
|
||||
},
|
||||
getInitialState: function() {
|
||||
return getStateFromStores();
|
||||
},
|
||||
resize: function() {
|
||||
var height = $(window).height() - $('#error_bar').outerHeight() - 100;
|
||||
$("#search-items-container").css("height", height + "px");
|
||||
$("#search-items-container").scrollTop(0);
|
||||
$("#search-items-container").perfectScrollbar();
|
||||
},
|
||||
render: function() {
|
||||
}
|
||||
|
||||
resize() {
|
||||
var height = $(window).height() - $('#error_bar').outerHeight() - 100;
|
||||
$('#search-items-container').css('height', height + 'px');
|
||||
$('#search-items-container').scrollTop(0);
|
||||
$('#search-items-container').perfectScrollbar();
|
||||
}
|
||||
|
||||
render() {
|
||||
var results = this.state.results;
|
||||
var currentId = UserStore.getCurrentId();
|
||||
var searchForm = currentId ? <SearchBox /> : null;
|
||||
var searchForm = null;
|
||||
if (currentId) {
|
||||
searchForm = <SearchBox />;
|
||||
}
|
||||
var noResults = (!results || !results.order || !results.order.length);
|
||||
var searchTerm = PostStore.getSearchTerm();
|
||||
|
||||
var ctls = null;
|
||||
|
||||
if (noResults) {
|
||||
ctls = <div className='sidebar--right__subheader'>No results</div>;
|
||||
} else {
|
||||
ctls = results.order.map(function mymap(id) {
|
||||
var post = results.posts[id];
|
||||
return (
|
||||
<SearchResultsItem
|
||||
key={post.id}
|
||||
post={post}
|
||||
term={searchTerm}
|
||||
isMentionSearch={this.props.isMentionSearch}
|
||||
/>
|
||||
);
|
||||
}, this);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="sidebar--right__content">
|
||||
<div className="search-bar__container sidebar--right__search-header">{searchForm}</div>
|
||||
<div className="sidebar-right__body">
|
||||
<RhsHeaderSearch isMentionSearch={this.props.isMentionSearch} />
|
||||
<div id="search-items-container" className="search-items-container">
|
||||
|
||||
{ noResults ? <div className="sidebar--right__subheader">No results</div>
|
||||
: results.order.map(function(id) {
|
||||
var post = results.posts[id];
|
||||
return <SearchItem key={post.id} post={post} term={searchTerm} isMentionSearch={this.props.isMentionSearch} />
|
||||
}, this)
|
||||
}
|
||||
|
||||
<div className='sidebar--right__content'>
|
||||
<div className='search-bar__container sidebar--right__search-header'>{searchForm}</div>
|
||||
<div className='sidebar-right__body'>
|
||||
<SearchResultsHeader isMentionSearch={this.props.isMentionSearch} />
|
||||
<div
|
||||
id='search-items-container'
|
||||
className='search-items-container'
|
||||
>
|
||||
{ctls}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
SearchResults.propTypes = {
|
||||
isMentionSearch: React.PropTypes.bool
|
||||
};
|
||||
|
||||
61
web/react/components/search_results_header.jsx
Обычный файл
61
web/react/components/search_results_header.jsx
Обычный файл
@@ -0,0 +1,61 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
|
||||
var Constants = require('../utils/constants.jsx');
|
||||
var ActionTypes = Constants.ActionTypes;
|
||||
|
||||
export default class SearchResultsHeader extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleClose = this.handleClose.bind(this);
|
||||
}
|
||||
|
||||
handleClose(e) {
|
||||
e.preventDefault();
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECIEVED_SEARCH,
|
||||
results: null
|
||||
});
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECIEVED_SEARCH_TERM,
|
||||
term: null,
|
||||
do_search: false,
|
||||
is_mention_search: false
|
||||
});
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECIEVED_POST_SELECTED,
|
||||
results: null
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
var title = 'Search Results';
|
||||
|
||||
if (this.props.isMentionSearch) {
|
||||
title = 'Recent Mentions';
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='sidebar--right__header'>
|
||||
<span className='sidebar--right__title'>{title}</span>
|
||||
<button
|
||||
type='button'
|
||||
className='sidebar--right__close'
|
||||
aria-label='Close'
|
||||
title='Close'
|
||||
onClick={this.handleClose}
|
||||
>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SearchResultsHeader.propTypes = {
|
||||
isMentionSearch: React.PropTypes.bool
|
||||
};
|
||||
105
web/react/components/search_results_item.jsx
Обычный файл
105
web/react/components/search_results_item.jsx
Обычный файл
@@ -0,0 +1,105 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
var PostStore = require('../stores/post_store.jsx');
|
||||
var ChannelStore = require('../stores/channel_store.jsx');
|
||||
var UserStore = require('../stores/user_store.jsx');
|
||||
var UserProfile = require('./user_profile.jsx');
|
||||
var utils = require('../utils/utils.jsx');
|
||||
var client = require('../utils/client.jsx');
|
||||
var AsyncClient = require('../utils/async_client.jsx');
|
||||
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
|
||||
var Constants = require('../utils/constants.jsx');
|
||||
var ActionTypes = Constants.ActionTypes;
|
||||
|
||||
export default class SearchResultsItem extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
|
||||
handleClick(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var self = this;
|
||||
|
||||
client.getPost(
|
||||
this.props.post.channel_id,
|
||||
this.props.post.id,
|
||||
function success(data) {
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECIEVED_POST_SELECTED,
|
||||
post_list: data,
|
||||
from_search: PostStore.getSearchTerm()
|
||||
});
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECIEVED_SEARCH,
|
||||
results: null,
|
||||
is_mention_search: self.props.isMentionSearch
|
||||
});
|
||||
},
|
||||
function success(err) {
|
||||
AsyncClient.dispatchError(err, 'getPost');
|
||||
}
|
||||
);
|
||||
|
||||
var postChannel = ChannelStore.get(this.props.post.channel_id);
|
||||
var teammate = '';
|
||||
|
||||
if (postChannel.type === 'D') {
|
||||
teammate = utils.getDirectTeammate(this.props.post.channel_id).username;
|
||||
}
|
||||
|
||||
utils.switchChannel(postChannel, teammate);
|
||||
}
|
||||
|
||||
render() {
|
||||
var message = utils.textToJsx(this.props.post.message, {searchTerm: this.props.term, noMentionHighlight: !this.props.isMentionSearch});
|
||||
var channelName = '';
|
||||
var channel = ChannelStore.get(this.props.post.channel_id);
|
||||
var timestamp = UserStore.getCurrentUser().update_at;
|
||||
|
||||
if (channel) {
|
||||
channelName = channel.display_name;
|
||||
if (channel.type === 'D') {
|
||||
channelName = 'Private Message';
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className='search-item-container post'
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
<div className='search-channel__name'>{channelName}</div>
|
||||
<div className='post-profile-img__container'>
|
||||
<img
|
||||
className='post-profile-img'
|
||||
src={'/api/v1/users/' + this.props.post.user_id + '/image?time=' + timestamp}
|
||||
height='36'
|
||||
width='36'
|
||||
/>
|
||||
</div>
|
||||
<div className='post__content'>
|
||||
<ul className='post-header'>
|
||||
<li className='post-header-col'><strong><UserProfile userId={this.props.post.user_id} /></strong></li>
|
||||
<li className='post-header-col'>
|
||||
<time className='search-item-time'>
|
||||
{utils.displayDate(this.props.post.create_at) + ' ' + utils.displayTime(this.props.post.create_at)}
|
||||
</time>
|
||||
</li>
|
||||
</ul>
|
||||
<div className='search-item-snippet'><span>{message}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SearchResultsItem.propTypes = {
|
||||
post: React.PropTypes.object,
|
||||
isMentionSearch: React.PropTypes.bool,
|
||||
term: React.PropTypes.string
|
||||
};
|
||||
@@ -1,25 +1,33 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
module.exports = React.createClass({
|
||||
setPicture: function(file) {
|
||||
export default class SettingPicture extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.setPicture = this.setPicture.bind(this);
|
||||
}
|
||||
|
||||
setPicture(file) {
|
||||
if (file) {
|
||||
var reader = new FileReader();
|
||||
|
||||
var img = this.refs.image.getDOMNode();
|
||||
reader.onload = function(e) {
|
||||
reader.onload = function load(e) {
|
||||
$(img).attr('src', e.target.result);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
},
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.picture) {
|
||||
this.setPicture(nextProps.picture);
|
||||
}
|
||||
},
|
||||
render: function() {
|
||||
}
|
||||
|
||||
render() {
|
||||
var clientError = null;
|
||||
if (this.props.client_error) {
|
||||
clientError = <div className='form-group has-error'><label className='control-label'>{this.props.client_error}</label></div>;
|
||||
@@ -31,14 +39,31 @@ module.exports = React.createClass({
|
||||
|
||||
var img = null;
|
||||
if (this.props.picture) {
|
||||
img = (<img ref='image' className='profile-img' src=''/>);
|
||||
img = (
|
||||
<img
|
||||
ref='image'
|
||||
className='profile-img'
|
||||
src=''
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
img = (<img ref='image' className='profile-img' src={this.props.src}/>);
|
||||
img = (
|
||||
<img
|
||||
ref='image'
|
||||
className='profile-img'
|
||||
src={this.props.src}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
var confirmButton;
|
||||
if (this.props.loadingPicture) {
|
||||
confirmButton = <img className='spinner' src='/static/images/load.gif'/>;
|
||||
confirmButton = (
|
||||
<img
|
||||
className='spinner'
|
||||
src='/static/images/load.gif'
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
var confirmButtonClass = 'btn btn-sm';
|
||||
if (this.props.submitActive) {
|
||||
@@ -46,9 +71,15 @@ module.exports = React.createClass({
|
||||
} else {
|
||||
confirmButtonClass += ' btn-inactive disabled';
|
||||
}
|
||||
confirmButton = <a className={confirmButtonClass} onClick={this.props.submit}>Save</a>;
|
||||
|
||||
confirmButton = (
|
||||
<a
|
||||
className={confirmButtonClass}
|
||||
onClick={this.props.submit}
|
||||
>Save</a>
|
||||
);
|
||||
}
|
||||
var helpText = 'Upload a profile picture in either JPG or PNG format, at least ' + config.ProfileWidth + 'px in width and ' + config.ProfileHeight + 'px height.'
|
||||
var helpText = 'Upload a profile picture in either JPG or PNG format, at least ' + config.ProfileWidth + 'px in width and ' + config.ProfileHeight + 'px height.';
|
||||
|
||||
var self = this;
|
||||
return (
|
||||
@@ -65,13 +96,36 @@ module.exports = React.createClass({
|
||||
<li className='setting-list-item'>
|
||||
{serverError}
|
||||
{clientError}
|
||||
<span className='btn btn-sm btn-primary btn-file sel-btn'>Select<input ref='input' accept='.jpg,.png,.bmp' type='file' onChange={this.props.pictureChange}/></span>
|
||||
<span className='btn btn-sm btn-primary btn-file sel-btn'
|
||||
>Select<input
|
||||
ref='input'
|
||||
accept='.jpg,.png,.bmp'
|
||||
type='file'
|
||||
onChange={this.props.pictureChange}
|
||||
/>
|
||||
</span>
|
||||
{confirmButton}
|
||||
<a className='btn btn-sm theme' href='#' onClick={self.props.updateSection}>Cancel</a>
|
||||
<a
|
||||
className='btn btn-sm theme'
|
||||
href='#'
|
||||
onClick={self.props.updateSection}
|
||||
>Cancel</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
SettingPicture.propTypes = {
|
||||
client_error: React.PropTypes.string,
|
||||
server_error: React.PropTypes.string,
|
||||
src: React.PropTypes.string,
|
||||
picture: React.PropTypes.object,
|
||||
loadingPicture: React.PropTypes.bool,
|
||||
submitActive: React.PropTypes.bool,
|
||||
submit: React.PropTypes.func,
|
||||
title: React.PropTypes.string,
|
||||
pictureChange: React.PropTypes.func
|
||||
};
|
||||
@@ -1,36 +1,37 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'Setting Upload',
|
||||
propTypes: {
|
||||
title: React.PropTypes.string.isRequired,
|
||||
submit: React.PropTypes.func.isRequired,
|
||||
fileTypesAccepted: React.PropTypes.string.isRequired,
|
||||
clientError: React.PropTypes.string,
|
||||
serverError: React.PropTypes.string,
|
||||
helpText: React.PropTypes.string
|
||||
},
|
||||
getInitialState: function() {
|
||||
return {
|
||||
export default class SettingsUpload extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.doFileSelect = this.doFileSelect.bind(this);
|
||||
this.doSubmit = this.doSubmit.bind(this);
|
||||
this.onFileSelect = this.onFileSelect.bind(this);
|
||||
|
||||
this.state = {
|
||||
clientError: this.props.clientError,
|
||||
serverError: this.props.serverError
|
||||
};
|
||||
},
|
||||
componentWillReceiveProps: function() {
|
||||
}
|
||||
|
||||
componentWillReceiveProps() {
|
||||
this.setState({
|
||||
clientError: this.props.clientError,
|
||||
serverError: this.props.serverError
|
||||
});
|
||||
},
|
||||
doFileSelect: function(e) {
|
||||
}
|
||||
|
||||
doFileSelect(e) {
|
||||
e.preventDefault();
|
||||
this.setState({
|
||||
clientError: '',
|
||||
serverError: ''
|
||||
});
|
||||
},
|
||||
doSubmit: function(e) {
|
||||
}
|
||||
|
||||
doSubmit(e) {
|
||||
e.preventDefault();
|
||||
var inputnode = this.refs.uploadinput.getDOMNode();
|
||||
if (inputnode.files && inputnode.files[0]) {
|
||||
@@ -38,16 +39,18 @@ module.exports = React.createClass({
|
||||
} else {
|
||||
this.setState({clientError: 'No file selected.'});
|
||||
}
|
||||
},
|
||||
onFileSelect: function(e) {
|
||||
}
|
||||
|
||||
onFileSelect(e) {
|
||||
var filename = $(e.target).val();
|
||||
if (filename.substring(3, 11) === 'fakepath') {
|
||||
filename = filename.substring(12);
|
||||
}
|
||||
$(e.target).closest('li').find('.file-status').addClass('hide');
|
||||
$(e.target).closest('li').find('.file-name').removeClass('hide').html(filename);
|
||||
},
|
||||
render: function() {
|
||||
}
|
||||
|
||||
render() {
|
||||
var clientError = null;
|
||||
if (this.state.clientError) {
|
||||
clientError = (
|
||||
@@ -67,7 +70,11 @@ module.exports = React.createClass({
|
||||
<li className='col-xs-offset-3 col-xs-8'>
|
||||
<ul className='setting-list'>
|
||||
<li className='setting-list-item'>
|
||||
<span className='btn btn-sm btn-primary btn-file sel-btn'>Select file<input ref='uploadinput' accept={this.props.fileTypesAccepted} type='file' onChange={this.onFileSelect}/></span>
|
||||
<span className='btn btn-sm btn-primary btn-file sel-btn'>Select file<input
|
||||
ref='uploadinput'
|
||||
accept={this.props.fileTypesAccepted}
|
||||
type='file'
|
||||
onChange={this.onFileSelect}/></span>
|
||||
<a
|
||||
className={'btn btn-sm btn-primary'}
|
||||
onClick={this.doSubmit}>
|
||||
@@ -82,4 +89,13 @@ module.exports = React.createClass({
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
SettingsUpload.propTypes = {
|
||||
title: React.PropTypes.string.isRequired,
|
||||
submit: React.PropTypes.func.isRequired,
|
||||
fileTypesAccepted: React.PropTypes.string.isRequired,
|
||||
clientError: React.PropTypes.string,
|
||||
serverError: React.PropTypes.string,
|
||||
helpText: React.PropTypes.object
|
||||
};
|
||||
@@ -5,12 +5,19 @@ var UserStore = require('../stores/user_store.jsx');
|
||||
var client = require('../utils/client.jsx');
|
||||
var utils = require('../utils/utils.jsx');
|
||||
|
||||
module.exports = React.createClass({
|
||||
handleLogoutClick: function(e) {
|
||||
export default class SidebarRightMenu extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleLogoutClick = this.handleLogoutClick.bind(this);
|
||||
}
|
||||
|
||||
handleLogoutClick(e) {
|
||||
e.preventDefault();
|
||||
client.logout();
|
||||
},
|
||||
render: function() {
|
||||
}
|
||||
|
||||
render() {
|
||||
var teamLink = '';
|
||||
var inviteLink = '';
|
||||
var teamSettingsLink = '';
|
||||
@@ -23,14 +30,22 @@ module.exports = React.createClass({
|
||||
|
||||
inviteLink = (
|
||||
<li>
|
||||
<a href='#' data-toggle='modal' data-target='#invite_member'><i className='glyphicon glyphicon-user'></i>Invite New Member</a>
|
||||
<a href='#'
|
||||
data-toggle='modal'
|
||||
data-target='#invite_member'
|
||||
><i className='glyphicon glyphicon-user'></i>Invite New Member</a>
|
||||
</li>
|
||||
);
|
||||
|
||||
if (this.props.teamType === 'O') {
|
||||
teamLink = (
|
||||
<li>
|
||||
<a href='#' data-toggle='modal' data-target='#get_link' data-title='Team Invite' data-value={utils.getWindowLocationOrigin()+'/signup_user_complete/?id='+currentUser.team_id}><i className='glyphicon glyphicon-link'></i>Get Team Invite Link</a>
|
||||
<a href='#'
|
||||
data-toggle='modal'
|
||||
data-target='#get_link'
|
||||
data-title='Team Invite'
|
||||
data-value={utils.getWindowLocationOrigin() + '/signup_user_complete/?id=' + currentUser.team_id}
|
||||
><i className='glyphicon glyphicon-link'></i>Get Team Invite Link</a>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
@@ -39,12 +54,20 @@ module.exports = React.createClass({
|
||||
if (isAdmin) {
|
||||
teamSettingsLink = (
|
||||
<li>
|
||||
<a href='#' data-toggle='modal' data-target='#team_settings'><i className='glyphicon glyphicon-globe'></i>Team Settings</a>
|
||||
<a
|
||||
href='#'
|
||||
data-toggle='modal'
|
||||
data-target='#team_settings'
|
||||
><i className='glyphicon glyphicon-globe'></i>Team Settings</a>
|
||||
</li>
|
||||
);
|
||||
manageLink = (
|
||||
<li>
|
||||
<a href='#' data-toggle='modal' data-target='#team_members'><i className='glyphicon glyphicon-wrench'></i>Manage Team</a>
|
||||
<a
|
||||
href='#'
|
||||
data-toggle='modal'
|
||||
data-target='#team_members'
|
||||
><i className='glyphicon glyphicon-wrench'></i>Manage Team</a>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
@@ -61,23 +84,48 @@ module.exports = React.createClass({
|
||||
return (
|
||||
<div>
|
||||
<div className='team__header theme'>
|
||||
<a className='team__name' href='/channels/town-square'>{teamDisplayName}</a>
|
||||
<a
|
||||
className='team__name'
|
||||
href='/channels/town-square'
|
||||
>{teamDisplayName}</a>
|
||||
</div>
|
||||
|
||||
<div className='nav-pills__container'>
|
||||
<ul className='nav nav-pills nav-stacked'>
|
||||
<li><a href='#' data-toggle='modal' data-target='#user_settings'><i className='glyphicon glyphicon-cog'></i>Account Settings</a></li>
|
||||
<li>
|
||||
<a
|
||||
href='#'
|
||||
data-toggle='modal'
|
||||
data-target='#user_settings'
|
||||
><i className='glyphicon glyphicon-cog'></i>Account Settings</a></li>
|
||||
{teamSettingsLink}
|
||||
{inviteLink}
|
||||
{teamLink}
|
||||
{manageLink}
|
||||
<li><a href='#' onClick={this.handleLogoutClick}><i className='glyphicon glyphicon-log-out'></i>Logout</a></li>
|
||||
<li>
|
||||
<a
|
||||
href='#'
|
||||
onClick={this.handleLogoutClick}
|
||||
><i className='glyphicon glyphicon-log-out'></i>Logout</a></li>
|
||||
<li className='divider'></li>
|
||||
<li><a target='_blank' href='/static/help/configure_links.html'><i className='glyphicon glyphicon-question-sign'></i>Help</a></li>
|
||||
<li><a target='_blank' href='/static/help/configure_links.html'><i className='glyphicon glyphicon-earphone'></i>Report a Problem</a></li>
|
||||
<li>
|
||||
<a
|
||||
target='_blank'
|
||||
href='/static/help/configure_links.html'
|
||||
><i className='glyphicon glyphicon-question-sign'></i>Help</a></li>
|
||||
<li>
|
||||
<a
|
||||
target='_blank'
|
||||
href='/static/help/configure_links.html'
|
||||
><i className='glyphicon glyphicon-earphone'></i>Report a Problem</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
SidebarRightMenu.propTypes = {
|
||||
teamType: React.PropTypes.string,
|
||||
teamDisplayName: React.PropTypes.string
|
||||
};
|
||||
@@ -4,22 +4,34 @@
|
||||
var utils = require('../utils/utils.jsx');
|
||||
var SettingUpload = require('./setting_upload.jsx');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'Import Tab',
|
||||
getInitialState: function() {
|
||||
return {status: 'ready', link: ''};
|
||||
},
|
||||
onImportFailure: function() {
|
||||
export default class TeamImportTab extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.onImportFailure = this.onImportFailure.bind(this);
|
||||
this.onImportSuccess = this.onImportSuccess.bind(this);
|
||||
this.doImportSlack = this.doImportSlack.bind(this);
|
||||
|
||||
this.state = {
|
||||
status: 'ready',
|
||||
link: ''
|
||||
};
|
||||
}
|
||||
|
||||
onImportFailure() {
|
||||
this.setState({status: 'fail', link: ''});
|
||||
},
|
||||
onImportSuccess: function(data) {
|
||||
}
|
||||
|
||||
onImportSuccess(data) {
|
||||
this.setState({status: 'done', link: 'data:application/octet-stream;charset=utf-8,' + encodeURIComponent(data)});
|
||||
},
|
||||
doImportSlack: function(file) {
|
||||
}
|
||||
|
||||
doImportSlack(file) {
|
||||
this.setState({status: 'in-progress', link: ''});
|
||||
utils.importSlack(file, this.onImportSuccess, this.onImportFailure);
|
||||
},
|
||||
render: function() {
|
||||
}
|
||||
|
||||
render() {
|
||||
var uploadHelpText = (
|
||||
<div>
|
||||
<br/>
|
||||
@@ -39,22 +51,25 @@ module.exports = React.createClass({
|
||||
|
||||
var messageSection;
|
||||
switch (this.state.status) {
|
||||
case 'ready':
|
||||
messageSection = '';
|
||||
|
||||
case 'ready':
|
||||
messageSection = '';
|
||||
break;
|
||||
case 'in-progress':
|
||||
messageSection = (
|
||||
<p className="confirm-import alert alert-warning"><i className="fa fa-spinner fa-pulse"></i> Importing...</p>
|
||||
case 'in-progress':
|
||||
messageSection = (
|
||||
<p className='confirm-import alert alert-warning'><i className='fa fa-spinner fa-pulse'></i> Importing...</p>
|
||||
);
|
||||
break;
|
||||
case 'done':
|
||||
messageSection = (
|
||||
<p className="confirm-import alert alert-success"><i className="fa fa-check"></i> Import successful: <a href={this.state.link} download='MattermostImportSummary.txt'>View Summary</a></p>
|
||||
case 'done':
|
||||
messageSection = (
|
||||
<p className='confirm-import alert alert-success'><i className='fa fa-check'></i> Import successful: <a href={this.state.link}
|
||||
download='MattermostImportSummary.txt'>View Summary</a></p>
|
||||
);
|
||||
break;
|
||||
case 'fail':
|
||||
messageSection = (
|
||||
<p className="confirm-import alert alert-warning"><i className="fa fa-warning"></i> Import failure: <a href={this.state.link} download='MattermostImportSummary.txt'>View Summary</a></p>
|
||||
case 'fail':
|
||||
messageSection = (
|
||||
<p className='confirm-import alert alert-warning'><i className='fa fa-warning'></i> Import failure: <a href={this.state.link}
|
||||
download='MattermostImportSummary.txt'>View Summary</a></p>
|
||||
);
|
||||
break;
|
||||
}
|
||||
@@ -62,10 +77,22 @@ module.exports = React.createClass({
|
||||
return (
|
||||
<div>
|
||||
<div className='modal-header'>
|
||||
<button type='button' className='close' data-dismiss='modal' aria-label='Close'><span aria-hidden='true'>×</span></button>
|
||||
<h4 className='modal-title' ref='title'><i className='modal-back'></i>Import</h4>
|
||||
<button type='button'
|
||||
className='close'
|
||||
data-dismiss='modal'
|
||||
aria-label='Close'
|
||||
>
|
||||
<span aria-hidden='true'>×</span>
|
||||
</button>
|
||||
<h4
|
||||
className='modal-title'
|
||||
ref='title'
|
||||
><i className='modal-back'></i>Import</h4>
|
||||
</div>
|
||||
<div ref='wrapper' className='user-settings'>
|
||||
<div
|
||||
ref='wrapper'
|
||||
className='user-settings'
|
||||
>
|
||||
<h3 className='tab-header'>Import</h3>
|
||||
<div className='divider-dark first'/>
|
||||
{uploadSection}
|
||||
@@ -75,4 +102,4 @@ module.exports = React.createClass({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,77 +2,131 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
var UserStore = require('../stores/user_store.jsx');
|
||||
var ChannelStore = require('../stores/channel_store.jsx');
|
||||
var MemberListTeam = require('./member_list_team.jsx');
|
||||
var Client = require('../utils/client.jsx');
|
||||
var utils = require('../utils/utils.jsx');
|
||||
|
||||
function getStateFromStores() {
|
||||
var users = UserStore.getProfiles();
|
||||
var member_list = [];
|
||||
for (var id in users) member_list.push(users[id]);
|
||||
var memberList = [];
|
||||
for (var id in users) {
|
||||
if (users.hasOwnProperty(id)) {
|
||||
memberList.push(users[id]);
|
||||
}
|
||||
}
|
||||
|
||||
memberList.sort(function sort(a, b) {
|
||||
if (a.username < b.username) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a.username > b.username) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
member_list.sort(function(a,b) {
|
||||
if (a.username < b.username) return -1;
|
||||
if (a.username > b.username) return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
return {
|
||||
member_list: member_list
|
||||
member_list: memberList
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = React.createClass({
|
||||
componentDidMount: function() {
|
||||
UserStore.addChangeListener(this._onChange);
|
||||
export default class TeamMembers extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.onChange = this.onChange.bind(this);
|
||||
|
||||
this.state = getStateFromStores();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
UserStore.addChangeListener(this.onChange);
|
||||
|
||||
var self = this;
|
||||
$(this.refs.modal.getDOMNode()).on('hidden.bs.modal', function(e) {
|
||||
self.setState({ render_members: false });
|
||||
$(this.refs.modal.getDOMNode()).on('hidden.bs.modal', function show() {
|
||||
self.setState({render_members: false});
|
||||
});
|
||||
|
||||
$(this.refs.modal.getDOMNode()).on('show.bs.modal', function(e) {
|
||||
self.setState({ render_members: true });
|
||||
$(this.refs.modal.getDOMNode()).on('show.bs.modal', function hide() {
|
||||
self.setState({render_members: true});
|
||||
});
|
||||
},
|
||||
componentWillUnmount: function() {
|
||||
UserStore.removeChangeListener(this._onChange);
|
||||
},
|
||||
_onChange: function() {
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
UserStore.removeChangeListener(this.onChange);
|
||||
}
|
||||
|
||||
onChange() {
|
||||
var newState = getStateFromStores();
|
||||
if (!utils.areStatesEqual(newState, this.state)) {
|
||||
this.setState(newState);
|
||||
}
|
||||
},
|
||||
getInitialState: function() {
|
||||
return getStateFromStores();
|
||||
},
|
||||
render: function() {
|
||||
var server_error = this.state.server_error ? <label className='has-error control-label'>{this.state.server_error}</label> : null;
|
||||
}
|
||||
|
||||
render() {
|
||||
var serverError = null;
|
||||
|
||||
if (this.state.server_error) {
|
||||
serverError = <label className='has-error control-label'>{this.state.server_error}</label>;
|
||||
}
|
||||
|
||||
var renderMembers = '';
|
||||
|
||||
if (this.state.render_members) {
|
||||
renderMembers = <MemberListTeam users={this.state.member_list} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="modal fade" ref="modal" id="team_members" 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" aria-label="Close" data-reactid=".5.0.0.0.0"><span aria-hidden="true" data-reactid=".5.0.0.0.0.0">×</span></button>
|
||||
<h4 className="modal-title" id="myModalLabel">{this.props.teamDisplayName + " Members"}</h4>
|
||||
</div>
|
||||
<div ref="modalBody" className="modal-body">
|
||||
<div className="channel-settings">
|
||||
<div className="team-member-list">
|
||||
{ this.state.render_members ? <MemberListTeam users={this.state.member_list} /> : "" }
|
||||
<div
|
||||
className='modal fade'
|
||||
ref='modal'
|
||||
id='team_members'
|
||||
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'
|
||||
aria-label='Close'
|
||||
>
|
||||
<span aria-hidden='true'>×</span>
|
||||
</button>
|
||||
<h4
|
||||
className='modal-title'
|
||||
id='myModalLabel'
|
||||
>{this.props.teamDisplayName + ' Members'}</h4>
|
||||
</div>
|
||||
<div
|
||||
ref='modalBody'
|
||||
className='modal-body'
|
||||
>
|
||||
<div className='channel-settings'>
|
||||
<div className='team-member-list'>
|
||||
{renderMembers}
|
||||
</div>
|
||||
{serverError}
|
||||
</div>
|
||||
{ server_error }
|
||||
</div>
|
||||
<div className='modal-footer'>
|
||||
<button
|
||||
type='button'
|
||||
className='btn btn-default'
|
||||
data-dismiss='modal'
|
||||
>Close</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
<button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
TeamMembers.propTypes = {
|
||||
teamDisplayName: React.PropTypes.string
|
||||
};
|
||||
|
||||
@@ -8,56 +8,82 @@ var SecurityTab = require('./user_settings_security.jsx');
|
||||
var GeneralTab = require('./user_settings_general.jsx');
|
||||
var AppearanceTab = require('./user_settings_appearance.jsx');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'UserSettings',
|
||||
propTypes: {
|
||||
activeTab: React.PropTypes.string,
|
||||
activeSection: React.PropTypes.string,
|
||||
updateSection: React.PropTypes.func,
|
||||
updateTab: React.PropTypes.func
|
||||
},
|
||||
componentDidMount: function() {
|
||||
export default class UserSettings extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.onListenerChange = this.onListenerChange.bind(this);
|
||||
|
||||
this.state = {user: UserStore.getCurrentUser()};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
UserStore.addChangeListener(this.onListenerChange);
|
||||
},
|
||||
componentWillUnmount: function() {
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
UserStore.removeChangeListener(this.onListenerChange);
|
||||
},
|
||||
onListenerChange: function () {
|
||||
}
|
||||
|
||||
onListenerChange() {
|
||||
var user = UserStore.getCurrentUser();
|
||||
if (!utils.areStatesEqual(this.state.user, user)) {
|
||||
this.setState({user: user});
|
||||
}
|
||||
},
|
||||
getInitialState: function() {
|
||||
return {user: UserStore.getCurrentUser()};
|
||||
},
|
||||
render: function() {
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.props.activeTab === 'general') {
|
||||
return (
|
||||
<div>
|
||||
<GeneralTab user={this.state.user} activeSection={this.props.activeSection} updateSection={this.props.updateSection} />
|
||||
<GeneralTab
|
||||
user={this.state.user}
|
||||
activeSection={this.props.activeSection}
|
||||
updateSection={this.props.updateSection}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
} else if (this.props.activeTab === 'security') {
|
||||
return (
|
||||
<div>
|
||||
<SecurityTab user={this.state.user} activeSection={this.props.activeSection} updateSection={this.props.updateSection} updateTab={this.props.updateTab} />
|
||||
<SecurityTab
|
||||
user={this.state.user}
|
||||
activeSection={this.props.activeSection}
|
||||
updateSection={this.props.updateSection}
|
||||
updateTab={this.props.updateTab}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
} else if (this.props.activeTab === 'notifications') {
|
||||
return (
|
||||
<div>
|
||||
<NotificationsTab user={this.state.user} activeSection={this.props.activeSection} updateSection={this.props.updateSection} updateTab={this.props.updateTab} />
|
||||
<NotificationsTab
|
||||
user={this.state.user}
|
||||
activeSection={this.props.activeSection}
|
||||
updateSection={this.props.updateSection}
|
||||
updateTab={this.props.updateTab}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
} else if (this.props.activeTab === 'appearance') {
|
||||
return (
|
||||
<div>
|
||||
<AppearanceTab activeSection={this.props.activeSection} updateSection={this.props.updateSection} updateTab={this.props.updateTab} />
|
||||
<AppearanceTab
|
||||
activeSection={this.props.activeSection}
|
||||
updateSection={this.props.updateSection}
|
||||
updateTab={this.props.updateTab}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return <div/>;
|
||||
}
|
||||
|
||||
return <div/>;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
UserSettings.propTypes = {
|
||||
activeTab: React.PropTypes.string,
|
||||
activeSection: React.PropTypes.string,
|
||||
updateSection: React.PropTypes.func,
|
||||
updateTab: React.PropTypes.func
|
||||
};
|
||||
Ссылка в новой задаче
Block a user