This commit is contained in:
2026-02-09 15:06:55 -05:00
parent 0a9ccfecf8
commit 9fa92a1dce
7 changed files with 115 additions and 44 deletions

BIN
.DS_Store vendored

Binary file not shown.

2
.gitignore vendored
View File

@@ -15,7 +15,7 @@
# misc
.DS_Store
**/.DS_Store
.env.local
.env.development.local
.env.test.local

BIN
app/.DS_Store vendored

Binary file not shown.

View File

@@ -692,10 +692,29 @@ input[type="number"] {
/* box-sizing: border-box; */
}
/* Exclude react-time-picker inputs from the padding rules above */
.react-time-picker__inputGroup__input {
padding-left: initial;
padding-right: initial;
/* Exclude react-time-picker inputs from the global input styles above */
.react-time-picker .react-time-picker__inputGroup__input {
height: auto !important;
padding-left: 1px !important;
padding-right: 1px !important;
border: none !important;
border-radius: 0 !important;
box-sizing: content-box !important;
min-width: 0;
font-variant-numeric: tabular-nums;
letter-spacing: normal;
text-align: center;
}
/* Add spacing between the ":" divider and the minute input */
.react-time-picker .react-time-picker__inputGroup__divider {
padding: 0 3px;
}
/* Ensure the leading zero and minute digit inputs have no extra spacing */
.react-time-picker .react-time-picker__inputGroup__leadingZero {
padding: 0;
margin: 0;
}
input[type="email"] {

View File

@@ -1,4 +1,4 @@
import React, {useState, useEffect} from "react";
import React, {useState, useEffect, useRef} from "react";
import { useNavigate } from "react-router-dom";
import { AuthService, EventsService, CustomerService, ResourceService } from "../../services";
import moment from 'moment';
@@ -24,6 +24,8 @@ import { Archive, PencilSquare, Filter } from "react-bootstrap-icons";
const EventsCalendar = () => {
const navigate = useNavigate();
const [events, setEvents] = useState([]);
const calendarColumnRef = useRef(null);
const [listHeight, setListHeight] = useState(null);
const [customers, setCustomers] = useState([]);
const [resources, setResources] = useState([]);
const [fromDate, setFromDate] = useState(new Date(new Date().getFullYear(), new Date().getMonth(), 1));
@@ -212,6 +214,27 @@ const EventsCalendar = () => {
}
}, [events, currentRangeStart, currentRangeEnd]);
// Sync list column height with calendar column height
useEffect(() => {
const updateListHeight = () => {
if (calendarColumnRef.current) {
const calendarHeight = calendarColumnRef.current.offsetHeight;
setListHeight(calendarHeight);
}
};
// Initial measurement after render
const timer = setTimeout(updateListHeight, 100);
// Update on window resize
window.addEventListener('resize', updateListHeight);
return () => {
clearTimeout(timer);
window.removeEventListener('resize', updateListHeight);
};
}, [events]);
const redirectToAdmin = () => {
@@ -357,38 +380,68 @@ const EventsCalendar = () => {
<div className="app-main-content-list-func-container">
<Tabs defaultActiveKey="eventsCalendar" id="events-calendar-tab">
<Tab eventKey="eventsCalendar" title="Medical Appointments">
<div className="multi-columns-container">
<div className="column-container" style={{'minWidth': '1000px'}}>
{calendar && <ScheduleXCalendar customComponents={customComponents} calendarApp={calendar} />}
</div>
<div className="column-container">
<div className="column-card" style={{ maxHeight: '800px', overflowY: 'auto', overflowX: 'hidden' }}>
<h6 className="text-primary me-4">List</h6>
{
Array.from(groupedEvents?.keys())?.map((key) => {
return <div key={key}>
<h6 className="text-primary me-2">{key}</h6>
{
groupedEvents.get(key).map(eventItem => <div
key={eventItem.id}
className={`event-${eventItem.color || 'primary'} mb-4 event-list-item-container`}
onClick={() => goToView(eventItem.id)}
style={{ cursor: 'pointer' }}
>
<div className="event-item-flex">
<div className="sx__month-agenda-event__title">{`${moment(eventItem?.start_time).format('hh:mm A')}: ${formatFullName(eventItem.customer)}`}</div>
</div>
<div className="sx__event-modal__time with-padding">{`provider: ${eventItem?.doctor}`}</div>
</div>)
}
</div>
})
}
</div>
</div>
</div>
</Tab>
</Tabs>
<div className="multi-columns-container" style={{ display: 'flex', alignItems: 'flex-start', width: '100%' }}>
<div className="column-container" ref={calendarColumnRef} style={{ minWidth: '1000px', flexShrink: 0, display: 'flex', flexDirection: 'column' }}>
{calendar && <ScheduleXCalendar customComponents={customComponents} calendarApp={calendar} />}
{/* Legend */}
<div className="calendar-legend mt-3">
<h6 className="text-muted mb-2" style={{ fontSize: '12px' }}>Legend:</h6>
<div className="d-flex flex-wrap gap-3">
{EventsService.labelOptions?.map((item) => (
<div key={item.value} className="d-flex align-items-center">
<span
className={`event-${item.value}`}
style={{
width: '16px',
height: '16px',
borderRadius: '4px',
display: 'inline-block',
marginRight: '6px'
}}
></span>
<span style={{ fontSize: '12px' }}>{item.label}</span>
</div>
))}
</div>
</div>
</div>
<div className="column-container calendar-list-column" style={{ display: 'flex', flexDirection: 'column', flex: 1, minWidth: 0 }}>
<div className="column-card" style={{ height: listHeight ? `${listHeight}px` : 'auto', overflowY: 'auto', overflowX: 'hidden', padding: '16px', display: 'flex', flexDirection: 'column', width: '100%', boxSizing: 'border-box' }}>
<h6 className="text-primary mb-3">List</h6>
<div style={{ flex: 1, overflowY: 'auto', width: '100%' }}>
{(!groupedEvents || groupedEvents.size === 0) && (
<div style={{ padding: '24px', textAlign: 'center', color: '#999' }}>
No events for this period
</div>
)}
{
Array.from(groupedEvents?.keys())?.map((key) => {
return <div key={key}>
<h6 className="text-primary me-2">{key}</h6>
{
groupedEvents.get(key).map(eventItem => <div
key={eventItem.id}
className={`event-${eventItem.color || 'primary'} mb-3 event-list-item-container`}
onClick={() => goToView(eventItem.id)}
style={{ cursor: 'pointer', padding: '8px 12px', borderRadius: '4px' }}
>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span className="sx__month-agenda-event__title">{formatFullName(eventItem.customer)}</span>
<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>
</div>)
}
</div>
})
}
</div>
</div>
</div>
</div>
<div className="list-func-panel">
<Dropdown
key={'event-calendar-filter'}

View File

@@ -5,6 +5,7 @@ import DatePicker from "react-datepicker";
import { Spinner, Breadcrumb, BreadcrumbItem, Tabs, Tab, Button, Modal } from "react-bootstrap";
import { Columns, Download, Filter, PencilSquare, PersonSquare, Plus } from "react-bootstrap-icons";
import TimePicker from 'react-time-picker';
import 'react-time-picker/dist/TimePicker.css';
import { ManageTable, Export } from "../../shared/components";
const EventsList = () => {

View File

@@ -521,10 +521,8 @@ const InfoScreen = () => {
(customers.find(c => c.id === item?.data?.customer)?.name || item?.data?.client_name || '') :
(item?.data?.client_name || '');
// Add location/address
item.location = item?.data?.resource ?
(resources.find(r => r.id === item?.data?.resource)?.address || item?.data?.resource_address || '') :
(item?.data?.resource_address || '');
// Add driver info (from linked transportation event)
item.driverInfo = item?.link_event_name || '';
// Format start time
item.startTime = item?.start_time ?
@@ -647,7 +645,7 @@ const InfoScreen = () => {
<tr>
<th>Time</th>
<th>Customer</th>
<th>Location</th>
<th>Driver</th>
</tr>
</thead>
<tbody>
@@ -656,7 +654,7 @@ const InfoScreen = () => {
<tr key={medicalEvent.id}>
<td>{medicalEvent.startTime}</td>
<td>{medicalEvent.customer}</td>
<td>{medicalEvent.location}</td>
<td>{medicalEvent.driverInfo}</td>
</tr>
))
) : (
@@ -934,7 +932,7 @@ const InfoScreen = () => {
<tr>
<th>Time</th>
<th>Customer</th>
<th>Location</th>
<th>Driver</th>
</tr>
</thead>
<tbody>
@@ -943,7 +941,7 @@ const InfoScreen = () => {
<tr key={medicalEvent.id}>
<td>{medicalEvent.startTime}</td>
<td>{medicalEvent.customer}</td>
<td>{medicalEvent.location}</td>
<td>{medicalEvent.driverInfo}</td>
</tr>
))
) : (