MM-2065 style refactoring
Этот коммит содержится в:
@@ -3,57 +3,86 @@
|
|||||||
|
|
||||||
var ChannelStore = require('../stores/channel_store.jsx');
|
var ChannelStore = require('../stores/channel_store.jsx');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
export default class CommandList extends React.Component {
|
||||||
componentDidMount: function() {
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
channel_id: ChannelStore.getCurrentId()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
var self = this;
|
var self = this;
|
||||||
if(this.refs.modal) {
|
if (this.refs.modal) {
|
||||||
$(this.refs.modal.getDOMNode()).on('show.bs.modal', function(e) {
|
$(this.refs.modal.getDOMNode()).on('show.bs.modal', function show(e) {
|
||||||
var button = e.relatedTarget;
|
var button = e.relatedTarget;
|
||||||
self.setState({ channel_id: $(button).attr('data-channelid') });
|
self.setState({channel_id: $(button).attr('data-channelid')});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
getInitialState: function() {
|
|
||||||
return { channel_id: ChannelStore.getCurrentId() };
|
render() {
|
||||||
},
|
|
||||||
render: function() {
|
|
||||||
var channel = ChannelStore.get(this.state.channel_id);
|
var channel = ChannelStore.get(this.state.channel_id);
|
||||||
|
|
||||||
if (!channel) {
|
if (!channel) {
|
||||||
channel = {};
|
channel = {};
|
||||||
channel.display_name = "No Channel Found";
|
channel.display_name = 'No Channel Found';
|
||||||
channel.name = "No Channel Found";
|
channel.name = 'No Channel Found';
|
||||||
channel.id = "No Channel Found";
|
channel.id = 'No Channel Found';
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="modal fade" ref="modal" id="channel_info" tabIndex="-1" role="dialog" aria-hidden="true">
|
<div
|
||||||
<div className="modal-dialog">
|
className='modal fade'
|
||||||
<div className="modal-content">
|
ref='modal'
|
||||||
<div className="modal-header">
|
id='channel_info'
|
||||||
<button type="button" className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
tabIndex='-1'
|
||||||
<h4 className="modal-title" id="myModalLabel"><span className="name">{channel.display_name}</span></h4>
|
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>
|
||||||
<div className="modal-body">
|
<div className='modal-body'>
|
||||||
<div className="row form-group">
|
<div className='row form-group'>
|
||||||
<div className="col-sm-3 info__label">Channel Name: </div>
|
<div className='col-sm-3 info__label'>Channel Name: </div>
|
||||||
<div className="col-sm-9">{channel.display_name}</div>
|
<div className='col-sm-9'>{channel.display_name}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="row form-group">
|
<div className='row form-group'>
|
||||||
<div className="col-sm-3 info__label">Channel Handle:</div>
|
<div className='col-sm-3 info__label'>Channel Handle:</div>
|
||||||
<div className="col-sm-9">{channel.name}</div>
|
<div className='col-sm-9'>{channel.name}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="row">
|
<div className='row'>
|
||||||
<div className="col-sm-3 info__label">Channel ID:</div>
|
<div className='col-sm-3 info__label'>Channel ID:</div>
|
||||||
<div className="col-sm-9">{channel.id}</div>
|
<div className='col-sm-9'>{channel.id}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="modal-footer">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ var utils = require('../utils/utils.jsx');
|
|||||||
var client = require('../utils/client.jsx');
|
var client = require('../utils/client.jsx');
|
||||||
var AsyncClient = require('../utils/async_client.jsx');
|
var AsyncClient = require('../utils/async_client.jsx');
|
||||||
|
|
||||||
|
|
||||||
export default class ChannelInviteModal extends React.Component {
|
export default class ChannelInviteModal extends React.Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@@ -129,15 +128,37 @@ export default class ChannelInviteModal extends React.Component {
|
|||||||
if (this.state.loading) {
|
if (this.state.loading) {
|
||||||
content = (<LoadingScreen />);
|
content = (<LoadingScreen />);
|
||||||
} else {
|
} else {
|
||||||
content = (<MemberList memberList={this.state.nonmembers} isAdmin={isAdmin} handleInvite={this.handleInvite} />);
|
content = (
|
||||||
|
<MemberList
|
||||||
|
memberList={this.state.nonmembers}
|
||||||
|
isAdmin={isAdmin}
|
||||||
|
handleInvite={this.handleInvite}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='modal fade' id='channel_invite' tabIndex='-1' role='dialog' aria-hidden='true'>
|
<div
|
||||||
<div className='modal-dialog' role='document'>
|
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-content'>
|
||||||
<div className='modal-header'>
|
<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>
|
<h4 className='modal-title'>Add New Members to <span className='name'>{this.state.channelName}</span></h4>
|
||||||
</div>
|
</div>
|
||||||
<div className='modal-body'>
|
<div className='modal-body'>
|
||||||
@@ -145,7 +166,11 @@ export default class ChannelInviteModal extends React.Component {
|
|||||||
{content}
|
{content}
|
||||||
</div>
|
</div>
|
||||||
<div className='modal-footer'>
|
<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>
|
||||||
</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');
|
var client = require('../utils/client.jsx');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
export default class CommandList extends React.Component {
|
||||||
getInitialState: function() {
|
constructor(props) {
|
||||||
return { suggestions: [ ], cmd: "" };
|
super(props);
|
||||||
},
|
|
||||||
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) {
|
|
||||||
|
|
||||||
if (!cmd || cmd.charAt(0) != '/') {
|
this.handleClick = this.handleClick.bind(this);
|
||||||
this.setState({ suggestions: [ ], cmd: "" });
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,36 +44,56 @@ module.exports = React.createClass({
|
|||||||
this.props.channelId,
|
this.props.channelId,
|
||||||
cmd,
|
cmd,
|
||||||
true,
|
true,
|
||||||
function(data) {
|
function success(data) {
|
||||||
if (data.suggestions.length === 1 && data.suggestions[0].suggestion === cmd) {
|
if (data.suggestions.length === 1 && data.suggestions[0].suggestion === cmd) {
|
||||||
data.suggestions = [];
|
data.suggestions = [];
|
||||||
}
|
}
|
||||||
this.setState({ suggestions: data.suggestions, cmd: cmd });
|
this.setState({suggestions: data.suggestions, cmd: cmd});
|
||||||
}.bind(this),
|
}.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 = [];
|
var suggestions = [];
|
||||||
|
|
||||||
for (var i = 0; i < this.state.suggestions.length; i++) {
|
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(
|
suggestions.push(
|
||||||
<div key={i} className="command-name" onClick={this.handleClick.bind(this, i)}>
|
<div
|
||||||
<div className="command__title"><strong>{ this.state.suggestions[i].suggestion }</strong></div>
|
key={i}
|
||||||
<div className="command__desc">{ this.state.suggestions[i].description }</div>
|
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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref="mentionlist" className="command-box" style={{height:(this.state.suggestions.length*56)+2}}>
|
<div
|
||||||
{ suggestions }
|
ref='mentionlist'
|
||||||
|
className='command-box'
|
||||||
|
style={{height: (this.state.suggestions.length * 56) + 2}}
|
||||||
|
>
|
||||||
|
{suggestions}
|
||||||
</div>
|
</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 ChannelStore = require('../stores/channel_store.jsx');
|
||||||
var utils = require('../utils/utils.jsx');
|
var utils = require('../utils/utils.jsx');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
export default class FileUpload extends React.Component {
|
||||||
displayName: 'FileUpload',
|
constructor(props) {
|
||||||
propTypes: {
|
super(props);
|
||||||
onUploadError: React.PropTypes.func,
|
|
||||||
getFileCount: React.PropTypes.func,
|
this.handleChange = this.handleChange.bind(this);
|
||||||
onFileUpload: React.PropTypes.func,
|
this.handleDrop = this.handleDrop.bind(this);
|
||||||
onUploadStart: React.PropTypes.func,
|
|
||||||
channelId: React.PropTypes.string,
|
this.state = {
|
||||||
postType: React.PropTypes.string
|
requests: {}
|
||||||
},
|
};
|
||||||
getInitialState: function() {
|
}
|
||||||
return {requests: {}};
|
|
||||||
},
|
handleChange() {
|
||||||
handleChange: function() {
|
|
||||||
var element = $(this.refs.fileInput.getDOMNode());
|
var element = $(this.refs.fileInput.getDOMNode());
|
||||||
var files = element.prop('files');
|
var files = element.prop('files');
|
||||||
|
|
||||||
@@ -30,7 +29,7 @@ module.exports = React.createClass({
|
|||||||
// This looks redundant, but must be done this way due to
|
// This looks redundant, but must be done this way due to
|
||||||
// setState being an asynchronous call
|
// setState being an asynchronous call
|
||||||
var numFiles = 0;
|
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) {
|
if (files[i].size <= Constants.MAX_FILE_SIZE) {
|
||||||
numFiles++;
|
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.');
|
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) {
|
if (files[i].size > Constants.MAX_FILE_SIZE) {
|
||||||
this.props.onUploadError('Files must be no more than ' + Constants.MAX_FILE_SIZE / 1000000 + ' MB');
|
this.props.onUploadError('Files must be no more than ' + Constants.MAX_FILE_SIZE / 1000000 + ' MB');
|
||||||
continue;
|
continue;
|
||||||
@@ -58,7 +57,7 @@ module.exports = React.createClass({
|
|||||||
formData.append('client_ids', clientId);
|
formData.append('client_ids', clientId);
|
||||||
|
|
||||||
var request = client.uploadFile(formData,
|
var request = client.uploadFile(formData,
|
||||||
function(data) {
|
function success(data) {
|
||||||
var parsedData = $.parseJSON(data);
|
var parsedData = $.parseJSON(data);
|
||||||
this.props.onFileUpload(parsedData.filenames, parsedData.client_ids, channelId);
|
this.props.onFileUpload(parsedData.filenames, parsedData.client_ids, channelId);
|
||||||
|
|
||||||
@@ -68,7 +67,7 @@ module.exports = React.createClass({
|
|||||||
}
|
}
|
||||||
this.setState({requests: requests});
|
this.setState({requests: requests});
|
||||||
}.bind(this),
|
}.bind(this),
|
||||||
function(err) {
|
function fail(err) {
|
||||||
this.props.onUploadError(err, clientId);
|
this.props.onUploadError(err, clientId);
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
);
|
);
|
||||||
@@ -87,9 +86,12 @@ module.exports = React.createClass({
|
|||||||
element[0].type = 'text';
|
element[0].type = 'text';
|
||||||
element[0].type = 'file';
|
element[0].type = 'file';
|
||||||
}
|
}
|
||||||
} catch(e) {}
|
} catch(e) {
|
||||||
},
|
// Do nothing
|
||||||
handleDrop: function(e) {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleDrop(e) {
|
||||||
this.props.onUploadError(null);
|
this.props.onUploadError(null);
|
||||||
|
|
||||||
var files = e.originalEvent.dataTransfer.files;
|
var files = e.originalEvent.dataTransfer.files;
|
||||||
@@ -120,7 +122,7 @@ module.exports = React.createClass({
|
|||||||
formData.append('client_ids', clientId);
|
formData.append('client_ids', clientId);
|
||||||
|
|
||||||
var request = client.uploadFile(formData,
|
var request = client.uploadFile(formData,
|
||||||
function(data) {
|
function success(data) {
|
||||||
var parsedData = $.parseJSON(data);
|
var parsedData = $.parseJSON(data);
|
||||||
this.props.onFileUpload(parsedData.filenames, parsedData.client_ids, channelId);
|
this.props.onFileUpload(parsedData.filenames, parsedData.client_ids, channelId);
|
||||||
|
|
||||||
@@ -130,7 +132,7 @@ module.exports = React.createClass({
|
|||||||
}
|
}
|
||||||
this.setState({requests: requests});
|
this.setState({requests: requests});
|
||||||
}.bind(this),
|
}.bind(this),
|
||||||
function(err) {
|
function fail(err) {
|
||||||
this.props.onUploadError(err, clientId);
|
this.props.onUploadError(err, clientId);
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
);
|
);
|
||||||
@@ -144,40 +146,41 @@ module.exports = React.createClass({
|
|||||||
} else {
|
} else {
|
||||||
this.props.onUploadError('Invalid file upload', -1);
|
this.props.onUploadError('Invalid file upload', -1);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
componentDidMount: function() {
|
|
||||||
|
componentDidMount() {
|
||||||
var inputDiv = this.refs.input.getDOMNode();
|
var inputDiv = this.refs.input.getDOMNode();
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
if (this.props.postType === 'post') {
|
if (this.props.postType === 'post') {
|
||||||
$('.row.main').dragster({
|
$('.row.main').dragster({
|
||||||
enter: function() {
|
enter() {
|
||||||
$('.center-file-overlay').removeClass('hidden');
|
$('.center-file-overlay').removeClass('hidden');
|
||||||
},
|
},
|
||||||
leave: function() {
|
leave() {
|
||||||
$('.center-file-overlay').addClass('hidden');
|
$('.center-file-overlay').addClass('hidden');
|
||||||
},
|
},
|
||||||
drop: function(dragsterEvent, e) {
|
drop(dragsterEvent, e) {
|
||||||
$('.center-file-overlay').addClass('hidden');
|
$('.center-file-overlay').addClass('hidden');
|
||||||
self.handleDrop(e);
|
self.handleDrop(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (this.props.postType === 'comment') {
|
} else if (this.props.postType === 'comment') {
|
||||||
$('.post-right__container').dragster({
|
$('.post-right__container').dragster({
|
||||||
enter: function() {
|
enter() {
|
||||||
$('.right-file-overlay').removeClass('hidden');
|
$('.right-file-overlay').removeClass('hidden');
|
||||||
},
|
},
|
||||||
leave: function() {
|
leave() {
|
||||||
$('.right-file-overlay').addClass('hidden');
|
$('.right-file-overlay').addClass('hidden');
|
||||||
},
|
},
|
||||||
drop: function(dragsterEvent, e) {
|
drop(dragsterEvent, e) {
|
||||||
$('.right-file-overlay').addClass('hidden');
|
$('.right-file-overlay').addClass('hidden');
|
||||||
self.handleDrop(e);
|
self.handleDrop(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('paste', function(e) {
|
document.addEventListener('paste', function handlePaste(e) {
|
||||||
var textarea = $(inputDiv.parentNode.parentNode).find('.custom-textarea')[0];
|
var textarea = $(inputDiv.parentNode.parentNode).find('.custom-textarea')[0];
|
||||||
|
|
||||||
if (textarea !== e.target && !$.contains(textarea, e.target)) {
|
if (textarea !== e.target && !$.contains(textarea, e.target)) {
|
||||||
@@ -191,7 +194,7 @@ module.exports = React.createClass({
|
|||||||
var items = e.clipboardData.items;
|
var items = e.clipboardData.items;
|
||||||
var numItems = 0;
|
var numItems = 0;
|
||||||
if (items) {
|
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) {
|
if (items[i].type.indexOf('image') !== -1) {
|
||||||
var testExt = items[i].type.split('/')[1].toLowerCase();
|
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 requests = this.state.requests;
|
||||||
var request = requests[clientId];
|
var request = requests[clientId];
|
||||||
|
|
||||||
@@ -280,15 +284,33 @@ module.exports = React.createClass({
|
|||||||
delete requests[clientId];
|
delete requests[clientId];
|
||||||
this.setState({requests: requests});
|
this.setState({requests: requests});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
render: function() {
|
|
||||||
|
render() {
|
||||||
return (
|
return (
|
||||||
<span ref='input' className='btn btn-file'>
|
<span
|
||||||
|
ref='input'
|
||||||
|
className='btn btn-file'
|
||||||
|
>
|
||||||
<span>
|
<span>
|
||||||
<i className='glyphicon glyphicon-paperclip' />
|
<i className='glyphicon glyphicon-paperclip' />
|
||||||
</span>
|
</span>
|
||||||
<input ref='fileInput' type='file' onChange={this.handleChange} multiple/>
|
<input
|
||||||
|
ref='fileInput'
|
||||||
|
type='file'
|
||||||
|
onChange={this.handleChange}
|
||||||
|
multiple='true'
|
||||||
|
/>
|
||||||
</span>
|
</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.
|
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
|
||||||
var utils = require('../utils/utils.jsx');
|
var utils = require('../utils/utils.jsx');
|
||||||
var client = require('../utils/client.jsx');
|
var client = require('../utils/client.jsx');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
export default class FindTeam extends React.Component {
|
||||||
handleSubmit: function(e) {
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {};
|
||||||
|
|
||||||
|
this.handleSubmit = this.handleSubmit.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSubmit(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
var state = { };
|
var state = { };
|
||||||
|
|
||||||
var email = this.refs.email.getDOMNode().value.trim().toLowerCase();
|
var email = this.refs.email.getDOMNode().value.trim().toLowerCase();
|
||||||
if (!email || !utils.isEmail(email)) {
|
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);
|
this.setState(state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
state.email_error = "";
|
state.email_error = '';
|
||||||
}
|
|
||||||
|
|
||||||
client.findTeamsSendEmail(email,
|
client.findTeamsSendEmail(email,
|
||||||
function(data) {
|
function success() {
|
||||||
state.sent = true;
|
state.sent = true;
|
||||||
this.setState(state);
|
this.setState(state);
|
||||||
}.bind(this),
|
}.bind(this),
|
||||||
function(err) {
|
function fail(err) {
|
||||||
state.email_error = err.message;
|
state.email_error = err.message;
|
||||||
this.setState(state);
|
this.setState(state);
|
||||||
}.bind(this)
|
}.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 = {
|
if (this.state.email_error) {
|
||||||
"marginTop": "50px",
|
emailError = <label className='control-label'>{this.state.email_error}</label>;
|
||||||
|
emailErrorClass = 'form-group has-error';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.sent) {
|
if (this.state.sent) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h4>{"Find Your " + utils.toTitleCase(strings.Team)}</h4>
|
<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>
|
<p>{'An email was sent with links to any ' + strings.TeamPlural + ' to which you are a member.'}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -56,17 +60,25 @@ module.exports = React.createClass({
|
|||||||
<div>
|
<div>
|
||||||
<h4>Find Your Team</h4>
|
<h4>Find Your Team</h4>
|
||||||
<form onSubmit={this.handleSubmit}>
|
<form onSubmit={this.handleSubmit}>
|
||||||
<p>{"Get an email with links to any " + strings.TeamPlural + " to which you are a member."}</p>
|
<p>{'Get an email with links to any ' + strings.TeamPlural + ' to which you are a member.'}</p>
|
||||||
<div className="form-group">
|
<div className='form-group'>
|
||||||
<label className='control-label'>Email</label>
|
<label className='control-label'>Email</label>
|
||||||
<div className={ email_error ? "form-group has-error" : "form-group" }>
|
<div className={emailErrorClass}>
|
||||||
<input type="text" ref="email" className="form-control" placeholder="you@domain.com" maxLength="128" />
|
<input
|
||||||
{ email_error }
|
type='text'
|
||||||
|
ref='email'
|
||||||
|
className='form-control'
|
||||||
|
placeholder='you@domain.com'
|
||||||
|
maxLength='128'
|
||||||
|
/>
|
||||||
|
{emailError}
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@@ -7,10 +7,28 @@ var Client = require('../utils/client.jsx');
|
|||||||
var UserStore = require('../stores/user_store.jsx');
|
var UserStore = require('../stores/user_store.jsx');
|
||||||
var ConfirmModal = require('./confirm_modal.jsx');
|
var ConfirmModal = require('./confirm_modal.jsx');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
export default class InviteMemberModal extends React.Component {
|
||||||
componentDidMount: function() {
|
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;
|
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') {
|
if ($('#invite_member').attr('data-confirm') === 'true') {
|
||||||
$('#invite_member').attr('data-confirm', 'false');
|
$('#invite_member').attr('data-confirm', 'false');
|
||||||
return;
|
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();
|
self.clearFields();
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
handleSubmit: function(e) {
|
|
||||||
|
handleSubmit() {
|
||||||
if (!this.state.emailEnabled) {
|
if (!this.state.emailEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -90,11 +109,11 @@ module.exports = React.createClass({
|
|||||||
data.invites = invites;
|
data.invites = invites;
|
||||||
|
|
||||||
Client.inviteMembers(data,
|
Client.inviteMembers(data,
|
||||||
function() {
|
function success() {
|
||||||
$(this.refs.modal.getDOMNode()).attr('data-confirm', 'true');
|
$(this.refs.modal.getDOMNode()).attr('data-confirm', 'true');
|
||||||
$(this.refs.modal.getDOMNode()).modal('hide');
|
$(this.refs.modal.getDOMNode()).modal('hide');
|
||||||
}.bind(this),
|
}.bind(this),
|
||||||
function(err) {
|
function fail(err) {
|
||||||
if (err.message === 'This person is already on your team') {
|
if (err.message === 'This person is already on your team') {
|
||||||
emailErrors[err.detailed_error] = err.message;
|
emailErrors[err.detailed_error] = err.message;
|
||||||
this.setState({emailErrors: emailErrors});
|
this.setState({emailErrors: emailErrors});
|
||||||
@@ -103,18 +122,21 @@ module.exports = React.createClass({
|
|||||||
}
|
}
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
componentDidUpdate: function() {
|
|
||||||
|
componentDidUpdate() {
|
||||||
$(this.refs.modalBody.getDOMNode()).css('max-height', $(window).height() - 200);
|
$(this.refs.modalBody.getDOMNode()).css('max-height', $(window).height() - 200);
|
||||||
$(this.refs.modalBody.getDOMNode()).css('overflow-y', 'scroll');
|
$(this.refs.modalBody.getDOMNode()).css('overflow-y', 'scroll');
|
||||||
},
|
}
|
||||||
addInviteFields: function() {
|
|
||||||
|
addInviteFields() {
|
||||||
var count = this.state.idCount + 1;
|
var count = this.state.idCount + 1;
|
||||||
var inviteIds = this.state.inviteIds;
|
var inviteIds = this.state.inviteIds;
|
||||||
inviteIds.push(count);
|
inviteIds.push(count);
|
||||||
this.setState({inviteIds: inviteIds, idCount: count});
|
this.setState({inviteIds: inviteIds, idCount: count});
|
||||||
},
|
}
|
||||||
clearFields: function() {
|
|
||||||
|
clearFields() {
|
||||||
var inviteIds = this.state.inviteIds;
|
var inviteIds = this.state.inviteIds;
|
||||||
|
|
||||||
for (var i = 0; i < inviteIds.length; i++) {
|
for (var i = 0; i < inviteIds.length; i++) {
|
||||||
@@ -133,8 +155,9 @@ module.exports = React.createClass({
|
|||||||
firstNameErrors: {},
|
firstNameErrors: {},
|
||||||
lastNameErrors: {}
|
lastNameErrors: {}
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
removeInviteFields: function(index) {
|
|
||||||
|
removeInviteFields(index) {
|
||||||
var count = this.state.idCount;
|
var count = this.state.idCount;
|
||||||
var inviteIds = this.state.inviteIds;
|
var inviteIds = this.state.inviteIds;
|
||||||
var i = inviteIds.indexOf(index);
|
var i = inviteIds.indexOf(index);
|
||||||
@@ -145,24 +168,10 @@ module.exports = React.createClass({
|
|||||||
inviteIds.push(++count);
|
inviteIds.push(++count);
|
||||||
}
|
}
|
||||||
this.setState({inviteIds: inviteIds, idCount: 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 = '';
|
render() {
|
||||||
if (!this.state.emailEnabled) {
|
var currentUser = UserStore.getCurrentUser();
|
||||||
inputDisabled = 'disabled';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentUser != null) {
|
if (currentUser != null) {
|
||||||
var inviteSections = [];
|
var inviteSections = [];
|
||||||
@@ -185,7 +194,13 @@ module.exports = React.createClass({
|
|||||||
var removeButton = null;
|
var removeButton = null;
|
||||||
if (index) {
|
if (index) {
|
||||||
removeButton = (<div>
|
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>);
|
</div>);
|
||||||
}
|
}
|
||||||
var emailClass = 'form-group invite';
|
var emailClass = 'form-group invite';
|
||||||
@@ -206,13 +221,27 @@ module.exports = React.createClass({
|
|||||||
nameFields = (<div className='row--invite'>
|
nameFields = (<div className='row--invite'>
|
||||||
<div className='col-sm-6'>
|
<div className='col-sm-6'>
|
||||||
<div className={firstNameClass}>
|
<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}
|
{firstNameError}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='col-sm-6'>
|
<div className='col-sm-6'>
|
||||||
<div className={lastNameClass}>
|
<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}
|
{lastNameError}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -223,7 +252,15 @@ module.exports = React.createClass({
|
|||||||
<div key={'key' + index}>
|
<div key={'key' + index}>
|
||||||
{removeButton}
|
{removeButton}
|
||||||
<div className={emailClass}>
|
<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}
|
{emailError}
|
||||||
</div>
|
</div>
|
||||||
{nameFields}
|
{nameFields}
|
||||||
@@ -242,23 +279,44 @@ module.exports = React.createClass({
|
|||||||
content = (
|
content = (
|
||||||
<div>
|
<div>
|
||||||
{serverError}
|
{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/>
|
||||||
<br/>
|
<br/>
|
||||||
<span>People invited automatically join Town Square channel.</span>
|
<span>People invited automatically join Town Square channel.</span>
|
||||||
</div>
|
</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 {
|
} else {
|
||||||
var teamInviteLink = null;
|
var teamInviteLink = null;
|
||||||
if (currentUser && this.props.teamType === 'O') {
|
if (currentUser && this.props.teamType === 'O') {
|
||||||
var linkUrl = utils.getWindowLocationOrigin() + '/signup_user_complete/?id=' + currentUser.team_id;
|
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={
|
var link =
|
||||||
function() {
|
(
|
||||||
$('#invite_member').modal('hide');
|
<a
|
||||||
}
|
href='#'
|
||||||
}>Team Invite Link</a>;
|
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 = (
|
teamInviteLink = (
|
||||||
<p>
|
<p>
|
||||||
@@ -277,22 +335,46 @@ module.exports = React.createClass({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<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-dialog'>
|
||||||
<div className='modal-content'>
|
<div className='modal-content'>
|
||||||
<div className='modal-header'>
|
<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>
|
<button
|
||||||
<h4 className='modal-title' id='myModalLabel'>Invite New Member</h4>
|
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>
|
||||||
<div ref='modalBody' className='modal-body'>
|
<div
|
||||||
|
ref='modalBody'
|
||||||
|
className='modal-body'
|
||||||
|
>
|
||||||
<form role='form'>
|
<form role='form'>
|
||||||
{inviteSections}
|
{inviteSections}
|
||||||
</form>
|
</form>
|
||||||
{content}
|
{content}
|
||||||
</div>
|
</div>
|
||||||
<div className='modal-footer'>
|
<div className='modal-footer'>
|
||||||
<button type='button' className='btn btn-default' data-dismiss='modal'>Cancel</button>
|
<button
|
||||||
{sendButton}
|
type='button'
|
||||||
|
className='btn btn-default'
|
||||||
|
data-dismiss='modal'
|
||||||
|
>Cancel</button>
|
||||||
|
{sendButton}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -309,4 +391,8 @@ module.exports = React.createClass({
|
|||||||
}
|
}
|
||||||
return <div/>;
|
return <div/>;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
InviteMemberModal.propTypes = {
|
||||||
|
teamType: React.PropTypes.string
|
||||||
|
};
|
||||||
|
|||||||
@@ -3,32 +3,45 @@
|
|||||||
|
|
||||||
var MemberListItem = require('./member_list_item.jsx');
|
var MemberListItem = require('./member_list_item.jsx');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
export default class MemberList extends React.Component {
|
||||||
render: function() {
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
var members = [];
|
var members = [];
|
||||||
|
|
||||||
if (this.props.memberList != null) {
|
if (this.props.memberList !== null) {
|
||||||
members = this.props.memberList;
|
members = this.props.memberList;
|
||||||
}
|
}
|
||||||
|
|
||||||
var message = "";
|
var message = '';
|
||||||
if (members.length === 0)
|
if (members.length === 0) {
|
||||||
message = <span>No users to add.</span>;
|
message = <span>No users to add.</span>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="member-list-holder">
|
<div className='member-list-holder'>
|
||||||
{members.map(function(member) {
|
{members.map(function mymembers(member) {
|
||||||
return <MemberListItem
|
return (<MemberListItem
|
||||||
key={member.id}
|
key={member.id}
|
||||||
member={member}
|
member={member}
|
||||||
isAdmin={this.props.isAdmin}
|
isAdmin={this.props.isAdmin}
|
||||||
handleInvite={this.props.handleInvite}
|
handleInvite={this.props.handleInvite}
|
||||||
handleRemove={this.props.handleRemove}
|
handleRemove={this.props.handleRemove}
|
||||||
handleMakeAdmin={this.props.handleMakeAdmin}
|
handleMakeAdmin={this.props.handleMakeAdmin}
|
||||||
/>;
|
/>);
|
||||||
}, this)}
|
}, this)}
|
||||||
{message}
|
{message}
|
||||||
</div>
|
</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 AsyncClient = require('../utils/async_client.jsx');
|
||||||
var utils = require('../utils/utils.jsx');
|
var utils = require('../utils/utils.jsx');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
export default class MoreDirectChannels extends React.Component {
|
||||||
displayName: 'MoreDirectChannels',
|
constructor(props) {
|
||||||
componentDidMount: function() {
|
super(props);
|
||||||
|
|
||||||
|
this.state = {channels: [], loadingDMChannel: -1};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
var self = this;
|
var self = this;
|
||||||
$(this.refs.modal.getDOMNode()).on('show.bs.modal', function showModal(e) {
|
$(this.refs.modal.getDOMNode()).on('show.bs.modal', function showModal(e) {
|
||||||
var button = e.relatedTarget;
|
var button = e.relatedTarget;
|
||||||
self.setState({channels: $(button).data('channels')});
|
self.setState({channels: $(button).data('channels')});
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
getInitialState: function() {
|
|
||||||
return {channels: [], loadingDMChannel: -1};
|
render() {
|
||||||
},
|
|
||||||
render: function() {
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var directMessageItems = this.state.channels.map(function mapActivityToChannel(channel, index) {
|
var directMessageItems = this.state.channels.map(function mapActivityToChannel(channel, index) {
|
||||||
@@ -48,7 +51,12 @@ module.exports = React.createClass({
|
|||||||
var otherUserId = utils.getUserIdFromChannelName(channel);
|
var otherUserId = utils.getUserIdFromChannelName(channel);
|
||||||
|
|
||||||
if (self.state.loadingDMChannel === index) {
|
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) {
|
if (self.state.loadingDMChannel === -1) {
|
||||||
@@ -73,16 +81,36 @@ module.exports = React.createClass({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
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 (
|
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-dialog'>
|
||||||
<div className='modal-content'>
|
<div className='modal-content'>
|
||||||
<div className='modal-header'>
|
<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 aria-hidden='true'>×</span>
|
||||||
<span className='sr-only'>Close</span>
|
<span className='sr-only'>Close</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -94,11 +122,15 @@ module.exports = React.createClass({
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div className='modal-footer'>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@@ -1,57 +1,70 @@
|
|||||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
|
||||||
var SocketStore = require('../stores/socket_store.jsx');
|
var SocketStore = require('../stores/socket_store.jsx');
|
||||||
var UserStore = require('../stores/user_store.jsx');
|
var UserStore = require('../stores/user_store.jsx');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
export default class MsgTyping extends React.Component {
|
||||||
timer: null,
|
constructor(props) {
|
||||||
lastTime: 0,
|
super(props);
|
||||||
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) {
|
|
||||||
|
|
||||||
|
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();
|
this.lastTime = new Date().getTime();
|
||||||
|
|
||||||
var username = "Someone";
|
var username = 'Someone';
|
||||||
if (UserStore.hasProfile(msg.user_id)) {
|
if (UserStore.hasProfile(msg.user_id)) {
|
||||||
username = UserStore.getProfile(msg.user_id).username;
|
username = UserStore.getProfile(msg.user_id).username;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({ text: username + " is typing..." });
|
this.setState({text: username + ' is typing...'});
|
||||||
|
|
||||||
if (!this.timer) {
|
if (!this.timer) {
|
||||||
var outer = this;
|
this.timer = setInterval(function myTimer() {
|
||||||
outer.timer = setInterval(function() {
|
if ((new Date().getTime() - this.lastTime) > 8000) {
|
||||||
if ((new Date().getTime() - outer.lastTime) > 8000) {
|
this.setState({text: ''});
|
||||||
outer.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:""})
|
|
||||||
}
|
render() {
|
||||||
},
|
|
||||||
getInitialState: function() {
|
|
||||||
return { text: "" };
|
|
||||||
},
|
|
||||||
render: function() {
|
|
||||||
return (
|
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) {
|
if (deletedPosts && Object.keys(deletedPosts).length > 0) {
|
||||||
for (var pid in deletedPosts) {
|
for (var pid in deletedPosts) {
|
||||||
postList.posts[pid] = deletedPosts[pid];
|
if (deletedPosts.hasOwnProperty(pid)) {
|
||||||
postList.order.unshift(pid);
|
postList.posts[pid] = deletedPosts[pid];
|
||||||
|
postList.order.unshift(pid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
postList.order.sort(function postSort(a, b) {
|
postList.order.sort(function postSort(a, b) {
|
||||||
@@ -71,7 +73,9 @@ export default class PostList extends React.Component {
|
|||||||
if (pendingPostList) {
|
if (pendingPostList) {
|
||||||
postList.order = pendingPostList.order.concat(postList.order);
|
postList.order = pendingPostList.order.concat(postList.order);
|
||||||
for (var ppid in pendingPostList.posts) {
|
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) {
|
onSocketChange(msg) {
|
||||||
var postList;
|
|
||||||
var post;
|
var post;
|
||||||
if (msg.action === 'posted' || msg.action === 'post_edited') {
|
if (msg.action === 'posted' || msg.action === 'post_edited') {
|
||||||
post = JSON.parse(msg.props.post);
|
post = JSON.parse(msg.props.post);
|
||||||
@@ -280,7 +283,6 @@ export default class PostList extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
post = JSON.parse(msg.props.post);
|
post = JSON.parse(msg.props.post);
|
||||||
postList = this.state.postList;
|
|
||||||
|
|
||||||
PostStore.storeUnseenDeletedPost(post);
|
PostStore.storeUnseenDeletedPost(post);
|
||||||
PostStore.removePost(post, true);
|
PostStore.removePost(post, true);
|
||||||
@@ -644,11 +646,18 @@ export default class PostList extends React.Component {
|
|||||||
if (posts && this.state.isFirstLoadComplete) {
|
if (posts && this.state.isFirstLoadComplete) {
|
||||||
postCtls = this.createPosts(posts, order);
|
postCtls = this.createPosts(posts, order);
|
||||||
} else {
|
} else {
|
||||||
postCtls.push(<LoadingScreen position='absolute' />);
|
postCtls.push(
|
||||||
|
<LoadingScreen
|
||||||
|
position='absolute'
|
||||||
|
key='loading'
|
||||||
|
/>);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
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__table'>
|
||||||
<div className='post-list__content'>
|
<div className='post-list__content'>
|
||||||
{moreMessages}
|
{moreMessages}
|
||||||
|
|||||||
@@ -3,62 +3,99 @@
|
|||||||
|
|
||||||
var ChannelStore = require('../stores/channel_store.jsx');
|
var ChannelStore = require('../stores/channel_store.jsx');
|
||||||
var UserStore = require('../stores/user_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');
|
var utils = require('../utils/utils.jsx');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
export default class RemovedFromChannelModal extends React.Component {
|
||||||
handleShow: function() {
|
constructor(props) {
|
||||||
var newState = {};
|
super(props);
|
||||||
if(BrowserStore.getItem("channel-removed-state")) {
|
|
||||||
newState = BrowserStore.getItem("channel-removed-state");
|
|
||||||
BrowserStore.removeItem("channel-removed-state");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState(newState);
|
this.handleShow = this.handleShow.bind(this);
|
||||||
},
|
this.handleClose = this.handleClose.bind(this);
|
||||||
handleClose: function() {
|
|
||||||
var townSquare = ChannelStore.getByName("town-square");
|
|
||||||
utils.switchChannel(townSquare);
|
|
||||||
|
|
||||||
this.setState({channelName: "", remover: ""});
|
this.state = {
|
||||||
},
|
channelName: '',
|
||||||
componentDidMount: function() {
|
remover: ''
|
||||||
$(this.getDOMNode()).on('show.bs.modal',this.handleShow);
|
};
|
||||||
$(this.getDOMNode()).on('hidden.bs.modal',this.handleClose);
|
}
|
||||||
},
|
|
||||||
componentWillUnmount: function() {
|
handleShow() {
|
||||||
$(this.getDOMNode()).off('show.bs.modal',this.handleShow);
|
var newState = {};
|
||||||
$(this.getDOMNode()).off('hidden.bs.modal',this.handleClose);
|
if (BrowserStore.getItem('channel-removed-state')) {
|
||||||
},
|
newState = BrowserStore.getItem('channel-removed-state');
|
||||||
getInitialState: function() {
|
BrowserStore.removeItem('channel-removed-state');
|
||||||
return {channelName: "", remover: ""}
|
}
|
||||||
},
|
|
||||||
render: function() {
|
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 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) {
|
if (currentUser != null) {
|
||||||
return (
|
return (
|
||||||
<div className='modal fade' ref='modal' id='removed_from_channel' tabIndex='-1' role='dialog' aria-hidden='true'>
|
<div
|
||||||
<div className='modal-dialog'>
|
className='modal fade'
|
||||||
<div className='modal-content'>
|
ref='modal'
|
||||||
<div className='modal-header'>
|
id='removed_from_channel'
|
||||||
<button type='button' className='close' data-dismiss='modal' aria-label='Close'><span aria-hidden='true'>×</span></button>
|
tabIndex='-1'
|
||||||
<h4 className='modal-title'>Removed from <span className='name'>{channelName}</span></h4>
|
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>
|
||||||
<div className='modal-body'>
|
</div>
|
||||||
<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) {
|
if (pendingPostList) {
|
||||||
for (var pid in pendingPostList.posts) {
|
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) {
|
if (currentPosts.posts[currentPosts.order[0]].channel_id === currentSelected.posts[currentSelected.order[0]].channel_id) {
|
||||||
currentSelected.posts = {};
|
currentSelected.posts = {};
|
||||||
for (var postId in currentPosts.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);
|
PostStore.storeSelectedPost(currentSelected);
|
||||||
@@ -128,9 +132,11 @@ export default class RhsThread extends React.Component {
|
|||||||
var postsArray = [];
|
var postsArray = [];
|
||||||
|
|
||||||
for (var postId in postList.posts) {
|
for (var postId in postList.posts) {
|
||||||
var cpost = postList.posts[postId];
|
if (postList.posts.hasOwnProperty(postId)) {
|
||||||
if (cpost.root_id === rootPost.id) {
|
var cpost = postList.posts[postId];
|
||||||
postsArray.push(cpost);
|
if (cpost.root_id === rootPost.id) {
|
||||||
|
postsArray.push(cpost);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,6 +215,7 @@ RhsThread.defaultProps = {
|
|||||||
fromSearch: '',
|
fromSearch: '',
|
||||||
isMentionSearch: false
|
isMentionSearch: false
|
||||||
};
|
};
|
||||||
|
|
||||||
RhsThread.propTypes = {
|
RhsThread.propTypes = {
|
||||||
fromSearch: React.PropTypes.string,
|
fromSearch: React.PropTypes.string,
|
||||||
isMentionSearch: React.PropTypes.bool
|
isMentionSearch: React.PropTypes.bool
|
||||||
|
|||||||
@@ -1,25 +1,33 @@
|
|||||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
module.exports = React.createClass({
|
export default class SettingPicture extends React.Component {
|
||||||
setPicture: function(file) {
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.setPicture = this.setPicture.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPicture(file) {
|
||||||
if (file) {
|
if (file) {
|
||||||
var reader = new FileReader();
|
var reader = new FileReader();
|
||||||
|
|
||||||
var img = this.refs.image.getDOMNode();
|
var img = this.refs.image.getDOMNode();
|
||||||
reader.onload = function(e) {
|
reader.onload = function load(e) {
|
||||||
$(img).attr('src', e.target.result);
|
$(img).attr('src', e.target.result);
|
||||||
};
|
};
|
||||||
|
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
componentWillReceiveProps: function(nextProps) {
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
if (nextProps.picture) {
|
if (nextProps.picture) {
|
||||||
this.setPicture(nextProps.picture);
|
this.setPicture(nextProps.picture);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
render: function() {
|
|
||||||
|
render() {
|
||||||
var clientError = null;
|
var clientError = null;
|
||||||
if (this.props.client_error) {
|
if (this.props.client_error) {
|
||||||
clientError = <div className='form-group has-error'><label className='control-label'>{this.props.client_error}</label></div>;
|
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;
|
var img = null;
|
||||||
if (this.props.picture) {
|
if (this.props.picture) {
|
||||||
img = (<img ref='image' className='profile-img' src=''/>);
|
img = (
|
||||||
|
<img
|
||||||
|
ref='image'
|
||||||
|
className='profile-img'
|
||||||
|
src=''
|
||||||
|
/>
|
||||||
|
);
|
||||||
} else {
|
} 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;
|
var confirmButton;
|
||||||
if (this.props.loadingPicture) {
|
if (this.props.loadingPicture) {
|
||||||
confirmButton = <img className='spinner' src='/static/images/load.gif'/>;
|
confirmButton = (
|
||||||
|
<img
|
||||||
|
className='spinner'
|
||||||
|
src='/static/images/load.gif'
|
||||||
|
/>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
var confirmButtonClass = 'btn btn-sm';
|
var confirmButtonClass = 'btn btn-sm';
|
||||||
if (this.props.submitActive) {
|
if (this.props.submitActive) {
|
||||||
@@ -46,9 +71,15 @@ module.exports = React.createClass({
|
|||||||
} else {
|
} else {
|
||||||
confirmButtonClass += ' btn-inactive disabled';
|
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;
|
var self = this;
|
||||||
return (
|
return (
|
||||||
@@ -65,13 +96,36 @@ module.exports = React.createClass({
|
|||||||
<li className='setting-list-item'>
|
<li className='setting-list-item'>
|
||||||
{serverError}
|
{serverError}
|
||||||
{clientError}
|
{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}
|
{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>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</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.
|
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
module.exports = React.createClass({
|
export default class SettingsUpload extends React.Component {
|
||||||
displayName: 'Setting Upload',
|
|
||||||
propTypes: {
|
constructor(props) {
|
||||||
title: React.PropTypes.string.isRequired,
|
super(props);
|
||||||
submit: React.PropTypes.func.isRequired,
|
|
||||||
fileTypesAccepted: React.PropTypes.string.isRequired,
|
this.doFileSelect = this.doFileSelect.bind(this);
|
||||||
clientError: React.PropTypes.string,
|
this.doSubmit = this.doSubmit.bind(this);
|
||||||
serverError: React.PropTypes.string,
|
this.onFileSelect = this.onFileSelect.bind(this);
|
||||||
helpText: React.PropTypes.string
|
|
||||||
},
|
this.state = {
|
||||||
getInitialState: function() {
|
|
||||||
return {
|
|
||||||
clientError: this.props.clientError,
|
clientError: this.props.clientError,
|
||||||
serverError: this.props.serverError
|
serverError: this.props.serverError
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
componentWillReceiveProps: function() {
|
|
||||||
|
componentWillReceiveProps() {
|
||||||
this.setState({
|
this.setState({
|
||||||
clientError: this.props.clientError,
|
clientError: this.props.clientError,
|
||||||
serverError: this.props.serverError
|
serverError: this.props.serverError
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
doFileSelect: function(e) {
|
|
||||||
|
doFileSelect(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.setState({
|
this.setState({
|
||||||
clientError: '',
|
clientError: '',
|
||||||
serverError: ''
|
serverError: ''
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
doSubmit: function(e) {
|
|
||||||
|
doSubmit(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var inputnode = this.refs.uploadinput.getDOMNode();
|
var inputnode = this.refs.uploadinput.getDOMNode();
|
||||||
if (inputnode.files && inputnode.files[0]) {
|
if (inputnode.files && inputnode.files[0]) {
|
||||||
@@ -38,16 +39,18 @@ module.exports = React.createClass({
|
|||||||
} else {
|
} else {
|
||||||
this.setState({clientError: 'No file selected.'});
|
this.setState({clientError: 'No file selected.'});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
onFileSelect: function(e) {
|
|
||||||
|
onFileSelect(e) {
|
||||||
var filename = $(e.target).val();
|
var filename = $(e.target).val();
|
||||||
if (filename.substring(3, 11) === 'fakepath') {
|
if (filename.substring(3, 11) === 'fakepath') {
|
||||||
filename = filename.substring(12);
|
filename = filename.substring(12);
|
||||||
}
|
}
|
||||||
$(e.target).closest('li').find('.file-status').addClass('hide');
|
$(e.target).closest('li').find('.file-status').addClass('hide');
|
||||||
$(e.target).closest('li').find('.file-name').removeClass('hide').html(filename);
|
$(e.target).closest('li').find('.file-name').removeClass('hide').html(filename);
|
||||||
},
|
}
|
||||||
render: function() {
|
|
||||||
|
render() {
|
||||||
var clientError = null;
|
var clientError = null;
|
||||||
if (this.state.clientError) {
|
if (this.state.clientError) {
|
||||||
clientError = (
|
clientError = (
|
||||||
@@ -67,7 +70,11 @@ module.exports = React.createClass({
|
|||||||
<li className='col-xs-offset-3 col-xs-8'>
|
<li className='col-xs-offset-3 col-xs-8'>
|
||||||
<ul className='setting-list'>
|
<ul className='setting-list'>
|
||||||
<li className='setting-list-item'>
|
<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
|
<a
|
||||||
className={'btn btn-sm btn-primary'}
|
className={'btn btn-sm btn-primary'}
|
||||||
onClick={this.doSubmit}>
|
onClick={this.doSubmit}>
|
||||||
@@ -82,4 +89,13 @@ module.exports = React.createClass({
|
|||||||
</ul>
|
</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 client = require('../utils/client.jsx');
|
||||||
var utils = require('../utils/utils.jsx');
|
var utils = require('../utils/utils.jsx');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
export default class SidebarRightMenu extends React.Component {
|
||||||
handleLogoutClick: function(e) {
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.handleLogoutClick = this.handleLogoutClick.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleLogoutClick(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
client.logout();
|
client.logout();
|
||||||
},
|
}
|
||||||
render: function() {
|
|
||||||
|
render() {
|
||||||
var teamLink = '';
|
var teamLink = '';
|
||||||
var inviteLink = '';
|
var inviteLink = '';
|
||||||
var teamSettingsLink = '';
|
var teamSettingsLink = '';
|
||||||
@@ -23,14 +30,22 @@ module.exports = React.createClass({
|
|||||||
|
|
||||||
inviteLink = (
|
inviteLink = (
|
||||||
<li>
|
<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>
|
</li>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this.props.teamType === 'O') {
|
if (this.props.teamType === 'O') {
|
||||||
teamLink = (
|
teamLink = (
|
||||||
<li>
|
<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>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -39,12 +54,20 @@ module.exports = React.createClass({
|
|||||||
if (isAdmin) {
|
if (isAdmin) {
|
||||||
teamSettingsLink = (
|
teamSettingsLink = (
|
||||||
<li>
|
<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>
|
</li>
|
||||||
);
|
);
|
||||||
manageLink = (
|
manageLink = (
|
||||||
<li>
|
<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>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -61,23 +84,48 @@ module.exports = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className='team__header theme'>
|
<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>
|
||||||
|
|
||||||
<div className='nav-pills__container'>
|
<div className='nav-pills__container'>
|
||||||
<ul className='nav nav-pills nav-stacked'>
|
<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}
|
{teamSettingsLink}
|
||||||
{inviteLink}
|
{inviteLink}
|
||||||
{teamLink}
|
{teamLink}
|
||||||
{manageLink}
|
{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 className='divider'></li>
|
||||||
<li><a target='_blank' href='/static/help/configure_links.html'><i className='glyphicon glyphicon-question-sign'></i>Help</a></li>
|
<li>
|
||||||
<li><a target='_blank' href='/static/help/configure_links.html'><i className='glyphicon glyphicon-earphone'></i>Report a Problem</a></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>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
SidebarRightMenu.propTypes = {
|
||||||
|
teamType: React.PropTypes.string,
|
||||||
|
teamDisplayName: React.PropTypes.string
|
||||||
|
};
|
||||||
@@ -4,22 +4,34 @@
|
|||||||
var utils = require('../utils/utils.jsx');
|
var utils = require('../utils/utils.jsx');
|
||||||
var SettingUpload = require('./setting_upload.jsx');
|
var SettingUpload = require('./setting_upload.jsx');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
export default class TeamImportTab extends React.Component {
|
||||||
displayName: 'Import Tab',
|
constructor(props) {
|
||||||
getInitialState: function() {
|
super(props);
|
||||||
return {status: 'ready', link: ''};
|
|
||||||
},
|
this.onImportFailure = this.onImportFailure.bind(this);
|
||||||
onImportFailure: function() {
|
this.onImportSuccess = this.onImportSuccess.bind(this);
|
||||||
|
this.doImportSlack = this.doImportSlack.bind(this);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
status: 'ready',
|
||||||
|
link: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onImportFailure() {
|
||||||
this.setState({status: 'fail', link: ''});
|
this.setState({status: 'fail', link: ''});
|
||||||
},
|
}
|
||||||
onImportSuccess: function(data) {
|
|
||||||
|
onImportSuccess(data) {
|
||||||
this.setState({status: 'done', link: 'data:application/octet-stream;charset=utf-8,' + encodeURIComponent(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: ''});
|
this.setState({status: 'in-progress', link: ''});
|
||||||
utils.importSlack(file, this.onImportSuccess, this.onImportFailure);
|
utils.importSlack(file, this.onImportSuccess, this.onImportFailure);
|
||||||
},
|
}
|
||||||
render: function() {
|
|
||||||
|
render() {
|
||||||
var uploadHelpText = (
|
var uploadHelpText = (
|
||||||
<div>
|
<div>
|
||||||
<br/>
|
<br/>
|
||||||
@@ -39,22 +51,25 @@ module.exports = React.createClass({
|
|||||||
|
|
||||||
var messageSection;
|
var messageSection;
|
||||||
switch (this.state.status) {
|
switch (this.state.status) {
|
||||||
case 'ready':
|
|
||||||
messageSection = '';
|
case 'ready':
|
||||||
|
messageSection = '';
|
||||||
break;
|
break;
|
||||||
case 'in-progress':
|
case 'in-progress':
|
||||||
messageSection = (
|
messageSection = (
|
||||||
<p className="confirm-import alert alert-warning"><i className="fa fa-spinner fa-pulse"></i> Importing...</p>
|
<p className='confirm-import alert alert-warning'><i className='fa fa-spinner fa-pulse'></i> Importing...</p>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'done':
|
case 'done':
|
||||||
messageSection = (
|
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>
|
<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;
|
break;
|
||||||
case 'fail':
|
case 'fail':
|
||||||
messageSection = (
|
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>
|
<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;
|
break;
|
||||||
}
|
}
|
||||||
@@ -62,10 +77,22 @@ module.exports = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className='modal-header'>
|
<div className='modal-header'>
|
||||||
<button type='button' className='close' data-dismiss='modal' aria-label='Close'><span aria-hidden='true'>×</span></button>
|
<button type='button'
|
||||||
<h4 className='modal-title' ref='title'><i className='modal-back'></i>Import</h4>
|
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>
|
||||||
<div ref='wrapper' className='user-settings'>
|
<div
|
||||||
|
ref='wrapper'
|
||||||
|
className='user-settings'
|
||||||
|
>
|
||||||
<h3 className='tab-header'>Import</h3>
|
<h3 className='tab-header'>Import</h3>
|
||||||
<div className='divider-dark first'/>
|
<div className='divider-dark first'/>
|
||||||
{uploadSection}
|
{uploadSection}
|
||||||
@@ -75,4 +102,4 @@ module.exports = React.createClass({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|||||||
@@ -2,77 +2,131 @@
|
|||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
var UserStore = require('../stores/user_store.jsx');
|
var UserStore = require('../stores/user_store.jsx');
|
||||||
var ChannelStore = require('../stores/channel_store.jsx');
|
|
||||||
var MemberListTeam = require('./member_list_team.jsx');
|
var MemberListTeam = require('./member_list_team.jsx');
|
||||||
var Client = require('../utils/client.jsx');
|
|
||||||
var utils = require('../utils/utils.jsx');
|
var utils = require('../utils/utils.jsx');
|
||||||
|
|
||||||
function getStateFromStores() {
|
function getStateFromStores() {
|
||||||
var users = UserStore.getProfiles();
|
var users = UserStore.getProfiles();
|
||||||
var member_list = [];
|
var memberList = [];
|
||||||
for (var id in users) member_list.push(users[id]);
|
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 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
member_list: member_list
|
member_list: memberList
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = React.createClass({
|
export default class TeamMembers extends React.Component {
|
||||||
componentDidMount: function() {
|
constructor(props) {
|
||||||
UserStore.addChangeListener(this._onChange);
|
super(props);
|
||||||
|
|
||||||
|
this.onChange = this.onChange.bind(this);
|
||||||
|
|
||||||
|
this.state = getStateFromStores();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
UserStore.addChangeListener(this.onChange);
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
$(this.refs.modal.getDOMNode()).on('hidden.bs.modal', function(e) {
|
$(this.refs.modal.getDOMNode()).on('hidden.bs.modal', function show() {
|
||||||
self.setState({ render_members: false });
|
self.setState({render_members: false});
|
||||||
});
|
});
|
||||||
|
|
||||||
$(this.refs.modal.getDOMNode()).on('show.bs.modal', function(e) {
|
$(this.refs.modal.getDOMNode()).on('show.bs.modal', function hide() {
|
||||||
self.setState({ render_members: true });
|
self.setState({render_members: true});
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
componentWillUnmount: function() {
|
|
||||||
UserStore.removeChangeListener(this._onChange);
|
componentWillUnmount() {
|
||||||
},
|
UserStore.removeChangeListener(this.onChange);
|
||||||
_onChange: function() {
|
}
|
||||||
|
|
||||||
|
onChange() {
|
||||||
var newState = getStateFromStores();
|
var newState = getStateFromStores();
|
||||||
if (!utils.areStatesEqual(newState, this.state)) {
|
if (!utils.areStatesEqual(newState, this.state)) {
|
||||||
this.setState(newState);
|
this.setState(newState);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
getInitialState: function() {
|
|
||||||
return getStateFromStores();
|
render() {
|
||||||
},
|
var serverError = null;
|
||||||
render: function() {
|
|
||||||
var server_error = this.state.server_error ? <label className='has-error control-label'>{this.state.server_error}</label> : 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 (
|
return (
|
||||||
<div className="modal fade" ref="modal" id="team_members" tabIndex="-1" role="dialog" aria-hidden="true">
|
<div
|
||||||
<div className="modal-dialog">
|
className='modal fade'
|
||||||
<div className="modal-content">
|
ref='modal'
|
||||||
<div className="modal-header">
|
id='team_members'
|
||||||
<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>
|
tabIndex='-1'
|
||||||
<h4 className="modal-title" id="myModalLabel">{this.props.teamDisplayName + " Members"}</h4>
|
role='dialog'
|
||||||
</div>
|
aria-hidden='true'
|
||||||
<div ref="modalBody" className="modal-body">
|
>
|
||||||
<div className="channel-settings">
|
<div className='modal-dialog'>
|
||||||
<div className="team-member-list">
|
<div className='modal-content'>
|
||||||
{ this.state.render_members ? <MemberListTeam users={this.state.member_list} /> : "" }
|
<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>
|
</div>
|
||||||
{ server_error }
|
</div>
|
||||||
|
<div className='modal-footer'>
|
||||||
|
<button
|
||||||
|
type='button'
|
||||||
|
className='btn btn-default'
|
||||||
|
data-dismiss='modal'
|
||||||
|
>Close</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="modal-footer">
|
|
||||||
<button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</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 GeneralTab = require('./user_settings_general.jsx');
|
||||||
var AppearanceTab = require('./user_settings_appearance.jsx');
|
var AppearanceTab = require('./user_settings_appearance.jsx');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
export default class UserSettings extends React.Component {
|
||||||
displayName: 'UserSettings',
|
constructor(props) {
|
||||||
propTypes: {
|
super(props);
|
||||||
activeTab: React.PropTypes.string,
|
|
||||||
activeSection: React.PropTypes.string,
|
this.onListenerChange = this.onListenerChange.bind(this);
|
||||||
updateSection: React.PropTypes.func,
|
|
||||||
updateTab: React.PropTypes.func
|
this.state = {user: UserStore.getCurrentUser()};
|
||||||
},
|
}
|
||||||
componentDidMount: function() {
|
|
||||||
|
componentDidMount() {
|
||||||
UserStore.addChangeListener(this.onListenerChange);
|
UserStore.addChangeListener(this.onListenerChange);
|
||||||
},
|
}
|
||||||
componentWillUnmount: function() {
|
|
||||||
|
componentWillUnmount() {
|
||||||
UserStore.removeChangeListener(this.onListenerChange);
|
UserStore.removeChangeListener(this.onListenerChange);
|
||||||
},
|
}
|
||||||
onListenerChange: function () {
|
|
||||||
|
onListenerChange() {
|
||||||
var user = UserStore.getCurrentUser();
|
var user = UserStore.getCurrentUser();
|
||||||
if (!utils.areStatesEqual(this.state.user, user)) {
|
if (!utils.areStatesEqual(this.state.user, user)) {
|
||||||
this.setState({user: user});
|
this.setState({user: user});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
getInitialState: function() {
|
|
||||||
return {user: UserStore.getCurrentUser()};
|
render() {
|
||||||
},
|
|
||||||
render: function() {
|
|
||||||
if (this.props.activeTab === 'general') {
|
if (this.props.activeTab === 'general') {
|
||||||
return (
|
return (
|
||||||
<div>
|
<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>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (this.props.activeTab === 'security') {
|
} else if (this.props.activeTab === 'security') {
|
||||||
return (
|
return (
|
||||||
<div>
|
<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>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (this.props.activeTab === 'notifications') {
|
} else if (this.props.activeTab === 'notifications') {
|
||||||
return (
|
return (
|
||||||
<div>
|
<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>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (this.props.activeTab === 'appearance') {
|
} else if (this.props.activeTab === 'appearance') {
|
||||||
return (
|
return (
|
||||||
<div>
|
<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>
|
</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