@kenyaemr/esm-ward-app 8.1.1-pre.114 → 8.1.1-pre.116
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 +18 -17
- package/dist/109.js +1 -0
- package/dist/109.js.map +1 -0
- package/dist/125.js +1 -0
- package/dist/125.js.map +1 -0
- package/dist/126.js +1 -0
- package/dist/126.js.map +1 -0
- package/dist/130.js +1 -1
- package/dist/130.js.map +1 -1
- package/dist/146.js +1 -0
- package/dist/146.js.map +1 -0
- package/dist/15.js +1 -0
- package/dist/15.js.map +1 -0
- package/dist/161.js +2 -0
- package/dist/161.js.map +1 -0
- package/dist/269.js +1 -1
- package/dist/269.js.map +1 -1
- package/dist/466.js +1 -1
- package/dist/466.js.map +1 -1
- package/dist/500.js +1 -0
- package/dist/500.js.map +1 -0
- package/dist/53.js +1 -0
- package/dist/53.js.map +1 -0
- package/dist/557.js +1 -0
- package/dist/557.js.map +1 -0
- package/dist/559.js +1 -0
- package/dist/559.js.map +1 -0
- package/dist/574.js +1 -1
- package/dist/577.js +1 -1
- package/dist/577.js.map +1 -1
- package/dist/659.js +1 -1
- package/dist/659.js.map +1 -1
- package/dist/701.js +1 -0
- package/dist/701.js.map +1 -0
- package/dist/749.js +1 -1
- package/dist/749.js.map +1 -1
- package/dist/908.js +1 -0
- package/dist/908.js.map +1 -0
- package/dist/922.js +1 -0
- package/dist/922.js.map +1 -0
- package/dist/969.js +1 -0
- package/dist/969.js.map +1 -0
- package/dist/kenyaemr-esm-ward-app.js +1 -1
- package/dist/kenyaemr-esm-ward-app.js.buildmanifest.json +294 -74
- package/dist/kenyaemr-esm-ward-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/mock.tsx +54 -0
- package/package.json +1 -1
- package/src/action-menu-buttons/clinical-forms-workspace-siderail.component.tsx +37 -0
- package/src/action-menu-buttons/discharge-workspace-siderail.component.tsx +20 -0
- package/src/beds/empty-bed-skeleton.tsx +2 -1
- package/src/beds/empty-bed.scss +0 -4
- package/src/beds/occupied-bed.scss +1 -0
- package/src/config-schema-mother-child-row.ts +26 -0
- package/src/config-schema-pending-items-extension.ts +29 -0
- package/src/config-schema.ts +12 -14
- package/src/hooks/useAdmissionLocation.ts +22 -4
- package/src/hooks/useBeds.ts +3 -4
- package/src/hooks/useConcept.ts +3 -4
- package/src/hooks/useEmrConfiguration.ts +5 -0
- package/src/hooks/useInpatientAdmission.ts +9 -14
- package/src/hooks/useInpatientRequest.ts +4 -15
- package/src/hooks/useLocations.ts +8 -51
- package/src/hooks/useMotherAndChildren.ts +46 -0
- package/src/hooks/useObs.ts +2 -6
- package/src/hooks/usePatientPendingOrders.ts +16 -0
- package/src/hooks/useWardPatientGrouping.ts +25 -0
- package/src/index.ts +50 -3
- package/src/location-selector/location-selector.component.tsx +18 -21
- package/src/routes.json +43 -0
- package/src/types/index.ts +34 -0
- package/src/ward-patient-card/card-rows/admission-request-note.extension.tsx +7 -2
- package/src/ward-patient-card/card-rows/mother-child-row.extension.tsx +110 -0
- package/src/ward-patient-card/card-rows/mother-child-row.scss +22 -0
- package/src/ward-patient-card/card-rows/pending-items-car-row.extension.tsx +50 -0
- package/src/ward-patient-card/row-elements/ward-pateint-skeleton-text.tsx +9 -0
- package/src/ward-patient-card/row-elements/ward-patient-age.tsx +1 -1
- package/src/ward-patient-card/row-elements/ward-patient-coded-obs-tags.tsx +54 -36
- package/src/ward-patient-card/row-elements/ward-patient-identifier.tsx +2 -3
- package/src/ward-patient-card/row-elements/ward-patient-location.tsx +19 -0
- package/src/ward-patient-card/row-elements/ward-patient-obs.resource.ts +36 -32
- package/src/ward-patient-card/row-elements/ward-patient-obs.tsx +15 -9
- package/src/ward-patient-card/row-elements/ward-patient-pending-order.component.tsx +45 -0
- package/src/ward-patient-card/row-elements/ward-patient-pending-transfer.tsx +38 -0
- package/src/ward-patient-card/row-elements/ward-patient-responsive-tooltip.tsx +32 -0
- package/src/ward-patient-card/ward-patient-card-element.component.tsx +4 -0
- package/src/ward-patient-card/ward-patient-card.component.tsx +21 -14
- package/src/ward-patient-card/ward-patient-card.scss +61 -8
- package/src/ward-patient-card/ward-patient-resource.ts +15 -0
- package/src/ward-view/ward-view.component.tsx +124 -132
- package/src/ward-view/ward-view.resource.ts +121 -1
- package/src/ward-view/ward-view.scss +16 -6
- package/src/ward-view/ward-view.test.tsx +27 -42
- package/src/ward-view-header/admission-requests-bar.component.tsx +8 -7
- package/src/ward-view-header/admission-requests-bar.test.tsx +8 -21
- package/src/ward-view-header/admission-requests.scss +1 -1
- package/src/ward-view-header/ward-metric.component.tsx +24 -0
- package/src/ward-view-header/ward-metric.scss +25 -0
- package/src/ward-view-header/ward-metrics.component.tsx +77 -0
- package/src/ward-view-header/ward-metrics.scss +8 -0
- package/src/ward-view-header/ward-metrics.test.tsx +91 -0
- package/src/ward-view-header/ward-view-header.component.tsx +3 -0
- package/src/ward-view-header/ward-view-header.scss +0 -1
- package/src/ward-workspace/admission-request-card/admission-request-card-actions.component.tsx +11 -3
- package/src/ward-workspace/admission-request-card/admission-request-card-header.component.tsx +4 -5
- package/src/ward-workspace/admission-request-card/admission-request-card.scss +8 -4
- package/src/ward-workspace/admission-request-workspace/admission-requests-workspace.test.tsx +8 -3
- package/src/ward-workspace/admission-request-workspace/admission-requests.workspace.tsx +2 -0
- package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.test.tsx +29 -61
- package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.workspace.tsx +37 -21
- package/src/ward-workspace/patient-banner/patient-banner.component.tsx +3 -3
- package/src/ward-workspace/patient-clinical-forms-workspace/patient-clinical-forms.workspace.tsx +23 -0
- package/src/{ward-patient-workspace → ward-workspace/patient-details}/ward-patient-action-button.extension.tsx +2 -1
- package/src/{ward-patient-workspace → ward-workspace/patient-details}/ward-patient.workspace.tsx +7 -5
- package/src/ward-workspace/patient-discharge/patient-discharge.scss +41 -0
- package/src/ward-workspace/patient-discharge/patient-discharge.workspace.tsx +120 -0
- package/src/ward-workspace/patient-transfer-bed-swap/patient-bed-swap-form.component.tsx +40 -30
- package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-request-form.component.tsx +29 -22
- package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-swap.scss +12 -2
- package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-swap.workspace.tsx +2 -2
- package/src/ward-workspace/patient-transfer-request-workspace/patient-transfer-request.workspace.tsx +11 -0
- package/src/ward-workspace/ward-patient-notes/form/notes-form.component.tsx +1 -1
- package/src/ward-workspace/ward-patient-notes/form/notes-form.test.tsx +1 -1
- package/src/ward-workspace/ward-patient-notes/history/notes-container.component.tsx +2 -2
- package/src/ward-workspace/ward-patient-notes/notes.resource.ts +5 -7
- package/src/ward-workspace/ward-patient-notes/notes.workspace.tsx +1 -1
- package/src/ward-workspace/ward-patient-notes/types.ts +0 -4
- package/src/ward.resource.ts +6 -0
- package/translations/en.json +18 -1
- package/dist/346.js +0 -1
- package/dist/346.js.map +0 -1
- package/dist/76.js +0 -1
- package/dist/76.js.map +0 -1
- package/dist/803.js +0 -1
- package/dist/803.js.map +0 -1
- package/dist/958.js +0 -2
- package/dist/958.js.map +0 -1
- package/dist/960.js +0 -1
- package/dist/960.js.map +0 -1
- /package/dist/{958.js.LICENSE.txt → 161.js.LICENSE.txt} +0 -0
- /package/src/{ward-patient-workspace → ward-workspace/patient-details}/ward-patient.style.scss +0 -0
package/src/ward-workspace/patient-clinical-forms-workspace/patient-clinical-forms.workspace.tsx
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { ExtensionSlot } from '@openmrs/esm-framework';
|
|
3
|
+
import type { WardPatientWorkspaceProps } from '../../types';
|
|
4
|
+
|
|
5
|
+
const WardPatientClinicalFormsWorkspace: React.FC<WardPatientWorkspaceProps> = (props) => {
|
|
6
|
+
const { wardPatient, ...restWorkspaceProps } = props;
|
|
7
|
+
const patientUuid = wardPatient?.patient?.uuid;
|
|
8
|
+
|
|
9
|
+
const clinicalFormsExtensionState = useMemo(
|
|
10
|
+
() => ({
|
|
11
|
+
patientUuid,
|
|
12
|
+
clinicalFormsWorkspaceName: 'ward-patient-clinical-forms-workspace',
|
|
13
|
+
formEntryWorkspaceName: 'ward-patient-form-entry-workspace',
|
|
14
|
+
htmlFormEntryWorkspaceName: 'ward-patient-html-form-entry-workspace',
|
|
15
|
+
...restWorkspaceProps,
|
|
16
|
+
}),
|
|
17
|
+
[patientUuid, restWorkspaceProps],
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
return <ExtensionSlot name="ward-patient-clinical-forms-workspace-slot" state={clinicalFormsExtensionState} />;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default WardPatientClinicalFormsWorkspace;
|
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import { UserAvatarIcon } from '@openmrs/esm-framework';
|
|
4
4
|
import { ActionMenuButton, launchWorkspace } from '@openmrs/esm-framework';
|
|
5
|
+
import { launchPatientWorkspace } from '../../ward-patient-card/ward-patient-resource';
|
|
5
6
|
|
|
6
7
|
export default function WardPatientActionButton() {
|
|
7
8
|
const { t } = useTranslation();
|
|
@@ -11,7 +12,7 @@ export default function WardPatientActionButton() {
|
|
|
11
12
|
getIcon={(props) => <UserAvatarIcon {...props} />}
|
|
12
13
|
label={t('Patient', 'patient')}
|
|
13
14
|
iconDescription={t('Patient', 'patient')}
|
|
14
|
-
handler={() =>
|
|
15
|
+
handler={() => launchPatientWorkspace()}
|
|
15
16
|
type={'ward'}
|
|
16
17
|
/>
|
|
17
18
|
);
|
package/src/{ward-patient-workspace → ward-workspace/patient-details}/ward-patient.workspace.tsx
RENAMED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { age, attach, ExtensionSlot, type Patient } from '@openmrs/esm-framework';
|
|
2
2
|
import React, { useEffect } from 'react';
|
|
3
|
-
import { type WardPatientWorkspaceProps } from '../types';
|
|
4
3
|
import styles from './ward-patient.style.scss';
|
|
5
4
|
import { useTranslation } from 'react-i18next';
|
|
6
|
-
import {
|
|
5
|
+
import { type WardPatientWorkspaceProps } from '../../types';
|
|
6
|
+
import { getGender } from '../../ward-patient-card/row-elements/ward-patient-gender.component';
|
|
7
7
|
|
|
8
8
|
attach('ward-patient-workspace-header-slot', 'patient-vitals-info');
|
|
9
9
|
|
|
10
10
|
export default function WardPatientWorkspace({ setTitle, wardPatient: { patient } }: WardPatientWorkspaceProps) {
|
|
11
11
|
useEffect(() => {
|
|
12
|
-
setTitle(patient.person.display, <PatientWorkspaceTitle patient={patient} />);
|
|
13
|
-
}, []);
|
|
12
|
+
setTitle(patient.person.display, <PatientWorkspaceTitle key={patient.uuid} patient={patient} />);
|
|
13
|
+
}, [patient.uuid]);
|
|
14
14
|
|
|
15
15
|
return (
|
|
16
16
|
<div className={styles.workspaceContainer}>
|
|
@@ -45,7 +45,9 @@ const PatientWorkspaceTitle: React.FC<WardPatientWorkspaceViewProps> = ({ patien
|
|
|
45
45
|
<>
|
|
46
46
|
<div>{patient.person.display} </div>
|
|
47
47
|
<div className={styles.headerPatientDetail}>· {getGender(t, patient.person?.gender)}</div>
|
|
48
|
-
|
|
48
|
+
{patient.person?.birthdate && (
|
|
49
|
+
<div className={styles.headerPatientDetail}>· {age(patient.person?.birthdate)}</div>
|
|
50
|
+
)}
|
|
49
51
|
</>
|
|
50
52
|
);
|
|
51
53
|
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
@use '@carbon/type';
|
|
2
|
+
@use '@carbon/layout';
|
|
3
|
+
@use '@openmrs/esm-styleguide/src/vars' as *;
|
|
4
|
+
|
|
5
|
+
.workspaceContent {
|
|
6
|
+
padding: layout.$spacing-05;
|
|
7
|
+
height: 100%;
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
color: #393939;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.patientWorkspaceBanner {
|
|
14
|
+
margin: (-(layout.$spacing-05)) (-(layout.$spacing-05)) layout.$spacing-05 (-(layout.$spacing-05));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.contentSwitcher {
|
|
18
|
+
margin-top: layout.$spacing-03;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.workspaceForm {
|
|
22
|
+
margin-top: layout.$spacing-05;
|
|
23
|
+
flex: 1;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.productiveHeading02 {
|
|
27
|
+
@include type.type-style('heading-compact-02');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.buttonSet {
|
|
31
|
+
margin: 0 (-(layout.$spacing-05)) (-(layout.$spacing-05)) (-(layout.$spacing-05));
|
|
32
|
+
|
|
33
|
+
button {
|
|
34
|
+
max-width: unset !important;
|
|
35
|
+
width: auto !important;
|
|
36
|
+
|
|
37
|
+
> svg {
|
|
38
|
+
fill: currentColor !important;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { Button, ButtonSet, InlineNotification } from '@carbon/react';
|
|
2
|
+
import { Exit } from '@carbon/react/icons';
|
|
3
|
+
import { ExtensionSlot, showSnackbar, useAppContext, useSession } from '@openmrs/esm-framework';
|
|
4
|
+
import React, { useCallback, useState } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import useEmrConfiguration from '../../hooks/useEmrConfiguration';
|
|
7
|
+
import useWardLocation from '../../hooks/useWardLocation';
|
|
8
|
+
import { type WardPatientGroupDetails, type WardPatientWorkspaceProps } from '../../types';
|
|
9
|
+
import { createEncounter, removePatientFromBed } from '../../ward.resource';
|
|
10
|
+
import WardPatientWorkspaceBanner from '../patient-banner/patient-banner.component';
|
|
11
|
+
import styles from './patient-discharge.scss';
|
|
12
|
+
|
|
13
|
+
export default function PatientDischargeWorkspace(props: WardPatientWorkspaceProps) {
|
|
14
|
+
const { wardPatient, closeWorkspaceWithSavedChanges } = props;
|
|
15
|
+
const { t } = useTranslation();
|
|
16
|
+
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
|
|
17
|
+
const { currentProvider } = useSession();
|
|
18
|
+
const { location } = useWardLocation();
|
|
19
|
+
const { emrConfiguration, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } = useEmrConfiguration();
|
|
20
|
+
const wardGroupingDetails = useAppContext<WardPatientGroupDetails>('ward-patients-group');
|
|
21
|
+
const { mutate: mutateAdmissionLocation } = wardGroupingDetails?.admissionLocationResponse ?? {};
|
|
22
|
+
const { mutate: mutateInpatientRequest } = wardGroupingDetails?.inpatientRequestResponse ?? {};
|
|
23
|
+
const { mutate: mutateInpatientAdmission } = wardGroupingDetails?.inpatientAdmissionResponse ?? {};
|
|
24
|
+
|
|
25
|
+
const submitDischarge = useCallback(() => {
|
|
26
|
+
setIsSubmitting(true);
|
|
27
|
+
|
|
28
|
+
createEncounter({
|
|
29
|
+
patient: wardPatient?.patient?.uuid,
|
|
30
|
+
encounterType: emrConfiguration.exitFromInpatientEncounterType.uuid,
|
|
31
|
+
location: location.uuid,
|
|
32
|
+
encounterProviders: [
|
|
33
|
+
{
|
|
34
|
+
encounterRole: emrConfiguration.clinicianEncounterRole.uuid,
|
|
35
|
+
provider: currentProvider?.uuid,
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
obs: [],
|
|
39
|
+
})
|
|
40
|
+
.then((response) => {
|
|
41
|
+
if (response?.ok) {
|
|
42
|
+
if (wardPatient?.bed?.id) {
|
|
43
|
+
return removePatientFromBed(wardPatient.bed.id, wardPatient?.patient?.uuid);
|
|
44
|
+
}
|
|
45
|
+
return response;
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
.then((response) => {
|
|
49
|
+
if (response?.ok) {
|
|
50
|
+
showSnackbar({
|
|
51
|
+
title: t('patientWasDischarged', 'Patient was discharged'),
|
|
52
|
+
kind: 'success',
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
.catch((err: Error) => {
|
|
57
|
+
showSnackbar({
|
|
58
|
+
title: t('errorDischargingPatient', 'Error discharging patient'),
|
|
59
|
+
subtitle: err.message,
|
|
60
|
+
kind: 'error',
|
|
61
|
+
});
|
|
62
|
+
})
|
|
63
|
+
.finally(() => {
|
|
64
|
+
setIsSubmitting(false);
|
|
65
|
+
closeWorkspaceWithSavedChanges();
|
|
66
|
+
mutateAdmissionLocation();
|
|
67
|
+
mutateInpatientRequest();
|
|
68
|
+
mutateInpatientAdmission();
|
|
69
|
+
});
|
|
70
|
+
}, [
|
|
71
|
+
currentProvider,
|
|
72
|
+
location,
|
|
73
|
+
emrConfiguration,
|
|
74
|
+
wardPatient?.patient?.uuid,
|
|
75
|
+
wardPatient?.bed?.uuid,
|
|
76
|
+
mutateAdmissionLocation,
|
|
77
|
+
mutateInpatientRequest,
|
|
78
|
+
mutateInpatientAdmission,
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
if (!wardGroupingDetails) return <></>;
|
|
82
|
+
return (
|
|
83
|
+
<div className={styles.workspaceContent}>
|
|
84
|
+
<div className={styles.patientWorkspaceBanner}>
|
|
85
|
+
<WardPatientWorkspaceBanner {...props?.wardPatient} />
|
|
86
|
+
</div>
|
|
87
|
+
<div className={styles.workspaceForm}>
|
|
88
|
+
<div>
|
|
89
|
+
{errorFetchingEmrConfiguration && (
|
|
90
|
+
<div className={styles.formError}>
|
|
91
|
+
<InlineNotification
|
|
92
|
+
kind="error"
|
|
93
|
+
title={t('somePartsOfTheFormDidntLoad', "Some parts of the form didn't load")}
|
|
94
|
+
subtitle={t(
|
|
95
|
+
'fetchingEmrConfigurationFailed',
|
|
96
|
+
'Fetching EMR configuration failed. Try refreshing the page or contact your system administrator.',
|
|
97
|
+
)}
|
|
98
|
+
lowContrast
|
|
99
|
+
hideCloseButton
|
|
100
|
+
/>
|
|
101
|
+
</div>
|
|
102
|
+
)}
|
|
103
|
+
</div>
|
|
104
|
+
<ExtensionSlot name="ward-patient-discharge-slot" />
|
|
105
|
+
<ButtonSet className={styles.buttonSet}>
|
|
106
|
+
<Button
|
|
107
|
+
size="sm"
|
|
108
|
+
kind="ghost"
|
|
109
|
+
renderIcon={(props) => <Exit size={16} {...props} />}
|
|
110
|
+
disabled={
|
|
111
|
+
isLoadingEmrConfiguration || isSubmitting || errorFetchingEmrConfiguration || !wardPatient?.patient
|
|
112
|
+
}
|
|
113
|
+
onClick={submitDischarge}>
|
|
114
|
+
{t('proceedWithPatientDischarge', 'Proceed with patient discharge')}
|
|
115
|
+
</Button>
|
|
116
|
+
</ButtonSet>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
@@ -1,26 +1,24 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
-
import styles from './patient-transfer-swap.scss';
|
|
3
|
-
import { useAdmissionLocation } from '../../hooks/useAdmissionLocation';
|
|
4
|
-
import { z } from 'zod';
|
|
5
|
-
import { useTranslation } from 'react-i18next';
|
|
6
|
-
import { Controller, useForm } from 'react-hook-form';
|
|
7
|
-
import { zodResolver } from '@hookform/resolvers/zod';
|
|
8
|
-
import { filterBeds } from '../../ward-view/ward-view.resource';
|
|
9
|
-
import type { BedLayout, WardPatientWorkspaceProps } from '../../types';
|
|
10
|
-
import { assignPatientToBed, createEncounter } from '../../ward.resource';
|
|
11
|
-
import useEmrConfiguration from '../../hooks/useEmrConfiguration';
|
|
12
|
-
import { showSnackbar, useSession } from '@openmrs/esm-framework';
|
|
13
|
-
import useWardLocation from '../../hooks/useWardLocation';
|
|
14
|
-
import { useInpatientRequest } from '../../hooks/useInpatientRequest';
|
|
15
1
|
import {
|
|
16
|
-
Form,
|
|
17
|
-
ButtonSet,
|
|
18
2
|
Button,
|
|
19
|
-
|
|
3
|
+
ButtonSet,
|
|
4
|
+
Form,
|
|
5
|
+
InlineNotification,
|
|
20
6
|
RadioButton,
|
|
7
|
+
RadioButtonGroup,
|
|
21
8
|
RadioButtonSkeleton,
|
|
22
|
-
InlineNotification,
|
|
23
9
|
} from '@carbon/react';
|
|
10
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
11
|
+
import { showSnackbar, useAppContext, useSession } from '@openmrs/esm-framework';
|
|
12
|
+
import classNames from 'classnames';
|
|
13
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
14
|
+
import { Controller, useForm } from 'react-hook-form';
|
|
15
|
+
import { useTranslation } from 'react-i18next';
|
|
16
|
+
import { z } from 'zod';
|
|
17
|
+
import useEmrConfiguration from '../../hooks/useEmrConfiguration';
|
|
18
|
+
import useWardLocation from '../../hooks/useWardLocation';
|
|
19
|
+
import type { BedLayout, WardPatientGroupDetails, WardPatientWorkspaceProps } from '../../types';
|
|
20
|
+
import { assignPatientToBed, createEncounter } from '../../ward.resource';
|
|
21
|
+
import styles from './patient-transfer-swap.scss';
|
|
24
22
|
|
|
25
23
|
export default function PatientBedSwapForm({
|
|
26
24
|
promptBeforeClosing,
|
|
@@ -30,13 +28,14 @@ export default function PatientBedSwapForm({
|
|
|
30
28
|
const { patient } = wardPatient;
|
|
31
29
|
const { t } = useTranslation();
|
|
32
30
|
const [showErrorNotifications, setShowErrorNotifications] = useState(false);
|
|
33
|
-
const { isLoading, admissionLocation } = useAdmissionLocation();
|
|
34
31
|
const { emrConfiguration, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } = useEmrConfiguration();
|
|
35
32
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
36
33
|
const { currentProvider } = useSession();
|
|
37
34
|
const { location } = useWardLocation();
|
|
38
|
-
const
|
|
39
|
-
const { mutate:
|
|
35
|
+
const wardGroupingDetails = useAppContext<WardPatientGroupDetails>('ward-patients-group');
|
|
36
|
+
const { isLoading, mutate: mutateAdmissionLocation } = wardGroupingDetails?.admissionLocationResponse ?? {};
|
|
37
|
+
const { mutate: mutateInpatientRequest } = wardGroupingDetails?.inpatientRequestResponse ?? {};
|
|
38
|
+
const { mutate: mutateInpatientAdmission } = wardGroupingDetails?.inpatientAdmissionResponse ?? {};
|
|
40
39
|
|
|
41
40
|
const zodSchema = useMemo(
|
|
42
41
|
() =>
|
|
@@ -71,7 +70,7 @@ export default function PatientBedSwapForm({
|
|
|
71
70
|
[t],
|
|
72
71
|
);
|
|
73
72
|
|
|
74
|
-
const beds =
|
|
73
|
+
const beds = wardGroupingDetails?.bedLayouts ?? [];
|
|
75
74
|
const bedDetails = useMemo(
|
|
76
75
|
() =>
|
|
77
76
|
beds.map((bed) => {
|
|
@@ -112,9 +111,6 @@ export default function PatientBedSwapForm({
|
|
|
112
111
|
bedNumber: bedSelected.bedNumber,
|
|
113
112
|
}),
|
|
114
113
|
});
|
|
115
|
-
mutateAdmissionLocation();
|
|
116
|
-
mutateInpatientRequest();
|
|
117
|
-
closeWorkspaceWithSavedChanges();
|
|
118
114
|
}
|
|
119
115
|
})
|
|
120
116
|
.catch((error: Error) => {
|
|
@@ -123,23 +119,37 @@ export default function PatientBedSwapForm({
|
|
|
123
119
|
title: t('errorAssigningBedToPatient', 'Error assigning bed to patient'),
|
|
124
120
|
subtitle: error?.message,
|
|
125
121
|
});
|
|
126
|
-
mutateAdmissionLocation();
|
|
127
|
-
mutateInpatientRequest();
|
|
128
|
-
closeWorkspaceWithSavedChanges();
|
|
129
122
|
})
|
|
130
123
|
.finally(() => {
|
|
131
124
|
setIsSubmitting(false);
|
|
125
|
+
mutateAdmissionLocation();
|
|
126
|
+
mutateInpatientRequest();
|
|
127
|
+
mutateInpatientAdmission();
|
|
128
|
+
closeWorkspaceWithSavedChanges();
|
|
132
129
|
});
|
|
133
130
|
},
|
|
134
|
-
[
|
|
131
|
+
[
|
|
132
|
+
setShowErrorNotifications,
|
|
133
|
+
patient,
|
|
134
|
+
emrConfiguration,
|
|
135
|
+
currentProvider,
|
|
136
|
+
location,
|
|
137
|
+
beds,
|
|
138
|
+
mutateAdmissionLocation,
|
|
139
|
+
mutateInpatientRequest,
|
|
140
|
+
mutateInpatientAdmission,
|
|
141
|
+
],
|
|
135
142
|
);
|
|
136
143
|
|
|
137
144
|
const onError = useCallback(() => {
|
|
138
145
|
setShowErrorNotifications(true);
|
|
139
146
|
}, []);
|
|
140
147
|
|
|
148
|
+
if (!wardGroupingDetails) return <></>;
|
|
141
149
|
return (
|
|
142
|
-
<Form
|
|
150
|
+
<Form
|
|
151
|
+
onSubmit={handleSubmit(onSubmit, onError)}
|
|
152
|
+
className={classNames(styles.formContainer, styles.workspaceContent)}>
|
|
143
153
|
<div>
|
|
144
154
|
{errorFetchingEmrConfiguration && (
|
|
145
155
|
<div className={styles.formError}>
|
package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-request-form.component.tsx
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
|
+
import { Button, ButtonSet, Form, InlineNotification, RadioButton, RadioButtonGroup, TextArea } from '@carbon/react';
|
|
2
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
3
|
+
import { ResponsiveWrapper, showSnackbar, useAppContext, useSession } from '@openmrs/esm-framework';
|
|
4
|
+
import classNames from 'classnames';
|
|
1
5
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import styles from './patient-transfer-swap.scss';
|
|
6
|
+
import { Controller, useForm } from 'react-hook-form';
|
|
4
7
|
import { useTranslation } from 'react-i18next';
|
|
5
|
-
import { useAdmissionLocation } from '../../hooks/useAdmissionLocation';
|
|
6
8
|
import { z } from 'zod';
|
|
7
|
-
import { Controller, useForm } from 'react-hook-form';
|
|
8
|
-
import { zodResolver } from '@hookform/resolvers/zod';
|
|
9
|
-
import LocationSelector from '../../location-selector/location-selector.component';
|
|
10
9
|
import useEmrConfiguration from '../../hooks/useEmrConfiguration';
|
|
11
|
-
import { createEncounter } from '../../ward.resource';
|
|
12
10
|
import useWardLocation from '../../hooks/useWardLocation';
|
|
13
|
-
import
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
11
|
+
import LocationSelector from '../../location-selector/location-selector.component';
|
|
12
|
+
import type { ObsPayload, WardPatientGroupDetails, WardPatientWorkspaceProps } from '../../types';
|
|
13
|
+
import { createEncounter } from '../../ward.resource';
|
|
14
|
+
import styles from './patient-transfer-swap.scss';
|
|
16
15
|
|
|
17
16
|
export default function PatientTransferForm({
|
|
18
17
|
closeWorkspaceWithSavedChanges,
|
|
@@ -30,8 +29,10 @@ export default function PatientTransferForm({
|
|
|
30
29
|
() => emrConfiguration?.dispositions.filter(({ type }) => type === 'TRANSFER'),
|
|
31
30
|
[emrConfiguration],
|
|
32
31
|
);
|
|
33
|
-
const
|
|
34
|
-
const { mutate:
|
|
32
|
+
const wardGroupingDetails = useAppContext<WardPatientGroupDetails>('ward-patients-group');
|
|
33
|
+
const { mutate: mutateAdmissionLocation } = wardGroupingDetails?.admissionLocationResponse ?? {};
|
|
34
|
+
const { mutate: mutateInpatientAdmission } = wardGroupingDetails?.inpatientAdmissionResponse ?? {};
|
|
35
|
+
const { mutate: mutateInpatientRequest } = wardGroupingDetails?.inpatientRequestResponse ?? {};
|
|
35
36
|
|
|
36
37
|
const zodSchema = useMemo(
|
|
37
38
|
() =>
|
|
@@ -64,7 +65,6 @@ export default function PatientTransferForm({
|
|
|
64
65
|
formState: { errors, isDirty },
|
|
65
66
|
control,
|
|
66
67
|
handleSubmit,
|
|
67
|
-
getValues,
|
|
68
68
|
setValue,
|
|
69
69
|
} = useForm<FormValues>({ resolver: zodResolver(zodSchema), defaultValues: formDefaultValues });
|
|
70
70
|
|
|
@@ -102,8 +102,8 @@ export default function PatientTransferForm({
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
createEncounter({
|
|
105
|
-
patient: patient
|
|
106
|
-
encounterType: emrConfiguration.
|
|
105
|
+
patient: patient?.uuid,
|
|
106
|
+
encounterType: emrConfiguration.transferRequestEncounterType.uuid,
|
|
107
107
|
location: location.uuid,
|
|
108
108
|
encounterProviders: [
|
|
109
109
|
{
|
|
@@ -123,9 +123,6 @@ export default function PatientTransferForm({
|
|
|
123
123
|
title: t('patientTransferRequestCreated', 'Patient transfer request created'),
|
|
124
124
|
kind: 'success',
|
|
125
125
|
});
|
|
126
|
-
closeWorkspaceWithSavedChanges();
|
|
127
|
-
mutateAdmissionLocation();
|
|
128
|
-
mutateInpatientRequest();
|
|
129
126
|
})
|
|
130
127
|
.catch((err: Error) => {
|
|
131
128
|
showSnackbar({
|
|
@@ -134,16 +131,23 @@ export default function PatientTransferForm({
|
|
|
134
131
|
kind: 'error',
|
|
135
132
|
});
|
|
136
133
|
})
|
|
137
|
-
.finally(() =>
|
|
134
|
+
.finally(() => {
|
|
135
|
+
setIsSubmitting(false);
|
|
136
|
+
closeWorkspaceWithSavedChanges();
|
|
137
|
+
mutateAdmissionLocation();
|
|
138
|
+
mutateInpatientAdmission();
|
|
139
|
+
mutateInpatientRequest();
|
|
140
|
+
});
|
|
138
141
|
},
|
|
139
142
|
[
|
|
140
143
|
setShowErrorNotifications,
|
|
141
144
|
currentProvider,
|
|
142
145
|
location,
|
|
143
146
|
emrConfiguration,
|
|
144
|
-
patient
|
|
147
|
+
patient?.uuid,
|
|
145
148
|
dispositionsWithTypeTransfer,
|
|
146
149
|
mutateAdmissionLocation,
|
|
150
|
+
mutateInpatientAdmission,
|
|
147
151
|
mutateInpatientRequest,
|
|
148
152
|
],
|
|
149
153
|
);
|
|
@@ -153,8 +157,11 @@ export default function PatientTransferForm({
|
|
|
153
157
|
setShowErrorNotifications(true);
|
|
154
158
|
}, []);
|
|
155
159
|
|
|
160
|
+
if (!wardGroupingDetails) return <></>;
|
|
156
161
|
return (
|
|
157
|
-
<Form
|
|
162
|
+
<Form
|
|
163
|
+
onSubmit={handleSubmit(onSubmit, onError)}
|
|
164
|
+
className={classNames(styles.formContainer, styles.workspaceContent)}>
|
|
158
165
|
<div>
|
|
159
166
|
{errorFetchingEmrConfiguration && (
|
|
160
167
|
<div className={styles.formError}>
|
|
@@ -229,7 +236,7 @@ export default function PatientTransferForm({
|
|
|
229
236
|
<Button
|
|
230
237
|
type="submit"
|
|
231
238
|
size="xl"
|
|
232
|
-
disabled={isLoadingEmrConfiguration || isSubmitting || errorFetchingEmrConfiguration}>
|
|
239
|
+
disabled={isLoadingEmrConfiguration || isSubmitting || errorFetchingEmrConfiguration || !patient}>
|
|
233
240
|
{t('save', 'Save')}
|
|
234
241
|
</Button>
|
|
235
242
|
</ButtonSet>
|
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
@use '@carbon/layout';
|
|
3
3
|
@use '@openmrs/esm-styleguide/src/vars' as *;
|
|
4
4
|
|
|
5
|
+
.flexWrapper {
|
|
6
|
+
height: 100%;
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
color: #393939;
|
|
10
|
+
}
|
|
11
|
+
|
|
5
12
|
.workspaceContent {
|
|
6
13
|
padding: layout.$spacing-05;
|
|
7
14
|
height: 100%;
|
|
@@ -10,8 +17,12 @@
|
|
|
10
17
|
color: #393939;
|
|
11
18
|
}
|
|
12
19
|
|
|
20
|
+
.contentSwitcherWrapper {
|
|
21
|
+
padding: 0 layout.$spacing-05;
|
|
22
|
+
}
|
|
23
|
+
|
|
13
24
|
.patientWorkspaceBanner {
|
|
14
|
-
margin:
|
|
25
|
+
margin-bottom: layout.$spacing-05;
|
|
15
26
|
}
|
|
16
27
|
|
|
17
28
|
.field {
|
|
@@ -26,7 +37,6 @@
|
|
|
26
37
|
}
|
|
27
38
|
|
|
28
39
|
.workspaceForm {
|
|
29
|
-
margin-top: layout.$spacing-05;
|
|
30
40
|
flex: 1;
|
|
31
41
|
}
|
|
32
42
|
|
|
@@ -21,12 +21,12 @@ export default function PatientTransferAndSwapWorkspace(props: WardPatientWorksp
|
|
|
21
21
|
const isBedManagementModuleInstalled = useFeatureFlag('bedmanagement-module');
|
|
22
22
|
|
|
23
23
|
return (
|
|
24
|
-
<div className={styles.
|
|
24
|
+
<div className={styles.flexWrapper}>
|
|
25
25
|
<div className={styles.patientWorkspaceBanner}>
|
|
26
26
|
<WardPatientWorkspaceBanner {...props?.wardPatient} />
|
|
27
27
|
</div>
|
|
28
28
|
{isBedManagementModuleInstalled && (
|
|
29
|
-
<div>
|
|
29
|
+
<div className={styles.contentSwitcherWrapper}>
|
|
30
30
|
<h2 className={styles.productiveHeading02}>{t('typeOfTransfer', 'Type of transfer')}</h2>
|
|
31
31
|
<div className={styles.contentSwitcher}>
|
|
32
32
|
<ContentSwitcher onChange={({ name }) => setSelectedSection(name)}>
|
package/src/ward-workspace/patient-transfer-request-workspace/patient-transfer-request.workspace.tsx
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PatientTransferForm from '../patient-transfer-bed-swap/patient-transfer-request-form.component';
|
|
3
|
+
import { type WardPatientWorkspaceProps } from '../../types';
|
|
4
|
+
|
|
5
|
+
interface PatientTransferRequestFormProps extends WardPatientWorkspaceProps {}
|
|
6
|
+
|
|
7
|
+
const PatientTransferRequestForm: React.FC<PatientTransferRequestFormProps> = (props) => {
|
|
8
|
+
return <PatientTransferForm {...props} />;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default PatientTransferRequestForm;
|
|
@@ -69,7 +69,7 @@ const PatientNotesForm: React.FC<PatientNotesFormProps> = ({
|
|
|
69
69
|
const notePayload = {
|
|
70
70
|
patient: patientUuid,
|
|
71
71
|
location: locationUuid,
|
|
72
|
-
encounterType: emrConfiguration?.
|
|
72
|
+
encounterType: emrConfiguration?.inpatientNoteEncounterType.uuid,
|
|
73
73
|
encounterProviders: [
|
|
74
74
|
{
|
|
75
75
|
encounterRole: emrConfiguration?.clinicianEncounterRole.uuid,
|
|
@@ -54,7 +54,7 @@ test('renders a success snackbar upon successfully recording a visit note', asyn
|
|
|
54
54
|
provider: undefined,
|
|
55
55
|
},
|
|
56
56
|
]),
|
|
57
|
-
encounterType: emrConfigurationMock.
|
|
57
|
+
encounterType: emrConfigurationMock.inpatientNoteEncounterType.uuid,
|
|
58
58
|
location: undefined,
|
|
59
59
|
obs: expect.arrayContaining([
|
|
60
60
|
{
|
|
@@ -14,12 +14,12 @@ interface PatientNotesHistoryProps {
|
|
|
14
14
|
|
|
15
15
|
const PatientNotesHistory: React.FC<PatientNotesHistoryProps> = ({ patientUuid, visitUuid }) => {
|
|
16
16
|
const { t } = useTranslation();
|
|
17
|
-
const { emrConfiguration, isLoadingEmrConfiguration
|
|
17
|
+
const { emrConfiguration, isLoadingEmrConfiguration } = useEmrConfiguration();
|
|
18
18
|
|
|
19
19
|
const { patientNotes, isLoadingPatientNotes, errorFetchingPatientNotes } = usePatientNotes(
|
|
20
20
|
patientUuid,
|
|
21
21
|
visitUuid,
|
|
22
|
-
emrConfiguration?.
|
|
22
|
+
emrConfiguration?.inpatientNoteEncounterType?.uuid,
|
|
23
23
|
emrConfiguration?.consultFreeTextCommentsConcept.uuid,
|
|
24
24
|
);
|
|
25
25
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import useSWR from 'swr';
|
|
3
|
-
import { type PatientNote, type UsePatientNotes, type VisitEncountersFetchResponse } from './types';
|
|
4
|
-
import { type EncounterPayload } from '../../types';
|
|
1
|
+
import { openmrsFetch, restBaseUrl, useOpenmrsFetchAll } from '@openmrs/esm-framework';
|
|
5
2
|
import { useMemo } from 'react';
|
|
3
|
+
import { type EncounterPayload } from '../../types';
|
|
4
|
+
import { type PatientNote, type RESTPatientNote, type UsePatientNotes } from './types';
|
|
6
5
|
|
|
7
6
|
export function savePatientNote(payload: EncounterPayload, abortController: AbortController = new AbortController()) {
|
|
8
7
|
return openmrsFetch(`${restBaseUrl}/encounter`, {
|
|
@@ -29,15 +28,14 @@ export function usePatientNotes(
|
|
|
29
28
|
'diagnoses';
|
|
30
29
|
const encountersApiUrl = `${restBaseUrl}/encounter?patient=${patientUuid}&encounterType=${encounterType}&visit=${visitUuid}&v=${customRepresentation}`;
|
|
31
30
|
|
|
32
|
-
const { data, error, isLoading, isValidating, mutate } =
|
|
31
|
+
const { data, error, isLoading, isValidating, mutate } = useOpenmrsFetchAll<RESTPatientNote>(
|
|
33
32
|
patientUuid && encounterType ? encountersApiUrl : null,
|
|
34
|
-
openmrsFetch,
|
|
35
33
|
);
|
|
36
34
|
|
|
37
35
|
const patientNotes: Array<PatientNote> | null = useMemo(
|
|
38
36
|
() =>
|
|
39
37
|
data
|
|
40
|
-
? data
|
|
38
|
+
? data
|
|
41
39
|
.map((encounter) => {
|
|
42
40
|
const noteObs = encounter.obs.find((obs) => obs.concept.uuid === conceptUuid);
|
|
43
41
|
|
|
@@ -17,7 +17,7 @@ const WardPatientNotesWorkspace: React.FC<WardPatientWorkspaceProps> = (props) =
|
|
|
17
17
|
<div>
|
|
18
18
|
<WardPatientWorkspaceBanner {...wardPatient} />
|
|
19
19
|
<PatientNotesForm {...notesFormState} />
|
|
20
|
-
<PatientNotesHistory patientUuid={patientUuid} visitUuid={wardPatient?.visit
|
|
20
|
+
<PatientNotesHistory patientUuid={patientUuid} visitUuid={wardPatient?.visit?.uuid} />
|
|
21
21
|
</div>
|
|
22
22
|
);
|
|
23
23
|
};
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { type Concept, type OpenmrsResource } from '@openmrs/esm-framework';
|
|
2
2
|
|
|
3
|
-
export interface VisitEncountersFetchResponse {
|
|
4
|
-
results: Array<RESTPatientNote>;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
3
|
export interface RESTPatientNote extends OpenmrsResource {
|
|
8
4
|
uuid: string;
|
|
9
5
|
display: string;
|
package/src/ward.resource.ts
CHANGED
|
@@ -23,3 +23,9 @@ export function assignPatientToBed(bedUuid: number, patientUuid: string, encount
|
|
|
23
23
|
},
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
|
+
|
|
27
|
+
export function removePatientFromBed(bedId: number, patientUuid: string) {
|
|
28
|
+
return openmrsFetch(`${restBaseUrl}/beds/${bedId}?patientUuid=${patientUuid}`, {
|
|
29
|
+
method: 'DELETE',
|
|
30
|
+
});
|
|
31
|
+
}
|