@kenyaemr/esm-morgue-app 5.4.1-pre.1848 → 5.4.1-pre.1859
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 +84 -21
- package/dist/160.js +1 -0
- package/dist/160.js.map +1 -0
- package/dist/195.js +1 -0
- package/dist/195.js.map +1 -0
- package/dist/240.js +1 -0
- package/dist/240.js.map +1 -0
- package/dist/282.js +1 -0
- package/dist/282.js.map +1 -0
- package/dist/300.js +1 -1
- package/dist/{561.js → 521.js} +1 -1
- package/dist/521.js.map +1 -0
- package/dist/527.js +1 -0
- package/dist/527.js.map +1 -0
- package/dist/596.js +1 -0
- package/dist/596.js.map +1 -0
- package/dist/652.js +1 -1
- package/dist/652.js.map +1 -1
- package/dist/659.js +2 -0
- package/dist/659.js.map +1 -0
- package/dist/675.js +2 -0
- package/dist/{485.js.map → 675.js.map} +1 -1
- package/dist/730.js +1 -0
- package/dist/730.js.map +1 -0
- package/dist/755.js +1 -0
- package/dist/755.js.map +1 -0
- package/dist/795.js +1 -0
- package/dist/795.js.map +1 -0
- package/dist/818.js +1 -0
- package/dist/818.js.map +1 -0
- package/dist/{942.js → 870.js} +1 -1
- package/dist/870.js.map +1 -0
- package/dist/909.js +2 -0
- package/dist/909.js.map +1 -0
- package/dist/926.js +1 -1
- package/dist/926.js.map +1 -1
- package/dist/929.js +1 -0
- package/dist/929.js.map +1 -0
- package/dist/960.js +1 -0
- package/dist/960.js.map +1 -0
- package/dist/kenyaemr-esm-morgue-app.js +1 -1
- package/dist/kenyaemr-esm-morgue-app.js.buildmanifest.json +371 -127
- package/dist/kenyaemr-esm-morgue-app.js.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/autosuggest/autosuggest.component.tsx +162 -0
- package/src/autosuggest/autosuggest.scss +61 -0
- package/src/autosuggest/patient-search-info.component.tsx +75 -0
- package/src/autosuggest/patient-search-info.scss +62 -0
- package/src/autosuggest/search-empty-state.component.tsx +21 -0
- package/src/autosuggest/search-empty-state.scss +18 -0
- package/src/card/avail-compartment.compartment.tsx +40 -41
- package/src/card/compartment-view.compartment.tsx +37 -14
- package/src/card/compartment.scss +18 -13
- package/src/card/compartmentSharing.component.tsx +21 -0
- package/src/card/compartmentSharing.scss +24 -0
- package/src/card/empty-compartment.component.tsx +11 -7
- package/src/card/empty-compartment.scss +61 -0
- package/src/component/deceasedInfo/deceased-info.component.tsx +1 -1
- package/src/component/main.component.tsx +1 -7
- package/src/component/next-of-kin-details/nextOfKinDetails.component.tsx +50 -0
- package/src/component/next-of-kin-details/nextOfKinDetails.scss +37 -0
- package/src/config-schema.ts +30 -22
- package/src/extension/actionButton.component.tsx +74 -0
- package/src/extension/actionButton.scss +69 -0
- package/src/extension/deceasedInfoBanner.component.tsx +57 -0
- package/src/hook/useAdmitPatient.ts +285 -0
- package/src/hook/useDeceasedPatients.ts +12 -0
- package/src/hook/useDischargedPatient.ts +55 -0
- package/src/hook/useMorgue.resource.ts +11 -120
- package/src/hook/useMortuaryAdmissionLocation.ts +64 -0
- package/src/hook/usePersonAttributes.ts +65 -0
- package/src/index.ts +4 -0
- package/src/routes.json +24 -7
- package/src/tables/admitted-queue.component.tsx +17 -21
- package/src/tables/discharge-queue.component.tsx +33 -27
- package/src/tables/generic-table.component.tsx +44 -19
- package/src/tabs/tabs.component.tsx +36 -16
- package/src/tabs/tabs.scss +3 -186
- package/src/types/index.ts +291 -9
- package/src/utils/utils.ts +55 -4
- package/src/workspaces/admit-body.scss +46 -0
- package/src/workspaces/admit-body.workspace.tsx +79 -0
- package/src/workspaces/discharge-body.scss +2 -2
- package/src/workspaces/discharge-body.workspace.tsx +157 -101
- package/src/workspaces/patientAdditionalInfoForm.workspace.tsx +141 -218
- package/src/workspaces/swap-unit.scss +46 -0
- package/src/workspaces/swap-unit.workspace.tsx +168 -0
- package/translations/en.json +22 -7
- package/dist/340.js +0 -1
- package/dist/340.js.map +0 -1
- package/dist/38.js +0 -1
- package/dist/38.js.map +0 -1
- package/dist/485.js +0 -2
- package/dist/553.js +0 -1
- package/dist/553.js.map +0 -1
- package/dist/561.js.map +0 -1
- package/dist/592.js +0 -2
- package/dist/592.js.map +0 -1
- package/dist/759.js +0 -1
- package/dist/759.js.map +0 -1
- package/dist/942.js.map +0 -1
- package/dist/987.js +0 -2
- package/dist/987.js.map +0 -1
- package/src/component/deceasedInfo/deceased-header.component.tsx +0 -37
- package/src/tables/waiting-queue.component.tsx +0 -91
- /package/dist/{987.js.LICENSE.txt → 659.js.LICENSE.txt} +0 -0
- /package/dist/{485.js.LICENSE.txt → 675.js.LICENSE.txt} +0 -0
- /package/dist/{592.js.LICENSE.txt → 909.js.LICENSE.txt} +0 -0
|
@@ -0,0 +1,46 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
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,17 +1,18 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
1
|
import {
|
|
3
2
|
Button,
|
|
4
3
|
ButtonSet,
|
|
4
|
+
Column,
|
|
5
5
|
DatePicker,
|
|
6
6
|
DatePickerInput,
|
|
7
7
|
Form,
|
|
8
|
+
InlineLoading,
|
|
9
|
+
SelectItem,
|
|
8
10
|
Stack,
|
|
11
|
+
TextInput,
|
|
9
12
|
TimePicker,
|
|
10
13
|
TimePickerSelect,
|
|
11
|
-
SelectItem,
|
|
12
|
-
Column,
|
|
13
|
-
TextInput,
|
|
14
14
|
} from '@carbon/react';
|
|
15
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
15
16
|
import {
|
|
16
17
|
ResponsiveWrapper,
|
|
17
18
|
restBaseUrl,
|
|
@@ -19,65 +20,60 @@ import {
|
|
|
19
20
|
showSnackbar,
|
|
20
21
|
useConfig,
|
|
21
22
|
useLayoutType,
|
|
22
|
-
useSession,
|
|
23
23
|
useVisit,
|
|
24
24
|
} from '@openmrs/esm-framework';
|
|
25
|
+
import React, { useCallback, useEffect } from 'react';
|
|
26
|
+
import { Controller, useForm } from 'react-hook-form';
|
|
25
27
|
import { useTranslation } from 'react-i18next';
|
|
26
|
-
import
|
|
27
|
-
import DeceasedInfo from '../component/deceasedInfo/deceased-info.component';
|
|
28
|
-
import {
|
|
29
|
-
removeQueuedPatient,
|
|
30
|
-
startVisitWithEncounter,
|
|
31
|
-
updateVisit,
|
|
32
|
-
useVisitQueueEntry,
|
|
33
|
-
} from '../hook/useMorgue.resource';
|
|
28
|
+
import { mutate } from 'swr';
|
|
34
29
|
import { z } from 'zod';
|
|
35
|
-
import
|
|
36
|
-
import { zodResolver } from '@hookform/resolvers/zod';
|
|
37
|
-
import { getCurrentTime } from '../utils/utils';
|
|
30
|
+
import DeceasedInfo from '../component/deceasedInfo/deceased-info.component';
|
|
38
31
|
import { ConfigObject } from '../config-schema';
|
|
39
|
-
import {
|
|
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';
|
|
40
38
|
|
|
41
39
|
interface DischargeFormProps {
|
|
42
40
|
closeWorkspace: () => void;
|
|
43
41
|
patientUuid: string;
|
|
42
|
+
personUuid: string;
|
|
43
|
+
bedId: number;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
const dischargeSchema = z.object({
|
|
47
|
-
dateOfDischarge: z.date({ coerce: true }).refine((date) => !!date, 'Date of discharge is required'),
|
|
48
|
-
timeOfDischarge: z.string().nonempty('Time of discharge is required'),
|
|
49
|
-
period: z
|
|
50
|
-
.string()
|
|
51
|
-
.nonempty('AM/PM is required')
|
|
52
|
-
.regex(/^(AM|PM)$/i, 'Invalid period'),
|
|
53
|
-
burialPermitNumber: z.string().nonempty('Burial Permit Number is required'),
|
|
54
|
-
});
|
|
55
|
-
|
|
56
46
|
type DischargeFormValues = z.infer<typeof dischargeSchema>;
|
|
57
47
|
|
|
58
|
-
const DischargeForm: React.FC<DischargeFormProps> = ({ closeWorkspace, patientUuid }) => {
|
|
48
|
+
const DischargeForm: React.FC<DischargeFormProps> = ({ closeWorkspace, patientUuid, bedId, personUuid }) => {
|
|
59
49
|
const { t } = useTranslation();
|
|
60
50
|
const layout = useLayoutType();
|
|
61
51
|
const { currentVisit, currentVisitIsRetrospective } = useVisit(patientUuid);
|
|
62
52
|
const { queueEntry } = useVisitQueueEntry(patientUuid, currentVisit?.uuid);
|
|
53
|
+
const { dischargeBody, isLoadingEmrConfiguration } = useMortuaryOperation();
|
|
54
|
+
const { createOrUpdatePersonAttribute, personAttributes } = usePersonAttributes(personUuid);
|
|
63
55
|
|
|
64
56
|
const { time: defaultTime, period: defaultPeriod } = getCurrentTime();
|
|
65
57
|
|
|
66
|
-
const {
|
|
67
|
-
|
|
68
|
-
sessionLocation: { uuid: locationUuid },
|
|
69
|
-
} = useSession();
|
|
58
|
+
const { nextOfKinAddressUuid, nextOfKinNameUuid, nextOfKinPhoneUuid, nextOfKinRelationshipUuid } =
|
|
59
|
+
useConfig<ConfigObject>();
|
|
70
60
|
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
+
);
|
|
78
72
|
|
|
79
73
|
const {
|
|
74
|
+
watch,
|
|
80
75
|
control,
|
|
76
|
+
setValue,
|
|
81
77
|
handleSubmit,
|
|
82
78
|
formState: { errors },
|
|
83
79
|
} = useForm<DischargeFormValues>({
|
|
@@ -89,82 +85,67 @@ const DischargeForm: React.FC<DischargeFormProps> = ({ closeWorkspace, patientUu
|
|
|
89
85
|
burialPermitNumber: '',
|
|
90
86
|
},
|
|
91
87
|
});
|
|
92
|
-
|
|
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
|
+
]);
|
|
93
104
|
const onSubmit = async (data: DischargeFormValues) => {
|
|
94
105
|
if (currentVisitIsRetrospective) {
|
|
95
106
|
setCurrentVisit(null, null);
|
|
96
107
|
closeWorkspace();
|
|
97
108
|
} else {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
{
|
|
110
|
-
provider: currentProviderUuid,
|
|
111
|
-
encounterRole: encounterProviderRoleUuid,
|
|
112
|
-
},
|
|
113
|
-
],
|
|
114
|
-
visit: currentVisit?.uuid,
|
|
115
|
-
obs: obs.length > 0 ? obs : undefined,
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
const endVisitPayload = {
|
|
119
|
-
stopDatetime: data.dateOfDischarge,
|
|
120
|
-
};
|
|
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 || [],
|
|
119
|
+
};
|
|
121
120
|
|
|
122
|
-
|
|
121
|
+
for (const attribute of nextOfKinAttributes) {
|
|
122
|
+
await createOrUpdatePersonAttribute(patientUuid, attribute, patientInfo);
|
|
123
|
+
}
|
|
123
124
|
|
|
124
|
-
|
|
125
|
-
// First, create the encounter
|
|
126
|
-
await startVisitWithEncounter(encounterPayload);
|
|
125
|
+
await dischargeBody(currentVisit, queueEntry, bedId, data);
|
|
127
126
|
|
|
128
127
|
showSnackbar({
|
|
129
|
-
title: '
|
|
130
|
-
subtitle: '
|
|
128
|
+
title: t('dischargeDeceasedPatient', 'Deceased patient'),
|
|
129
|
+
subtitle: t('deceasedPatientDischargedSuccessfully', 'Deceased patient has been discharged successfully'),
|
|
131
130
|
kind: 'success',
|
|
131
|
+
isLowContrast: true,
|
|
132
132
|
});
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
abortController,
|
|
142
|
-
response?.data.stopDatetime,
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
closeWorkspace();
|
|
146
|
-
showSnackbar({
|
|
147
|
-
isLowContrast: true,
|
|
148
|
-
kind: 'success',
|
|
149
|
-
subtitle: t('visitEndSuccessfully', `${response?.data?.visitType?.display} ended successfully`),
|
|
150
|
-
title: t('visitEnded', 'Visit ended'),
|
|
151
|
-
});
|
|
152
|
-
mutate((key) => typeof key === 'string' && key.startsWith(`${restBaseUrl}/visit`));
|
|
153
|
-
},
|
|
154
|
-
error: (error) => {
|
|
155
|
-
showSnackbar({
|
|
156
|
-
title: t('errorEndingVisit', 'Error ending visit'),
|
|
157
|
-
kind: 'error',
|
|
158
|
-
isLowContrast: false,
|
|
159
|
-
subtitle: error?.message,
|
|
160
|
-
});
|
|
161
|
-
},
|
|
162
|
-
});
|
|
134
|
+
mutate(
|
|
135
|
+
(key) =>
|
|
136
|
+
typeof key === 'string' && key.startsWith(`${restBaseUrl}/patient/${patientUuid}/chart/deceased-panel`),
|
|
137
|
+
undefined,
|
|
138
|
+
);
|
|
139
|
+
mutate((key) => typeof key === 'string' && key.startsWith(`${restBaseUrl}/visit`));
|
|
140
|
+
closeWorkspace();
|
|
163
141
|
} catch (error) {
|
|
164
142
|
const errorMessage = JSON.stringify(error?.responseBody?.error?.message?.replace(/\[/g, '').replace(/\]/g, ''));
|
|
165
143
|
showSnackbar({
|
|
166
|
-
title: 'Visit Error',
|
|
167
|
-
subtitle:
|
|
144
|
+
title: t('visitError', 'Visit Error'),
|
|
145
|
+
subtitle: t(
|
|
146
|
+
'visitErrorMessage',
|
|
147
|
+
`An error has occurred while ending visit, Contact system administrator quoting this error ${errorMessage}`,
|
|
148
|
+
),
|
|
168
149
|
kind: 'error',
|
|
169
150
|
isLowContrast: true,
|
|
170
151
|
});
|
|
@@ -172,6 +153,9 @@ const DischargeForm: React.FC<DischargeFormProps> = ({ closeWorkspace, patientUu
|
|
|
172
153
|
}
|
|
173
154
|
};
|
|
174
155
|
|
|
156
|
+
if (isLoadingEmrConfiguration || !personAttributes) {
|
|
157
|
+
return <InlineLoading status="active" iconDescription="Loading" description="Loading ..." />;
|
|
158
|
+
}
|
|
175
159
|
return (
|
|
176
160
|
<Form className={styles.formContainer} onSubmit={handleSubmit(onSubmit)}>
|
|
177
161
|
<Stack gap={4} className={styles.formGrid}>
|
|
@@ -259,13 +243,85 @@ const DischargeForm: React.FC<DischargeFormProps> = ({ closeWorkspace, patientUu
|
|
|
259
243
|
)}
|
|
260
244
|
/>
|
|
261
245
|
</Column>
|
|
246
|
+
<Column className={styles.fieldColumn}>
|
|
247
|
+
<Controller
|
|
248
|
+
name="nextOfKinNames"
|
|
249
|
+
control={control}
|
|
250
|
+
render={({ field }) => (
|
|
251
|
+
<TextInput
|
|
252
|
+
{...field}
|
|
253
|
+
id="nextOfKinNames"
|
|
254
|
+
type="text"
|
|
255
|
+
className={styles.fieldSection}
|
|
256
|
+
placeholder={t('nextOfKinNames', 'Next of kin names')}
|
|
257
|
+
labelText={t('nextOfKinNames', 'Next of kin names')}
|
|
258
|
+
invalid={!!errors.nextOfKinNames}
|
|
259
|
+
invalidText={errors.nextOfKinNames?.message}
|
|
260
|
+
/>
|
|
261
|
+
)}
|
|
262
|
+
/>
|
|
263
|
+
</Column>
|
|
264
|
+
<Column className={styles.fieldColumn}>
|
|
265
|
+
<Controller
|
|
266
|
+
name="relationshipType"
|
|
267
|
+
control={control}
|
|
268
|
+
render={({ field }) => (
|
|
269
|
+
<TextInput
|
|
270
|
+
{...field}
|
|
271
|
+
id="relationship"
|
|
272
|
+
type="text"
|
|
273
|
+
className={styles.fieldSection}
|
|
274
|
+
placeholder={t('relationship', 'Relationship')}
|
|
275
|
+
labelText={t('relationship', 'Relationship')}
|
|
276
|
+
invalid={!!errors.relationshipType}
|
|
277
|
+
invalidText={errors.relationshipType?.message}
|
|
278
|
+
/>
|
|
279
|
+
)}
|
|
280
|
+
/>
|
|
281
|
+
</Column>
|
|
282
|
+
<Column className={styles.fieldColumn}>
|
|
283
|
+
<Controller
|
|
284
|
+
name="nextOfKinContact"
|
|
285
|
+
control={control}
|
|
286
|
+
render={({ field }) => (
|
|
287
|
+
<TextInput
|
|
288
|
+
{...field}
|
|
289
|
+
id="telephone"
|
|
290
|
+
type="text"
|
|
291
|
+
className={styles.fieldSection}
|
|
292
|
+
placeholder={t('telephone', 'Telephone number')}
|
|
293
|
+
labelText={t('telephone', 'Telephone number')}
|
|
294
|
+
invalid={!!errors.nextOfKinContact}
|
|
295
|
+
invalidText={errors.nextOfKinContact?.message}
|
|
296
|
+
/>
|
|
297
|
+
)}
|
|
298
|
+
/>
|
|
299
|
+
</Column>
|
|
300
|
+
<Column className={styles.fieldColumn}>
|
|
301
|
+
<Controller
|
|
302
|
+
name="nextOfKinAddress"
|
|
303
|
+
control={control}
|
|
304
|
+
render={({ field }) => (
|
|
305
|
+
<TextInput
|
|
306
|
+
{...field}
|
|
307
|
+
id="nextOfKinAddress"
|
|
308
|
+
type="text"
|
|
309
|
+
className={styles.fieldSection}
|
|
310
|
+
placeholder={t('nextOfKinAddress', 'Next of kin address')}
|
|
311
|
+
labelText={t('nextOfKinAddress', 'Next of kin address')}
|
|
312
|
+
invalid={!!errors.nextOfKinAddress}
|
|
313
|
+
invalidText={errors.nextOfKinAddress?.message}
|
|
314
|
+
/>
|
|
315
|
+
)}
|
|
316
|
+
/>
|
|
317
|
+
</Column>
|
|
262
318
|
|
|
263
319
|
<ButtonSet className={styles.buttonSet}>
|
|
264
320
|
<Button size="lg" kind="secondary" onClick={closeWorkspace}>
|
|
265
321
|
{t('discard', 'Discard')}
|
|
266
322
|
</Button>
|
|
267
323
|
<Button kind="primary" size="lg" type="submit">
|
|
268
|
-
{t('
|
|
324
|
+
{t('submit', 'Submit')}
|
|
269
325
|
</Button>
|
|
270
326
|
</ButtonSet>
|
|
271
327
|
</Stack>
|