As title says. Select a cell then resize the window, i lose my selection.
import React, {
FunctionComponent,
memo,
useEffect,
useRef,
useState,
} from "react";
import { DayPilotCalendar, DayPilot } from "daypilot-pro-react";
import { useAgendaSetup } from "../hooks/useAgendaSetup";
import { customAppointment, onEventPicked } from "../utils/AgendaUtils";
import useWindowDimensions from "../../../hooks/useWindowDimensions";
import {
findEmployeeById,
getFormattedHours,
onEventMoving,
setHourToCell,
} from "../../../utils/AgendaUtils";
import { TableSettings } from "../../../interfaces/settings/table_settings";
import { useSelector } from "react-redux";
import { RootState } from "../../../redux/store";
import { OverlayScrollbars } from "overlayscrollbars";
import dayjs from "dayjs";
import isBetween from "dayjs/plugin/isBetween";
import {
afterCellAreas,
onBeforeColumnHeaderRender,
onHeaderClick,
renderCellAreas,
} from "../utils/DaypilotCalendarUtils";
import { useQueryClient } from "@tanstack/react-query";
import { ensureColumnVisibility } from "../utils/SidebarUtils";
import {
styled,
Drawer as MuiDrawer,
Backdrop,
capitalize,
} from "@mui/material";
import ReactDOMServer, { renderToStaticMarkup } from "react-dom/server";
import "./AgendaGrid.scss";
import AgendaSidebar, { SidebarState } from "../AgendaSidebar/AgendaSidebar";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { AgendaGridProvider } from "../context/AgendaGridContext";
import { clsx } from "clsx";
import ExCalendar from "../../../components/ExCalendar/ExCalendar";
import { Drawer, Dropdown, MenuProps, Space } from "antd";
import useDeviceOrientation from "../../../hooks/useDeviceOrientation";
import { useAppointmentsCache } from "../AgendaSidebar/section/AgendaSidebarTabSection/tabs/hooks/useAppointmentsCache";
import ExDropdown from "../../../components/ExDropdown/ExDropdown";
import { useDialogManager } from "../../../hooks/useDialogManager";
import ClockRightIcon from "../../assets/icons/clock-rotate-right.svg?react";
import useAgendaStore from "../AgendaSidebar/store/useAgendaStore";
import moment from "moment";
import { useGenericDrawer } from "../../../drawers/useGenericDrawer/useGenericDrawer";
import Loader from "../../../components/Loader/Loader";
import NiceModal from "@ebay/nice-modal-react";
import ModalConfirmation from "../../../modals/ConfirmationModal/ModalConfirmation";
import { usePersonalPermissionCreationOrUpdate } from "../../../api/data-hooks/usePersonalPermissionCreationOrEdit";
import { AuthProvider } from "../../../interfaces/auth/AuthProvider";
interface AgendaGridProps {}
const AgendaGrid: FunctionComponent<
AgendaGridProps
> = ({}: AgendaGridProps) => {
dayjs.extend(isBetween);
const settings: TableSettings = useSelector(
(state: RootState) => state.tableSettings.settings as TableSettings
);
const calendarRef = useRef<DayPilotCalendar>(null);
const { handlePersonalPermissionMutation } =
usePersonalPermissionCreationOrUpdate();
const { height, width } = useWindowDimensions();
const { orientation } = useDeviceOrientation();
const { isOpen, closeDrawer, openDrawer } = useGenericDrawer();
const authProvider: AuthProvider = useSelector(
(state: RootState) => state.auth.auth
);
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const [isSidebarHidden, setIsSidebarHidden] = useState(false);
const [isTableResized, setIsTableResized] = useState(false);
const [selectColumn, setSelectColumn] = useState(0);
const [selectedEvents, setSelectedEvents] = useState<
DayPilot.Event[] | undefined
>([]);
const [targetCell, setTargetCell] = useState<any>();
const [startHour, setStartHour] = useState<string>("");
const [resourceId, setResourceId] = useState<string>("");
const {
colHeaders,
appointments,
dbAppointments,
onEventDnd,
onEventResize,
startDayHour,
endDayHour,
agendaDayData,
cellDuration,
startWorkHour: posStartHour,
endWorkHour: posEndHour,
formattedDate: date,
isLoading: isCalendarLoading,
isRefetching,
} = useAgendaSetup({
fetchAppointments: true,
calendarRef: calendarRef,
});
const actualDate = useRef(date);
useEffect(() => {
if (!isSidebarOpen) {
deactivateMovingMode();
if (actualDate.current !== date) {
actualDate.current = date;
}
}
}, [date, isSidebarOpen]);
useEffect(() => {
if (!isMovingEventMode) onCloseDrawer();
}, [date]);
const { syncAppointmentCache } = useAppointmentsCache({
services: [],
});
const calendarContainer = document?.querySelector(
"div.calendar_default_scroll >div > div:nth-child(2)"
);
const container = document.getElementById("calendar_container");
function isValidFormat(date: any, format: any) {
const regex = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\.(\d{3})$/;
if (!regex.test(date)) {
return false;
}
const parsedDate = dayjs(date);
return parsedDate.format(format) === date;
}
const dateToCheck = "2024-07-25T11:09:04.186";
const format = "YYYY-MM-DDTHH:mm:ss.SSS";
const isValid = isValidFormat(dateToCheck, format);
console.log(isValid);
function onCloseDrawer() {
if (!isMovingEventMode) {
setIsSidebarOpen(false);
setIsTableResized(false);
deactivateMovingMode();
setTimeout(() => {
syncAppointmentCache();
}, 1500);
setTimeout(() => {
calendarRef.current?.control.multiselect.clear();
}, 200);
}
}
const { showChangelogDialog } = useDialogManager();
useEffect(() => {
if (settings.tableConfig?.popup != null) {
showChangelogDialog(settings.tableConfig?.popup);
}
}, []);
if (calendarContainer && /iPad|iPhone|iPod/.test(navigator.platform)) {
const container = document.querySelector("#day-pilot-calendar-container");
if (container) {
OverlayScrollbars(container as any, {
overflow: {
y: "hidden",
},
});
}
}
const queryClient = useQueryClient();
const { isMovingEventMode, deactivateMovingMode } = useAgendaStore();
useEffect(() => {
if (isMovingEventMode && width < 1024) {
setIsSidebarHidden(true);
setIsTableResized(false);
} else if (isMovingEventMode && width > 1024) {
setIsSidebarHidden(false);
}
}, [isMovingEventMode, width]);
useEffect(() => {
if (!isMovingEventMode) {
if (isSidebarOpen === false) {
setIsTableResized(false);
setTimeout(() => {
setSelectedEvents([]);
}, 500);
} else {
setTimeout(() => {
setIsTableResized(true);
}, 100);
setTimeout(() => {
if (calendarContainer) {
ensureColumnVisibility(selectColumn, width, calendarContainer!);
}
}, 300);
}
}
}, [isSidebarOpen]);
const items: MenuProps["items"] =
settings.tableConfig?.mod_agenda?.employees.map((employee) => ({
key: employee.id,
label: capitalize(employee.first_name ?? ""),
}));
const config: any = {
showCurrentTimeMode: "Full",
viewType: "Resources",
locale: "it-IT",
useEventBoxes: "Never",
startDate: date,
scrollDelayCells: 0,
headerHeightAutoFit: false,
events: appointments,
columns: colHeaders,
showCurrentTime: true,
allowMultiRange: false,
allowMultiSelect: true,
snapToGrid: true,
snapToGridTimeRangeSelecting: true,
snapToGridEventMoving: false,
snapToGridEventResizing: false,
rectangleSelectHandling: "Disabled",
headerHeight: 50,
rowHeaderWidth: 100,
cellHeight: cellDuration * (43 / 15),
timeHeaderCellDuration: cellDuration,
cellDuration: cellDuration,
scrollDelayDynamic: 0,
cellSweeping: false,
EventHoverHandling: "Bubble",
columnWidth:
(width - 62) / colHeaders.length >= 160
? (width - 62) / colHeaders.length
: 160,
crosshairType: "Disabled",
columnWidthSpec: "Fixed",
columnMarginRight: 10,
columnMarginLeft: 10,
dynamicEventRendering: "Disabled",
eventArrangement: "SideBySide",
eventClickHandling: "JavaScript",
dayBeginsHour: startDayHour,
businessBeginsHour: posStartHour,
businessEndsHour: posEndHour,
dayEndsHour: endDayHour,
onHeaderClick: (args: any) => {
console.log(
settings.tableConfig!.mod_agenda.days[
moment(date).format("YYYY-MM-DD")
]?.["employees"]?.[args.header.id]?.["work_time"]
);
onHeaderClick(
args,
queryClient,
date,
settings.tableConfig?.current_pos.id_pos! ?? "",
settings.tableConfig!.mod_agenda.days[
moment(date).format("YYYY-MM-DD")
]?.["employees"]?.[args.header.id]?.["work_time"],
() =>
openDrawer("absenceDrawer", {
id_employee: args.header.id,
})
);
},
onBeforeHeaderRender: (args: any) => {
if (agendaDayData) {
const isDefaultHour =
agendaDayData?.employees[args.header.id].work_time[0].default;
onBeforeColumnHeaderRender(args, isDefaultHour);
}
},
onBeforeEventDomAdd: (args: any) => {
const isSelected =
calendarRef.current?.control.multiselect.events().some((event) => {
return (
event.data.id === args.e.data.id ||
event.data.tag.client_id === args.e.data.tag.client_id
);
}) || args.e.data.tag["type"] === "draft";
args.element = customAppointment(
args,
isSelected ?? false,
args.e.data.tag.group
);
},
onBeforeCellRender: (args: any) => {
const colIndex = colHeaders.findIndex(
(column: any) => column.id === args.resource
);
renderCellAreas(agendaDayData, args);
},
onAfterCellRender: (args: any) => {
let date =
args.cell.start.getHours() +
":" +
(args.cell.start.getMinutes() === 0
? "00"
: args.cell.start.getMinutes());
args.div?.firstElementChild.setAttribute(
"data-after",
isMovingEventMode ? "Sposta qui: " + date : true ? date : ""
);
const colIndex = colHeaders.findIndex(
(column: any) => column.id === args.cell.resource
);
afterCellAreas(agendaDayData, args, colIndex, date);
},
onBeforeEventRender: (args: any) => {
if (args.data.tag.group === "personal_appointment") {
args.data.borderColor = "rgba(255, 126, 152, 1)";
args.data.backColor = "rgba(255, 251, 251, 1)";
args.data.fontColor = "rgba(255, 126, 152, 1)";
}
args.data.areas = [
{
width: "15px",
height: "15px",
right: 10,
bottom: 10,
icon: "fas fa-trash",
},
{
width: "400px",
height: 10,
right: 0,
top: 0,
action: "ResizeStart",
cssClass: "resize_area",
},
{
width: "400px",
height: "30px",
right: 0,
bottom: 0,
action: "ResizeEnd",
cssClass: "resize_area",
},
];
},
onTimeRangeSelecting: (args: any) => {},
onTimeRangeSelected: (args: any) => {
/* setTargetCell(args);
if (!isMovingEventMode) {
setSelectedEvents([]);
const columnIndex = colHeaders.findIndex(
(resource) => resource.id === args.resource
);
syncAppointmentCache();
setTimeout(() => {
if (isSidebarOpen === false) {
setIsSidebarOpen(!isSidebarOpen);
} else {
ensureColumnVisibility(columnIndex, width, calendarContainer!);
}
}, 600);
setTimeout(() => {
const hour = dayjs(args.start).format("HH:mm");
setStartHour(hour);
setResourceId(args.resource);
calendarRef.current?.control.multiselect.clear();
setSelectColumn(columnIndex);
}, 300);
(calendarRef.current?.control as any)?.selectTimeRange(
args.start,
args.start,
args.resource,
true
);
} */
},
onEventResized: (args: any) => {
const {
newStart: start,
newEnd: end,
e: {
data: { id: eventId },
},
} = args;
const { formattedStart, formattedEnd, minutesDifference } =
getFormattedHours(start, end, cellDuration);
if (isNaN(Number(eventId))) {
onEventResize.mutate({
eventId: eventId,
formattedStart: formattedStart,
formattedEnd: formattedEnd,
type: args.e.data.tag.group,
duration:
minutesDifference < cellDuration ? cellDuration : minutesDifference,
});
}
},
onEventMoving: (args: any) => {
onEventMoving(args);
},
onEventMove: (args: any) => {},
onEventMoved: (args: any) => {
const eventId = args.e.data.id;
const { newStart: start, newEnd: end, newResource: resource } = args;
if (true) {
const { formattedStart, formattedEnd, minutesDifference } =
getFormattedHours(start, end, cellDuration);
const formattedResource = findEmployeeById(
settings.tableConfig?.mod_agenda?.employees || [],
resource
);
if (isNaN(Number(eventId))) {
onEventDnd.mutate({
eventId: eventId,
formattedStart: formattedStart,
end: formattedEnd,
id_staff: resource,
type: args.e.data.tag.group,
});
}
}
},
onEventClicked: (args: any) => {
console.log(args);
if (args.e.data.tag.group === "appointment") {
const isSelected = calendarRef.current?.control.multiselect
.events()
.some((event) => {
return event.data.tag.client_id === args.e.data.tag.client_id;
});
setTimeout(() => {
if (isSelected === true) {
setTimeout(() => {
setIsSidebarOpen(false);
calendarRef.current?.control.multiselect.clear();
}, 600);
} else {
calendarRef.current?.control.multiselect.clear();
const days = calendarRef.current?.control.events.list.filter(
(element) => element.tag.client_id === args.e.data.tag.client_id
);
days?.forEach((day) => {
const dayValue = calendarRef.current?.control.events.find(
day.id.toString()
);
if (dayValue) {
calendarRef.current?.control.multiselect.add(dayValue);
}
});
setTimeout(() => {
const events = calendarRef.current?.control.multiselect.events();
const columnIndex = colHeaders.findIndex(
(resource) => resource.id === args.e.data.resource
);
setSelectColumn(columnIndex);
setSelectedEvents(events);
if (events && events.length > 0) {
const sortedEvents = events.sort(
(a: DayPilot.Event, b: DayPilot.Event) =>
dayjs(a.start() as any).diff(dayjs(b.start() as any))
);
const startHour = dayjs(sortedEvents[0].start() as any).format(
"HH:mm"
);
setStartHour(startHour);
}
setIsSidebarOpen(true);
}, 0);
}
}, 500);
} else {
openDrawer("absenceDrawer", {
id_employee: args.e.data.resource,
body: args.e.data.tag.permission_body,
});
/* NiceModal.show(ModalConfirmation, {
title: "Conferma eliminazione dei permessi",
subtitle: "Vuoi eliminare questo periodi di pausa selezionato?",
onConfirm: () => {
const appointment = {
id_booking_diary:
settings.tableConfig?.mod_agenda.options.id_diary,
id_appointment: args.e.data.id,
state: "deleted",
};
const dataRequest = {
email: authProvider.email,
token: authProvider.token,
pin: authProvider.pin,
appointment_date: date,
personal_appointments: [appointment],
};
handlePersonalPermissionMutation.mutate(dataRequest);
},
considerNavbar: false,
}); */
}
/* const isSelected = calendarRef.current?.control.multiselect
.events()
.some(
(event) => event.data.tag.client_id === args.e.data.tag.client_id
);
if (isSelected) {
calendarRef.current.?control.multiselect.clear();
setTimeout(() => {
setIsSidebarOpen(false);
}, 1000);
} else {
onEventPicked(calendarRef, args.e.data.tag.client_id, dbAppointments);
setTimeout(() => {
const events = calendarRef.current?.control.multiselect.events();
const columnIndex = colHeaders.findIndex(
(resource) => resource.id === args.e.data.resource
);
setSelectColumn(columnIndex);
setSelectedEvents(events);
setIsSidebarOpen(true);
}, 750);
} */
},
};
return (
<>
<div
className="animate-fade"
id="calendar_container"
style={{
height: `${(height ?? 150) - 50}px`,
width: `calc(100% - ${isTableResized ? "400" : "0"}px)`,
willChange: "auto",
}}
>
<DayPilotCalendar
ref={calendarRef}
heightSpec={"Parent100Pct"}
{...config}
/>
</div>
<div
className={clsx("", {
"opacity-0": isSidebarHidden,
})}
style={{
visibility: isSidebarHidden ? "hidden" : "visible",
}}
>
<AgendaSidebar
calendarRef={calendarRef}
isSidebarOpen={isSidebarOpen}
startHour={startHour}
resource={resourceId}
startingSidebarState={SidebarState.create}
selectedServices={selectedEvents || []}
targetCell={targetCell}
userId={
selectedEvents && selectedEvents?.length > 0
? selectedEvents[0].data.tag.client_id
: undefined
}
date={actualDate.current?.valueOf() ?? ""}
handleSidebarHiding={() => {
setIsSidebarHidden(false);
setIsTableResized(true);
}}
closeSidebar={() => {
onCloseDrawer();
}}
/>
</div>
</>
);
};
export default AgendaGrid;