application/components/assignment/assignment-item.js
import React from 'react';
import _ from 'lodash';
import {connect} from 'react-redux';
import {Toolbar, ToolbarGroup, ToolbarSeparator, ToolbarTitle} from 'material-ui/Toolbar';
import {List, ListItem} from 'material-ui/List'
import RaisedButton from 'material-ui/RaisedButton';
import FlatButton from 'material-ui/FlatButton';
import SelectField from 'material-ui/SelectField';
import MenuItem from 'material-ui/MenuItem';
import TextField from 'material-ui/TextField';
import FontIcon from 'material-ui/FontIcon';
import DatePicker from 'material-ui/DatePicker';
import TimePicker from 'material-ui/TimePicker';
import Paper from 'material-ui/Paper';
import Divider from 'material-ui/Divider';
import Subheader from 'material-ui/Subheader';
import {browserHistory, Link} from 'react-router';
import Config from './../../config';
import Immutable from 'immutable';
import moment from 'moment';
import CurrentUser from './../../current-user';
import {sluggify} from './../../util/strings';
import {timeToFormat, htmlDecode} from './../../util/strings';
import LoadingIndicator from './../common/loading-indicator';
import UserSearchBox from './../common/user-search-box';
import SimpleEditor from './../common/simple-editor';
import BaseView from './../base-view';
import DeleteButton from './../common/delete-button';
import ContentSearchModal from './../common/content-search-modal';
import {Row, Col} from './../flexbox';
import {rawToHtml} from '../../util/rawToHtml';
import {ContentRow} from './../content/content-table';
import AssignmentDiscussion from './assignment-discussion';
import {
workflowsMaybeFetch,
workflowsFilterAssignmentOnly,
workflowsFilterPrintOnly
} from './../../redux/actions/workflow-actions';
import {
issuesFetch,
issuesMaybeFetch,
issuesFilterOpen
} from './../../redux/actions/issue-actions';
import {
snackbarShowMessage,
snackbarClose
} from './../../redux/actions/snackbar-actions';
import {
alertShowMessage
} from './../../redux/actions/alert-actions';
import {
globalHistoryPush,
globalHistoryPop
} from './../../redux/actions/global-history-actions';
import {
assignmentsMaybeFetchCache,
assignmentsFetchOne,
assignmentsCheckIn,
assignmentsCheckOut,
assignmentsRemove,
assignmentsUpdate,
assignmentsCreate,
assignmentsClearLock
} from './../../redux/actions/assignment-actions';
import {
usersMaybeFetch,
usersFetchOne,
usersFetch,
usersRemove,
userSetSelected,
userUpdate,
userCreate
} from './../../redux/actions/user-actions';
import {
applicationIsDirty
} from './../../redux/actions/application-actions';
import LockButtons from './../lock-buttons';
class AssignmentItem extends BaseView {
constructor(props) {
super(props);
this.getUuid = this.getUuid.bind(this);
this.isNew = this.isNew.bind(this);
this.isLocked = this.isLocked.bind(this);
this.isUserEditable = this.isUserEditable.bind(this);
this.handleFormChange = this.handleFormChange.bind(this);
this.handleEditorChange = this.handleEditorChange.bind(this);
this.handleCheckout = this.handleCheckout.bind(this);
this.handleCheckin = this.handleCheckin.bind(this);
this.handleSaveCheckIn = this.handleSaveCheckIn.bind(this);
this.handleSave = this.handleSave.bind(this);
this.freezeAssignment = this.freezeAssignment.bind(this);
this.thawAssignment = this.thawAssignment.bind(this);
this.state = {
contentIsOpen: false,
dirty: false,
didDelete: false,
edited: {
users: [],
children: []
},
actionStartDate: null,
actionStartTime: null,
actionEndDate: null,
actionEndTime: null
}
}
getUuid() {
if (this.props.uuid) {
return this.props.uuid;
}
if (this.props.params && this.props.params.id) {
return this.props.params.id;
}
return false;
}
isNew() {
if (!this.getUuid() || this.getUuid() === 'new') {
return true;
}
return false;
}
isLocked() {
if (this.isNew()) {
return false;
}
if (this.state.edited.lock) {
return true;
}
return false;
}
isUserEditable() {
if (this.isNew()) {
return true;
}
if (!this.state.edited.lock) {
return false;
}
if (this.state.edited.lock.user_id === CurrentUser.getId()) {
return true;
}
return false;
}
getRouter() {
return this.props.router;
}
componentWillMount() {
const {dispatch} = this.props;
dispatch(workflowsMaybeFetch())
.then(() => dispatch(workflowsFilterAssignmentOnly()))
.then(() => dispatch(workflowsFilterPrintOnly()))
.then(() => dispatch(issuesFetch()))
.then(() => dispatch(issuesFilterOpen()))
.then(() => dispatch(usersMaybeFetch()));
if (!this.isNew()) {
dispatch(assignmentsFetchOne(this.getUuid()))
.then(() => {
let assignment = this.props.assignments.items.find((item) => item.get('uuid') == this.getUuid());
let dirty = false;
// pause here for a second and see if we have a modified version in the global history state
const savedState = this.props.globalHistory.items.find((item) => item.get('uuid') == this.getUuid());
if (savedState && savedState.size && savedState.get('isDirty')) {
// we have a freeze dried state. reconstitute that
// then set the dirty state to 'true'
assignment = this.thawAssignment(savedState.get('cachedObject'));
dirty = true;
}
this.setState({'edited': assignment.toJS(), 'dirty': dirty});
})
.then(() => {
if (this.state.edited.action_start_time) {
this.setState({
'actionStartDate': moment.utc(this.state.edited.action_start_time).local().toDate(),
'actionStartTime': moment.utc(this.state.edited.action_start_time).local().toDate(),
'actionEndDate': moment.utc(this.state.edited.action_end_time).local().toDate(),
'actionEndTime': moment.utc(this.state.edited.action_end_time).local().toDate(),
})
}
});
} else {
this.setState({
'edited': {
'children': [],
'users': []
}
});
}
this.setState({'publishIsOpen': false});
}
componentDidMount() {
this.getRouter().setRouteLeaveHook(this.props.route, this.routerWillLeave.bind(this));
if (this.refs.slugTextField && !this.refs.slugTextField.input.value) {
setTimeout(() => this.refs.slugTextField.focus(), 0);
}
}
routerWillLeave(nextLocation) {
if (!this.isNew() && !this.state.didDelete) {
const {dispatch} = this.props;
dispatch(globalHistoryPush({
'label': this.state.edited.title ? this.state.edited.title : this.state.edited.slug,
'type': 'assignment',
'contentType': 'assignment',
'url': '/ceo/assignment/' + this.state.edited.uuid,
'uuid': this.state.edited.uuid,
'isDirty': this.state.dirty,
'cachedObject': (this.state.dirty ? this.freezeAssignment(this.state.edited) : {})
}));
}
if (this.isNew() && this.isUserEditable() && this.state.dirty && this.state.dirty === true) {
return 'You have not saved this assignment! Any unsaved changes will be lost once you click OK. Click cancel and then save to preserve your work. Are you still sure you want to leave this item?';
}
}
freezeAssignment(assignment) {
let toFreeze = assignment;
let rawContent = this.state.editorContent ? this.state.editorContent : toFreeze.content;
toFreeze.content = rawContent;
return toFreeze;
}
thawAssignment(assignment) {
let toThaw = assignment;
this.state.editorContent = toThaw.get('content') ? toThaw.get('content') : '';
return toThaw;
}
// callbacks to handle the user selection
onSelectUser(user) {
let assignment = this.state.edited;
const existing = _.find(assignment.users, {'uuid': user.get('uuid')});
if (!existing) {
assignment.users.push(user.toJS());
this.setState({'edited': assignment, dirty: true});
this.props.dispatch(applicationIsDirty(true));
}
}
onRemoveUser(user) {
let assignment = this.state.edited;
assignment.users = assignment.users.filter((item, i) => {
return user.uuid != item.uuid;
});
this.setState({'edited': assignment, dirty: true});
this.props.dispatch(applicationIsDirty(true));
}
dueDateChange(empty, timestamp) {
let assignment = this.state.edited;
assignment.due_at = moment(timestamp).utc().format('YYYY-MM-DD HH:mm:ss');
this.setState({'edited': assignment, dirty: true});
this.props.dispatch(applicationIsDirty(true));
}
actionDateChange(context, empty, date) {
if (context == 'start') {
this.setState({actionStartDate: date});
this.setState({actionEndDate: date});
}
}
actionTimeChange(context, empty, time) {
if (context == 'start') {
this.setState({actionStartTime: time});
} else if (context == 'end') {
this.setState({actionEndTime: time});
}
}
// state management
handleSave(andCheckin = false) {
const {dispatch} = this.props;
// all of the start and end times for assignment actions
let actionStartDate = null;
let actionStartTime = null;
let actionEndDate = null;
let actionEndTime = null;
if (this.state.actionStartDate) {
actionStartDate = new moment(this.state.actionStartDate).utc();
}
if (this.state.actionStartTime) {
actionStartTime = new moment(this.state.actionStartTime).utc();
}
if (this.state.actionEndDate) {
actionEndDate = new moment(this.state.actionEndDate).utc();
}
if (this.state.actionEndTime) {
actionEndTime = new moment(this.state.actionEndTime).utc();
}
let data = {
'title': this.state.edited.title,
'slug': this.state.edited.slug,
'content': this.state.editorContent,
'type': this.state.edited.type,
'contact_name': this.state.edited.contact_name,
'contact_phone': this.state.edited.contact_phone,
'location': this.state.edited.location
};
if (this.state.edited.issue) {
data['issue'] = this.state.edited.issue.id;
}
//clean up and set start_time
if (actionStartDate && actionStartTime) {
data.action_start_time = actionStartDate.format('L') + ' ' + actionStartTime.format('HH:mm:ss');
} else if (actionStartDate && !actionStartTime) {
data.action_start_time = actionStartDate.format('L') + ' ' + new moment().endOf('day').utc().format('HH:mm:ss');
}
//clean up and set end_time
if (actionEndDate && actionEndTime) {
data.action_end_time = actionEndDate.format('L') + ' ' + actionEndTime.format('HH:mm:ss');
} else if (actionEndDate && !actionEndTime && actionStartTime) {
data.action_end_time = actionEndDate.format('L') + ' ' + actionStartTime.format('HH:mm:ss');
} else if (actionEndDate && !actionEndTime && !actionStartTime && data.action_start_time) {
data.action_end_time = data.action_start_time;
}
if (parseInt(this.state.edited.workflow_id)) {
data['workflow_id'] = parseInt(this.state.edited.workflow_id);
}
if (this.state.edited.users && this.state.edited.users.length) {
data['users'] = this.state.edited.users.map((user, i) => {
return user.uuid;
});
}
if (this.state.edited.children && this.state.edited.children.length) {
data['children'] = this.state.edited.children.map((content, i) => {
return content.uuid;
})
}
if (this.state.edited.due_at) {
data['due_at'] = this.state.edited.due_at;
}
if (!this.isUserEditable()) {
return;
}
if (!this.isNew()) {
dispatch(assignmentsUpdate(this.getUuid(), data))
.then(() => {
const assignment = this.props.assignments.items.find((item) => item.get('uuid') == this.state.edited.uuid);
this.setState({'edited': assignment.toJS(), dirty: false});
dispatch(applicationIsDirty(false));
})
.then(() => {
dispatch(snackbarShowMessage('Assignment updated'));
})
.then(() => {
if (andCheckin !== true) {
return;
}
this.handleCheckin();
})
.catch(() => {
dispatch(snackbarClose());
dispatch(alertShowMessage({
'title': 'Oops',
'message': (
<p>There was a problem saving your assignment. Usually this means you don't have permission to perform an action, like publishing or deleting.</p>
)
}));
this.setState({'dirty': true});
dispatch(applicationIsDirty(true));
});
} else {
// Create is slightly different
// first, create it
dispatch(assignmentsCreate(data))
.then(() => {
// then grab the newly created item and pass it on
const assignment = this.props.assignments.items.find((item) => item.get('uuid') == this.props.assignments.selected);
dispatch(snackbarShowMessage('Assignment created'));
return assignment;
})
.then((assignment) => {
// update the state with the newly created object
dispatch(applicationIsDirty(false));
this.setState({
'edited': assignment.toJS(),
dirty: false
}, () => {
// after that's done check it out
this.handleCheckout({})
.then(() => {
// when the checkout is complete, update the URL
// if you don't wait, you can get a race condition that can
// result in a no-op warning
browserHistory.push('/ceo/assignment/' + this.props.assignments.selected);
});
});
})
.catch(() => {
dispatch(snackbarClose());
dispatch(alertShowMessage({
'title': 'Oops',
'message': (
<p>There was a problem saving your assignment. Usually this means you don't have permission to perform an action, like publishing or deleting.</p>
)
}));
this.setState({'dirty': true});
dispatch(applicationIsDirty(true));
});
}
}
handleFormChange(e) {
const val = e.target.value;
const key = e.target.getAttribute('for');
let assignment = this.state.edited;
assignment[key] = val;
if (key === 'slug') {
assignment[key] = sluggify(val, true);
}
this.setState({'edited': assignment, dirty: true});
this.props.dispatch(applicationIsDirty(true));
}
handleSelectChange(e, index, val) {
let assignment = this.state.edited;
assignment.type = val;
this.setState({'edited': assignment, dirty: true});
this.props.dispatch(applicationIsDirty(true));
}
handleWorkflowChange(e, index, val) {
let assignment = this.state.edited;
assignment.workflow_id = val;
this.setState({'edited': assignment, dirty: true});
this.props.dispatch(applicationIsDirty(true));
}
handleEditorChange(raw, editorState, name) {
this.setState({'editorContent': this.toHtml(editorState.getCurrentContent()), dirty: true});
this.props.dispatch(applicationIsDirty(true));
}
handleIssueChange(e, index, val) {
const issue = this.props.issues.items.find((item, i) => item.get('uuid') == val);
if (!issue) {
return;
}
let assignment = this.state.edited;
assignment.issue = issue.toJS();
this.setState({'edited': assignment, dirty: true});
this.props.dispatch(applicationIsDirty(true));
}
handleCheckout(e) {
const {dispatch} = this.props;
return dispatch(assignmentsCheckOut(this.state.edited.srn))
.then(() => dispatch(assignmentsFetchOne(this.state.edited.uuid)))
.then(() => {
const assignment = this.props.assignments.items.find((item) => item.get('uuid') == this.state.edited.uuid);
this.setState({'edited': assignment.toJS()});
});
}
handleCheckin(e) {
const {dispatch} = this.props;
dispatch(assignmentsCheckIn(this.getUuid(), this.state.edited.lock.uuid))
.then(() => dispatch(assignmentsFetchOne(this.getUuid())))
.then(() => {
const assignment = this.props.assignments.items.find((item) => item.get('uuid') == this.state.edited.uuid);
this.setState({'edited': assignment.toJS()});
});
}
handleSaveCheckIn(e) {
this.handleSave(true);
}
handleDelete(e) {
const {dispatch} = this.props;
dispatch(assignmentsRemove(this.getUuid()))
.then(() => dispatch(globalHistoryPop(this.getUuid())))
.then(() => this.setState({'didDelete': true}, () => {
browserHistory.push('/ceo/assignment');
dispatch(snackbarShowMessage('Assignment removed'));
}))
.catch(() => {
dispatch(snackbarClose());
dispatch(alertShowMessage({
'title': 'Oops',
'message': (
<p>There was a problem removing your assignment. You may not have permission to delete.</p>
)
}));
this.setState({'dirty': true});
dispatch(applicationIsDirty(true));
});
}
handleClearLock(e) {
if (!CurrentUser.hasRole('Administrator')) {
return;
}
if (!confirm('Are you sure you want to clear this lock? You may overwrite pending changes.')) {
return;
}
const {dispatch} = this.props;
return dispatch(assignmentsClearLock(CurrentUser.getUuid(), this.state.edited.lock.uuid))
.then(() => dispatch(assignmentsFetchOne(this.getUuid())))
.then(() => {
const assignment = this.props.assignments.items.find((item) => item.get('uuid') == this.state.edited.uuid);
this.setState({'edited': assignment.toJS()});
});
}
toHtml(state) {
return rawToHtml(state);
}
handleSelectContent(content) {
let assignment = this.state.edited;
const existing = _.find(assignment.children, {'uuid': content.get('uuid')});
const {dispatch} = this.props;
if (!existing) {
dispatch(snackbarShowMessage('Content added'));
assignment.children.push(content.toJS());
this.setState({'edited': assignment, dirty: true});
dispatch(applicationIsDirty(true));
}
}
handleRemoveContent(content, e) {
let assignment = this.state.edited;
const {dispatch} = this.props;
assignment.children = assignment.children.filter((item, i) => {
return content.uuid != item.uuid;
});
dispatch(snackbarShowMessage('Content removed'));
this.setState({'edited': assignment, dirty: true});
dispatch(applicationIsDirty(true));
}
handleOpenContent() {
this.setState({'contentIsOpen': true});
}
handleCloseContent() {
this.setState({'contentIsOpen': false});
}
render() {
if (this.getUuid() && !this.props.assignments.items.size) {
return <LoadingIndicator />;
}
let dueDate = null;
if (this.state.edited.due_at) {
dueDate = moment.utc(this.state.edited.due_at, 'YYYY-MM-DD HH:mm:ss').local().toDate();
}
let assignment_types = [];
if (Config && Config.get('assignment_types')) {
assignment_types = Config.get('assignment_types');
}
const presetIssue = (this.props.location && this.props.location.query.issue)
? decodeURIComponent(this.props.location.query.issue)
: null;
if (presetIssue) {
let issue = this.props.issues.items.find((item) => item.get('uuid') == presetIssue);
if (issue)
this.state.edited.issue = issue.toJS();
}
// Allows existing items attached to closed issues
// to still show the issue in the select drop down
let useIssue = null;
let didUseIssue = false;
if (this.state.edited
&& this.state.edited.issue
&& !parseInt(this.state.edited.issue.status) ) {
let tempIssue = this.state.edited.issue;
let useLabel = [];
if (tempIssue.published_at) {
useLabel.push(moment(new Date(tempIssue.published_at)).local().format('LL'));
}
if (tempIssue.label) {
useLabel.push(tempIssue.label);
}
useLabel = useLabel.join(' - ');
if (useLabel.length > 25) {
useLabel = useLabel.substring(0, 22) + '...';
}
tempIssue.decorated_label = useLabel;
useIssue = tempIssue;
}
let creator = this.props.users.items.find((user) => {
return this.state.edited.creator_id == user.get('id');
})
return (
<div className='assignment-item-root'>
<Row>
<Col xs={12}>
<Paper className='toolbar' style={{ paddingTop:'10px', paddingBottom:'10px' }}>
<Row middle='xs'>
<Col xs={6}>
<LockButtons
onSave={this.handleSave}
onSaveCheckIn={this.handleSaveCheckIn}
onCheckIn={this.handleCheckin}
onCheckOut={this.handleCheckout}
userEditable={this.isUserEditable()}
lockable={this.state.edited}
/>
</Col>
</Row>
</Paper>
<Row>
<Col xs={9}>
<Paper className='padded clear-bottom'>
<TextField
style={{display:'none'}}
htmlFor='slug'
fullWidth={true}
floatingLabelText='Slug'
disabled={this.isUserEditable() ? false : true}
onChange={this.handleFormChange}
value={this.state.edited.slug ? this.state.edited.slug : ''}
ref='slugTextField'
/>
<TextField
htmlFor='title'
fullWidth={true}
floatingLabelText='Title'
disabled={this.isUserEditable() ? false : true}
onChange={this.handleFormChange}
value={this.state.edited.title ? this.state.edited.title : ''}
/>
<div style={{marginTop:'1em'}}>
<Subheader style={{paddingLeft:'0px'}}>Description</Subheader>
<SimpleEditor
value={this.state.edited.content}
onChange={this.handleEditorChange}
readOnly={this.isUserEditable() ? false : true}
/>
</div>
<Row middle='xs'>
<Col xs={6}>
<TextField
htmlFor='contact_name'
fullWidth={true}
floatingLabelText='Contact Name'
disabled={this.isUserEditable() ? false : true}
onChange={this.handleFormChange}
value={this.state.edited.contact_name ? this.state.edited.contact_name : ''}
/>
</Col>
<Col xs={6}>
<TextField
htmlFor='contact_phone'
fullWidth={true}
floatingLabelText='Contact Phone'
disabled={this.isUserEditable() ? false : true}
onChange={this.handleFormChange}
value={this.state.edited.contact_phone ? this.state.edited.contact_phone : ''}
/>
</Col>
</Row>
<Row middle='xs'>
<Col xs={6}>
<Row middle='xs'>
<Col xs={12}>
<DatePicker
fullWidth={true}
floatingLabelText='Start Date'
disabled={this.isUserEditable() ? false : true}
onChange={this.actionDateChange.bind(this, 'start')}
value={this.state.actionStartDate}
firstDayOfWeek={0}
/>
</Col>
</Row>
</Col>
<Col xs={6}>
{
new Date(this.state.actionStartTime).valueOf() == new Date(this.state.actionEndTime).valueOf()
? (
<Row middle='xs'>
<Col xs={12}>
<TimePicker
fullWidth={true}
floatingLabelText='Start Time'
disabled={this.isUserEditable() && this.state.actionStartDate ? false : true}
onChange={this.actionTimeChange.bind(this, 'start')}
value={this.state.actionStartTime}
defaultTime={this.state.actionStartDate}
/>
</Col>
</Row>
)
: (
<Row middle='xs'>
<Col xs={6}>
<TimePicker
fullWidth={true}
floatingLabelText='Start Time'
disabled={this.isUserEditable() && this.state.actionStartDate ? false : true}
onChange={this.actionTimeChange.bind(this, 'start')}
value={this.state.actionStartTime}
defaultTime={this.state.actionStartDate}
/>
</Col>
<Col xs={6}>
<TimePicker
fullWidth={true}
floatingLabelText='End Time'
disabled={this.isUserEditable() && this.state.actionStartTime ? false : true}
onChange={this.actionTimeChange.bind(this, 'end')}
value={this.state.actionEndTime}
/>
</Col>
</Row>
)
}
</Col>
<Col xs={12}>
<TextField
htmlFor='location'
fullWidth={true}
floatingLabelText='Location'
disabled={this.isUserEditable() ? false : true}
onChange={this.handleFormChange}
value={this.state.edited.location ? this.state.edited.location : ''}
/>
</Col>
</Row>
</Paper>
<Paper className='padded clear-bottom'>
<Subheader style={{paddingLeft:'0px'}}>Linked Content</Subheader>
{this.state.edited.children.map((item, i) => {
return (
<Row key={i}>
<Col xs={12} style={{marginBottom:'6px'}}>
<ContentRow
item={Immutable.fromJS(item)}
closeIcon={
<FontIcon
className='mui-icons'
style={{'cursor': 'pointer'}}
>
close
</FontIcon>
}
closeAction={
this.handleRemoveContent.bind(this, item)
}
disabled={this.isUserEditable() ? false : true}
/>
</Col>
</Row>
)
})}
<Row>
<Col xs={12}>
<RaisedButton
onClick={this.handleOpenContent.bind(this)}
secondary={true}
label='Attach Content'
style={{marginRight:'10px'}}
disabled={this.isUserEditable() ? false : true}
/>
<RaisedButton
containerElement={<Link to={'/ceo/content/new?assignment='+this.getUuid()} />}
label='Create Content'
disabled={this.isUserEditable() ? false : true}
/>
</Col>
</Row>
</Paper>
{
this.getUuid()
? (
<Paper className='padded clear-bottom'>
<AssignmentDiscussion assignment={this.getUuid()} readOnly={this.isUserEditable() ? false : true} />
</Paper>
)
: ''
}
</Col>
<Col xs={3}>
<Paper className='padded clear-bottom'>
<SelectField
fullWidth={true}
style={{'maxWidth': '100%'}}
floatingLabelText='Assignment Type'
disabled={this.isUserEditable() ? false : true}
onChange={this.handleSelectChange.bind(this)}
value={this.state.edited.type}
>
{assignment_types.map((type, i) => {
return <MenuItem key={i} value={type} primaryText={type} />;
})}
</SelectField>
<SelectField
autoWidth={true}
style={{maxWidth: '100%'}}
value={parseInt(this.state.edited.workflow_id) ? this.state.edited.workflow_id : null}
disabled={this.isUserEditable() ? false : true}
onChange={this.handleWorkflowChange.bind(this)}
floatingLabelText='Workflow Status'
>
{this.props.workflows.filters.assignmentOnly.map((id, i) => {
const wf = this.props.workflows.items.find((workflow) => {
return workflow.get('uuid') == id;
})
return <MenuItem key={i} value={wf.get('id')} primaryText={wf.get('name')} />
})}
</SelectField>
<DatePicker
autoOk={true}
fullWidth={true}
hintText="Due Date"
value={dueDate}
disabled={this.isUserEditable() ? false : true}
onChange={this.dueDateChange.bind(this)}
floatingLabelText='Due Date'
style={{'maxWidth': '100%'}}
firstDayOfWeek={0}
/>
<SelectField
floatingLabelText='Issue'
value={this.state.edited.issue ? this.state.edited.issue.uuid : ''}
disabled={this.isUserEditable() ? false : true}
onChange={this.handleIssueChange.bind(this)}
style={{width:'100%'}}
>
{this.props.issues.items.map((item, i) => {
// const item = this.props.issues.items.find((item, i) => item.get('uuid') == id);
if (useIssue && item.get('uuid') == useIssue.uuid) {
didUseIssue = true;
}
let label = [];
if (item.get('published_at')) {
label.push(moment(new Date(item.get('published_at'))).local().format('LL'));
}
if (item.get('label')) {
label.push(item.get('label'));
}
label = label.join(' - ');
if (label.length > 25) {
label = label.substring(0, 22) + '...';
}
return (
<MenuItem key={i} value={item.get('uuid')} primaryText={label} />
);
})}
{
useIssue && !didUseIssue
? <MenuItem value={useIssue.uuid} primaryText={useIssue.decorated_label} />
: ''
}
</SelectField>
</Paper>
<Paper className='clear-bottom'>
<List>
<Subheader className='fixed-label'>Assigned Users</Subheader>
<ListItem disabled={true} style={{marginTop:'-16px', paddingTop:'0px', paddingBottom:'0px'}}>
<UserSearchBox
onSelectUser={this.onSelectUser.bind(this)}
disabled={this.isUserEditable() ? false : true}
/>
</ListItem>
{this.state.edited.users.map((user, i) => {
return (
<ListItem
key={i}
disabled={true}
primaryText={user.name}
secondaryText={user.phone ? ('tel: '+user.phone) : ''}
rightIcon={
<FontIcon
className='mui-icons '
style={{'cursor': 'pointer'}}
onClick={this.onRemoveUser.bind(this, user)}
>close</FontIcon>
}
>
</ListItem>
);
})}
{
creator
? (
<div>
<Subheader>Created By</Subheader>
<ListItem
style={{paddingTop:'0px'}}
disabled={true}
primaryText={creator.get('name')}
secondaryText={creator.get('phone') ? ('tel: '+creator.get('phone')) : ''}
/>
</div>
)
: ''
}
</List>
</Paper>
<div className="clear-bottom">
<DeleteButton
className='full'
fullWidth={true}
disabled={this.isNew() || !this.isUserEditable() ? true : false}
onDelete={this.handleDelete.bind(this)} />
</div>
{
this.isLocked()
? (
<div className='clear-bottom'>
<RaisedButton
label='Clear Lock'
style={{width:'100%'}}
icon={<FontIcon className='mui-icons'>clear</FontIcon>}
onClick={this.handleClearLock.bind(this)}
disabled={CurrentUser.hasRole('Administrator') && !this.isNew() ? false : true}
/>
</div>
)
: ''
}
</Col>
</Row>
<ContentSearchModal
isOpen={this.state.contentIsOpen}
onRequestClose={this.handleCloseContent.bind(this)}
onSelectContent={this.handleSelectContent.bind(this)}
/>
</Col>
</Row>
</div>
);
}
}
export default connect((state) => {
return {
assignments: state.assignments,
workflows: state.workflows,
issues: state.issues,
users: state.users,
globalHistory: state.globalHistory
}
})(AssignmentItem);