fix
All checks were successful
Build And Deploy Main / build-and-deploy (push) Successful in 40s

This commit is contained in:
2026-03-18 11:54:16 -04:00
parent 4fabab69d0
commit 84d1e4ca47
4 changed files with 89 additions and 13 deletions

View File

@@ -607,7 +607,11 @@ const EventsCalendar = () => {
}
const disableEvent = (id) => {
if (!AuthService.canEditCalendarTab(currentTab)) return;
if (currentTab === 'medicalCalendar') {
if (!AuthService.canEditMedicalEvents()) return;
} else {
if (!AuthService.canEditCalendarTab(currentTab)) return;
}
// Handle recurring event instances
const isRecurInstance = typeof id === 'string' && id.startsWith('recur-');
if (isRecurInstance) {
@@ -921,7 +925,7 @@ const EventsCalendar = () => {
style={{ cursor: 'pointer' }}
title="Edit"
/>}
{currentTab !== 'medicalCalendar' && AuthService.canEditCalendarTab(currentTab) && <Archive
{((currentTab === 'medicalCalendar' && AuthService.canEditMedicalEvents()) || (currentTab !== 'medicalCalendar' && AuthService.canEditCalendarTab(currentTab))) && <Archive
size={16}
onClick={() => { setDeleteTargetId(calendarEvent?.id); setShowDeleteConfirm(true); }}
style={{ cursor: 'pointer' }}

View File

@@ -13,7 +13,7 @@ import {
import { createEventsServicePlugin } from '@schedule-x/events-service';
import { createEventModalPlugin} from '@schedule-x/event-modal';
import '@schedule-x/theme-default/dist/calendar.css';
import { Filter } from "react-bootstrap-icons";
import { Archive, Filter, PencilSquare } from "react-bootstrap-icons";
import DatePicker from "react-datepicker";
@@ -40,6 +40,8 @@ const EventsCalendar = () => {
const [currentRangeStart, setCurrentRangeStart] = useState(null);
const [currentRangeEnd, setCurrentRangeEnd] = useState(null);
const [showCreationModal, setShowCreationModal] = useState(false);
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
const [deleteTargetId, setDeleteTargetId] = useState(null);
const [newEventStartDateTime, setNewEventStartDateTime] = useState(new Date());
const [newEventEndDateTime, setNewEventEndDateTime] = useState(new Date());
const [newEventColor, setNewEventColor] = useState('');
@@ -270,6 +272,28 @@ const EventsCalendar = () => {
navigate(`/medical/events/${id}`)
}
const goToEdit = (id) => {
if (!AuthService.canEditMedicalEvents()) return;
navigate(`/medical/events/edit/${id}?from=calendar`)
}
const disableEvent = (id) => {
if (!AuthService.canEditMedicalEvents()) return;
const currentEvent = events.find(item => item.id === id);
EventsService.disableEvent(id, {
status: 'inactive',
edit_by: localStorage.getItem('user') && JSON.parse(localStorage.getItem('user'))?.name,
edit_date: new Date(),
edit_history: currentEvent?.edit_history
? [...currentEvent.edit_history, { employee: localStorage.getItem('user') && JSON.parse(localStorage.getItem('user'))?.name, date: new Date() }]
: [{ employee: localStorage.getItem('user') && JSON.parse(localStorage.getItem('user'))?.name, date: new Date() }]
}).then(() => {
EventsService.getAllEvents({ from: EventsService.formatDate(fromDate), to: EventsService.formatDate(toDate) }).then((data) => {
setAllEvents(data?.data);
})
});
}
const toggleColorFilter = (colorValue) => {
setSelectedColorFilters(prev =>
prev.includes(colorValue)
@@ -294,6 +318,20 @@ const EventsCalendar = () => {
<div className="sx__event-modal__title">{calendarEvent?.customer}</div>
{calendarEvent?.doctor && <div className="sx__event-modal__time">{`${calendarEvent?.doctor}`}</div>}
<div className="sx__event-modal__time">{`${calendarEvent?.start}`}</div>
{AuthService.canEditMedicalEvents() && <div className="sx__event-modal__time" style={{ display: 'flex', gap: '12px', marginTop: '8px' }}>
<PencilSquare
size={16}
onClick={() => goToEdit(calendarEvent?.id)}
style={{ cursor: 'pointer' }}
title="Edit"
/>
<Archive
size={16}
onClick={() => { setDeleteTargetId(calendarEvent?.id); setShowDeleteConfirm(true); }}
style={{ cursor: 'pointer' }}
title="Delete"
/>
</div>}
</>
}
};
@@ -412,6 +450,20 @@ const EventsCalendar = () => {
<span style={{ fontSize: '12px' }}>{moment(eventItem?.start_time).format('HH:mm')} - {moment(eventItem?.stop_time || eventItem?.start_time).format('HH:mm')}</span>
</div>
<div className="sx__event-modal__time" style={{ fontSize: '12px', marginTop: '4px' }}>Provider: {eventItem?.doctor || '-'}</div>
{AuthService.canEditMedicalEvents() && <div style={{ display: 'flex', gap: '10px', marginTop: '6px' }} onClick={(e) => e.stopPropagation()}>
<PencilSquare
size={14}
onClick={() => goToEdit(eventItem?.id)}
style={{ cursor: 'pointer' }}
title="Edit"
/>
<Archive
size={14}
onClick={() => { setDeleteTargetId(eventItem?.id); setShowDeleteConfirm(true); }}
style={{ cursor: 'pointer' }}
title="Delete"
/>
</div>}
</div>)
}
</div>
@@ -592,6 +644,22 @@ const handleSave = () => {
</Button>
</Modal.Footer>
</Modal>
<Modal show={showDeleteConfirm} onHide={() => { setShowDeleteConfirm(false); setDeleteTargetId(null); }} size="sm" centered>
<Modal.Header closeButton>
<Modal.Title>Confirm Delete</Modal.Title>
</Modal.Header>
<Modal.Body>
Are you sure you want to delete this event?
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" size="sm" onClick={() => { setShowDeleteConfirm(false); setDeleteTargetId(null); }}>
Cancel
</Button>
<Button variant="danger" size="sm" onClick={() => { disableEvent(deleteTargetId); setShowDeleteConfirm(false); setDeleteTargetId(null); }}>
Delete
</Button>
</Modal.Footer>
</Modal>
</div>
</div>
</>

View File

@@ -97,6 +97,11 @@ const EventsList = () => {
const currentCustomer = customers?.find(c => c?.id === event?.data?.customer || c?.name === event?.data?.client_name || c?.name === event?.target_name);
return currentCustomer?.disability || event?.data?.disability?.toLowerCase() === 'yes' || false;
};
const isEligibleDriverOption = (employee) => {
const roles = Array.isArray(employee?.roles) ? employee.roles.map((role) => `${role || ''}`.toLowerCase()) : [];
const permissions = Array.isArray(employee?.permissions) ? employee.permissions.map((permission) => `${permission || ''}`.toLowerCase()) : [];
return roles.includes('driver') || permissions.includes('isdriver');
};
// Default sort: 1) driver name ascending, 2) start time early to late, 3) address ascending, 4) language (empty first)
const applyDefaultSort = (eventsArray) => {
@@ -141,8 +146,11 @@ const EventsList = () => {
setCustomers(data.data);
})
DriverService.getAllActiveDrivers().then((data) => {
console.log('drivers', data.data);
setDriverOptions(data.data);
const filteredDrivers = (data?.data || [])
.filter((employee) => employee?.status === 'active')
.filter(isEligibleDriverOption)
.sort((a, b) => `${a?.name || ''}`.localeCompare(`${b?.name || ''}`));
setDriverOptions(filteredDrivers);
})
ResourceService.getAll().then(data => {
setResources(data.data);

View File

@@ -179,9 +179,10 @@ const RouteEdit = () => {
if (!validateRoute()) {
return;
}
// Do not persist scheduled-absence entries into route_customer_list.
// Keep scheduled-absence customers in route assignment payload; only skip transient
// attendance-derived placeholder rows if any are ever injected into this list.
const filteredCustomerList = (newCustomerList || []).filter(
(customer) => customer?.customer_route_status !== PERSONAL_ROUTE_STATUS.SCHEDULED_ABSENT
(customer) => customer?._attendance_based !== true
);
const existingRouteCustomers = currentRoute?.route_customer_list || [];
const existingByCustomerId = new Map(existingRouteCustomers.map((c) => [c?.customer_id, c]));
@@ -677,12 +678,7 @@ const RouteEdit = () => {
const mergedAbsentIds = Array.from(new Set([].concat(existingScheduledAbsentIds, attendanceBasedAbsentIds)));
return (
<RouteCustomerEditor
currentRoute={currentRoute ? {
...currentRoute,
route_customer_list: currentRoute.route_customer_list?.filter(
customer => customer?.customer_route_status !== PERSONAL_ROUTE_STATUS.SCHEDULED_ABSENT
) || []
} : undefined}
currentRoute={currentRoute}
setNewCustomerList={setNewCustomerList}
onAddCustomer={(addFn) => setAddCustomerToRoute(() => addFn)}
scheduledAbsentCustomerIds={mergedAbsentIds}