@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.
Files changed (143) hide show
  1. package/.turbo/turbo-build.log +18 -17
  2. package/dist/109.js +1 -0
  3. package/dist/109.js.map +1 -0
  4. package/dist/125.js +1 -0
  5. package/dist/125.js.map +1 -0
  6. package/dist/126.js +1 -0
  7. package/dist/126.js.map +1 -0
  8. package/dist/130.js +1 -1
  9. package/dist/130.js.map +1 -1
  10. package/dist/146.js +1 -0
  11. package/dist/146.js.map +1 -0
  12. package/dist/15.js +1 -0
  13. package/dist/15.js.map +1 -0
  14. package/dist/161.js +2 -0
  15. package/dist/161.js.map +1 -0
  16. package/dist/269.js +1 -1
  17. package/dist/269.js.map +1 -1
  18. package/dist/466.js +1 -1
  19. package/dist/466.js.map +1 -1
  20. package/dist/500.js +1 -0
  21. package/dist/500.js.map +1 -0
  22. package/dist/53.js +1 -0
  23. package/dist/53.js.map +1 -0
  24. package/dist/557.js +1 -0
  25. package/dist/557.js.map +1 -0
  26. package/dist/559.js +1 -0
  27. package/dist/559.js.map +1 -0
  28. package/dist/574.js +1 -1
  29. package/dist/577.js +1 -1
  30. package/dist/577.js.map +1 -1
  31. package/dist/659.js +1 -1
  32. package/dist/659.js.map +1 -1
  33. package/dist/701.js +1 -0
  34. package/dist/701.js.map +1 -0
  35. package/dist/749.js +1 -1
  36. package/dist/749.js.map +1 -1
  37. package/dist/908.js +1 -0
  38. package/dist/908.js.map +1 -0
  39. package/dist/922.js +1 -0
  40. package/dist/922.js.map +1 -0
  41. package/dist/969.js +1 -0
  42. package/dist/969.js.map +1 -0
  43. package/dist/kenyaemr-esm-ward-app.js +1 -1
  44. package/dist/kenyaemr-esm-ward-app.js.buildmanifest.json +294 -74
  45. package/dist/kenyaemr-esm-ward-app.js.map +1 -1
  46. package/dist/main.js +1 -1
  47. package/dist/main.js.map +1 -1
  48. package/dist/routes.json +1 -1
  49. package/mock.tsx +54 -0
  50. package/package.json +1 -1
  51. package/src/action-menu-buttons/clinical-forms-workspace-siderail.component.tsx +37 -0
  52. package/src/action-menu-buttons/discharge-workspace-siderail.component.tsx +20 -0
  53. package/src/beds/empty-bed-skeleton.tsx +2 -1
  54. package/src/beds/empty-bed.scss +0 -4
  55. package/src/beds/occupied-bed.scss +1 -0
  56. package/src/config-schema-mother-child-row.ts +26 -0
  57. package/src/config-schema-pending-items-extension.ts +29 -0
  58. package/src/config-schema.ts +12 -14
  59. package/src/hooks/useAdmissionLocation.ts +22 -4
  60. package/src/hooks/useBeds.ts +3 -4
  61. package/src/hooks/useConcept.ts +3 -4
  62. package/src/hooks/useEmrConfiguration.ts +5 -0
  63. package/src/hooks/useInpatientAdmission.ts +9 -14
  64. package/src/hooks/useInpatientRequest.ts +4 -15
  65. package/src/hooks/useLocations.ts +8 -51
  66. package/src/hooks/useMotherAndChildren.ts +46 -0
  67. package/src/hooks/useObs.ts +2 -6
  68. package/src/hooks/usePatientPendingOrders.ts +16 -0
  69. package/src/hooks/useWardPatientGrouping.ts +25 -0
  70. package/src/index.ts +50 -3
  71. package/src/location-selector/location-selector.component.tsx +18 -21
  72. package/src/routes.json +43 -0
  73. package/src/types/index.ts +34 -0
  74. package/src/ward-patient-card/card-rows/admission-request-note.extension.tsx +7 -2
  75. package/src/ward-patient-card/card-rows/mother-child-row.extension.tsx +110 -0
  76. package/src/ward-patient-card/card-rows/mother-child-row.scss +22 -0
  77. package/src/ward-patient-card/card-rows/pending-items-car-row.extension.tsx +50 -0
  78. package/src/ward-patient-card/row-elements/ward-pateint-skeleton-text.tsx +9 -0
  79. package/src/ward-patient-card/row-elements/ward-patient-age.tsx +1 -1
  80. package/src/ward-patient-card/row-elements/ward-patient-coded-obs-tags.tsx +54 -36
  81. package/src/ward-patient-card/row-elements/ward-patient-identifier.tsx +2 -3
  82. package/src/ward-patient-card/row-elements/ward-patient-location.tsx +19 -0
  83. package/src/ward-patient-card/row-elements/ward-patient-obs.resource.ts +36 -32
  84. package/src/ward-patient-card/row-elements/ward-patient-obs.tsx +15 -9
  85. package/src/ward-patient-card/row-elements/ward-patient-pending-order.component.tsx +45 -0
  86. package/src/ward-patient-card/row-elements/ward-patient-pending-transfer.tsx +38 -0
  87. package/src/ward-patient-card/row-elements/ward-patient-responsive-tooltip.tsx +32 -0
  88. package/src/ward-patient-card/ward-patient-card-element.component.tsx +4 -0
  89. package/src/ward-patient-card/ward-patient-card.component.tsx +21 -14
  90. package/src/ward-patient-card/ward-patient-card.scss +61 -8
  91. package/src/ward-patient-card/ward-patient-resource.ts +15 -0
  92. package/src/ward-view/ward-view.component.tsx +124 -132
  93. package/src/ward-view/ward-view.resource.ts +121 -1
  94. package/src/ward-view/ward-view.scss +16 -6
  95. package/src/ward-view/ward-view.test.tsx +27 -42
  96. package/src/ward-view-header/admission-requests-bar.component.tsx +8 -7
  97. package/src/ward-view-header/admission-requests-bar.test.tsx +8 -21
  98. package/src/ward-view-header/admission-requests.scss +1 -1
  99. package/src/ward-view-header/ward-metric.component.tsx +24 -0
  100. package/src/ward-view-header/ward-metric.scss +25 -0
  101. package/src/ward-view-header/ward-metrics.component.tsx +77 -0
  102. package/src/ward-view-header/ward-metrics.scss +8 -0
  103. package/src/ward-view-header/ward-metrics.test.tsx +91 -0
  104. package/src/ward-view-header/ward-view-header.component.tsx +3 -0
  105. package/src/ward-view-header/ward-view-header.scss +0 -1
  106. package/src/ward-workspace/admission-request-card/admission-request-card-actions.component.tsx +11 -3
  107. package/src/ward-workspace/admission-request-card/admission-request-card-header.component.tsx +4 -5
  108. package/src/ward-workspace/admission-request-card/admission-request-card.scss +8 -4
  109. package/src/ward-workspace/admission-request-workspace/admission-requests-workspace.test.tsx +8 -3
  110. package/src/ward-workspace/admission-request-workspace/admission-requests.workspace.tsx +2 -0
  111. package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.test.tsx +29 -61
  112. package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.workspace.tsx +37 -21
  113. package/src/ward-workspace/patient-banner/patient-banner.component.tsx +3 -3
  114. package/src/ward-workspace/patient-clinical-forms-workspace/patient-clinical-forms.workspace.tsx +23 -0
  115. package/src/{ward-patient-workspace → ward-workspace/patient-details}/ward-patient-action-button.extension.tsx +2 -1
  116. package/src/{ward-patient-workspace → ward-workspace/patient-details}/ward-patient.workspace.tsx +7 -5
  117. package/src/ward-workspace/patient-discharge/patient-discharge.scss +41 -0
  118. package/src/ward-workspace/patient-discharge/patient-discharge.workspace.tsx +120 -0
  119. package/src/ward-workspace/patient-transfer-bed-swap/patient-bed-swap-form.component.tsx +40 -30
  120. package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-request-form.component.tsx +29 -22
  121. package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-swap.scss +12 -2
  122. package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-swap.workspace.tsx +2 -2
  123. package/src/ward-workspace/patient-transfer-request-workspace/patient-transfer-request.workspace.tsx +11 -0
  124. package/src/ward-workspace/ward-patient-notes/form/notes-form.component.tsx +1 -1
  125. package/src/ward-workspace/ward-patient-notes/form/notes-form.test.tsx +1 -1
  126. package/src/ward-workspace/ward-patient-notes/history/notes-container.component.tsx +2 -2
  127. package/src/ward-workspace/ward-patient-notes/notes.resource.ts +5 -7
  128. package/src/ward-workspace/ward-patient-notes/notes.workspace.tsx +1 -1
  129. package/src/ward-workspace/ward-patient-notes/types.ts +0 -4
  130. package/src/ward.resource.ts +6 -0
  131. package/translations/en.json +18 -1
  132. package/dist/346.js +0 -1
  133. package/dist/346.js.map +0 -1
  134. package/dist/76.js +0 -1
  135. package/dist/76.js.map +0 -1
  136. package/dist/803.js +0 -1
  137. package/dist/803.js.map +0 -1
  138. package/dist/958.js +0 -2
  139. package/dist/958.js.map +0 -1
  140. package/dist/960.js +0 -1
  141. package/dist/960.js.map +0 -1
  142. /package/dist/{958.js.LICENSE.txt → 161.js.LICENSE.txt} +0 -0
  143. /package/src/{ward-patient-workspace → ward-workspace/patient-details}/ward-patient.style.scss +0 -0
@@ -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={() => launchWorkspace('ward-patient-workspace')}
15
+ handler={() => launchPatientWorkspace()}
15
16
  type={'ward'}
16
17
  />
17
18
  );
@@ -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 { getGender } from '../ward-patient-card/row-elements/ward-patient-gender.component';
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} &nbsp;</div>
47
47
  <div className={styles.headerPatientDetail}>&middot; &nbsp; {getGender(t, patient.person?.gender)}</div>
48
- <div className={styles.headerPatientDetail}>&middot; &nbsp; {age(patient.person?.birthdate)}</div>
48
+ {patient.person?.birthdate && (
49
+ <div className={styles.headerPatientDetail}>&middot; &nbsp; {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
- RadioButtonGroup,
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 { mutate: mutateAdmissionLocation } = useAdmissionLocation();
39
- const { mutate: mutateInpatientRequest } = useInpatientRequest();
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 = useMemo(() => (admissionLocation ? filterBeds(admissionLocation) : []), [admissionLocation]);
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
- [setShowErrorNotifications, patient, emrConfiguration, currentProvider, location, beds],
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 onSubmit={handleSubmit(onSubmit, onError)} className={styles.formContainer}>
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}>
@@ -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 { ResponsiveWrapper, showSnackbar, useSession } from '@openmrs/esm-framework';
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 type { ObsPayload, WardPatientWorkspaceProps } from '../../types';
14
- import { useInpatientRequest } from '../../hooks/useInpatientRequest';
15
- import { Form, ButtonSet, Button, TextArea, InlineNotification, RadioButtonGroup, RadioButton } from '@carbon/react';
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 { mutate: mutateAdmissionLocation } = useAdmissionLocation();
34
- const { mutate: mutateInpatientRequest } = useInpatientRequest();
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.uuid,
106
- encounterType: emrConfiguration.visitNoteEncounterType.uuid,
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(() => setIsSubmitting(false));
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.uuid,
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 onSubmit={handleSubmit(onSubmit, onError)} className={styles.formContainer}>
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: (-(layout.$spacing-05)) (-(layout.$spacing-05)) layout.$spacing-05 (-(layout.$spacing-05));
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.workspaceContent}>
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)}>
@@ -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?.visitNoteEncounterType.uuid,
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.visitNoteEncounterType.uuid,
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, errorFetchingEmrConfiguration } = useEmrConfiguration();
17
+ const { emrConfiguration, isLoadingEmrConfiguration } = useEmrConfiguration();
18
18
 
19
19
  const { patientNotes, isLoadingPatientNotes, errorFetchingPatientNotes } = usePatientNotes(
20
20
  patientUuid,
21
21
  visitUuid,
22
- emrConfiguration?.visitNoteEncounterType?.uuid,
22
+ emrConfiguration?.inpatientNoteEncounterType?.uuid,
23
23
  emrConfiguration?.consultFreeTextCommentsConcept.uuid,
24
24
  );
25
25
 
@@ -1,8 +1,7 @@
1
- import { type FetchResponse, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
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 } = useSWR<FetchResponse<VisitEncountersFetchResponse>, Error>(
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.data.results
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.uuid} />
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;
@@ -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
+ }