Issue Removing Temporary Event on Cancel with Drag-and-Drop in Mobiscroll Scheduler

Hello,

I am currently developing a scheduling component in a React/TypeScript project using Mobiscroll Scheduler, and I’ve encountered a problem with handling temporary events during drag-and-drop actions. Here is the issue and relevant code.

Problem Description

In my setup, users can drag an external event (defined as draggableEvent) onto the Mobiscroll Scheduler. When the drag is in progress, a temporary event appears, which should become permanent only if the user confirms it by submitting a form with details. However, if the user cancels this form without saving, the temporary event still remains visible in the scheduler. This behavior leads to confusion, as the canceled event continues to occupy a time slot on the scheduler.

Goal

I need the temporary event to disappear if the user cancels the creation. My attempt to use Mobiscroll’s onEventCreateFailed and onClose callbacks to remove the event hasn’t been successful.

Key Code Sections

  1. Event Creation on Drag: When an event is dragged onto the scheduler, handleEventCreate initializes the temporary event with a 1.5-hour duration. Here’s the relevant code:

const handleEventCreate = useCallback((args: MbscEventCreateEvent) => {
const event = args.event;

// Récupération de l'heure de début du drop
const startDate = event.start;

// Calcul de l'heure de fin : 1h30 après le début
const endDate = addMinutes(startDate as Date, 90); // 90 minutes = 1h30

// Mise à jour des dates de l'événement
event.start = startDate;
event.end = endDate;
if (event.start && event.end) {
    setDateStart(event.start);
    setDateEnd(event.end);
}
setPopupEventTypeCode(event.id_code);
setPopupEventTypeDesc(event.description);
setPopupCollabId(event.resource?.toString() || "");
setDate([startDate!, endDate!]);
// Ouvrir la popup
setEdit(false);
setTempEvent(event);
setAnchor(args.domEvent.target);
setOpen(true);

}, );

useEffect(() => {
console.log(‘tempEvent:’, tempEvent);
}, [tempEvent]);

const handleEventCreated = useCallback(
(args: MbscEventCreatedEvent, inst: EventcalendarBase) => {
// Récupérer les informations de l’événement créé
console.log(“Event created:”, args.event);
// Mettre à jour initialValues.popupEventType avec la description de l’événement
setInitialValues((prevValues) => ({
…prevValues,
popupEventType: args.event.description,
}));
setToastText(args.event.title + " Ajouter");
setToastOpen(true);
setMyEvents((prevEvents) => […prevEvents, args.event]);
setTempEvent(undefined); // Nettoie l’événement temporaire
setForceReload(true);
},

);

const handleFailed = useCallback((event: MbscCalendarEvent) => {

setToastText('erreur lors de la création de l\'événement');
setForceReload(true);
setToastOpen(true);

}, );

const handleEventCreateFailed = useCallback(
(args: MbscEventCreateFailedEvent, inst: EventcalendarBase) => {
const { action, event, invalid, overlap, originEvent, source } = args;

  console.error('Event creation failed:');
  console.error('Action:', action);
  console.error('Event:', event);
  console.error('Invalid object:', invalid);
  console.error('Overlapped event:', overlap);
  console.error('Origin event:', originEvent);
  console.error('Source:', source);

  // Vider les variables si nécessaire
  setPopupEventTypeCode('');
  setPopupEventTypeDesc('');
  setPopupCollabId('');
  setEdit(false);
  // setTempEvent(null);
  handleFailed(event);
  setForceReload(true);
},
[handleFailed]

);

const handleEventDeleted = useCallback(
(args: MbscEventDeletedEvent, inst: EventcalendarBase) => {
setToastText(currentEvent?.title + " Supprimer");
setToastOpen(true);
setCurrentEvent(undefined);
setForceReload(true);
},

);

 const handlePageLoaded = useCallback(
   (args: MbscPageLoadedEvent) => {
     if (eventsLoaded) return;

     const firstDay = startOfWeek(args.firstDay);
     const lastDay = endOfWeek(args.lastDay);
     const startDate = `${firstDay.getFullYear()}-${firstDay.getMonth() + 1}-${firstDay.getDate()}`;
     const endDate = `${lastDay.getFullYear()}-${lastDay.getMonth() + 1}-${lastDay.getDate()}`;

     PlanningSchedulerService.GetAllEventsByIdCollabs(
       collabResources.map((collab) => collab.id),
       startDate,
       endDate
     ).then((result: { status: number; data: any }) => {
       if (result.status === 200) {
         const newEvents: MbscCalendarEvent[] = [];
         for (let id_collaborateur in result.data) {
           result.data[id_collaborateur].forEach((event: any) => {
             newEvents.push({
               id: event.id_plng,
               resource: event.id_collaborateur,
               start: event.start,
               end: event.end,
               allDay: event.fullday,
               title: event.ticket,
               color: event.activityCode.color,
               descActivity: event.activityCode.description,
               commentaire: event.commentaire,
               adresse: event.adresse,
               phone: event.phone,
               status: event.status,
               contact: event.contact,
               env: event.environment.name,
               envcolor: event.environment.color,
             });
           });
         }
         setMyEvents(newEvents);
         setForceReload(false);
       } else {
         console.log("Error: ", result);
       }
     });
   },
   [ forceReload]
 );
  1. Attempted Cleanup on Cancel: To remove the temporary event on cancel, I created a clearTempEvent function, which should clear tempEvent from myEvents.
    Here’s how I use it:

    const clearTempEvent = useCallback(() => {
    if (tempEvent) {
    setMyEvents((prevEvents) => prevEvents.filter(event => event.id !== tempEvent.id));
    setTempEvent(undefined);
    }
    }, [tempEvent]);

    const onClose = useCallback(() => {
    if (!isEdit) {
    clearTempEvent(); // Clear on cancel
    }
    setOpen(false);
    }, [isEdit, clearTempEvent]);

Also my component :

        <Eventcalendar
          className="rounded-lg"
          view={calView}
          renderHeader={customWithNavButtons}
          resources={memoizedCollabResources}
          renderResource={renderMyResource}
          renderResourceEmpty={renderCustomResourceEmpty}
          renderScheduleEvent={customScheduleEvent}
          externalDrop={true}
          externalDrag={true}
          // renderBufferBefore={myBeforeBuffer}
          data={myEvents}
          dragToCreate={false}
          dragToMove={false}
          dragToResize={false}
          showEventTooltip={true}
          showEventBuffer={false}
          onEventClick={handleEventClick}
          onEventCreate={handleEventCreate}
          onEventCreated={handleEventCreated}
          onEventCreateFailed={handleEventCreateFailed} 
          onEventDeleted={handleEventDeleted}
          onEventUpdated={handleEventUpdated}
          onPageLoading={handlePageLoading}
          onPageLoaded={handlePageLoaded}
          invalid={disabledDates}
          theme={isDarkTheme ? "customMaterial-dark" : "customMaterial"}
          cssClass="md-switching-view-cont"
        />
        <Popup
          isOpen={isMainPopupOpen}
          onClose={() => setMainPopupOpen(false)}
          display="anchored"
          anchor={anchor}
          responsive={popupResponsive}
          cssClass="md-tooltip"
        >
          <div onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
            <div className="md-tooltip-header" style={headerStyle}>
              <h4 className="dark:text-white text-black">
                {currentEvent?.title ?? ""}
              </h4>
            </div>
            <div className="md-tooltip-info">
              <div className="md-tooltip-title">
                Status:{" "}
                <span className="md-tooltip-status md-tooltip-text">
                  {currentEvent?.status ?? "Pas de statut"}
                </span>
                <br />
                Journée complète:{" "}
                <span className="md-tooltip-fullday md-tooltip-text">
                  {currentEvent?.fullDay ? "Oui" : "Non"}
                </span>
                <p>Collaborateur : {selectedCollabName}</p>
              </div>
              <div className="md-tooltip-title">
                Type d'activité:{" "}
                <span className="md-tooltip-typeActivity md-tooltip-text">
                  {currentEvent?.descActivity}
                </span>
              </div>
              <div className="md-tooltip-title">
                Contact:{" "}
                <span className="md-tooltip-contact md-tooltip-text">
                  {currentEvent?.contact}
                </span>
                <br />
                Telephone:{" "}
                <span className="md-tooltip-phone md-tooltip-text">
                  {currentEvent?.phone}
                </span>
              </div>
              <div className="md-tooltip-title">
                Adresse:{" "}
                <span className="md-tooltip-location md-tooltip-text">
                  {currentEvent?.adresse}
                </span>
              </div>
              <div className="md-tooltip-title">
                Commentaire:{" "}
                <span className="md-tooltip-reason md-tooltip-text">
                  {currentEvent?.commentaire}
                </span>
              </div>
              <div className="md-tooltip-title">
                Horaire:{" "}
                <span className="md-tooltip-time md-tooltip-text">
                  {String(currentEvent?.start)} - {String(currentEvent?.end)}
                </span>
                </div>
            </div>
          </div>
          <Button
            onClick={() => {
              setMainPopupOpen(false);
              setOpen(true);
            }}
          >
            Modifier
          </Button>
        </Popup>
        <Popup
  display="center"
  fullScreen={true}
  contentPadding={false}
  headerText={headerText}
  anchor={anchor}
  isOpen={isOpen}
  onClose={onClose}
  responsive={popupResponsive}
>
  1. Current Behavior: Even with this configuration, the temporary event is not always removed. I’ve logged tempEvent to verify it, and it seems the event does not fully disappear from the UI when canceled.

Environment

React: 18.2.0
Mobiscroll React Package: 5.29.0

Question: Is there a recommended approach for cleaning up temporary events on cancel? Any guidance on ensuring that the event is fully removed from the scheduler’s UI and state would be appreciated.

Thank you for your assistance!

Hi,

Thank you for the details and sorry for the trouble!
The onClose method should do the job. There are two PopUp-s used in the shared code and it is not clear what the order of their appearance is and how the isEdit is managed. It is hard to understand it completely based on the shared code. What I suspect is that when the onClose is called, there might be cases when the isEdit is not set properly, thus this code won’t run:

if (!isEdit) {
clearTempEvent(); // Clear on cancel
}

Let me know what you find!