@ampath/esm-dha-workflow-app 4.0.0-next.68 → 4.0.0-next.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/110.js +1 -0
- package/dist/110.js.map +1 -0
- package/dist/125.js +1 -1
- package/dist/264.js +1 -1
- package/dist/321.js +1 -1
- package/dist/474.js +1 -0
- package/dist/474.js.map +1 -0
- package/dist/547.js +1 -0
- package/dist/547.js.map +1 -0
- package/dist/605.js +1 -1
- package/dist/744.js +1 -1
- package/dist/752.js +1 -1
- package/dist/826.js +1 -1
- package/dist/826.js.map +1 -1
- package/dist/93.js +1 -1
- package/dist/93.js.map +1 -1
- package/dist/968.js +1 -0
- package/dist/968.js.map +1 -0
- package/dist/975.js +1 -1
- package/dist/986.js +1 -1
- package/dist/esm-dha-workflow-app.js +1 -1
- package/dist/esm-dha-workflow-app.js.buildmanifest.json +115 -66
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/admissions/admission-request-list/admission-request-list.scss +0 -0
- package/src/admissions/admission-request-list/admission-request-list.tsx +134 -0
- package/src/admissions/admissions-dashboard.component.scss +15 -0
- package/src/admissions/admissions-dashboard.component.tsx +147 -0
- package/src/admissions/admissions.resource.ts +101 -0
- package/src/admissions/admitted-list/admitted-patients-list.tsx +130 -0
- package/src/admissions/constants/index.ts +33 -0
- package/src/admissions/discharged-list/discharged-list.scss +0 -0
- package/src/admissions/discharged-list/discharged-list.tsx +58 -0
- package/src/admissions/modal/admit-elsewhere/admit-elsewhere.modal.scss +23 -0
- package/src/admissions/modal/admit-elsewhere/admit-elsewhere.modal.tsx +156 -0
- package/src/admissions/modal/admit-patient/admit-patient.modal.scss +0 -0
- package/src/admissions/modal/admit-patient/admit-patient.modal.tsx +109 -0
- package/src/admissions/modal/bed-swap/bed-swap.modal.scss +0 -0
- package/src/admissions/modal/bed-swap/bed-swap.modal.tsx +102 -0
- package/src/admissions/modal/cancel-admission-request/cancel-admission-request.scss +11 -0
- package/src/admissions/modal/cancel-admission-request/cancel-admission-request.tsx +103 -0
- package/src/admissions/modal/discharge/discharge-patient.modal.scss +13 -0
- package/src/admissions/modal/discharge/discharge-patient.modal.tsx +84 -0
- package/src/admissions/types/index.ts +192 -0
- package/src/dashboard-meta/admissions-dashboard.meta.ts +6 -0
- package/src/index.ts +7 -0
- package/src/root.component.tsx +2 -0
- package/src/routes.json +17 -0
- package/src/service-queues/service-queue/stats/stat-card/stat-card.component.tsx +5 -2
- package/src/shared/ui/stat-card/start-card.component.tsx +0 -0
- package/dist/838.js +0 -1
- package/dist/838.js.map +0 -1
- package/dist/863.js +0 -1
- package/dist/863.js.map +0 -1
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { Button, OverflowMenu, OverflowMenuItem, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@carbon/react';
|
|
3
|
+
import { BedLayout, Disposition } from '../types';
|
|
4
|
+
import AdmitPatientModal from '../modal/admit-patient/admit-patient.modal';
|
|
5
|
+
import { formatDate, Patient } from '@openmrs/esm-framework';
|
|
6
|
+
import CancelAdmissionRequestModal from '../modal/cancel-admission-request/cancel-admission-request';
|
|
7
|
+
import AdmitElsewhereModal from '../modal/admit-elsewhere/admit-elsewhere.modal';
|
|
8
|
+
|
|
9
|
+
interface AdmissionListProps {
|
|
10
|
+
admissionListData: Disposition[];
|
|
11
|
+
bedLayouts: BedLayout[];
|
|
12
|
+
refresh: () => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const AdmissionsRequestList: React.FC<AdmissionListProps> = ({ admissionListData, bedLayouts, refresh }) => {
|
|
16
|
+
const [selectedPatient, setSelectedPatient] = useState<Patient>();
|
|
17
|
+
const [selectedDisposition, setSelectedDisposition] = useState<Disposition>();
|
|
18
|
+
const [showAdmitModal, setShowAdmitModal] = useState<boolean>(false);
|
|
19
|
+
const [showAdmitElsewhereModal, setShowAdmitElsewhereModal] = useState<boolean>(false);
|
|
20
|
+
const [showCancelAdmissionModal, setShowCancelAdmissionModal] = useState<boolean>(false);
|
|
21
|
+
if (!admissionListData || admissionListData.length === 0) {
|
|
22
|
+
return <>No Data</>;
|
|
23
|
+
}
|
|
24
|
+
const handleCancelRequest = (disposition: Disposition) => {
|
|
25
|
+
setSelectedDisposition(disposition);
|
|
26
|
+
setShowCancelAdmissionModal(true);
|
|
27
|
+
};
|
|
28
|
+
const handleAdmitPatient = (disposition: Disposition) => {
|
|
29
|
+
setShowAdmitModal(true);
|
|
30
|
+
setSelectedPatient(disposition.patient);
|
|
31
|
+
setSelectedDisposition(disposition);
|
|
32
|
+
};
|
|
33
|
+
const handleAdmitElsewhere = (disposition: Disposition) => {
|
|
34
|
+
setSelectedPatient(disposition.patient);
|
|
35
|
+
setSelectedDisposition(disposition);
|
|
36
|
+
setShowAdmitElsewhereModal(true);
|
|
37
|
+
};
|
|
38
|
+
const handleAdmitModalClose = () => {
|
|
39
|
+
setShowAdmitModal(false);
|
|
40
|
+
};
|
|
41
|
+
const handeSuccessfullAdmission = () => {
|
|
42
|
+
handleAdmitModalClose();
|
|
43
|
+
refresh();
|
|
44
|
+
};
|
|
45
|
+
const handleCancelAdmissionClose = () => {
|
|
46
|
+
setShowCancelAdmissionModal(false);
|
|
47
|
+
refresh();
|
|
48
|
+
};
|
|
49
|
+
const handleCancelAdmissionSuccess = () => {
|
|
50
|
+
handleCancelAdmissionClose();
|
|
51
|
+
};
|
|
52
|
+
const handleCancelAdmitElsewhere = () => {
|
|
53
|
+
setShowAdmitElsewhereModal(false);
|
|
54
|
+
};
|
|
55
|
+
const handleSuccessfullTransfer = () => {
|
|
56
|
+
handleCancelAdmitElsewhere();
|
|
57
|
+
refresh();
|
|
58
|
+
}
|
|
59
|
+
return (
|
|
60
|
+
<>
|
|
61
|
+
<Table>
|
|
62
|
+
<TableHead>
|
|
63
|
+
<TableRow>
|
|
64
|
+
<TableHeader>No</TableHeader>
|
|
65
|
+
<TableHeader>Date</TableHeader>
|
|
66
|
+
<TableHeader>Name</TableHeader>
|
|
67
|
+
<TableHeader>Gender</TableHeader>
|
|
68
|
+
<TableHeader>Age</TableHeader>
|
|
69
|
+
<TableHeader>Action</TableHeader>
|
|
70
|
+
</TableRow>
|
|
71
|
+
</TableHead>
|
|
72
|
+
|
|
73
|
+
<TableBody>
|
|
74
|
+
{admissionListData &&
|
|
75
|
+
admissionListData.map((val, index) => (
|
|
76
|
+
<TableRow key={val.dispositionLocation.uuid ?? index}>
|
|
77
|
+
<TableCell>{index + 1}</TableCell>
|
|
78
|
+
<TableCell>{formatDate(new Date(val.dispositionEncounter.encounterDatetime))}</TableCell>
|
|
79
|
+
<TableCell>{val.patient.person.display}</TableCell>
|
|
80
|
+
<TableCell>{val.patient.person.gender}</TableCell>
|
|
81
|
+
<TableCell>{val.patient.person.age}</TableCell>
|
|
82
|
+
<TableCell>
|
|
83
|
+
<>
|
|
84
|
+
<OverflowMenu aria-label="overflow-menu">
|
|
85
|
+
<OverflowMenuItem itemText="Cancel" onClick={() => handleCancelRequest(val)} />
|
|
86
|
+
<OverflowMenuItem itemText="Admit" onClick={() => handleAdmitPatient(val)} />
|
|
87
|
+
<OverflowMenuItem itemText="Admit Elsewhere" onClick={() => handleAdmitElsewhere(val)} />
|
|
88
|
+
</OverflowMenu>
|
|
89
|
+
</>
|
|
90
|
+
</TableCell>
|
|
91
|
+
</TableRow>
|
|
92
|
+
))}
|
|
93
|
+
</TableBody>
|
|
94
|
+
</Table>
|
|
95
|
+
{
|
|
96
|
+
showAdmitModal ? (<>
|
|
97
|
+
<AdmitPatientModal
|
|
98
|
+
onModalClose={handleAdmitModalClose}
|
|
99
|
+
open={showAdmitModal}
|
|
100
|
+
onSuccessfullAdmission={handeSuccessfullAdmission}
|
|
101
|
+
disposition={selectedDisposition}
|
|
102
|
+
bedLayouts={bedLayouts}
|
|
103
|
+
/>
|
|
104
|
+
</>) : (<></>)
|
|
105
|
+
}
|
|
106
|
+
{
|
|
107
|
+
showCancelAdmissionModal ? (<>
|
|
108
|
+
<CancelAdmissionRequestModal
|
|
109
|
+
open={showCancelAdmissionModal}
|
|
110
|
+
onModalClose={handleCancelAdmissionClose}
|
|
111
|
+
onCancelAdmission={handleCancelAdmissionSuccess}
|
|
112
|
+
admissionRequest={selectedDisposition}
|
|
113
|
+
|
|
114
|
+
/>
|
|
115
|
+
</>) : (<></>)
|
|
116
|
+
}
|
|
117
|
+
{
|
|
118
|
+
showAdmitElsewhereModal ? (<>
|
|
119
|
+
<AdmitElsewhereModal
|
|
120
|
+
open={showAdmitElsewhereModal}
|
|
121
|
+
onModalClose={handleCancelAdmitElsewhere}
|
|
122
|
+
patient={selectedPatient}
|
|
123
|
+
visit={selectedDisposition.visit}
|
|
124
|
+
onSuccessfullTransfer={handleSuccessfullTransfer} />
|
|
125
|
+
</>) : (<></>)
|
|
126
|
+
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
</>
|
|
130
|
+
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export default AdmissionsRequestList;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import styles from './admissions-dashboard.component.scss';
|
|
3
|
+
import StatCard from '../service-queues/service-queue/stats/stat-card/stat-card.component';
|
|
4
|
+
import { InlineLoading, Tab, TabList, TabPanel, TabPanels, Tabs } from '@carbon/react';
|
|
5
|
+
import { FHIRResource, useSession } from '@openmrs/esm-framework';
|
|
6
|
+
import { getAdmissionLoactionData, getAdmissionRequests, getAdmittedPatientsData, getDichargedEncounters } from './admissions.resource';
|
|
7
|
+
import { type Disposition, type AdmissionLocationData, BedLayout, FhirEncounter, FhirBundleEntry, FhirEncounterBundle } from './types';
|
|
8
|
+
import AdmittedPatientsList from './admitted-list/admitted-patients-list';
|
|
9
|
+
import AdmissionsRequestList from './admission-request-list/admission-request-list';
|
|
10
|
+
import { AdmissionEncounterTypeUuids } from './constants';
|
|
11
|
+
import DischargedList from './discharged-list/discharged-list';
|
|
12
|
+
|
|
13
|
+
const AdmissionsDashboard: React.FC = () => {
|
|
14
|
+
const [dashboardData, setDashboardData] = useState<AdmissionLocationData>(null);
|
|
15
|
+
const [admissionListData, setAdmissionListData] = useState<Disposition[]>([]);
|
|
16
|
+
const [admittedPatientsData, setAdmittedPatientsData] = useState<BedLayout[]>([]);
|
|
17
|
+
const [dischargeEncounterBundle,setDischargeEncounterBundle] = useState<FhirEncounterBundle>();
|
|
18
|
+
const [loading, setLoading] = useState<boolean>(false);
|
|
19
|
+
const session = useSession();
|
|
20
|
+
const locationUuid = session.sessionLocation.uuid;
|
|
21
|
+
const sortedDischargeEncounters = useMemo(()=>generateDischargeEncounters(),[dischargeEncounterBundle])
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
fetchData();
|
|
24
|
+
}, [locationUuid]);
|
|
25
|
+
const fetchData = () => {
|
|
26
|
+
setLoading(true);
|
|
27
|
+
getDashboardData();
|
|
28
|
+
getAdmissionListData();
|
|
29
|
+
getAdmittedPatients();
|
|
30
|
+
getDisachargedEncounters();
|
|
31
|
+
}
|
|
32
|
+
const getDashboardData = async () => {
|
|
33
|
+
const res = await getAdmissionLoactionData(locationUuid);
|
|
34
|
+
setDashboardData(res);
|
|
35
|
+
setLoading(false);
|
|
36
|
+
};
|
|
37
|
+
const getFreeBeds = (dashboardData: AdmissionLocationData): number => {
|
|
38
|
+
return (dashboardData?.totalBeds ?? 0) - (dashboardData.occupiedBeds ?? 0);
|
|
39
|
+
};
|
|
40
|
+
const getBedOccupancy = (dashboardData: AdmissionLocationData): number => {
|
|
41
|
+
return parseFloat(((dashboardData?.occupiedBeds / dashboardData.totalBeds) * 100).toFixed(2));
|
|
42
|
+
};
|
|
43
|
+
const getAdmissionListData = async () => {
|
|
44
|
+
const res = await getAdmissionRequests(locationUuid);
|
|
45
|
+
setAdmissionListData(res);
|
|
46
|
+
setLoading(false);
|
|
47
|
+
};
|
|
48
|
+
const getAdmittedPatients = async () => {
|
|
49
|
+
const res = await getAdmittedPatientsData(locationUuid);
|
|
50
|
+
setAdmittedPatientsData(res);
|
|
51
|
+
setLoading(false);
|
|
52
|
+
};
|
|
53
|
+
const getDisachargedEncounters = async () => {
|
|
54
|
+
const res = await getDichargedEncounters(AdmissionEncounterTypeUuids.DISCHARGE_ENCOUNTER_TYPE_UUID, locationUuid);
|
|
55
|
+
setDischargeEncounterBundle(res);
|
|
56
|
+
}
|
|
57
|
+
function generateDischargeEncounters(): FhirEncounter[]{
|
|
58
|
+
if(dischargeEncounterBundle && dischargeEncounterBundle.entry){
|
|
59
|
+
const fhirEntries = dischargeEncounterBundle.entry ?? [];
|
|
60
|
+
let dischargeEncounters: FhirEncounter[] = [];
|
|
61
|
+
fhirEntries.forEach((fe) => {
|
|
62
|
+
const resource = fe.resource;
|
|
63
|
+
if (resource && resource.resourceType === 'Encounter') {
|
|
64
|
+
dischargeEncounters.push(resource);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
// order encounters in desc order
|
|
68
|
+
const sortedEnc = dischargeEncounters.sort((a,b)=>{
|
|
69
|
+
return new Date(b.period.start).getTime() - new Date(a.period.start).getTime();
|
|
70
|
+
});
|
|
71
|
+
return sortedEnc;
|
|
72
|
+
}else{
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
const handleRefresh = () => {
|
|
78
|
+
fetchData();
|
|
79
|
+
}
|
|
80
|
+
return (
|
|
81
|
+
<>
|
|
82
|
+
<div className={styles.admissionsLayout}>
|
|
83
|
+
<div className={styles.headerSection}>
|
|
84
|
+
<h4>Admissions</h4>
|
|
85
|
+
</div>
|
|
86
|
+
<div className={styles.statsSection}>
|
|
87
|
+
<>
|
|
88
|
+
{dashboardData ? (
|
|
89
|
+
<>
|
|
90
|
+
<StatCard title="Number of beds" count={dashboardData.totalBeds} />
|
|
91
|
+
<StatCard title="Admitted Patients" count={dashboardData.occupiedBeds} />
|
|
92
|
+
<StatCard title="Free Beds" count={getFreeBeds(dashboardData)} />
|
|
93
|
+
<StatCard title="Bed Occupancy" count={getBedOccupancy(dashboardData)} other="%" />
|
|
94
|
+
</>
|
|
95
|
+
) : (
|
|
96
|
+
<></>
|
|
97
|
+
)}
|
|
98
|
+
</>
|
|
99
|
+
</div>
|
|
100
|
+
<div className={styles.contentSection}>
|
|
101
|
+
{
|
|
102
|
+
loading ? (<>
|
|
103
|
+
<InlineLoading description="Fetching Data...please wait...." />
|
|
104
|
+
</>) : (<>
|
|
105
|
+
<Tabs>
|
|
106
|
+
<TabList contained>
|
|
107
|
+
<Tab>Admission Requests</Tab>
|
|
108
|
+
<Tab>Admitted</Tab>
|
|
109
|
+
<Tab>Discharged</Tab>
|
|
110
|
+
</TabList>
|
|
111
|
+
<TabPanels>
|
|
112
|
+
<TabPanel>
|
|
113
|
+
{admissionListData ? <AdmissionsRequestList
|
|
114
|
+
admissionListData={admissionListData}
|
|
115
|
+
bedLayouts={admittedPatientsData}
|
|
116
|
+
refresh={handleRefresh}
|
|
117
|
+
/> : <></>}
|
|
118
|
+
</TabPanel>
|
|
119
|
+
<TabPanel>
|
|
120
|
+
{admittedPatientsData ?
|
|
121
|
+
<AdmittedPatientsList
|
|
122
|
+
admittedPatientsData={admittedPatientsData}
|
|
123
|
+
refresh={handleRefresh}
|
|
124
|
+
/> : <></>}
|
|
125
|
+
</TabPanel>
|
|
126
|
+
<TabPanel>
|
|
127
|
+
{
|
|
128
|
+
sortedDischargeEncounters ? (<>
|
|
129
|
+
<DischargedList
|
|
130
|
+
dischargedEncounters={sortedDischargeEncounters}
|
|
131
|
+
refresh={handleRefresh}
|
|
132
|
+
/>
|
|
133
|
+
</>) : (<></>)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
</TabPanel>
|
|
137
|
+
</TabPanels>
|
|
138
|
+
</Tabs>
|
|
139
|
+
</>)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
</>
|
|
145
|
+
);
|
|
146
|
+
};
|
|
147
|
+
export default AdmissionsDashboard;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { Encounter, fhirBaseUrl, FHIRResource, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
|
|
2
|
+
import { AdmitPatientDto, AssignBedToPatientDto, BedLayout, BedSwapDto, CancelAdmissionDto, DischargePatientDto, Disposition, DispositionResponse, FhirEncounterBundle, TransferPatientDto, UnAssignBedDto, type AdmissionLocationData } from './types';
|
|
3
|
+
|
|
4
|
+
const customRep =
|
|
5
|
+
'custom:(ward,totalBeds,occupiedBeds,bedLayouts:(rowNumber,columnNumber,bedNumber,bedId,bedUuid,status,location,patients:(person:full,identifiers,uuid)))';
|
|
6
|
+
|
|
7
|
+
export async function getAdmissionLoactionData(locationUuid: string): Promise<AdmissionLocationData> {
|
|
8
|
+
const admissionLocationUrl = `${restBaseUrl}/admissionLocation/${locationUuid}?v=${customRep}`;
|
|
9
|
+
const response = await openmrsFetch(admissionLocationUrl);
|
|
10
|
+
const result = await response.json();
|
|
11
|
+
return result ?? null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function getAdmissionRequests(locationUuid: string): Promise<Disposition[]> {
|
|
15
|
+
const admissionRep = 'custom:(dispositionLocation,dispositionType,disposition,dispositionEncounter:full,patient:(uuid,identifiers,voided,person:(uuid,display,gender,age,birthdate,birthtime,preferredName,preferredAddress,dead,deathDate)),dispositionObsGroup,visit)';
|
|
16
|
+
const params = {
|
|
17
|
+
v: admissionRep,
|
|
18
|
+
dispositionLocation: locationUuid,
|
|
19
|
+
dispositionType: 'ADMIT,TRANSFER'
|
|
20
|
+
};
|
|
21
|
+
const queryString = new URLSearchParams(params).toString();
|
|
22
|
+
const admissionRequestUrl = `${restBaseUrl}/emrapi/inpatient/request?${queryString}`;
|
|
23
|
+
const response = await openmrsFetch(admissionRequestUrl);
|
|
24
|
+
const result = await response.json();
|
|
25
|
+
return result.results ?? null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function getAdmittedPatientsData(locationUuid: string): Promise<BedLayout[]> {
|
|
29
|
+
const admissionLocationData = await getAdmissionLoactionData(locationUuid);
|
|
30
|
+
if (admissionLocationData.bedLayouts && admissionLocationData.bedLayouts.length > 0) {
|
|
31
|
+
const bedLayouts = admissionLocationData.bedLayouts;
|
|
32
|
+
return bedLayouts;
|
|
33
|
+
} else {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function postRequest(url: string, dto: any) {
|
|
39
|
+
const resp = await openmrsFetch(url, {
|
|
40
|
+
method: 'POST',
|
|
41
|
+
headers: { 'Content-Type': 'application/json' },
|
|
42
|
+
body: JSON.stringify(dto),
|
|
43
|
+
});
|
|
44
|
+
const result = await resp.json();
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function admitPatientToWard(admitPatientDto: AdmitPatientDto): Promise<Encounter> {
|
|
49
|
+
const admitPatientUrl = `${restBaseUrl}/encounter`;
|
|
50
|
+
return postRequest(admitPatientUrl, admitPatientDto);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function assignBedToPatient(bedId: number, assignBedToPatientDto: AssignBedToPatientDto) {
|
|
54
|
+
const assignBedUrl = `${restBaseUrl}/beds/${bedId}`;
|
|
55
|
+
return postRequest(assignBedUrl, assignBedToPatientDto);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function cancelAdmissionRequest(cancelAdmissionDto: CancelAdmissionDto) {
|
|
59
|
+
const cancelAdmissionUrl = `${restBaseUrl}/encounter`;
|
|
60
|
+
return postRequest(cancelAdmissionUrl, cancelAdmissionDto);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export async function bedSwapRequest(bedSwapDto: BedSwapDto) {
|
|
64
|
+
const cancelAdmissionUrl = `${restBaseUrl}/encounter`;
|
|
65
|
+
return postRequest(cancelAdmissionUrl, bedSwapDto);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function dischargePatientFromWard(dischargePatientDto: DischargePatientDto) {
|
|
69
|
+
const cancelAdmissionUrl = `${restBaseUrl}/encounter`;
|
|
70
|
+
return postRequest(cancelAdmissionUrl, dischargePatientDto);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function unassignBed(unAssignBedDto: UnAssignBedDto) {
|
|
74
|
+
const params = {
|
|
75
|
+
patientUuid: unAssignBedDto.patientUuid
|
|
76
|
+
};
|
|
77
|
+
const queryString = new URLSearchParams(params).toString();
|
|
78
|
+
const unassignBedUrl = `${restBaseUrl}/beds/${unAssignBedDto.bedId}?${queryString}`;
|
|
79
|
+
await openmrsFetch(unassignBedUrl, {
|
|
80
|
+
method: 'DELETE'
|
|
81
|
+
});
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
export async function admitPatientElseWhere(transferPatientDto: TransferPatientDto) {
|
|
85
|
+
const transferUrl = `${restBaseUrl}/encounter`;
|
|
86
|
+
return postRequest(transferUrl, transferPatientDto);
|
|
87
|
+
}
|
|
88
|
+
export async function getDichargedEncounters(encounterTypeUuid: string,locationUuid: string): Promise<FhirEncounterBundle>{
|
|
89
|
+
const params = {
|
|
90
|
+
_summary: 'data',
|
|
91
|
+
type: encounterTypeUuid,
|
|
92
|
+
location: locationUuid,
|
|
93
|
+
_count: '100',
|
|
94
|
+
_getpagesoffset: '0'
|
|
95
|
+
};
|
|
96
|
+
const queryString = new URLSearchParams(params).toString();
|
|
97
|
+
const encountersUrl = `${fhirBaseUrl}/Encounter?${queryString}`;
|
|
98
|
+
const resp = await openmrsFetch(encountersUrl);
|
|
99
|
+
const result = await resp.json();
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { OverflowMenu, OverflowMenuItem, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@carbon/react';
|
|
3
|
+
import { BedLayout } from '../types';
|
|
4
|
+
import BedSwapModal from '../modal/bed-swap/bed-swap.modal';
|
|
5
|
+
import DischargeModal from '../modal/discharge/discharge-patient.modal';
|
|
6
|
+
|
|
7
|
+
interface AdmittedPatientsListProps {
|
|
8
|
+
admittedPatientsData: BedLayout[];
|
|
9
|
+
refresh: ()=> void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const AdmittedPatientsList: React.FC<AdmittedPatientsListProps> = ({ admittedPatientsData, refresh }) => {
|
|
13
|
+
const [showBedSwapModal,setShowBedSwapModal]= useState<boolean>(false);
|
|
14
|
+
const [showDischargeModal,setShowDischargeModal]= useState<boolean>(false);
|
|
15
|
+
const [selectedLayout,setSelectedLayout] = useState<any>();
|
|
16
|
+
if(!admittedPatientsData){
|
|
17
|
+
return <>No data to display</>
|
|
18
|
+
}
|
|
19
|
+
const handleTransferRequest = (layout: BedLayout)=>{
|
|
20
|
+
setSelectedLayout(layout);
|
|
21
|
+
};
|
|
22
|
+
const handleBedSwapRequest = (layout: BedLayout)=>{
|
|
23
|
+
setSelectedLayout(layout);
|
|
24
|
+
setShowBedSwapModal(true);
|
|
25
|
+
};
|
|
26
|
+
const handleDischargeRequest = (layout: BedLayout)=>{
|
|
27
|
+
setSelectedLayout(layout);
|
|
28
|
+
setShowDischargeModal(true);
|
|
29
|
+
};
|
|
30
|
+
const handleBedSwapModalClose = ()=>{
|
|
31
|
+
setShowBedSwapModal(false);
|
|
32
|
+
refresh()
|
|
33
|
+
}
|
|
34
|
+
const handleDischargeModalClose = ()=>{
|
|
35
|
+
setShowDischargeModal(false);
|
|
36
|
+
}
|
|
37
|
+
const handleSuccessfullDischarge = ()=>{
|
|
38
|
+
handleBedSwapModalClose();
|
|
39
|
+
refresh();
|
|
40
|
+
}
|
|
41
|
+
const rows =
|
|
42
|
+
admittedPatientsData?.flatMap((layout) =>
|
|
43
|
+
(layout.patients ?? []).map((patient) => ({
|
|
44
|
+
key: `${layout.bedUuid}-${patient.uuid}`,
|
|
45
|
+
bedNumber: layout.bedNumber,
|
|
46
|
+
bedId: layout.bedId,
|
|
47
|
+
status: layout.status,
|
|
48
|
+
location: layout.location,
|
|
49
|
+
name: patient.person.display,
|
|
50
|
+
gender: patient.person.gender,
|
|
51
|
+
age: patient.person.age,
|
|
52
|
+
identifier: patient.identifiers?.[0]?.identifier ?? 'N/A',
|
|
53
|
+
person: patient.person
|
|
54
|
+
})),
|
|
55
|
+
) ?? [];
|
|
56
|
+
|
|
57
|
+
if (!rows.length) {
|
|
58
|
+
return <>No Data</>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<>
|
|
63
|
+
<Table>
|
|
64
|
+
<TableHead>
|
|
65
|
+
<TableRow>
|
|
66
|
+
<TableHeader>No</TableHeader>
|
|
67
|
+
<TableHeader>Bed No</TableHeader>
|
|
68
|
+
<TableHeader>Patient Name</TableHeader>
|
|
69
|
+
<TableHeader>Gender</TableHeader>
|
|
70
|
+
<TableHeader>Age</TableHeader>
|
|
71
|
+
<TableHeader>Identifier</TableHeader>
|
|
72
|
+
<TableHeader>Status</TableHeader>
|
|
73
|
+
<TableHeader>Location</TableHeader>
|
|
74
|
+
<TableHeader>Action</TableHeader>
|
|
75
|
+
</TableRow>
|
|
76
|
+
</TableHead>
|
|
77
|
+
<TableBody>
|
|
78
|
+
{rows.map((row, index) => (
|
|
79
|
+
<TableRow key={row.key}>
|
|
80
|
+
<TableCell>{index + 1}</TableCell>
|
|
81
|
+
<TableCell>{row.bedNumber}</TableCell>
|
|
82
|
+
<TableCell>{row.name}</TableCell>
|
|
83
|
+
<TableCell>{row.gender}</TableCell>
|
|
84
|
+
<TableCell>{row.age}</TableCell>
|
|
85
|
+
<TableCell>{row.identifier}</TableCell>
|
|
86
|
+
<TableCell>{row.status}</TableCell>
|
|
87
|
+
<TableCell>{row.location}</TableCell>
|
|
88
|
+
<TableCell>
|
|
89
|
+
<>
|
|
90
|
+
<OverflowMenu aria-label="overflow-menu">
|
|
91
|
+
<OverflowMenuItem itemText="Transfer" onClick={() => handleTransferRequest(row as any)} />
|
|
92
|
+
<OverflowMenuItem itemText="Bed Swap" onClick={() => handleBedSwapRequest(row as any)} />
|
|
93
|
+
<OverflowMenuItem itemText="Discharge" onClick={() => handleDischargeRequest(row as any)} />
|
|
94
|
+
</OverflowMenu>
|
|
95
|
+
</>
|
|
96
|
+
</TableCell>
|
|
97
|
+
</TableRow>
|
|
98
|
+
))}
|
|
99
|
+
</TableBody>
|
|
100
|
+
</Table>
|
|
101
|
+
{
|
|
102
|
+
showBedSwapModal && selectedLayout ? (<>
|
|
103
|
+
<BedSwapModal
|
|
104
|
+
open={showBedSwapModal}
|
|
105
|
+
onModalClose={handleBedSwapModalClose}
|
|
106
|
+
onSuccessfullBedSwap={handleBedSwapModalClose}
|
|
107
|
+
disposition={null}
|
|
108
|
+
person={selectedLayout.person}
|
|
109
|
+
bedLayouts={admittedPatientsData}/>
|
|
110
|
+
</>): (<></>)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
{
|
|
114
|
+
showDischargeModal && selectedLayout ? (<>
|
|
115
|
+
<DischargeModal
|
|
116
|
+
open={showDischargeModal}
|
|
117
|
+
onModalClose={handleDischargeModalClose}
|
|
118
|
+
onDischarge={handleSuccessfullDischarge}
|
|
119
|
+
admissionRequest={selectedLayout}
|
|
120
|
+
/>
|
|
121
|
+
</>) : (<></>)
|
|
122
|
+
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
</>
|
|
126
|
+
);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export default AdmittedPatientsList;
|
|
130
|
+
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const ADMIT_ENCOUNTER_TYPE_UUID = 'e22e39fd-7db2-45e7-80f1-60fa0d5a4378';
|
|
2
|
+
const CANCEL_ADT_ENCOUNTER_TYPE_UUID = "550e8400-e29b-41d4-a716-446655440000";
|
|
3
|
+
const BED_ASSIGNMENT_ENCOUNTER_TYPE_UUID = 'f47ac10b-58cc-4372-a567-0e02b2c3d479';
|
|
4
|
+
const DISCHARGE_ENCOUNTER_TYPE_UUID = '181820aa-88c9-479b-9077-af92f5364329';
|
|
5
|
+
const TRANSFER_REQUEST_ENCOUNTER_TYPE_UUID = 'b2c4d5e6-7f8a-4e9b-8c1d-2e3f8e4a3b8f';
|
|
6
|
+
|
|
7
|
+
const ADMISSION_TO_HOSPITAL_DECISION_UUID = 'ac4d3e94-03f3-458a-9cb1-9c2ab3c3a3f7';
|
|
8
|
+
const ADMISSION_DENIED_UUID = 'cc6a6126-b8a1-4d2d-9a35-31f9be7c5e68';
|
|
9
|
+
const CLINICAL_IMPRESSION_UUID = '159395AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
|
|
10
|
+
const CLINICAL_NOTES_UUID = '5e4dc798-2cce-4a1a-97e9-bcf22d64b07c';
|
|
11
|
+
const INPATIENT_DISPOSITION_CONSTRUCT_UUID = '9ceedfb7-60e4-42ce-a11e-f2dbabc82112';
|
|
12
|
+
const INTERNAL_TRANSFER_LOCATION_UUID = '731318a6-9fa9-4f68-97a9-5bd4cbc707f7';
|
|
13
|
+
const INPATIENT_PATIENT_DISPOSITION_UUID = 'ce085d74-323c-4c9a-9fdf-051de81dd020';
|
|
14
|
+
const TRANSFER_OUT_UUID = '5520f234-258e-49f0-97ab-701b98fab608';
|
|
15
|
+
|
|
16
|
+
export const AdmissionEncounterTypeUuids = {
|
|
17
|
+
ADMIT_ENCOUNTER_TYPE_UUID,
|
|
18
|
+
CANCEL_ADT_ENCOUNTER_TYPE_UUID,
|
|
19
|
+
BED_ASSIGNMENT_ENCOUNTER_TYPE_UUID,
|
|
20
|
+
DISCHARGE_ENCOUNTER_TYPE_UUID,
|
|
21
|
+
TRANSFER_REQUEST_ENCOUNTER_TYPE_UUID
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const AdmissionConcepts = {
|
|
25
|
+
ADMISSION_TO_HOSPITAL_DECISION_UUID,
|
|
26
|
+
ADMISSION_DENIED_UUID,
|
|
27
|
+
CLINICAL_IMPRESSION_UUID,
|
|
28
|
+
CLINICAL_NOTES_UUID,
|
|
29
|
+
INPATIENT_DISPOSITION_CONSTRUCT_UUID,
|
|
30
|
+
INTERNAL_TRANSFER_LOCATION_UUID,
|
|
31
|
+
INPATIENT_PATIENT_DISPOSITION_UUID,
|
|
32
|
+
TRANSFER_OUT_UUID
|
|
33
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@carbon/react";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { FhirEncounter } from "../types";
|
|
4
|
+
import { formatDate } from "@openmrs/esm-framework";
|
|
5
|
+
interface DischargedListProps{
|
|
6
|
+
dischargedEncounters: FhirEncounter[];
|
|
7
|
+
refresh: () => void;
|
|
8
|
+
}
|
|
9
|
+
const DischargedList: React.FC<DischargedListProps> = ({dischargedEncounters,refresh})=>{
|
|
10
|
+
if(!dischargedEncounters){
|
|
11
|
+
return <>No Data to display</>
|
|
12
|
+
}
|
|
13
|
+
const getPatientName = (display: string): string=>{
|
|
14
|
+
const splitString = display.split("(");
|
|
15
|
+
let names = '';
|
|
16
|
+
if(splitString.length > 0){
|
|
17
|
+
names = splitString[0];
|
|
18
|
+
}
|
|
19
|
+
return names;
|
|
20
|
+
};
|
|
21
|
+
const getPatientIdentifier = (display: string): string=>{
|
|
22
|
+
const splitString = display.split("(");
|
|
23
|
+
let identifier = '';
|
|
24
|
+
if(splitString.length > 1){
|
|
25
|
+
identifier = splitString[1];
|
|
26
|
+
}
|
|
27
|
+
return identifier;
|
|
28
|
+
}
|
|
29
|
+
return <>
|
|
30
|
+
<Table>
|
|
31
|
+
<TableHead>
|
|
32
|
+
<TableRow>
|
|
33
|
+
<TableHeader>No</TableHeader>
|
|
34
|
+
<TableHeader>Discharge Date</TableHeader>
|
|
35
|
+
<TableHeader>Name</TableHeader>
|
|
36
|
+
<TableHeader>Identifier</TableHeader>
|
|
37
|
+
</TableRow>
|
|
38
|
+
</TableHead>
|
|
39
|
+
|
|
40
|
+
<TableBody>
|
|
41
|
+
{
|
|
42
|
+
dischargedEncounters.map((val,index)=>{
|
|
43
|
+
return <>
|
|
44
|
+
<TableRow key={val.id}>
|
|
45
|
+
<TableCell>{index + 1}</TableCell>
|
|
46
|
+
<TableCell>{formatDate(new Date(val.period.start))}</TableCell>
|
|
47
|
+
<TableCell>{getPatientName(val.subject.display ?? '')}</TableCell>
|
|
48
|
+
<TableCell>{getPatientIdentifier(val.subject.display ?? '')}</TableCell>
|
|
49
|
+
</TableRow>
|
|
50
|
+
</>
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
</TableBody>
|
|
55
|
+
</Table>
|
|
56
|
+
</>
|
|
57
|
+
}
|
|
58
|
+
export default DischargedList;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
.admitModalLayout{
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
row-gap: 15px;
|
|
5
|
+
width: 100%;
|
|
6
|
+
}
|
|
7
|
+
.admitModalContentSection{
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
row-gap: 15px;
|
|
11
|
+
width: 100%;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.locationSelect{
|
|
15
|
+
width: 100%;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.formRow{
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: row;
|
|
21
|
+
width: 100%;
|
|
22
|
+
column-gap: 5px;
|
|
23
|
+
}
|