2025-07-04 14:13:25 -04:00

522 lines
24 KiB
JavaScript

import React, {useState, useEffect} from "react";
import { useNavigate } from "react-router-dom";
import { AuthService, EventsService, CustomerService, DriverService, ResourceService } from "../../services";
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 { ManageTable, Export } from "../../shared/components";
const EventsList = () => {
const navigate = useNavigate();
const [events, setEvents] = useState([]);
const [customers, setCustomers] = useState([]);
const [resources, setResources] = useState([]);
const [selectedDate, setSelectedDate] = useState(new Date());
const [sorting, setSorting] = useState({key: '', order: ''});
const [selectedItems, setSelectedItems] = useState([]);
const [showTransportationModal, setShowTransportationModal] = useState(false);
const [driver, setDriver] = useState(null);
const [driverOptions, setDriverOptions] = useState([]);
const [transportStartTime, setTransportStartTime] = useState(null);
const [transportOptionsList, setTransportationOptionsList] = useState([]);
const [transportSelected, setTransportSelected] = useState(null);
const [showDeletedItems, setShowDeletedItems] = useState(false);
const [columns, setColumns] = useState([
{
key: 'customer',
label:'Customer',
show: true
},
{
key: 'chinese_name',
label: 'Preferred Name',
show: true
},
{
key: 'member_type',
label: 'Member Type',
show: true
},
{
key: 'eyes_on',
label: 'Eyes-on',
show: true
},
{
key: 'doctor',
label: 'Doctor',
show: true
},
{
key: 'phone',
label: 'Phone',
show: true
},
{
key: 'address',
label: 'Address',
show: true
},
{
key: 'translation',
label: 'Translation',
show: true
},
{
key: 'newPatient',
label: 'New Patient',
show: true
},
{
key: 'needId',
label: 'Need ID',
show: true
},
{
key: 'disability',
label: 'Disability',
show: true
},
{
key: 'startTime',
label: 'Start Time',
show: true
},
{
key: 'fasting',
label: 'Fasting',
show: true
},
{
key: 'transportation',
label: 'Driver',
show: true
}
]);
const checkDisability = (customers, event) => {
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;
};
useEffect(() => {
if (!AuthService.canAccessLegacySystem()) {
window.alert('You haven\'t login yet OR this user does not have access to this page. Please change an admin account to login.')
AuthService.logout();
navigate(`/login`);
}
CustomerService.getAllCustomers().then((data) => {
setCustomers(data.data);
})
DriverService.getAllActiveDrivers().then((data) => {
console.log('drivers', data.data);
setDriverOptions(data.data);
})
ResourceService.getAll().then(data => {
setResources(data.data);
})
}, []);
useEffect(() => {
if (customers?.length > 0 && resources?.length>0) {
EventsService.getAllEvents({ date: EventsService.formatDate(selectedDate) }).then((data) => {
setEvents(data.data.filter((item) => {
item.customer = item?.data?.customer ? (customers.find(c=>c.id === item?.data?.customer)?.name || item?.data?.client_name || '') : (item?.data?.client_name || '');
item.doctor = item?.data?.resource ? (resources.find(r=> r.id === item?.data?.resource)?.name || item?.data?.resource_name || '') : (item?.data?.resource_name || '');
item.phone = item?.data?.resource ? (resources.find(r=> r.id === item?.data?.resource)?.phone || item?.data?.resource_phone || '') : (item?.data?.resource_phone || '');
item.address = item?.data?.resource ? (resources.find(r=> r.id === item?.data?.resource)?.address || item?.data?.resource_address || '') : (item?.data?.resource_address || '');
item.translation = item?.data?.interpreter || '';
item.newPatient = item?.data?.new_patient || '';
item.needId = item?.data?.need_id || '';
item.disability = item?.data?.disability || '';
item.member_type = item?.data?.customer ? (customers.find(c => c.id === item?.data?.customer)?.type || '') : '';
item.eyes_on = checkDisability(customers, item) ? 'Yes' : 'No';
item.startTime = item?.start_time? `${new Date(item?.start_time).toLocaleDateString()} ${new Date(item?.start_time).toLocaleTimeString()}` : '' ;
item.fasting = item?.data?.fasting || '';
item.chinese_name = item?.data?.customer ? customers.find(c => c.id === item?.data?.customer)?.name_cn : (customers?.find(c=> c?.name === item?.data?.client_name || c?.name === item?.target_name )?.name_cn || '');
item.transportation = item?.link_event_name || '';
item.dob = item?.data?.customer ? customers.find(c => c.id === item?.data?.customer)?.birth_date : (item?.data?.client_birth_date || '');
item.transMethod = item?.data?.trans_method;
return item;
}).filter(item => item.type === 'medical' && item.confirmed));
setTransportationOptionsList(data.data.filter((item) => item.type === 'transportation' && item.status === 'active'))
})
}
}, [selectedDate, resources, customers]);
useEffect(() => {
const newEvents = [...events];
const sortedEvents = sorting.key === '' ? newEvents : newEvents.sort((a, b) => {
return a[sorting.key].localeCompare(b[sorting.key]);
});
setEvents(
sorting.order === 'asc' ? sortedEvents : sortedEvents.reverse()
)
}, [sorting]);
const redirectToAdmin = () => {
navigate(`/medical`)
}
const goToEdit = (id) => {
navigate(`/medical/events/edit/${id}`)
}
const goToCreateNew = () => {
navigate(`/medical/events`)
}
const goToEventsCalendar = () => {
navigate(`/medical/events/calendar`)
}
const goToMultipleList = () => {
navigate(`/medical/events/multiple-list`)
}
const goToResourceList = () => {
navigate(`/medical/resources/list`)
}
const goToView = (id) => {
navigate(`/medical/events/${id}`)
}
const goToNextDay = () => {
setSelectedDate(new Date(selectedDate.setDate(selectedDate.getDate() + 1)));
}
const goToPreviousDay = () => {
setSelectedDate(new Date(selectedDate.setDate(selectedDate.getDate() - 1)));
}
const showDeleted = (value) => {
setShowDeletedItems(value === 'archivedEvents');
// Recover all filters
// setKeyword('');
setSorting({key: '', order: ''});
setSelectedItems([]);
}
const getSortingImg = (key) => {
return sorting.key === key ? (sorting.order === 'asc' ? 'up_arrow' : 'down_arrow') : 'default';
}
const sortTableWithField = (key) => {
let newSorting = {
key,
order: 'asc',
}
if (sorting.key === key && sorting.order === 'asc') {
newSorting = {...newSorting, order: 'desc'};
}
setSorting(newSorting);
}
const toggleSelectedAllItems = () => {
if (selectedItems.length !== events.length || selectedItems.length === 0) {
const newSelectedItems = [...events].map((event) => event.id);
setSelectedItems(newSelectedItems);
} else {
setSelectedItems([]);
}
}
const toggleItem = (id) => {
if (selectedItems.includes(id)) {
const newSelectedItems = [...selectedItems].filter((item) => item !== id);
setSelectedItems(newSelectedItems);
} else {
const newSelectedItems = [...selectedItems, id];
setSelectedItems(newSelectedItems);
}
}
const checkSelectAll = () => {
return selectedItems.length === events.length && selectedItems.length > 0;
}
const disableAssignTransportationButton = () => {
return (!transportSelected || transportSelected === '') || ((transportSelected === 'create_new') && (!driver || !transportStartTime || driver === '' || transportStartTime === ''));
}
const closePanel = () => {
setShowTransportationModal(false);
setTransportStartTime(null);
setDriver(null);
setTransportSelected(null);
}
const assignDriver = () => {
// if select create new event, then create a new transportation event first
if (transportSelected === 'create_new') {
const dateString = new Date().toLocaleDateString();
const startDateTime = new Date(`${dateString} ${transportStartTime}`);
const transportationParameter = {
title: `${driverOptions.find((item) => item.id === driver)?.name} ${startDateTime.toLocaleTimeString()}`,
description: 'transportatoin for med events',
type: 'transportation',
source_type: 'resource',
source_uuid: '',
target_type: 'staff',
target_uuid: driver,
start_time: startDateTime,
stop_time: startDateTime,
status: 'active',
create_by: JSON.parse(localStorage.getItem('user'))?.name,
create_date: new Date(),
edit_by: JSON.parse(localStorage.getItem('user'))?.name,
edit_date: new Date(),
edit_history: [{
employee: JSON.parse(localStorage.getItem('user'))?.name,
date: new Date()
}]
};
EventsService.createNewEvent(transportationParameter).then(data => {
const trans = data.data;
EventsService.assignTransportationToEvents({
transportationId: trans.id,
transportationName: trans.title,
eventIds: selectedItems
}).then(() => {
setSelectedItems([]);
EventsService.getAllEvents({ date: EventsService.formatDate(selectedDate) }).then((data) => {
const results = [...data.data];
const eventsResults = results.filter((item) => {
item.customer = item?.data?.customer ? (customers.find(c=>c.id === item?.data?.customer)?.name || item?.data?.client_name || '') : (item?.data?.client_name || '');
item.doctor = item?.data?.resource ? (resources.find(r=> r.id === item?.data?.resource)?.name || item?.data?.resource_name || '') : (item?.data?.resource_name || '');
item.phone = item?.data?.resource ? (resources.find(r=> r.id === item?.data?.resource)?.phone || item?.data?.resource_phone || '') : (item?.data?.resource_phone || '');
item.address = item?.data?.resource ? (resources.find(r=> r.id === item?.data?.resource)?.address || item?.data?.resource_address || '') : (item?.data?.resource_address || '');
item.translation = item?.data?.interpreter || '';
item.newPatient = item?.data?.new_patient || '';
item.needId = item?.data?.need_id || '';
item.disability = item?.data?.disability || '';
item.member_type = item?.data?.customer ? (customers.find(c => c.id === item?.data?.customer)?.type || '') : '';
item.eyes_on = checkDisability(customers, item) ? 'Yes' : 'No';
item.startTime = item?.start_time? `${new Date(item?.start_time).toLocaleDateString()} ${new Date(item?.start_time).toLocaleTimeString()}` : '' ;
item.fasting = item?.data?.fasting || '';
item.chinese_name = item?.data?.customer ? customers.find(c => c.id === item?.data?.customer)?.name_cn : (customers?.find(c=> c?.name === item?.data?.client_name || c?.name === item?.target_name )?.name_cn || '');
item.transportation = item?.link_event_name || '';
item.dob = item?.data?.customer ? customers.find(c => c.id === item?.data?.customer)?.birth_date : (item?.data?.client_birth_date || '');
item.transMethod = item?.data?.trans_method;
return item;
}).filter(item => item.type === 'medical' && item.confirmed);
const newEvents = [...eventsResults];
const sortedEvents = sorting.key === '' ? newEvents : newEvents.sort((a, b) => {
return a[sorting.key].localeCompare(b[sorting.key]);
});
setEvents(
sorting.order === 'asc' ? sortedEvents : sortedEvents.reverse()
)
setTransportationOptionsList(data.data.filter((item) => item.type === 'transportation' && item.status === 'active'));
closePanel();
})
});
}).catch((err) => console.log('Transportation Event Creation failed'))
} else {
if (transportSelected && transportSelected !== '') {
EventsService.assignTransportationToEvents({
transportationId: transportSelected,
transportationName: transportOptionsList.find((item) => item.id === transportSelected)?.title,
eventIds: selectedItems
}).then(() => {
setSelectedItems([]);
EventsService.getAllEvents({ date: EventsService.formatDate(selectedDate) }).then((data) => {
const results = [...data.data];
const eventsResults = results.filter((item) => {
item.customer = item?.data?.customer ? (customers.find(c=>c.id === item?.data?.customer)?.name || item?.data?.client_name || '') : (item?.data?.client_name || '');
item.doctor = item?.data?.resource ? (resources.find(r=> r.id === item?.data?.resource)?.name || item?.data?.resource_name || '') : (item?.data?.resource_name || '');
item.phone = item?.data?.resource ? (resources.find(r=> r.id === item?.data?.resource)?.phone || item?.data?.resource_phone || '') : (item?.data?.resource_phone || '');
item.address = item?.data?.resource ? (resources.find(r=> r.id === item?.data?.resource)?.address || item?.data?.resource_address || '') : (item?.data?.resource_address || '');
item.translation = item?.data?.interpreter || '';
item.newPatient = item?.data?.new_patient || '';
item.needId = item?.data?.need_id || '';
item.disability = item?.data?.disability || '';
item.member_type = item?.data?.customer ? (customers.find(c => c.id === item?.data?.customer)?.type || '') : '';
item.eyes_on = checkDisability(customers, item) ? 'Yes' : 'No';
item.startTime = item?.start_time? `${EventsService.formatDate(new Date(item?.start_time))} ${new Date(item?.start_time).toLocaleTimeString('en-US', { hour: '2-digit', minute: 'numeric', hour12: true })}` : '' ;
item.fasting = item?.data?.fasting || '';
item.chinese_name = item?.data?.customer ? customers.find(c => c.id === item?.data?.customer)?.name_cn : (customers?.find(c=> c?.name === item?.data?.client_name || c?.name === item?.target_name )?.name_cn || '');
item.transportation = item?.link_event_name || '';
item.dob = item?.data?.customer ? customers.find(c => c.id === item?.data?.customer)?.birth_date : (item?.data?.client_birth_date || '');
item.transMethod = item?.data?.trans_method;
return item;
}).filter(item => item.type === 'medical' && item.confirmed);
const newEvents = [...eventsResults];
const sortedEvents = sorting.key === '' ? newEvents : newEvents.sort((a, b) => {
return a[sorting.key].localeCompare(b[sorting.key]);
});
setEvents(
sorting.order === 'asc' ? sortedEvents : sortedEvents.reverse()
)
// setTransportationOptionsList(data.data.filter((item) => item.type === 'transportation' && item.status === 'active'));
closePanel();
})
});
}
};
};
const table = (statusParam) => <div className="list row mb-4">
<div className="col-md-12">
<table className="personnel-info-table">
<thead>
<tr>
<th className="th-checkbox"><input type="checkbox" checked={checkSelectAll()} onClick={() => toggleSelectedAllItems()}></input></th>
<th className="th-index">No.</th>
{
columns.filter(col => col.show).map((column, index) => <th className="sortable-header" key={index}>
{column.label} <span className="float-right" onClick={() => sortTableWithField(column.key)}><img src={`/images/${getSortingImg(column.key)}.png`}></img></span>
</th>)
}
<th>Customer Date of Birth</th>
<th>Transportation</th>
</tr>
</thead>
<tbody>
{
events && events.filter(event => event.status === statusParam).map((medicalEvent, index) => <tr key={medicalEvent.id}>
<td className="td-checkbox"><input type="checkbox" checked={selectedItems.includes(medicalEvent.id)} onClick={()=>toggleItem(medicalEvent?.id)}/></td>
<td className="td-index">{index + 1}</td>
{columns.find(col => col.key === 'customer')?.show && <td>{medicalEvent?.customer}</td>}
{columns.find(col => col.key === 'chinese_name')?.show && <td>{medicalEvent?.chinese_name}</td>}
{columns.find(col => col.key === 'member_type')?.show && <td>{medicalEvent?.member_type}</td>}
{columns.find(col => col.key === 'eyes_on')?.show && <td>{medicalEvent?.eyes_on}</td>}
{columns.find(col => col.key === 'doctor')?.show && <td>{medicalEvent?.doctor}</td>}
{columns.find(col => col.key === 'phone')?.show && <td>{medicalEvent?.phone}</td>}
{columns.find(col => col.key === 'address')?.show && <td>{medicalEvent?.address}</td>}
{columns.find(col => col.key === 'translation')?.show && <td>{medicalEvent?.translation}</td>}
{columns.find(col => col.key === 'newPatient')?.show && <td>{medicalEvent?.newPatient}</td>}
{columns.find(col => col.key === 'needId')?.show && <td>{medicalEvent?.needId}</td>}
{columns.find(col => col.key === 'disability')?.show && <td>{medicalEvent?.disability}</td>}
{columns.find(col => col.key === 'startTime')?.show && <td>{medicalEvent?.startTime}</td>}
{columns.find(col => col.key === 'fasting')?.show && <td>{medicalEvent?.fasting}</td>}
{columns.find(col => col.key === 'transportation')?.show && <td>{medicalEvent?.transportation}</td>}
<td>{medicalEvent?.dob}</td>
<td>{medicalEvent?.transMethod}</td>
</tr>)
}
</tbody>
</table>
</div>
</div>;
return (
<>
<div className="list row mb-4">
<Breadcrumb>
<Breadcrumb.Item>Medical</Breadcrumb.Item>
<Breadcrumb.Item active>
Appointment Information
</Breadcrumb.Item>
</Breadcrumb>
<div className="col-md-12 text-primary">
<h4>
Medical Event One-Day List (With Driver Assignment)
{/* <button className="btn btn-primary btn-sm" onClick={() => {goToCreateNew()}}>Create New Customer</button>
<button className="btn btn-link btn-sm" onClick={() => {redirectToAdmin()}}>Back</button> */}
</h4>
</div>
</div>
<div className="app-main-content-list-container">
<div className="app-main-content-list-func-container">
<Tabs defaultActiveKey="activeEvents" id="requests-tab" onSelect={(k) => showDeleted(k)}>
<Tab eventKey="activeEvents" title="Active Appointments">
<div className="app-main-content-fields-section with-function">
<Button className="me-2" variant="outline-primary" size="sm" onClick={() => goToPreviousDay()} > {'<'} </Button>
<DatePicker className="me-2" selected={selectedDate} onChange={(v) => setSelectedDate(v)} />
<Button className="me-2 ms-2" variant="outline-primary" size="sm" onClick={() => goToNextDay()}> {'>'} </Button>
<Button className="me-2" variant="primary" size="sm" disabled={selectedItems.length === 0} onClick={() => setShowTransportationModal(true)}> + Show Assign Transportation Panel</Button>
</div>
{table('active')}
</Tab>
<Tab eventKey="archivedEvents" title="Archived Appointments">
<div className="app-main-content-fields-section with-function">
<Button className="me-2" variant="outline-primary" size="sm" onClick={() => goToPreviousDay()} > {'<'} </Button>
<DatePicker className="me-2" selected={selectedDate} onChange={(v) => setSelectedDate(v)} />
<Button className="me-2 ms-2" variant="outline-primary" size="sm" onClick={() => goToNextDay()}> {'>'} </Button>
</div>
{table('inactive')}
</Tab>
</Tabs>
<div className="list-func-panel">
{/* <input className="me-2 with-search-icon" type="text" placeholder="Search" value={keyword} onChange={(e) => setKeyword(e.currentTarget.value)} /> */}
{/* <button className="btn btn-primary me-2"><Filter size={16} className="me-2"></Filter>Filter</button> */}
<ManageTable columns={columns} onColumnsChange={setColumns} />
<button className="btn btn-primary me-2" onClick={() => goToCreateNew()}><Plus size={16}></Plus>Add New Medical Appointment</button>
<Export
columns={columns}
data={events.filter(event => event.status === (showDeletedItems ? 'inactive' : 'active'))}
filename="events"
/>
</div>
</div>
</div>
<Modal show={showTransportationModal} onHide={() => closePanel()}>
<Modal.Header closeButton>
<Modal.Title>Assign Transportations Panel</Modal.Title>
</Modal.Header>
<Modal.Body>
<>
<div className="app-main-content-fields-section">
<div className="mb-4 me-4"></div>
<div className="field-label">Select Transportation</div>
<select value={transportSelected} onChange={(e)=>{setTransportSelected(e.currentTarget.value)}}>
<option value=""></option>
<option value="create_new">Create A New Transportation</option>
{transportOptionsList.map((item) => <option key={item.id} value={item.id}>{item.title}</option>)}
</select>
</div>
{transportSelected === 'create_new' && (
<>
<hr/>
<div>
Start Time:
<div>
<TimePicker disableClock={true} value={transportStartTime} onChange={setTransportStartTime} />
</div>
</div>
</>)
}
{transportSelected === 'create_new' && (
<>
<hr/>
<div>
Driver:
<div>
<select value={driver} onChange={(e)=>{setDriver(e.currentTarget.value)}}>
<option value=""></option>
{
driverOptions.map((item) => <option key={item.id} value={item.id}>{item.name}</option>)
}
</select>
</div>
</div>
</>)
}
</>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={() => closePanel()}>
Close
</Button>
<Button disabled={disableAssignTransportationButton()} variant="primary" onClick={() => assignDriver()}>
Assign Transportation
</Button>
</Modal.Footer>
</Modal>
</>
)
};
export default EventsList;