Mobile View Schedular Filter

How to set this filtering? When i first click, there's some list there, but the second time the list is empty.


WhatsApp Image 2022-01-06 at 4.40.48 PM.jpeg

WhatsApp Image 2022-01-05 at 3.29.01 PM.jpeg






5 Replies

VM Vengatesh Maniraj Syncfusion Team January 7, 2022 06:32 AM UTC

Hi Samantha,


By default Scheduler, the resource filter has been handled in the source end. Since this is worked by default, could you please get back to us with the below details to proceed further to validate and provide the solution earlier?

- Please share the complete set of scheduler codes.

- Please share the scheduler package version

- Please share the details of the mobile device 


Regards,

Vengatesh



SA Samantha January 7, 2022 07:30 AM UTC

1) Scheduler Source code:

import React, { useCallback, useEffect, useState } from "react";
import "@fullcalendar/daygrid/main.css";
import "@fullcalendar/timegrid/main.css";
import {
  ScheduleComponent,
  Day,
  WorkWeek,
  Week,
  Month,
  TimelineMonth,
  Year,
  Inject,
  ViewsDirective,
  ViewDirective,
  DragAndDrop,
  ResourcesDirective,
  ResourceDirective,
  Resize,
} from "@syncfusion/ej2-react-schedule";
import { CheckBoxComponent } from "@syncfusion/ej2-react-buttons";
import {
  getAppointmentListDoctor,
  getApptDetail,
  getApptLocation,
  getApptResource,
  getApptStatus,
  getApptType,
  getSchedulerOrganizerList,
  reschedule_appt,
  updateDoctorAppt,
} from "./appointmentCrud";
import {
  formatDateStringAsDate2,
  formatDateTimeStringAsDateTime,
  getStartEndDateDifference,
  SAASDateFormat,
} from "../../../../_metronic/_helpers/DateHelper";
import { Form, Modal } from "react-bootstrap";
import moment from "moment";
import { AddAppointmentForm } from "./add-appointment-dialog/AddAppointmentForm";
import { RemoveAppointmentForm } from "./add-appointment-dialog/RemoveAppointmentForm";
import { FormattedMessage } from "react-intl";
import { useLang } from "../../../../_metronic/i18n";
import { DateRangePickerComponent } from "@syncfusion/ej2-react-calendars";

export function Scheduler() {
  const [list, setLists] = useState([]);
  const [doctorList, setDoctorList] = useState([]);
  const [doctorListScheduler, setDoctorListScheduler] = useState([{}]);
  const [doctorResource, setDoctorResource] = useState([{}]);
  const [selectedDoctorList, setSelectedDoctorList] = useState([]);
  const [startDate, setStartDate] = useState(
    formatDateTimeStringAsDateTime(new Date())
  );
  const [endDate, setEndDate] = useState(
    formatDateTimeStringAsDateTime(new Date())
  );
  const [appt, setAppt] = useState({});
  const [startTime, setStartTime] = useState("");
  const [openPopup, setOpenPopup] = useState(false);
  const [openUpdatePopup, setOpenUpdatePopup] = useState(false);
  const [openDeletePopup, setOpenDeletePopup] = useState(false);
  const [appTypeList, setAppType] = useState([]);
  const lang = useLang();
  const [apptLocationList, setApptLocationList] = useState([]);
  const [apptStatusList, setApptStatusList] = useState([]);
  const [locationList, setLocationList] = useState([]);
  const [statusList, setStatusList] = useState([]);
  const [typeList, setTypeList] = useState([]);
  const [minDate] = useState(
    formatDateTimeStringAsDateTime(new Date("01/01/1990"))
  );
  const [maxDate] = useState(
    formatDateTimeStringAsDateTime(new Date("01/01/3000"))
  );
  const [dateInterval, setDateInterval] = useState(1);
  const [schedularView, setSchedularView] = useState("Day");
  const [organizerList, setOrganizerList] = useState([]);

  const getApptList = useCallback(() => {
    getAppointmentListDoctor(
      startDate,
      endDate,
      JSON.stringify(selectedDoctorList),
      JSON.stringify(statusList),
      JSON.stringify(locationList),
      JSON.stringify(typeList)
    ).then((response) => {
      setLists(
        response.data.data.map((list) => {
          return {
            Id: list.id,
            Subject: list.name,
            Doctor: list.doctor.includes("|") ? list.doctor.split("|") : list.doctor,
            Type: list.type,
            Location: list.location,
            Status: list.apt_status,
            Duration: "00:" + list.duration,
            StartTime: formatDateTimeStringAsDateTime(list.apt_date),
            EndTime: formatDateTimeStringAsDateTime(list.endTime),
            IsBlock: false,
          };
        })
      );
    });
  }, [selectedDoctorList, startDate, endDate, statusList, locationList, typeList]);

  const getAppType = useCallback(() => {
    getApptType().then((response) => {
      setAppType(response.data);
    });
  }, []);

  const getDoctorList = ...

  const getScheduleList = ...

  const getApptLocations = ...

  const getAppointmentStatus = ...

  useEffect(() => {
    getApptList();
    getScheduleList();
    getAppType();
  }, [getApptList, getScheduleList, getAppType, startDate, endDate]);

  useEffect(() => {
    getDoctorList();
    getApptLocations();
    getAppointmentStatus();
  }, [getDoctorList, getApptLocations, getAppointmentStatus]);

  useEffect(() => {
    getOrganizer();
  }, [list]);

  const closePopup = () => {
    setOpenPopup(false);
  };

  const closeUpdatePopup = () => {
    setOpenUpdatePopup(false);
  };

  const closeDeletePopup = () => {
    setOpenDeletePopup(false);
  };

  const onEventRendered = (e) => {
    if (e.type === "event") {
      appTypeList.forEach((element) => {
        if (e.data.Type === element.type) {
          e.element.style.backgroundColor = element.slotViewColor;
          e.element.style.color = "black";
        }
      });
    } else {
      e.element.lastChild.className = "";
    }
  };

  const onCellRender = (e) => {
    if (e.name === "renderCells") {
      let date = new Date(e.date);
      doctorResource[e.groupIndex].doctorOrganizerList.forEach(
        (element, index) => {
          if (
            date > new Date(element.fromDate[index]) &&
            date < new Date(element.toDate[index])
          ) {
            e.element.style.backgroundColor = "grey";
            e.element.blocked = true;
          }
        }
      );
    }
  };

  const rescheduleDrag = (e) => {
    var date1 = new Date();
    var date2 = new Date(e.data.StartTime);
    var date3 = new Date(e.data.EndTime);
    var startTime = date2.getTime();
    var endTime = date3.getTime();
    var duration_hours = Math.floor((endTime - startTime)/ (1000 * 60 * 60) % 24);
    var duration_minutes = (endTime - startTime)/ (1000 * 60) % 60;
    var estimatedDuration = (duration_hours.toString() + ":" + duration_minutes.toString() + ":00");

    if (date2.setHours(0, 0, 0, 0) >= date1.setHours(0, 0, 0, 0)) {
      reschedule_appt(
        e.data.Id,
        moment(e.data.StartTime).add(8, "hours"),
        estimatedDuration
      );
      getApptDetail(e.data.Id).then((response) => {
        updateDoctorAppt(e.data.Id, e.data.Doctor);
      });
    } else {
      e.cancel = true;
    }
  };

  const popUpHandler = (e) => {
    if (e.type === "Editor") {
      e.cancel = true;
      if (e.data.Id !== undefined) {
        getApptDetail(e.data.Id).then((response) => {
          setAppt(response.data);
        });
        setOpenUpdatePopup(true);
      }
    }
    if (e.type === "DeleteAlert") {
      e.cancel = true;
      if (e.data.Id !== undefined) {
        getApptDetail(e.data.Id).then((response) => {
          setAppt(response.data);
        });
        setOpenDeletePopup(true);
      }
    }
    if (e.type === "QuickInfo" && e.target.classList[0] === "e-work-cells") {
      e.cancel = true;
      if (e.data.StartTime !== undefined && e.data.StartTime >= new Date()) {
        setStartTime(e.data.StartTime);
        setOpenPopup(true);
      }
    }
  };

  const checkLocal = () => {
    if (lang === "ms-MY") return "ms";
    else if (lang === "zh-CN") return "zh";
    else return "en";
  };

  const handleResource = (checked, resource) => {
    if (checked === true) {
      setSelectedDoctorList([...selectedDoctorList, resource]);
    } else {
      const newList = selectedDoctorList.filter((item) => item !== resource);
      setSelectedDoctorList(newList);
    }
  };

  const handleLocation = (checked, description) => {
    if (checked === true) {
      setLocationList([...locationList, description]);
    } else {
      const newList = locationList.filter((item) => item !== description);
      setLocationList(newList);
    }
  };

  const handleStatus = (checked, status) => {
    if (checked === true) {
      setStatusList([...statusList, status]);
    } else {
      const newList = statusList.filter((item) => item !== status);
      setStatusList(newList);
    }
  };

  const handleType = (checked, type) => {
    if (checked === true) {
      setTypeList([...typeList, type]);
    } else {
      const newList = typeList.filter((item) => item !== type);
      setTypeList(newList);
    }
  };

  const handleDateRange = (props) => {
    var startDate = props.nativeEvent.text[0];
    var endDate = props.nativeEvent.text[1];
    var formattedStartDate = startDate.toDateString();
    var formattedEndDate = endDate.toDateString();
    setStartDate(formattedStartDate);
    setEndDate(formattedEndDate);
    var difference = getStartEndDateDifference(startDate, endDate);
    setDateInterval(difference + 1);
    setSchedularView("Week");
    setSchedularView("Day");
  };

  const getOrganizer = useCallback(() => {
    getSchedulerOrganizerList().then((response) => {
      var data = response.data;
      setOrganizerList(
        data.map((schedulerBlock) => {
          for (var i = 0; i < schedulerBlock.fromDate.length; i++) {
            var fromDate = schedulerBlock.fromDate[i];
          }
          for (var j = 0; j < schedulerBlock.toDate.length; j++) {
            var toDate = schedulerBlock.toDate[j];
          }
          var repeatType = "FREQ=" + schedulerBlock.repeatType.toUpperCase()
          var startDate = new Date(formatDateStringAsDate2(schedulerBlock.startDate));
          var endDate = new Date(formatDateStringAsDate2(schedulerBlock.stopDate));
          var Difference_In_Time = endDate.getTime() - startDate.getTime();
          var Difference_In_Days = (Difference_In_Time / (1000 * 3600 * 24));
          var count = ";COUNT=" + Difference_In_Days
          var recurrenceRule = repeatType + count;
          return {
            Id: schedulerBlock.id,
            Subject: schedulerBlock.reason,
            Doctor: schedulerBlock.doctor,
            StartTime: formatDateTimeStringAsDateTime(fromDate),
            EndTime: formatDateTimeStringAsDateTime(toDate),
            RecurrenceRule: recurrenceRule,
            IsBlock: true,
          };
        }),
      );
    });
  }, []);

  return (
    <>
      <Modal show={openPopup} onHide={closePopup} size="lg" scrollable={true}>
        <AddAppointmentForm
          startTime={startTime}
          close={closePopup}
          reloadList={getApptList}
        />
      </Modal>

      <Modal
        show={openUpdatePopup}
        onHide={closeUpdatePopup}
        size="lg"
        scrollable={true}
      >
        <AddAppointmentForm
          apptData={appt}
          close={closeUpdatePopup}
          reloadList={getApptList}
        />
      </Modal>

      <Modal show={openDeletePopup} onHide={closeDeletePopup} scrollable={true}>
        <RemoveAppointmentForm
          apptData={appt}
          close={closeDeletePopup}
          reloadList={getApptList}
        />
      </Modal>

      <div className="row">
        <div className="col-lg-3">
          <div
            className="card card-custom card-stretch"
            style={{ height: "75v" }}
          >
            {/* Date Filter */}
            <div className="card-header">
              <div className="card-title pt-9">
                <h3 className="apptSchedular-font">
                  <FormattedMessage id="GENERAL.DATE_FILTER" />
                </h3>
              </div>
            </div>
            <Form.Group className="pt-3 px-8">
              <div className="control-pane">
                <div className="control-section">
                  <div className="daterangepicker-control-section">
                    <DateRangePickerComponent
                      min={minDate}
                      max={maxDate}
                      format={SAASDateFormat}
                      onChange={(e) => handleDateRange(e)}
                    ></DateRangePickerComponent>
                  </div>
                </div>
              </div>
            </Form.Group>

            {/* Doctor Filter */}
            <div className="card-header">
              <div className="card-title pt-9">
                <h3 className="apptSchedular-font">
                  <FormattedMessage id="GENERAL.DOCTOR_FILTER" />
                </h3>
              </div>
            </div>
            <Form.Group className="pt-3 px-8">
              <table>
                <tbody>
                  {doctorList.map((data) => (
                    <tr
                      key={data.id}
                      style={{ width: "100%" }}
                    >
                      <td style={{ width: "63.5%" }}>{data.resource}</td>
                      <td
                        style={{
                          backgroundColor: data.blockcolor,
                          width: "20%",
                        }}
                        className="pr-3"
                      />
                      <td style={{ width: "20%" }} className="pl-5">
                        <CheckBoxComponent
                          name={data.resource}
                          onChange={(e) =>
                            handleResource(e.target.checked, data.resource)
                          }
                          value="resource"
                        />
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </Form.Group>

            {/* Appointment Location */}
            <div className="card-header">
              <div className="card-title pt-9">
                <h3 className="apptSchedular-font">
                  <FormattedMessage id="GENERAL.APPOINTMENT_LOCATION" />
                </h3>
              </div>
            </div>
            <Form.Group className="pt-3 px-8">
              <table>
                <tbody>
                  {apptLocationList.map((data) => (
                    <tr key={data.id} style={{ width: "100%" }}>
                      <td style={{ width: "63.5%" }}>{data.description}</td>
                      <td
                        style={{
                          backgroundColor: data.slotViewColor,
                          width: "20%",
                        }}
                        className="pr-3"
                      />
                      <td style={{ width: "20%" }} className="pl-5">
                        <CheckBoxComponent
                          name={data.description}
                          onChange={(e) =>
                            handleLocation(e.target.checked, data.description)
                          }
                          value="description"
                        />
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </Form.Group>

            {/* Appointment Status */}
            <div className="card-header">
              <div className="card-title pt-9">
                <h3 className="apptSchedular-font">
                  <FormattedMessage id="GENERAL.APPOINTMENT_STATUS" />
                </h3>
              </div>
            </div>
            <Form.Group className="pt-3 px-8">
              <table>
                <tbody>
                  {apptStatusList.map((data) => (
                    <tr key={data.id} style={{ width: "100%" }}>
                      <td style={{ width: "63.5%" }}>{data.statusDesc}</td>
                      <td
                        style={{
                          backgroundColor: data.slotViewColor,
                          width: "20%",
                        }}
                        className="pr-3"
                      />
                      <td style={{ width: "20%" }} className="pl-5">
                        <CheckBoxComponent
                          name={data.statusDesc}
                          onChange={(e) =>
                            handleStatus(e.target.checked, data.statusDesc)
                          }
                          value="statusDesc"
                        />
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </Form.Group>

            {/* Appointment Type */}
            <div className="card-header">
              <div className="card-title pt-9">
                <h3 className="apptSchedular-font">
                  <FormattedMessage id="GENERAL.APPOINTMENT_TYPE" />
                </h3>
              </div>
            </div>
            <Form.Group className="pt-3 px-8">
              <table>
                <tbody>
                  {appTypeList.map((data) => (
                    <tr key={data.id} style={{ width: "100%" }}>
                      <td style={{ width: "63.5%" }}>{data.type}</td>
                      <td
                        style={{
                          backgroundColor: data.slotViewColor,
                          width: "20%",
                        }}
                        className="pr-3"
                      />
                      <td style={{ width: "20%" }} className="pl-5">
                        <CheckBoxComponent
                          name={data.type}
                          onChange={(e) =>
                            handleType(e.target.checked, data.type)
                          }
                          value="type"
                        />
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </Form.Group>
          </div>
        </div>
        <div className="col-lg-9">
          <div className="card card-custom card-stretch">
            <div className="card-header">
              <div className="card-title pt-7">
                <h3 className="card-label">
                  <FormattedMessage id="GENERAL.CALENDAR" />
                </h3>
              </div>
            </div>
            <div className="card-body">
              <div>
                <div className="demo-app">
                  <div className="demo-app-top"></div>
                  <div className="demo-app-calendar">
                    <ScheduleComponent
                      cssClass='virtual-scrolling' width='100%' height='650px'
                      resizeStop={rescheduleDrag.bind()}
                      dragStop={rescheduleDrag.bind()}
                      locale={checkLocal()}
                      currentView={schedularView}
                      eventSettings={{ dataSource: list.concat(organizerList) }}
                      renderCell={onCellRender.bind()}
                      eventRendered={onEventRendered.bind()}
                      rowAutoHeight={true}
                      timeScale={{ enable: true, interval: 60, slotCount: 6 }}
                      popupOpen={popUpHandler.bind()}
                      group={{ byDate: true, resources: ["Doctors"] }}
                      selectedDate={startDate}
                    >
                      <ResourcesDirective>
                        <ResourceDirective
                          field="Doctor"
                          name="Doctors"
                          dataSource={
                            selectedDoctorList.length === 0
                              ? doctorListScheduler
                              : doctorListScheduler.filter((data) => {
                                  return selectedDoctorList.includes(
                                    data.resource
                                  );
                                })
                          }
                          textField={"resource"}
                          idField={"resource"}
                          allowMultiple={true}
                        ></ResourceDirective>
                      </ResourcesDirective>

                      <Inject
                        services={[Day, Week, WorkWeek, Month, TimelineMonth, Year, Resize, DragAndDrop]}
                      />
                      <ViewsDirective>
                        <ViewDirective
                          option="Day"
                          endHour="24:00"
                          startHour="08:00"
                          interval={dateInterval}
                        />
                        <ViewDirective
                          option="Week"
                          startHour="08:00"
                          endHour="24:00"
                        />
                        <ViewDirective
                          option="WorkWeek"
                          startHour="08:00"
                          endHour="24:00"
                        />
                        <ViewDirective option="Month" />
                        <ViewDirective option="TimelineMonth" />
                        <ViewDirective option="Year" />
                      </ViewsDirective>
                    </ScheduleComponent>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </>
  );
}



2) Scheduler package version

"@syncfusion/ej2-react-schedule": "^19.1.65",

3)  Details of the mobile device 

What do you mean by the detail of the mobile device? Is it android version or screen size ?



VM Vengatesh Maniraj Syncfusion Team January 10, 2022 12:30 PM UTC

Hi Samantha,


Thanks for sharing details.

We will check the shared codes and get back to you by 11th Jan 2022. In meantime, could you please confirm whether this issue replicates in our latest package version (19.4.41)? 

3)  Details of the mobile device  - is this issue replicate any particular mobile or all the mobiles?


Regards,

Vengatesh






SA Samantha January 10, 2022 01:59 PM UTC

Hi Vengatesh,

Thanks for reply.

The issue above seems fine when I test again, this time it able to switch the option without error. But this only works for Android device (tested on two different Android devices), when test on IOS device, the calendar is gone.





BS Balasubramanian Sattanathan Syncfusion Team January 11, 2022 04:25 PM UTC

Hi Samantha,

We will update the response in the following forum #171813 and kindly have a follow-up with that for further details.

Regards,
Balasubramanian 


Loader.
Up arrow icon