@kenyaemr/esm-ward-app 8.0.1-pre.99 → 8.0.3-pre.131
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 +20 -24
- package/dist/109.js +1 -0
- package/dist/109.js.map +1 -0
- package/dist/124.js +1 -0
- package/dist/124.js.map +1 -0
- package/dist/125.js +1 -0
- package/dist/125.js.map +1 -0
- package/dist/130.js +1 -1
- package/dist/130.js.LICENSE.txt +2 -0
- 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/153.js +1 -0
- package/dist/153.js.map +1 -0
- package/dist/303.js +2 -1
- package/dist/303.js.map +1 -1
- package/dist/325.js +1 -0
- package/dist/325.js.map +1 -0
- package/dist/372.js +2 -0
- package/dist/372.js.map +1 -0
- package/dist/471.js +1 -0
- package/dist/471.js.map +1 -0
- package/dist/481.js +1 -0
- package/dist/481.js.map +1 -0
- package/dist/53.js +1 -0
- package/dist/53.js.map +1 -0
- package/dist/{960.js → 559.js} +1 -1
- package/dist/559.js.map +1 -0
- package/dist/574.js +1 -1
- package/dist/576.js +1 -0
- package/dist/576.js.map +1 -0
- package/dist/577.js +1 -1
- package/dist/577.js.map +1 -1
- package/dist/{255.js → 649.js} +2 -2
- package/dist/649.js.LICENSE.txt +9 -0
- package/dist/649.js.map +1 -0
- package/dist/{659.js → 662.js} +1 -1
- package/dist/662.js.map +1 -0
- package/dist/920.js +1 -0
- package/dist/920.js.map +1 -0
- package/dist/921.js +1 -0
- package/dist/921.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 +304 -128
- package/dist/kenyaemr-esm-ward-app.js.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.LICENSE.txt +0 -10
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/mock.tsx +62 -0
- package/package-lock.json +5001 -0
- package/package.json +2 -2
- 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 +4 -3
- package/src/beds/empty-bed.component.tsx +3 -3
- package/src/beds/ward-bed.component.tsx +41 -0
- package/src/beds/ward-bed.scss +45 -0
- package/src/beds/{occupied-bed.test.tsx → ward-bed.test.tsx} +42 -20
- package/src/config-schema.ts +203 -84
- package/src/constant.ts +1 -1
- package/src/hooks/useAdmissionLocation.ts +22 -4
- package/src/hooks/useAssignedBedByPatient.ts +9 -0
- 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 +3 -7
- package/src/hooks/usePatientPendingOrders.ts +16 -0
- package/src/hooks/useWardPatientGrouping.ts +32 -0
- package/src/index.ts +45 -17
- package/src/location-selector/location-selector.component.tsx +18 -21
- package/src/root.component.tsx +3 -0
- package/src/routes.json +41 -3
- package/src/types/index.ts +50 -1
- package/src/ward-patient-card/card-rows/admission-request-note-row.component.tsx +38 -0
- package/src/ward-patient-card/card-rows/coded-obs-tags-row.component.tsx +108 -0
- package/src/ward-patient-card/card-rows/mother-child-row.component.tsx +84 -0
- package/src/ward-patient-card/card-rows/mother-child-row.scss +22 -0
- package/src/ward-patient-card/card-rows/pending-items-row.component.tsx +54 -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 +62 -39
- package/src/ward-patient-card/row-elements/ward-patient-header-address.tsx +5 -5
- package/src/ward-patient-card/row-elements/ward-patient-identifier.tsx +18 -41
- 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 +38 -34
- package/src/ward-patient-card/row-elements/ward-patient-obs.tsx +26 -13
- 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/row-elements/ward-patient-skeleton-text.tsx +9 -0
- package/src/ward-patient-card/ward-patient-card.component.tsx +14 -45
- package/src/ward-patient-card/ward-patient-card.scss +68 -9
- package/src/ward-view/default-ward/default-ward-beds.component.tsx +42 -0
- package/src/ward-view/default-ward/default-ward-patient-card-header.component.tsx +32 -0
- package/src/ward-view/default-ward/default-ward-patient-card.component.tsx +31 -0
- package/src/ward-view/default-ward/default-ward-pending-patients.component.tsx +52 -0
- package/src/ward-view/default-ward/default-ward-unassigned-patients.component.tsx +32 -0
- package/src/ward-view/default-ward/default-ward-view.component.tsx +31 -0
- package/src/ward-view/materal-ward/maternal-ward-beds.component.tsx +65 -0
- package/src/ward-view/materal-ward/maternal-ward-patient-card-header.component.tsx +30 -0
- package/src/ward-view/materal-ward/maternal-ward-patient-card.component.tsx +93 -0
- package/src/{beds/occupied-bed.scss → ward-view/materal-ward/maternal-ward-patient-card.scss} +4 -9
- package/src/ward-view/materal-ward/maternal-ward-patient-card.test.tsx +58 -0
- package/src/ward-view/materal-ward/maternal-ward-pending-patients.component.tsx +48 -0
- package/src/ward-view/materal-ward/maternal-ward-unassigned-patients.component.tsx +33 -0
- package/src/ward-view/materal-ward/maternal-ward-view.component.tsx +38 -0
- package/src/ward-view/materal-ward/maternal-ward-view.resource.ts +89 -0
- package/src/ward-view/ward-view.component.tsx +15 -163
- package/src/ward-view/ward-view.resource.ts +193 -1
- package/src/ward-view/ward-view.scss +17 -6
- package/src/ward-view/ward-view.test.tsx +43 -48
- package/src/ward-view/ward.component.tsx +106 -0
- package/src/ward-view-header/admission-requests-bar.component.tsx +14 -9
- package/src/ward-view-header/admission-requests-bar.test.tsx +11 -23
- 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 +78 -0
- package/src/ward-view-header/ward-metrics.scss +7 -0
- package/src/ward-view-header/ward-metrics.test.tsx +37 -0
- package/src/ward-view-header/ward-view-header.component.tsx +9 -4
- package/src/ward-view-header/ward-view-header.scss +0 -1
- package/src/ward-workspace/admission-request-card/admission-request-card-actions.component.tsx +70 -6
- package/src/ward-workspace/admission-request-card/admission-request-card-header.component.tsx +10 -23
- package/src/ward-workspace/admission-request-card/admission-request-card.component.tsx +9 -3
- package/src/ward-workspace/admission-request-card/admission-request-card.scss +13 -4
- package/src/ward-workspace/admission-request-workspace/admission-requests-workspace.test.tsx +55 -33
- package/src/ward-workspace/admission-request-workspace/admission-requests.workspace.tsx +30 -37
- package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.test.tsx +98 -203
- package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.workspace.tsx +116 -180
- package/src/ward-workspace/bed-selector.component.tsx +119 -0
- package/src/ward-workspace/bed-selector.scss +15 -0
- package/src/ward-workspace/patient-banner/patient-banner.component.tsx +7 -14
- 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 +18 -9
- package/src/ward-workspace/patient-discharge/patient-discharge.scss +41 -0
- package/src/ward-workspace/patient-discharge/patient-discharge.workspace.tsx +113 -0
- package/src/ward-workspace/patient-transfer-bed-swap/patient-bed-swap-form.component.tsx +68 -79
- package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-request-form.component.tsx +24 -24
- 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 +12 -8
- 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 +38 -2
- package/translations/en.json +31 -7
- package/dist/152.js +0 -1
- package/dist/152.js.map +0 -1
- package/dist/255.js.map +0 -1
- package/dist/269.js +0 -1
- package/dist/269.js.map +0 -1
- package/dist/346.js +0 -1
- package/dist/346.js.map +0 -1
- package/dist/466.js +0 -1
- package/dist/466.js.map +0 -1
- package/dist/659.js.map +0 -1
- package/dist/729.js +0 -1
- package/dist/729.js.map +0 -1
- package/dist/749.js +0 -1
- package/dist/749.js.map +0 -1
- package/dist/76.js +0 -1
- package/dist/76.js.map +0 -1
- package/dist/793.js +0 -2
- package/dist/793.js.map +0 -1
- package/dist/803.js +0 -1
- package/dist/803.js.map +0 -1
- package/dist/960.js.map +0 -1
- package/src/beds/empty-bed.scss +0 -28
- package/src/beds/occupied-bed.component.tsx +0 -35
- package/src/beds/unassigned-patient.component.tsx +0 -20
- package/src/beds/unassigned-patient.scss +0 -6
- package/src/config-schema-admission-request-note.ts +0 -9
- package/src/config-schema-extension-colored-obs-tags.ts +0 -91
- package/src/hooks/useCurrentWardCardConfig.ts +0 -32
- package/src/ward-patient-card/card-rows/admission-request-note.extension.tsx +0 -27
- package/src/ward-patient-card/card-rows/colored-obs-tags-card-row.extension.tsx +0 -13
- package/src/ward-patient-card/ward-patient-card-element.component.tsx +0 -65
- package/src/ward-view/ward-bed.component.tsx +0 -14
- /package/dist/{793.js.LICENSE.txt → 303.js.LICENSE.txt} +0 -0
- /package/dist/{255.js.LICENSE.txt → 372.js.LICENSE.txt} +0 -0
- /package/src/{ward-patient-workspace → ward-workspace/patient-details}/ward-patient.style.scss +0 -0
|
@@ -0,0 +1,113 @@
|
|
|
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 WardPatientWorkspaceProps, type WardViewContext } 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 { wardPatientGroupDetails } = useAppContext<WardViewContext>('ward-view-context') ?? {};
|
|
21
|
+
|
|
22
|
+
const submitDischarge = useCallback(() => {
|
|
23
|
+
setIsSubmitting(true);
|
|
24
|
+
|
|
25
|
+
createEncounter({
|
|
26
|
+
patient: wardPatient?.patient?.uuid,
|
|
27
|
+
encounterType: emrConfiguration.exitFromInpatientEncounterType.uuid,
|
|
28
|
+
location: location.uuid,
|
|
29
|
+
encounterProviders: [
|
|
30
|
+
{
|
|
31
|
+
encounterRole: emrConfiguration.clinicianEncounterRole.uuid,
|
|
32
|
+
provider: currentProvider?.uuid,
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
obs: [],
|
|
36
|
+
})
|
|
37
|
+
.then((response) => {
|
|
38
|
+
if (response?.ok) {
|
|
39
|
+
if (wardPatient?.bed?.id) {
|
|
40
|
+
return removePatientFromBed(wardPatient.bed.id, wardPatient?.patient?.uuid);
|
|
41
|
+
}
|
|
42
|
+
return response;
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
.then((response) => {
|
|
46
|
+
if (response?.ok) {
|
|
47
|
+
showSnackbar({
|
|
48
|
+
title: t('patientWasDischarged', 'Patient was discharged'),
|
|
49
|
+
kind: 'success',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
.catch((err: Error) => {
|
|
54
|
+
showSnackbar({
|
|
55
|
+
title: t('errorDischargingPatient', 'Error discharging patient'),
|
|
56
|
+
subtitle: err.message,
|
|
57
|
+
kind: 'error',
|
|
58
|
+
});
|
|
59
|
+
})
|
|
60
|
+
.finally(() => {
|
|
61
|
+
setIsSubmitting(false);
|
|
62
|
+
closeWorkspaceWithSavedChanges();
|
|
63
|
+
wardPatientGroupDetails.mutate();
|
|
64
|
+
});
|
|
65
|
+
}, [
|
|
66
|
+
currentProvider,
|
|
67
|
+
location,
|
|
68
|
+
emrConfiguration,
|
|
69
|
+
wardPatient?.patient?.uuid,
|
|
70
|
+
wardPatient?.bed?.uuid,
|
|
71
|
+
wardPatientGroupDetails,
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
if (!wardPatientGroupDetails) return <></>;
|
|
75
|
+
return (
|
|
76
|
+
<div className={styles.workspaceContent}>
|
|
77
|
+
<div className={styles.patientWorkspaceBanner}>
|
|
78
|
+
<WardPatientWorkspaceBanner {...props?.wardPatient} />
|
|
79
|
+
</div>
|
|
80
|
+
<div className={styles.workspaceForm}>
|
|
81
|
+
<div>
|
|
82
|
+
{errorFetchingEmrConfiguration && (
|
|
83
|
+
<div className={styles.formError}>
|
|
84
|
+
<InlineNotification
|
|
85
|
+
kind="error"
|
|
86
|
+
title={t('somePartsOfTheFormDidntLoad', "Some parts of the form didn't load")}
|
|
87
|
+
subtitle={t(
|
|
88
|
+
'fetchingEmrConfigurationFailed',
|
|
89
|
+
'Fetching EMR configuration failed. Try refreshing the page or contact your system administrator.',
|
|
90
|
+
)}
|
|
91
|
+
lowContrast
|
|
92
|
+
hideCloseButton
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
)}
|
|
96
|
+
</div>
|
|
97
|
+
<ExtensionSlot name="ward-patient-discharge-slot" />
|
|
98
|
+
<ButtonSet className={styles.buttonSet}>
|
|
99
|
+
<Button
|
|
100
|
+
size="sm"
|
|
101
|
+
kind="ghost"
|
|
102
|
+
renderIcon={(props) => <Exit size={16} {...props} />}
|
|
103
|
+
disabled={
|
|
104
|
+
isLoadingEmrConfiguration || isSubmitting || errorFetchingEmrConfiguration || !wardPatient?.patient
|
|
105
|
+
}
|
|
106
|
+
onClick={submitDischarge}>
|
|
107
|
+
{t('proceedWithPatientDischarge', 'Proceed with patient discharge')}
|
|
108
|
+
</Button>
|
|
109
|
+
</ButtonSet>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
@@ -1,26 +1,17 @@
|
|
|
1
|
+
import { Button, ButtonSet, Form, InlineNotification } from '@carbon/react';
|
|
2
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
3
|
+
import { showSnackbar, useAppContext, useSession } from '@openmrs/esm-framework';
|
|
4
|
+
import classNames from 'classnames';
|
|
1
5
|
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
6
|
import { Controller, useForm } from 'react-hook-form';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import type { BedLayout, WardPatientWorkspaceProps } from '../../types';
|
|
10
|
-
import { assignPatientToBed, createEncounter } from '../../ward.resource';
|
|
7
|
+
import { useTranslation } from 'react-i18next';
|
|
8
|
+
import { z } from 'zod';
|
|
11
9
|
import useEmrConfiguration from '../../hooks/useEmrConfiguration';
|
|
12
|
-
import { showSnackbar, useSession } from '@openmrs/esm-framework';
|
|
13
10
|
import useWardLocation from '../../hooks/useWardLocation';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Button,
|
|
19
|
-
RadioButtonGroup,
|
|
20
|
-
RadioButton,
|
|
21
|
-
RadioButtonSkeleton,
|
|
22
|
-
InlineNotification,
|
|
23
|
-
} from '@carbon/react';
|
|
11
|
+
import type { BedLayout, WardPatientWorkspaceProps, WardViewContext } from '../../types';
|
|
12
|
+
import { assignPatientToBed, createEncounter, removePatientFromBed } from '../../ward.resource';
|
|
13
|
+
import BedSelector from '../bed-selector.component';
|
|
14
|
+
import styles from './patient-transfer-swap.scss';
|
|
24
15
|
|
|
25
16
|
export default function PatientBedSwapForm({
|
|
26
17
|
promptBeforeClosing,
|
|
@@ -30,13 +21,12 @@ export default function PatientBedSwapForm({
|
|
|
30
21
|
const { patient } = wardPatient;
|
|
31
22
|
const { t } = useTranslation();
|
|
32
23
|
const [showErrorNotifications, setShowErrorNotifications] = useState(false);
|
|
33
|
-
const { isLoading, admissionLocation } = useAdmissionLocation();
|
|
34
24
|
const { emrConfiguration, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } = useEmrConfiguration();
|
|
35
25
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
36
26
|
const { currentProvider } = useSession();
|
|
37
27
|
const { location } = useWardLocation();
|
|
38
|
-
const {
|
|
39
|
-
const {
|
|
28
|
+
const { wardPatientGroupDetails } = useAppContext<WardViewContext>('ward-view-context') ?? {};
|
|
29
|
+
const { isLoading } = wardPatientGroupDetails?.admissionLocationResponse ?? {};
|
|
40
30
|
|
|
41
31
|
const zodSchema = useMemo(
|
|
42
32
|
() =>
|
|
@@ -71,15 +61,7 @@ export default function PatientBedSwapForm({
|
|
|
71
61
|
[t],
|
|
72
62
|
);
|
|
73
63
|
|
|
74
|
-
const beds =
|
|
75
|
-
const bedDetails = useMemo(
|
|
76
|
-
() =>
|
|
77
|
-
beds.map((bed) => {
|
|
78
|
-
const isPatientAssignedToBed = bed.patients.find((bedPatient) => bedPatient.uuid === patient.uuid);
|
|
79
|
-
return { id: bed.bedId, label: getBedInformation(bed), isPatientAssignedToBed };
|
|
80
|
-
}),
|
|
81
|
-
[beds, getBedInformation],
|
|
82
|
-
);
|
|
64
|
+
const beds = wardPatientGroupDetails?.bedLayouts ?? [];
|
|
83
65
|
|
|
84
66
|
const onSubmit = useCallback(
|
|
85
67
|
(values: FormValues) => {
|
|
@@ -99,47 +81,69 @@ export default function PatientBedSwapForm({
|
|
|
99
81
|
})
|
|
100
82
|
.then(async (response) => {
|
|
101
83
|
if (response.ok) {
|
|
102
|
-
|
|
84
|
+
if (bedSelected) {
|
|
85
|
+
return assignPatientToBed(values.bedId, patient.uuid, response.data.uuid);
|
|
86
|
+
} else {
|
|
87
|
+
// get the bed that the patient is currently assigned to
|
|
88
|
+
const bedAssignedToPatient = beds.find((bed) =>
|
|
89
|
+
bed.patients.some((bedPatient) => bedPatient.uuid == patient.uuid),
|
|
90
|
+
);
|
|
91
|
+
if (bedAssignedToPatient) {
|
|
92
|
+
return removePatientFromBed(bedAssignedToPatient.bedId, patient.uuid);
|
|
93
|
+
} else {
|
|
94
|
+
// no-op
|
|
95
|
+
return Promise.resolve({ ok: true });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
103
98
|
}
|
|
104
99
|
})
|
|
105
100
|
.then((response) => {
|
|
106
101
|
if (response && response?.ok) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
102
|
+
if (bedSelected) {
|
|
103
|
+
showSnackbar({
|
|
104
|
+
kind: 'success',
|
|
105
|
+
title: t('patientAssignedNewBed', 'Patient assigned to new bed'),
|
|
106
|
+
subtitle: t('patientAssignedNewBedDetail', '{{patientName}} assigned to bed {{bedNumber}}', {
|
|
107
|
+
patientName: patient.person.preferredName.display,
|
|
108
|
+
bedNumber: bedSelected.bedNumber,
|
|
109
|
+
}),
|
|
110
|
+
});
|
|
111
|
+
} else {
|
|
112
|
+
showSnackbar({
|
|
113
|
+
kind: 'success',
|
|
114
|
+
title: t('patientUnassignedFromBed', 'Patient unassigned from bed'),
|
|
115
|
+
subtitle: t('patientUnassignedFromBedDetail', '{{patientName}} is now unassigned from bed', {
|
|
116
|
+
patientName: patient.person.preferredName.display,
|
|
117
|
+
}),
|
|
118
|
+
});
|
|
119
|
+
}
|
|
118
120
|
}
|
|
119
121
|
})
|
|
120
122
|
.catch((error: Error) => {
|
|
121
123
|
showSnackbar({
|
|
122
124
|
kind: 'error',
|
|
123
|
-
title: t('
|
|
125
|
+
title: t('errorChangingPatientBedAssignment', 'Error changing patient bed assignment'),
|
|
124
126
|
subtitle: error?.message,
|
|
125
127
|
});
|
|
126
|
-
mutateAdmissionLocation();
|
|
127
|
-
mutateInpatientRequest();
|
|
128
|
-
closeWorkspaceWithSavedChanges();
|
|
129
128
|
})
|
|
130
129
|
.finally(() => {
|
|
131
130
|
setIsSubmitting(false);
|
|
131
|
+
wardPatientGroupDetails.mutate();
|
|
132
|
+
closeWorkspaceWithSavedChanges();
|
|
132
133
|
});
|
|
133
134
|
},
|
|
134
|
-
[setShowErrorNotifications, patient, emrConfiguration, currentProvider, location, beds],
|
|
135
|
+
[setShowErrorNotifications, patient, emrConfiguration, currentProvider, location, beds, wardPatientGroupDetails],
|
|
135
136
|
);
|
|
136
137
|
|
|
137
138
|
const onError = useCallback(() => {
|
|
138
139
|
setShowErrorNotifications(true);
|
|
139
140
|
}, []);
|
|
140
141
|
|
|
142
|
+
if (!wardPatientGroupDetails) return <></>;
|
|
141
143
|
return (
|
|
142
|
-
<Form
|
|
144
|
+
<Form
|
|
145
|
+
onSubmit={handleSubmit(onSubmit, onError)}
|
|
146
|
+
className={classNames(styles.formContainer, styles.workspaceContent)}>
|
|
143
147
|
<div>
|
|
144
148
|
{errorFetchingEmrConfiguration && (
|
|
145
149
|
<div className={styles.formError}>
|
|
@@ -156,36 +160,21 @@ export default function PatientBedSwapForm({
|
|
|
156
160
|
</div>
|
|
157
161
|
)}
|
|
158
162
|
<h2 className={styles.productiveHeading02}>{t('selectABed', 'Select a bed')}</h2>
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
<
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
invalidText={errors?.bedId?.message}>
|
|
175
|
-
{bedDetails.map(({ id, label, isPatientAssignedToBed }) => (
|
|
176
|
-
<RadioButton
|
|
177
|
-
key={id}
|
|
178
|
-
labelText={label}
|
|
179
|
-
control={control}
|
|
180
|
-
value={id}
|
|
181
|
-
checked={id === value}
|
|
182
|
-
disabled={isPatientAssignedToBed}
|
|
183
|
-
/>
|
|
184
|
-
))}
|
|
185
|
-
</RadioButtonGroup>
|
|
186
|
-
)}
|
|
187
|
-
/>
|
|
188
|
-
)}
|
|
163
|
+
<Controller
|
|
164
|
+
name="bedId"
|
|
165
|
+
control={control}
|
|
166
|
+
render={({ field: { onChange, value }, fieldState: { error } }) => (
|
|
167
|
+
<BedSelector
|
|
168
|
+
beds={beds}
|
|
169
|
+
isLoadingBeds={isLoading}
|
|
170
|
+
currentPatient={patient}
|
|
171
|
+
selectedBedId={value}
|
|
172
|
+
error={error}
|
|
173
|
+
control={control}
|
|
174
|
+
onChange={onChange}
|
|
175
|
+
/>
|
|
176
|
+
)}
|
|
177
|
+
/>
|
|
189
178
|
{showErrorNotifications && (
|
|
190
179
|
<div className={styles.notifications}>
|
|
191
180
|
{Object.values(errors).map((error) => (
|
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, WardPatientWorkspaceProps, WardViewContext } 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,7 @@ export default function PatientTransferForm({
|
|
|
30
29
|
() => emrConfiguration?.dispositions.filter(({ type }) => type === 'TRANSFER'),
|
|
31
30
|
[emrConfiguration],
|
|
32
31
|
);
|
|
33
|
-
const {
|
|
34
|
-
const { mutate: mutateInpatientRequest } = useInpatientRequest();
|
|
32
|
+
const { wardPatientGroupDetails } = useAppContext<WardViewContext>('ward-view-context') ?? {};
|
|
35
33
|
|
|
36
34
|
const zodSchema = useMemo(
|
|
37
35
|
() =>
|
|
@@ -64,7 +62,6 @@ export default function PatientTransferForm({
|
|
|
64
62
|
formState: { errors, isDirty },
|
|
65
63
|
control,
|
|
66
64
|
handleSubmit,
|
|
67
|
-
getValues,
|
|
68
65
|
setValue,
|
|
69
66
|
} = useForm<FormValues>({ resolver: zodResolver(zodSchema), defaultValues: formDefaultValues });
|
|
70
67
|
|
|
@@ -102,8 +99,8 @@ export default function PatientTransferForm({
|
|
|
102
99
|
}
|
|
103
100
|
|
|
104
101
|
createEncounter({
|
|
105
|
-
patient: patient
|
|
106
|
-
encounterType: emrConfiguration.
|
|
102
|
+
patient: patient?.uuid,
|
|
103
|
+
encounterType: emrConfiguration.transferRequestEncounterType.uuid,
|
|
107
104
|
location: location.uuid,
|
|
108
105
|
encounterProviders: [
|
|
109
106
|
{
|
|
@@ -123,9 +120,6 @@ export default function PatientTransferForm({
|
|
|
123
120
|
title: t('patientTransferRequestCreated', 'Patient transfer request created'),
|
|
124
121
|
kind: 'success',
|
|
125
122
|
});
|
|
126
|
-
closeWorkspaceWithSavedChanges();
|
|
127
|
-
mutateAdmissionLocation();
|
|
128
|
-
mutateInpatientRequest();
|
|
129
123
|
})
|
|
130
124
|
.catch((err: Error) => {
|
|
131
125
|
showSnackbar({
|
|
@@ -134,17 +128,20 @@ export default function PatientTransferForm({
|
|
|
134
128
|
kind: 'error',
|
|
135
129
|
});
|
|
136
130
|
})
|
|
137
|
-
.finally(() =>
|
|
131
|
+
.finally(() => {
|
|
132
|
+
setIsSubmitting(false);
|
|
133
|
+
closeWorkspaceWithSavedChanges();
|
|
134
|
+
wardPatientGroupDetails.mutate();
|
|
135
|
+
});
|
|
138
136
|
},
|
|
139
137
|
[
|
|
140
138
|
setShowErrorNotifications,
|
|
141
139
|
currentProvider,
|
|
142
140
|
location,
|
|
143
141
|
emrConfiguration,
|
|
144
|
-
patient
|
|
142
|
+
patient?.uuid,
|
|
145
143
|
dispositionsWithTypeTransfer,
|
|
146
|
-
|
|
147
|
-
mutateInpatientRequest,
|
|
144
|
+
wardPatientGroupDetails,
|
|
148
145
|
],
|
|
149
146
|
);
|
|
150
147
|
|
|
@@ -153,8 +150,11 @@ export default function PatientTransferForm({
|
|
|
153
150
|
setShowErrorNotifications(true);
|
|
154
151
|
}, []);
|
|
155
152
|
|
|
153
|
+
if (!wardPatientGroupDetails) return <></>;
|
|
156
154
|
return (
|
|
157
|
-
<Form
|
|
155
|
+
<Form
|
|
156
|
+
onSubmit={handleSubmit(onSubmit, onError)}
|
|
157
|
+
className={classNames(styles.formContainer, styles.workspaceContent)}>
|
|
158
158
|
<div>
|
|
159
159
|
{errorFetchingEmrConfiguration && (
|
|
160
160
|
<div className={styles.formError}>
|
|
@@ -229,7 +229,7 @@ export default function PatientTransferForm({
|
|
|
229
229
|
<Button
|
|
230
230
|
type="submit"
|
|
231
231
|
size="xl"
|
|
232
|
-
disabled={isLoadingEmrConfiguration || isSubmitting || errorFetchingEmrConfiguration}>
|
|
232
|
+
disabled={isLoadingEmrConfiguration || isSubmitting || errorFetchingEmrConfiguration || !patient}>
|
|
233
233
|
{t('save', 'Save')}
|
|
234
234
|
</Button>
|
|
235
235
|
</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
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import { useFeatureFlag } from '@openmrs/esm-framework';
|
|
3
1
|
import { ContentSwitcher, Switch } from '@carbon/react';
|
|
2
|
+
import { useFeatureFlag } from '@openmrs/esm-framework';
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
|
-
import
|
|
5
|
+
import type { WardPatientWorkspaceProps } from '../../types';
|
|
6
|
+
import WardPatientWorkspaceBanner from '../patient-banner/patient-banner.component';
|
|
6
7
|
import PatientBedSwapForm from './patient-bed-swap-form.component';
|
|
8
|
+
import PatientTransferForm from './patient-transfer-request-form.component';
|
|
7
9
|
import styles from './patient-transfer-swap.scss';
|
|
8
|
-
import WardPatientWorkspaceBanner from '../patient-banner/patient-banner.component';
|
|
9
|
-
import type { WardPatientWorkspaceProps } from '../../types';
|
|
10
10
|
|
|
11
11
|
const TransferSection = {
|
|
12
12
|
TRANSFER: 'transfer',
|
|
@@ -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)}>
|
|
@@ -37,7 +37,11 @@ export default function PatientTransferAndSwapWorkspace(props: WardPatientWorksp
|
|
|
37
37
|
</div>
|
|
38
38
|
)}
|
|
39
39
|
<div className={styles.workspaceForm}>
|
|
40
|
-
{selectedSection ===
|
|
40
|
+
{selectedSection === TransferSection.TRANSFER ? (
|
|
41
|
+
<PatientTransferForm {...props} />
|
|
42
|
+
) : (
|
|
43
|
+
<PatientBedSwapForm {...props} />
|
|
44
|
+
)}
|
|
41
45
|
</div>
|
|
42
46
|
</div>
|
|
43
47
|
);
|
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;
|