@kenyaemr/esm-morgue-app 5.4.2-pre.2283 → 5.4.2-pre.2291
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/.turbo/turbo-build.log +19 -19
- package/dist/109.js +2 -0
- package/dist/109.js.map +1 -0
- package/dist/201.js +1 -0
- package/dist/201.js.map +1 -0
- package/dist/293.js +1 -0
- package/dist/293.js.map +1 -0
- package/dist/300.js +1 -1
- package/dist/347.js +1 -2
- package/dist/347.js.map +1 -1
- package/dist/373.js +2 -0
- package/dist/373.js.map +1 -0
- package/dist/38.js +1 -0
- package/dist/38.js.map +1 -0
- package/dist/389.js +1 -0
- package/dist/389.js.map +1 -0
- package/dist/398.js +1 -0
- package/dist/398.js.map +1 -0
- package/dist/4.js +2 -0
- package/dist/4.js.map +1 -0
- package/dist/410.js +1 -0
- package/dist/410.js.map +1 -0
- package/dist/420.js +2 -0
- package/dist/420.js.map +1 -0
- package/dist/467.js +1 -0
- package/dist/467.js.map +1 -0
- package/dist/632.js +1 -0
- package/dist/632.js.map +1 -0
- package/dist/798.js +1 -0
- package/dist/798.js.map +1 -0
- package/dist/811.js +1 -0
- package/dist/811.js.map +1 -0
- package/dist/824.js +1 -0
- package/dist/824.js.map +1 -0
- package/dist/827.js +1 -0
- package/dist/827.js.map +1 -0
- package/dist/842.js +2 -0
- package/dist/842.js.LICENSE.txt +5 -0
- package/dist/842.js.map +1 -0
- package/dist/918.js +1 -1
- package/dist/918.js.map +1 -1
- package/dist/kenyaemr-esm-morgue-app.js +1 -1
- package/dist/kenyaemr-esm-morgue-app.js.buildmanifest.json +218 -291
- package/dist/kenyaemr-esm-morgue-app.js.map +1 -1
- package/dist/main.js +2 -1
- package/dist/main.js.LICENSE.txt +15 -0
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/bed/bed.component.tsx +164 -0
- package/src/bed/bed.scss +192 -0
- package/src/bed/divider/divider.component.tsx +18 -0
- package/src/bed/empty-bed.component.tsx +47 -0
- package/src/bed-layout/admitted/admitted-bed-layout.component.tsx +189 -0
- package/src/bed-layout/awaiting/awaiting-bed-layout.component.tsx +86 -0
- package/src/bed-layout/bed-layout.resource.ts +72 -0
- package/src/bed-layout/bed-layout.scss +55 -0
- package/src/bed-layout/discharged/discharged-bed-layout.component.tsx +109 -0
- package/src/bed-layout/discharged/discharged-bed-layout.resource.ts +99 -0
- package/src/bed-linelist-view/admitted/admitted-bed-linelist-view.component.tsx +420 -0
- package/src/bed-linelist-view/awaiting/awaiting-bed-linelist-view.component.tsx +224 -0
- package/src/bed-linelist-view/bed-linelist-view.scss +5 -0
- package/src/bed-linelist-view/discharged/discharged-bed-line-view.component.tsx +256 -0
- package/src/config-schema.ts +41 -9
- package/src/constants.ts +57 -0
- package/src/deceased-patient-header/deceased-patient-header.component.tsx +31 -0
- package/src/deceased-patient-header/deceased-patient-header.scss +50 -0
- package/src/{component → deceased-patient-header}/deceasedInfo/deceased-info.component.tsx +1 -1
- package/src/deceased-patient-header/deceasedInfo/deceased-info.resource.ts +11 -0
- package/src/extension/actionButton.component.tsx +5 -59
- package/src/extension/deceasedInfoBanner.component.tsx +5 -9
- package/src/{hook/useAdmitPatient.ts → forms/admit-deceased-person-workspace/admit-deceased-person.resource.ts} +177 -46
- package/src/forms/admit-deceased-person-workspace/admit-deceased-person.scss +143 -0
- package/src/forms/admit-deceased-person-workspace/admit-deceased-person.workspace.tsx +648 -0
- package/src/{hook/usePersonAttributes.ts → forms/discharge-deceased-person-workspace/discharge-body.resource.ts} +1 -1
- package/src/forms/discharge-deceased-person-workspace/discharge-body.scss +56 -0
- package/src/forms/discharge-deceased-person-workspace/discharge-body.workspace.tsx +362 -0
- package/src/forms/dispose-deceased-person-workspace/dispose-deceased-person.resource.ts +18 -0
- package/src/{workspaces/patientAdditionalInfoForm.scss → forms/dispose-deceased-person-workspace/dispose-deceased-person.scss} +46 -66
- package/src/forms/dispose-deceased-person-workspace/dispose-deceased-person.workspace.tsx +401 -0
- package/src/forms/form-entry-workspace/form-entry-workspace.workspace.tsx +62 -0
- package/src/forms/swap-compartment-workspace/swap-unit.scss +144 -0
- package/src/forms/swap-compartment-workspace/swap-unit.workspace.tsx +280 -0
- package/src/header/header.component.tsx +41 -0
- package/src/header/header.scss +58 -0
- package/src/home/home.component.tsx +87 -0
- package/src/home/home.resource.ts +261 -0
- package/src/home/home.scss +5 -0
- package/src/index.ts +18 -12
- package/src/metrics/metrics-card.component.tsx +31 -0
- package/src/metrics/metrics-card.scss +51 -0
- package/src/root.component.tsx +7 -3
- package/src/routes.json +25 -14
- package/src/schemas/index.ts +66 -0
- package/src/summary/summary.component.tsx +42 -0
- package/src/summary/summary.scss +10 -0
- package/src/switcher/content-switcher.component.tsx +220 -0
- package/src/switcher/content-switcher.scss +30 -0
- package/src/types/index.ts +336 -359
- package/src/utils/utils.ts +20 -2
- package/src/view-details/main/main.component.tsx +34 -0
- package/src/view-details/main/main.scss +45 -0
- package/src/view-details/panels/attachement.component.tsx +21 -0
- package/src/view-details/panels/autopsy.component.tsx +215 -0
- package/src/view-details/panels/billing-history.component.tsx +13 -0
- package/src/view-details/panels/observations/observation.component.tsx +57 -0
- package/src/view-details/panels/observations/observation.scss +24 -0
- package/src/view-details/panels/panels.scss +46 -0
- package/src/view-details/view-details.component.tsx +65 -0
- package/src/view-details/view-details.resource.ts +65 -0
- package/src/view-details/views-details.scss +82 -0
- package/translations/en.json +74 -21
- package/tsconfig.json +1 -1
- package/dist/113.js +0 -1
- package/dist/113.js.map +0 -1
- package/dist/160.js +0 -1
- package/dist/160.js.map +0 -1
- package/dist/299.js +0 -1
- package/dist/299.js.map +0 -1
- package/dist/433.js +0 -2
- package/dist/433.js.map +0 -1
- package/dist/441.js +0 -1
- package/dist/441.js.map +0 -1
- package/dist/496.js +0 -1
- package/dist/496.js.map +0 -1
- package/dist/511.js +0 -1
- package/dist/511.js.map +0 -1
- package/dist/603.js +0 -1
- package/dist/603.js.map +0 -1
- package/dist/610.js +0 -1
- package/dist/610.js.map +0 -1
- package/dist/612.js +0 -1
- package/dist/612.js.map +0 -1
- package/dist/656.js +0 -2
- package/dist/656.js.map +0 -1
- package/dist/752.js +0 -1
- package/dist/752.js.map +0 -1
- package/dist/754.js +0 -1
- package/dist/754.js.map +0 -1
- package/dist/781.js +0 -1
- package/dist/781.js.map +0 -1
- package/dist/801.js +0 -2
- package/dist/801.js.map +0 -1
- package/dist/817.js +0 -1
- package/dist/817.js.map +0 -1
- package/dist/877.js +0 -1
- package/dist/877.js.map +0 -1
- package/dist/924.js +0 -1
- package/dist/924.js.map +0 -1
- package/src/autosuggest/autosuggest.component.tsx +0 -162
- package/src/autosuggest/autosuggest.scss +0 -61
- package/src/autosuggest/patient-search-info.component.tsx +0 -75
- package/src/autosuggest/patient-search-info.scss +0 -62
- package/src/autosuggest/search-empty-state.component.tsx +0 -21
- package/src/autosuggest/search-empty-state.scss +0 -18
- package/src/card/avail-compartment.compartment.tsx +0 -94
- package/src/card/compartment-view.compartment.tsx +0 -62
- package/src/card/compartment.scss +0 -128
- package/src/card/compartmentSharing.component.tsx +0 -21
- package/src/card/compartmentSharing.scss +0 -24
- package/src/card/empty-compartment.component.tsx +0 -28
- package/src/card/empty-compartment.scss +0 -61
- package/src/component/main.component.tsx +0 -17
- package/src/component/next-of-kin-details/nextOfKinDetails.component.tsx +0 -50
- package/src/component/next-of-kin-details/nextOfKinDetails.scss +0 -37
- package/src/header/admitted-queue-header.component.tsx +0 -30
- package/src/header/admitted-queue-header.scss +0 -32
- package/src/header/morgue-header.component.tsx +0 -38
- package/src/header/morgue-header.scss +0 -95
- package/src/header/morgue-illustration.component.tsx +0 -13
- package/src/hook/useDeceasedPatients.ts +0 -12
- package/src/hook/useDischargedPatient.ts +0 -55
- package/src/hook/useMorgue.resource.ts +0 -163
- package/src/hook/useMortuaryAdmissionLocation.ts +0 -64
- package/src/tables/admitted-queue.component.tsx +0 -54
- package/src/tables/admitted-queue.scss +0 -62
- package/src/tables/discharge-queue.component.tsx +0 -87
- package/src/tables/generic-table.component.tsx +0 -140
- package/src/tables/generic-table.scss +0 -37
- package/src/tabs/tabs.component.tsx +0 -82
- package/src/tabs/tabs.scss +0 -15
- package/src/workspaces/admit-body.scss +0 -46
- package/src/workspaces/admit-body.workspace.tsx +0 -79
- package/src/workspaces/discharge-body.scss +0 -67
- package/src/workspaces/discharge-body.workspace.tsx +0 -329
- package/src/workspaces/patientAdditionalInfoForm.workspace.tsx +0 -562
- package/src/workspaces/swap-unit.scss +0 -46
- package/src/workspaces/swap-unit.workspace.tsx +0 -168
- /package/dist/{347.js.LICENSE.txt → 109.js.LICENSE.txt} +0 -0
- /package/dist/{656.js.LICENSE.txt → 373.js.LICENSE.txt} +0 -0
- /package/dist/{801.js.LICENSE.txt → 4.js.LICENSE.txt} +0 -0
- /package/dist/{433.js.LICENSE.txt → 420.js.LICENSE.txt} +0 -0
- /package/src/{component → deceased-patient-header}/deceasedInfo/deceased-info.scss +0 -0
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { FetchResponse, openmrsFetch, restBaseUrl, useFhirFetchAll } from '@openmrs/esm-framework';
|
|
2
|
-
import { type Patient, type FHIREncounter } from '../types';
|
|
3
|
-
import { useAdmissionLocation } from './useMortuaryAdmissionLocation';
|
|
4
|
-
import useSWR from 'swr';
|
|
5
|
-
|
|
6
|
-
export const useDischargedPatient = (dischargeEncounterTypeUuid: string) => {
|
|
7
|
-
const url = dischargeEncounterTypeUuid
|
|
8
|
-
? `/ws/fhir2/R4/Encounter?_format=json&type=${dischargeEncounterTypeUuid}`
|
|
9
|
-
: null;
|
|
10
|
-
const { data, error, isLoading } = useFhirFetchAll<FHIREncounter>(url);
|
|
11
|
-
|
|
12
|
-
const dischargedPatientUuids = data
|
|
13
|
-
?.map((encounter) => {
|
|
14
|
-
const reference = encounter?.subject?.reference;
|
|
15
|
-
if (reference && reference.startsWith('Patient/')) {
|
|
16
|
-
return reference.split('/')[1];
|
|
17
|
-
}
|
|
18
|
-
return undefined;
|
|
19
|
-
})
|
|
20
|
-
.filter((uuid) => uuid);
|
|
21
|
-
|
|
22
|
-
const { admissionLocation } = useAdmissionLocation();
|
|
23
|
-
|
|
24
|
-
const admittedPatientUuids = admissionLocation?.bedLayouts
|
|
25
|
-
?.flatMap((bed) => bed.patients?.map((patient) => patient.uuid))
|
|
26
|
-
.filter(Boolean);
|
|
27
|
-
|
|
28
|
-
const filteredDischargedPatientUuids = dischargedPatientUuids?.filter(
|
|
29
|
-
(uuid) => !admittedPatientUuids?.includes(uuid),
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
const uniqueDischargedPatientUuids = [...new Set(filteredDischargedPatientUuids)];
|
|
33
|
-
|
|
34
|
-
return { dischargedPatientUuids: uniqueDischargedPatientUuids, error, isLoading };
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export const usePatients = (uuids: string[]) => {
|
|
38
|
-
const customRepresentation =
|
|
39
|
-
'custom:(uuid,display,identifiers:(uuid,display),person:(uuid,display,gender,birthdate,dead,age,deathDate,causeOfDeath:(uuid,display),attributes:(uuid,display,value,attributeType:(uuid,))))';
|
|
40
|
-
const urls = uuids.map((uuid) => `${restBaseUrl}/patient/${uuid}?v=${customRepresentation}`);
|
|
41
|
-
|
|
42
|
-
const { data, error, isLoading } = useSWR<FetchResponse<Patient>[]>(urls, (urls) =>
|
|
43
|
-
Promise.all(urls.map((url) => openmrsFetch<Patient>(url))),
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
const deceasedPatients = data?.map((response) => response.data)?.filter((patient) => patient?.person?.dead === true);
|
|
47
|
-
|
|
48
|
-
return {
|
|
49
|
-
isLoading,
|
|
50
|
-
error,
|
|
51
|
-
patients: deceasedPatients,
|
|
52
|
-
};
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export default usePatients;
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
FetchResponse,
|
|
3
|
-
openmrsFetch,
|
|
4
|
-
openmrsObservableFetch,
|
|
5
|
-
OpenmrsResource,
|
|
6
|
-
restBaseUrl,
|
|
7
|
-
toDateObjectStrict,
|
|
8
|
-
toOmrsIsoString,
|
|
9
|
-
useConfig,
|
|
10
|
-
useOpenmrsPagination,
|
|
11
|
-
} from '@openmrs/esm-framework';
|
|
12
|
-
import {
|
|
13
|
-
DeceasedPatientResponse,
|
|
14
|
-
PaymentMethod,
|
|
15
|
-
VisitTypeResponse,
|
|
16
|
-
Location,
|
|
17
|
-
Patient,
|
|
18
|
-
Visit,
|
|
19
|
-
UseVisitQueueEntries,
|
|
20
|
-
VisitQueueEntry,
|
|
21
|
-
MappedVisitQueueEntry,
|
|
22
|
-
UpdateVisitPayload,
|
|
23
|
-
PaginatedResponse,
|
|
24
|
-
} from '../types';
|
|
25
|
-
import useSWR from 'swr';
|
|
26
|
-
import { BillingConfig, ConfigObject } from '../config-schema';
|
|
27
|
-
import { useEffect, useState } from 'react';
|
|
28
|
-
import useSWRImmutable from 'swr/immutable';
|
|
29
|
-
import { makeUrlUrl } from '../utils/utils';
|
|
30
|
-
import type { Observable } from 'rxjs';
|
|
31
|
-
|
|
32
|
-
export const useVisitType = () => {
|
|
33
|
-
const customRepresentation = 'custom:(uuid,display,name)';
|
|
34
|
-
const url = `${restBaseUrl}/visittype?v=${customRepresentation}`;
|
|
35
|
-
const { data, error, isLoading } = useSWR<FetchResponse<{ results: VisitTypeResponse[] }>>(url, openmrsFetch);
|
|
36
|
-
const visitType = data?.data?.results || null;
|
|
37
|
-
|
|
38
|
-
return { data: visitType, error, isLoading };
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export const usePaymentModes = (excludeWaiver: boolean = true) => {
|
|
42
|
-
const { excludedPaymentMode } = useConfig<BillingConfig>();
|
|
43
|
-
const url = `${restBaseUrl}/cashier/paymentMode?v=full`;
|
|
44
|
-
const { data, isLoading, error, mutate } = useSWR<{ data: { results: Array<PaymentMethod> } }>(url, openmrsFetch, {
|
|
45
|
-
errorRetryCount: 2,
|
|
46
|
-
});
|
|
47
|
-
const allowedPaymentModes =
|
|
48
|
-
excludedPaymentMode?.length > 0
|
|
49
|
-
? data?.data?.results.filter((mode) => !excludedPaymentMode.some((excluded) => excluded.uuid === mode.uuid)) ?? []
|
|
50
|
-
: data?.data?.results ?? [];
|
|
51
|
-
return {
|
|
52
|
-
paymentModes: excludeWaiver ? allowedPaymentModes : data?.data?.results,
|
|
53
|
-
isLoading,
|
|
54
|
-
mutate,
|
|
55
|
-
error,
|
|
56
|
-
};
|
|
57
|
-
};
|
|
58
|
-
export const useBillableItems = () => {
|
|
59
|
-
const url = `${restBaseUrl}/cashier/billableService?v=custom:(uuid,name,shortName,serviceStatus,serviceType:(uuid,display),servicePrices:(uuid,name,price,paymentMode))`;
|
|
60
|
-
const { data, isLoading, error } = useSWR<{ data: { results: Array<OpenmrsResource> } }>(url, openmrsFetch);
|
|
61
|
-
const [searchTerm, setSearchTerm] = useState('');
|
|
62
|
-
const filteredItems =
|
|
63
|
-
data?.data?.results?.filter((item) => item.name.toLowerCase().includes(searchTerm.toLowerCase())) ?? [];
|
|
64
|
-
return {
|
|
65
|
-
lineItems: filteredItems,
|
|
66
|
-
isLoading,
|
|
67
|
-
error,
|
|
68
|
-
searchTerm,
|
|
69
|
-
setSearchTerm,
|
|
70
|
-
};
|
|
71
|
-
};
|
|
72
|
-
// // Used
|
|
73
|
-
export const createPatientBill = (payload) => {
|
|
74
|
-
const postUrl = `${restBaseUrl}/cashier/bill`;
|
|
75
|
-
return openmrsFetch(postUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: payload });
|
|
76
|
-
};
|
|
77
|
-
// Used
|
|
78
|
-
export const useCashPoint = () => {
|
|
79
|
-
const url = `/ws/rest/v1/cashier/cashPoint`;
|
|
80
|
-
const { data, isLoading, error } = useSWR<{ data: { results: Array<OpenmrsResource> } }>(url, openmrsFetch);
|
|
81
|
-
|
|
82
|
-
return { isLoading, error, cashPoints: data?.data?.results ?? [] };
|
|
83
|
-
};
|
|
84
|
-
// // Used
|
|
85
|
-
|
|
86
|
-
export function useVisitQueueEntry(patientUuid, visitUuid): UseVisitQueueEntries {
|
|
87
|
-
const apiUrl = `${restBaseUrl}/visit-queue-entry?v=full&patient=${patientUuid}`;
|
|
88
|
-
const { data, error, isLoading, isValidating, mutate } = useSWR<{ data: { results: Array<VisitQueueEntry> } }, Error>(
|
|
89
|
-
apiUrl,
|
|
90
|
-
openmrsFetch,
|
|
91
|
-
);
|
|
92
|
-
const mapVisitQueueEntryProperties = (visitQueueEntry: VisitQueueEntry): MappedVisitQueueEntry => ({
|
|
93
|
-
id: visitQueueEntry.uuid,
|
|
94
|
-
name: visitQueueEntry.queueEntry.queue.display,
|
|
95
|
-
patientUuid: visitQueueEntry.queueEntry.patient.uuid,
|
|
96
|
-
priority:
|
|
97
|
-
visitQueueEntry.queueEntry.priority.display === 'Urgent'
|
|
98
|
-
? 'Priority'
|
|
99
|
-
: visitQueueEntry.queueEntry.priority.display,
|
|
100
|
-
priorityUuid: visitQueueEntry.queueEntry.priority.uuid,
|
|
101
|
-
service: visitQueueEntry.queueEntry.queue?.display,
|
|
102
|
-
status: visitQueueEntry.queueEntry.status.display,
|
|
103
|
-
statusUuid: visitQueueEntry.queueEntry.status.uuid,
|
|
104
|
-
visitUuid: visitQueueEntry.visit?.uuid,
|
|
105
|
-
visitType: visitQueueEntry.visit?.visitType?.display,
|
|
106
|
-
queue: visitQueueEntry.queueEntry.queue,
|
|
107
|
-
queueEntryUuid: visitQueueEntry.queueEntry.uuid,
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
const mappedVisitQueueEntry =
|
|
111
|
-
data?.data?.results
|
|
112
|
-
?.map(mapVisitQueueEntryProperties)
|
|
113
|
-
.filter((visitQueueEntry) => visitUuid !== undefined && visitUuid === visitQueueEntry.visitUuid)
|
|
114
|
-
.shift() ?? null;
|
|
115
|
-
return {
|
|
116
|
-
queueEntry: mappedVisitQueueEntry,
|
|
117
|
-
isLoading,
|
|
118
|
-
error: error,
|
|
119
|
-
isValidating,
|
|
120
|
-
mutate,
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
export const usePerson = (uuid: string) => {
|
|
124
|
-
const customRepresentation = `custom:(uuid,display,gender,birthdate,dead,age,deathDate,causeOfDeath:(uuid,display))`;
|
|
125
|
-
const url = `${restBaseUrl}/person/${uuid}?v=${customRepresentation}`;
|
|
126
|
-
const { isLoading, error, data } = useSWR<FetchResponse<Patient['person']>>(url, openmrsFetch);
|
|
127
|
-
const person = data?.data;
|
|
128
|
-
return { isLoading, error, person };
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
// Used
|
|
132
|
-
export function removeQueuedPatient(
|
|
133
|
-
queueUuid: string,
|
|
134
|
-
queueEntryUuid: string,
|
|
135
|
-
abortController: AbortController,
|
|
136
|
-
endedAt?: Date,
|
|
137
|
-
) {
|
|
138
|
-
return openmrsFetch(`${restBaseUrl}/queue/${queueUuid}/entry/${queueEntryUuid}`, {
|
|
139
|
-
method: 'POST',
|
|
140
|
-
headers: {
|
|
141
|
-
'Content-Type': 'application/json',
|
|
142
|
-
},
|
|
143
|
-
body: {
|
|
144
|
-
endedAt: toDateObjectStrict(toOmrsIsoString(endedAt) ?? toOmrsIsoString(new Date())),
|
|
145
|
-
},
|
|
146
|
-
signal: abortController.signal,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
export function updateVisit(
|
|
151
|
-
uuid: string,
|
|
152
|
-
payload: UpdateVisitPayload,
|
|
153
|
-
abortController: AbortController,
|
|
154
|
-
): Observable<any> {
|
|
155
|
-
return openmrsObservableFetch(`${restBaseUrl}/visit/${uuid}`, {
|
|
156
|
-
signal: abortController.signal,
|
|
157
|
-
method: 'POST',
|
|
158
|
-
headers: {
|
|
159
|
-
'Content-type': 'application/json',
|
|
160
|
-
},
|
|
161
|
-
body: payload,
|
|
162
|
-
});
|
|
163
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type FetchResponse,
|
|
3
|
-
openmrsFetch,
|
|
4
|
-
restBaseUrl,
|
|
5
|
-
useFeatureFlag,
|
|
6
|
-
type Location,
|
|
7
|
-
useSession,
|
|
8
|
-
} from '@openmrs/esm-framework';
|
|
9
|
-
import useSWR from 'swr';
|
|
10
|
-
import useSWRImmutable from 'swr/immutable';
|
|
11
|
-
import { useParams } from 'react-router-dom';
|
|
12
|
-
import { type MortuaryLocationFetchResponse, type FHIREncounter } from '../types';
|
|
13
|
-
|
|
14
|
-
export function useLocation(locationUuid: string, rep: string = 'custom:(display,uuid)') {
|
|
15
|
-
return useSWRImmutable<FetchResponse<Location>>(
|
|
16
|
-
locationUuid ? `${restBaseUrl}/location/${locationUuid}?v=${rep}` : null,
|
|
17
|
-
openmrsFetch,
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function useMortuaryLocation(): {
|
|
22
|
-
location: Location | undefined;
|
|
23
|
-
isLoadingLocation: boolean;
|
|
24
|
-
errorFetchingLocation: Error | undefined;
|
|
25
|
-
invalidLocation: boolean;
|
|
26
|
-
} {
|
|
27
|
-
const { locationUuid: locationUuidFromUrl } = useParams();
|
|
28
|
-
const { sessionLocation } = useSession();
|
|
29
|
-
|
|
30
|
-
const {
|
|
31
|
-
data: locationResponse,
|
|
32
|
-
isLoading: isLoadingLocation,
|
|
33
|
-
error: errorFetchingLocation,
|
|
34
|
-
} = useLocation(locationUuidFromUrl ?? null);
|
|
35
|
-
|
|
36
|
-
const invalidLocation = !!locationUuidFromUrl && !!errorFetchingLocation;
|
|
37
|
-
|
|
38
|
-
return {
|
|
39
|
-
location: locationUuidFromUrl ? locationResponse?.data : sessionLocation,
|
|
40
|
-
isLoadingLocation,
|
|
41
|
-
errorFetchingLocation,
|
|
42
|
-
invalidLocation,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const requestRep =
|
|
47
|
-
'custom:(ward,totalBeds,occupiedBeds,bedLayouts:(rowNumber,columnNumber,bedNumber,bedId,bedUuid,status,location,patients:(person:full,identifiers,uuid)))';
|
|
48
|
-
|
|
49
|
-
export function useAdmissionLocation(rep: string = requestRep) {
|
|
50
|
-
const { location } = useMortuaryLocation();
|
|
51
|
-
const isBedManagementModuleInstalled = useFeatureFlag('bedmanagement-module');
|
|
52
|
-
|
|
53
|
-
const apiUrl = location?.uuid ? `${restBaseUrl}/admissionLocation/${location.uuid}?v=${rep}` : null;
|
|
54
|
-
|
|
55
|
-
const { data, ...rest } = useSWR<FetchResponse<MortuaryLocationFetchResponse>, Error>(
|
|
56
|
-
isBedManagementModuleInstalled ? apiUrl : null,
|
|
57
|
-
openmrsFetch,
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
return {
|
|
61
|
-
admissionLocation: data?.data,
|
|
62
|
-
...rest,
|
|
63
|
-
};
|
|
64
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import { useTranslation } from 'react-i18next';
|
|
3
|
-
import { UserHasAccess } from '@openmrs/esm-framework';
|
|
4
|
-
import DeceasedFilter from '../header/admitted-queue-header.component';
|
|
5
|
-
import styles from './admitted-queue.scss';
|
|
6
|
-
import CompartmentView from '../card/compartment-view.compartment';
|
|
7
|
-
import { useAdmissionLocation } from '../hook/useMortuaryAdmissionLocation';
|
|
8
|
-
import { InlineLoading } from '@carbon/react';
|
|
9
|
-
import { CardHeader, ErrorState } from '@openmrs/esm-patient-common-lib';
|
|
10
|
-
import EmptyMorgueAdmission from '../empty-state/empty-morgue-admission.component';
|
|
11
|
-
import useEmrConfiguration from '../hook/useAdmitPatient';
|
|
12
|
-
import { useDischargedPatient } from '../hook/useDischargedPatient';
|
|
13
|
-
|
|
14
|
-
export const AdmittedQueue: React.FC = () => {
|
|
15
|
-
const { t } = useTranslation();
|
|
16
|
-
const [searchQuery, setSearchQuery] = useState('');
|
|
17
|
-
const { admissionLocation, isLoading, error } = useAdmissionLocation();
|
|
18
|
-
const handleSearchChange = (query: string) => {
|
|
19
|
-
setSearchQuery(query);
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
if (isLoading) {
|
|
23
|
-
return <InlineLoading description={t('loading', 'Loading...')} />;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (error) {
|
|
27
|
-
return <ErrorState headerTitle={t('errorLoadingData', 'Error loading data')} error={error} />;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const filteredBedLayouts = admissionLocation?.bedLayouts?.filter((bed) => {
|
|
31
|
-
return bed.patients.some((patient) => patient?.person?.display?.toLowerCase().includes(searchQuery.toLowerCase()));
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
<div className={styles.layoutWrapper}>
|
|
36
|
-
<CardHeader title={t('allocation', 'Allocation')} children={''} />
|
|
37
|
-
<DeceasedFilter onSearchChange={handleSearchChange} />
|
|
38
|
-
<div className={styles.patientCardContainer}>
|
|
39
|
-
{filteredBedLayouts?.length === 0 ? (
|
|
40
|
-
<EmptyMorgueAdmission
|
|
41
|
-
title={t('allocations', 'Allocation')}
|
|
42
|
-
subTitle={t('noAdmittedBodies', 'There are no admitted bodies matching your search')}
|
|
43
|
-
/>
|
|
44
|
-
) : (
|
|
45
|
-
<UserHasAccess privilege="o3 : View Mortuary Compartments">
|
|
46
|
-
<CompartmentView />
|
|
47
|
-
</UserHasAccess>
|
|
48
|
-
)}
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
);
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export default AdmittedQueue;
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
@use '@carbon/layout';
|
|
2
|
-
@use '@carbon/type';
|
|
3
|
-
@use '@carbon/colors';
|
|
4
|
-
// @use '~@openmrs/esm-styleguide/src/vars' as *;
|
|
5
|
-
|
|
6
|
-
.container {
|
|
7
|
-
display: flex;
|
|
8
|
-
flex-wrap: wrap;
|
|
9
|
-
justify-content: space-between;
|
|
10
|
-
margin: layout.$spacing-04;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
.column {
|
|
14
|
-
width: calc(25% - 1rem);
|
|
15
|
-
height: 776px;
|
|
16
|
-
flex-grow: 0;
|
|
17
|
-
display: flex;
|
|
18
|
-
flex-direction: column;
|
|
19
|
-
justify-content: flex-start;
|
|
20
|
-
align-items: center;
|
|
21
|
-
gap: layout.$spacing-03;
|
|
22
|
-
padding: 0;
|
|
23
|
-
margin: 0.5rem;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
.tile {
|
|
27
|
-
width: 340px;
|
|
28
|
-
height: layout.$spacing-09;
|
|
29
|
-
display: flex;
|
|
30
|
-
justify-content: center;
|
|
31
|
-
align-items: center;
|
|
32
|
-
margin: layout.$spacing-03 0;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.tileContent {
|
|
36
|
-
display: flex;
|
|
37
|
-
justify-content: center;
|
|
38
|
-
align-items: center;
|
|
39
|
-
gap: layout.$spacing-04;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
.label {
|
|
43
|
-
width: layout.$spacing-07;
|
|
44
|
-
height: layout.$spacing-07;
|
|
45
|
-
display: flex;
|
|
46
|
-
justify-content: center;
|
|
47
|
-
align-items: center;
|
|
48
|
-
font-size: layout.$spacing-01;
|
|
49
|
-
font-weight: 600;
|
|
50
|
-
line-height: 1.29;
|
|
51
|
-
background-color: colors.$cool-gray-20;
|
|
52
|
-
border: 1px solid colors.$cool-gray-20;
|
|
53
|
-
border-radius: 50%;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.emptyunit {
|
|
57
|
-
line-height: 1.38;
|
|
58
|
-
}
|
|
59
|
-
.layoutWrapper {
|
|
60
|
-
border: 1px solid colors.$gray-30;
|
|
61
|
-
padding: layout.$spacing-05 layout.$spacing-05;
|
|
62
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { DataTableSkeleton } from '@carbon/react';
|
|
2
|
-
import { ConfigurableLink, ErrorState, formatDate, useConfig } from '@openmrs/esm-framework';
|
|
3
|
-
import React from 'react';
|
|
4
|
-
import { useTranslation } from 'react-i18next';
|
|
5
|
-
import styles from './generic-table.scss';
|
|
6
|
-
import GenericTable from './generic-table.component';
|
|
7
|
-
import { ConfigObject } from '../config-schema';
|
|
8
|
-
import usePatients from '../hook/useDischargedPatient';
|
|
9
|
-
|
|
10
|
-
interface DischargedProps {
|
|
11
|
-
dischargedPatientUuids: string[];
|
|
12
|
-
isLoading: boolean;
|
|
13
|
-
error: any;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const DischargedBodies: React.FC<DischargedProps> = ({ isLoading, error, dischargedPatientUuids }) => {
|
|
17
|
-
const { t } = useTranslation();
|
|
18
|
-
const dischargedInLine = t('dischargeBodies', 'Discharged bodies');
|
|
19
|
-
const patientChartUrl = '${openmrsSpaBase}/patient/${patientUuid}/chart/deceased-panel';
|
|
20
|
-
const { patients, isLoading: isLoadingPatients, error: patientsError } = usePatients(dischargedPatientUuids);
|
|
21
|
-
|
|
22
|
-
const { nextOfKinAddressUuid, nextOfKinNameUuid, nextOfKinPhoneUuid, nextOfKinRelationshipUuid } =
|
|
23
|
-
useConfig<ConfigObject>();
|
|
24
|
-
|
|
25
|
-
const genericTableHeader = [
|
|
26
|
-
{ header: 'Patient Name', key: 'name' },
|
|
27
|
-
{ header: 'Gender', key: 'gender' },
|
|
28
|
-
{ header: 'Identifier', key: 'identifier' },
|
|
29
|
-
{ header: 'Age', key: 'age' },
|
|
30
|
-
{ header: 'Date of Death', key: 'deathDate' },
|
|
31
|
-
{ header: 'Cause of Death', key: 'causeOfDeath' },
|
|
32
|
-
];
|
|
33
|
-
|
|
34
|
-
if (isLoading) {
|
|
35
|
-
return (
|
|
36
|
-
<div className={styles.table}>
|
|
37
|
-
<DataTableSkeleton
|
|
38
|
-
headers={genericTableHeader}
|
|
39
|
-
aria-label="discharged-datatable"
|
|
40
|
-
showToolbar={false}
|
|
41
|
-
showHeader={false}
|
|
42
|
-
rowCount={10}
|
|
43
|
-
zebra
|
|
44
|
-
columnCount={7}
|
|
45
|
-
/>
|
|
46
|
-
</div>
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (error) {
|
|
51
|
-
return <ErrorState error={error} headerTitle={t('dischargeBodies', 'Discharged bodies')} />;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const getAttributeValue = (patient, uuid) => {
|
|
55
|
-
return patient?.person?.attributes?.find((attr) => attr?.attributeType?.uuid === uuid)?.value || '--';
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const rows = patients?.map((patient) => {
|
|
59
|
-
const openmrsID = patient?.identifiers?.find((id) => id.display.startsWith('OpenMRS ID'))?.display.split(' = ')[1];
|
|
60
|
-
|
|
61
|
-
const nextOfKin = {
|
|
62
|
-
name: getAttributeValue(patient, nextOfKinNameUuid),
|
|
63
|
-
phone: getAttributeValue(patient, nextOfKinPhoneUuid),
|
|
64
|
-
address: getAttributeValue(patient, nextOfKinAddressUuid),
|
|
65
|
-
relationship: getAttributeValue(patient, nextOfKinRelationshipUuid),
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
return {
|
|
69
|
-
id: patient?.uuid,
|
|
70
|
-
name: (
|
|
71
|
-
<ConfigurableLink
|
|
72
|
-
style={{ textDecoration: 'none', maxWidth: '50%' }}
|
|
73
|
-
to={patientChartUrl}
|
|
74
|
-
templateParams={{ patientUuid: patient?.uuid }}>
|
|
75
|
-
{patient?.person?.display?.toUpperCase()}
|
|
76
|
-
</ConfigurableLink>
|
|
77
|
-
),
|
|
78
|
-
gender: patient?.person?.gender || '--',
|
|
79
|
-
age: patient?.person?.age || '--',
|
|
80
|
-
identifier: openmrsID || '--',
|
|
81
|
-
deathDate: formatDate(new Date(patient?.person?.deathDate)) || '--',
|
|
82
|
-
causeOfDeath: patient?.person?.causeOfDeath?.display || '--',
|
|
83
|
-
nextOfKin: nextOfKin, // Ensure nextOfKin is included in the row
|
|
84
|
-
};
|
|
85
|
-
});
|
|
86
|
-
return <GenericTable rows={rows} headers={genericTableHeader} title={dischargedInLine} />;
|
|
87
|
-
};
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import classNames from 'classnames';
|
|
3
|
-
import { useTranslation } from 'react-i18next';
|
|
4
|
-
import {
|
|
5
|
-
DataTable,
|
|
6
|
-
Table,
|
|
7
|
-
TableCell,
|
|
8
|
-
TableContainer,
|
|
9
|
-
TableBody,
|
|
10
|
-
TableHead,
|
|
11
|
-
TableHeader,
|
|
12
|
-
TableRow,
|
|
13
|
-
TableExpandRow,
|
|
14
|
-
TableExpandedRow,
|
|
15
|
-
Search,
|
|
16
|
-
TableExpandHeader,
|
|
17
|
-
} from '@carbon/react';
|
|
18
|
-
import { CardHeader, PatientChartPagination } from '@openmrs/esm-patient-common-lib';
|
|
19
|
-
import { useLayoutType, usePagination } from '@openmrs/esm-framework';
|
|
20
|
-
import styles from './generic-table.scss';
|
|
21
|
-
import EmptyDeceasedSearch from '../empty-state/empty-morgue-admission.component';
|
|
22
|
-
import { Patient } from '../types';
|
|
23
|
-
import NextOfKinDetails from '../component/next-of-kin-details/nextOfKinDetails.component';
|
|
24
|
-
|
|
25
|
-
interface GenericTableProps {
|
|
26
|
-
rows: any[];
|
|
27
|
-
headers: { header: string; key: string }[];
|
|
28
|
-
actionColumn?: (row: any) => React.ReactNode;
|
|
29
|
-
title?: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const GenericTable: React.FC<GenericTableProps> = ({ rows, headers, actionColumn, title }) => {
|
|
33
|
-
const { t } = useTranslation();
|
|
34
|
-
const pageSize = 10;
|
|
35
|
-
const isTablet = useLayoutType() === 'tablet';
|
|
36
|
-
|
|
37
|
-
const [searchTerm, setSearchTerm] = useState('');
|
|
38
|
-
|
|
39
|
-
const filteredRows = rows?.filter((row) =>
|
|
40
|
-
headers.some((header) => row[header.key]?.toString().toLowerCase().includes(searchTerm.toLowerCase())),
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
const { results: paginatedData, currentPage, goTo } = usePagination(filteredRows, pageSize);
|
|
44
|
-
|
|
45
|
-
return (
|
|
46
|
-
<div className={styles.table}>
|
|
47
|
-
<CardHeader title={title} children={''} />
|
|
48
|
-
<div className={styles.searchContainer}>
|
|
49
|
-
<Search
|
|
50
|
-
size="sm"
|
|
51
|
-
placeholder="Search for deceased"
|
|
52
|
-
labelText="Search"
|
|
53
|
-
closeButtonLabelText="Clear search input"
|
|
54
|
-
id="search-deceased"
|
|
55
|
-
value={searchTerm}
|
|
56
|
-
onChange={(e) => setSearchTerm(e.target.value)}
|
|
57
|
-
className={styles.searchInput}
|
|
58
|
-
/>
|
|
59
|
-
</div>
|
|
60
|
-
|
|
61
|
-
{rows?.length === 0 ? (
|
|
62
|
-
<EmptyDeceasedSearch
|
|
63
|
-
title={t('noWaitingList', 'Waiting List')}
|
|
64
|
-
subTitle={t('noDeceasedPersons', 'There are no deceased persons on the waiting list')}
|
|
65
|
-
/>
|
|
66
|
-
) : searchTerm && filteredRows?.length === 0 ? (
|
|
67
|
-
<EmptyDeceasedSearch
|
|
68
|
-
title={t('noResultFound', 'Sorry, no results found')}
|
|
69
|
-
subTitle={t('searchForADeceased', "Try to search again using the deceased patient's unique ID number")}
|
|
70
|
-
/>
|
|
71
|
-
) : (
|
|
72
|
-
<div className={styles.genericTable}>
|
|
73
|
-
<DataTable rows={paginatedData} headers={headers} isSortable size={isTablet ? 'lg' : 'sm'} useZebraStyles>
|
|
74
|
-
{({
|
|
75
|
-
rows: tableRows,
|
|
76
|
-
headers,
|
|
77
|
-
getHeaderProps,
|
|
78
|
-
getTableProps,
|
|
79
|
-
getRowProps,
|
|
80
|
-
getTableContainerProps,
|
|
81
|
-
getExpandHeaderProps,
|
|
82
|
-
}) => (
|
|
83
|
-
<TableContainer {...getTableContainerProps()} className={styles.tableContainer}>
|
|
84
|
-
<Table {...getTableProps()}>
|
|
85
|
-
<TableHead>
|
|
86
|
-
<TableRow>
|
|
87
|
-
<TableExpandHeader enableToggle {...getExpandHeaderProps()} />
|
|
88
|
-
{headers?.map((header, i) => (
|
|
89
|
-
<TableHeader
|
|
90
|
-
key={i}
|
|
91
|
-
{...getHeaderProps({
|
|
92
|
-
header,
|
|
93
|
-
})}>
|
|
94
|
-
{header.header}
|
|
95
|
-
</TableHeader>
|
|
96
|
-
))}
|
|
97
|
-
{actionColumn && <TableHeader>Action</TableHeader>}
|
|
98
|
-
</TableRow>
|
|
99
|
-
</TableHead>
|
|
100
|
-
<TableBody>
|
|
101
|
-
{tableRows?.map((row, i) => {
|
|
102
|
-
const originalRow = rows.find((r) => r.id === row.id);
|
|
103
|
-
|
|
104
|
-
return (
|
|
105
|
-
<React.Fragment key={row.id}>
|
|
106
|
-
<TableExpandRow {...getRowProps({ row })}>
|
|
107
|
-
{row.cells.map((cell) => (
|
|
108
|
-
<TableCell key={cell.id}>{cell.value}</TableCell>
|
|
109
|
-
))}
|
|
110
|
-
{actionColumn && <TableCell>{actionColumn(row)}</TableCell>}
|
|
111
|
-
</TableExpandRow>
|
|
112
|
-
{row.isExpanded && (
|
|
113
|
-
<TableExpandedRow colSpan={headers.length + 1}>
|
|
114
|
-
<div className={styles.expandedRowContent}>
|
|
115
|
-
{originalRow && <NextOfKinDetails nextOfKin={originalRow.nextOfKin} />}
|
|
116
|
-
</div>
|
|
117
|
-
</TableExpandedRow>
|
|
118
|
-
)}
|
|
119
|
-
</React.Fragment>
|
|
120
|
-
);
|
|
121
|
-
})}
|
|
122
|
-
</TableBody>
|
|
123
|
-
</Table>
|
|
124
|
-
</TableContainer>
|
|
125
|
-
)}
|
|
126
|
-
</DataTable>
|
|
127
|
-
<PatientChartPagination
|
|
128
|
-
currentItems={paginatedData?.length}
|
|
129
|
-
totalItems={filteredRows?.length}
|
|
130
|
-
onPageNumberChange={({ page }) => goTo(page)}
|
|
131
|
-
pageNumber={currentPage}
|
|
132
|
-
pageSize={pageSize}
|
|
133
|
-
/>
|
|
134
|
-
</div>
|
|
135
|
-
)}
|
|
136
|
-
</div>
|
|
137
|
-
);
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
export default GenericTable;
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
@use '@carbon/layout';
|
|
2
|
-
@use '@carbon/type';
|
|
3
|
-
@use '@carbon/colors';
|
|
4
|
-
|
|
5
|
-
.genericTable {
|
|
6
|
-
margin: 0 auto;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
.searchContainer {
|
|
10
|
-
margin-bottom: layout.$spacing-05;
|
|
11
|
-
border: solid colors.$gray-30 0.1rem;
|
|
12
|
-
margin-left: layout.$spacing-06;
|
|
13
|
-
margin-right: layout.$spacing-06;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.tableContainer {
|
|
17
|
-
margin: 0 layout.$spacing-05;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
.actionBtn {
|
|
21
|
-
--cds-layout-size-height-context: var(--cds-layout-size-height-sm, 2rem);
|
|
22
|
-
--cds-layout-size-height: var(--cds-layout-size-height-context);
|
|
23
|
-
display: flex;
|
|
24
|
-
align-items: center;
|
|
25
|
-
justify-content: center;
|
|
26
|
-
text-align: center;
|
|
27
|
-
padding: 0 layout.$spacing-04;
|
|
28
|
-
}
|
|
29
|
-
.table {
|
|
30
|
-
border: 1px solid colors.$gray-30;
|
|
31
|
-
width: 98%;
|
|
32
|
-
margin: 0 auto;
|
|
33
|
-
}
|
|
34
|
-
.groupButtons {
|
|
35
|
-
display: flex;
|
|
36
|
-
gap: layout.$spacing-05;
|
|
37
|
-
}
|