Skip to content

Commit

Permalink
feat: add background events feature (jquense#1851)
Browse files Browse the repository at this point in the history
* feat: Add background events

* Clean up time grid background event

* Update time grid background event name

* Add storybook example

* Fix typo in documentation

* Remove unused props in documentation

* Clean up Background Events feature in preparation for merge

* Remove package-lock.json

* Code clean up

* jquense#1727 Add better background events example and address code review

* Remove changes not related to the background event feature

* Fix <Calendar /> background event story

* Fix background event width calculation

Co-authored-by: rrjoson <rrjoson08@gmail.com>
Co-authored-by: Jeremy Mauzy <jmauzy@alertmd.com>
  • Loading branch information
3 people authored Jan 29, 2021
1 parent 8ffe39d commit e797ab3
Show file tree
Hide file tree
Showing 13 changed files with 202 additions and 25 deletions.
3 changes: 3 additions & 0 deletions examples/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import './prism.scss'
import Card from './Card'
import ExampleControlSlot from './ExampleControlSlot'
import Basic from './demos/basic'
import BackgroundEvents from './demos/backgroundEvents'
import Selectable from './demos/selectable'
import CreateEventWithNoOverlap from './demos/createEventWithNoOverlap'
import Cultures from './demos/cultures'
Expand Down Expand Up @@ -44,6 +45,7 @@ const EXAMPLES = {
timeslots: 'Custom Time Grids',
rendering: 'Customized Component Rendering',
customView: 'Custom Calendar Views',
backgroundEvents: 'Background Events',
resource: 'Resource Scheduling',
dnd: 'Addon: Drag and drop',
dndresource: 'Resource Drag and drop',
Expand Down Expand Up @@ -74,6 +76,7 @@ class Example extends React.Component {
let selected = this.state.selected
let Current = {
basic: Basic,
backgroundEvents: BackgroundEvents,
selectable: Selectable,
cultures: Cultures,
popup: Popup,
Expand Down
8 changes: 8 additions & 0 deletions examples/backgroundEvents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default [
{
id: 0,
title: 'Available for Clients',
start: new Date(2015, 3, 13, 6),
end: new Date(2015, 3, 13, 18),
},
]
24 changes: 24 additions & 0 deletions examples/demos/backgroundEvents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react'
import { Calendar, Views } from 'react-big-calendar'
import events from '../events'
import backgroundEvents from '../backgroundEvents'
import * as dates from '../../src/utils/dates'

let allViews = Object.keys(Views).map(k => Views[k])

let Basic = ({ localizer }) => (
<Calendar
events={events}
defaultView={Views.DAY}
views={allViews}
step={60}
showMultiDayTimes
max={dates.add(dates.endOf(new Date(2015, 17, 1), 'day'), -1, 'hours')}
defaultDate={new Date(2015, 3, 13)}
localizer={localizer}
backgroundEvents={backgroundEvents}
dayLayoutAlgorithm={'no-overlap'}
/>
)

export default Basic
22 changes: 20 additions & 2 deletions examples/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,28 @@ export default [
},
{
id: 11,
title: 'Birthday Party',
start: new Date(2015, 3, 13, 7, 0, 0),
title: 'Planning Meeting with Paige',
start: new Date(2015, 3, 13, 8, 0, 0),
end: new Date(2015, 3, 13, 10, 30, 0),
},
{
id: 11.1,
title: 'Inconvenient Conference Call',
start: new Date(2015, 3, 13, 9, 30, 0),
end: new Date(2015, 3, 13, 12, 0, 0),
},
{
id: 11.2,
title: "Project Kickoff - Lou's Shoes",
start: new Date(2015, 3, 13, 11, 30, 0),
end: new Date(2015, 3, 13, 14, 0, 0),
},
{
id: 11.3,
title: 'Quote Follow-up - Tea by Tina',
start: new Date(2015, 3, 13, 15, 30, 0),
end: new Date(2015, 3, 13, 16, 0, 0),
},
{
id: 12,
title: 'Late Night Event',
Expand Down
31 changes: 31 additions & 0 deletions src/Calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,29 @@ class Calendar extends React.Component {
*/
events: PropTypes.arrayOf(PropTypes.object),

/**
* An array of background event objects to display on the calendar. Background
* Events behave similarly to Events but are not factored into Event overlap logic,
* allowing them to sit behind any Events that may occur during the same period.
* Background Events objects can be any shape, as long as the Calendar knows how to
* retrieve the following details of the event:
*
* - start time
* - end time
*
* Each of these properties can be customized or generated dynamically by
* setting the various "accessor" props. Without any configuration the default
* event should look like:
*
* ```js
* BackgroundEvent {
* start: Date,
* end: Date,
* }
* ```
*/
backgroundEvents: PropTypes.arrayOf(PropTypes.object),

/**
* Accessor for the event title, used to display event information. Should
* resolve to a `renderable` value.
Expand Down Expand Up @@ -783,6 +806,7 @@ class Calendar extends React.Component {

constructor(...args) {
super(...args)

this.state = {
context: this.getContext(this.props),
}
Expand All @@ -801,6 +825,7 @@ class Calendar extends React.Component {
resourceIdAccessor,
resourceTitleAccessor,
eventPropGetter,
backgroundEventPropGetter,
slotPropGetter,
slotGroupPropGetter,
dayPropGetter,
Expand All @@ -820,6 +845,9 @@ class Calendar extends React.Component {
getters: {
eventProp: (...args) =>
(eventPropGetter && eventPropGetter(...args)) || {},
backgroundEventProp: (...args) =>
(backgroundEventPropGetter && backgroundEventPropGetter(...args)) ||
{},
slotProp: (...args) =>
(slotPropGetter && slotPropGetter(...args)) || {},
slotGroupProp: (...args) =>
Expand All @@ -828,6 +856,7 @@ class Calendar extends React.Component {
},
components: defaults(components[view] || {}, omit(components, names), {
eventWrapper: NoopWrapper,
backgroundEventWrapper: NoopWrapper,
eventContainerWrapper: NoopWrapper,
dateCellWrapper: NoopWrapper,
weekWrapper: NoopWrapper,
Expand Down Expand Up @@ -885,6 +914,7 @@ class Calendar extends React.Component {
view,
toolbar,
events,
backgroundEvents = [],
style,
className,
elementProps,
Expand Down Expand Up @@ -934,6 +964,7 @@ class Calendar extends React.Component {
<View
{...props}
events={events}
backgroundEvents={backgroundEvents}
date={current}
getNow={getNow}
length={length}
Expand Down
11 changes: 8 additions & 3 deletions src/DayColumn.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,11 @@ class DayColumn extends React.Component {
slotMetrics={slotMetrics}
>
<div className={clsx('rbc-events-container', rtl && 'rtl')}>
{this.renderEvents()}
{this.renderEvents({
events: this.props.backgroundEvents,
isBackgroundEvent: true,
})}
{this.renderEvents({ events: this.props.events })}
</div>
</EventContainer>

Expand All @@ -174,9 +178,8 @@ class DayColumn extends React.Component {
)
}

renderEvents = () => {
renderEvents = ({ events, isBackgroundEvent }) => {
let {
events,
rtl,
selected,
accessors,
Expand Down Expand Up @@ -233,6 +236,7 @@ class DayColumn extends React.Component {
selected={isSelected(event, selected)}
onClick={e => this._select(event, e)}
onDoubleClick={e => this._doubleClick(event, e)}
isBackgroundEvent={isBackgroundEvent}
onKeyPress={e => this._keyPress(event, e)}
resizable={resizable}
/>
Expand Down Expand Up @@ -382,6 +386,7 @@ class DayColumn extends React.Component {

DayColumn.propTypes = {
events: PropTypes.array.isRequired,
backgroundEvents: PropTypes.array.isRequired,
step: PropTypes.number.isRequired,
date: PropTypes.instanceOf(Date).isRequired,
min: PropTypes.instanceOf(Date).isRequired,
Expand Down
33 changes: 30 additions & 3 deletions src/TimeGrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export default class TimeGrid extends Component {
})
}

renderEvents(range, events, now) {
renderEvents(range, events, backgroundEvents, now) {
let {
min,
max,
Expand All @@ -117,6 +117,7 @@ export default class TimeGrid extends Component {

const resources = this.memoizedResources(this.props.resources, accessors)
const groupedEvents = resources.groupEvents(events)
const groupedBackgroundEvents = resources.groupEvents(backgroundEvents)

return resources.map(([id, resource], i) =>
range.map((date, jj) => {
Expand All @@ -129,6 +130,17 @@ export default class TimeGrid extends Component {
)
)

let daysBackgroundEvents = (
groupedBackgroundEvents.get(id) || []
).filter(event =>
dates.inRange(
date,
accessors.start(event),
accessors.end(event),
'day'
)
)

return (
<DayColumn
{...this.props}
Expand All @@ -141,6 +153,7 @@ export default class TimeGrid extends Component {
key={i + '-' + jj}
date={date}
events={daysEvents}
backgroundEvents={daysBackgroundEvents}
dayLayoutAlgorithm={dayLayoutAlgorithm}
/>
)
Expand All @@ -151,6 +164,7 @@ export default class TimeGrid extends Component {
render() {
let {
events,
backgroundEvents,
range,
width,
rtl,
Expand All @@ -176,7 +190,8 @@ export default class TimeGrid extends Component {
this.slots = range.length

let allDayEvents = [],
rangeEvents = []
rangeEvents = [],
rangeBackgroundEvents = []

events.forEach(event => {
if (inRange(event, start, end, accessors)) {
Expand All @@ -195,6 +210,12 @@ export default class TimeGrid extends Component {
}
})

backgroundEvents.forEach(event => {
if (inRange(event, start, end, accessors)) {
rangeBackgroundEvents.push(event)
}
})

allDayEvents.sort((a, b) => sortEvents(a, b, accessors))

return (
Expand Down Expand Up @@ -246,7 +267,12 @@ export default class TimeGrid extends Component {
className="rbc-time-gutter"
getters={getters}
/>
{this.renderEvents(range, rangeEvents, getNow())}
{this.renderEvents(
range,
rangeEvents,
rangeBackgroundEvents,
getNow()
)}
</div>
</div>
)
Expand Down Expand Up @@ -311,6 +337,7 @@ export default class TimeGrid extends Component {

TimeGrid.propTypes = {
events: PropTypes.array.isRequired,
backgroundEvents: PropTypes.array.isRequired,
resources: PropTypes.array,

step: PropTypes.number,
Expand Down
41 changes: 29 additions & 12 deletions src/TimeGridEvent.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ function TimeGridEvent(props) {
getters,
onClick,
onDoubleClick,
isBackgroundEvent,
onKeyPress,
components: { event: Event, eventWrapper: EventWrapper },
} = props
Expand All @@ -40,29 +41,45 @@ function TimeGridEvent(props) {
</div>,
]

const eventStyle = isBackgroundEvent
? {
...userProps.style,
top: stringifyPercent(top),
height: stringifyPercent(height),
// Adding 10px to take events container right margin into account
width: `calc(${width} + 10px)`,
[rtl ? 'right' : 'left']: stringifyPercent(Math.max(0, xOffset)),
}
: {
...userProps.style,
top: stringifyPercent(top),
width: stringifyPercent(width),
height: stringifyPercent(height),
[rtl ? 'right' : 'left']: stringifyPercent(xOffset),
}

return (
<EventWrapper type="time" {...props}>
<div
onClick={onClick}
onDoubleClick={onDoubleClick}
style={eventStyle}
onKeyPress={onKeyPress}
style={{
...userProps.style,
top: stringifyPercent(top),
[rtl ? 'right' : 'left']: stringifyPercent(xOffset),
width: stringifyPercent(width),
height: stringifyPercent(height),
}}
title={
tooltip
? (typeof label === 'string' ? label + ': ' : '') + tooltip
: undefined
}
className={clsx('rbc-event', className, userProps.className, {
'rbc-selected': selected,
'rbc-event-continues-earlier': continuesEarlier,
'rbc-event-continues-later': continuesLater,
})}
className={clsx(
isBackgroundEvent ? 'rbc-background-event' : 'rbc-event',
className,
userProps.className,
{
'rbc-selected': selected,
'rbc-event-continues-earlier': continuesEarlier,
'rbc-event-continues-later': continuesLater,
}
)}
>
{inner}
</div>
Expand Down
Loading

0 comments on commit e797ab3

Please sign in to comment.