@kenyaemr/esm-ward-app 8.1.1-pre.129 → 8.1.2-pre.152

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 (125) hide show
  1. package/.turbo/turbo-build.log +25 -22
  2. package/dist/109.js +1 -1
  3. package/dist/109.js.map +1 -1
  4. package/dist/124.js +1 -1
  5. package/dist/124.js.map +1 -1
  6. package/dist/125.js +1 -1
  7. package/dist/125.js.map +1 -1
  8. package/dist/126.js +1 -0
  9. package/dist/126.js.map +1 -0
  10. package/dist/130.js +1 -1
  11. package/dist/130.js.map +1 -1
  12. package/dist/146.js +1 -1
  13. package/dist/146.js.map +1 -1
  14. package/dist/15.js +1 -1
  15. package/dist/15.js.map +1 -1
  16. package/dist/348.js +1 -1
  17. package/dist/362.js +1 -0
  18. package/dist/362.js.map +1 -0
  19. package/dist/443.js +1 -0
  20. package/dist/443.js.map +1 -0
  21. package/dist/471.js +1 -1
  22. package/dist/471.js.map +1 -1
  23. package/dist/481.js +1 -1
  24. package/dist/481.js.map +1 -1
  25. package/dist/53.js +1 -1
  26. package/dist/53.js.map +1 -1
  27. package/dist/534.js +1 -0
  28. package/dist/534.js.map +1 -0
  29. package/dist/559.js +1 -1
  30. package/dist/559.js.map +1 -1
  31. package/dist/574.js +1 -1
  32. package/dist/576.js +1 -1
  33. package/dist/576.js.map +1 -1
  34. package/dist/577.js +1 -1
  35. package/dist/577.js.map +1 -1
  36. package/dist/598.js +1 -0
  37. package/dist/598.js.map +1 -0
  38. package/dist/662.js +1 -1
  39. package/dist/662.js.map +1 -1
  40. package/dist/767.js +1 -1
  41. package/dist/921.js +1 -1
  42. package/dist/921.js.map +1 -1
  43. package/dist/922.js +1 -1
  44. package/dist/922.js.map +1 -1
  45. package/dist/925.js +2 -0
  46. package/dist/925.js.LICENSE.txt +40 -0
  47. package/dist/925.js.map +1 -0
  48. package/dist/kenyaemr-esm-ward-app.js +1 -1
  49. package/dist/kenyaemr-esm-ward-app.js.buildmanifest.json +169 -139
  50. package/dist/kenyaemr-esm-ward-app.js.map +1 -1
  51. package/dist/main.js +1 -1
  52. package/dist/main.js.LICENSE.txt +35 -0
  53. package/dist/main.js.map +1 -1
  54. package/dist/routes.json +1 -1
  55. package/mock.tsx +5 -4
  56. package/package-lock.json +2 -2
  57. package/package.json +4 -4
  58. package/src/action-menu-buttons/clinical-forms-workspace-siderail.component.tsx +1 -1
  59. package/src/action-menu-buttons/discharge-workspace-siderail.component.tsx +1 -1
  60. package/src/beds/bed-share-divider.component.tsx +21 -0
  61. package/src/beds/bed-share-divider.scss +18 -0
  62. package/src/beds/ward-bed.component.tsx +7 -17
  63. package/src/beds/ward-bed.scss +1 -15
  64. package/src/beds/ward-bed.test.tsx +3 -3
  65. package/src/config-schema.ts +6 -0
  66. package/src/hooks/useEmrConfiguration.ts +8 -0
  67. package/src/index.ts +6 -6
  68. package/src/location-selector/location-selector.component.tsx +8 -7
  69. package/src/root.component.tsx +0 -2
  70. package/src/routes.json +20 -6
  71. package/src/types/index.ts +9 -4
  72. package/src/ward-patient-card/row-elements/ward-patient-identifier.tsx +2 -2
  73. package/src/ward-patient-card/row-elements/ward-patient-pending-transfer.tsx +22 -4
  74. package/src/ward-patient-card/ward-patient-card.component.tsx +24 -6
  75. package/src/ward-patient-card/ward-patient-card.scss +6 -0
  76. package/src/ward-view/default-ward/default-ward-beds.component.tsx +3 -5
  77. package/src/ward-view/default-ward/default-ward-patient-card-header.component.tsx +1 -1
  78. package/src/ward-view/default-ward/default-ward-patient-card.component.tsx +2 -2
  79. package/src/ward-view/default-ward/default-ward-unassigned-patients.component.tsx +2 -2
  80. package/src/ward-view/materal-ward/maternal-ward-beds.component.tsx +9 -2
  81. package/src/ward-view/materal-ward/maternal-ward-patient-card-header.component.tsx +1 -1
  82. package/src/ward-view/materal-ward/maternal-ward-patient-card.component.tsx +2 -2
  83. package/src/ward-view/materal-ward/maternal-ward-view.resource.ts +7 -7
  84. package/src/ward-view/ward-view.component.tsx +1 -2
  85. package/src/ward-view/ward.component.tsx +19 -11
  86. package/src/ward-view-header/admission-requests-bar.component.tsx +4 -2
  87. package/src/ward-view-header/admission-requests.scss +11 -1
  88. package/src/ward-view-header/ward-metrics.test.tsx +5 -13
  89. package/src/ward-workspace/admission-request-card/admission-request-card-actions.component.tsx +17 -62
  90. package/src/ward-workspace/admission-request-card/admission-request-card-header.component.tsx +1 -1
  91. package/src/ward-workspace/admission-request-card/admission-request-card.component.tsx +2 -2
  92. package/src/ward-workspace/admit-patient-button.component.tsx +82 -0
  93. package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.scss +7 -0
  94. package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.test.tsx +28 -13
  95. package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.workspace.tsx +72 -66
  96. package/src/ward-workspace/cancel-admission-request-workspace/cancel-admission-request.scss +55 -0
  97. package/src/ward-workspace/cancel-admission-request-workspace/cancel-admission-request.test.tsx +99 -0
  98. package/src/ward-workspace/cancel-admission-request-workspace/cancel-admission-request.workspace.tsx +174 -0
  99. package/src/ward-workspace/patient-banner/patient-banner.component.tsx +9 -7
  100. package/src/ward-workspace/patient-banner/style.scss +3 -19
  101. package/src/ward-workspace/patient-clinical-forms-workspace/patient-clinical-forms.workspace.tsx +8 -2
  102. package/src/ward-workspace/patient-details/ward-patient-action-button.extension.tsx +2 -3
  103. package/src/ward-workspace/patient-details/ward-patient.style.scss +12 -0
  104. package/src/ward-workspace/patient-details/ward-patient.workspace.tsx +18 -47
  105. package/src/ward-workspace/patient-discharge/patient-discharge.workspace.tsx +14 -24
  106. package/src/ward-workspace/patient-transfer-bed-swap/patient-bed-swap-form.component.tsx +12 -34
  107. package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-request-form.component.tsx +48 -35
  108. package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-swap.scss +4 -0
  109. package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-swap.workspace.tsx +1 -1
  110. package/src/ward-workspace/ward-patient-notes/form/notes-form.component.tsx +30 -25
  111. package/src/ward-workspace/ward-patient-notes/notes.workspace.tsx +1 -1
  112. package/src/ward.resource.ts +32 -22
  113. package/translations/en.json +7 -1
  114. package/dist/153.js +0 -1
  115. package/dist/153.js.map +0 -1
  116. package/dist/169.js +0 -1
  117. package/dist/169.js.map +0 -1
  118. package/dist/303.js +0 -2
  119. package/dist/303.js.LICENSE.txt +0 -5
  120. package/dist/303.js.map +0 -1
  121. package/dist/501.js +0 -1
  122. package/dist/501.js.map +0 -1
  123. package/dist/920.js +0 -1
  124. package/dist/920.js.map +0 -1
  125. package/src/ward-workspace/admit-patient-form-workspace/types.ts +0 -7
@@ -1,60 +1,31 @@
1
- import { age, attach, ExtensionSlot, type Patient } from '@openmrs/esm-framework';
2
- import React, { useEffect } from 'react';
3
- import styles from './ward-patient.style.scss';
4
- import { useTranslation } from 'react-i18next';
1
+ import { attach, ExtensionSlot, useConfig } from '@openmrs/esm-framework';
2
+ import React from 'react';
5
3
  import { type WardPatientWorkspaceProps } from '../../types';
6
- import { getGender } from '../../ward-patient-card/row-elements/ward-patient-gender.component';
4
+ import WardPatientWorkspaceBanner from '../patient-banner/patient-banner.component';
5
+ import styles from './ward-patient.style.scss';
6
+ import { type WardConfigObject } from '../../config-schema';
7
+ import classNames from 'classnames';
7
8
 
8
9
  attach('ward-patient-workspace-header-slot', 'patient-vitals-info');
9
10
 
10
- export default function WardPatientWorkspace({ setTitle, wardPatient }: WardPatientWorkspaceProps) {
11
- useEffect(() => {
12
- if (wardPatient) {
13
- const { patient } = wardPatient;
14
- setTitle(patient.person.display, <PatientWorkspaceTitle key={patient.uuid} patient={patient} />);
15
- }
16
- }, [wardPatient]);
11
+ export default function WardPatientWorkspace({ wardPatient }: WardPatientWorkspaceProps) {
12
+ const { patient } = wardPatient ?? {};
13
+ const { hideWorkspaceVitalsLinks } = useConfig<WardConfigObject>();
14
+ const extensionSlotState = { patient, patientUuid: patient?.uuid, hideLinks: hideWorkspaceVitalsLinks };
17
15
 
18
16
  return (
19
17
  <>
20
18
  {wardPatient && (
21
- <div className={styles.workspaceContainer}>
22
- <WardPatientWorkspaceView patient={wardPatient.patient} />
19
+ <div className={classNames(styles.workspaceContainer, styles.patientWorkspace)}>
20
+ <WardPatientWorkspaceBanner {...{ wardPatient }} />
21
+ <ExtensionSlot name="ward-patient-workspace-header-slot" state={extensionSlotState} />
22
+ <ExtensionSlot
23
+ name="ward-patient-workspace-content-slot"
24
+ state={extensionSlotState}
25
+ className={styles.patientWorkspaceContentSlot}
26
+ />
23
27
  </div>
24
28
  )}
25
29
  </>
26
30
  );
27
31
  }
28
-
29
- interface WardPatientWorkspaceViewProps {
30
- patient: Patient;
31
- }
32
-
33
- const WardPatientWorkspaceView: React.FC<WardPatientWorkspaceViewProps> = ({ patient }) => {
34
- const extensionSlotState = { patient, patientUuid: patient.uuid };
35
-
36
- return (
37
- <>
38
- <div>
39
- <ExtensionSlot name="ward-patient-workspace-header-slot" state={extensionSlotState} />
40
- </div>
41
- <div>
42
- <ExtensionSlot name="ward-patient-workspace-content-slot" state={extensionSlotState} />
43
- </div>
44
- </>
45
- );
46
- };
47
-
48
- const PatientWorkspaceTitle: React.FC<WardPatientWorkspaceViewProps> = ({ patient }) => {
49
- const { t } = useTranslation();
50
-
51
- return (
52
- <>
53
- <div>{patient.person.display} &nbsp;</div>
54
- <div className={styles.headerPatientDetail}>&middot; &nbsp; {getGender(t, patient.person?.gender)}</div>
55
- {patient.person?.birthdate && (
56
- <div className={styles.headerPatientDetail}>&middot; &nbsp; {age(patient.person?.birthdate)}</div>
57
- )}
58
- </>
59
- );
60
- };
@@ -1,39 +1,28 @@
1
+ import React, { useCallback, useState } from 'react';
1
2
  import { Button, ButtonSet, InlineNotification } from '@carbon/react';
2
3
  import { Exit } from '@carbon/react/icons';
3
- import { ExtensionSlot, showSnackbar, useAppContext, useSession } from '@openmrs/esm-framework';
4
- import React, { useCallback, useState } from 'react';
5
4
  import { useTranslation } from 'react-i18next';
6
- import useEmrConfiguration from '../../hooks/useEmrConfiguration';
7
- import useWardLocation from '../../hooks/useWardLocation';
5
+ import { ExtensionSlot, showSnackbar, useAppContext, useSession } from '@openmrs/esm-framework';
8
6
  import { type WardPatientWorkspaceProps, type WardViewContext } from '../../types';
9
- import { createEncounter, removePatientFromBed } from '../../ward.resource';
7
+ import { removePatientFromBed, useCreateEncounter } from '../../ward.resource';
8
+ import useWardLocation from '../../hooks/useWardLocation';
10
9
  import WardPatientWorkspaceBanner from '../patient-banner/patient-banner.component';
11
10
  import styles from './patient-discharge.scss';
12
11
 
13
12
  export default function PatientDischargeWorkspace(props: WardPatientWorkspaceProps) {
14
13
  const { wardPatient, closeWorkspaceWithSavedChanges } = props;
15
14
  const { t } = useTranslation();
16
- const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
15
+ const [isSubmitting, setIsSubmitting] = useState(false);
17
16
  const { currentProvider } = useSession();
18
17
  const { location } = useWardLocation();
19
- const { emrConfiguration, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } = useEmrConfiguration();
18
+ const { createEncounter, emrConfiguration, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } =
19
+ useCreateEncounter();
20
20
  const { wardPatientGroupDetails } = useAppContext<WardViewContext>('ward-view-context') ?? {};
21
21
 
22
22
  const submitDischarge = useCallback(() => {
23
23
  setIsSubmitting(true);
24
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
- })
25
+ createEncounter(wardPatient?.patient, emrConfiguration.exitFromInpatientEncounterType)
37
26
  .then((response) => {
38
27
  if (response?.ok) {
39
28
  if (wardPatient?.bed?.id) {
@@ -63,11 +52,12 @@ export default function PatientDischargeWorkspace(props: WardPatientWorkspacePro
63
52
  wardPatientGroupDetails.mutate();
64
53
  });
65
54
  }, [
66
- currentProvider,
67
- location,
55
+ createEncounter,
56
+ wardPatient?.patient,
57
+ wardPatient.bed.id,
68
58
  emrConfiguration,
69
- wardPatient?.patient?.uuid,
70
- wardPatient?.bed?.uuid,
59
+ t,
60
+ closeWorkspaceWithSavedChanges,
71
61
  wardPatientGroupDetails,
72
62
  ]);
73
63
 
@@ -75,7 +65,7 @@ export default function PatientDischargeWorkspace(props: WardPatientWorkspacePro
75
65
  return (
76
66
  <div className={styles.workspaceContent}>
77
67
  <div className={styles.patientWorkspaceBanner}>
78
- <WardPatientWorkspaceBanner {...props?.wardPatient} />
68
+ <WardPatientWorkspaceBanner wardPatient={props?.wardPatient} />
79
69
  </div>
80
70
  <div className={styles.workspaceForm}>
81
71
  <div>
@@ -1,15 +1,13 @@
1
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
1
2
  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
3
  import classNames from 'classnames';
5
- import React, { useCallback, useEffect, useMemo, useState } from 'react';
4
+ import { zodResolver } from '@hookform/resolvers/zod';
6
5
  import { Controller, useForm } from 'react-hook-form';
7
6
  import { useTranslation } from 'react-i18next';
8
7
  import { z } from 'zod';
9
- import useEmrConfiguration from '../../hooks/useEmrConfiguration';
10
- import useWardLocation from '../../hooks/useWardLocation';
11
- import type { BedLayout, WardPatientWorkspaceProps, WardViewContext } from '../../types';
12
- import { assignPatientToBed, createEncounter, removePatientFromBed } from '../../ward.resource';
8
+ import { showSnackbar, useAppContext } from '@openmrs/esm-framework';
9
+ import type { WardPatientWorkspaceProps, WardViewContext } from '../../types';
10
+ import { assignPatientToBed, useCreateEncounter, removePatientFromBed } from '../../ward.resource';
13
11
  import BedSelector from '../bed-selector.component';
14
12
  import styles from './patient-transfer-swap.scss';
15
13
 
@@ -21,10 +19,9 @@ export default function PatientBedSwapForm({
21
19
  const { patient } = wardPatient;
22
20
  const { t } = useTranslation();
23
21
  const [showErrorNotifications, setShowErrorNotifications] = useState(false);
24
- const { emrConfiguration, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } = useEmrConfiguration();
22
+ const { createEncounter, emrConfiguration, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } =
23
+ useCreateEncounter();
25
24
  const [isSubmitting, setIsSubmitting] = useState(false);
26
- const { currentProvider } = useSession();
27
- const { location } = useWardLocation();
28
25
  const { wardPatientGroupDetails } = useAppContext<WardViewContext>('ward-view-context') ?? {};
29
26
  const { isLoading } = wardPatientGroupDetails?.admissionLocationResponse ?? {};
30
27
 
@@ -50,35 +47,16 @@ export default function PatientBedSwapForm({
50
47
  useEffect(() => {
51
48
  promptBeforeClosing(() => isDirty);
52
49
  return () => promptBeforeClosing(null);
53
- }, [isDirty]);
54
-
55
- const getBedInformation = useCallback(
56
- (bed: BedLayout) => {
57
- const patients = bed.patients.map((bedPatient) => bedPatient?.person?.preferredName?.display);
58
- const bedNumber = bed.bedNumber;
59
- return [bedNumber, ...(patients.length ? patients : [t('empty', 'Empty')])].join(' · ');
60
- },
61
- [t],
62
- );
50
+ }, [isDirty, promptBeforeClosing]);
63
51
 
64
- const beds = wardPatientGroupDetails?.bedLayouts ?? [];
52
+ const beds = useMemo(() => wardPatientGroupDetails?.bedLayouts ?? [], [wardPatientGroupDetails]);
65
53
 
66
54
  const onSubmit = useCallback(
67
55
  (values: FormValues) => {
68
56
  const bedSelected = beds.find((bed) => bed.bedId === values.bedId);
57
+ setIsSubmitting(true);
69
58
  setShowErrorNotifications(false);
70
- createEncounter({
71
- patient: patient.uuid,
72
- encounterType: emrConfiguration.transferWithinHospitalEncounterType.uuid,
73
- location: location?.uuid,
74
- encounterProviders: [
75
- {
76
- provider: currentProvider?.uuid,
77
- encounterRole: emrConfiguration.clinicianEncounterRole.uuid,
78
- },
79
- ],
80
- obs: [],
81
- })
59
+ createEncounter(patient, emrConfiguration.bedAssignmentEncounterType)
82
60
  .then(async (response) => {
83
61
  if (response.ok) {
84
62
  if (bedSelected) {
@@ -132,7 +110,7 @@ export default function PatientBedSwapForm({
132
110
  closeWorkspaceWithSavedChanges();
133
111
  });
134
112
  },
135
- [setShowErrorNotifications, patient, emrConfiguration, currentProvider, location, beds, wardPatientGroupDetails],
113
+ [beds, createEncounter, patient, emrConfiguration, t, wardPatientGroupDetails, closeWorkspaceWithSavedChanges],
136
114
  );
137
115
 
138
116
  const onError = useCallback(() => {
@@ -1,16 +1,16 @@
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';
5
1
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
2
+ import classNames from 'classnames';
3
+ import { z } from 'zod';
4
+ import { Button, ButtonSet, Form, InlineNotification, RadioButton, RadioButtonGroup, TextArea } from '@carbon/react';
6
5
  import { Controller, useForm } from 'react-hook-form';
7
6
  import { useTranslation } from 'react-i18next';
8
- import { z } from 'zod';
9
- import useEmrConfiguration from '../../hooks/useEmrConfiguration';
7
+ import { zodResolver } from '@hookform/resolvers/zod';
8
+ import { ResponsiveWrapper, showSnackbar, useAppContext, useLayoutType, useSession } from '@openmrs/esm-framework';
9
+ import { useCreateEncounter } from '../../ward.resource';
10
+ import type { ObsPayload, WardPatientWorkspaceProps, WardViewContext } from '../../types';
10
11
  import useWardLocation from '../../hooks/useWardLocation';
12
+ import AdmissionPatientButton from '../admit-patient-button.component';
11
13
  import LocationSelector from '../../location-selector/location-selector.component';
12
- import type { ObsPayload, WardPatientWorkspaceProps, WardViewContext } from '../../types';
13
- import { createEncounter } from '../../ward.resource';
14
14
  import styles from './patient-transfer-swap.scss';
15
15
 
16
16
  export default function PatientTransferForm({
@@ -18,11 +18,12 @@ export default function PatientTransferForm({
18
18
  wardPatient,
19
19
  promptBeforeClosing,
20
20
  }: WardPatientWorkspaceProps) {
21
- const { patient } = wardPatient ?? {};
22
21
  const { t } = useTranslation();
22
+ const { patient, inpatientAdmission } = wardPatient ?? {};
23
23
  const [showErrorNotifications, setShowErrorNotifications] = useState(false);
24
24
  const [isSubmitting, setIsSubmitting] = useState(false);
25
- const { emrConfiguration, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } = useEmrConfiguration();
25
+ const { createEncounter, emrConfiguration, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } =
26
+ useCreateEncounter();
26
27
  const { currentProvider } = useSession();
27
28
  const { location } = useWardLocation();
28
29
  const dispositionsWithTypeTransfer = useMemo(
@@ -30,6 +31,8 @@ export default function PatientTransferForm({
30
31
  [emrConfiguration],
31
32
  );
32
33
  const { wardPatientGroupDetails } = useAppContext<WardViewContext>('ward-view-context') ?? {};
34
+ const responsiveSize = useLayoutType() === 'tablet' ? 'lg' : 'md';
35
+ const isAdmitted = inpatientAdmission != null;
33
36
 
34
37
  const zodSchema = useMemo(
35
38
  () =>
@@ -69,12 +72,12 @@ export default function PatientTransferForm({
69
72
  if (dispositionsWithTypeTransfer?.length === 1) {
70
73
  setValue('transferType', dispositionsWithTypeTransfer[0].uuid);
71
74
  }
72
- }, [dispositionsWithTypeTransfer]);
75
+ }, [dispositionsWithTypeTransfer, setValue]);
73
76
 
74
77
  useEffect(() => {
75
78
  promptBeforeClosing(() => isDirty);
76
79
  return () => promptBeforeClosing(null);
77
- }, [isDirty]);
80
+ }, [isDirty, promptBeforeClosing]);
78
81
 
79
82
  const onSubmit = useCallback(
80
83
  (values: FormValues) => {
@@ -98,23 +101,12 @@ export default function PatientTransferForm({
98
101
  });
99
102
  }
100
103
 
101
- createEncounter({
102
- patient: patient?.uuid,
103
- encounterType: emrConfiguration.transferRequestEncounterType.uuid,
104
- location: location.uuid,
105
- encounterProviders: [
106
- {
107
- encounterRole: emrConfiguration.clinicianEncounterRole.uuid,
108
- provider: currentProvider?.uuid,
109
- },
110
- ],
111
- obs: [
112
- {
113
- concept: emrConfiguration.dispositionDescriptor.dispositionSetConcept.uuid,
114
- groupMembers: obs,
115
- },
116
- ],
117
- })
104
+ createEncounter(patient, emrConfiguration.transferRequestEncounterType, [
105
+ {
106
+ concept: emrConfiguration.dispositionDescriptor.dispositionSetConcept.uuid,
107
+ groupMembers: obs,
108
+ },
109
+ ])
118
110
  .then(() => {
119
111
  showSnackbar({
120
112
  title: t('patientTransferRequestCreated', 'Patient transfer request created'),
@@ -135,12 +127,12 @@ export default function PatientTransferForm({
135
127
  });
136
128
  },
137
129
  [
138
- setShowErrorNotifications,
139
- currentProvider,
140
- location,
141
- emrConfiguration,
142
- patient?.uuid,
130
+ closeWorkspaceWithSavedChanges,
131
+ createEncounter,
143
132
  dispositionsWithTypeTransfer,
133
+ emrConfiguration,
134
+ patient,
135
+ t,
144
136
  wardPatientGroupDetails,
145
137
  ],
146
138
  );
@@ -150,7 +142,28 @@ export default function PatientTransferForm({
150
142
  setShowErrorNotifications(true);
151
143
  }, []);
152
144
 
153
- if (!wardPatientGroupDetails) return <></>;
145
+ if (!wardPatientGroupDetails) {
146
+ return <></>;
147
+ }
148
+ if (!isAdmitted) {
149
+ return (
150
+ <div className={styles.workspaceContent}>
151
+ <div className={styles.formError}>
152
+ <InlineNotification
153
+ kind="info"
154
+ title={t('unableToTransferPatient', 'Unable to transfer patient')}
155
+ subtitle={t(
156
+ 'unableToTransferPatientNotYetAdmitted',
157
+ 'This patient is not admitted to this ward. Admit this patient before transferring them to a different location.',
158
+ )}
159
+ lowContrast
160
+ hideCloseButton
161
+ />
162
+ </div>
163
+ <AdmissionPatientButton wardPatient={wardPatient} onAdmitPatientSuccess={closeWorkspaceWithSavedChanges} />
164
+ </div>
165
+ );
166
+ }
154
167
  return (
155
168
  <Form
156
169
  onSubmit={handleSubmit(onSubmit, onError)}
@@ -9,6 +9,10 @@
9
9
  color: #393939;
10
10
  }
11
11
 
12
+ .formError {
13
+ margin-bottom: layout.$spacing-05;
14
+ }
15
+
12
16
  .workspaceContent {
13
17
  padding: layout.$spacing-05;
14
18
  height: 100%;
@@ -23,7 +23,7 @@ export default function PatientTransferAndSwapWorkspace(props: WardPatientWorksp
23
23
  return (
24
24
  <div className={styles.flexWrapper}>
25
25
  <div className={styles.patientWorkspaceBanner}>
26
- <WardPatientWorkspaceBanner {...props?.wardPatient} />
26
+ <WardPatientWorkspaceBanner wardPatient={props?.wardPatient} />
27
27
  </div>
28
28
  {isBedManagementModuleInstalled && (
29
29
  <div className={styles.contentSwitcherWrapper}>
@@ -5,7 +5,6 @@ import { zodResolver } from '@hookform/resolvers/zod';
5
5
  import { Controller, useForm } from 'react-hook-form';
6
6
  import { Button, Column, Form, InlineLoading, InlineNotification, Row, Stack, TextArea } from '@carbon/react';
7
7
  import {
8
- createErrorHandler,
9
8
  type DefaultWorkspaceProps,
10
9
  type PatientUuid,
11
10
  ResponsiveWrapper,
@@ -13,13 +12,17 @@ import {
13
12
  translateFrom,
14
13
  useSession,
15
14
  } from '@openmrs/esm-framework';
16
- import { savePatientNote } from '../notes.resource';
17
- import styles from './notes-form.scss';
18
15
  import { moduleName } from '../../../constant';
16
+ import { savePatientNote } from '../notes.resource';
19
17
  import useEmrConfiguration from '../../../hooks/useEmrConfiguration';
18
+ import styles from './notes-form.scss';
20
19
 
21
20
  type NotesFormData = z.infer<typeof noteFormSchema>;
22
21
 
22
+ interface PatientNotesFormProps extends DefaultWorkspaceProps {
23
+ patientUuid: PatientUuid;
24
+ }
25
+
23
26
  const noteFormSchema = z.object({
24
27
  wardClinicalNote: z.string().refine((val) => val.trim().length > 0, {
25
28
  //t('clinicalNoteErrorMessage','Clinical note is required')
@@ -27,10 +30,6 @@ const noteFormSchema = z.object({
27
30
  }),
28
31
  });
29
32
 
30
- interface PatientNotesFormProps extends DefaultWorkspaceProps {
31
- patientUuid: PatientUuid;
32
- }
33
-
34
33
  const PatientNotesForm: React.FC<PatientNotesFormProps> = ({
35
34
  closeWorkspaceWithSavedChanges,
36
35
  patientUuid,
@@ -39,8 +38,9 @@ const PatientNotesForm: React.FC<PatientNotesFormProps> = ({
39
38
  const { emrConfiguration, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } = useEmrConfiguration();
40
39
  const { t } = useTranslation();
41
40
  const session = useSession();
41
+
42
42
  const [isSubmitting, setIsSubmitting] = useState(false);
43
- const [rows, setRows] = useState<number>();
43
+ const [rows, setRows] = useState(0);
44
44
 
45
45
  const {
46
46
  control,
@@ -93,26 +93,31 @@ const PatientNotesForm: React.FC<PatientNotesFormProps> = ({
93
93
  closeWorkspaceWithSavedChanges();
94
94
  showSnackbar({
95
95
  isLowContrast: true,
96
- subtitle: t('patientNoteNowVisible', 'It should be now visible in the notes history'),
97
96
  kind: 'success',
97
+ subtitle: t('patientNoteNowVisible', 'It should be now visible in the notes history'),
98
98
  title: t('visitNoteSaved', 'Patient note saved'),
99
99
  });
100
100
  })
101
101
  .catch((err) => {
102
- createErrorHandler();
103
-
104
102
  showSnackbar({
105
- title: t('patientNoteSaveError', 'Error saving patient note'),
106
- kind: 'error',
107
103
  isLowContrast: false,
104
+ kind: 'error',
108
105
  subtitle: err?.message,
106
+ title: t('patientNoteSaveError', 'Error saving patient note'),
109
107
  });
110
108
  })
111
- .finally(() => {
112
- setIsSubmitting(false);
113
- });
109
+ .finally(() => setIsSubmitting(false));
114
110
  },
115
- [emrConfiguration, patientUuid, locationUuid, providerUuid],
111
+ [
112
+ closeWorkspaceWithSavedChanges,
113
+ emrConfiguration?.clinicianEncounterRole.uuid,
114
+ emrConfiguration?.consultFreeTextCommentsConcept.uuid,
115
+ emrConfiguration?.inpatientNoteEncounterType.uuid,
116
+ locationUuid,
117
+ patientUuid,
118
+ providerUuid,
119
+ t,
120
+ ],
116
121
  );
117
122
 
118
123
  const onError = (errors) => console.error(errors);
@@ -146,19 +151,19 @@ const PatientNotesForm: React.FC<PatientNotesFormProps> = ({
146
151
  <ResponsiveWrapper>
147
152
  <TextArea
148
153
  id="additionalNote"
149
- rows={rows}
150
- labelText={t('clinicalNoteLabel', 'Write your notes')}
151
- placeholder={t('wardClinicalNotePlaceholder', 'Write any notes here')}
152
- value={value}
153
- onBlur={onBlur}
154
154
  invalid={!!errors.wardClinicalNote}
155
155
  invalidText={errors.wardClinicalNote?.message}
156
+ labelText={t('clinicalNoteLabel', 'Write your notes')}
157
+ onBlur={onBlur}
156
158
  onChange={(event) => {
157
159
  onChange(event);
158
- const textareaLineHeight = 24; // This is the default line height for Carbon's TextArea component
159
- const newRows = Math.ceil(event.target.scrollHeight / textareaLineHeight);
160
+ const textAreaLineHeight = 24; // This is the default line height for Carbon's TextArea component
161
+ const newRows = Math.ceil(event.target.scrollHeight / textAreaLineHeight);
160
162
  setRows(newRows);
161
163
  }}
164
+ placeholder={t('wardClinicalNotePlaceholder', 'Write any notes here')}
165
+ rows={rows}
166
+ value={value}
162
167
  />
163
168
  </ResponsiveWrapper>
164
169
  )}
@@ -167,9 +172,9 @@ const PatientNotesForm: React.FC<PatientNotesFormProps> = ({
167
172
  </Row>
168
173
  </Stack>
169
174
  <Button
170
- kind="primary"
171
175
  className={styles.saveButton}
172
176
  disabled={isSubmitting || isLoadingEmrConfiguration || errorFetchingEmrConfiguration}
177
+ kind="primary"
173
178
  type="submit">
174
179
  {isSubmitting ? <InlineLoading description={t('saving', 'Saving...')} /> : <span>{t('save', 'Save')}</span>}
175
180
  </Button>
@@ -15,7 +15,7 @@ const WardPatientNotesWorkspace: React.FC<WardPatientWorkspaceProps> = (props) =
15
15
 
16
16
  return (
17
17
  <div>
18
- <WardPatientWorkspaceBanner {...wardPatient} />
18
+ <WardPatientWorkspaceBanner {...{ wardPatient }} />
19
19
  <PatientNotesForm {...notesFormState} />
20
20
  <PatientNotesHistory patientUuid={patientUuid} visitUuid={wardPatient?.visit?.uuid} />
21
21
  </div>
@@ -1,32 +1,17 @@
1
- import { openmrsFetch, type Patient, restBaseUrl, useSession } from '@openmrs/esm-framework';
2
- import type { DispositionType, Encounter, EncounterPayload } from './types';
1
+ import { openmrsFetch, type OpenmrsResource, type Patient, restBaseUrl, useSession } from '@openmrs/esm-framework';
2
+ import type { DispositionType, Encounter, EncounterPayload, ObsPayload } from './types';
3
3
  import useEmrConfiguration from './hooks/useEmrConfiguration';
4
4
  import useWardLocation from './hooks/useWardLocation';
5
5
 
6
- export function createEncounter(encounterPayload: EncounterPayload) {
7
- return openmrsFetch<Encounter>(`${restBaseUrl}/encounter`, {
8
- method: 'POST',
9
- headers: {
10
- 'content-type': 'application/json',
11
- },
12
- body: encounterPayload,
13
- });
14
- }
15
-
16
- export function useAdmitPatient() {
6
+ export function useCreateEncounter() {
17
7
  const { location } = useWardLocation();
18
8
  const { currentProvider } = useSession();
19
9
  const { emrConfiguration, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } = useEmrConfiguration();
20
10
 
21
- const admitPatient = (patient: Patient, dispositionType: DispositionType) => {
22
- return createEncounter({
11
+ const createEncounter = (patient: Patient, encounterType: OpenmrsResource, obs: ObsPayload[] = []) => {
12
+ const encounterPayload = {
23
13
  patient: patient.uuid,
24
- encounterType:
25
- dispositionType === 'ADMIT'
26
- ? emrConfiguration.admissionEncounterType.uuid
27
- : dispositionType === 'TRANSFER'
28
- ? emrConfiguration.transferWithinHospitalEncounterType.uuid
29
- : null,
14
+ encounterType,
30
15
  location: location?.uuid,
31
16
  encounterProviders: [
32
17
  {
@@ -34,10 +19,35 @@ export function useAdmitPatient() {
34
19
  encounterRole: emrConfiguration.clinicianEncounterRole.uuid,
35
20
  },
36
21
  ],
37
- obs: [],
22
+ obs,
23
+ };
24
+
25
+ return openmrsFetch<Encounter>(`${restBaseUrl}/encounter`, {
26
+ method: 'POST',
27
+ headers: {
28
+ 'content-type': 'application/json',
29
+ },
30
+ body: encounterPayload,
38
31
  });
39
32
  };
40
33
 
34
+ return { createEncounter, emrConfiguration, isLoadingEmrConfiguration, errorFetchingEmrConfiguration };
35
+ }
36
+
37
+ export function useAdmitPatient() {
38
+ const { createEncounter, emrConfiguration, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } =
39
+ useCreateEncounter();
40
+
41
+ const admitPatient = (patient: Patient, dispositionType: DispositionType) => {
42
+ const encounterType =
43
+ dispositionType === 'ADMIT'
44
+ ? emrConfiguration.admissionEncounterType
45
+ : dispositionType === 'TRANSFER'
46
+ ? emrConfiguration.transferWithinHospitalEncounterType
47
+ : null;
48
+ return createEncounter(patient, encounterType);
49
+ };
50
+
41
51
  return { admitPatient, isLoadingEmrConfiguration, errorFetchingEmrConfiguration };
42
52
  }
43
53
 
@@ -1,4 +1,5 @@
1
1
  {
2
+ "admissionRequestCancelled": "Admission request cancelled.",
2
3
  "admissionRequests": "Admission requests",
3
4
  "admissionRequestsCount_one": "{{count}} admission request",
4
5
  "admissionRequestsCount_other": "{{count}} admission requests",
@@ -8,18 +9,20 @@
8
9
  "bedShare": "Bed share",
9
10
  "bedSwap": "Bed swap",
10
11
  "cancel": "Cancel",
12
+ "cancelAdmissionRequest": "Cancel admission request",
11
13
  "capacity": "Capacity",
12
14
  "capacityMetricValue": "{{ metricValue }} %",
13
15
  "chooseAnOption": "Choose an option",
14
16
  "clinicalForms": "Clinical forms",
15
17
  "clinicalNoteLabel": "Write your notes",
18
+ "clinicalNotes": "Clinical notes",
16
19
  "countItems_one": "{{count}} {{item}}",
17
20
  "countItems_other": "{{count}} {{item}}",
18
21
  "discharge": "Discharge",
19
- "empty": "Empty",
20
22
  "emptyBed": "Empty bed",
21
23
  "emptyText": "Empty",
22
24
  "encounterDisplay": "{{encounterType}} {{encounterDate}}",
25
+ "Error cancelling admission request": "Error cancelling admission request",
23
26
  "errorChangingPatientBedAssignment": "Error changing patient bed assignment",
24
27
  "errorConfiguringPatientCard": "Error configuring patient card",
25
28
  "errorConfiguringPatientCardMessage": "Unable to find configuration for {{elementType}}, id: {{id}}",
@@ -50,6 +53,7 @@
50
53
  "noLocationsFound": "No locations found",
51
54
  "note": "Note",
52
55
  "notes": "Notes",
56
+ "notesRequiredForCancellingRequest": "Notes required for cancelling admission or transfer request",
53
57
  "Orders": "Orders",
54
58
  "other": "Other",
55
59
  "patientAdmittedButBedNotAssigned": "Patient admitted successfully but fail to assign bed to patient",
@@ -89,6 +93,8 @@
89
93
  "transfers": "Transfers",
90
94
  "transferType": "Transfer type",
91
95
  "typeOfTransfer": "Type of transfer",
96
+ "unableToTransferPatient": "Unable to transfer patient",
97
+ "unableToTransferPatientNotYetAdmitted": "This patient is not admitted to this ward. Admit this patient before transferring them to a different location.",
92
98
  "unknown": "Unknown",
93
99
  "visitNoteSaved": "Patient note saved",
94
100
  "wardClinicalNotePlaceholder": "Write any notes here",