Skip to content

Commit

Permalink
Add resource (#423)
Browse files Browse the repository at this point in the history
  • Loading branch information
TeaBough authored and jquense committed Jan 3, 2018
1 parent 2396975 commit 0c0b17c
Show file tree
Hide file tree
Showing 10 changed files with 169 additions and 34 deletions.
6 changes: 6 additions & 0 deletions src/Calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -575,6 +580,7 @@ class Calendar extends React.Component {
allDayAccessor: 'allDay',
startAccessor: 'start',
endAccessor: 'end',
resourceIdAccessor: 'resourceId',

longPressThreshold: 250,
};
Expand Down
2 changes: 2 additions & 0 deletions src/DayColumn.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class DayColumn extends React.Component {
dayWrapperComponent: elementType,
eventComponent: elementType,
eventWrapperComponent: elementType.isRequired,
resource: PropTypes.string
}

static defaultProps = {
Expand Down Expand Up @@ -367,6 +368,7 @@ class DayColumn extends React.Component {
slots,
start: startDate,
end: endDate,
resourceId: this.props.resource,
action,
})
}
Expand Down
8 changes: 5 additions & 3 deletions src/TimeColumn.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 (
Expand All @@ -46,6 +47,7 @@ export default class TimeColumn extends Component {
dayPropGetter={dayPropGetter}
culture={culture}
timeslots={timeslots}
resource={resource}
showLabels={showLabels}
timeGutterFormat={timeGutterFormat}
dayWrapperComponent={dayWrapperComponent}
Expand All @@ -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 = []
Expand All @@ -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
}
Expand Down
93 changes: 68 additions & 25 deletions src/TimeGrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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']),
Expand Down Expand Up @@ -146,6 +148,7 @@ export default class TimeGrid extends Component {
, width
, startAccessor
, endAccessor
, resources
, allDayAccessor
, showMultiDayTimes} = this.props;

Expand Down Expand Up @@ -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 (
<div className='rbc-time-view'>

{this.renderHeader(range, allDayEvents, width)}
{this.renderHeader(range, allDayEvents, width, resources)}

<div ref='content' className='rbc-time-content'>
<div ref='timeIndicator' className='rbc-current-time-indicator' />
Expand All @@ -193,50 +198,60 @@ export default class TimeGrid extends Component {
ref={gutterRef}
className='rbc-time-gutter'
/>

{this.renderEvents(range, rangeEvents, this.props.now)}
{eventsRendered}

</div>
</div>
);
}

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 (
<DayColumn
{...this.props }
min={dates.merge(date, min)}
max={dates.merge(date, max)}
eventComponent={components.event}
eventWrapperComponent={components.eventWrapper}
dayWrapperComponent={components.dayWrapper}
className={cn({ 'rbc-now': dates.eq(date, today, 'day') })}
style={segStyle(1, this.slots)}
key={idx}
date={date}
events={daysEvents}
/>
)
return resources.map((resource, id) => {

let eventsToDisplay = daysEvents.filter(
event => get(event, resourceIdAccessor) === resource.id
)

return (
<DayColumn
{...this.props }
min={dates.merge(date, min)}
max={dates.merge(date, max)}
resource={resource.id}
eventComponent={components.event}
eventWrapperComponent={components.eventWrapper}
dayWrapperComponent={components.dayWrapper}
className={cn({ 'rbc-now': dates.eq(date, today, 'day') })}
style={segStyle(1, this.slots)}
key={idx + '-' + id}
date={date}
events={eventsToDisplay}
/>
)
})
})
}

renderHeader(range, events, width) {
renderHeader(range, events, width, resources) {
let { messages, rtl, selectable, components, now } = this.props;
let { isOverflowing } = this.state || {};

let style = {};
if (isOverflowing)
style[rtl ? 'marginLeft' : 'marginRight'] = scrollbarSize() + 'px';

let headerRendered = resources ?
this.renderHeaderResources(range, resources) :
message(messages).allDay;

return (
<div
ref='headerCell'
Expand All @@ -253,6 +268,13 @@ export default class TimeGrid extends Component {
/>
{ this.renderHeaderCells(range) }
</div>
{ resources && <div className='rbc-row rbc-row-resource'>
<div
className='rbc-label rbc-header-gutter'
style={{ width }}
/>
{ headerRendered }
</div> }
<div className='rbc-row'>
<div
ref={ref => this._gutters[0] = ref}
Expand Down Expand Up @@ -289,6 +311,27 @@ export default class TimeGrid extends Component {
)
}

renderHeaderResources(range, resources) {
return range.map((date, i) => {
return resources.map((resource, j) => {
return (
<div
key={i+ '-' + j}
className={cn(
'rbc-header',
dates.isToday(date) && 'rbc-today',
)}
style={segStyle(1, this.slots)}
>
<span>
{resource.title}
</span>
</div>
)
})
})
}

renderHeaderCells(range){
let { dayFormat, culture, components, dayPropGetter, getDrilldownView } = this.props;
let HeaderComponent = components.header || Header
Expand Down
5 changes: 3 additions & 2 deletions src/TimeSlot.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export default class TimeSlot extends Component {
content: PropTypes.string,
culture: PropTypes.string,
slotPropGetter: PropTypes.func,
resource: PropTypes.string
}

static defaultProps = {
Expand All @@ -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 (
<Wrapper value={value}>
<Wrapper value={value} resource={resource}>
<div
style={style}
className={cn(
Expand Down
6 changes: 4 additions & 2 deletions src/TimeSlotGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export default class TimeSlotGroup extends Component {
isNow: PropTypes.bool,
slotPropGetter: PropTypes.func,
timeGutterFormat: dateFormat,
culture: PropTypes.string
culture: PropTypes.string,
resource: PropTypes.string
}
static defaultProps = {
timeslots: 2,
Expand All @@ -25,7 +26,7 @@ export default class TimeSlotGroup extends Component {
}

renderSlice(slotNumber, content, value) {
const { dayWrapperComponent, showLabels, isNow, culture, slotPropGetter } = this.props;
const { dayWrapperComponent, showLabels, isNow, culture, resource, slotPropGetter } = this.props;
return (
<TimeSlot
key={slotNumber}
Expand All @@ -35,6 +36,7 @@ export default class TimeSlotGroup extends Component {
content={content}
culture={culture}
isNow={isNow}
resource={resource}
value={value}
/>
)
Expand Down
5 changes: 3 additions & 2 deletions src/addons/dragAndDrop/backgroundWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,15 @@ function createWrapper(type) {
const dropTarget = {
drop(_, monitor, { props, context }) {
const event = monitor.getItem();
const { value } = props
const { value, resource } = props
const { onEventDrop, startAccessor, endAccessor } = context
const start = get(event, startAccessor);
const end = get(event, endAccessor);

onEventDrop({
event,
...getEventTimes(start, end, value, type)
...getEventTimes(start, end, value, type),
...resource && {resource}
})
}
};
Expand Down
4 changes: 4 additions & 0 deletions src/less/time-grid.less
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@
border-bottom: 1px solid @cell-border;
}

> .rbc-row.rbc-row-resource {
border-bottom: 1px solid @cell-border;
}

.rbc-gutter-cell {
flex: none;
}
Expand Down
31 changes: 31 additions & 0 deletions stories/Calendar.js
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -38,6 +43,25 @@ const events = [{
allDay: true
}]

const DragAndDropCalendar = withDragAndDrop(Calendar)

const DragCalendar = () => {
return (
<DragAndDropCalendar
popup
selectable
events={resources.events}
resources={resources.list}
onEventDrop={(event) => { 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 (
Expand Down Expand Up @@ -77,6 +101,13 @@ storiesOf('module.Calendar.week', module)
</div>
)
})
.add('resource', () => {
return (
<div style={{height: 500}}>
<DragableCalendar />
</div>
)
})
.add('selectable', () => {
return (
<div style={{height: 600}}>
Expand Down
Loading

0 comments on commit 0c0b17c

Please sign in to comment.