jquense / react-big-calendar

gcal/outlook like calendar component
http://jquense.github.io/react-big-calendar/examples/index.html
MIT License
7.89k stars 2.24k forks source link

Drop external events onto calendar? #1090

Closed MinhNguyen41092 closed 5 years ago

MinhNguyen41092 commented 6 years ago

Hi everyone. I've developed an app that requires dragging and dropping events from an external list onto the calendar. I've made it work in the old version using React-DnD. But in the new version it was ditched for another technology that I still can't find out what it is. So I'd like to ask is it possible to drop an outside event onto the calendar by using the new DnD approach? If yes could you give me a hint? Thank you very much.

jquense commented 5 years ago

ditched for another technology that I still can't find out what it is.

no other library we do the drag and drop "in house", all the code for it is in the dnd addon. At the moment there is no first class API for dropping events from an external element, but i'd be open to adding one if anyone has a good idea for it

szagoret commented 5 years ago

Hi everyone. I've developed an app that requires dragging and dropping events from an external list onto the calendar. I've made it work in the old version using React-DnD. But in the new version it was ditched for another technology that I still can't find out what it is. So I'd like to ask is it possible to drop an outside event onto the calendar by using the new DnD approach? If yes could you give me a hint? Thank you very much.

For which version (old one) did you implemented?

MinhNguyen41092 commented 5 years ago

@zagoret v0.19.1

szagoret commented 5 years ago

@MinhNguyen41092 Thanks for your response. I implemented also for version 0.19.0 and it works fine. Any update about the last version, still doesn't work external dnd?

MinhNguyen41092 commented 5 years ago

@zagoret we found a way to work around it. We wrap the calender with react-dnd drop target and try to calculate the drop position externally. It's not pretty but atleast it works

jquense commented 5 years ago

Btw happy to add an API for this. It should be as simple as handling onDrop events and passing back the, already caclulated pointer to slot position

RoslerWS commented 5 years ago

I've tried to accomplish this with a method similar to @MinhNguyen41092. except by passing in a custom dateCellWrapper component as a component prop to the calendar that is wrapped with react-dnd DropTarget. Unfortunately, it doesn't work for date rows containing events, because the date cell wrapper wraps the 'rbc-day-bg' cells in the 'rbc-row-bg' row, whereas the 'rbc-row-content' row is what contains the events..... hence the drop target isn't detected because there is something on top of it. If I bring the background cell to the forefront, then the built-in react-big-calendar drag and drop no longer works for these cells, because it is underneath....

...And I can't wrap the actual 'rbc-event-content' cells, because they only exist if there are events on that date cell (and such a wrapper doesn't exist anyway).

kamry-bowman commented 5 years ago

Any hints on how to go about adding this? It's a functionality we need, but I'm not super familiar with how dnd is being handled in this library since it's a custom approach.

francescocerri commented 5 years ago

@zagoret we found a way to work around it. We wrap the calender with react-dnd drop target and try to calculate the drop position externally. It's not pretty but atleast it works

Can you add an example about this?

kamry-bowman commented 5 years ago

@francescocerri

This is the route we ended up taking, even though the implementation is a bit "hacky".

Here is the DnDCal wrapped as a react-dnd drop-target:

const DnDCal = withDragAndDrop(Calendar)

function dropCollect(connect, monitor) {
  return {
    connectDropTarget: connect.dropTarget()
  }
}

const click = (x, y) => {
  const eventConfig = {
    bubbles: true,
    button: 0,
    clientX: x,
    clientY: y,
    pageX: window.scrollLeft + x,
    pageY: window.scrollRight + y,
    view: window,
    which: 1,
    x: x,
    y: y
  }

  let mouseDown = new window.MouseEvent('mousedown', eventConfig)
  let mouseUp = new window.MouseEvent('mouseup', eventConfig)
  const elem = document.elementFromPoint(x, y)
  elem.dispatchEvent(mouseDown)
  elem.dispatchEvent(mouseUp)
}

const dropSpec = {
  drop(props, monitor, component) {
    const { x, y } = monitor.getClientOffset()
    // dispatch a DOM click event at the place of dropping, so react-big-cal
    // library can take over event creation
    click(x, y)
  }
}

class DropCal extends Component {
  state = { hoursModal: false }

  toggleModal = e => {
    this.setState(state => ({ hoursModal: !state.hoursModal }))
  }

  render() {

    return connectDropTarget(
      <div>
        <DnDCal
         {...this.prop}
        />
      </div>
    )
  }
}

export default DropTarget('SHIFT', dropSpec, dropCollect)(DropCal)

And then we wired up the dragStart for react-dnd to put an outside resource on state, and passed onSelectSlot callback to the the calendar. The onSelectSlot callback checks to see if anything was being dragged on state, and if it was, it uses that dragged resource's info to create the new event.

 createEvent = ({ start, end }) => {
    const { draggedEmployee } = this.state
    if (draggedEmployee) {
        // fires a redux event
        this.props.createEvent(
            { employee: draggedEmployee, start },
         )
        this.setState({ draggedEmployee: null })
      }
    }
  }

There's more unrelated stuff going on than that in the component, but here's a link to the repo. https://github.com/Lambda-School-Labs/labs9-employee-scheduler/tree/master/client/src/components/Scheduler

rchancey commented 5 years ago

hey nice.. does this still work well? A lot of us need this and this seems the most current attempt?

kamry-bowman commented 5 years ago

It still works but it's definitely a hack

ghost commented 5 years ago

Unfortunately, it doesn't work when dropping on an existing event. All I want is my unplanned events to be dropped from outside the calendar :( Should I downgrade to v19? Anybody got any ideas?

kamry-bowman commented 5 years ago

Yes, that's correct, although it does work if they drop in the small space to the right of the event in the same column.

Downgrading was our first approach, but the resizing behavior prior to the update, while functional, was not attractive. So it's a tradeoff to get better behavior from external dropping, but IMO inferior UX for existing events.

kamry-bowman commented 5 years ago

I do think it would be great to figure out how to do this:

It should be as simple as handling onDrop events and passing back the, already calculated pointer to slot position

I think my ability to understand the codebase and drag and drop primitives in general isn't there to implement it, but I wonder if it makes sense to anyone else?

ghost commented 5 years ago

Thanks for your reply @kamry-bowman I am giving full calendar a try, since it's now made to work without jquery as well, so perhaps still usable in react. If that doesn't work, back to this one :) I'll try to find another way

kamry-bowman commented 5 years ago

@kilroy05 did that end up working out well?

ghost commented 5 years ago

hi @kamry-bowman I managed to convert pretty much all the functionality I had with react-big-calendar to fullcalendar (the V4 beta). It already supports drag and drop between calendar and external components, so I need to try that out (probably tomorrow) I had to learn a new API and new docs to read ... but you gotta do what you gotta do :)

Dragomir-Ivanov commented 5 years ago

@kilroy05 Please keep us posted. I also need dropping external events.

ghost commented 5 years ago

@Dragomir-Ivanov It's so easy to drop between calendars, I was a bit shocked :) All you need is to include a plugin and set droppable: true on instantiation About to try dropping from external source (ie: not calendar)

ghost commented 5 years ago

Update to those interested: dropping from outside components works nicely with full calendar v4 beta. So I am now going to stop using react-big-calendar, as it lacks some features I need. It's a good piece of work and greatly appreciated :)

jquense commented 5 years ago

Please use the best tool for the job :) if that's full calendar, go for it. If anyone tho is gonna switch solely because of this issue it might be worth sending a PR to add the API I mentioned above since it'll likely be less work overall and likely small change, just one I don't have time to make.

ghost commented 5 years ago

True. I would've loved to help but my react skills are not there yet and this is a small project I'm doing in my free time. So while it's that, I use what ever works even if not pretty :)

Dragomir-Ivanov commented 5 years ago

@jquense I might be able to help with that, just not right now. I will need this feature in next coming months, so if nobody steps in until then, I will do it.

kohenchia commented 5 years ago

So is the new API ready yet?

kamry-bowman commented 5 years ago

I'm trying to implement an API on this, hope to have an idea of what it looks like in the next few days

kamry-bowman commented 5 years ago

Okay, I have a version of this implemented. Here's a gif of it in action.

I added an example to the examples folder of how it would work in the PR. The gist is that we expose a prop on DndCalendar called onDropFromOutside. The callback will receive the following argument: { start, end, isAllDay }, representing the start and end of the event based on slot size where it was dropped.

It is up to the end user to handle actual event creation. If you want to create an event that corresponds to an outside resource, you will need to put it on state and reference that in your onDropFromOutside handler. That means having an onDragStart prop on the outside dragsource. The linked example code shows what this could look like.

Feedback is welcome! If this works for people I can update the docs as well and make a PR.

kamry-bowman commented 5 years ago

Went ahead and opened a PR for this here #1290.

milkysingh commented 5 years ago

@kamry-bowman Great job. @jquense When can we expect a new npm release with outside drag and drop added?

victor-guillen-housecall commented 5 years ago

Went ahead and opened a PR for this here #1290.

Not all heroes wear capes 🦸🏼‍♂️

Thank you @kamry-bowman

fridaystreet commented 5 years ago

Hi,

Thanks for the extra work here in making the external draggables, it's very useful. How hard is it to make the preview/clone appear when dragging across the time based slots in day and week views? I've had a quick look and I can see the timeevent is using the event wrapper, just wondering if it's something easy?

Even if it could just flash up the timeslots overlay so there is some sort of feedback to the user that they can drop it in a timeslot and it will be in the right timeslot?

Happy to help if someone could point me in the direction of how this might be achieved?

Cheers Paul

tungcntt619 commented 5 years ago

dragFromOutsideItem not work when i use calendar in 'week' mode. please help me :(( @kamry-bowman

AymericG commented 4 years ago

dragFromOutsideItem not work when i use calendar in 'week' mode. please help me :(( @kamry-bowman

For me, it works in all day area, but not in the time slots.

Nahov91 commented 3 years ago

Hi,

Thanks for the extra work here in making the external draggables, it's very useful. How hard is it to make the preview/clone appear when dragging across the time based slots in day and week views? I've had a quick look and I can see the timeevent is using the event wrapper, just wondering if it's something easy?

Even if it could just flash up the timeslots overlay so there is some sort of feedback to the user that they can drop it in a timeslot and it will be in the right timeslot?

Happy to help if someone could point me in the direction of how this might be achieved?

Cheers Paul

Hi, Is there any progress on this? Is there a way that if I drag an event from the outside I could see a preview of it in the dropzone on the place where it would land? Even just a highlight around the slot would do it for me.

Thanks in advance.

jvidlund commented 2 years ago

Hi, really appreciate this feature! I would find it very useful to get the resourceId parameter in the onDropFromOutside arguments as well for when dropping in e.g week or day with resources. If that is something you find useful and could implement it would be much appreciated. Otherwise, does anyone have a workaround solution for this?

BR, Johan

MALIK-0 commented 1 year ago

Hey @jvidlund I have the same request. Does anyone know if it is possible to get the resourceId inside of the onDropFromOutside event handler?

EDIT solved it by looking up the arguments of the onDropFromOutside event handler, it receives on an "resource" property which contains the id.