application/components/assignment/assignment-calendar.js
- import React from 'react';
- import {browserHistory, Link} from 'react-router';
- import {timeToFormat} from './../../util/strings';
- import {connect} from 'react-redux';
- import moment from 'moment';
- import _ from 'lodash';
- import Immutable from 'immutable';
-
- import HTML5Backend from 'react-dnd-html5-backend'
- import { DragDropContext } from 'react-dnd'
-
- import CurrentUser from './../../current-user';
-
- import BigCalendar from 'react-big-calendar';
- import withDragAndDrop from './addons/dragAndDrop';
-
- import Paper from 'material-ui/Paper';
- import Dialog from 'material-ui/Dialog';
- import DatePicker from 'material-ui/DatePicker';
- import FlatButton from 'material-ui/FlatButton';
- import SelectField from 'material-ui/SelectField';
- import MenuItem from 'material-ui/MenuItem';
- import FontIcon from 'material-ui/FontIcon';
- import Subheader from 'material-ui/Subheader';
- import {RadioButton, RadioButtonGroup} from 'material-ui/RadioButton';
-
- import {Row, Col} from './../flexbox';
- import ceoTheme from './../../theme';
-
- import {IssueModal} from './../issue';
-
- import {
- assignmentsUpdate,
- assignmentsCheckOut,
- assignmentsCheckIn,
- assignmentsFetch,
- assignmentsFetchOne
- } from './../../redux/actions/assignment-actions';
-
- import {
- issuesFetch,
- issueUpdate
- } from './../../redux/actions/issue-actions';
-
- import {
- snackbarShowMessage
- } from './../../redux/actions/snackbar-actions';
-
- import {
- assignmentViewUpdate
- } from './../../redux/actions/assignment-view-actions';
-
- import AssignmentManager from './../../managers/assignment-manager';
-
- import request from './../../util/request';
- import LoadingIndicator from '../common/loading-indicator';
-
- const localizer = BigCalendar.momentLocalizer(moment)
- const DragAndDropCalendar = withDragAndDrop(BigCalendar);
-
- function getUrlParameter(name) {
- name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
- var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
- var results = regex.exec(location.search);
- return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
- };
-
- function Event({ event }) {
- let colors = {
- 'photo': '#DA8AE5',
- 'article': '#01BCD4',
- 'issue': 'green',
- 'misc': 'orange'
- }
-
- const lock = <FontIcon style={{color:'white', verticalAlign:'middle', fontSize:'20px', marginLeft:'-2px'}} className='mui-icons'>lock</FontIcon>;
- const lockBlack = <FontIcon style={{color:'black', verticalAlign:'middle', fontSize:'16px', marginLeft:'-2px', marginRight:'1px'}} className='mui-icons'>lock</FontIcon>;
-
- let color = colors['misc'];
- if (colors[event.type]) {
- color = colors[event.type];
- }
-
- if (event.type == 'issue') {
- return (
- <div style={{
- backgroundColor: color,
- padding: '2px 5px',
- }}>
- {event.lock ? lock : ''}<strong style={{verticalAlign:'middle'}}>{event.title ? event.title : (moment(event.start).format('MMMM Do') + ' Issue')}</strong>
- </div>
- )
- }
-
- if (!event.unscheduled) {
- return (
- <div style={{
- padding: '2px 5px',
- color: 'black'
- }}>
- {event.lock ? lockBlack : <span style={{width:'10px', height:'10px', backgroundColor:color, display:'inline-block', marginRight:'3px'}}></span>}
- <span style={{verticalAlign:'middle'}}>{event.title ? event.title : event.slug}</span>
- </div>
- )
- }
-
- return null;
- }
-
- function CustomToolbar(toolbar) {
- const goToBack = () => {
- toolbar.date.setMonth(toolbar.date.getMonth() - 1);
- toolbar.onNavigate('prev');
- };
-
- const goToNext = () => {
- toolbar.date.setMonth(toolbar.date.getMonth() + 1);
- toolbar.onNavigate('next');
- };
-
- const goToCurrent = () => {
- const now = new Date();
- toolbar.date.setMonth(now.getMonth());
- toolbar.date.setYear(now.getFullYear());
- toolbar.onNavigate('current');
- };
-
- const label = () => {
- const date = moment(toolbar.date);
- return (
- <h3 style={{margin:'0px'}}>{date.format('MMMM')} {date.format('YYYY')}</h3>
- );
- };
-
- let calView = window.Store.getState().assignmentView.calview;
-
- const swapView = () => {
- if (window.Store.getState().assignmentView.calview == 'issue') {
- window.Store.dispatch(assignmentViewUpdate({
- 'calview': 'assignment'
- }))
- .then(() => AssignmentManager.fetchFromView());
- } else if (window.Store.getState().assignmentView.calview == 'assignment') {
- window.Store.dispatch(assignmentViewUpdate({
- 'calview': 'issue'
- }))
- .then(() => AssignmentManager.fetchFromView());
- }
-
- }
-
- return (
- <div>
- <Row className='rbc-toolbar'>
- <Col xs={4}>
- <FlatButton
- label="BACK"
- labelPosition="after"
- onClick={goToBack}
- icon={<FontIcon className='mui-icons'>keyboard_arrow_left</FontIcon>}
- />
- <FlatButton
- label="TODAY"
- onClick={goToCurrent}
- />
- <FlatButton
- label="NEXT"
- labelPosition="before"
- onClick={goToNext}
- icon={<FontIcon className='mui-icons'>keyboard_arrow_right</FontIcon>}
- />
- </Col>
- <Col xs={4} style={{textAlign:'center'}}>
- {label()}
- </Col>
- <Col xs={4} style={{textAlign:'right'}}>
- <span style={{fontSize:'14px', verticalAlign:'middle'}}>SORT BY: </span>
- <FlatButton
- label="ISSUE"
- onClick={swapView}
- disabled={calView == 'issue'}
- icon={calView == 'issue'
- ? (<FontIcon className='mui-icons'>check_circle</FontIcon>)
- : ''
- }
- />
- <FlatButton
- label="DUE DATE"
- onClick={swapView}
- disabled={calView == 'assignment'}
- icon={calView == 'assignment'
- ? (<FontIcon className='mui-icons'>check_circle</FontIcon>)
- : ''
- }
- />
- </Col>
- </Row>
- </div>
- );
- };
-
- class UnwrappedAssignmentCalendar extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = {
- eventSetterOpen: false,
- eventSetterDate: null,
- eventSetterAssignment: null,
- eventSetterIssue: null,
- multiIssueDrop: [],
- multiIssueSetterOpen: false,
- multiIssueSetterId: null,
- multiIssueSetterAssignment: null,
- issueModalOpen: false,
- issueModalDate: null,
- unassigned: Immutable.fromJS([])
- }
-
- this.handleMove = this.handleMove.bind(this);
- this.handleNavigate = this.handleNavigate.bind(this);
- this.handleClose = this.handleClose.bind(this);
- this.handleSetterSave = this.handleSetterSave.bind(this);
- this.handleAssignmentChange = this.handleAssignmentChange.bind(this);
- this.handleDateChange = this.handleDateChange.bind(this);
- this.handleMultiIssueSave = this.handleMultiIssueSave.bind(this);
- this.handleMultiIssueChange = this.handleMultiIssueChange.bind(this);
- this.handleIssueModalClose = this.handleIssueModalClose.bind(this);
-
- this.fetchUpdate = this.fetchUpdate.bind(this);
- }
-
- componentWillMount() {
- if (this.props.assignmentView.useDate) {
- this.fetchUpdate();
- } else {
- this.props.dispatch(assignmentViewUpdate({
- useDate: moment()
- }))
- .then(() => this.fetchUpdate());
- }
- }
-
- fetchUpdate() {
- const {dispatch} = this.props;
- dispatch(issuesFetch({
- 'start': this.props.assignmentView.useDate.startOf('month').format('YYYY-MM-DD'),
- 'end': this.props.assignmentView.useDate.endOf('month').format('YYYY-MM-DD')
- }))
- .then(() => {
- dispatch(assignmentsFetch({'type': 'unscheduled'}))
- .then(() => {
- this.setState({unassigned: this.props.assignments.items});
- })
- .then(() => {
- if (this.props.assignmentView.calview == 'issue') {
- let issues = [];
- this.props.issues.items.map((issue) => {
- issues.push(issue.get('uuid'));
- });
-
- dispatch(assignmentViewUpdate({
- issues: issues,
- type: 'any'
- }))
- .then(() => AssignmentManager.fetchFromView());
- } else {
- dispatch(assignmentViewUpdate({
- start: this.props.assignmentView.useDate.startOf('month').format('YYYY-MM-DD'),
- end: this.props.assignmentView.useDate.endOf('month').format('YYYY-MM-DD'),
- issues: [],
- type: 'any'
- }))
- .then(() => AssignmentManager.fetchFromView());
- }
- });
- });
- }
-
- // shouldComponentUpdate(nextProps, nextState) {
- // if (this.props.assignments != nextProps.assignments) {
- // return true;
- // }
-
- // if (this.props.issueDueDates != nextProps.dueDates) {
- // return true;
- // }
-
- // if (this.state.eventSetterOpen != nextState.eventSetterOpen) {
- // return true;
- // }
-
- // return false;
- // }
-
- handleMove({ event, start, end }) {
- let useEvent = this.props.assignments.items.find(item => item.get('uuid') == event.uuid);
-
- if (this.props.assignmentView.calview == 'issue') {
- const day = moment(start).format('MMDDYYYY');
-
- let issues = this.props.issues.items.filter((issue) => {
- if (moment(issue.get('published_at')).format('MMDDYYYY') == day) {
- return true;
- }
- return false;
- });
-
- if (issues.size == 1) {
- let issue = this.props.issues.items.find((item) => moment(item.get('published_at')).format('MMDDYYYY') == day);
- this.handleAssignmentSave(useEvent, event.start, event.end, issue.get('id'));
- } else if (issues.size > 1){
- this.setState({multiIssueDrop: issues, multiIssueSetterOpen: true, multiIssueSetterAssignment: event.uuid});
- }
- } else if (this.props.assignmentView.calview == 'assignment') {
- if (!event.lock && event.start !== start) {
- this.handleAssignmentSave(useEvent, start, end);
- event.unscheduled = false;
- }
- }
- }
-
- handleEventClick(event) {
- if (event.type == 'issue') {
- this.setState({eventSetterOpen: true, eventSetterIssue: event});
- } else {
- browserHistory.push('/ceo/redirect?next=assignment/' + event.uuid);
- }
- }
-
- handleDayClick(day) {
- if (this.props.calView == 'assignment') {
- this.setState({eventSetterOpen: true, eventSetterDate: day.start});
- } else {
- this.setState({issueModalOpen: true, issueModalDate: day.start});
- }
- }
-
- handleAssignmentSave(event, start, end, issueId) {
- const {dispatch} = this.props;
- let data = {};
-
- if (!issueId) {
- data.due_at = moment(start).utc();
- } else {
- data.issue = issueId;
- }
-
- if (event.get('lock')) {
- console.log('handling the lock');
- } else {
- dispatch(assignmentsCheckOut(event.get('srn')))
- .then(() => {
- dispatch(assignmentsUpdate(event.get('uuid'), data));
- })
- .then(() => {
- dispatch(snackbarShowMessage('Assignment updated'));
- })
- .then(() => {
- this.handleCheckIn(event);
- })
- }
- }
-
- handleIssueSave(event, start, end) {
- const {dispatch} = this.props;
- let data = {};
-
- //set datetime as utc
- data.published_at = moment(start).utc();
-
- dispatch(issueUpdate(event.uuid, data))
- .then(() => dispatch(issuesFetch()))
- .then(() => dispatch(snackbarShowMessage('Issue updated')));
- }
-
- handleNavigate(date) {
- //do stuff when you navigate
- const {dispatch} = this.props;
-
- dispatch(assignmentViewUpdate({
- useDate: moment(date)
- }))
- .then(() => this.fetchUpdate());
- }
-
- handleAssignmentChange(e, i, uuid) {
- console.log(uuid);
- this.setState({eventSetterAssignment: uuid});
- }
-
- handleDateChange(e, i, date) {
- this.setState({eventSetterDate: date})
- }
-
- handleSetterSave() {
- let event = this.state.unassigned.filter((item) => item.get('uuid') == this.state.eventSetterAssignment).first();
-
- let issue = null;
-
- if (this.props.assignmentView.calview == 'issue' && this.state.eventSetterIssue) {
- issue = this.props.issues.items.find((item) => item.get('uuid') == this.state.eventSetterIssue.uuid);
- }
-
- if (this.state.eventSetterDate) {
- event = event.set('start', this.state.eventSetterDate)
- .set('end', this.state.eventSetterDate);
- }
-
- event = event.set('unscheduled', false);
-
- if (event && event.type !== 'issue' && !issue) {
- this.handleAssignmentSave(event, event.start, event.end);
- } else if (event && issue) {
- this.handleAssignmentSave(event, event.start, event.end, issue.get('id'));
- }
-
- this.handleClose();
- }
-
- handleMultiIssueChange(e, i, id) {
- this.setState({multiIssueSetterId: id})
- };
-
- handleMultiIssueSave() {
- const event = this.props.issueDueDates.find((item) => item.uuid == this.state.multiIssueSetterAssignment);
- const id = this.state.multiIssueSetterId;
-
- if (event && id) {
- this.handleAssignmentSave(event, event.start, event.end, id);
- }
-
- this.handleClose();
- }
-
- handleClose() {
- this.setState({eventSetterOpen: false, eventSetterAssignment: null, multiIssueSetterOpen: false, multiIssueSetterId: null});
- }
-
- handleCheckIn(event) {
- const {dispatch} = this.props;
-
- dispatch(assignmentsFetchOne(event.get('uuid')))
- .then((response) => {
- // console.log(response);
- const assignment = this.props.assignments.items.find((item) => item.get('uuid') == event.get('uuid'));
- dispatch(assignmentsCheckIn(assignment.get('uuid'), assignment.get('lock').get('uuid')));
- });
- }
-
- handleIssueModalClose(e) {
- this.setState({issueModalOpen: false, issueModalDate: null});
- }
-
- render() {
- const formats = {
- dateFormat: 'D'
- }
-
- let assignments = [];
-
- if (this.props.assignmentView.calview == 'issue') {
- this.props.issues.items.map((issue,i) => {
- let event = {};
-
- //event.allDay = true;
- event.title = issue.get('label') ? issue.get('label') : issue.get('slug');
- event.uuid = issue.get('uuid');
- event.type = 'issue';
-
- if (!CurrentUser.hasRole('Administrator')) {
- event.lock = true;
- } else {
- event.lock = false;
- }
-
- if (issue.get('published_at')) {
- event.start = moment.utc(issue.get('published_at')).local().toDate();
- event.end = moment.utc(issue.get('published_at')).local().toDate();
- } else {
- event.unscheduled = true;
- }
-
- assignments.push(event);
-
- let issueId = issue.get('id');
- let filtered = this.props.assignments.items.filter((assignment,i) => {
- if (assignment.get('issue_id') == issueId) {
- return true;
- }
-
- return false;
- })
-
- filtered.map((assignment,i) => {
- let event = {};
-
- //event.allDay = true;
- event.title = assignment.get('title') ? assignment.get('title') : assignment.get('slug');
- event.type = assignment.get('type');
- event.slug = assignment.get('slug');
- event.uuid = assignment.get('uuid');
- event.srn = assignment.get('srn');
-
- // check if the assignment is locked
- if (assignment.get('lock') && assignment.get('lock').get('user_id') !== CurrentUser.getId()) {
- event.lock = assignment.get('lock').get('uuid');
- event.lockUser = assignment.get('lock').get('user_id');
- }
-
- event.start = moment.utc(issue.get('published_at')).local().toDate();
- event.end = moment.utc(issue.get('published_at')).local().toDate();
-
- assignments.push(event);
- })
- });
- } else {
- this.props.assignments.items.map((item,i) => {
- let event = {};
-
- //event.allDay = true;
- event.title = item.get('title') ? item.get('title') : item.get('slug');
- event.type = item.get('type');
- event.slug = item.get('slug');
- event.uuid = item.get('uuid');
- event.srn = item.get('srn');
- event.issue = item.get('issue_id') ? item.get('issue_id') : null;
- //need a way of differentiating viewmodes in backgroundWrapper
- event.flag = true;
-
- // check if the assignment is locked
- if (item.get('lock') && item.get('lock').get('user_id') !== CurrentUser.getId()) {
- event.lock = item.get('lock').get('uuid');
- event.lockUser = item.get('lock').get('user_id');
- }
-
- // set the event unscheduled if it has no due_at
- if (item.get('due_at')) {
- event.start = moment.utc(item.get('due_at')).local().toDate();
- event.end = moment.utc(item.get('due_at')).local().toDate();
- } else {
- event.unscheduled = true;
- }
-
- assignments.push(event);
- });
- }
-
- const eventSetterActions = [
- <FlatButton
- label="Cancel"
- primary={true}
- onClick={this.handleClose}
- />,
- <FlatButton
- label="Submit"
- primary={true}
- disabled={this.state.eventSetterAssignment ? false : true}
- onClick={this.handleSetterSave}
- />,
- ];
-
- const multiIssueSetterActions = [
- <FlatButton
- label="Cancel"
- primary={true}
- onClick={this.handleClose}
- />,
- <FlatButton
- label="Submit"
- primary={true}
- disabled={this.state.multiIssueSetterId ? false : true}
- onClick={this.handleMultiIssueSave}
- />,
- ];
-
- return (
- <Paper style={{height:window.innerHeight}}>
- {
- this.props.issues.isFetching || this.props.assignments.isFetching
- ? <LoadingIndicator centered={true} />
- : ''
- }
- <DragAndDropCalendar
- className={this.props.assignmentView.calView}
- selectable
- popup
- views={['month', 'agenda']}
- events={assignments}
- onNavigate={this.handleNavigate.bind(this)}
- onSelectEvent={this.handleEventClick.bind(this)}
- onSelectSlot={this.handleDayClick.bind(this)}
- onEventDrop={this.handleMove}
- formats={formats}
- localizer={localizer}
- components={{
- event: Event,
- toolbar: CustomToolbar
- }}
- />
- <Dialog
- title='Schedule an Assignment Due Date'
- actions={eventSetterActions}
- modal={true}
- open={this.state.eventSetterOpen}
- contentStyle={{width:'500px'}}
- >
- <div>
- {
- this.props.assignmentView.calview == 'issue'
- ? (
- <SelectField
- floatingLabelText={'Add Assignment to Issue'}
- onChange={this.handleAssignmentChange}
- value={this.state.eventSetterAssignment}
- >
- {
- this.state.unassigned.map((item,i) => {
- if (!item.get('issue_id') && !item.get('lock')) {
- return (
- <MenuItem key={i} value={item.get('uuid')} primaryText={item.get('title') ? item.get('title') : item.get('slug')} />
- )
- }
- })
- }
- </SelectField>
- )
- : (
- <div>
- <DatePicker
- floatingLabelText='Selected Due Date'
- container='inline'
- mode='landscape'
- value={this.state.eventSetterDate}
- onChange={this.handleDateChange}
- firstDayOfWeek={0}
- />
- <SelectField
- floatingLabelText='Unscheduled Assignments'
- onChange={this.handleAssignmentChange}
- value={this.state.eventSetterAssignment}
- >
- {
- assignments.map((event,i) => {
- if (event.unscheduled && !event.lock) {
- return (
- <MenuItem key={i} value={event.uuid} primaryText={event.title} />
- )
- }
- })
- }
- </SelectField>
- </div>
- )
- }
- </div>
- </Dialog>
- <Dialog
- title='Which Issue do you want this Assignment linked to?'
- actions={multiIssueSetterActions}
- modal={true}
- open={this.state.multiIssueSetterOpen}
- contentStyle={{width:'500px'}}
- >
- <SelectField
- floatingLabelText='Select an Issue'
- onChange={this.handleMultiIssueChange}
- value={this.state.multiIssueSetterId}
- >
- {
- this.state.multiIssueDrop.map((issue,i) => {
- return (
- <MenuItem key={i} value={issue.get('id')} primaryText={issue.get('label') ? issue.get('label') : (moment(issue.get('published_at')).format('MMMM Do') + ' Issue')} />
- )
- })
- }
- </SelectField>
- </Dialog>
- {
- this.state.issueModalDate
- ? (
- <IssueModal onClose={this.handleIssueModalClose} open={this.state.issueModalOpen} issueDate={this.state.issueModalDate} />
- )
- : ''
- }
- </Paper>
- );
- }
- }
-
- const mapStateToProps = (state) => {
- return {
- assignments: state.assignments,
- issues: state.issues,
- workflows: state.workflows,
- assignmentView: state.assignmentView
- };
- }
-
- const AssignmentCalendar = connect(mapStateToProps)(UnwrappedAssignmentCalendar);
-
- export default DragDropContext(HTML5Backend)(AssignmentCalendar);