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>
</>
);
}
What do you mean by the detail of the mobile device? Is it android version or screen size ?