@kenyaemr/esm-morgue-app 5.4.2-pre.2283 → 5.4.2-pre.2288

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 (193) hide show
  1. package/.turbo/turbo-build.log +19 -19
  2. package/dist/109.js +2 -0
  3. package/dist/109.js.map +1 -0
  4. package/dist/201.js +1 -0
  5. package/dist/201.js.map +1 -0
  6. package/dist/293.js +1 -0
  7. package/dist/293.js.map +1 -0
  8. package/dist/300.js +1 -1
  9. package/dist/347.js +1 -2
  10. package/dist/347.js.map +1 -1
  11. package/dist/373.js +2 -0
  12. package/dist/373.js.map +1 -0
  13. package/dist/38.js +1 -0
  14. package/dist/38.js.map +1 -0
  15. package/dist/389.js +1 -0
  16. package/dist/389.js.map +1 -0
  17. package/dist/398.js +1 -0
  18. package/dist/398.js.map +1 -0
  19. package/dist/4.js +2 -0
  20. package/dist/4.js.map +1 -0
  21. package/dist/410.js +1 -0
  22. package/dist/410.js.map +1 -0
  23. package/dist/420.js +2 -0
  24. package/dist/420.js.map +1 -0
  25. package/dist/467.js +1 -0
  26. package/dist/467.js.map +1 -0
  27. package/dist/632.js +1 -0
  28. package/dist/632.js.map +1 -0
  29. package/dist/798.js +1 -0
  30. package/dist/798.js.map +1 -0
  31. package/dist/811.js +1 -0
  32. package/dist/811.js.map +1 -0
  33. package/dist/824.js +1 -0
  34. package/dist/824.js.map +1 -0
  35. package/dist/827.js +1 -0
  36. package/dist/827.js.map +1 -0
  37. package/dist/842.js +2 -0
  38. package/dist/842.js.LICENSE.txt +5 -0
  39. package/dist/842.js.map +1 -0
  40. package/dist/918.js +1 -1
  41. package/dist/918.js.map +1 -1
  42. package/dist/kenyaemr-esm-morgue-app.js +1 -1
  43. package/dist/kenyaemr-esm-morgue-app.js.buildmanifest.json +218 -291
  44. package/dist/kenyaemr-esm-morgue-app.js.map +1 -1
  45. package/dist/main.js +2 -1
  46. package/dist/main.js.LICENSE.txt +15 -0
  47. package/dist/main.js.map +1 -1
  48. package/dist/routes.json +1 -1
  49. package/package.json +1 -1
  50. package/src/bed/bed.component.tsx +164 -0
  51. package/src/bed/bed.scss +192 -0
  52. package/src/bed/divider/divider.component.tsx +18 -0
  53. package/src/bed/empty-bed.component.tsx +47 -0
  54. package/src/bed-layout/admitted/admitted-bed-layout.component.tsx +189 -0
  55. package/src/bed-layout/awaiting/awaiting-bed-layout.component.tsx +86 -0
  56. package/src/bed-layout/bed-layout.resource.ts +72 -0
  57. package/src/bed-layout/bed-layout.scss +55 -0
  58. package/src/bed-layout/discharged/discharged-bed-layout.component.tsx +109 -0
  59. package/src/bed-layout/discharged/discharged-bed-layout.resource.ts +99 -0
  60. package/src/bed-linelist-view/admitted/admitted-bed-linelist-view.component.tsx +420 -0
  61. package/src/bed-linelist-view/awaiting/awaiting-bed-linelist-view.component.tsx +224 -0
  62. package/src/bed-linelist-view/bed-linelist-view.scss +5 -0
  63. package/src/bed-linelist-view/discharged/discharged-bed-line-view.component.tsx +256 -0
  64. package/src/config-schema.ts +41 -9
  65. package/src/constants.ts +57 -0
  66. package/src/deceased-patient-header/deceased-patient-header.component.tsx +31 -0
  67. package/src/deceased-patient-header/deceased-patient-header.scss +50 -0
  68. package/src/{component → deceased-patient-header}/deceasedInfo/deceased-info.component.tsx +1 -1
  69. package/src/deceased-patient-header/deceasedInfo/deceased-info.resource.ts +11 -0
  70. package/src/extension/actionButton.component.tsx +5 -59
  71. package/src/extension/deceasedInfoBanner.component.tsx +5 -9
  72. package/src/{hook/useAdmitPatient.ts → forms/admit-deceased-person-workspace/admit-deceased-person.resource.ts} +177 -46
  73. package/src/forms/admit-deceased-person-workspace/admit-deceased-person.scss +143 -0
  74. package/src/forms/admit-deceased-person-workspace/admit-deceased-person.workspace.tsx +648 -0
  75. package/src/{hook/usePersonAttributes.ts → forms/discharge-deceased-person-workspace/discharge-body.resource.ts} +1 -1
  76. package/src/forms/discharge-deceased-person-workspace/discharge-body.scss +56 -0
  77. package/src/forms/discharge-deceased-person-workspace/discharge-body.workspace.tsx +362 -0
  78. package/src/forms/dispose-deceased-person-workspace/dispose-deceased-person.resource.ts +18 -0
  79. package/src/{workspaces/patientAdditionalInfoForm.scss → forms/dispose-deceased-person-workspace/dispose-deceased-person.scss} +46 -66
  80. package/src/forms/dispose-deceased-person-workspace/dispose-deceased-person.workspace.tsx +401 -0
  81. package/src/forms/form-entry-workspace/form-entry-workspace.workspace.tsx +62 -0
  82. package/src/forms/swap-compartment-workspace/swap-unit.scss +144 -0
  83. package/src/forms/swap-compartment-workspace/swap-unit.workspace.tsx +280 -0
  84. package/src/header/header.component.tsx +41 -0
  85. package/src/header/header.scss +58 -0
  86. package/src/home/home.component.tsx +87 -0
  87. package/src/home/home.resource.ts +261 -0
  88. package/src/home/home.scss +5 -0
  89. package/src/index.ts +18 -12
  90. package/src/metrics/metrics-card.component.tsx +31 -0
  91. package/src/metrics/metrics-card.scss +51 -0
  92. package/src/root.component.tsx +7 -3
  93. package/src/routes.json +25 -1
  94. package/src/schemas/index.ts +66 -0
  95. package/src/summary/summary.component.tsx +42 -0
  96. package/src/summary/summary.scss +10 -0
  97. package/src/switcher/content-switcher.component.tsx +220 -0
  98. package/src/switcher/content-switcher.scss +30 -0
  99. package/src/types/index.ts +336 -359
  100. package/src/utils/utils.ts +20 -2
  101. package/src/view-details/main/main.component.tsx +34 -0
  102. package/src/view-details/main/main.scss +45 -0
  103. package/src/view-details/panels/attachement.component.tsx +21 -0
  104. package/src/view-details/panels/autopsy.component.tsx +215 -0
  105. package/src/view-details/panels/billing-history.component.tsx +13 -0
  106. package/src/view-details/panels/observations/observation.component.tsx +57 -0
  107. package/src/view-details/panels/observations/observation.scss +24 -0
  108. package/src/view-details/panels/panels.scss +46 -0
  109. package/src/view-details/view-details.component.tsx +65 -0
  110. package/src/view-details/view-details.resource.ts +65 -0
  111. package/src/view-details/views-details.scss +82 -0
  112. package/translations/en.json +74 -21
  113. package/tsconfig.json +1 -1
  114. package/dist/113.js +0 -1
  115. package/dist/113.js.map +0 -1
  116. package/dist/160.js +0 -1
  117. package/dist/160.js.map +0 -1
  118. package/dist/299.js +0 -1
  119. package/dist/299.js.map +0 -1
  120. package/dist/433.js +0 -2
  121. package/dist/433.js.map +0 -1
  122. package/dist/441.js +0 -1
  123. package/dist/441.js.map +0 -1
  124. package/dist/496.js +0 -1
  125. package/dist/496.js.map +0 -1
  126. package/dist/511.js +0 -1
  127. package/dist/511.js.map +0 -1
  128. package/dist/603.js +0 -1
  129. package/dist/603.js.map +0 -1
  130. package/dist/610.js +0 -1
  131. package/dist/610.js.map +0 -1
  132. package/dist/612.js +0 -1
  133. package/dist/612.js.map +0 -1
  134. package/dist/656.js +0 -2
  135. package/dist/656.js.map +0 -1
  136. package/dist/752.js +0 -1
  137. package/dist/752.js.map +0 -1
  138. package/dist/754.js +0 -1
  139. package/dist/754.js.map +0 -1
  140. package/dist/781.js +0 -1
  141. package/dist/781.js.map +0 -1
  142. package/dist/801.js +0 -2
  143. package/dist/801.js.map +0 -1
  144. package/dist/817.js +0 -1
  145. package/dist/817.js.map +0 -1
  146. package/dist/877.js +0 -1
  147. package/dist/877.js.map +0 -1
  148. package/dist/924.js +0 -1
  149. package/dist/924.js.map +0 -1
  150. package/src/autosuggest/autosuggest.component.tsx +0 -162
  151. package/src/autosuggest/autosuggest.scss +0 -61
  152. package/src/autosuggest/patient-search-info.component.tsx +0 -75
  153. package/src/autosuggest/patient-search-info.scss +0 -62
  154. package/src/autosuggest/search-empty-state.component.tsx +0 -21
  155. package/src/autosuggest/search-empty-state.scss +0 -18
  156. package/src/card/avail-compartment.compartment.tsx +0 -94
  157. package/src/card/compartment-view.compartment.tsx +0 -62
  158. package/src/card/compartment.scss +0 -128
  159. package/src/card/compartmentSharing.component.tsx +0 -21
  160. package/src/card/compartmentSharing.scss +0 -24
  161. package/src/card/empty-compartment.component.tsx +0 -28
  162. package/src/card/empty-compartment.scss +0 -61
  163. package/src/component/main.component.tsx +0 -17
  164. package/src/component/next-of-kin-details/nextOfKinDetails.component.tsx +0 -50
  165. package/src/component/next-of-kin-details/nextOfKinDetails.scss +0 -37
  166. package/src/header/admitted-queue-header.component.tsx +0 -30
  167. package/src/header/admitted-queue-header.scss +0 -32
  168. package/src/header/morgue-header.component.tsx +0 -38
  169. package/src/header/morgue-header.scss +0 -95
  170. package/src/header/morgue-illustration.component.tsx +0 -13
  171. package/src/hook/useDeceasedPatients.ts +0 -12
  172. package/src/hook/useDischargedPatient.ts +0 -55
  173. package/src/hook/useMorgue.resource.ts +0 -163
  174. package/src/hook/useMortuaryAdmissionLocation.ts +0 -64
  175. package/src/tables/admitted-queue.component.tsx +0 -54
  176. package/src/tables/admitted-queue.scss +0 -62
  177. package/src/tables/discharge-queue.component.tsx +0 -87
  178. package/src/tables/generic-table.component.tsx +0 -140
  179. package/src/tables/generic-table.scss +0 -37
  180. package/src/tabs/tabs.component.tsx +0 -82
  181. package/src/tabs/tabs.scss +0 -15
  182. package/src/workspaces/admit-body.scss +0 -46
  183. package/src/workspaces/admit-body.workspace.tsx +0 -79
  184. package/src/workspaces/discharge-body.scss +0 -67
  185. package/src/workspaces/discharge-body.workspace.tsx +0 -329
  186. package/src/workspaces/patientAdditionalInfoForm.workspace.tsx +0 -562
  187. package/src/workspaces/swap-unit.scss +0 -46
  188. package/src/workspaces/swap-unit.workspace.tsx +0 -168
  189. /package/dist/{347.js.LICENSE.txt → 109.js.LICENSE.txt} +0 -0
  190. /package/dist/{656.js.LICENSE.txt → 373.js.LICENSE.txt} +0 -0
  191. /package/dist/{801.js.LICENSE.txt → 4.js.LICENSE.txt} +0 -0
  192. /package/dist/{433.js.LICENSE.txt → 420.js.LICENSE.txt} +0 -0
  193. /package/src/{component → deceased-patient-header}/deceasedInfo/deceased-info.scss +0 -0
@@ -0,0 +1,401 @@
1
+ import {
2
+ Button,
3
+ ButtonSet,
4
+ Column,
5
+ DatePicker,
6
+ DatePickerInput,
7
+ Form,
8
+ InlineLoading,
9
+ SelectItem,
10
+ Stack,
11
+ TextInput,
12
+ TimePicker,
13
+ TimePickerSelect,
14
+ } from '@carbon/react';
15
+ import { zodResolver } from '@hookform/resolvers/zod';
16
+ import {
17
+ ExtensionSlot,
18
+ fhirBaseUrl,
19
+ ResponsiveWrapper,
20
+ restBaseUrl,
21
+ setCurrentVisit,
22
+ showSnackbar,
23
+ useConfig,
24
+ useLayoutType,
25
+ useVisit,
26
+ } from '@openmrs/esm-framework';
27
+ import React, { useCallback, useEffect } from 'react';
28
+ import { Controller, useForm } from 'react-hook-form';
29
+ import { useTranslation } from 'react-i18next';
30
+ import { mutate as mutateSWR } from 'swr';
31
+ import { z } from 'zod';
32
+ import styles from './dispose-deceased-person.scss';
33
+ import DeceasedInfo from '../../deceased-patient-header/deceasedInfo/deceased-info.component';
34
+ import { PatientInfo } from '../../types';
35
+ import { usePersonAttributes } from '../discharge-deceased-person-workspace/discharge-body.resource';
36
+ import { ConfigObject } from '../../config-schema';
37
+ import { getCurrentTime } from '../../utils/utils';
38
+ import { disposeSchema } from '../../schemas';
39
+ import { useAwaitingQueuePatients, useVisitQueueEntry } from '../../home/home.resource';
40
+ import classNames from 'classnames';
41
+ import { useMortuaryOperation } from '../admit-deceased-person-workspace/admit-deceased-person.resource';
42
+
43
+ interface DisposeFormProps {
44
+ closeWorkspace: () => void;
45
+ patientUuid: string;
46
+ personUuid: string;
47
+ bedId: number;
48
+ mutate: () => void;
49
+ }
50
+
51
+ type DisposeFormValues = z.infer<typeof disposeSchema>;
52
+
53
+ const DisposeForm: React.FC<DisposeFormProps> = ({ closeWorkspace, patientUuid, bedId, personUuid, mutate }) => {
54
+ const { t } = useTranslation();
55
+ const isTablet = useLayoutType() === 'tablet';
56
+ const { activeVisit, currentVisitIsRetrospective } = useVisit(patientUuid);
57
+ const { queueEntry } = useVisitQueueEntry(patientUuid, activeVisit?.uuid);
58
+ const { disposeBody, isLoadingEmrConfiguration } = useMortuaryOperation();
59
+ const { createOrUpdatePersonAttribute, personAttributes } = usePersonAttributes(personUuid);
60
+ const { mutateAll, mutateAwaitingQueuePatients } = useAwaitingQueuePatients();
61
+
62
+ const { time: defaultTime, period: defaultPeriod } = getCurrentTime();
63
+
64
+ const { nextOfKinNameUuid, nextOfKinRelationshipUuid, nextOfKinPhoneUuid, nextOfKinAddressUuid } =
65
+ useConfig<ConfigObject>();
66
+
67
+ const getAttributeValue = useCallback(
68
+ (attributeTypeUuid: string) => {
69
+ if (!personAttributes) {
70
+ return '';
71
+ }
72
+ const attributes = Array.isArray(personAttributes) ? personAttributes : [];
73
+ const attribute = attributes.find((attr) => attr.attributeType.uuid === attributeTypeUuid);
74
+ return attribute ? attribute.value : '';
75
+ },
76
+ [personAttributes],
77
+ );
78
+
79
+ const {
80
+ control,
81
+ setValue,
82
+ handleSubmit,
83
+ formState: { errors, isDirty, isSubmitting },
84
+ } = useForm<DisposeFormValues>({
85
+ resolver: zodResolver(disposeSchema),
86
+ defaultValues: {
87
+ dateOfDischarge: new Date(),
88
+ timeOfDischarge: defaultTime,
89
+ period: defaultPeriod,
90
+ serialNumber: '',
91
+ courtOrderCaseNumber: '',
92
+ nextOfKinNames: '',
93
+ relationshipType: '',
94
+ nextOfKinContact: '',
95
+ nextOfKinAddress: '',
96
+ },
97
+ });
98
+
99
+ useEffect(() => {
100
+ if (Array.isArray(personAttributes) && personAttributes.length > 0) {
101
+ setValue('nextOfKinNames', getAttributeValue(nextOfKinNameUuid));
102
+ setValue('relationshipType', getAttributeValue(nextOfKinRelationshipUuid));
103
+ setValue('nextOfKinContact', getAttributeValue(nextOfKinPhoneUuid));
104
+ setValue('nextOfKinAddress', getAttributeValue(nextOfKinAddressUuid));
105
+ }
106
+ }, [
107
+ personAttributes,
108
+ getAttributeValue,
109
+ nextOfKinNameUuid,
110
+ nextOfKinRelationshipUuid,
111
+ nextOfKinPhoneUuid,
112
+ nextOfKinAddressUuid,
113
+ setValue,
114
+ ]);
115
+
116
+ const onSubmit = async (data: DisposeFormValues) => {
117
+ if (currentVisitIsRetrospective) {
118
+ setCurrentVisit(null, null);
119
+ closeWorkspace();
120
+ return;
121
+ }
122
+
123
+ try {
124
+ const nextOfKinAttributes = [
125
+ { attributeType: nextOfKinNameUuid, value: data.nextOfKinNames },
126
+ { attributeType: nextOfKinRelationshipUuid, value: data.relationshipType },
127
+ { attributeType: nextOfKinPhoneUuid, value: data.nextOfKinContact },
128
+ { attributeType: nextOfKinAddressUuid, value: data.nextOfKinAddress },
129
+ ];
130
+
131
+ const patientInfo: PatientInfo = {
132
+ uuid: activeVisit.patient.uuid,
133
+ attributes: (activeVisit?.patient?.person?.attributes || []).map((attr) => ({
134
+ uuid: attr.uuid,
135
+ display: attr.display || '',
136
+ })),
137
+ };
138
+
139
+ for (const attribute of nextOfKinAttributes) {
140
+ try {
141
+ await createOrUpdatePersonAttribute(patientUuid, attribute, patientInfo);
142
+ } catch (attributeError) {
143
+ showSnackbar({
144
+ title: t('errorDisposingPatient', 'Error disposing patient'),
145
+ subtitle: attributeError?.message || t('unknownError', 'Unknown error occurred'),
146
+ kind: 'error',
147
+ isLowContrast: true,
148
+ });
149
+ }
150
+ }
151
+
152
+ await disposeBody(activeVisit, queueEntry, bedId, data);
153
+
154
+ showSnackbar({
155
+ title: t('disposedDeceasedPatient', 'Deceased patient disposed'),
156
+ subtitle: t('deceasedPatientDisposedSuccessfully', 'Deceased patient has been disposed successfully'),
157
+ kind: 'success',
158
+ isLowContrast: true,
159
+ });
160
+
161
+ mutateSWR((key) => typeof key === 'string' && key.startsWith(`${restBaseUrl}/visit`));
162
+ mutateSWR((key) => typeof key === 'string' && key.startsWith(`${restBaseUrl}/patient`));
163
+ mutateSWR((key) => typeof key === 'string' && key.startsWith(`${fhirBaseUrl}/Encounter`));
164
+ mutateAwaitingQueuePatients();
165
+ mutateAll();
166
+ mutate();
167
+ closeWorkspace();
168
+ } catch (error) {
169
+ showSnackbar({
170
+ title: t('errorDisposingPatient', 'Error disposing patient'),
171
+ subtitle: error?.message || t('unknownError', 'Unknown error occurred'),
172
+ kind: 'error',
173
+ isLowContrast: true,
174
+ });
175
+ }
176
+ };
177
+
178
+ if (isLoadingEmrConfiguration || !personAttributes || !activeVisit) {
179
+ return <InlineLoading status="active" iconDescription="Loading" description="Loading ..." />;
180
+ }
181
+
182
+ return (
183
+ <Form onSubmit={handleSubmit(onSubmit)} className={styles.form}>
184
+ <div className={styles.formContainer}>
185
+ <Stack gap={3}>
186
+ <DeceasedInfo patientUuid={patientUuid} />
187
+ <ResponsiveWrapper>
188
+ <div className={styles.dateTimePickerContainer}>
189
+ <Column>
190
+ <Controller
191
+ name="dateOfDischarge"
192
+ control={control}
193
+ render={({ field }) => (
194
+ <DatePicker
195
+ datePickerType="single"
196
+ className={styles.formAdmissionDatepicker}
197
+ onChange={(event) => {
198
+ if (event.length) {
199
+ field.onChange(event[0]);
200
+ }
201
+ }}
202
+ value={field.value ? new Date(field.value) : null}>
203
+ <DatePickerInput
204
+ {...field}
205
+ id="date-of-discharge"
206
+ placeholder="yyyy-mm-dd"
207
+ labelText={t('dateOfDischarge', 'Date of discharge*')}
208
+ invalid={!!errors.dateOfDischarge}
209
+ invalidText={errors.dateOfDischarge?.message}
210
+ />
211
+ </DatePicker>
212
+ )}
213
+ />
214
+ </Column>
215
+
216
+ <Column>
217
+ <div className={styles.dateTimeSection}>
218
+ <ResponsiveWrapper>
219
+ <Controller
220
+ name="timeOfDischarge"
221
+ control={control}
222
+ render={({ field }) => (
223
+ <TimePicker
224
+ {...field}
225
+ id="time-of-discharge-picker"
226
+ labelText={t('timeOfDischarge', 'Time of discharge*')}
227
+ className={styles.formAdmissionTimepicker}
228
+ invalid={!!errors.timeOfDischarge}
229
+ invalidText={errors.timeOfDischarge?.message}
230
+ />
231
+ )}
232
+ />
233
+ <Controller
234
+ name="period"
235
+ control={control}
236
+ render={({ field }) => (
237
+ <TimePickerSelect
238
+ {...field}
239
+ className={styles.formDeathTimepickerSelector}
240
+ id="time-picker-select">
241
+ <SelectItem value="AM" text="AM" />
242
+ <SelectItem value="PM" text="PM" />
243
+ </TimePickerSelect>
244
+ )}
245
+ />
246
+ </ResponsiveWrapper>
247
+ </div>
248
+ </Column>
249
+ </div>
250
+
251
+ <Column className={styles.fieldColumn}>
252
+ <Controller
253
+ name="serialNumber"
254
+ control={control}
255
+ render={({ field }) => (
256
+ <TextInput
257
+ {...field}
258
+ id="serialNumber"
259
+ type="text"
260
+ className={styles.sectionField}
261
+ placeholder={t('serialNumber', 'Serial number')}
262
+ labelText={t('serialNumber', 'Serial number*')}
263
+ invalid={!!errors.serialNumber}
264
+ invalidText={errors.serialNumber?.message}
265
+ />
266
+ )}
267
+ />
268
+ </Column>
269
+
270
+ <Column className={styles.fieldColumn}>
271
+ <Controller
272
+ name="courtOrderCaseNumber"
273
+ control={control}
274
+ render={({ field }) => (
275
+ <TextInput
276
+ {...field}
277
+ id="courtOrderCaseNumber"
278
+ type="text"
279
+ className={styles.sectionField}
280
+ placeholder={t('courtOrderCaseNumber', 'Court order case number')}
281
+ labelText={t('courtOrderCaseNumber', 'Court order case number')}
282
+ invalid={!!errors.courtOrderCaseNumber}
283
+ invalidText={errors.courtOrderCaseNumber?.message}
284
+ />
285
+ )}
286
+ />
287
+ </Column>
288
+
289
+ <Column className={styles.fieldColumn}>
290
+ <Controller
291
+ name="nextOfKinNames"
292
+ control={control}
293
+ render={({ field }) => (
294
+ <TextInput
295
+ {...field}
296
+ id="nextOfKinNames"
297
+ type="text"
298
+ className={styles.sectionField}
299
+ placeholder={t('nextOfKinNames', 'Next of kin names')}
300
+ labelText={t('nextOfKinNames', 'Next of kin names')}
301
+ invalid={!!errors.nextOfKinNames}
302
+ invalidText={errors.nextOfKinNames?.message}
303
+ />
304
+ )}
305
+ />
306
+ </Column>
307
+
308
+ <Column className={styles.fieldColumn}>
309
+ <Controller
310
+ name="relationshipType"
311
+ control={control}
312
+ render={({ field }) => (
313
+ <TextInput
314
+ {...field}
315
+ id="relationshipType"
316
+ type="text"
317
+ className={styles.sectionField}
318
+ placeholder={t('relationshipType', 'Relationship')}
319
+ labelText={t('relationshipType', 'Relationship')}
320
+ invalid={!!errors.relationshipType}
321
+ invalidText={errors.relationshipType?.message}
322
+ />
323
+ )}
324
+ />
325
+ </Column>
326
+
327
+ <Column className={styles.fieldColumn}>
328
+ <Controller
329
+ name="nextOfKinContact"
330
+ control={control}
331
+ render={({ field }) => (
332
+ <TextInput
333
+ {...field}
334
+ id="nextOfKinContact"
335
+ type="text"
336
+ className={styles.sectionField}
337
+ placeholder={t('nextOfKinContact', 'Next of kin contact')}
338
+ labelText={t('nextOfKinContact', 'Next of kin contact')}
339
+ invalid={!!errors.nextOfKinContact}
340
+ invalidText={errors.nextOfKinContact?.message}
341
+ />
342
+ )}
343
+ />
344
+ </Column>
345
+
346
+ <Column className={styles.fieldColumn}>
347
+ <Controller
348
+ name="nextOfKinAddress"
349
+ control={control}
350
+ render={({ field }) => (
351
+ <TextInput
352
+ {...field}
353
+ id="nextOfKinAddress"
354
+ type="text"
355
+ className={styles.sectionField}
356
+ placeholder={t('nextOfKinAddress', 'Next of kin address')}
357
+ labelText={t('nextOfKinAddress', 'Next of kin address')}
358
+ invalid={!!errors.nextOfKinAddress}
359
+ invalidText={errors.nextOfKinAddress?.message}
360
+ />
361
+ )}
362
+ />
363
+ </Column>
364
+ </ResponsiveWrapper>
365
+ <ResponsiveWrapper>
366
+ <Column>
367
+ <ExtensionSlot
368
+ name="patient-chart-attachments-dashboard-slot"
369
+ className={styles.sectionField}
370
+ state={{
371
+ patientUuid,
372
+ }}
373
+ />
374
+ </Column>
375
+ </ResponsiveWrapper>
376
+ </Stack>
377
+ </div>
378
+ <ButtonSet
379
+ className={classNames({
380
+ [styles.tablet]: isTablet,
381
+ [styles.desktop]: !isTablet,
382
+ })}>
383
+ <Button className={styles.buttonContainer} kind="secondary" onClick={() => closeWorkspace()}>
384
+ {t('cancel', 'Cancel')}
385
+ </Button>
386
+ <Button className={styles.buttonContainer} disabled={isSubmitting || !isDirty} kind="primary" type="submit">
387
+ {isSubmitting ? (
388
+ <span className={styles.inlineLoading}>
389
+ {t('submitting', 'Submitting...')}
390
+ <InlineLoading status="active" iconDescription="Loading" />
391
+ </span>
392
+ ) : (
393
+ t('saveAndClose', 'Save & close')
394
+ )}
395
+ </Button>
396
+ </ButtonSet>
397
+ </Form>
398
+ );
399
+ };
400
+
401
+ export default DisposeForm;
@@ -0,0 +1,62 @@
1
+ import { InlineLoading } from '@carbon/react';
2
+ import { DefaultWorkspaceProps, ExtensionSlot, useConnectivity, usePatient } from '@openmrs/esm-framework';
3
+ import React, { useMemo } from 'react';
4
+
5
+ type FormEntryWorkspaceProps = DefaultWorkspaceProps & {
6
+ formUuid?: string;
7
+ patientUuid?: string;
8
+ encounterUuid?: string;
9
+ mutateForm: () => void;
10
+ };
11
+
12
+ const FormEntryWorkspace: React.FC<FormEntryWorkspaceProps> = (props) => {
13
+ const { formUuid, patientUuid, encounterUuid, mutateForm, closeWorkspace, closeWorkspaceWithSavedChanges } = props;
14
+ const { patient, isLoading } = usePatient(patientUuid);
15
+ const isOnline = useConnectivity();
16
+ const state = useMemo(
17
+ () => ({
18
+ ...props,
19
+ view: 'form',
20
+ formUuid: formUuid ?? null,
21
+ visitUuid: '',
22
+ visitTypeUuid: '',
23
+ visitStartDatetime: null,
24
+ visitStopDatetime: null,
25
+ isOffline: !isOnline,
26
+ patientUuid: patientUuid ?? null,
27
+ patient,
28
+ encounterUuid: encounterUuid ?? null,
29
+ closeWorkspace: () => {
30
+ typeof mutateForm === 'function' && mutateForm();
31
+ closeWorkspace();
32
+ },
33
+ closeWorkspaceWithSavedChanges: () => {
34
+ typeof mutateForm === 'function' && mutateForm();
35
+ closeWorkspaceWithSavedChanges();
36
+ },
37
+ }),
38
+ [
39
+ patient,
40
+ patientUuid,
41
+ encounterUuid,
42
+ formUuid,
43
+ isOnline,
44
+ props,
45
+ closeWorkspace,
46
+ closeWorkspaceWithSavedChanges,
47
+ mutateForm,
48
+ ],
49
+ );
50
+
51
+ if (isLoading) {
52
+ return (
53
+ <div>
54
+ <InlineLoading status="active" iconDescription="Loading" description="Loading form..." />
55
+ </div>
56
+ );
57
+ }
58
+
59
+ return <ExtensionSlot name="form-widget-slot" state={state} />;
60
+ };
61
+
62
+ export default FormEntryWorkspace;
@@ -0,0 +1,144 @@
1
+ @use '@carbon/colors';
2
+ @use '@carbon/layout';
3
+ @use '@carbon/type';
4
+
5
+ .form {
6
+ display: flex;
7
+ flex-direction: column;
8
+ justify-content: space-between;
9
+ height: 100%;
10
+ }
11
+
12
+ .formContainer {
13
+ margin: layout.$spacing-05;
14
+ display: flex;
15
+ flex-direction: column;
16
+ gap: layout.$spacing-05;
17
+ }
18
+
19
+ .tablet {
20
+ padding: layout.$spacing-06 layout.$spacing-05;
21
+ background-color: colors.$white;
22
+ }
23
+
24
+ .desktop {
25
+ padding: 0;
26
+ padding: layout.$spacing-01 layout.$spacing-05;
27
+ }
28
+ .buttonContainer {
29
+ max-width: 50%;
30
+ }
31
+ .inlineLoading {
32
+ display: flex;
33
+ align-items: center;
34
+ gap: layout.$spacing-03;
35
+ }
36
+ .formDeathTimepickerSelector {
37
+ min-width: layout.$spacing-05;
38
+ margin-top: layout.$spacing-06;
39
+ }
40
+ .formAdmissionTimepicker input {
41
+ min-width: 11rem;
42
+ }
43
+ .formAdmissionDatepicker input {
44
+ min-width: 24rem;
45
+ }
46
+ .dateTimeSection {
47
+ display: flex;
48
+ flex-direction: row;
49
+ gap: layout.$spacing-02;
50
+ align-items: center;
51
+ }
52
+
53
+ .radioButtonGroup {
54
+ display: flex;
55
+ flex-direction: column;
56
+ align-items: flex-start;
57
+ margin-top: layout.$spacing-03;
58
+ min-height: layout.$spacing-10;
59
+ width: 100%;
60
+ @include type.type-style('body-compact-01');
61
+ }
62
+
63
+ .radioButton {
64
+ padding: layout.$spacing-02 layout.$spacing-05;
65
+ margin: layout.$spacing-03 0;
66
+ }
67
+
68
+ .visitTypeOverviewWrapper {
69
+ margin: layout.$spacing-05 0;
70
+ border: 0.0625rem solid colors.$gray-30;
71
+ }
72
+
73
+ .visitTypeOverviewWrapper div:nth-child(3) > div:nth-child(2) {
74
+ position: relative;
75
+ }
76
+
77
+ .visitTypeOverviewWrapper div:nth-child(3) span * {
78
+ display: none;
79
+ }
80
+
81
+ .compartmentListContainer {
82
+ max-height: 15rem;
83
+ overflow-y: auto;
84
+ margin-top: layout.$spacing-03;
85
+ padding-right: layout.$spacing-03;
86
+ }
87
+
88
+ .radioButtonGroup {
89
+ display: flex;
90
+ flex-direction: column;
91
+ gap: layout.$spacing-03;
92
+ width: 100%;
93
+ padding-left: layout.$spacing-05;
94
+ }
95
+
96
+ .compartmentOption {
97
+ display: flex;
98
+ justify-content: space-between;
99
+ align-items: center;
100
+ width: 110%;
101
+ padding: layout.$spacing-03 0;
102
+ border-bottom: 1px solid colors.$gray-20;
103
+
104
+ &:last-child {
105
+ border-bottom: none;
106
+ }
107
+ }
108
+
109
+ .radioButtonWrapper {
110
+ display: flex;
111
+ align-items: center;
112
+ gap: layout.$spacing-03;
113
+ flex: 1;
114
+ }
115
+
116
+ .compartmentTags {
117
+ display: flex;
118
+ gap: layout.$spacing-03;
119
+ align-items: center;
120
+ margin-left: auto;
121
+ }
122
+ .radioButton {
123
+ margin: 0;
124
+ padding: 0;
125
+ }
126
+ .emptyStateTile {
127
+ display: flex;
128
+ flex-direction: column;
129
+ align-items: center;
130
+ justify-content: center;
131
+ padding: layout.$spacing-06;
132
+ text-align: center;
133
+ margin: layout.$spacing-05 0;
134
+ }
135
+
136
+ .emptyStateContent {
137
+ @include type.type-style('body-01');
138
+ color: colors.$gray-70;
139
+ margin-top: layout.$spacing-05;
140
+ max-width: 20rem;
141
+ }
142
+ .sectionField {
143
+ padding-top: layout.$spacing-03;
144
+ }