@kenyaemr/esm-ward-app 8.1.1-pre.124 → 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,17 +1,17 @@
1
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
1
2
  import { Button, ButtonSet, Column, Form, InlineNotification, Row } from '@carbon/react';
2
3
  import { zodResolver } from '@hookform/resolvers/zod';
3
- import { showSnackbar, useAppContext } from '@openmrs/esm-framework';
4
- import React, { useCallback, useEffect, useMemo, useState } from 'react';
5
4
  import { Controller, useForm } from 'react-hook-form';
6
5
  import { useTranslation } from 'react-i18next';
7
6
  import { z } from 'zod';
7
+ import { showSnackbar, useAppContext } from '@openmrs/esm-framework';
8
+ import type { WardPatientWorkspaceProps, WardViewContext } from '../../types';
8
9
  import { useAssignedBedByPatient } from '../../hooks/useAssignedBedByPatient';
9
- import useWardLocation from '../../hooks/useWardLocation';
10
- import type { WardViewContext } from '../../types';
11
10
  import { assignPatientToBed, removePatientFromBed, useAdmitPatient } from '../../ward.resource';
11
+ import useWardLocation from '../../hooks/useWardLocation';
12
12
  import BedSelector from '../bed-selector.component';
13
+ import WardPatientWorkspaceBanner from '../patient-banner/patient-banner.component';
13
14
  import styles from './admit-patient-form.scss';
14
- import type { AdmitPatientFormWorkspaceProps } from './types';
15
15
 
16
16
  /**
17
17
  * This form gets rendered when the user clicks "admit patient" in
@@ -19,13 +19,15 @@ import type { AdmitPatientFormWorkspaceProps } from './types';
19
19
  * the bed management module is installed. It asks to (optionally) select
20
20
  * a bed to assign to patient
21
21
  */
22
- const AdmitPatientFormWorkspace: React.FC<AdmitPatientFormWorkspaceProps> = ({
23
- patient,
24
- dispositionType,
22
+ const AdmitPatientFormWorkspace: React.FC<WardPatientWorkspaceProps> = ({
23
+ wardPatient,
25
24
  closeWorkspace,
26
25
  closeWorkspaceWithSavedChanges,
27
26
  promptBeforeClosing,
28
27
  }) => {
28
+ const { patient, inpatientRequest } = wardPatient ?? {};
29
+ const dispositionType = inpatientRequest?.dispositionType ?? 'ADMIT';
30
+
29
31
  const { t } = useTranslation();
30
32
  const { location } = useWardLocation();
31
33
  const [isSubmitting, setIsSubmitting] = useState(false);
@@ -44,7 +46,7 @@ const AdmitPatientFormWorkspace: React.FC<AdmitPatientFormWorkspaceProps> = ({
44
46
  z.object({
45
47
  bedId: z.number().optional(),
46
48
  }),
47
- [beds],
49
+ [],
48
50
  );
49
51
 
50
52
  type FormValues = z.infer<typeof zodSchema>;
@@ -59,7 +61,7 @@ const AdmitPatientFormWorkspace: React.FC<AdmitPatientFormWorkspaceProps> = ({
59
61
 
60
62
  useEffect(() => {
61
63
  promptBeforeClosing(() => isDirty);
62
- }, [isDirty]);
64
+ }, [isDirty, promptBeforeClosing]);
63
65
 
64
66
  const onSubmit = (values: FormValues) => {
65
67
  setShowErrorNotifications(false);
@@ -139,64 +141,68 @@ const AdmitPatientFormWorkspace: React.FC<AdmitPatientFormWorkspaceProps> = ({
139
141
  }, []);
140
142
 
141
143
  if (!wardPatientGroupDetails) return <></>;
144
+
142
145
  return (
143
- <Form control={control} className={styles.form} onSubmit={handleSubmit(onSubmit, onError)}>
144
- <div className={styles.formContent}>
145
- <Row>
146
- <Column>
147
- <h2 className={styles.productiveHeading02}>{t('selectABed', 'Select a bed')}</h2>
148
- <div className={styles.bedSelectionDropdown}>
149
- <Controller
150
- control={control}
151
- name="bedId"
152
- render={({ field: { onChange, value }, fieldState: { error } }) => {
153
- return (
154
- <BedSelector
155
- beds={beds}
156
- isLoadingBeds={isLoading}
157
- currentPatient={patient}
158
- selectedBedId={value}
159
- error={error}
160
- control={control}
161
- onChange={onChange}
162
- />
163
- );
164
- }}
165
- />
166
- </div>
167
- </Column>
168
- </Row>
169
- <div className={styles.errorNotifications}>
170
- {showErrorNotifications &&
171
- Object.entries(errors).map(([key, value]) => {
172
- return (
173
- <Row key={key}>
174
- <Column>
175
- <InlineNotification kind="error" subtitle={value.message} lowContrast />
176
- </Column>
177
- </Row>
178
- );
179
- })}
146
+ <div className={styles.flexWrapper}>
147
+ <WardPatientWorkspaceBanner {...{ wardPatient }} />
148
+ <Form control={control} className={styles.form} onSubmit={handleSubmit(onSubmit, onError)}>
149
+ <div className={styles.formContent}>
150
+ <Row>
151
+ <Column>
152
+ <h2 className={styles.productiveHeading02}>{t('selectABed', 'Select a bed')}</h2>
153
+ <div className={styles.bedSelectionDropdown}>
154
+ <Controller
155
+ control={control}
156
+ name="bedId"
157
+ render={({ field: { onChange, value }, fieldState: { error } }) => {
158
+ return (
159
+ <BedSelector
160
+ beds={beds}
161
+ isLoadingBeds={isLoading}
162
+ currentPatient={patient}
163
+ selectedBedId={value}
164
+ error={error}
165
+ control={control}
166
+ onChange={onChange}
167
+ />
168
+ );
169
+ }}
170
+ />
171
+ </div>
172
+ </Column>
173
+ </Row>
174
+ <div className={styles.errorNotifications}>
175
+ {showErrorNotifications &&
176
+ Object.entries(errors).map(([key, value]) => {
177
+ return (
178
+ <Row key={key}>
179
+ <Column>
180
+ <InlineNotification kind="error" subtitle={value.message} lowContrast />
181
+ </Column>
182
+ </Row>
183
+ );
184
+ })}
185
+ </div>
180
186
  </div>
181
- </div>
182
- <ButtonSet className={styles.buttonSet}>
183
- <Button size="xl" kind="secondary" onClick={() => closeWorkspace({ ignoreChanges: true })}>
184
- {t('cancel', 'Cancel')}
185
- </Button>
186
- <Button
187
- type="submit"
188
- size="xl"
189
- disabled={
190
- isSubmitting ||
191
- isLoadingEmrConfiguration ||
192
- errorFetchingEmrConfiguration ||
193
- isLoading ||
194
- isLoadingBedsAssignedToPatient
195
- }>
196
- {!isSubmitting ? t('admit', 'Admit') : t('admitting', 'Admitting...')}
197
- </Button>
198
- </ButtonSet>
199
- </Form>
187
+ <ButtonSet className={styles.buttonSet}>
188
+ <Button size="xl" kind="secondary" onClick={() => closeWorkspace({ ignoreChanges: true })}>
189
+ {t('cancel', 'Cancel')}
190
+ </Button>
191
+ <Button
192
+ type="submit"
193
+ size="xl"
194
+ disabled={
195
+ isSubmitting ||
196
+ isLoadingEmrConfiguration ||
197
+ errorFetchingEmrConfiguration ||
198
+ isLoading ||
199
+ isLoadingBedsAssignedToPatient
200
+ }>
201
+ {!isSubmitting ? t('admit', 'Admit') : t('admitting', 'Admitting...')}
202
+ </Button>
203
+ </ButtonSet>
204
+ </Form>
205
+ </div>
200
206
  );
201
207
  };
202
208
 
@@ -0,0 +1,55 @@
1
+ @use '@carbon/type';
2
+ @use '@carbon/layout';
3
+ @use '@openmrs/esm-styleguide/src/vars' as *;
4
+
5
+ .flexWrapper {
6
+ height: 100%;
7
+ display: flex;
8
+ flex-direction: column;
9
+ color: #393939;
10
+ }
11
+
12
+ .workspaceContent {
13
+ padding: layout.$spacing-05;
14
+ height: 100%;
15
+ display: flex;
16
+ flex-direction: column;
17
+ color: #393939;
18
+ }
19
+
20
+ .field {
21
+ margin-bottom: layout.$spacing-05;
22
+ & > h2 {
23
+ margin-bottom: layout.$spacing-03;
24
+ }
25
+ }
26
+
27
+ .productiveHeading02 {
28
+ @include type.type-style('heading-compact-02');
29
+ }
30
+
31
+ .formContainer {
32
+ display: flex;
33
+ flex-direction: column;
34
+ justify-content: space-between;
35
+ height: 100%;
36
+ }
37
+
38
+ .buttonSet {
39
+ display: flex;
40
+ align-items: center;
41
+ margin: 0 (-(layout.$spacing-05)) (-(layout.$spacing-05)) (-(layout.$spacing-05));
42
+
43
+ button {
44
+ max-width: unset !important;
45
+ width: 50% !important;
46
+
47
+ > svg {
48
+ fill: currentColor !important;
49
+ }
50
+ }
51
+ }
52
+
53
+ .notifications {
54
+ margin-top: layout.$spacing-05;
55
+ }
@@ -0,0 +1,99 @@
1
+ import React from 'react';
2
+ import { screen } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { useAppContext, type DefaultWorkspaceProps } from '@openmrs/esm-framework';
5
+ import { mockInpatientRequestAlice, mockLocationInpatientWard, mockPatientAlice } from '__mocks__';
6
+ import { renderWithSwr } from 'tools';
7
+ import useWardLocation from '../../hooks/useWardLocation';
8
+ import type { WardPatient, WardViewContext } from '../../types';
9
+ import { useCreateEncounter } from '../../ward.resource';
10
+ import CancelAdmissionRequestWorkspace from './cancel-admission-request.workspace';
11
+ import { mockWardViewContext } from '../../../mock';
12
+
13
+ jest.mock('../../hooks/useWardLocation', () => jest.fn());
14
+
15
+ jest.mock('../../hooks/useInpatientRequest', () => ({
16
+ useInpatientRequest: jest.fn(),
17
+ }));
18
+
19
+ jest.mock('../../hooks/useWardPatientGrouping', () => ({
20
+ useWardPatientGrouping: jest.fn(),
21
+ }));
22
+
23
+ jest.mock('../../hooks/useInpatientAdmission', () => ({
24
+ useInpatientAdmission: jest.fn(),
25
+ }));
26
+
27
+ jest.mock('../../ward.resource', () => ({
28
+ useCreateEncounter: jest.fn(),
29
+ }));
30
+
31
+ const mockedUseWardLocation = jest.mocked(useWardLocation);
32
+ const mockedCreateEncounter = jest.fn().mockResolvedValue({
33
+ ok: true,
34
+ data: {
35
+ uuid: 'encounter-uuid',
36
+ },
37
+ });
38
+ const mockedUseCreateEncounter = jest.mocked(useCreateEncounter);
39
+ mockedUseCreateEncounter.mockReturnValue({
40
+ createEncounter: mockedCreateEncounter,
41
+ isLoadingEmrConfiguration: false,
42
+ errorFetchingEmrConfiguration: false,
43
+ emrConfiguration: null,
44
+ });
45
+
46
+ mockedUseWardLocation.mockReturnValue({
47
+ location: mockLocationInpatientWard,
48
+ invalidLocation: false,
49
+ isLoadingLocation: false,
50
+ errorFetchingLocation: null,
51
+ });
52
+
53
+ const mockWorkspaceProps: DefaultWorkspaceProps = {
54
+ closeWorkspaceWithSavedChanges: jest.fn(),
55
+ promptBeforeClosing: jest.fn(),
56
+ setTitle: jest.fn(),
57
+ closeWorkspace: jest.fn(),
58
+ };
59
+
60
+ const mockWardPatientAliceProps: WardPatient = {
61
+ visit: mockInpatientRequestAlice.visit,
62
+ patient: mockPatientAlice,
63
+ bed: null,
64
+ inpatientAdmission: null,
65
+ inpatientRequest: mockInpatientRequestAlice,
66
+ };
67
+
68
+ jest.mocked(useAppContext<WardViewContext>).mockReturnValue(mockWardViewContext);
69
+
70
+ function renderCancelAdmissionRequestWorkspace() {
71
+ renderWithSwr(
72
+ <CancelAdmissionRequestWorkspace
73
+ {...{ ...mockWorkspaceProps, wardPatient: mockWardPatientAliceProps, WardPatientHeader: jest.fn() }}
74
+ />,
75
+ );
76
+ }
77
+
78
+ describe('CancelAdmissionRequestWorkspace', () => {
79
+ it('should cancel admission request form creates encounter when form is filled out and submitted ', async () => {
80
+ const user = userEvent.setup();
81
+ renderCancelAdmissionRequestWorkspace();
82
+
83
+ const textbox = screen.getByRole('textbox');
84
+ expect(textbox).toBeInTheDocument();
85
+ const submit = screen.getByRole('button', { name: /save/i });
86
+ await user.click(submit);
87
+
88
+ const warningText = /notes required for cancelling admission or transfer request/i;
89
+ const warning = screen.getByText(warningText);
90
+ expect(warning).toBeInTheDocument();
91
+
92
+ await user.type(textbox, 'Test note');
93
+ expect(screen.queryByText(warningText)).not.toBeInTheDocument();
94
+
95
+ await user.click(submit);
96
+
97
+ expect(mockedCreateEncounter).toHaveBeenCalled();
98
+ });
99
+ });
@@ -0,0 +1,174 @@
1
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
2
+ import { Button, ButtonSet, Form, InlineNotification, TextArea } from '@carbon/react';
3
+ import classNames from 'classnames';
4
+ import { zodResolver } from '@hookform/resolvers/zod';
5
+ import { Controller, useForm } from 'react-hook-form';
6
+ import { useTranslation } from 'react-i18next';
7
+ import { z } from 'zod';
8
+ import { ResponsiveWrapper, showSnackbar, useAppContext, useSession } from '@openmrs/esm-framework';
9
+ import type { ObsPayload, WardPatientWorkspaceProps, WardViewContext } from '../../types';
10
+ import { useCreateEncounter } from '../../ward.resource';
11
+ import useWardLocation from '../../hooks/useWardLocation';
12
+ import WardPatientWorkspaceBanner from '../patient-banner/patient-banner.component';
13
+ import styles from './cancel-admission-request.scss';
14
+
15
+ export default function CancelAdmissionRequestWorkspace({
16
+ closeWorkspaceWithSavedChanges,
17
+ wardPatient,
18
+ promptBeforeClosing,
19
+ }: WardPatientWorkspaceProps) {
20
+ const { patient } = wardPatient ?? {};
21
+ const { t } = useTranslation();
22
+ const [showErrorNotifications, setShowErrorNotifications] = useState(false);
23
+ const [isSubmitting, setIsSubmitting] = useState(false);
24
+ const { createEncounter, emrConfiguration, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } =
25
+ useCreateEncounter();
26
+ const { currentProvider } = useSession();
27
+ const { location } = useWardLocation();
28
+ const { wardPatientGroupDetails } = useAppContext<WardViewContext>('ward-view-context') ?? {};
29
+
30
+ const zodSchema = useMemo(
31
+ () =>
32
+ z.object({
33
+ note: z
34
+ .string()
35
+ .trim()
36
+ .min(1, {
37
+ message: t(
38
+ 'notesRequiredForCancellingRequest',
39
+ 'Notes required for cancelling admission or transfer request',
40
+ ),
41
+ }),
42
+ }),
43
+ [t],
44
+ );
45
+
46
+ type FormValues = z.infer<typeof zodSchema>;
47
+
48
+ const formDefaultValues: Partial<FormValues> = {
49
+ note: '',
50
+ };
51
+
52
+ const {
53
+ formState: { errors, isDirty },
54
+ control,
55
+ handleSubmit,
56
+ } = useForm<FormValues>({ resolver: zodResolver(zodSchema), defaultValues: formDefaultValues });
57
+
58
+ useEffect(() => {
59
+ promptBeforeClosing(() => isDirty);
60
+ return () => promptBeforeClosing(null);
61
+ }, [isDirty, promptBeforeClosing]);
62
+
63
+ const onSubmit = useCallback(
64
+ (values: FormValues) => {
65
+ setIsSubmitting(true);
66
+ setShowErrorNotifications(false);
67
+ const obs: Array<ObsPayload> = [
68
+ {
69
+ concept: emrConfiguration?.consultFreeTextCommentsConcept?.uuid,
70
+ value: values.note,
71
+ },
72
+ {
73
+ concept: emrConfiguration?.admissionDecisionConcept?.uuid,
74
+ value: {
75
+ uuid: emrConfiguration?.denyAdmissionConcept?.uuid,
76
+ },
77
+ },
78
+ ];
79
+
80
+ createEncounter(patient, emrConfiguration?.cancelADTRequestEncounterType, obs)
81
+ .then(() => {
82
+ showSnackbar({
83
+ title: t('admissionRequestCancelled', 'Admission request cancelled.'),
84
+ kind: 'success',
85
+ });
86
+ })
87
+ .catch((err: Error) => {
88
+ showSnackbar({
89
+ title: t('Error cancelling admission request', 'Error cancelling admission request'),
90
+ subtitle: err.message,
91
+ kind: 'error',
92
+ });
93
+ })
94
+ .finally(() => {
95
+ setIsSubmitting(false);
96
+ closeWorkspaceWithSavedChanges();
97
+ wardPatientGroupDetails.mutate();
98
+ });
99
+ },
100
+ [
101
+ emrConfiguration?.consultFreeTextCommentsConcept?.uuid,
102
+ emrConfiguration?.admissionDecisionConcept?.uuid,
103
+ emrConfiguration?.denyAdmissionConcept?.uuid,
104
+ emrConfiguration?.cancelADTRequestEncounterType,
105
+ createEncounter,
106
+ patient,
107
+ t,
108
+ closeWorkspaceWithSavedChanges,
109
+ wardPatientGroupDetails,
110
+ ],
111
+ );
112
+
113
+ const onError = useCallback(() => {
114
+ setIsSubmitting(false);
115
+ setShowErrorNotifications(true);
116
+ }, []);
117
+
118
+ if (!wardPatientGroupDetails) return <></>;
119
+ return (
120
+ <div className={styles.flexWrapper}>
121
+ <WardPatientWorkspaceBanner wardPatient={wardPatient} />
122
+ <Form
123
+ onSubmit={handleSubmit(onSubmit, onError)}
124
+ className={classNames(styles.formContainer, styles.workspaceContent)}>
125
+ <div>
126
+ {errorFetchingEmrConfiguration && (
127
+ <div className={styles.formError}>
128
+ <InlineNotification
129
+ kind="error"
130
+ title={t('somePartsOfTheFormDidntLoad', "Some parts of the form didn't load")}
131
+ subtitle={t(
132
+ 'fetchingEmrConfigurationFailed',
133
+ 'Fetching EMR configuration failed. Try refreshing the page or contact your system administrator.',
134
+ )}
135
+ lowContrast
136
+ hideCloseButton
137
+ />
138
+ </div>
139
+ )}
140
+ <div className={styles.field}>
141
+ <h2 className={styles.productiveHeading02}>{t('clinicalNotes', 'Clinical notes')}</h2>
142
+ <Controller
143
+ name="note"
144
+ control={control}
145
+ render={({ field, fieldState: { error } }) => (
146
+ <ResponsiveWrapper>
147
+ <TextArea {...field} labelText={''} />
148
+ </ResponsiveWrapper>
149
+ )}
150
+ />
151
+ </div>
152
+ {showErrorNotifications && (
153
+ <div className={styles.notifications}>
154
+ {Object.values(errors).map((error) => (
155
+ <InlineNotification key={error.message} lowContrast subtitle={error?.message} hideCloseButton />
156
+ ))}
157
+ </div>
158
+ )}
159
+ </div>
160
+ <ButtonSet className={styles.buttonSet}>
161
+ <Button size="xl" kind="secondary" onClick={closeWorkspaceWithSavedChanges}>
162
+ {t('cancel', 'Cancel')}
163
+ </Button>
164
+ <Button
165
+ type="submit"
166
+ size="xl"
167
+ disabled={isLoadingEmrConfiguration || isSubmitting || errorFetchingEmrConfiguration || !patient}>
168
+ {t('save', 'Save')}
169
+ </Button>
170
+ </ButtonSet>
171
+ </Form>
172
+ </div>
173
+ );
174
+ }
@@ -1,21 +1,23 @@
1
1
  import { useAppContext } from '@openmrs/esm-framework';
2
2
  import React from 'react';
3
- import type { WardPatient, WardViewContext } from '../../types';
3
+ import type { WardPatientCardType, WardViewContext } from '../../types';
4
4
  import styles from './style.scss';
5
5
 
6
- const WardPatientWorkspaceBanner = (wardPatient: WardPatient) => {
7
- const { patient } = wardPatient;
8
- const {WardPatientHeader} = useAppContext<WardViewContext>('ward-view-context') ?? {};
6
+ const WardPatientWorkspaceBanner: WardPatientCardType = ({ wardPatient }) => {
7
+ const { patient } = wardPatient ?? {};
8
+ const { WardPatientHeader } = useAppContext<WardViewContext>('ward-view-context') ?? {};
9
9
 
10
10
  if (!patient) {
11
11
  console.warn('Patient details were not received by the ward workspace');
12
12
  return null;
13
13
  }
14
14
 
15
- return (
16
- <div className={styles.patientBanner}>
17
- {WardPatientHeader && <WardPatientHeader {...wardPatient} />}
15
+ return WardPatientHeader ? (
16
+ <div className={styles.wardWorkspacePatientBanner}>
17
+ <WardPatientHeader wardPatient={wardPatient} />
18
18
  </div>
19
+ ) : (
20
+ <></>
19
21
  );
20
22
  };
21
23
 
@@ -1,23 +1,7 @@
1
- @use '@carbon/layout';
2
1
  @use '@openmrs/esm-styleguide/src/vars' as *;
3
2
 
4
- .patientBanner {
5
- @extend .dotSeparatedChildren;
6
- display: flex;
7
- flex-wrap: wrap;
8
- width: 100%;
9
- padding: layout.$spacing-04;
10
- background: $ui-01;
11
- }
12
-
13
- .dotSeparatedChildren {
14
- > div:not(div:first-of-type):not(:empty) {
15
- display: flex;
16
- align-items: center;
17
-
18
- &::before {
19
- content: '·';
20
- padding: 0 layout.$spacing-02;
21
- }
3
+ .wardWorkspacePatientBanner {
4
+ > div {
5
+ background: $ui-01;
22
6
  }
23
7
  }
@@ -1,6 +1,7 @@
1
- import React, { useMemo } from 'react';
2
1
  import { ExtensionSlot } from '@openmrs/esm-framework';
2
+ import React, { useMemo } from 'react';
3
3
  import type { WardPatientWorkspaceProps } from '../../types';
4
+ import WardPatientWorkspaceBanner from '../patient-banner/patient-banner.component';
4
5
 
5
6
  const WardPatientClinicalFormsWorkspace: React.FC<WardPatientWorkspaceProps> = (props) => {
6
7
  const { wardPatient, ...restWorkspaceProps } = props;
@@ -17,7 +18,12 @@ const WardPatientClinicalFormsWorkspace: React.FC<WardPatientWorkspaceProps> = (
17
18
  [patientUuid, restWorkspaceProps],
18
19
  );
19
20
 
20
- return <ExtensionSlot name="ward-patient-clinical-forms-workspace-slot" state={clinicalFormsExtensionState} />;
21
+ return (
22
+ <div>
23
+ <WardPatientWorkspaceBanner {...{ wardPatient }} />
24
+ <ExtensionSlot name="ward-patient-clinical-forms-workspace-slot" state={clinicalFormsExtensionState} />
25
+ </div>
26
+ );
21
27
  };
22
28
 
23
29
  export default WardPatientClinicalFormsWorkspace;
@@ -1,7 +1,6 @@
1
1
  import React from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
- import { UserAvatarIcon } from '@openmrs/esm-framework';
4
- import { ActionMenuButton, launchWorkspace } from '@openmrs/esm-framework';
3
+ import { ActionMenuButton, launchWorkspace, UserAvatarIcon } from '@openmrs/esm-framework';
5
4
  import type { WardPatientWorkspaceProps } from '../../types';
6
5
 
7
6
  export default function WardPatientActionButton() {
@@ -12,7 +11,7 @@ export default function WardPatientActionButton() {
12
11
  getIcon={(props) => <UserAvatarIcon {...props} />}
13
12
  label={t('Patient', 'patient')}
14
13
  iconDescription={t('Patient', 'patient')}
15
- handler={() => launchWorkspace<WardPatientWorkspaceProps>('ward-patient-workspace')}
14
+ handler={() => launchWorkspace<WardPatientWorkspaceProps>('ward-patient-workspace')}
16
15
  type={'ward'}
17
16
  />
18
17
  );
@@ -5,7 +5,19 @@
5
5
  min-height: var(--desktop-workspace-window-height);
6
6
  }
7
7
 
8
+ .patientWorkspace {
9
+ display: flex;
10
+ height: 100%;
11
+ flex-direction: column;
12
+ }
13
+
8
14
  .headerPatientDetail {
9
15
  @include type.type-style('body-compact-02');
10
16
  margin: 0 layout.$spacing-02;
11
17
  }
18
+
19
+ .patientWorkspaceContentSlot {
20
+ display: flex;
21
+ flex: 1;
22
+ flex-direction: column;
23
+ }