From 02181b141b1a1ea7ae410cca3a6dc7689a381be3 Mon Sep 17 00:00:00 2001 From: Thibault Vigouroux Date: Fri, 2 Jun 2017 12:49:51 +0200 Subject: [PATCH] Add resource --- src/Calendar.js | 6 ++ src/DayColumn.js | 2 + src/TimeColumn.js | 8 +- src/TimeGrid.js | 93 +++++++++++++++------ src/TimeSlot.js | 5 +- src/TimeSlotGroup.js | 5 +- src/addons/dragAndDrop/backgroundWrapper.js | 5 +- src/less/time-grid.less | 4 + stories/Calendar.js | 31 +++++++ stories/resourceEvents.js | 43 ++++++++++ 10 files changed, 168 insertions(+), 34 deletions(-) create mode 100644 stories/resourceEvents.js diff --git a/src/Calendar.js b/src/Calendar.js index 67cd073ca..d87ab1ac5 100644 --- a/src/Calendar.js +++ b/src/Calendar.js @@ -81,6 +81,11 @@ class Calendar extends React.Component { */ events: PropTypes.arrayOf(PropTypes.object), + /** + * An array of resource objects that map events to a specific resource + */ + resources: PropTypes.arrayOf(PropTypes.object), + /** * Callback fired when the `date` value changes. * @@ -575,6 +580,7 @@ class Calendar extends React.Component { allDayAccessor: 'allDay', startAccessor: 'start', endAccessor: 'end', + resourceIdAccessor: 'resourceId', longPressThreshold: 250, }; diff --git a/src/DayColumn.js b/src/DayColumn.js index ad9fdda03..061090c5d 100644 --- a/src/DayColumn.js +++ b/src/DayColumn.js @@ -68,6 +68,7 @@ class DayColumn extends React.Component { dayWrapperComponent: elementType, eventComponent: elementType, eventWrapperComponent: elementType.isRequired, + resource: PropTypes.string } static defaultProps = { @@ -367,6 +368,7 @@ class DayColumn extends React.Component { slots, start: startDate, end: endDate, + resourceId: this.props.resource, action, }) } diff --git a/src/TimeColumn.js b/src/TimeColumn.js index 262a82790..fffd8525f 100644 --- a/src/TimeColumn.js +++ b/src/TimeColumn.js @@ -19,6 +19,7 @@ export default class TimeColumn extends Component { timeGutterFormat: dateFormat, type: PropTypes.string.isRequired, className: PropTypes.string, + resource: PropTypes.string, slotPropGetter: PropTypes.func, dayPropGetter: PropTypes.func, @@ -33,7 +34,7 @@ export default class TimeColumn extends Component { dayWrapperComponent: BackgroundWrapper, } - renderTimeSliceGroup(key, isNow, date) { + renderTimeSliceGroup(key, isNow, date, resource) { const { dayWrapperComponent, timeslots, showLabels, step, slotPropGetter, dayPropGetter, timeGutterFormat, culture } = this.props; return ( @@ -46,6 +47,7 @@ export default class TimeColumn extends Component { dayPropGetter={dayPropGetter} culture={culture} timeslots={timeslots} + resource={resource} showLabels={showLabels} timeGutterFormat={timeGutterFormat} dayWrapperComponent={dayWrapperComponent} @@ -54,7 +56,7 @@ export default class TimeColumn extends Component { } render() { - const { className, children, style, now, min, max, step, timeslots } = this.props; + const { className, children, style, now, min, max, step, timeslots, resource } = this.props; const totalMin = dates.diff(min, max, 'minutes') const numGroups = Math.ceil(totalMin / (step * timeslots)) const renderedSlots = [] @@ -73,7 +75,7 @@ export default class TimeColumn extends Component { ) next = dates.add(date, groupLengthInMinutes, 'minutes'); - renderedSlots.push(this.renderTimeSliceGroup(i, isNow, date)) + renderedSlots.push(this.renderTimeSliceGroup(i, isNow, date, resource)) date = next } diff --git a/src/TimeGrid.js b/src/TimeGrid.js index fc58e02e4..0ca6936d7 100644 --- a/src/TimeGrid.js +++ b/src/TimeGrid.js @@ -26,6 +26,7 @@ export default class TimeGrid extends Component { static propTypes = { events: PropTypes.array.isRequired, + resources: PropTypes.array, step: PropTypes.number, range: PropTypes.arrayOf( @@ -49,6 +50,7 @@ export default class TimeGrid extends Component { allDayAccessor: accessor.isRequired, startAccessor: accessor.isRequired, endAccessor: accessor.isRequired, + resourceIdAccessor: accessor.isRequired, selected: PropTypes.object, selectable: PropTypes.oneOf([true, false, 'ignoreEvents']), @@ -146,6 +148,7 @@ export default class TimeGrid extends Component { , width , startAccessor , endAccessor + , resources , allDayAccessor , showMultiDayTimes} = this.props; @@ -178,10 +181,12 @@ export default class TimeGrid extends Component { let gutterRef = ref => this._gutters[1] = ref && findDOMNode(ref); + let eventsRendered = this.renderEvents(range, rangeEvents, this.props.now, resources || [{}]); + return (
- {this.renderHeader(range, allDayEvents, width)} + {this.renderHeader(range, allDayEvents, width, resources)}
@@ -193,43 +198,49 @@ export default class TimeGrid extends Component { ref={gutterRef} className='rbc-time-gutter' /> - - {this.renderEvents(range, rangeEvents, this.props.now)} + {eventsRendered}
); } - - renderEvents(range, events, today){ - let { min, max, endAccessor, startAccessor, components } = this.props; + renderEvents(range, events, today, resources) { + let { min, max, endAccessor, startAccessor, resourceIdAccessor, components } = this.props; return range.map((date, idx) => { let daysEvents = events.filter( - event => dates.inRange(date, - get(event, startAccessor), - get(event, endAccessor), 'day') + event => dates.inRange(date, + get(event, startAccessor), + get(event, endAccessor), 'day') ) - return ( - - ) + return resources.map((resource, id) => { + + let eventsToDisplay = daysEvents.filter( + event => get(event, resourceIdAccessor) === resource.id + ) + + return ( + + ) + }) }) } - renderHeader(range, events, width) { + renderHeader(range, events, width, resources) { let { messages, rtl, selectable, components, now } = this.props; let { isOverflowing } = this.state || {}; @@ -237,6 +248,10 @@ export default class TimeGrid extends Component { if (isOverflowing) style[rtl ? 'marginLeft' : 'marginRight'] = scrollbarSize() + 'px'; + let headerRendered = resources ? + this.renderHeaderResources(range, resources) : + message(messages).allDay; + return (
{ this.renderHeaderCells(range) }
+ { resources &&
+
+ { headerRendered } +
}
this._gutters[0] = ref} @@ -289,6 +311,27 @@ export default class TimeGrid extends Component { ) } + renderHeaderResources(range, resources) { + return range.map((date, i) => { + return resources.map((resource, j) => { + return ( +
+ + {resource.title} + +
+ ) + }) + }) + } + renderHeaderCells(range){ let { dayFormat, culture, components, dayPropGetter, getDrilldownView } = this.props; let HeaderComponent = components.header || Header diff --git a/src/TimeSlot.js b/src/TimeSlot.js index 34caf8500..121affc3d 100644 --- a/src/TimeSlot.js +++ b/src/TimeSlot.js @@ -13,6 +13,7 @@ export default class TimeSlot extends Component { content: PropTypes.string, culture: PropTypes.string, slotPropGetter: PropTypes.func, + resource: PropTypes.string } static defaultProps = { @@ -22,12 +23,12 @@ export default class TimeSlot extends Component { } render() { - const { value, slotPropGetter } = this.props; + const { value, slotPropGetter, resource } = this.props; const Wrapper = this.props.dayWrapperComponent; const { className, style } = (slotPropGetter && slotPropGetter(value)) || {}; return ( - +
.rbc-row.rbc-row-resource { + border-bottom: 1px solid @cell-border; + } + .rbc-gutter-cell { flex: none; } diff --git a/stories/Calendar.js b/stories/Calendar.js index e89541d42..22132705e 100644 --- a/stories/Calendar.js +++ b/stories/Calendar.js @@ -1,12 +1,17 @@ import { storiesOf, action } from '@storybook/react'; import moment from 'moment'; import React from 'react'; +import HTML5Backend from 'react-dnd-html5-backend'; +import { DragDropContext } from 'react-dnd'; import Calendar from '../src'; import momentLocalizer from '../src/localizers/moment.js' import '../src/less/styles.less' +import '../src/addons/dragAndDrop/styles.less' import demoEvents from '../examples/events'; import createEvents from './createEvents'; +import resources from './resourceEvents'; +import withDragAndDrop from '../src/addons/dragAndDrop'; // Setup the localizer by providing the moment (or globalize) Object // to the correct localizer. @@ -38,6 +43,25 @@ const events = [{ allDay: true }] +const DragAndDropCalendar = withDragAndDrop(Calendar) + +const DragCalendar = () => { + return ( + { action(event) }} + onSelectEvent={action('event selected')} + onSelectSlot={action('slot selected')} + defaultDate={new Date(2015, 3, 1)} + /> + ) +} + +const DragableCalendar = DragDropContext(HTML5Backend)(DragCalendar) + storiesOf('module.Calendar.week', module) .add('demo', () => { return ( @@ -77,6 +101,13 @@ storiesOf('module.Calendar.week', module)
) }) + .add('resource', () => { + return ( +
+ +
+ ) + }) .add('selectable', () => { return (
diff --git a/stories/resourceEvents.js b/stories/resourceEvents.js new file mode 100644 index 000000000..d99ab5975 --- /dev/null +++ b/stories/resourceEvents.js @@ -0,0 +1,43 @@ +export default { + events: [ { + 'title': 'Rencontre', + 'resourceId': 'a', + 'start': new Date(2015, 3, 2, 5, 30, 0, 0), + 'end': new Date(2015, 3, 2, 10, 30, 0, 0), + }, { + 'title': 'Another Meeting', + 'resourceId': 'b', + 'start': new Date(2015, 3, 1, 2, 30, 0, 0), + 'end': new Date(2015, 3, 1, 4, 30, 0, 0), + }, + { + 'title': 'A', + 'resourceId': 'a', + 'start': new Date(2015, 3, 4, 5, 30, 0, 0), + 'end': new Date(2015, 3, 4, 10, 30, 0, 0), + }, + { + 'title': 'B', + 'resourceId': 'b', + 'start': new Date(2015, 3, 4, 5, 30, 0, 0), + 'end': new Date(2015, 3, 4, 10, 30, 0, 0), + }, + { + 'title': 'C', + 'resourceId': 'c', + 'start': new Date(2015, 3, 4, 5, 30, 0, 0), + 'end': new Date(2015, 3, 4, 10, 30, 0, 0), + } + ], + + list: [{ + id: 'a', + title: 'Room A' + }, { + id: 'b', + title: 'Room B' + }, { + id: 'c', + title: 'Room C' + }] +} \ No newline at end of file