import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import dayjs from 'dayjs'; import isToday from 'dayjs/plugin/isToday'; import utc from 'dayjs/plugin/utc'; import { Button, DataTable, DataTableSkeleton, Layer, OverflowMenu, OverflowMenuItem, Pagination, Search, Table, TableBody, TableCell, TableContainer, TableExpandedRow, TableExpandHeader, TableExpandRow, TableHead, TableHeader, TableRow, Tile, } from '@carbon/react'; import { Download } from '@carbon/react/icons'; import { ConfigurableLink, formatDate, formatDatetime, isDesktop, parseDate, useConfig, useLayoutType, launchWorkspace, usePagination, } from '@openmrs/esm-framework'; import { EmptyState } from '../../empty-state/empty-state.component'; import { exportAppointmentsToSpreadsheet } from '../../helpers/excel'; import { useTodaysVisits } from '../../hooks/useTodaysVisits'; import { type Appointment } from '../../types'; import { type ConfigObject } from '../../config-schema'; import { getPageSizes, useAppointmentSearchResults } from '../utils'; import AppointmentActions from './appointments-actions.component'; import AppointmentDetails from '../details/appointment-details.component'; import styles from './appointments-table.scss'; dayjs.extend(utc); dayjs.extend(isToday); interface AppointmentsTableProps { appointments: Array; isLoading: boolean; tableHeading: string; hasActiveFilters?: boolean; } const AppointmentsTable: React.FC = ({ appointments, isLoading, tableHeading, hasActiveFilters, }) => { const { t } = useTranslation(); const [pageSize, setPageSize] = useState(25); const [searchString, setSearchString] = useState(''); const searchResults = useAppointmentSearchResults(appointments, searchString); const { results, goTo, currentPage } = usePagination(searchResults, pageSize); const { customPatientChartUrl, patientIdentifierType } = useConfig(); const { visits } = useTodaysVisits(); const layout = useLayoutType(); const responsiveSize = isDesktop(layout) ? 'sm' : 'lg'; const headerData = [ { header: t('patientName', 'Patient name'), key: 'patientName', }, { header: t('location', 'Location'), key: 'location', }, { header: t('serviceType', 'Service type'), key: 'serviceType', }, { header: t('status', 'Status'), key: 'status', }, ]; const rowData = results?.map((appointment) => { let patientIdentifier = '--'; let patientName = '--'; if (appointment.patient) { if ( 'display' in appointment.patient && typeof appointment.patient.display === 'string' && appointment.patient.display ) { const [identifier, ...nameParts] = (appointment.patient.display as string).split(' - '); patientIdentifier = identifier || appointment.patient.identifier || '--'; patientName = nameParts.join(' - ') || appointment.patient.name || '--'; } else if (appointment.patient.name) { patientName = appointment.patient.name; patientIdentifier = appointment.patient.identifier || '--'; } } let locationDisplay = '--'; if (appointment.location) { if ( 'display' in appointment.location && typeof appointment.location.display === 'string' && appointment.location.display ) { locationDisplay = appointment.location.display as string; } else if (appointment.location.name) { locationDisplay = appointment.location.name; } } let providerDisplay = '--'; if (appointment.provider) { if ( 'display' in appointment.provider && typeof appointment.provider.display === 'string' && appointment.provider.display ) { providerDisplay = appointment.provider.display as string; } else if (appointment.provider.name) { providerDisplay = appointment.provider.name; } } return { id: String(appointment.appointmentId), patientName: ( {patientName} ), location: locationDisplay, serviceType: appointment.service?.name || '--', provider: providerDisplay, dateTime: appointment.appointmentDate ? formatDatetime(new Date(appointment.appointmentDate)) : '--', status: , }; }); if (isLoading) { return ; } if (hasActiveFilters && !appointments?.length) { return (

{t('noMatchingAppointments', 'No matching appointments found')}

{t('checkFilters', 'Check the filters above')}

); } if (!appointments?.length) { return ( launchWorkspace('search-patient')} /> ); } return (

{`${t(tableHeading)} ${t('appointments', 'Appointments')}`}

setSearchString(event.target.value)} size={responsiveSize} />
{({ rows, headers, getExpandHeaderProps, getHeaderProps, getRowProps, getTableProps, getTableContainerProps, }) => ( <> {headers.map((header) => ( {header.header} ))} {rows.map((row) => { const matchingAppointment = appointments.find( (appointment) => String(appointment.appointmentId) === row.id, ); if (!matchingAppointment) { return null; } const patientUuid = matchingAppointment.patient?.uuid; const visitDate = dayjs(matchingAppointment.startDateTime); const isFutureAppointment = visitDate.isAfter(dayjs()); const isTodayAppointment = visitDate.isToday(); const hasActiveVisitToday = visits?.some( (visit) => visit?.patient?.uuid === patientUuid && visit?.startDatetime, ); return ( {row.cells.map((cell) => ( {cell.value?.content ?? cell.value} ))} {isFutureAppointment || (isTodayAppointment && !hasActiveVisitToday) ? ( launchWorkspace('appointments-form-workspace', { patientUuid: matchingAppointment.patient.uuid, appointment: matchingAppointment, context: 'editing', workspaceTitle: t('editAppointment', 'Edit appointment'), }) } /> ) : null} {row.isExpanded ? ( ) : ( )} ); })}
{rows.length === 0 ? (

{t('noAppointmentsToDisplay', 'No appointments to display')}

{t('checkFilters', 'Check the filters above')}

) : null} )}
{ goTo(page); setPageSize(pageSize); }} totalItems={appointments.length ?? 0} />
); }; export default AppointmentsTable;