-
Notifications
You must be signed in to change notification settings - Fork 147
Open
Description
Hello @aldabil21
The feature getRemoteEvents is workly perfectly and is a great feature to the scheduler ! It is usefull for performance issue and avoiding to reload the Scheduler.
However, is it possible to add getRemoteResources as well ? Would be a great adding this to an already awesome library (if it's possible) 💯
I explain:
- I have filters to display or not Resources, and each time I filter, to update resources => I have to reload the scheduler through key prop.
here is the code:
import React, { useRef } from "react";
import { useSchedulerData } from "./useSchedulerData";
import DataTableSheet from "@/components/DataTable/Sheet/DataTableSheet";
import { Roles } from "@/enum/roles.enum";
import "./scheduler-fix.css";
import CustomEvent from "./CustomEvent/CustomEvent";
import { DefaultResource, SchedulerRef } from "@aldabil/react-scheduler/types";
import { Scheduler } from "@aldabil/react-scheduler";
import SchedulerWeekConfig from "./Config/WeekConfig";
import CustomResourceHeader from "./CustomResourceHeader/CustomResourceHeader";
import HeaderBar from "./Header/Header";
const DEFAULT_HOUR_FORMAT = "24";
interface CustomSchedulerProps {
selectedFilters: any;
}
const CustomScheduler: React.FC<CustomSchedulerProps> = ({
selectedFilters,
}) => {
const calendarRef = useRef<SchedulerRef | null>(null);
const {
resources,
resourceFields,
pointings,
reloadKey,
setReloadKey,
view,
setView,
handleCellClick,
handleEventClick,
isSheetOpen,
handleClose,
selectedRowData,
isLoading,
weekDays,
currentDate,
setCurrentDate,
resourceViewMode,
setResourceViewMode,
fetchRemote,
} = useSchedulerData(selectedFilters);
return (
<>
<HeaderBar
currentDate={currentDate}
setCurrentDate={setCurrentDate}
view={view}
setView={setView}
resourceViewMode={resourceViewMode}
setResourceViewMode={setResourceViewMode}
/>
{resources.length ? (
<Scheduler
key={`${reloadKey}-${currentDate.toString()}-${view}-${resourceViewMode}`}
resourceViewMode={resourceViewMode}
ref={calendarRef}
getRemoteEvents={fetchRemote}
selectedDate={currentDate}
onSelectedDateChange={setCurrentDate}
loading={isLoading}
events={pointings}
resources={resources}
hourFormat={DEFAULT_HOUR_FORMAT}
resourceFields={resourceFields}
view={view}
onViewChange={setView}
week={SchedulerWeekConfig({ weekDays })}
day={null}
agenda={false}
editable={false}
deletable={false}
draggable={false}
disableViewer={true}
resourceHeaderComponent={(resource: DefaultResource) => (
<CustomResourceHeader resource={resource} />
)}
onCellClick={(
start: Date,
end: Date,
resourceVal?: string | number,
resourceKey?: string,
) => handleCellClick(start, end, resourceVal, resourceKey)}
onEventClick={handleEventClick}
eventRenderer={(event) => (
<CustomEvent event={event} onClick={handleEventClick} />
)}
/>
) : null}
<DataTableSheet
open={isSheetOpen}
onOpenChange={handleClose}
selectedRowData={selectedRowData}
formKey="pointing"
reloadData={() => setReloadKey(reloadKey + 1)}
minimumAllowedRoleToEdit={Roles.ADMIN}
/>
</>
);
};
export default CustomScheduler;
My hooks:
import React, { useState, useEffect } from "react";
import { ProcessedEvent, WeekDays } from "@aldabil/react-scheduler/types";
import { getEmployees } from "@/utils/employee.utils";
import { getPointings } from "@/utils/pointing.utils";
import { EmployeeForScheduler } from "@/types/entities/Employee";
import { Pointing } from "@/types/entities/Ponting";
import { View } from "@aldabil/react-scheduler/components/nav/Navigation";
const DEFAULT_WEEK_DAYS: WeekDays[] = [0, 1, 2, 3, 4];
// Custom hook to fetch scheduler data
export const useSchedulerData = (selectedFilters?: Record<string, any[]>) => {
const [resources, setResources] = useState<EmployeeForScheduler[]>([]);
const [pointings, setPointings] = useState<ProcessedEvent[]>([]);
const [reloadKey, setReloadKey] = useState(0);
const [isSheetOpen, setIsSheetOpen] = useState(false);
const [selectedRowData, setSelectedRowData] = useState({});
const [view, setView] = useState<View>("week");
const [resourceViewMode, setResourceViewMode] = useState<
"default" | "vertical" | "tabs" | undefined
>("default");
const [isLoading, setIsLoading] = useState(true);
const [weekDays, setWeekDays] = useState<WeekDays[]>(DEFAULT_WEEK_DAYS);
const [currentDate, setCurrentDate] = useState(new Date());
const resourceFields = {
idField: "employee_id",
textField: "firstname",
subTextField: "lastname",
avatarField: "firstname",
};
const handleCellClick = (
start: Date,
end: Date,
resourceVal?: string | number,
resourceKey?: string,
) => {
setSelectedRowData({
startDate: start,
endDate: end,
employeeId: resourceKey,
schedulerIdResource: resourceVal,
creation: true,
});
setIsSheetOpen(true);
};
const handleEventClick = (event: any) => {
setIsSheetOpen(true);
setSelectedRowData(event);
};
const handleClose = () => {
setIsSheetOpen(false);
setSelectedRowData({});
};
const filterEmployees = (employees: EmployeeForScheduler[]) => {
if (!selectedFilters) return employees;
return employees.filter((employee) => {
// Agency filter
if (
selectedFilters.agencyId?.length &&
!selectedFilters.agencyId.includes(employee.agencyId)
) {
return false;
}
// Entity filter (comes from employee.agency.entityId)
if (
selectedFilters.entityId?.length &&
!selectedFilters.entityId.includes(employee.agency?.entityId)
) {
return false;
}
// ContractType filter (assuming you later add `contractType` on employees)
// if (
// selectedFilters.contractType?.length &&
// !selectedFilters.contractType.includes(employee.contractType)
// ) {
// return false;
// }
return true;
});
};
const fetchEmployees = async () => {
setIsLoading(true);
try {
const employeeResponse = await getEmployees();
if (Array.isArray(employeeResponse) && employeeResponse.length > 0) {
const employeesWithResourceId: EmployeeForScheduler[] =
employeeResponse.map((employee) => ({
...employee,
employee_id: employee.id,
}));
const filtered = filterEmployees(employeesWithResourceId);
setResources(filtered);
} else {
console.error("Employees API response is not an array or is empty");
}
} catch (error) {
console.error("Error fetching employees or pointings:", error);
} finally {
setReloadKey((prev) => prev + 1);
setIsLoading(false);
}
};
const fetchRemote = async (): Promise<ProcessedEvent[] | undefined> => {
try {
const pointingResponse = await getPointings();
if (Array.isArray(pointingResponse)) {
const mappedEvents: ProcessedEvent[] = pointingResponse
.filter(
(pointing: Pointing) => pointing.startDate && pointing.endDate,
)
.map((pointing: Pointing) => ({
event_id: pointing.id,
title: pointing.clientName || `Pointing ${pointing.id}`,
start: new Date(pointing.startDate!),
end: new Date(pointing.endDate!),
employee_id: pointing.employeeId,
id: pointing.id,
notes: pointing.notes,
breakTime: pointing.breakTime,
hasTransport: pointing.hasTransport,
hasFood: pointing.hasFood,
employeeId: pointing.employeeId,
employee: pointing.employee,
startDate: pointing.startDate,
endDate: pointing.endDate,
clientName: pointing.clientName,
}));
return mappedEvents;
} else {
console.error("Pointings API response is not an array");
}
} catch (error) {
console.error("Error fetching pointings:", error);
}
};
useEffect(() => {
fetchEmployees();
}, [JSON.stringify(selectedFilters)]);
return {
resources,
resourceFields,
pointings,
fetchEmployees,
reloadKey,
setReloadKey,
isSheetOpen,
setIsSheetOpen,
handleCellClick,
handleEventClick,
handleClose,
selectedRowData,
setSelectedRowData,
view,
setView,
isLoading,
setIsLoading,
weekDays,
setWeekDays,
currentDate,
setCurrentDate,
resourceViewMode,
setResourceViewMode,
fetchRemote,
};
};
Here is the line to reload otherwise, my resources can't be updated:
setReloadKey((prev) => prev + 1); in fetchEmployees function.
The idea is to have the getRemoteResources i can callback when my filters are updated and avoid reloading the entire component :)
Thanks and have a nice day !
Metadata
Metadata
Assignees
Labels
No labels