Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#165 To-Do View (for unscheduled plans) #182

Merged
merged 3 commits into from Mar 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/components/event_view/event_info/EventInfo.js
Expand Up @@ -32,5 +32,7 @@ export default class EventInfo extends Component {
}

EventInfo.propTypes = {
event: PropTypes.object.isRequired
// Not required since the event may be null when rendered and then changed
// after the user makes a selection
event: PropTypes.object
};
42 changes: 21 additions & 21 deletions src/components/trip_view/cal/CalViewOptions.js
Expand Up @@ -43,29 +43,29 @@ export class CalViewOptions extends Component {
let location = this.props.history.location;
let currView = queryString.parse(location.search).view;

// These are all the view buttons that are needed.
// Index 0 is the route, index 1 is the title display.
let views = [
['month', 'Month View'],
['week', 'Week View'],
['day', 'Day View'],
['agenda', 'Agenda View'],
['todo', 'To-Do View']
];

return (
<ButtonGroup>
<Button
onClick={() => this.routeTo('month')}
active={currView === 'month'}
>
Month View
</Button>
<Button
onClick={() => this.routeTo('week')}
active={currView === 'week'}
>
Week View
</Button>
<Button onClick={() => this.routeTo('day')} active={currView === 'day'}>
Day View
</Button>
<Button
onClick={() => this.routeTo('agenda')}
active={currView === 'agenda'}
>
Agenda View
</Button>
{views.map((view) => {
return (
<Button
key={view[0]}
onClick={() => this.routeTo(view[0])}
active={currView === view[0]}
>
{view[1]}
</Button>
);
})}
</ButtonGroup>
);
}
Expand Down
5 changes: 0 additions & 5 deletions src/components/trip_view/cal/EventModal.js
Expand Up @@ -9,12 +9,7 @@ import EventInfo from '../../event_view/event_info/EventInfo';
* a component that is specific to the type of event being shown.
*/
export class EventModal extends Component {
constructor(props) {
super(props);
}
render() {
let eventComponent = null;

return (
<Modal show={this.props.show} onHide={this.props.onHide}>
<Modal.Header closeButton>
Expand Down
9 changes: 9 additions & 0 deletions src/components/trip_view/cal/ToDoItem.css
@@ -0,0 +1,9 @@

/*
Overrides the default styles to make the span visible
*/
.pull-right {
width: 50px;
height: 40px;
display: block;
}
46 changes: 46 additions & 0 deletions src/components/trip_view/cal/ToDoItem.js
@@ -0,0 +1,46 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Card } from 'react-bootstrap';
import { PriorityIndicator } from '../../global/PriorityIndicator';
import './AgendaItem.css';
import './ToDoItem.css'; // This is needed for a CSS hack
import { EventTypeIndicator } from '../../global/EventTypeIndicator';

/**
* This is the code for a single item displayed on the react-big-calendar
* to-do list. It displays the title, priority, and event type (no dates).
*/
export class ToDoItem extends Component {
render() {
let { accessors, event } = this.props;

// Retrieve info in the default way for react-big-calendar
let title = accessors.title(event);

// Retrieve specialized info
let priority = event.priority; // May be null
let eventType = event.event_type; // May be null

return (
<Card onClick={() => this.props.onSelectEvent(event)}>
<Card.Body>
<div>
<EventTypeIndicator type={eventType} size={'3x'} />
{title}
<div className="pull-right">
<PriorityIndicator priority={+priority} />
</div>
</div>
</Card.Body>
</Card>
);
}
}

ToDoItem.propTypes = {
event: PropTypes.object.isRequired, // The event to show
accessors: PropTypes.object.isRequired, // The accessors to figure out
// what to show from the event object
localizer: PropTypes.object.isRequired, // moment (for dealing with dates)
onSelectEvent: PropTypes.func.isRequired // what to do when selected
};
80 changes: 80 additions & 0 deletions src/components/trip_view/cal/ToDoView.js
@@ -0,0 +1,80 @@
import PropTypes from 'prop-types';
import React from 'react';

import { ToDoItem } from './ToDoItem';
import { filterTripToDos } from '../../../redux/getters/getEvents';

/**
* This react-big-calendar view displays all events that have a NULL
* start time. That is, it shows all unscheduled to-dos.
* It takes much of its structure from the AgendaView component.
*/
class ToDoList extends React.Component {
constructor(props) {
super(props);
this.renderToDo = this.renderToDo.bind(this);
}

render() {
let { events } = this.props;

// Gets just events with no associated start time.
events = filterTripToDos(events);

// Sort by date (the + turns them into numbers that are easily sortable)
events.sort((a, b) => +b.priority - +a.priority);
gzinck marked this conversation as resolved.
Show resolved Hide resolved

// Figure out what to show for the to-do list
// (depends on if there are any events)
let agendaContent;
if (events.length !== 0) {
agendaContent = (
<div className="rbc-agenda-content" ref="content">
{events.map((event) => {
return this.renderToDo(event);
})}
</div>
);
} else {
agendaContent = (
<span className="rbc-agenda-empty">
There are no unscheduled to-dos.
</span>
);
}

return <div className="rbc-agenda-view">{agendaContent}</div>;
}

/**
* This renders a single to-do (event)
* @param event the event to render (with no dates)
* @returns {*} JSX for the event view
*/
renderToDo(event) {
gzinck marked this conversation as resolved.
Show resolved Hide resolved
let { accessors, localizer } = this.props;

return (
<ToDoItem
key={event.event_type + '_' + event.e_id}
event={event}
accessors={accessors}
localizer={localizer}
onSelectEvent={this.props.onSelectEvent}
/>
);
}
}

ToDoList.propTypes = {
events: PropTypes.array, // The events to show
accessors: PropTypes.object.isRequired, // How to get the data from event objects
localizer: PropTypes.object.isRequired // moment localizer for dates
};

// This is required for react-big-calendar
ToDoList.title = () => {
return 'Trip To-Dos';
};

export default ToDoList;
9 changes: 8 additions & 1 deletion src/components/trip_view/cal/TripCal.js
Expand Up @@ -7,6 +7,7 @@ import { TripCalToolbar } from './TripCalToolbar';
import { EventModal } from './EventModal';
import './TripCal.css';
import Agenda from './AgendaView';
import ToDoView from './ToDoView';

// Localizer for the calendar for formatting date objects
const localizer = BigCalendar.momentLocalizer(moment);
Expand Down Expand Up @@ -65,7 +66,13 @@ export class TripCal extends Component {
onSelectEvent={this.selectEvent}
popup={true}
components={components}
views={{ month: true, week: true, day: true, agenda: Agenda }}
views={{
month: true,
week: true,
day: true,
agenda: Agenda,
todo: ToDoView
}}
/>
</div>
<EventModal
Expand Down
15 changes: 15 additions & 0 deletions src/redux/getters/getEvents.js
Expand Up @@ -38,3 +38,18 @@ export function getTripEvents(state, tripId) {
}))
];
}

/**
* This gets all of the plans associated with the trip ID where the
* start time is undefined. That is, it filters the events to find
* all of the to-dos not on the calendar.
* @param events array of events (as from getTripEvents(state, tripId)
* @returns {any[]} array of to-dos
*/
export function filterTripToDos(events) {
events = events.filter((event) => {
// keep if no start time and it's a plan type
return event.begin_time === null;
});
return events;
}