This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, {useState, useEffect, useRef, useCallback} from "react";
|
||||
import React, {useState, useEffect, useMemo, useRef, useCallback} from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { AuthService, EventsService, CustomerService, ResourceService, VehicleService, EmployeeService } from "../../services";
|
||||
import moment from 'moment';
|
||||
@@ -38,9 +38,6 @@ const EventsCalendar = () => {
|
||||
const [resources, setResources] = useState([]);
|
||||
const [fromDate, setFromDate] = useState(new Date(new Date().getFullYear(), new Date().getMonth(), 1));
|
||||
const [toDate, setToDate] = useState(new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0));
|
||||
const [currentTotalTranslate1, setCurrentTotalTranslate1] = useState(0);
|
||||
const [currentTotalTranslate2, setCurrentTotalTranslate2] = useState(0);
|
||||
const [currentTotalResource, setCurrentTotalResource] = useState(0);
|
||||
const [showDeletedItems, setShowDeletedItems] = useState(false);
|
||||
const [selectedColorFilters, setSelectedColorFilters] = useState([]);
|
||||
const [timeData, setTimeData] = useState([]);
|
||||
@@ -147,6 +144,7 @@ const EventsCalendar = () => {
|
||||
const [initialEventsLoaded, setInitialEventsLoaded] = useState(false);
|
||||
const [isTabTransitionLoading, setIsTabTransitionLoading] = useState(false);
|
||||
const hasMarkedInitialEventsLoadedRef = useRef(false);
|
||||
const eventsFetchRequestIdRef = useRef(0);
|
||||
const visibleCalendarTabs = calendarTabOrder.filter((tabKey) => AuthService.canViewCalendarTab(tabKey) || AuthService.canEditCalendarTab(tabKey));
|
||||
const canEditCurrentTab = () => AuthService.canEditCalendarTab(currentTab);
|
||||
|
||||
@@ -184,6 +182,22 @@ const EventsCalendar = () => {
|
||||
return doctorName ? `${fullName} - ${doctorName}` : fullName;
|
||||
};
|
||||
|
||||
const customerById = useMemo(() => {
|
||||
const map = new Map();
|
||||
(customers || []).forEach((customer) => {
|
||||
if (customer?.id) map.set(customer.id, customer);
|
||||
});
|
||||
return map;
|
||||
}, [customers]);
|
||||
|
||||
const resourceById = useMemo(() => {
|
||||
const map = new Map();
|
||||
(resources || []).forEach((resource) => {
|
||||
if (resource?.id) map.set(resource.id, resource);
|
||||
});
|
||||
return map;
|
||||
}, [resources]);
|
||||
|
||||
// Helper: expand a recurring rule into individual event instances for a date range
|
||||
const expandRecurrence = (rule, rangeFrom, rangeTo) => {
|
||||
const instances = [];
|
||||
@@ -297,15 +311,15 @@ const EventsCalendar = () => {
|
||||
plugins: [eventModalService, eventsServicePlugin, eventRecurrence],
|
||||
callbacks: {
|
||||
onRangeUpdate(range) {
|
||||
console.log('new calendar range start date', range.start);
|
||||
console.log('new calendar range end date', range.end);
|
||||
setCurrentRangeStart(range.start);
|
||||
setCurrentRangeEnd(range.end);
|
||||
// Update fromDate/toDate for API fetching based on the range
|
||||
const startDate = new Date(range.start);
|
||||
const endDate = new Date(range.end);
|
||||
setFromDate(new Date(startDate.getFullYear(), startDate.getMonth(), 1));
|
||||
setToDate(new Date(endDate.getFullYear(), endDate.getMonth() + 1, 0));
|
||||
const nextFromDate = new Date(startDate.getFullYear(), startDate.getMonth(), 1);
|
||||
const nextToDate = new Date(endDate.getFullYear(), endDate.getMonth() + 1, 0);
|
||||
setFromDate((prev) => (prev?.getTime?.() === nextFromDate.getTime() ? prev : nextFromDate));
|
||||
setToDate((prev) => (prev?.getTime?.() === nextToDate.getTime() ? prev : nextToDate));
|
||||
},
|
||||
onClickDate(date) {
|
||||
if (currentTabRef.current === 'medicalCalendar' || !AuthService.canEditCalendarTab(currentTabRef.current)) return;
|
||||
@@ -331,8 +345,6 @@ const EventsCalendar = () => {
|
||||
|
||||
// Filter events based on current calendar range
|
||||
const getFilteredEvents = () => {
|
||||
console.log("CenterCalendar - range:", currentRangeStart, "to", currentRangeEnd, "events:", events.length);
|
||||
|
||||
if (!currentRangeStart || !currentRangeEnd) {
|
||||
// If no range set yet, show all events for current month
|
||||
const now = moment();
|
||||
@@ -429,19 +441,34 @@ const EventsCalendar = () => {
|
||||
}, [currentTab]);
|
||||
|
||||
useEffect(() => {
|
||||
Promise.allSettled([
|
||||
EventsService.getAllEvents({ from: EventsService.formatDate(fromDate), to: EventsService.formatDate(toDate) }),
|
||||
EventsService.getAllEventRecurrences()
|
||||
]).then(([eventsResult, recurrencesResult]) => {
|
||||
setAllEvents(eventsResult?.status === 'fulfilled' ? (eventsResult.value?.data || []) : []);
|
||||
setAllEventRecurrences(recurrencesResult?.status === 'fulfilled' ? (recurrencesResult.value?.data || []) : []);
|
||||
const requestId = ++eventsFetchRequestIdRef.current;
|
||||
const timer = setTimeout(() => {
|
||||
EventsService.getAllEvents({ from: EventsService.formatDate(fromDate), to: EventsService.formatDate(toDate) })
|
||||
.then((eventsResult) => {
|
||||
if (requestId !== eventsFetchRequestIdRef.current) return;
|
||||
setAllEvents(eventsResult?.data || []);
|
||||
if (!hasMarkedInitialEventsLoadedRef.current) {
|
||||
hasMarkedInitialEventsLoadedRef.current = true;
|
||||
setInitialEventsLoaded(true);
|
||||
}
|
||||
}).catch(() => {
|
||||
if (requestId !== eventsFetchRequestIdRef.current) return;
|
||||
setAllEvents([]);
|
||||
if (!hasMarkedInitialEventsLoadedRef.current) {
|
||||
hasMarkedInitialEventsLoadedRef.current = true;
|
||||
setInitialEventsLoaded(true);
|
||||
}
|
||||
});
|
||||
}, 180);
|
||||
return () => clearTimeout(timer);
|
||||
}, [fromDate, toDate]);
|
||||
|
||||
useEffect(() => {
|
||||
EventsService.getAllEventRecurrences()
|
||||
.then((data) => setAllEventRecurrences(data?.data || []))
|
||||
.catch(() => setAllEventRecurrences([]));
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!showSpinner) return;
|
||||
const timer = setInterval(() => {
|
||||
@@ -490,14 +517,16 @@ const EventsCalendar = () => {
|
||||
if (customers?.length > 0 && resources.length > 0) {
|
||||
const orignialEvents = [...allEvents];
|
||||
setEvents(orignialEvents?.filter(item => item.type === 'medical')?.map((item) => {
|
||||
const customerField = item?.data?.customer ? (customers?.find(c => c.id === item?.data?.customer)?.name || item?.data?.client_name || '') : (item?.data?.client_name || '');
|
||||
const doctorField = item?.data?.resource ? ((resources?.find(r => r.id === item?.data?.resource))?.name || item?.data?.resource_name || '') : (item?.data?.resource_name || '');
|
||||
const customer = item?.data?.customer ? customerById.get(item?.data?.customer) : null;
|
||||
const resource = item?.data?.resource ? resourceById.get(item?.data?.resource) : null;
|
||||
const customerField = customer?.name || item?.data?.client_name || '';
|
||||
const doctorField = resource?.name || item?.data?.resource_name || '';
|
||||
item.event_id = item.id;
|
||||
item.customer = customerField;
|
||||
item.doctor = doctorField;
|
||||
item.phone = item?.data?.resource ? ((resources?.find(r => r.id === item?.data?.resource))?.phone || item?.data?.resource_phone || '') : (item?.data?.resource_phone || '');
|
||||
item.contact = item?.data?.resource? ((resources?.find(r => r.id === item?.data?.resource))?.contact || item?.data?.resource_contact || '') : (item?.data?.resource_contact || '')
|
||||
item.address = item?.data?.resource ? ((resources?.find(r => r.id === item?.data?.resource))?.address || item?.data?.resource_address || '') : (item?.data?.resource_address || '');
|
||||
item.phone = resource?.phone || item?.data?.resource_phone || '';
|
||||
item.contact = resource?.contact || item?.data?.resource_contact || '';
|
||||
item.address = resource?.address || item?.data?.resource_address || '';
|
||||
item.translation = item?.data?.interpreter || '';
|
||||
item.newPatient = item?.data?.new_patient || '';
|
||||
item.needId = item?.data?.need_id || '';
|
||||
@@ -519,11 +548,8 @@ const EventsCalendar = () => {
|
||||
item.maxTranslate2 = maxTranslate2;
|
||||
item.maxResource = maxResource;
|
||||
item.totalTranslate1 = totalTranslate1;
|
||||
setCurrentTotalTranslate1(item.totalTranslate1);
|
||||
item.totalTranslate2 = totalTranslate2;
|
||||
setCurrentTotalTranslate2(item.totalTranslate2);
|
||||
item.totalResource = totalResource;
|
||||
setCurrentTotalResource(item.totalResource);
|
||||
return item;
|
||||
})?.filter(item => {
|
||||
const includeDeleted = selectedColorFilters.includes('gray');
|
||||
@@ -598,7 +624,7 @@ const EventsCalendar = () => {
|
||||
filteredEvents = filteredEvents?.filter(item => {
|
||||
// If it's a customer-related event, check if the customer is active
|
||||
if (item.target_type === 'customer' && item.target_uuid) {
|
||||
const customer = customers.find(c => c.id === item.target_uuid);
|
||||
const customer = customerById.get(item.target_uuid);
|
||||
// Only show if customer exists and is active (not discharged/transferred/deceased)
|
||||
return customer && customer.status === 'active' &&
|
||||
customer.type !== 'discharged' &&
|
||||
@@ -612,13 +638,12 @@ const EventsCalendar = () => {
|
||||
|
||||
setEvents(filteredEvents);
|
||||
}
|
||||
}, [customers, resources, timeData, currentTab, allEvents, allEventRecurrences, showDeletedItems, selectedColorFilters])
|
||||
}, [customers, resources, timeData, currentTab, allEvents, allEventRecurrences, showDeletedItems, selectedColorFilters, customerById, resourceById])
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (events && calendar) {
|
||||
console.log("CenterCalendar useEffect - events:", events.length, "range:", currentRangeStart, "to", currentRangeEnd);
|
||||
calendar?.eventsService?.set(events);
|
||||
setGroupedEvents(getGroupedEvents());
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {useState, useEffect, useRef} from "react";
|
||||
import React, {useState, useEffect, useMemo, useRef} from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { AuthService, EventsService, CustomerService, ResourceService } from "../../services";
|
||||
import moment from 'moment';
|
||||
@@ -27,9 +27,6 @@ const EventsCalendar = () => {
|
||||
const [resources, setResources] = useState([]);
|
||||
const [fromDate, setFromDate] = useState(new Date(new Date().getFullYear(), new Date().getMonth(), 1));
|
||||
const [toDate, setToDate] = useState(new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0));
|
||||
const [currentTotalTranslate1, setCurrentTotalTranslate1] = useState(0);
|
||||
const [currentTotalTranslate2, setCurrentTotalTranslate2] = useState(0);
|
||||
const [currentTotalResource, setCurrentTotalResource] = useState(0);
|
||||
const [selectedColorFilters, setSelectedColorFilters] = useState([]);
|
||||
const [timeData, setTimeData] = useState([]);
|
||||
const [showFilterDropdown, setShowFilterDropdown] = useState(false);
|
||||
@@ -54,6 +51,7 @@ const EventsCalendar = () => {
|
||||
const [initialLookupsLoaded, setInitialLookupsLoaded] = useState(false);
|
||||
const [initialEventsLoaded, setInitialEventsLoaded] = useState(false);
|
||||
const hasMarkedInitialEventsLoadedRef = useRef(false);
|
||||
const eventsFetchRequestIdRef = useRef(0);
|
||||
const [newEventStartDateTime, setNewEventStartDateTime] = useState(new Date());
|
||||
const [newEventEndDateTime, setNewEventEndDateTime] = useState(new Date());
|
||||
const [newEventColor, setNewEventColor] = useState('');
|
||||
@@ -90,6 +88,22 @@ const EventsCalendar = () => {
|
||||
return doctorName ? `${fullName} - ${doctorName}` : fullName;
|
||||
};
|
||||
|
||||
const customerById = useMemo(() => {
|
||||
const map = new Map();
|
||||
(customers || []).forEach((customer) => {
|
||||
if (customer?.id) map.set(customer.id, customer);
|
||||
});
|
||||
return map;
|
||||
}, [customers]);
|
||||
|
||||
const resourceById = useMemo(() => {
|
||||
const map = new Map();
|
||||
(resources || []).forEach((resource) => {
|
||||
if (resource?.id) map.set(resource.id, resource);
|
||||
});
|
||||
return map;
|
||||
}, [resources]);
|
||||
|
||||
const calendar = useCalendarApp({
|
||||
views: [createViewMonthGrid(), createViewDay(), createViewWeek()],
|
||||
monthGridOptions: {
|
||||
@@ -106,8 +120,10 @@ const EventsCalendar = () => {
|
||||
setCurrentRangeEnd(range.end);
|
||||
const startDate = new Date(range.start);
|
||||
const endDate = new Date(range.end);
|
||||
setFromDate(new Date(startDate.getFullYear(), startDate.getMonth(), 1));
|
||||
setToDate(new Date(endDate.getFullYear(), endDate.getMonth() + 1, 0));
|
||||
const nextFromDate = new Date(startDate.getFullYear(), startDate.getMonth(), 1);
|
||||
const nextToDate = new Date(endDate.getFullYear(), endDate.getMonth() + 1, 0);
|
||||
setFromDate((prev) => (prev?.getTime?.() === nextFromDate.getTime() ? prev : nextFromDate));
|
||||
setToDate((prev) => (prev?.getTime?.() === nextToDate.getTime() ? prev : nextToDate));
|
||||
},
|
||||
onClickDate(date) {
|
||||
// Disabled: prevent creating new event by tapping calendar date
|
||||
@@ -191,19 +207,25 @@ const EventsCalendar = () => {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const requestId = ++eventsFetchRequestIdRef.current;
|
||||
const timer = setTimeout(() => {
|
||||
EventsService.getAllEvents({ from: EventsService.formatDate(fromDate), to: EventsService.formatDate(toDate) }).then(data => {
|
||||
if (requestId !== eventsFetchRequestIdRef.current) return;
|
||||
setAllEvents(data?.data || []);
|
||||
if (!hasMarkedInitialEventsLoadedRef.current) {
|
||||
hasMarkedInitialEventsLoadedRef.current = true;
|
||||
setInitialEventsLoaded(true);
|
||||
}
|
||||
}).catch(() => {
|
||||
if (requestId !== eventsFetchRequestIdRef.current) return;
|
||||
setAllEvents([]);
|
||||
if (!hasMarkedInitialEventsLoadedRef.current) {
|
||||
hasMarkedInitialEventsLoadedRef.current = true;
|
||||
setInitialEventsLoaded(true);
|
||||
}
|
||||
});
|
||||
}, 180);
|
||||
return () => clearTimeout(timer);
|
||||
}, [fromDate, toDate]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -230,14 +252,16 @@ const EventsCalendar = () => {
|
||||
if (customers?.length > 0 && resources.length > 0) {
|
||||
const orignialEvents = [...allEvents];
|
||||
setEvents(orignialEvents?.filter(item => item.type === 'medical')?.map((item) => {
|
||||
const customerField = item?.data?.customer ? (customers?.find(c => c.id === item?.data?.customer)?.name || item?.data?.client_name || '') : (item?.data?.client_name || '');
|
||||
const doctorField = item?.data?.resource ? ((resources?.find(r => r.id === item?.data?.resource))?.name || item?.data?.resource_name || '') : (item?.data?.resource_name || '');
|
||||
const customer = item?.data?.customer ? customerById.get(item?.data?.customer) : null;
|
||||
const resource = item?.data?.resource ? resourceById.get(item?.data?.resource) : null;
|
||||
const customerField = customer?.name || item?.data?.client_name || '';
|
||||
const doctorField = resource?.name || item?.data?.resource_name || '';
|
||||
item.event_id = item.id;
|
||||
item.customer = customerField;
|
||||
item.doctor = doctorField;
|
||||
item.phone = item?.data?.resource ? ((resources?.find(r => r.id === item?.data?.resource))?.phone || item?.data?.resource_phone || '') : (item?.data?.resource_phone || '');
|
||||
item.contact = item?.data?.resource? ((resources?.find(r => r.id === item?.data?.resource))?.contact || item?.data?.resource_contact || '') : (item?.data?.resource_contact || '')
|
||||
item.address = item?.data?.resource ? ((resources?.find(r => r.id === item?.data?.resource))?.address || item?.data?.resource_address || '') : (item?.data?.resource_address || '');
|
||||
item.phone = resource?.phone || item?.data?.resource_phone || '';
|
||||
item.contact = resource?.contact || item?.data?.resource_contact || '';
|
||||
item.address = resource?.address || item?.data?.resource_address || '';
|
||||
item.translation = item?.data?.interpreter || '';
|
||||
item.newPatient = item?.data?.new_patient || '';
|
||||
item.needId = item?.data?.need_id || '';
|
||||
@@ -259,11 +283,8 @@ const EventsCalendar = () => {
|
||||
item.maxTranslate2 = maxTranslate2;
|
||||
item.maxResource = maxResource;
|
||||
item.totalTranslate1 = totalTranslate1;
|
||||
setCurrentTotalTranslate1(item.totalTranslate1);
|
||||
item.totalTranslate2 = totalTranslate2;
|
||||
setCurrentTotalTranslate2(item.totalTranslate2);
|
||||
item.totalResource = totalResource;
|
||||
setCurrentTotalResource(item.totalResource);
|
||||
return item;
|
||||
})?.filter(item => {
|
||||
const includeDeleted = selectedColorFilters.includes('gray');
|
||||
@@ -282,7 +303,7 @@ const EventsCalendar = () => {
|
||||
return false;
|
||||
}));
|
||||
}
|
||||
}, [customers, resources, timeData, allEvents, selectedColorFilters])
|
||||
}, [customers, resources, timeData, allEvents, selectedColorFilters, customerById, resourceById])
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user