File: components/SelectUsers.js
/** @jsx React.DOM */
"use strict";
var _ = require("lodash");
var React = require("react/addons");
var Promise = require("bluebird");
var Button = require("react-bootstrap/Button");
var User = require("../models/client/User");
var Ticket = require("../models/client/Ticket");
var captureError = require("../utils/captureError");
/**
* UserItem
*
* @namespace components
* @class SelectUsers.UserItem
* @constructor
* @param {Object} props
* @param {models.client.User} props.user
*/
var UserItem = React.createClass({
propTypes: {
user: React.PropTypes.instanceOf(User).isRequired
},
getDefaultProps: function() {
return {
checked: false,
disabled: false
};
},
handleOnChange: function(e) {
if (e.target.checked) this.props.onSelectUser(this.props.user);
else this.props.onRemoveUser(this.props.user);
},
render: function() {
var id = _.uniqueId("checkbox");
var user = this.props.user;
return (
<label className="UserItem" for={id}>
<input
id={id}
type="checkbox"
checked={this.props.checked}
disabled={this.props.disabled}
onChange={this.handleOnChange}
ref="checkbox" />
<span className="first-name" >{user.get("externalData").first_name + " "}</span>
<span className="last-name" >{user.get("externalData").last_name + " "}</span>
<span className="badge" >{user.getDomainUsername()}</span>
</label>
);
}
});
/**
* SelectUsers
*
* @namespace components
* @class SelectUsers
* @constructor
* @param {Object} props
* @param {models.client.User} props.user
* @param {models.client.Ticket} props.Ticket
*/
var SelectUsers = React.createClass({
propTypes: {
user: React.PropTypes.instanceOf(User).isRequired,
ticket: React.PropTypes.instanceOf(Ticket).isRequired
},
/**
* Search users with the given search string. The results will be saved to
* the component state in `searchedUsers` key
*
* @method doSearch
* @param {String} searchString
*/
doSearch: function(searchString) {
this.cancelCurrentSearch();
var self = this;
var user = this.props.user;
var ticket = this.props.ticket;
var creatorDomain = ticket.createdBy().getOrganisationDomain();
var currentDomain = user.getOrganisationDomain();
var orgs = [currentDomain];
// If the user is manager and the ticket creator is from a another
// organisation search users from that organisation too.
if (creatorDomain !== currentDomain && user.isManager()) {
orgs.push(creatorDomain);
}
var searchOp = Promise.map(orgs, function(domain) {
return User.search(domain, searchString);
})
.then(function(users) {
self.setState({ searchedUsers: _.flatten(users) });
})
.catch(Promise.CancellationError, function() {
// cancel is ok
})
.catch(captureError("Käyttäjien haku epäonnistui"));
self.setState({ searchOp: searchOp });
},
componentWillMount: function() {
// search after 500ms of silence for each mounted component
this.bouncedSearch = _.debounce(this.doSearch, 500);
},
componentDidMount: function() {
this.refs.search.getDOMNode().focus();
},
cancelCurrentSearch: function() {
if (!this.state.searchOp) return;
if (!this.state.searchOp.isPending()) return;
this.state.searchOp.cancel();
},
getInitialState: function() {
return {
searchString: "",
searchOp: null,
searchedUsers: [],
selectedUsers: this.props.currentHandlers
};
},
handleSearchStringChange: function(e) {
this.setState({ searchString: e.target.value });
this.bouncedSearch(e.target.value);
},
handleSelectUser: function(user) {
this.refs.search.getDOMNode().focus();
if (this.isSelected(user)) return;
this.setState({
selectedUsers: this.state.selectedUsers.concat(user)
});
},
handleRemoveUser: function(user) {
this.refs.search.getDOMNode().focus();
this.setState({
selectedUsers: this.state.selectedUsers.filter(function(selectedUser) {
return selectedUser.getExternalId() !== user.getExternalId();
})
});
},
/**
* saved handlers cannot be removed yet...
*/
isSaved: function(user) {
return this.props.currentHandlers.some(function(selectedUser) {
return selectedUser.getExternalId() === user.getExternalId();
});
},
isSelected: function(user) {
return this.state.selectedUsers.some(function(selectedUser) {
return selectedUser.getExternalId() === user.getExternalId();
});
},
handleOk: function(e) {
e.preventDefault();
var self = this;
this.props.onSelect(this.state.selectedUsers.filter(function(user) {
return !self.isSaved(user);
}));
},
render: function() {
var self = this;
return (
<div className="SelectUsers">
<div className="search-input-wrap">
<input
className="form-control search-input"
ref="search"
placeholder="Aloita kirjoittamaan käsittelijän nimeä"
value={self.state.searchString}
onChange={self.handleSearchStringChange} />
</div>
<div className="selectuser">
<ul className="list-group" >
{self.state.searchedUsers.map(function(user) {
return (
<li key={user.get("externalId")} className="list-group-item" >
<UserItem
user={user}
disabled={self.isSaved(user)}
checked={self.isSelected(user)}
onRemoveUser={self.handleRemoveUser}
onSelectUser={self.handleSelectUser} />
</li>
);
})}
</ul>
{self.state.selectedUsers.length > 0 &&
<h2>
Valitut
</h2>
}
<ul className="list-group" >
{self.state.selectedUsers.map(function(user) {
return (
<li key={user.get("externalId")} className="list-group-item selected" >
<UserItem
user={user}
checked={self.isSelected(user)}
disabled={self.isSaved(user)}
onRemoveUser={self.handleRemoveUser}
onSelectUser={self.handleSelectUser} />
</li>
);
})}
</ul>
</div>
<div className="modal-footer">
<Button onClick={self.handleOk}>
Lisää käsittelijät
</Button>
<Button bsStyle="danger" onClick={self.handleOk}>
Peruuta
</Button>
</div>
</div>
);
},
});
module.exports = SelectUsers;