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

2405 (Copy of 1649) multiple resources #2405

Merged
merged 16 commits into from
Jun 2, 2023
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ class Calendar extends React.Component {
resources: PropTypes.arrayOf(PropTypes.object),

/**
* Provides a unique identifier for each resource in the `resources` array
* Provides a unique identifier, or an array of unique identifiers, for each resource in the `resources` array
*
* ```js
* string | (resource: Object) => any
Expand Down
5 changes: 4 additions & 1 deletion src/DayColumn.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,11 @@ class DayColumn extends React.Component {
continuesPrior={continuesPrior}
continuesAfter={continuesAfter}
accessors={accessors}
resource={this.props.resource}
selected={isSelected(event, selected)}
onClick={(e) => this._select(event, e)}
onClick={(e) =>
this._select({ ...event, sourceResource: this.props.resource }, e)
}
onDoubleClick={(e) => this._doubleClick(event, e)}
isBackgroundEvent={isBackgroundEvent}
onKeyPress={(e) => this._keyPress(event, e)}
Expand Down
6 changes: 5 additions & 1 deletion src/addons/dragAndDrop/EventWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class EventWrapper extends React.Component {
continuesAfter: PropTypes.bool,
isDragging: PropTypes.bool,
isResizing: PropTypes.bool,
resource: PropTypes.number,
resizable: PropTypes.bool,
}

Expand Down Expand Up @@ -45,8 +46,11 @@ class EventWrapper extends React.Component {
const isResizeHandle = e.target
.getAttribute('class')
?.includes('rbc-addons-dnd-resize')
if (!isResizeHandle)
if (!isResizeHandle) {
let extendedEvent = this.props.event
extendedEvent.sourceResource = this.props.resource
this.context.draggable.onBeginAction(this.props.event, 'move')
}
}

renderAnchor(direction) {
Expand Down
14 changes: 11 additions & 3 deletions src/utils/Resources.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,17 @@ export default function Resources(resources, accessors) {

events.forEach((event) => {
const id = accessors.resource(event) || NONE
let resourceEvents = eventsByResource.get(id) || []
resourceEvents.push(event)
eventsByResource.set(id, resourceEvents)
if (Array.isArray(id)) {
id.forEach((item) => {
let resourceEvents = eventsByResource.get(item) || []
resourceEvents.push(event)
eventsByResource.set(item, resourceEvents)
})
} else {
let resourceEvents = eventsByResource.get(id) || []
resourceEvents.push(event)
eventsByResource.set(id, resourceEvents)
}
})
return eventsByResource
},
Expand Down
26 changes: 25 additions & 1 deletion stories/DragAndDrop.stories.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import React from 'react'
import { action } from '@storybook/addon-actions'

import { events, Calendar, Views, DragAndDropCalendar } from './helpers'
import {
events,
resourceEvents,
resources,
Calendar,
Views,
DragAndDropCalendar,
} from './helpers'
import customComponents from './resources/customComponents'

export default {
Expand Down Expand Up @@ -106,3 +113,20 @@ WithCustomEventWrapper.args = {
eventWrapper: customComponents.eventWrapper,
},
}

export const DraggableMultipleResources = Template.bind({})
DraggableMultipleResources.storyName =
'draggable and resizable with multiple resource lanes'
DraggableMultipleResources.args = {
defaultDate: new Date(),
defaultView: Views.DAY,
views: [Views.DAY, Views.WEEK, Views.AGENDA],
events: resourceEvents,
resources: resources,
resourceAccessor: 'resourceId',
resourceIdAccessor: 'id',
resourceTitleAccessor: 'name',
resizable: true,
onEventDrop: action('event dropped'),
onEventResize: action('event resized'),
}
29 changes: 27 additions & 2 deletions stories/demos/exampleCode/dndresource.js
basstager marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const events = [
title: 'Board meeting',
start: new Date(2018, 0, 29, 9, 0, 0),
end: new Date(2018, 0, 29, 13, 0, 0),
resourceId: 1,
resourceId: [1, 2],
},
{
id: 1,
Expand Down Expand Up @@ -77,6 +77,9 @@ const resourceMap = [

export default function DnDResource({ localizer }) {
const [myEvents, setMyEvents] = useState(events)
const [copyEvent, setCopyEvent] = useState(true)

const toggleCopyEvent = useCallback(() => setCopyEvent((val) => !val), [])

const moveEvent = useCallback(
({
Expand All @@ -90,14 +93,26 @@ export default function DnDResource({ localizer }) {
if (!allDay && droppedOnAllDaySlot) {
event.allDay = true
}
if (Array.isArray(event.resourceId)) {
if (copyEvent) {
resourceId = [...new Set([...event.resourceId, resourceId])]
} else {
const filtered = event.resourceId.filter(
(ev) => ev !== event.sourceResource
)
resourceId = [...new Set([...filtered, resourceId])]
}
} else if (copyEvent) {
resourceId = [...new Set([event.resourceId, resourceId])]
}

setMyEvents((prev) => {
const existing = prev.find((ev) => ev.id === event.id) ?? {}
const filtered = prev.filter((ev) => ev.id !== event.id)
return [...filtered, { ...existing, start, end, resourceId, allDay }]
})
},
[setMyEvents]
[setMyEvents, copyEvent]
)

const resizeEvent = useCallback(
Expand Down Expand Up @@ -125,6 +140,16 @@ export default function DnDResource({ localizer }) {
<strong>
Drag and Drop an "event" from one resource slot to another.
</strong>
<div style={{ margin: '10px 0 20px 0' }}>
<label>
<input
type="checkbox"
checked={copyEvent}
onChange={toggleCopyEvent}
/>
Keep copy of dragged "source" event in its original resource slot.
</label>
</div>
</DemoLink>
<div className="height600">
<DragAndDropCalendar
Expand Down
8 changes: 7 additions & 1 deletion stories/demos/exampleCode/resource.js
basstager marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { Fragment, useMemo } from 'react'
import PropTypes from 'prop-types'
import { Calendar, Views, DateLocalizer } from 'react-big-calendar'
import DemoLink from '../../DemoLink.component'
import LinkTo from '@storybook/addon-links/react'

const events = [
{
Expand All @@ -24,7 +25,7 @@ const events = [
title: 'Team lead meeting',
start: new Date(2018, 0, 29, 8, 30, 0),
end: new Date(2018, 0, 29, 12, 30, 0),
resourceId: 3,
resourceId: [2, 3],
},
{
id: 11,
Expand Down Expand Up @@ -54,6 +55,11 @@ export default function Resource({ localizer }) {
return (
<Fragment>
<DemoLink fileName="resource" />
<strong>
The calendar below uses the <LinkTo kind="props" story="resource-id-accessor">resourceIdAccessor</LinkTo>, <LinkTo kind="props" story="resource-title-accessor">resourceTitleAccessor</LinkTo> and <LinkTo kind="props" story="resources">resources</LinkTo> props to show events scheduled for different resources.
<br/>
Events can be mapped to a single resource, or multiple resources.
</strong>
<div className="height600">
<Calendar
defaultDate={defaultDate}
Expand Down
39 changes: 39 additions & 0 deletions stories/helpers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,42 @@ export const backgroundEvents = [
allDay: false,
},
]

export const resourceEvents = [
{
title: 'event 1',
start: moment().startOf('day').add(1, 'hours').toDate(),
end: moment().startOf('day').add(2, 'hours').toDate(),
allDay: false,
resourceId: 1,
},
{
title: 'event 2',
start: moment().startOf('day').add(3, 'hours').toDate(),
end: moment().startOf('day').add(4, 'hours').toDate(),
allDay: false,
resourceId: [1, 2],
},
{
title: 'event 3',
start: moment().startOf('day').add(1, 'hours').toDate(),
end: moment().startOf('day').add(3, 'hours').toDate(),
allDay: false,
resourceId: 3,
},
]

export const resources = [
{
id: 1,
name: 'Resource One',
},
{
id: 2,
name: 'Resource Two',
},
{
id: 3,
name: 'Resource Three',
},
]
2 changes: 1 addition & 1 deletion stories/props/API.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ Resource {
Example
</LinkTo>

Provides a unique identifier for each resource in the <LinkTo kind="props" story="resources">resources</LinkTo> array
Provides a unique identifier, or an array of unique identifiers, for each resource in the <LinkTo kind="props" story="resources">resources</LinkTo> array

### resourceTitleAccessor

Expand Down
2 changes: 1 addition & 1 deletion stories/props/resourceIdAccessor.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ import LinkTo from '@storybook/addon-links/react'

- type: `string | function (resource: Object) => string | number // must be unique`

Provides a unique identifier for each resource in the <LinkTo kind="props" story="resources">resources</LinkTo> array
Provides a unique identifier, or an array of unique identifiers, for each resource in the <LinkTo kind="props" story="resources">resources</LinkTo> array

<Story id="props--resource-id-accessor" />