@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.
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 -14
  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
@@ -1,82 +0,0 @@
1
- import { Button, Layer, Tab, TabList, TabPanel, TabPanels, Tabs } from '@carbon/react';
2
- import { SearchAdvanced } from '@carbon/react/icons';
3
- import { launchWorkspace, UserHasAccess } from '@openmrs/esm-framework';
4
- import React from 'react';
5
- import { useTranslation } from 'react-i18next';
6
- import useEmrConfiguration from '../hook/useAdmitPatient';
7
- import { useDischargedPatient } from '../hook/useDischargedPatient';
8
- import { useAdmissionLocation } from '../hook/useMortuaryAdmissionLocation';
9
- import { AdmittedQueue } from '../tables/admitted-queue.component';
10
- import { DischargedBodies } from '../tables/discharge-queue.component';
11
- import styles from './tabs.scss';
12
-
13
- export const MorgueTabs: React.FC = () => {
14
- const { t } = useTranslation();
15
- const { admissionLocation } = useAdmissionLocation();
16
- const admittedCount = admissionLocation?.bedLayouts?.filter((bed) => bed.status === 'OCCUPIED').length || 0;
17
- const { emrConfiguration, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } = useEmrConfiguration();
18
-
19
- const dischargeEncounterTypeUuid = emrConfiguration?.exitFromInpatientEncounterType?.uuid;
20
- const { dischargedPatientUuids, isLoading: isLoadingDischargedPatient } =
21
- useDischargedPatient(dischargeEncounterTypeUuid);
22
- const dischargedCount = dischargedPatientUuids?.length || 0;
23
-
24
- const getTabLabel = (baseLabel: string, count: number | null) => (
25
- <span className={styles.tabLabel}>
26
- {baseLabel} {count ? `(${count})` : ''}
27
- </span>
28
- );
29
-
30
- const tabPanels = [
31
- {
32
- name: getTabLabel(t('admitted', 'Admitted'), admittedCount),
33
- component: <AdmittedQueue />,
34
- },
35
- {
36
- name: getTabLabel(t('discharged', 'Discharged'), dischargedCount),
37
- component: (
38
- <DischargedBodies
39
- isLoading={isLoadingDischargedPatient || isLoadingEmrConfiguration}
40
- error={errorFetchingEmrConfiguration}
41
- dischargedPatientUuids={dischargedPatientUuids}
42
- />
43
- ),
44
- },
45
- ];
46
- const handleAdmitBodyWorkspace = () => {
47
- launchWorkspace('admit-body-form');
48
- };
49
- return (
50
- <div className={styles.referralsList} data-testid="">
51
- <Tabs>
52
- <div className={styles.tabsContainer}>
53
- <TabList aria-label="Content Switcher as Tabs" contained>
54
- {tabPanels.map((tab, index) => (
55
- <Tab key={index}>{tab.name}</Tab>
56
- ))}
57
- </TabList>
58
- <div className={styles.actionBtn}>
59
- <UserHasAccess privilege="o3 : Admit Body to Mortuary">
60
- <Button
61
- kind="primary"
62
- renderIcon={(props) => <SearchAdvanced size={40} {...props} />}
63
- onClick={() => handleAdmitBodyWorkspace()}
64
- className={styles.actionBtn}
65
- disabled={isLoadingDischargedPatient}>
66
- {t('admitBodies', 'Admit bodies')}
67
- </Button>
68
- </UserHasAccess>
69
- </div>
70
- </div>
71
-
72
- <TabPanels>
73
- {tabPanels.map((tab, index) => (
74
- <TabPanel key={index}>
75
- <Layer>{tab.component}</Layer>
76
- </TabPanel>
77
- ))}
78
- </TabPanels>
79
- </Tabs>
80
- </div>
81
- );
82
- };
@@ -1,15 +0,0 @@
1
- @use '@carbon/layout';
2
- @use '@carbon/type';
3
- @use '@carbon/colors';
4
-
5
- .tabsContainer {
6
- display: flex;
7
- justify-content: space-between;
8
- align-items: center;
9
- padding-left: layout.$spacing-05;
10
- }
11
-
12
- .actionBtn {
13
- display: flex;
14
- margin-right: layout.$spacing-03;
15
- }
@@ -1,46 +0,0 @@
1
- @use '@carbon/layout';
2
- @use '@carbon/type';
3
- @use '@carbon/colors';
4
-
5
- .formButton {
6
- height: layout.$spacing-09;
7
- display: flex;
8
- align-content: flex-start;
9
- align-items: baseline;
10
- min-width: layout.$spacing-11;
11
- margin-bottom: layout.$spacing-05;
12
- }
13
-
14
- .buttonSet {
15
- position: absolute;
16
- bottom: layout.$spacing-05;
17
- left: 4%;
18
- width: 80%;
19
- display: flex;
20
- gap: layout.$spacing-02;
21
-
22
- & > button {
23
- max-width: 40%;
24
- width: 40%;
25
- }
26
- }
27
- .searchContainer {
28
- padding: layout.$spacing-04;
29
- }
30
-
31
- .admissionRequestActionBar {
32
- width: 100%;
33
- padding: layout.$spacing-05;
34
- margin-left: layout.$spacing-10;
35
- }
36
-
37
- .buttonRow {
38
- display: flex;
39
- width: 100%;
40
- gap: 8px;
41
- }
42
-
43
- .actionButton {
44
- flex-grow: 1;
45
- width: 100%;
46
- }
@@ -1,79 +0,0 @@
1
- import { Column, Form, Stack } from '@carbon/react';
2
- import { zodResolver } from '@hookform/resolvers/zod';
3
- import React from 'react';
4
- import { Controller, useForm } from 'react-hook-form';
5
- import { useTranslation } from 'react-i18next';
6
- import { z } from 'zod';
7
- import { Autosuggest } from '../autosuggest/autosuggest.component';
8
- import SearchEmptyState from '../autosuggest/search-empty-state.component';
9
- import styles from './admit-body.scss';
10
- import PatientSearchInfo from '../autosuggest/patient-search-info.component';
11
- import { fetchDeceasedPatient } from '../hook/useDeceasedPatients';
12
-
13
- const schema = z.object({
14
- deceasedPatient: z.string().nonempty('Patient selection is required').uuid('Invalid patient selection'),
15
- });
16
-
17
- type AdmitBodyFormInputs = z.infer<typeof schema>;
18
-
19
- const AdmitBodyForm: React.FC = () => {
20
- const { t } = useTranslation();
21
-
22
- const searchPatient = async (query: string) => {
23
- const abortController = new AbortController();
24
- return await fetchDeceasedPatient(query, abortController);
25
- };
26
-
27
- const form = useForm<AdmitBodyFormInputs>({
28
- resolver: zodResolver(schema),
29
- defaultValues: {
30
- deceasedPatient: '',
31
- },
32
- });
33
-
34
- const { handleSubmit, control, formState } = form;
35
-
36
- const onSuggestionSelected = (value: string) => {
37
- if (value) {
38
- // Handle suggestion selection logic here
39
- }
40
- };
41
-
42
- return (
43
- <Form className={styles.formContainer}>
44
- <Stack gap={4} className={styles.formGrid}>
45
- <Column className={styles.searchContainer}>
46
- <Controller
47
- control={control}
48
- name="deceasedPatient"
49
- render={({ field }) => (
50
- <Autosuggest
51
- labelText={t('searchDeceasedPatient', 'Search for a deceased patient')}
52
- placeholder={t('searchDeceasedPatientPlaceholder', 'Search for a deceased patient')}
53
- invalid={!!formState.errors[field.name]?.message}
54
- invalidText={formState.errors[field.name]?.message}
55
- getDisplayValue={() => ''}
56
- renderSuggestionItem={(item) => <PatientSearchInfo patient={item.patient} />}
57
- getFieldValue={(item) => item.patient.uuid}
58
- getSearchResults={searchPatient}
59
- renderEmptyState={(value) => (
60
- <SearchEmptyState
61
- searchValue={value}
62
- message={t('deceasedPatientNotFound', 'Deceased Patient Not Found')}
63
- />
64
- )}
65
- onClear={() => field.onChange('')}
66
- onSuggestionSelected={(_, value) => {
67
- onSuggestionSelected(value);
68
- field.onChange(value);
69
- }}
70
- />
71
- )}
72
- />
73
- </Column>
74
- </Stack>
75
- </Form>
76
- );
77
- };
78
-
79
- export default AdmitBodyForm;
@@ -1,67 +0,0 @@
1
- @use '@carbon/layout';
2
- @use '@carbon/type';
3
- @use '@carbon/colors';
4
-
5
- .formContainer {
6
- width: 100%;
7
- max-height: 100vh;
8
- display: flex;
9
- flex-direction: column;
10
- overflow-y: auto;
11
- }
12
-
13
- .formButton {
14
- height: layout.$spacing-09;
15
- display: flex;
16
- align-content: flex-start;
17
- align-items: baseline;
18
- min-width: layout.$spacing-11;
19
- margin-bottom: layout.$spacing-05;
20
- }
21
-
22
- .buttonSet {
23
- position: relative;
24
- padding-top: layout.$spacing-05;
25
- left: 4%;
26
- width: 80%;
27
- display: flex;
28
- gap: layout.$spacing-02;
29
-
30
- & > button {
31
- max-width: 40%;
32
- width: 40%;
33
- }
34
- }
35
- .formAdmissionDatepicker input {
36
- min-width: 25rem;
37
- }
38
- .formAdmissionTimepicker input {
39
- min-width: 12rem;
40
- }
41
- .dateTimeSection {
42
- display: flex;
43
- flex-direction: row;
44
- gap: layout.$spacing-02;
45
- align-items: center;
46
- margin-top: layout.$spacing-04;
47
- }
48
- .formDeathTimepickerSelector {
49
- margin-top: layout.$spacing-06;
50
- margin-right: layout.$spacing-03;
51
- }
52
- .dateTimePickerContainer {
53
- margin-left: layout.$spacing-04;
54
- }
55
-
56
- .sectionField {
57
- min-width: 25rem;
58
- }
59
- .columnField {
60
- padding: layout.$spacing-02;
61
- }
62
- .fieldColumn {
63
- padding: layout.$spacing-04;
64
- }
65
- .fieldSection {
66
- min-width: 22rem;
67
- }
@@ -1,329 +0,0 @@
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
- ResponsiveWrapper,
18
- restBaseUrl,
19
- setCurrentVisit,
20
- showSnackbar,
21
- useConfig,
22
- useLayoutType,
23
- useVisit,
24
- } from '@openmrs/esm-framework';
25
- import React, { useCallback, useEffect } from 'react';
26
- import { Controller, useForm } from 'react-hook-form';
27
- import { useTranslation } from 'react-i18next';
28
- import { mutate } from 'swr';
29
- import { z } from 'zod';
30
- import DeceasedInfo from '../component/deceasedInfo/deceased-info.component';
31
- import { ConfigObject } from '../config-schema';
32
- import { useMortuaryOperation } from '../hook/useAdmitPatient';
33
- import { useVisitQueueEntry } from '../hook/useMorgue.resource';
34
- import { usePersonAttributes } from '../hook/usePersonAttributes';
35
- import { PatientInfo } from '../types';
36
- import { dischargeSchema, getCurrentTime } from '../utils/utils';
37
- import styles from './discharge-body.scss';
38
-
39
- interface DischargeFormProps {
40
- closeWorkspace: () => void;
41
- patientUuid: string;
42
- personUuid: string;
43
- bedId: number;
44
- }
45
-
46
- type DischargeFormValues = z.infer<typeof dischargeSchema>;
47
-
48
- const DischargeForm: React.FC<DischargeFormProps> = ({ closeWorkspace, patientUuid, bedId, personUuid }) => {
49
- const { t } = useTranslation();
50
- const layout = useLayoutType();
51
- const { currentVisit, currentVisitIsRetrospective } = useVisit(patientUuid);
52
- const { queueEntry } = useVisitQueueEntry(patientUuid, currentVisit?.uuid);
53
- const { dischargeBody, isLoadingEmrConfiguration } = useMortuaryOperation();
54
- const { createOrUpdatePersonAttribute, personAttributes } = usePersonAttributes(personUuid);
55
-
56
- const { time: defaultTime, period: defaultPeriod } = getCurrentTime();
57
-
58
- const { nextOfKinAddressUuid, nextOfKinNameUuid, nextOfKinPhoneUuid, nextOfKinRelationshipUuid } =
59
- useConfig<ConfigObject>();
60
-
61
- const getAttributeValue = useCallback(
62
- (attributeTypeUuid: string) => {
63
- if (!personAttributes) {
64
- return '';
65
- }
66
- const attributes = Array.isArray(personAttributes) ? personAttributes : [];
67
- const attribute = attributes.find((attr) => attr.attributeType.uuid === attributeTypeUuid);
68
- return attribute ? attribute.value : '';
69
- },
70
- [personAttributes],
71
- );
72
-
73
- const {
74
- watch,
75
- control,
76
- setValue,
77
- handleSubmit,
78
- formState: { errors },
79
- } = useForm<DischargeFormValues>({
80
- resolver: zodResolver(dischargeSchema),
81
- defaultValues: {
82
- dateOfDischarge: new Date(),
83
- timeOfDischarge: defaultTime,
84
- period: defaultPeriod,
85
- burialPermitNumber: '',
86
- },
87
- });
88
- useEffect(() => {
89
- if (Array.isArray(personAttributes) && personAttributes.length > 0) {
90
- setValue('nextOfKinNames', getAttributeValue(nextOfKinNameUuid));
91
- setValue('relationshipType', getAttributeValue(nextOfKinRelationshipUuid));
92
- setValue('nextOfKinContact', getAttributeValue(nextOfKinPhoneUuid));
93
- setValue('nextOfKinAddress', getAttributeValue(nextOfKinAddressUuid));
94
- }
95
- }, [
96
- personAttributes,
97
- getAttributeValue,
98
- nextOfKinNameUuid,
99
- nextOfKinRelationshipUuid,
100
- nextOfKinPhoneUuid,
101
- nextOfKinAddressUuid,
102
- setValue,
103
- ]);
104
- const onSubmit = async (data: DischargeFormValues) => {
105
- if (currentVisitIsRetrospective) {
106
- setCurrentVisit(null, null);
107
- closeWorkspace();
108
- } else {
109
- try {
110
- const nextOfKinAttributes = [
111
- { attributeType: nextOfKinNameUuid, value: data.nextOfKinNames },
112
- { attributeType: nextOfKinRelationshipUuid, value: data.relationshipType },
113
- { attributeType: nextOfKinPhoneUuid, value: data.nextOfKinContact },
114
- { attributeType: nextOfKinAddressUuid, value: data.nextOfKinAddress },
115
- ];
116
- const patientInfo: PatientInfo = {
117
- uuid: currentVisit.patient.uuid,
118
- attributes: (currentVisit?.patient?.person?.attributes || []).map((attr) => ({
119
- uuid: attr.uuid,
120
- display: attr.display || '',
121
- })),
122
- };
123
-
124
- for (const attribute of nextOfKinAttributes) {
125
- await createOrUpdatePersonAttribute(patientUuid, attribute, patientInfo);
126
- }
127
-
128
- await dischargeBody(currentVisit, queueEntry, bedId, data);
129
-
130
- showSnackbar({
131
- title: t('dischargeDeceasedPatient', 'Deceased patient'),
132
- subtitle: t('deceasedPatientDischargedSuccessfully', 'Deceased patient has been discharged successfully'),
133
- kind: 'success',
134
- isLowContrast: true,
135
- });
136
-
137
- mutate(
138
- (key) =>
139
- typeof key === 'string' && key.startsWith(`${restBaseUrl}/patient/${patientUuid}/chart/deceased-panel`),
140
- undefined,
141
- );
142
- mutate((key) => typeof key === 'string' && key.startsWith(`${restBaseUrl}/visit`));
143
- closeWorkspace();
144
- } catch (error) {
145
- const errorMessage = JSON.stringify(error?.responseBody?.error?.message?.replace(/\[/g, '').replace(/\]/g, ''));
146
- showSnackbar({
147
- title: t('visitError', 'Visit Error'),
148
- subtitle: t(
149
- 'visitErrorMessage',
150
- `An error has occurred while ending visit, Contact system administrator quoting this error ${errorMessage}`,
151
- ),
152
- kind: 'error',
153
- isLowContrast: true,
154
- });
155
- }
156
- }
157
- };
158
-
159
- if (isLoadingEmrConfiguration || !personAttributes) {
160
- return <InlineLoading status="active" iconDescription="Loading" description="Loading ..." />;
161
- }
162
- return (
163
- <Form className={styles.formContainer} onSubmit={handleSubmit(onSubmit)}>
164
- <Stack gap={4} className={styles.formGrid}>
165
- <DeceasedInfo patientUuid={patientUuid} />
166
- <div className={styles.dateTimePickerContainer}>
167
- <Column>
168
- <Controller
169
- name="dateOfDischarge"
170
- control={control}
171
- render={({ field }) => (
172
- <DatePicker
173
- datePickerType="single"
174
- className={styles.formAdmissionDatepicker}
175
- onChange={(event) => {
176
- if (event.length) {
177
- field.onChange(event[0]);
178
- }
179
- }}
180
- value={field.value ? new Date(field.value) : null}>
181
- <DatePickerInput
182
- {...field}
183
- id="date-of-admission"
184
- placeholder="yyyy-mm-dd"
185
- labelText={t('dateOfAdmission', 'Date of discharge*')}
186
- invalid={!!errors.dateOfDischarge}
187
- invalidText={errors.dateOfDischarge?.message}
188
- />
189
- </DatePicker>
190
- )}
191
- />
192
- </Column>
193
-
194
- <Column>
195
- <div className={styles.dateTimeSection}>
196
- <ResponsiveWrapper>
197
- <Controller
198
- name="timeOfDischarge"
199
- control={control}
200
- render={({ field }) => (
201
- <TimePicker
202
- {...field}
203
- id="time-of-discharge-picker"
204
- labelText={t('timeOfDischarge', 'Time of discharge*')}
205
- className={styles.formAdmissionTimepicker}
206
- invalid={!!errors.timeOfDischarge}
207
- invalidText={errors.timeOfDischarge?.message}
208
- />
209
- )}
210
- />
211
- <Controller
212
- name="period"
213
- control={control}
214
- render={({ field }) => (
215
- <TimePickerSelect {...field} className={styles.formDeathTimepickerSelector} id="time-picker-select">
216
- <SelectItem value="AM" text="AM" />
217
- <SelectItem value="PM" text="PM" />
218
- </TimePickerSelect>
219
- )}
220
- />
221
- </ResponsiveWrapper>
222
- </div>
223
- </Column>
224
- </div>
225
- <Column className={styles.fieldColumn}>
226
- <Controller
227
- name="burialPermitNumber"
228
- control={control}
229
- render={({ field }) => (
230
- <TextInput
231
- {...field}
232
- id="burialPermitNumber"
233
- type="text"
234
- className={styles.fieldSection}
235
- placeholder={t('burialPermitNumber', 'Burial permit number')}
236
- labelText={t('burialPermitNumber', 'Burial permit number')}
237
- invalid={!!errors.burialPermitNumber}
238
- invalidText={errors.burialPermitNumber?.message}
239
- />
240
- )}
241
- />
242
- </Column>
243
- <Column className={styles.fieldColumn}>
244
- <Controller
245
- name="nextOfKinNames"
246
- control={control}
247
- render={({ field }) => (
248
- <TextInput
249
- {...field}
250
- id="nextOfKinNames"
251
- type="text"
252
- className={styles.fieldSection}
253
- placeholder={t('nextOfKinNames', 'Next of kin names')}
254
- labelText={t('nextOfKinNames', 'Next of kin names')}
255
- invalid={!!errors.nextOfKinNames}
256
- invalidText={errors.nextOfKinNames?.message}
257
- />
258
- )}
259
- />
260
- </Column>
261
- <Column className={styles.fieldColumn}>
262
- <Controller
263
- name="relationshipType"
264
- control={control}
265
- render={({ field }) => (
266
- <TextInput
267
- {...field}
268
- id="relationship"
269
- type="text"
270
- className={styles.fieldSection}
271
- placeholder={t('relationship', 'Relationship')}
272
- labelText={t('relationship', 'Relationship')}
273
- invalid={!!errors.relationshipType}
274
- invalidText={errors.relationshipType?.message}
275
- />
276
- )}
277
- />
278
- </Column>
279
- <Column className={styles.fieldColumn}>
280
- <Controller
281
- name="nextOfKinContact"
282
- control={control}
283
- render={({ field }) => (
284
- <TextInput
285
- {...field}
286
- id="telephone"
287
- type="text"
288
- className={styles.fieldSection}
289
- placeholder={t('telephone', 'Telephone number')}
290
- labelText={t('telephone', 'Telephone number')}
291
- invalid={!!errors.nextOfKinContact}
292
- invalidText={errors.nextOfKinContact?.message}
293
- />
294
- )}
295
- />
296
- </Column>
297
- <Column className={styles.fieldColumn}>
298
- <Controller
299
- name="nextOfKinAddress"
300
- control={control}
301
- render={({ field }) => (
302
- <TextInput
303
- {...field}
304
- id="nextOfKinAddress"
305
- type="text"
306
- className={styles.fieldSection}
307
- placeholder={t('nextOfKinAddress', 'Next of kin address')}
308
- labelText={t('nextOfKinAddress', 'Next of kin address')}
309
- invalid={!!errors.nextOfKinAddress}
310
- invalidText={errors.nextOfKinAddress?.message}
311
- />
312
- )}
313
- />
314
- </Column>
315
-
316
- <ButtonSet className={styles.buttonSet}>
317
- <Button size="lg" kind="secondary" onClick={closeWorkspace}>
318
- {t('discard', 'Discard')}
319
- </Button>
320
- <Button kind="primary" size="lg" type="submit">
321
- {t('submit', 'Submit')}
322
- </Button>
323
- </ButtonSet>
324
- </Stack>
325
- </Form>
326
- );
327
- };
328
-
329
- export default DischargeForm;