@kenyaemr/esm-morgue-app 5.4.1-pre.1848 → 5.4.1-pre.1850

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.
Files changed (111) hide show
  1. package/.turbo/turbo-build.log +84 -21
  2. package/dist/160.js +1 -0
  3. package/dist/160.js.map +1 -0
  4. package/dist/195.js +1 -0
  5. package/dist/195.js.map +1 -0
  6. package/dist/240.js +1 -0
  7. package/dist/240.js.map +1 -0
  8. package/dist/282.js +1 -0
  9. package/dist/282.js.map +1 -0
  10. package/dist/300.js +1 -1
  11. package/dist/{561.js → 521.js} +1 -1
  12. package/dist/521.js.map +1 -0
  13. package/dist/527.js +1 -0
  14. package/dist/527.js.map +1 -0
  15. package/dist/596.js +1 -0
  16. package/dist/596.js.map +1 -0
  17. package/dist/652.js +1 -1
  18. package/dist/652.js.map +1 -1
  19. package/dist/659.js +2 -0
  20. package/dist/659.js.map +1 -0
  21. package/dist/675.js +2 -0
  22. package/dist/{485.js.map → 675.js.map} +1 -1
  23. package/dist/730.js +1 -0
  24. package/dist/730.js.map +1 -0
  25. package/dist/755.js +1 -0
  26. package/dist/755.js.map +1 -0
  27. package/dist/795.js +1 -0
  28. package/dist/795.js.map +1 -0
  29. package/dist/818.js +1 -0
  30. package/dist/818.js.map +1 -0
  31. package/dist/{942.js → 870.js} +1 -1
  32. package/dist/870.js.map +1 -0
  33. package/dist/909.js +2 -0
  34. package/dist/909.js.map +1 -0
  35. package/dist/926.js +1 -1
  36. package/dist/926.js.map +1 -1
  37. package/dist/929.js +1 -0
  38. package/dist/929.js.map +1 -0
  39. package/dist/960.js +1 -0
  40. package/dist/960.js.map +1 -0
  41. package/dist/kenyaemr-esm-morgue-app.js +1 -1
  42. package/dist/kenyaemr-esm-morgue-app.js.buildmanifest.json +371 -127
  43. package/dist/kenyaemr-esm-morgue-app.js.map +1 -1
  44. package/dist/main.js +1 -1
  45. package/dist/main.js.map +1 -1
  46. package/dist/routes.json +1 -1
  47. package/package.json +1 -1
  48. package/src/autosuggest/autosuggest.component.tsx +162 -0
  49. package/src/autosuggest/autosuggest.scss +61 -0
  50. package/src/autosuggest/patient-search-info.component.tsx +75 -0
  51. package/src/autosuggest/patient-search-info.scss +62 -0
  52. package/src/autosuggest/search-empty-state.component.tsx +21 -0
  53. package/src/autosuggest/search-empty-state.scss +18 -0
  54. package/src/card/avail-compartment.compartment.tsx +40 -41
  55. package/src/card/compartment-view.compartment.tsx +37 -14
  56. package/src/card/compartment.scss +18 -13
  57. package/src/card/compartmentSharing.component.tsx +21 -0
  58. package/src/card/compartmentSharing.scss +24 -0
  59. package/src/card/empty-compartment.component.tsx +11 -7
  60. package/src/card/empty-compartment.scss +61 -0
  61. package/src/component/deceasedInfo/deceased-info.component.tsx +1 -1
  62. package/src/component/main.component.tsx +1 -7
  63. package/src/component/next-of-kin-details/nextOfKinDetails.component.tsx +50 -0
  64. package/src/component/next-of-kin-details/nextOfKinDetails.scss +37 -0
  65. package/src/config-schema.ts +30 -22
  66. package/src/extension/actionButton.component.tsx +74 -0
  67. package/src/extension/actionButton.scss +69 -0
  68. package/src/extension/deceasedInfoBanner.component.tsx +57 -0
  69. package/src/hook/useAdmitPatient.ts +285 -0
  70. package/src/hook/useDeceasedPatients.ts +12 -0
  71. package/src/hook/useDischargedPatient.ts +55 -0
  72. package/src/hook/useMorgue.resource.ts +11 -120
  73. package/src/hook/useMortuaryAdmissionLocation.ts +64 -0
  74. package/src/hook/usePersonAttributes.ts +65 -0
  75. package/src/index.ts +4 -0
  76. package/src/routes.json +24 -7
  77. package/src/tables/admitted-queue.component.tsx +17 -21
  78. package/src/tables/discharge-queue.component.tsx +33 -27
  79. package/src/tables/generic-table.component.tsx +44 -19
  80. package/src/tabs/tabs.component.tsx +36 -16
  81. package/src/tabs/tabs.scss +3 -186
  82. package/src/types/index.ts +291 -9
  83. package/src/utils/utils.ts +55 -4
  84. package/src/workspaces/admit-body.scss +46 -0
  85. package/src/workspaces/admit-body.workspace.tsx +79 -0
  86. package/src/workspaces/discharge-body.scss +2 -2
  87. package/src/workspaces/discharge-body.workspace.tsx +157 -101
  88. package/src/workspaces/patientAdditionalInfoForm.workspace.tsx +141 -218
  89. package/src/workspaces/swap-unit.scss +46 -0
  90. package/src/workspaces/swap-unit.workspace.tsx +168 -0
  91. package/translations/en.json +22 -7
  92. package/dist/340.js +0 -1
  93. package/dist/340.js.map +0 -1
  94. package/dist/38.js +0 -1
  95. package/dist/38.js.map +0 -1
  96. package/dist/485.js +0 -2
  97. package/dist/553.js +0 -1
  98. package/dist/553.js.map +0 -1
  99. package/dist/561.js.map +0 -1
  100. package/dist/592.js +0 -2
  101. package/dist/592.js.map +0 -1
  102. package/dist/759.js +0 -1
  103. package/dist/759.js.map +0 -1
  104. package/dist/942.js.map +0 -1
  105. package/dist/987.js +0 -2
  106. package/dist/987.js.map +0 -1
  107. package/src/component/deceasedInfo/deceased-header.component.tsx +0 -37
  108. package/src/tables/waiting-queue.component.tsx +0 -91
  109. /package/dist/{987.js.LICENSE.txt → 659.js.LICENSE.txt} +0 -0
  110. /package/dist/{485.js.LICENSE.txt → 675.js.LICENSE.txt} +0 -0
  111. /package/dist/{592.js.LICENSE.txt → 909.js.LICENSE.txt} +0 -0
@@ -0,0 +1,74 @@
1
+ import { Button } from '@carbon/react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { launchWorkspace, navigate } from '@openmrs/esm-framework';
4
+ import { Movement, Return, ShareKnowledge } from '@carbon/react/icons';
5
+ import React from 'react';
6
+ import { useAdmissionLocation } from '../hook/useMortuaryAdmissionLocation';
7
+ import styles from './actionButton.scss';
8
+
9
+ interface ActionButtonProps {
10
+ patientUuid: string;
11
+ }
12
+
13
+ const ActionButton: React.FC<ActionButtonProps> = ({ patientUuid }) => {
14
+ const { t } = useTranslation();
15
+ const { admissionLocation, isLoading, error } = useAdmissionLocation();
16
+
17
+ const isPatientInAdmissionLocation = admissionLocation?.bedLayouts?.some((bed) =>
18
+ bed.patients.some((patient) => patient.uuid === patientUuid),
19
+ );
20
+
21
+ const bedId = admissionLocation?.bedLayouts?.find((bed) =>
22
+ bed.patients.some((patient) => patient.uuid === patientUuid),
23
+ )?.bedId;
24
+
25
+ const personUuid = admissionLocation?.bedLayouts
26
+ ?.find((bed) => bed.patients.some((patient) => patient.uuid === patientUuid))
27
+ ?.patients.find((patient) => patient.uuid === patientUuid)?.person?.uuid;
28
+
29
+ const handleNavigateToAllocationPage = () =>
30
+ navigate({
31
+ to: window.getOpenmrsSpaBase() + `home/morgue/allocation`,
32
+ });
33
+
34
+ const handleDischargeForm = (uuid: string, bedId: number) => {
35
+ launchWorkspace('discharge-body-form', {
36
+ workspaceTitle: t('dischargeForm', 'Discharge form'),
37
+ patientUuid: uuid,
38
+ bedId,
39
+ personUuid,
40
+ });
41
+ };
42
+
43
+ const handleSwapForm = (uuid: string, bedId: number) => {
44
+ launchWorkspace('swap-unit-form', {
45
+ workspaceTitle: t('swapCompartment', 'Swap compartment'),
46
+ patientUuid: uuid,
47
+ bedId,
48
+ });
49
+ };
50
+
51
+ return (
52
+ <div className={styles.actionButton}>
53
+ <Button kind="primary" size="sm" renderIcon={Return} onClick={handleNavigateToAllocationPage}>
54
+ {t('allocation', 'Allocation View')}
55
+ </Button>
56
+ {isPatientInAdmissionLocation && (
57
+ <>
58
+ <Button
59
+ kind="secondary"
60
+ size="sm"
61
+ renderIcon={ShareKnowledge}
62
+ onClick={() => handleSwapForm(patientUuid, bedId)}>
63
+ {t('swapCompartment', 'Swap compartment')}
64
+ </Button>
65
+ <Button kind="danger" size="sm" renderIcon={Movement} onClick={() => handleDischargeForm(patientUuid, bedId)}>
66
+ {t('discharge', 'Discharge body')}
67
+ </Button>
68
+ </>
69
+ )}
70
+ </div>
71
+ );
72
+ };
73
+
74
+ export default ActionButton;
@@ -0,0 +1,69 @@
1
+ @use '@carbon/layout';
2
+ @use '@carbon/type';
3
+ @use '@carbon/colors';
4
+
5
+ .actionButton {
6
+ display: flex;
7
+ gap: layout.$spacing-03;
8
+ }
9
+
10
+ .metrics {
11
+ display: flex;
12
+ flex-direction: row;
13
+ justify-content: flex-end;
14
+ align-items: center;
15
+ gap: layout.$spacing-06;
16
+ flex-wrap: wrap;
17
+ padding: layout.$spacing-04 layout.$spacing-05 0 0;
18
+ width: auto;
19
+ height: auto;
20
+ }
21
+
22
+ .wrapMetrics {
23
+ display: flex;
24
+ flex-direction: column;
25
+ justify-content: center;
26
+ align-items: flex-start;
27
+ gap: layout.$spacing-03;
28
+ padding: 0;
29
+ min-width: layout.$spacing-12;
30
+ }
31
+
32
+ .metricLabel {
33
+ flex-grow: 0;
34
+ font-size: layout.$spacing-04;
35
+ line-height: 1.33;
36
+ letter-spacing: 0.32px;
37
+ text-align: left;
38
+ white-space: nowrap;
39
+ overflow: hidden;
40
+ text-overflow: ellipsis;
41
+ }
42
+
43
+ .metricValue {
44
+ flex-grow: 0;
45
+ font-size: type.type-scale(2);
46
+ color: colors.$gray-60;
47
+ line-height: 1.4;
48
+ text-align: left;
49
+ white-space: nowrap;
50
+ overflow: hidden;
51
+ text-overflow: ellipsis;
52
+ }
53
+
54
+ .metricLocationDate {
55
+ display: flex;
56
+ flex-direction: column;
57
+ justify-content: flex-start;
58
+ align-items: flex-start;
59
+ gap: layout.$spacing-05;
60
+ width: auto;
61
+ max-width: 120px;
62
+ }
63
+
64
+ .metricList {
65
+ display: flex;
66
+ flex-flow: row wrap;
67
+ padding-bottom: layout.$spacing-03;
68
+ margin: 0 layout.$spacing-05;
69
+ }
@@ -0,0 +1,57 @@
1
+ import { Button } from '@carbon/react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { launchWorkspace, navigate, usePatient, useVisit } from '@openmrs/esm-framework';
4
+ import { Movement, Return, ShareKnowledge } from '@carbon/react/icons';
5
+ import React from 'react';
6
+ import { useAdmissionLocation } from '../hook/useMortuaryAdmissionLocation';
7
+ import styles from './actionButton.scss';
8
+ import { convertDateToDays, formatDateTime } from '../utils/utils';
9
+ import { Console } from '@carbon/pictograms-react';
10
+
11
+ interface BannerInfoProps {
12
+ patientUuid: string;
13
+ }
14
+
15
+ const BannerInfo: React.FC<BannerInfoProps> = ({ patientUuid }) => {
16
+ const { t } = useTranslation();
17
+ const { admissionLocation, isLoading, error } = useAdmissionLocation();
18
+ const { patient } = usePatient(patientUuid);
19
+ const { currentVisit } = useVisit(patientUuid);
20
+
21
+ const bedNumber =
22
+ admissionLocation?.bedLayouts?.find((bed) => bed.patients.some((patient) => patient.uuid === patientUuid))
23
+ ?.bedNumber || t('discharged', 'Discharged');
24
+
25
+ const timeAndDateOfDeath = patient?.deceasedDateTime;
26
+
27
+ const startDate = currentVisit?.startDatetime;
28
+
29
+ const lengthOfStay = `${convertDateToDays(startDate)} ${
30
+ convertDateToDays(startDate) === 1 ? t('day', 'Day') : t('days', 'Days')
31
+ }`;
32
+
33
+ return (
34
+ <div className={styles.metricList}>
35
+ <div className={styles.metrics}>
36
+ <div className={styles.wrapMetrics}>
37
+ <span className={styles.metricLabel}>{t('dateOfAdmission', 'Date of admission')}</span>
38
+ <span className={styles.metricValue}>{formatDateTime(startDate)}</span>
39
+ </div>
40
+ <div className={styles.wrapMetrics}>
41
+ <span className={styles.metricLabel}>{t('dateAndTimeofDeath', 'Date and time of death')}</span>{' '}
42
+ <span className={styles.metricValue}>{formatDateTime(timeAndDateOfDeath)}</span>
43
+ </div>
44
+ <div className={styles.wrapMetrics}>
45
+ <span className={styles.metricLabel}>{t('lengthofStay', 'Length of stay')}</span>
46
+ <span className={styles.metricValue}>{lengthOfStay}</span>
47
+ </div>
48
+ <div className={styles.wrapMetrics}>
49
+ <span className={styles.metricLabel}>{t('compartment', 'Compartment')}</span>
50
+ <span className={styles.metricValue}>{bedNumber}</span>
51
+ </div>
52
+ </div>
53
+ </div>
54
+ );
55
+ };
56
+
57
+ export default BannerInfo;
@@ -0,0 +1,285 @@
1
+ import {
2
+ closeWorkspace,
3
+ FetchResponse,
4
+ openmrsFetch,
5
+ restBaseUrl,
6
+ showSnackbar,
7
+ updateVisit,
8
+ useConfig,
9
+ useSession,
10
+ type Visit,
11
+ } from '@openmrs/esm-framework';
12
+ import dayjs from 'dayjs';
13
+ import { useCallback, useMemo } from 'react';
14
+ import useSWR from 'swr';
15
+ import useSWRImmutable from 'swr/immutable';
16
+ import { z } from 'zod';
17
+ import { ConfigObject } from '../config-schema';
18
+ import {
19
+ CurrentLocationEncounterResponse,
20
+ customRepProps,
21
+ EmrApiConfigurationResponse,
22
+ Encounter,
23
+ MappedVisitQueueEntry,
24
+ VisitQueueEntry,
25
+ } from '../types';
26
+ import { dischargeSchema, patientInfoSchema } from '../utils/utils';
27
+ import { useMortuaryLocation } from './useMortuaryAdmissionLocation';
28
+ import { removeQueuedPatient } from './useMorgue.resource';
29
+ const customRep = `custom:${customRepProps.map((prop) => prop.join(':')).join(',')}`;
30
+
31
+ export default function useEmrConfiguration() {
32
+ const swrData = useSWRImmutable<FetchResponse<EmrApiConfigurationResponse>>(
33
+ `${restBaseUrl}/emrapi/configuration?v=${customRep}`,
34
+ openmrsFetch,
35
+ );
36
+
37
+ const results = useMemo(
38
+ () => ({
39
+ emrConfiguration: swrData.data?.data,
40
+ isLoadingEmrConfiguration: swrData.isLoading,
41
+ mutateEmrConfiguration: swrData.mutate,
42
+ errorFetchingEmrConfiguration: swrData.error,
43
+ }),
44
+ [swrData],
45
+ );
46
+ return results;
47
+ }
48
+
49
+ export const useMortuaryOperation = () => {
50
+ const { location } = useMortuaryLocation();
51
+ const { currentProvider } = useSession();
52
+ const { emrConfiguration, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } = useEmrConfiguration();
53
+ const {
54
+ visitPaymentMethodAttributeUuid,
55
+ tagNumberUuid,
56
+ obNumberUuid,
57
+ burialPermitNumberUuid,
58
+ policeNameUuid,
59
+ policeIDNumber,
60
+ dischargeAreaUuid,
61
+ } = useConfig<ConfigObject>();
62
+
63
+ const createMortuaryAdmissionEncounter = useCallback(
64
+ async (
65
+ patientUuid: string,
66
+ {
67
+ availableCompartment,
68
+ dateOfAdmission,
69
+ insuranceScheme,
70
+ dischargeArea,
71
+ obNumber,
72
+ paymentMethod,
73
+ period,
74
+ policeIDNo,
75
+ policeName,
76
+ tagNumber,
77
+ visitType,
78
+ }: z.infer<typeof patientInfoSchema>,
79
+ ) => {
80
+ const obs = [];
81
+ if (tagNumber) {
82
+ obs.push({ concept: tagNumberUuid, value: tagNumber });
83
+ }
84
+ if (obNumber) {
85
+ obs.push({ concept: obNumberUuid, value: obNumber });
86
+ }
87
+ if (policeName) {
88
+ obs.push({ concept: policeNameUuid, value: policeName });
89
+ }
90
+ if (policeIDNo) {
91
+ obs.push({ concept: policeIDNumber, value: policeIDNo });
92
+ }
93
+ if (dischargeArea) {
94
+ obs.push({ concept: dischargeAreaUuid, value: dischargeArea });
95
+ }
96
+ const encounterPayload = {
97
+ visit: {
98
+ patient: patientUuid,
99
+ startDatetime: dayjs(dateOfAdmission).toISOString(),
100
+ visitType: visitType,
101
+ location: location?.uuid,
102
+ attributes: [
103
+ {
104
+ attributeType: visitPaymentMethodAttributeUuid,
105
+ value: paymentMethod,
106
+ },
107
+ ],
108
+ },
109
+ patient: patientUuid,
110
+ encounterType: emrConfiguration?.admissionEncounterType?.uuid,
111
+ location: location?.uuid,
112
+ encounterProviders: [
113
+ {
114
+ provider: currentProvider?.uuid,
115
+ encounterRole: emrConfiguration?.clinicianEncounterRole?.uuid,
116
+ },
117
+ ],
118
+ obs: obs.length > 0 ? obs : undefined,
119
+ };
120
+ return openmrsFetch<Encounter>(`${restBaseUrl}/encounter`, {
121
+ method: 'POST',
122
+ headers: {
123
+ 'content-type': 'application/json',
124
+ },
125
+ body: encounterPayload,
126
+ });
127
+ },
128
+ [
129
+ currentProvider?.uuid,
130
+ dischargeAreaUuid,
131
+ emrConfiguration?.admissionEncounterType?.uuid,
132
+ emrConfiguration?.clinicianEncounterRole?.uuid,
133
+ location?.uuid,
134
+ obNumberUuid,
135
+ policeIDNumber,
136
+ policeNameUuid,
137
+ tagNumberUuid,
138
+ visitPaymentMethodAttributeUuid,
139
+ ],
140
+ );
141
+
142
+ const assignDeceasedToCompartment = useCallback(
143
+ async (patientUuid: string, bedId: number, encounterUuid: string) =>
144
+ openmrsFetch(`${restBaseUrl}/beds/${bedId}`, {
145
+ method: 'POST',
146
+ headers: {
147
+ 'content-type': 'application/json',
148
+ },
149
+ body: {
150
+ patientUuid,
151
+ encounterUuid,
152
+ },
153
+ }),
154
+ [],
155
+ );
156
+
157
+ const admitBody = useCallback(
158
+ async (patientUuid: string, data: z.infer<typeof patientInfoSchema>) => {
159
+ const admissionEncounter = await createMortuaryAdmissionEncounter(patientUuid, data);
160
+ const compartment = await assignDeceasedToCompartment(
161
+ patientUuid,
162
+ data.availableCompartment,
163
+ admissionEncounter.data.uuid,
164
+ );
165
+ return { admissionEncounter, compartment };
166
+ },
167
+ [assignDeceasedToCompartment, createMortuaryAdmissionEncounter],
168
+ );
169
+
170
+ const createDischargeMortuaryEncounter = useCallback(
171
+ async (visit: Visit, data: z.infer<typeof dischargeSchema>) => {
172
+ const obs = [];
173
+ if (data.burialPermitNumber) {
174
+ obs.push({ concept: burialPermitNumberUuid, value: data.burialPermitNumber });
175
+ }
176
+
177
+ const encounterPayload = {
178
+ encounterDatetime: data?.dateOfDischarge,
179
+ patient: visit?.patient?.uuid,
180
+ encounterType: emrConfiguration?.exitFromInpatientEncounterType,
181
+ location: visit?.location?.uuid,
182
+ encounterProviders: [
183
+ {
184
+ provider: currentProvider?.uuid,
185
+ encounterRole: emrConfiguration?.clinicianEncounterRole?.uuid,
186
+ },
187
+ ],
188
+ visit: visit?.uuid,
189
+ obs: obs.length > 0 ? obs : undefined,
190
+ };
191
+ return openmrsFetch<Encounter>(`${restBaseUrl}/encounter`, {
192
+ method: 'POST',
193
+ headers: {
194
+ 'content-type': 'application/json',
195
+ },
196
+ body: encounterPayload,
197
+ });
198
+ },
199
+ [
200
+ burialPermitNumberUuid,
201
+ currentProvider?.uuid,
202
+ emrConfiguration?.clinicianEncounterRole?.uuid,
203
+ emrConfiguration?.exitFromInpatientEncounterType,
204
+ ],
205
+ );
206
+ const removeDeceasedFromCompartment = useCallback(
207
+ async (patientUuid: string, bedId: number) =>
208
+ openmrsFetch(`${restBaseUrl}/beds/${bedId}?patientUuid=${patientUuid}`, {
209
+ method: 'DELETE',
210
+ }),
211
+ [],
212
+ );
213
+
214
+ const endCurrentVisit = useCallback(
215
+ async (currentVisit: Visit, queueEntry: MappedVisitQueueEntry, data: z.infer<typeof dischargeSchema>) => {
216
+ const abortController = new AbortController();
217
+ const response = await updateVisit(
218
+ currentVisit.uuid,
219
+ {
220
+ stopDatetime: new Date(),
221
+ },
222
+ abortController,
223
+ );
224
+
225
+ if (queueEntry) {
226
+ removeQueuedPatient(
227
+ queueEntry.queue.uuid,
228
+ queueEntry.queueEntryUuid,
229
+ abortController,
230
+ response?.data?.stopDatetime,
231
+ );
232
+ }
233
+ },
234
+ [],
235
+ );
236
+
237
+ const dischargeBody = useCallback(
238
+ async (visit: Visit, queueEntry: MappedVisitQueueEntry, bedId: number, data: z.infer<typeof dischargeSchema>) => {
239
+ const dischargeEncounter = await createDischargeMortuaryEncounter(visit, data);
240
+ const compartment = await removeDeceasedFromCompartment(visit?.patient?.uuid, bedId);
241
+ await endCurrentVisit(visit, queueEntry, data);
242
+ return { dischargeEncounter, compartment };
243
+ },
244
+ [createDischargeMortuaryEncounter, endCurrentVisit, removeDeceasedFromCompartment],
245
+ );
246
+ const createEncounterForCompartmentSwap = useCallback(
247
+ async (patientUuid: string, visitUuid: string) =>
248
+ openmrsFetch<Encounter>(`${restBaseUrl}/encounter`, {
249
+ method: 'POST',
250
+ headers: {
251
+ 'content-type': 'application/json',
252
+ },
253
+ body: {
254
+ encounterDatetime: new Date(),
255
+ patient: patientUuid,
256
+ encounterType: emrConfiguration?.bedAssignmentEncounterType,
257
+ location: location?.uuid,
258
+ encounterProviders: [
259
+ {
260
+ provider: currentProvider?.uuid,
261
+ encounterRole: emrConfiguration?.clinicianEncounterRole?.uuid,
262
+ },
263
+ ],
264
+ visit: visitUuid,
265
+ obs: [],
266
+ },
267
+ }),
268
+ [
269
+ currentProvider?.uuid,
270
+ emrConfiguration?.bedAssignmentEncounterType,
271
+ emrConfiguration?.clinicianEncounterRole?.uuid,
272
+ location?.uuid,
273
+ ],
274
+ );
275
+
276
+ return {
277
+ admitBody,
278
+ createEncounterForCompartmentSwap,
279
+ assignDeceasedToCompartment,
280
+ removeDeceasedFromCompartment,
281
+ dischargeBody,
282
+ isLoadingEmrConfiguration,
283
+ errorFetchingEmrConfiguration,
284
+ };
285
+ };
@@ -0,0 +1,12 @@
1
+ import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
+ import { PaginatedResponse } from '../types';
3
+ export async function fetchDeceasedPatient(query: string, abortController: AbortController) {
4
+ const customRepresentation =
5
+ 'custom:(uuid,display,identifiers:(identifier,uuid,preferred,location:(uuid,name)),person:(uuid,display,gender,birthdate,dead,age,deathDate,causeOfDeath:(uuid,display),preferredAddress:(uuid,stateProvince,countyDistrict,address4)))';
6
+ const url = `${restBaseUrl}/morgue/patient?v=${customRepresentation}&dead=true&name=${query}`;
7
+
8
+ const resp = await openmrsFetch<{ results: Array<PaginatedResponse> }>(url, {
9
+ signal: abortController.signal,
10
+ });
11
+ return resp?.data?.results;
12
+ }
@@ -0,0 +1,55 @@
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;