@kenyaemr/esm-ward-app 8.0.1-pre.99 → 8.0.2

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 (196) hide show
  1. package/.turbo/turbo-build.log +20 -24
  2. package/dist/109.js +1 -0
  3. package/dist/109.js.map +1 -0
  4. package/dist/124.js +1 -0
  5. package/dist/124.js.map +1 -0
  6. package/dist/125.js +1 -0
  7. package/dist/125.js.map +1 -0
  8. package/dist/130.js +1 -1
  9. package/dist/130.js.LICENSE.txt +2 -0
  10. package/dist/130.js.map +1 -1
  11. package/dist/146.js +1 -0
  12. package/dist/146.js.map +1 -0
  13. package/dist/15.js +1 -0
  14. package/dist/15.js.map +1 -0
  15. package/dist/153.js +1 -0
  16. package/dist/153.js.map +1 -0
  17. package/dist/303.js +2 -1
  18. package/dist/303.js.map +1 -1
  19. package/dist/325.js +1 -0
  20. package/dist/325.js.map +1 -0
  21. package/dist/372.js +2 -0
  22. package/dist/372.js.map +1 -0
  23. package/dist/471.js +1 -0
  24. package/dist/471.js.map +1 -0
  25. package/dist/481.js +1 -0
  26. package/dist/481.js.map +1 -0
  27. package/dist/53.js +1 -0
  28. package/dist/53.js.map +1 -0
  29. package/dist/{960.js → 559.js} +1 -1
  30. package/dist/559.js.map +1 -0
  31. package/dist/574.js +1 -1
  32. package/dist/576.js +1 -0
  33. package/dist/576.js.map +1 -0
  34. package/dist/577.js +1 -1
  35. package/dist/577.js.map +1 -1
  36. package/dist/{255.js → 649.js} +2 -2
  37. package/dist/649.js.LICENSE.txt +9 -0
  38. package/dist/649.js.map +1 -0
  39. package/dist/{659.js → 662.js} +1 -1
  40. package/dist/662.js.map +1 -0
  41. package/dist/920.js +1 -0
  42. package/dist/920.js.map +1 -0
  43. package/dist/921.js +1 -0
  44. package/dist/921.js.map +1 -0
  45. package/dist/922.js +1 -0
  46. package/dist/922.js.map +1 -0
  47. package/dist/969.js +1 -0
  48. package/dist/969.js.map +1 -0
  49. package/dist/kenyaemr-esm-ward-app.js +1 -1
  50. package/dist/kenyaemr-esm-ward-app.js.buildmanifest.json +304 -128
  51. package/dist/kenyaemr-esm-ward-app.js.map +1 -1
  52. package/dist/main.js +1 -1
  53. package/dist/main.js.LICENSE.txt +0 -10
  54. package/dist/main.js.map +1 -1
  55. package/dist/routes.json +1 -1
  56. package/mock.tsx +62 -0
  57. package/package-lock.json +5001 -0
  58. package/package.json +2 -3
  59. package/src/action-menu-buttons/clinical-forms-workspace-siderail.component.tsx +37 -0
  60. package/src/action-menu-buttons/discharge-workspace-siderail.component.tsx +20 -0
  61. package/src/beds/empty-bed-skeleton.tsx +4 -3
  62. package/src/beds/empty-bed.component.tsx +3 -3
  63. package/src/beds/ward-bed.component.tsx +41 -0
  64. package/src/beds/ward-bed.scss +45 -0
  65. package/src/beds/{occupied-bed.test.tsx → ward-bed.test.tsx} +42 -20
  66. package/src/config-schema.ts +203 -84
  67. package/src/constant.ts +1 -1
  68. package/src/hooks/useAdmissionLocation.ts +22 -4
  69. package/src/hooks/useAssignedBedByPatient.ts +9 -0
  70. package/src/hooks/useBeds.ts +3 -4
  71. package/src/hooks/useConcept.ts +3 -4
  72. package/src/hooks/useEmrConfiguration.ts +5 -0
  73. package/src/hooks/useInpatientAdmission.ts +9 -14
  74. package/src/hooks/useInpatientRequest.ts +4 -15
  75. package/src/hooks/useLocations.ts +8 -51
  76. package/src/hooks/useMotherAndChildren.ts +46 -0
  77. package/src/hooks/useObs.ts +3 -7
  78. package/src/hooks/usePatientPendingOrders.ts +16 -0
  79. package/src/hooks/useWardPatientGrouping.ts +32 -0
  80. package/src/index.ts +45 -17
  81. package/src/location-selector/location-selector.component.tsx +18 -21
  82. package/src/root.component.tsx +3 -0
  83. package/src/routes.json +41 -3
  84. package/src/types/index.ts +50 -1
  85. package/src/ward-patient-card/card-rows/admission-request-note-row.component.tsx +38 -0
  86. package/src/ward-patient-card/card-rows/coded-obs-tags-row.component.tsx +108 -0
  87. package/src/ward-patient-card/card-rows/mother-child-row.component.tsx +84 -0
  88. package/src/ward-patient-card/card-rows/mother-child-row.scss +22 -0
  89. package/src/ward-patient-card/card-rows/pending-items-row.component.tsx +54 -0
  90. package/src/ward-patient-card/row-elements/ward-patient-age.tsx +1 -1
  91. package/src/ward-patient-card/row-elements/ward-patient-coded-obs-tags.tsx +62 -39
  92. package/src/ward-patient-card/row-elements/ward-patient-header-address.tsx +5 -5
  93. package/src/ward-patient-card/row-elements/ward-patient-identifier.tsx +18 -41
  94. package/src/ward-patient-card/row-elements/ward-patient-location.tsx +19 -0
  95. package/src/ward-patient-card/row-elements/ward-patient-obs.resource.ts +38 -34
  96. package/src/ward-patient-card/row-elements/ward-patient-obs.tsx +26 -13
  97. package/src/ward-patient-card/row-elements/ward-patient-pending-order.component.tsx +45 -0
  98. package/src/ward-patient-card/row-elements/ward-patient-pending-transfer.tsx +38 -0
  99. package/src/ward-patient-card/row-elements/ward-patient-responsive-tooltip.tsx +32 -0
  100. package/src/ward-patient-card/row-elements/ward-patient-skeleton-text.tsx +9 -0
  101. package/src/ward-patient-card/ward-patient-card.component.tsx +14 -45
  102. package/src/ward-patient-card/ward-patient-card.scss +68 -9
  103. package/src/ward-view/default-ward/default-ward-beds.component.tsx +42 -0
  104. package/src/ward-view/default-ward/default-ward-patient-card-header.component.tsx +32 -0
  105. package/src/ward-view/default-ward/default-ward-patient-card.component.tsx +31 -0
  106. package/src/ward-view/default-ward/default-ward-pending-patients.component.tsx +52 -0
  107. package/src/ward-view/default-ward/default-ward-unassigned-patients.component.tsx +32 -0
  108. package/src/ward-view/default-ward/default-ward-view.component.tsx +31 -0
  109. package/src/ward-view/materal-ward/maternal-ward-beds.component.tsx +65 -0
  110. package/src/ward-view/materal-ward/maternal-ward-patient-card-header.component.tsx +30 -0
  111. package/src/ward-view/materal-ward/maternal-ward-patient-card.component.tsx +93 -0
  112. package/src/{beds/occupied-bed.scss → ward-view/materal-ward/maternal-ward-patient-card.scss} +4 -9
  113. package/src/ward-view/materal-ward/maternal-ward-patient-card.test.tsx +58 -0
  114. package/src/ward-view/materal-ward/maternal-ward-pending-patients.component.tsx +48 -0
  115. package/src/ward-view/materal-ward/maternal-ward-unassigned-patients.component.tsx +33 -0
  116. package/src/ward-view/materal-ward/maternal-ward-view.component.tsx +38 -0
  117. package/src/ward-view/materal-ward/maternal-ward-view.resource.ts +89 -0
  118. package/src/ward-view/ward-view.component.tsx +15 -163
  119. package/src/ward-view/ward-view.resource.ts +193 -1
  120. package/src/ward-view/ward-view.scss +17 -6
  121. package/src/ward-view/ward-view.test.tsx +43 -48
  122. package/src/ward-view/ward.component.tsx +106 -0
  123. package/src/ward-view-header/admission-requests-bar.component.tsx +14 -9
  124. package/src/ward-view-header/admission-requests-bar.test.tsx +11 -23
  125. package/src/ward-view-header/admission-requests.scss +1 -1
  126. package/src/ward-view-header/ward-metric.component.tsx +24 -0
  127. package/src/ward-view-header/ward-metric.scss +25 -0
  128. package/src/ward-view-header/ward-metrics.component.tsx +78 -0
  129. package/src/ward-view-header/ward-metrics.scss +7 -0
  130. package/src/ward-view-header/ward-metrics.test.tsx +37 -0
  131. package/src/ward-view-header/ward-view-header.component.tsx +9 -4
  132. package/src/ward-view-header/ward-view-header.scss +0 -1
  133. package/src/ward-workspace/admission-request-card/admission-request-card-actions.component.tsx +70 -6
  134. package/src/ward-workspace/admission-request-card/admission-request-card-header.component.tsx +10 -23
  135. package/src/ward-workspace/admission-request-card/admission-request-card.component.tsx +9 -3
  136. package/src/ward-workspace/admission-request-card/admission-request-card.scss +13 -4
  137. package/src/ward-workspace/admission-request-workspace/admission-requests-workspace.test.tsx +55 -33
  138. package/src/ward-workspace/admission-request-workspace/admission-requests.workspace.tsx +30 -37
  139. package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.test.tsx +98 -203
  140. package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.workspace.tsx +116 -180
  141. package/src/ward-workspace/bed-selector.component.tsx +119 -0
  142. package/src/ward-workspace/bed-selector.scss +15 -0
  143. package/src/ward-workspace/patient-banner/patient-banner.component.tsx +7 -14
  144. package/src/ward-workspace/patient-clinical-forms-workspace/patient-clinical-forms.workspace.tsx +23 -0
  145. package/src/{ward-patient-workspace → ward-workspace/patient-details}/ward-patient-action-button.extension.tsx +2 -1
  146. package/src/{ward-patient-workspace → ward-workspace/patient-details}/ward-patient.workspace.tsx +18 -9
  147. package/src/ward-workspace/patient-discharge/patient-discharge.scss +41 -0
  148. package/src/ward-workspace/patient-discharge/patient-discharge.workspace.tsx +113 -0
  149. package/src/ward-workspace/patient-transfer-bed-swap/patient-bed-swap-form.component.tsx +68 -79
  150. package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-request-form.component.tsx +24 -24
  151. package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-swap.scss +12 -2
  152. package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-swap.workspace.tsx +12 -8
  153. package/src/ward-workspace/patient-transfer-request-workspace/patient-transfer-request.workspace.tsx +11 -0
  154. package/src/ward-workspace/ward-patient-notes/form/notes-form.component.tsx +1 -1
  155. package/src/ward-workspace/ward-patient-notes/form/notes-form.test.tsx +1 -1
  156. package/src/ward-workspace/ward-patient-notes/history/notes-container.component.tsx +2 -2
  157. package/src/ward-workspace/ward-patient-notes/notes.resource.ts +5 -7
  158. package/src/ward-workspace/ward-patient-notes/notes.workspace.tsx +1 -1
  159. package/src/ward-workspace/ward-patient-notes/types.ts +0 -4
  160. package/src/ward.resource.ts +38 -2
  161. package/translations/en.json +31 -7
  162. package/dist/152.js +0 -1
  163. package/dist/152.js.map +0 -1
  164. package/dist/255.js.map +0 -1
  165. package/dist/269.js +0 -1
  166. package/dist/269.js.map +0 -1
  167. package/dist/346.js +0 -1
  168. package/dist/346.js.map +0 -1
  169. package/dist/466.js +0 -1
  170. package/dist/466.js.map +0 -1
  171. package/dist/659.js.map +0 -1
  172. package/dist/729.js +0 -1
  173. package/dist/729.js.map +0 -1
  174. package/dist/749.js +0 -1
  175. package/dist/749.js.map +0 -1
  176. package/dist/76.js +0 -1
  177. package/dist/76.js.map +0 -1
  178. package/dist/793.js +0 -2
  179. package/dist/793.js.map +0 -1
  180. package/dist/803.js +0 -1
  181. package/dist/803.js.map +0 -1
  182. package/dist/960.js.map +0 -1
  183. package/src/beds/empty-bed.scss +0 -28
  184. package/src/beds/occupied-bed.component.tsx +0 -35
  185. package/src/beds/unassigned-patient.component.tsx +0 -20
  186. package/src/beds/unassigned-patient.scss +0 -6
  187. package/src/config-schema-admission-request-note.ts +0 -9
  188. package/src/config-schema-extension-colored-obs-tags.ts +0 -91
  189. package/src/hooks/useCurrentWardCardConfig.ts +0 -32
  190. package/src/ward-patient-card/card-rows/admission-request-note.extension.tsx +0 -27
  191. package/src/ward-patient-card/card-rows/colored-obs-tags-card-row.extension.tsx +0 -13
  192. package/src/ward-patient-card/ward-patient-card-element.component.tsx +0 -65
  193. package/src/ward-view/ward-bed.component.tsx +0 -14
  194. /package/dist/{793.js.LICENSE.txt → 303.js.LICENSE.txt} +0 -0
  195. /package/dist/{255.js.LICENSE.txt → 372.js.LICENSE.txt} +0 -0
  196. /package/src/{ward-patient-workspace → ward-workspace/patient-details}/ward-patient.style.scss +0 -0
@@ -1,59 +1,28 @@
1
- import { ExtensionSlot, getPatientName, launchWorkspace } from '@openmrs/esm-framework';
2
- import classNames from 'classnames';
3
- import React from 'react';
4
- import { useCurrentWardCardConfig } from '../hooks/useCurrentWardCardConfig';
5
- import { type WardPatientCard, type WardPatientWorkspaceProps } from '../types';
6
- import WardPatientBedNumber from './row-elements/ward-patient-bed-number';
7
- import WardPatientName from './row-elements/ward-patient-name';
8
- import { WardPatientCardElement } from './ward-patient-card-element.component';
1
+ import { getPatientName, launchWorkspace, useAppContext } from '@openmrs/esm-framework';
2
+ import React, { type ReactNode } from 'react';
3
+ import { type WardViewContext, type WardPatient,type PatientWorkspaceAdditionalProps } from '../types';
9
4
  import styles from './ward-patient-card.scss';
10
5
 
11
- const WardPatientCard: WardPatientCard = (wardPatient) => {
12
- const { patient, bed } = wardPatient;
13
- const { id, headerRowElements, footerRowElements } = useCurrentWardCardConfig();
6
+ interface Props {
7
+ children: ReactNode;
8
+ wardPatient: WardPatient;
9
+ }
14
10
 
15
- const headerExtensionSlotName =
16
- id == 'default' ? 'ward-patient-card-header-slot' : `ward-patient-card-header-${id}-slot`;
17
- const rowsExtensionSlotName = id == 'default' ? 'ward-patient-card-slot' : `ward-patient-card-${id}-slot`;
18
- const footerExtensionSlotName =
19
- id == 'default' ? 'ward-patient-card-footer-slot' : `ward-patient-card-footer-${id}-slot`;
11
+ const WardPatientCard: React.FC<Props> = ({ children, wardPatient }) => {
12
+ const { patient } = wardPatient;
13
+ const { WardPatientHeader } = useAppContext<WardViewContext>('ward-view-context') ?? {};
20
14
 
21
15
  return (
22
16
  <div className={styles.wardPatientCard}>
23
- <div className={classNames(styles.wardPatientCardRow, styles.wardPatientCardHeader)}>
24
- {bed ? <WardPatientBedNumber bed={bed} /> : null}
25
- <WardPatientName patient={patient} />
26
- {headerRowElements.map((elementId, i) => (
27
- <WardPatientCardElement
28
- key={`ward-card-${patient.uuid}-header-${i}`}
29
- elementId={elementId}
30
- {...wardPatient}
31
- />
32
- ))}
33
- <ExtensionSlot name={headerExtensionSlotName} state={wardPatient} />
34
- </div>
35
- <ExtensionSlot
36
- name={rowsExtensionSlotName}
37
- state={wardPatient}
38
- className={classNames(styles.wardPatientCardRow, styles.wardPatientCardExtensionSlot)}
39
- />
40
- <div className={styles.wardPatientCardRow}>
41
- {footerRowElements.map((elementId, i) => (
42
- <WardPatientCardElement
43
- key={`ward-card-${patient.uuid}-footer-${i}`}
44
- elementId={elementId}
45
- {...wardPatient}
46
- />
47
- ))}
48
- <ExtensionSlot name={footerExtensionSlotName} state={wardPatient} />
49
- </div>
17
+ {children}
50
18
  <button
51
19
  className={styles.wardPatientCardButton}
52
20
  onClick={() => {
53
- launchWorkspace<WardPatientWorkspaceProps>('ward-patient-workspace', {
21
+ launchWorkspace<PatientWorkspaceAdditionalProps>('ward-patient-workspace', {
54
22
  wardPatient,
23
+ WardPatientHeader
55
24
  });
56
- }}>
25
+ }}>
57
26
  {/* Name will not be displayed; just there for a11y */}
58
27
  {getPatientName(patient.person)}
59
28
  </button>
@@ -14,10 +14,6 @@
14
14
  background-color: $ui-02;
15
15
 
16
16
  position: relative; // this allows positioning the button correctly
17
-
18
- > .wardPatientCardRow:not(:first-child) {
19
- border-top: 1px colors.$gray-20 solid;
20
- }
21
17
  }
22
18
 
23
19
  .wardPatientCardButton {
@@ -59,24 +55,52 @@
59
55
  .wardPatientCardRow {
60
56
  width: 100%;
61
57
  padding: layout.$spacing-04;
58
+ border-top: 1px colors.$gray-20 solid;
59
+ background-color: colors.$white;
60
+
61
+ &:empty {
62
+ border-top: 0px;
63
+ display: none;
64
+ }
62
65
  }
63
66
 
64
- .wardPatientCardRow:empty {
67
+ .wardPatientPendingOrdersRow:empty {
65
68
  display: none;
69
+ margin-left: layout.$spacing-04;
66
70
  }
67
71
 
68
72
  .wardPatientCardExtensionSlot {
69
73
  display: none;
74
+ width: 100%;
70
75
 
71
76
  &:has(div:not(:empty)) {
72
77
  display: block;
73
78
  }
74
79
  }
75
80
 
81
+ .wardPatientCardPendingItemsRow:empty {
82
+ display: none;
83
+ margin-left: layout.$spacing-04;
84
+ }
85
+
86
+ .wardPatientCardPendingItemsRow {
87
+ @extend .wardPatientCardRow;
88
+ display: flex;
89
+ align-items: center;
90
+ flex-flow: row wrap;
91
+ color: $ui-02;
92
+ background-color: colors.$gray-80;
93
+ }
94
+
76
95
  .wardPatientCardHeader {
77
96
  @extend .dotSeparatedChildren;
97
+ border-top: 0;
98
+ }
99
+
100
+ .wardPatientCardDispositionTypeContainer {
78
101
  display: flex;
79
- flex-wrap: wrap;
102
+ flex-flow: row;
103
+ align-items: center;
80
104
  }
81
105
 
82
106
  .wardPatientName {
@@ -112,10 +136,26 @@
112
136
  align-items: center;
113
137
  }
114
138
 
139
+ .movementIcon {
140
+ padding: layout.$spacing-02;
141
+ border-radius: 50%;
142
+ fill: $ui-03;
143
+ background-color: $color-blue-60-2;
144
+ margin-left: layout.$spacing-03;
145
+ margin-right: layout.$spacing-02;
146
+ }
147
+
148
+ .chemistryReferenceIcon {
149
+ padding: layout.$spacing-02;
150
+ border-radius: 50%;
151
+ fill: $ui-03;
152
+ background-color: #a2191f;
153
+ margin-left: layout.$spacing-03;
154
+ margin-right: layout.$spacing-02;
155
+ }
156
+
115
157
  .wardPatientAddress {
116
158
  @extend .dotSeparatedChildren;
117
- display: flex;
118
- flex-wrap: wrap;
119
159
  align-items: center;
120
160
  gap: layout.$spacing-02;
121
161
  }
@@ -124,8 +164,18 @@
124
164
  padding-right: layout.$spacing-02;
125
165
  }
126
166
 
167
+ .responsiveTooltip {
168
+ z-index: 2;
169
+ & :global(.cds--tag) {
170
+ border: 0;
171
+ }
172
+ }
173
+
127
174
  .dotSeparatedChildren {
128
- > div:not(div:first-of-type):not(:empty) {
175
+ display: flex;
176
+ flex-wrap: wrap;
177
+
178
+ > *:not(*:first-of-type):not(:empty) {
129
179
  display: flex;
130
180
  align-items: center;
131
181
 
@@ -135,3 +185,12 @@
135
185
  }
136
186
  }
137
187
  }
188
+
189
+ .skeletonText {
190
+ width: 6.25rem;
191
+ }
192
+
193
+ .unassignedPatient {
194
+ display: flex;
195
+ flex-direction: column;
196
+ }
@@ -0,0 +1,42 @@
1
+ import { useAppContext } from '@openmrs/esm-framework';
2
+ import React from 'react';
3
+ import WardBed from '../../beds/ward-bed.component';
4
+ import { type WardPatient, type WardViewContext } from '../../types';
5
+ import { bedLayoutToBed } from '../ward-view.resource';
6
+ import DefaultWardPatientCard from './default-ward-patient-card.component';
7
+
8
+ function DefaultWardBeds() {
9
+ const {wardPatientGroupDetails} = useAppContext<WardViewContext>('ward-view-context') ?? {};
10
+ const { bedLayouts, wardAdmittedPatientsWithBed } = wardPatientGroupDetails ?? {};
11
+
12
+ const wardBeds = bedLayouts?.map((bedLayout) => {
13
+ const { patients } = bedLayout;
14
+ const bed = bedLayoutToBed(bedLayout);
15
+ const wardPatients: WardPatient[] = patients.map((patient): WardPatient => {
16
+ const inpatientAdmission = wardAdmittedPatientsWithBed?.get(patient.uuid);
17
+ if (inpatientAdmission) {
18
+ const { patient, visit, currentInpatientRequest } = inpatientAdmission;
19
+ return { patient, visit, bed, inpatientAdmission, inpatientRequest: currentInpatientRequest || null };
20
+ } else {
21
+ // for some reason this patient is in a bed but not in the list of admitted patients, so we need to use the patient data from the bed endpoint
22
+ return {
23
+ patient: patient,
24
+ visit: null,
25
+ bed,
26
+ inpatientAdmission: null, // populate after BED-13
27
+ inpatientRequest: null,
28
+ };
29
+ }
30
+ });
31
+ const patientCards = wardPatients.map(wardPatient => (
32
+ <DefaultWardPatientCard
33
+ key={wardPatient.patient.uuid}
34
+ {...wardPatient} />
35
+ ));
36
+ return <WardBed key={bed.uuid} bed={bed} patientCards={patientCards} />;
37
+ });
38
+
39
+ return <>{wardBeds}</>;
40
+ }
41
+
42
+ export default DefaultWardBeds;
@@ -0,0 +1,32 @@
1
+ import classNames from 'classnames';
2
+ import React from 'react';
3
+ import WardPatientAge from '../../ward-patient-card/row-elements/ward-patient-age';
4
+ import WardPatientBedNumber from '../../ward-patient-card/row-elements/ward-patient-bed-number';
5
+ import WardPatientIdentifier from '../../ward-patient-card/row-elements/ward-patient-identifier';
6
+ import WardPatientName from '../../ward-patient-card/row-elements/ward-patient-name';
7
+ import WardPatientTimeOnWard from '../../ward-patient-card/row-elements/ward-patient-time-on-ward';
8
+ import WardPatientTimeSinceAdmission from '../../ward-patient-card/row-elements/ward-patient-time-since-admission';
9
+ import styles from '../../ward-patient-card/ward-patient-card.scss';
10
+ import { type WardPatientCardType } from '../../types';
11
+ import WardPatientGender from '../../ward-patient-card/row-elements/ward-patient-gender.component';
12
+
13
+ const DefaultWardPatientCardHeader: WardPatientCardType = (wardPatient) => {
14
+ const { patient, bed, inpatientAdmission } = wardPatient;
15
+ const { encounterAssigningToCurrentInpatientLocation, firstAdmissionOrTransferEncounter } = inpatientAdmission ?? {};
16
+
17
+ return (
18
+ <div className={classNames(styles.wardPatientCardRow, styles.wardPatientCardHeader)}>
19
+ {bed ? <WardPatientBedNumber bed={bed} /> : null}
20
+ <WardPatientName patient={patient} />
21
+ <WardPatientIdentifier id="patient-identifier" patient={patient} />
22
+ <WardPatientGender patient={patient} />
23
+ <WardPatientAge patient={patient} />
24
+ <WardPatientTimeSinceAdmission firstAdmissionOrTransferEncounter={firstAdmissionOrTransferEncounter} />
25
+ <WardPatientTimeOnWard
26
+ encounterAssigningToCurrentInpatientLocation={encounterAssigningToCurrentInpatientLocation}
27
+ />
28
+ </div>
29
+ );
30
+ };
31
+
32
+ export default DefaultWardPatientCardHeader;
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+ import { type WardPatientCardType } from '../../types';
3
+ import AdmissionRequestNoteRow from '../../ward-patient-card/card-rows/admission-request-note-row.component';
4
+ import PendingItemsRow from '../../ward-patient-card/card-rows/pending-items-row.component';
5
+ import WardPatientCard from '../../ward-patient-card/ward-patient-card.component';
6
+ import styles from '../../ward-patient-card/ward-patient-card.scss';
7
+ import DefaultWardPatientCardHeader from './default-ward-patient-card-header.component';
8
+
9
+ const DefaultWardPatientCard: WardPatientCardType = (wardPatient) => {
10
+ const { bed } = wardPatient;
11
+
12
+ const card = (
13
+ <WardPatientCard wardPatient={wardPatient}>
14
+ <DefaultWardPatientCardHeader {...wardPatient} />
15
+ <PendingItemsRow id={'pending-items'} wardPatient={wardPatient} />
16
+ <AdmissionRequestNoteRow id={'admission-request-note'} wardPatient={wardPatient} />
17
+ </WardPatientCard>
18
+ );
19
+
20
+ if (bed) {
21
+ return card;
22
+ } else {
23
+ return (
24
+ <div className={styles.unassignedPatient}>
25
+ <div key={'unassigned-bed-pt-' + wardPatient.patient.uuid}>{card}</div>
26
+ </div>
27
+ );
28
+ }
29
+ };
30
+
31
+ export default DefaultWardPatientCard;
@@ -0,0 +1,52 @@
1
+ import { ErrorState, useAppContext } from '@openmrs/esm-framework';
2
+ import React from 'react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { type WardViewContext, type InpatientRequest } from '../../types';
5
+ import AdmissionRequestCard from '../../ward-workspace/admission-request-card/admission-request-card.component';
6
+ import WardPatientSkeletonText from '../../ward-patient-card/row-elements/ward-patient-skeleton-text';
7
+ import AdmissionRequestNoteRow from '../../ward-patient-card/card-rows/admission-request-note-row.component';
8
+
9
+ function DefaultWardPendingPatients() {
10
+ const { wardPatientGroupDetails } = useAppContext<WardViewContext>('ward-view-context') ?? {};
11
+ const { t } = useTranslation();
12
+ const { inpatientRequestResponse } = wardPatientGroupDetails ?? {};
13
+ const {
14
+ inpatientRequests,
15
+ isLoading: isLoadingInpatientRequests,
16
+ error: errorFetchingInpatientRequests,
17
+ } = inpatientRequestResponse ?? {};
18
+
19
+ return isLoadingInpatientRequests ? (
20
+ <WardPatientSkeletonText />
21
+ ) : errorFetchingInpatientRequests ? (
22
+ <ErrorState headerTitle={t('admissionRequests', 'Admission requests')} error={errorFetchingInpatientRequests} />
23
+ ) : (
24
+ <>
25
+ {inpatientRequests?.map((request: InpatientRequest, i) => {
26
+ const wardPatient = {
27
+ patient: request.patient,
28
+ visit: request.visit,
29
+ bed: null,
30
+ inpatientRequest: request,
31
+ inpatientAdmission: null,
32
+ };
33
+
34
+ return (
35
+ <AdmissionRequestCard
36
+ key={`admission-request-card-${i}`}
37
+ wardPatient={{
38
+ patient: request.patient,
39
+ visit: request.visit,
40
+ bed: null,
41
+ inpatientRequest: request,
42
+ inpatientAdmission: null,
43
+ }}>
44
+ <AdmissionRequestNoteRow id={'admission-request-note'} wardPatient={wardPatient} />
45
+ </AdmissionRequestCard>
46
+ );
47
+ })}
48
+ </>
49
+ );
50
+ }
51
+
52
+ export default DefaultWardPendingPatients;
@@ -0,0 +1,32 @@
1
+ import { useAppContext } from '@openmrs/esm-framework';
2
+ import React from 'react';
3
+ import { type WardViewContext } from '../../types';
4
+ import DefaultWardPatientCard from './default-ward-patient-card.component';
5
+
6
+ /**
7
+ * Renders a list of patients in the ward that are admitted but not assigned a bed
8
+ * @returns
9
+ */
10
+ function DefaultWardUnassignedPatients() {
11
+ const {wardPatientGroupDetails} = useAppContext<WardViewContext>('ward-view-context') ?? {};
12
+ const { wardUnassignedPatientsList } = wardPatientGroupDetails ?? {};
13
+
14
+ const wardUnassignedPatients = wardUnassignedPatientsList?.map((inpatientAdmission) => {
15
+ return (
16
+ <DefaultWardPatientCard
17
+ {...{
18
+ patient: inpatientAdmission.patient,
19
+ visit: inpatientAdmission.visit,
20
+ bed: null,
21
+ inpatientAdmission,
22
+ inpatientRequest: inpatientAdmission.currentInpatientRequest,
23
+ }}
24
+ key={inpatientAdmission.patient.uuid}
25
+ />
26
+ );
27
+ });
28
+
29
+ return <>{wardUnassignedPatients}</>;
30
+ }
31
+
32
+ export default DefaultWardUnassignedPatients;
@@ -0,0 +1,31 @@
1
+ import { useDefineAppContext } from '@openmrs/esm-framework';
2
+ import React from 'react';
3
+ import { useWardPatientGrouping } from '../../hooks/useWardPatientGrouping';
4
+ import { type WardViewContext } from '../../types';
5
+ import WardViewHeader from '../../ward-view-header/ward-view-header.component';
6
+ import Ward from '../ward.component';
7
+ import DefaultWardBeds from './default-ward-beds.component';
8
+ import DefaultWardPendingPatients from './default-ward-pending-patients.component';
9
+ import DefaultWardUnassignedPatients from './default-ward-unassigned-patients.component';
10
+ import DefaultWardPatientCardHeader from './default-ward-patient-card-header.component';
11
+
12
+ const DefaultWardView = () => {
13
+ const wardPatientGroupDetails = useWardPatientGrouping();
14
+ useDefineAppContext<WardViewContext>('ward-view-context', {
15
+ wardPatientGroupDetails,
16
+ WardPatientHeader: DefaultWardPatientCardHeader
17
+ });
18
+
19
+ const wardBeds = <DefaultWardBeds />;
20
+ const wardUnassignedPatients = <DefaultWardUnassignedPatients />;
21
+ const wardPendingPatients = <DefaultWardPendingPatients />;
22
+
23
+ return (
24
+ <>
25
+ <WardViewHeader {...{ wardPendingPatients }} />
26
+ <Ward {...{ wardBeds, wardUnassignedPatients }} />
27
+ </>
28
+ );
29
+ };
30
+
31
+ export default DefaultWardView;
@@ -0,0 +1,65 @@
1
+ import { useAppContext } from '@openmrs/esm-framework';
2
+ import React from 'react';
3
+ import WardBed from '../../beds/ward-bed.component';
4
+ import { type MotherChildRelationships, type WardPatient, type WardViewContext } from '../../types';
5
+ import { bedLayoutToBed } from '../ward-view.resource';
6
+ import MaternalWardPatientCard from './maternal-ward-patient-card.component';
7
+
8
+ const MaternalWardBeds: React.FC<MotherChildRelationships> = (motherChildRelationships) => {
9
+ const { motherByChildUuid } = motherChildRelationships ?? {};
10
+ const { wardPatientGroupDetails } = useAppContext<WardViewContext>('ward-view-context') ?? {};
11
+ const { bedLayouts, wardAdmittedPatientsWithBed } = wardPatientGroupDetails ?? {};
12
+
13
+ const wardBeds = bedLayouts?.map((bedLayout) => {
14
+ const { patients: patientsInCurrentBed } = bedLayout;
15
+ const bed = bedLayoutToBed(bedLayout);
16
+ const childrenInSameBedByMotherUuid = new Map<string, WardPatient[]>();
17
+
18
+ const wardPatients: WardPatient[] = patientsInCurrentBed
19
+ .map((patient): WardPatient => {
20
+ const inpatientAdmission = wardAdmittedPatientsWithBed?.get(patient.uuid);
21
+ if (inpatientAdmission) {
22
+ const { patient, visit, currentInpatientRequest } = inpatientAdmission;
23
+ return { patient, visit, bed, inpatientAdmission, inpatientRequest: currentInpatientRequest || null };
24
+ } else {
25
+ // for some reason this patient is in a bed but not in the list of admitted patients,
26
+ // so we need to use the patient data from the bed endpoint
27
+ return {
28
+ patient: patient,
29
+ visit: null,
30
+ bed,
31
+ inpatientAdmission: null,
32
+ inpatientRequest: null,
33
+ };
34
+ }
35
+ })
36
+ .filter((wardPatient) => {
37
+ // filter out any child patient whose mother is also assigned to the same bed
38
+ // and put the child in childrenInSameBedByMotherUuid
39
+ const patientUuid = wardPatient.patient.uuid;
40
+ const { patient: mother } = motherByChildUuid?.get(patientUuid) ?? {};
41
+ const motherInSameBed = patientsInCurrentBed.some((p) => p.uuid == mother?.uuid);
42
+ if (motherInSameBed) {
43
+ if (!childrenInSameBedByMotherUuid.has(mother.uuid)) {
44
+ childrenInSameBedByMotherUuid.set(mother.uuid, []);
45
+ }
46
+ childrenInSameBedByMotherUuid.get(mother.uuid).push(wardPatient);
47
+ }
48
+ return !motherInSameBed;
49
+ });
50
+
51
+ const patientCards = wardPatients.map((wardPatient) => (
52
+ <MaternalWardPatientCard
53
+ key={wardPatient.patient.uuid}
54
+ wardPatient={wardPatient}
55
+ childrenOfWardPatientInSameBed={childrenInSameBedByMotherUuid.get(wardPatient.patient.uuid)}
56
+ />
57
+ ));
58
+
59
+ return <WardBed key={bed.uuid} bed={bed} patientCards={patientCards} />;
60
+ });
61
+
62
+ return <>{wardBeds}</>;
63
+ };
64
+
65
+ export default MaternalWardBeds;
@@ -0,0 +1,30 @@
1
+ import classNames from 'classnames';
2
+ import React from 'react';
3
+ import { type WardPatientCardType } from '../../types';
4
+ import WardPatientAge from '../../ward-patient-card/row-elements/ward-patient-age';
5
+ import WardPatientBedNumber from '../../ward-patient-card/row-elements/ward-patient-bed-number';
6
+ import WardPatientAddress from '../../ward-patient-card/row-elements/ward-patient-header-address';
7
+ import WardPatientIdentifier from '../../ward-patient-card/row-elements/ward-patient-identifier';
8
+ import WardPatientName from '../../ward-patient-card/row-elements/ward-patient-name';
9
+ import WardPatientObs from '../../ward-patient-card/row-elements/ward-patient-obs';
10
+ import WardPatientTimeSinceAdmission from '../../ward-patient-card/row-elements/ward-patient-time-since-admission';
11
+ import styles from '../../ward-patient-card/ward-patient-card.scss';
12
+
13
+ const MaternalWardPatientCardHeader: WardPatientCardType = (wardPatient) => {
14
+ const { patient, bed, visit, inpatientAdmission } = wardPatient;
15
+ const { firstAdmissionOrTransferEncounter } = inpatientAdmission ?? {};
16
+
17
+ return (
18
+ <div className={classNames(styles.wardPatientCardRow, styles.wardPatientCardHeader)}>
19
+ {bed ? <WardPatientBedNumber bed={bed} /> : null}
20
+ <WardPatientName patient={patient} />
21
+ <WardPatientIdentifier id="patient-identifier" patient={patient} />
22
+ <WardPatientAge patient={patient} />
23
+ <WardPatientAddress id={'patient-address'} patient={patient} />
24
+ <WardPatientObs id={'admission-reason'} patient={patient} visit={visit} />
25
+ <WardPatientTimeSinceAdmission firstAdmissionOrTransferEncounter={firstAdmissionOrTransferEncounter} />
26
+ </div>
27
+ );
28
+ };
29
+
30
+ export default MaternalWardPatientCardHeader;
@@ -0,0 +1,93 @@
1
+ import { Tag } from '@carbon/react';
2
+ import classNames from 'classnames';
3
+ import React from 'react';
4
+ import { useTranslation } from 'react-i18next';
5
+ import { type WardPatient } from '../../types';
6
+ import CodedObsTagsRow from '../../ward-patient-card/card-rows/coded-obs-tags-row.component';
7
+ import MotherChildRow from '../../ward-patient-card/card-rows/mother-child-row.component';
8
+ import PendingItemsRow from '../../ward-patient-card/card-rows/pending-items-row.component';
9
+ import WardPatientObs from '../../ward-patient-card/row-elements/ward-patient-obs';
10
+ import WardPatientTimeOnWard from '../../ward-patient-card/row-elements/ward-patient-time-on-ward';
11
+ import WardPatientCard from '../../ward-patient-card/ward-patient-card.component';
12
+ import styles from '../../ward-patient-card/ward-patient-card.scss';
13
+ import MaternalWardPatientCardHeader from './maternal-ward-patient-card-header.component';
14
+ import maternalWardPatientCardStyles from './maternal-ward-patient-card.scss';
15
+
16
+ export interface MaternalWardPatientCardProps {
17
+ /**
18
+ * the patient to render. Note that this patient can be a mother or a child
19
+ */
20
+ wardPatient: WardPatient;
21
+
22
+ /**
23
+ * Children of the wardPatient occupying the same bed. A non-empty array implies that the wardPatient
24
+ * is a mother.
25
+ */
26
+ childrenOfWardPatientInSameBed: WardPatient[];
27
+ }
28
+
29
+ /**
30
+ * One major different between MaternalWardPatientCard vs DefaultWardPatientCard, besides the
31
+ * different elements being rendered, is that it renders just not the patient card for the patient,
32
+ * but also those of the the patient's children in same bed. This is done to ensure that the children's
33
+ * patient cards are always rendered right below the mother's.
34
+ *
35
+ * @param param0
36
+ * @returns
37
+ */
38
+ const MaternalWardPatientCard: React.FC<MaternalWardPatientCardProps> = (props) => {
39
+ const { wardPatient, childrenOfWardPatientInSameBed } = props;
40
+ const { patient, visit, bed, inpatientAdmission } = wardPatient;
41
+ const { encounterAssigningToCurrentInpatientLocation } = inpatientAdmission ?? {};
42
+
43
+ const card = (
44
+ <>
45
+ <WardPatientCard wardPatient={wardPatient}>
46
+ <MaternalWardPatientCardHeader {...wardPatient} />
47
+ <div className={classNames(styles.wardPatientCardRow, styles.dotSeparatedChildren)}>
48
+ <WardPatientTimeOnWard
49
+ encounterAssigningToCurrentInpatientLocation={encounterAssigningToCurrentInpatientLocation}
50
+ />
51
+ <WardPatientObs id={'gravida'} patient={patient} visit={visit} />
52
+ </div>
53
+ <PendingItemsRow id={'pending-items'} wardPatient={wardPatient} />
54
+ <CodedObsTagsRow id="pregnancy-complications" {...wardPatient} />
55
+ <MotherChildRow {...props} />
56
+ </WardPatientCard>
57
+ {childrenOfWardPatientInSameBed?.map((childWardPatient) => {
58
+ return (
59
+ <React.Fragment key={childWardPatient.patient.uuid}>
60
+ <MotherChildBedShareDivider />
61
+ <WardPatientCard wardPatient={childWardPatient}>
62
+ <MaternalWardPatientCardHeader {...childWardPatient} />
63
+ <PendingItemsRow id={'pending-items'} wardPatient={childWardPatient} />
64
+ </WardPatientCard>
65
+ </React.Fragment>
66
+ );
67
+ })}
68
+ </>
69
+ );
70
+
71
+ if (bed) {
72
+ return card;
73
+ } else {
74
+ return (
75
+ <div className={styles.unassignedPatient}>
76
+ <div key={'unassigned-bed-pt-' + wardPatient.patient.uuid}>{card}</div>
77
+ </div>
78
+ );
79
+ }
80
+ };
81
+
82
+ const MotherChildBedShareDivider = () => {
83
+ const { t } = useTranslation();
84
+ return (
85
+ <div className={maternalWardPatientCardStyles.motherChildBedDivider}>
86
+ <div className={maternalWardPatientCardStyles.motherChildBedDividerLine}></div>
87
+ <Tag type="purple">{t('motherChildBedShare', 'Mother / Child')}</Tag>
88
+ <div className={maternalWardPatientCardStyles.motherChildBedDividerLine}></div>
89
+ </div>
90
+ );
91
+ };
92
+
93
+ export default MaternalWardPatientCard;
@@ -1,13 +1,8 @@
1
1
  @use '@carbon/layout';
2
2
  @use '@openmrs/esm-styleguide/src/vars';
3
+ @use '@carbon/type';
3
4
 
4
- .occupiedBed {
5
- display: flex;
6
- flex-direction: column;
7
- background-color: vars.$ui-02;
8
- }
9
-
10
- .bedDivider {
5
+ .motherChildBedDivider {
11
6
  background-color: vars.$ui-02;
12
7
  color: vars.$text-02;
13
8
  padding: layout.$spacing-01;
@@ -16,8 +11,8 @@
16
11
  justify-content: space-between;
17
12
  }
18
13
 
19
- .bedDividerLine {
14
+ .motherChildBedDividerLine {
20
15
  height: 1px;
21
- background-color: vars.$ui-05;
22
16
  width: 30%;
17
+ border-top: 1px dashed vars.$ui-05;
23
18
  }