0

I have a react-big-calendar with drag and drop, I want when I move an event to another position, a snackbar appeared which having the undo action like that :

enter image description here

I want when I click on the undo action, the event set the initial state (the initial position)

My code is :

 moveEvent = ({event, start, end, isAllDay: droppedOnAllDaySlot}) => {
      const { events } = this.state;
      const idx = events.indexOf(event);
      let allDay = event.allDay ;
      if(!event.allDay && droppedOnAllDaySlot)
      {allDay = true;}
      else if (event.allDay && !droppedOnAllDaySlot)
      { allDay = false;}
      const updatedEvent = { ...event, start, end, allDay }
      const nextEvents = [...events]
      nextEvents.splice(idx, 1, updatedEvent)
      this.setState({
        events : nextEvents,
        dragAndDrop : true,
        open : true
      })
  }
  handleClose = () => {
      this.setState({ open: false });
  };
  handleClick = () => {
      this.setState({ open: true });
  };
  handleUndo = () => {
      this.setState({
        dragAndDrop : !this.state.dragAndDrop,
        events: this.state.events
      })
 }
  render() {
    return (
       <div>
          <DragAndDropCalendar
            selectable
            localizer={localizer}
            events={this.state.events} 
            views={['month','week','day']}
            //defaultDate={new Date(2019, 2, 19)}
            defaultView="week"
            culture = 'fr'
            timeslots={1}
            step={15}
            style={{ height: "100vh" }}
            onEventDrop={this.moveEvent}
            min={new Date(2017, 10, 0, 7, 0, 0)}
            max={new Date(2017, 10, 0, 21, 0, 0)} 
            resizable  
            onEventResize={this.resizeEvent}
            onSelectSlot={this.newEvent}
            onSelectEvent={this.handleClickOpen}
          />
        <Snackbar
          anchorOrigin={{
            vertical: 'bottom',
            horizontal: 'center',
          }}
          open={this.state.open}
          autoHideDuration={6000}
          onClose={this.handleClose}
          ContentProps={{
            'aria-describedby': 'message-id',
          }}
          message={<span id="message-id">Evénement enregistré</span>}
          action={[
              <Button key="undo" color="secondary" size="small" onClick={this.handleUndo}>
                Annuler
              </Button>,
              <IconButton
                key="close"
                aria-label="Close"
                color="inherit"
                onClick={this.handleClose}
              >
                <CloseIcon />
              </IconButton>,
            ]}
        />

My full code : https://codesandbox.io/s/mq42x1j90x

When I run my code and I click on the undo action, it doesn't work, and my event doesn't set the initial position.

How can I fix that ?

Ichrak Mansour
  • 1,850
  • 11
  • 34
  • 61

1 Answers1

2

I suggest to store previous events in separate field inside this.state(for instance, this.state.previousEvents), and at undo() action set current events to previous events. Also, when user closes snackbar or do some other action which changes events and can't be reverted, don't forget to update previousEvents as current events value.

Also instead of using this.state in this.setState

this.setState({
        dragAndDrop : !this.state.dragAndDrop,
        events: this.state.events
      })

you should use previousState:

this.setState((prevState) => ({
        dragAndDrop : !prevState.dragAndDrop,
        events: prevState.events
      }))

So the full version is

class Calendar extends Component {
  state  = {
    events: [],
    prevEvents: []
  };

  handleUndo = () => {
    this.setState((prevState) => ({
      events: prevState.prevEvents
    }))
  }

  handleCloseSnackbar = () => {
    this.setState((prevState) => ({
      prevEvents: prevState.events
    }))
  }

  ...
}
IfSoGirl
  • 161
  • 1
  • 7
  • I get `Uncaught TypeError: Cannot read property 'setState' of undefined` into `handleUndo()` – Ichrak Mansour Mar 29 '19 at 10:54
  • @CodeLover that’s weird, but that was just a quick example and I could mistyped something. We can discuss it in chat or you can paste your code to sandbox – IfSoGirl Mar 29 '19 at 10:57
  • 1
    I edited your sandbox and it works, please check it https://codesandbox.io/s/kkm0okkr4o. – IfSoGirl Mar 29 '19 at 11:56
  • and what about when the events is getted from the database, and I initialise it on my state :`events :[]` – Ichrak Mansour Mar 29 '19 at 13:18
  • You can create a HOC(High-order-component), which will connect to store and get events from it. And pass events as prop to your calendar. Then, in calendar you can write constructor and initialize your state based on passed props. Here is the link to general code (it doesn't work, its just the idea of what you can do) https://pastebin.com/KMNVXHCJ – IfSoGirl Mar 29 '19 at 13:25
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/190915/discussion-between-codelover-and-ifsogirl). – Ichrak Mansour Mar 29 '19 at 13:30