@kenyaemr/esm-ward-app 8.1.1-pre.118 → 8.1.1-pre.119

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 (149) hide show
  1. package/.turbo/turbo-build.log +16 -20
  2. package/dist/124.js +1 -0
  3. package/dist/124.js.map +1 -0
  4. package/dist/125.js +1 -1
  5. package/dist/125.js.map +1 -1
  6. package/dist/130.js +1 -1
  7. package/dist/130.js.map +1 -1
  8. package/dist/153.js +1 -0
  9. package/dist/153.js.map +1 -0
  10. package/dist/372.js +1 -1
  11. package/dist/372.js.map +1 -1
  12. package/dist/471.js +1 -0
  13. package/dist/471.js.map +1 -0
  14. package/dist/481.js +1 -0
  15. package/dist/481.js.map +1 -0
  16. package/dist/53.js +1 -1
  17. package/dist/53.js.map +1 -1
  18. package/dist/559.js +1 -1
  19. package/dist/559.js.map +1 -1
  20. package/dist/574.js +1 -1
  21. package/dist/{500.js → 576.js} +1 -1
  22. package/dist/576.js.map +1 -0
  23. package/dist/577.js +1 -1
  24. package/dist/577.js.map +1 -1
  25. package/dist/649.js +2 -0
  26. package/dist/{161.js.LICENSE.txt → 649.js.LICENSE.txt} +0 -6
  27. package/dist/649.js.map +1 -0
  28. package/dist/{659.js → 662.js} +1 -1
  29. package/dist/662.js.map +1 -0
  30. package/dist/67.js +2 -0
  31. package/dist/67.js.LICENSE.txt +5 -0
  32. package/dist/67.js.map +1 -0
  33. package/dist/920.js +1 -0
  34. package/dist/920.js.map +1 -0
  35. package/dist/921.js +1 -0
  36. package/dist/921.js.map +1 -0
  37. package/dist/922.js +1 -1
  38. package/dist/922.js.map +1 -1
  39. package/dist/kenyaemr-esm-ward-app.js +1 -1
  40. package/dist/kenyaemr-esm-ward-app.js.buildmanifest.json +148 -165
  41. package/dist/kenyaemr-esm-ward-app.js.map +1 -1
  42. package/dist/main.js +1 -1
  43. package/dist/main.js.LICENSE.txt +0 -10
  44. package/dist/main.js.map +1 -1
  45. package/dist/routes.json +1 -1
  46. package/mock.tsx +8 -0
  47. package/package.json +1 -1
  48. package/src/beds/empty-bed-skeleton.tsx +3 -3
  49. package/src/beds/empty-bed.component.tsx +3 -3
  50. package/src/beds/ward-bed.component.tsx +41 -0
  51. package/src/beds/ward-bed.scss +45 -0
  52. package/src/beds/{occupied-bed.test.tsx → ward-bed.test.tsx} +27 -16
  53. package/src/config-schema.ts +196 -75
  54. package/src/hooks/useAssignedBedByPatient.ts +9 -0
  55. package/src/hooks/useInpatientAdmission.ts +1 -1
  56. package/src/hooks/useMotherAndChildren.ts +2 -2
  57. package/src/hooks/useObs.ts +2 -2
  58. package/src/hooks/useWardPatientGrouping.ts +2 -0
  59. package/src/index.ts +10 -29
  60. package/src/root.component.tsx +3 -0
  61. package/src/routes.json +6 -11
  62. package/src/types/index.ts +29 -14
  63. package/src/ward-patient-card/card-rows/admission-request-note-row.component.tsx +38 -0
  64. package/src/ward-patient-card/card-rows/coded-obs-tags-row.component.tsx +108 -0
  65. package/src/ward-patient-card/card-rows/mother-child-row.component.tsx +84 -0
  66. package/src/ward-patient-card/card-rows/{pending-items-car-row.extension.tsx → pending-items-row.component.tsx} +12 -8
  67. package/src/ward-patient-card/row-elements/ward-patient-coded-obs-tags.tsx +12 -7
  68. package/src/ward-patient-card/row-elements/ward-patient-header-address.tsx +5 -5
  69. package/src/ward-patient-card/row-elements/ward-patient-identifier.tsx +18 -40
  70. package/src/ward-patient-card/row-elements/ward-patient-obs.resource.ts +2 -2
  71. package/src/ward-patient-card/row-elements/ward-patient-obs.tsx +15 -8
  72. package/src/ward-patient-card/ward-patient-card.component.tsx +16 -54
  73. package/src/ward-patient-card/ward-patient-card.scss +7 -1
  74. package/src/ward-view/default-ward/default-ward-beds.component.tsx +42 -0
  75. package/src/ward-view/default-ward/default-ward-patient-card-header.component.tsx +32 -0
  76. package/src/ward-view/default-ward/default-ward-patient-card.component.tsx +31 -0
  77. package/src/ward-view/default-ward/default-ward-pending-patients.component.tsx +52 -0
  78. package/src/ward-view/default-ward/default-ward-unassigned-patients.component.tsx +32 -0
  79. package/src/ward-view/default-ward/default-ward-view.component.tsx +31 -0
  80. package/src/ward-view/materal-ward/maternal-ward-beds.component.tsx +65 -0
  81. package/src/ward-view/materal-ward/maternal-ward-patient-card-header.component.tsx +30 -0
  82. package/src/ward-view/materal-ward/maternal-ward-patient-card.component.tsx +93 -0
  83. package/src/{beds/occupied-bed.scss → ward-view/materal-ward/maternal-ward-patient-card.scss} +4 -10
  84. package/src/ward-view/materal-ward/maternal-ward-patient-card.test.tsx +47 -0
  85. package/src/ward-view/materal-ward/maternal-ward-pending-patients.component.tsx +48 -0
  86. package/src/ward-view/materal-ward/maternal-ward-unassigned-patients.component.tsx +33 -0
  87. package/src/ward-view/materal-ward/maternal-ward-view.component.tsx +38 -0
  88. package/src/ward-view/materal-ward/maternal-ward-view.resource.ts +89 -0
  89. package/src/ward-view/ward-view.component.tsx +11 -151
  90. package/src/ward-view/ward-view.resource.ts +78 -6
  91. package/src/ward-view/ward-view.scss +1 -0
  92. package/src/ward-view/ward-view.test.tsx +10 -8
  93. package/src/ward-view/ward.component.tsx +106 -0
  94. package/src/ward-view-header/admission-requests-bar.component.tsx +10 -6
  95. package/src/ward-view-header/admission-requests-bar.test.tsx +5 -4
  96. package/src/ward-view-header/ward-metrics.component.tsx +12 -11
  97. package/src/ward-view-header/ward-metrics.test.tsx +4 -58
  98. package/src/ward-view-header/ward-view-header.component.tsx +6 -4
  99. package/src/ward-workspace/admission-request-card/admission-request-card-actions.component.tsx +7 -4
  100. package/src/ward-workspace/admission-request-card/admission-request-card-header.component.tsx +9 -21
  101. package/src/ward-workspace/admission-request-card/admission-request-card.component.tsx +9 -3
  102. package/src/ward-workspace/admission-request-card/admission-request-card.scss +6 -1
  103. package/src/ward-workspace/admission-request-workspace/admission-requests-workspace.test.tsx +11 -38
  104. package/src/ward-workspace/admission-request-workspace/admission-requests.workspace.tsx +8 -38
  105. package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.test.tsx +80 -89
  106. package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.workspace.tsx +21 -13
  107. package/src/ward-workspace/patient-banner/patient-banner.component.tsx +5 -12
  108. package/src/ward-workspace/patient-details/ward-patient-action-button.extension.tsx +2 -2
  109. package/src/ward-workspace/patient-details/ward-patient.workspace.tsx +13 -6
  110. package/src/ward-workspace/patient-discharge/patient-discharge.workspace.tsx +6 -6
  111. package/src/ward-workspace/patient-transfer-bed-swap/patient-bed-swap-form.component.tsx +7 -7
  112. package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-request-form.component.tsx +6 -6
  113. package/translations/en.json +7 -1
  114. package/dist/126.js +0 -1
  115. package/dist/126.js.map +0 -1
  116. package/dist/161.js +0 -2
  117. package/dist/161.js.map +0 -1
  118. package/dist/2.js +0 -1
  119. package/dist/2.js.map +0 -1
  120. package/dist/269.js +0 -1
  121. package/dist/269.js.map +0 -1
  122. package/dist/466.js +0 -1
  123. package/dist/466.js.map +0 -1
  124. package/dist/500.js.map +0 -1
  125. package/dist/557.js +0 -1
  126. package/dist/557.js.map +0 -1
  127. package/dist/659.js.map +0 -1
  128. package/dist/701.js +0 -1
  129. package/dist/701.js.map +0 -1
  130. package/dist/749.js +0 -1
  131. package/dist/749.js.map +0 -1
  132. package/dist/908.js +0 -1
  133. package/dist/908.js.map +0 -1
  134. package/src/beds/empty-bed.scss +0 -24
  135. package/src/beds/occupied-bed.component.tsx +0 -35
  136. package/src/beds/unassigned-patient.component.tsx +0 -20
  137. package/src/beds/unassigned-patient.scss +0 -6
  138. package/src/config-schema-admission-request-note.ts +0 -9
  139. package/src/config-schema-extension-colored-obs-tags.ts +0 -91
  140. package/src/config-schema-mother-child-row.ts +0 -26
  141. package/src/config-schema-pending-items-extension.ts +0 -29
  142. package/src/hooks/useCurrentWardCardConfig.ts +0 -32
  143. package/src/ward-patient-card/card-rows/admission-request-note.extension.tsx +0 -32
  144. package/src/ward-patient-card/card-rows/colored-obs-tags-card-row.extension.tsx +0 -13
  145. package/src/ward-patient-card/card-rows/mother-child-row.extension.tsx +0 -110
  146. package/src/ward-patient-card/ward-patient-card-element.component.tsx +0 -69
  147. package/src/ward-patient-card/ward-patient-resource.ts +0 -15
  148. package/src/ward-view/ward-bed.component.tsx +0 -14
  149. /package/src/ward-patient-card/row-elements/{ward-pateint-skeleton-text.tsx → ward-patient-skeleton-text.tsx} +0 -0
@@ -21,5 +21,7 @@ export function useWardPatientGrouping() {
21
21
  admissionLocationResponse,
22
22
  inpatientAdmissionResponse,
23
23
  inpatientRequestResponse,
24
+ isLoading:
25
+ admissionLocationResponse.isLoading || inpatientAdmissionResponse.isLoading || inpatientRequestResponse.isLoading,
24
26
  };
25
27
  }
package/src/index.ts CHANGED
@@ -1,19 +1,14 @@
1
1
  import {
2
2
  defineConfigSchema,
3
- defineExtensionConfigSchema,
4
3
  getAsyncLifecycle,
5
4
  getSyncLifecycle,
6
5
  registerBreadcrumbs,
7
6
  registerFeatureFlag,
8
7
  } from '@openmrs/esm-framework';
9
8
  import { configSchema } from './config-schema';
10
- import { admissionRequestNoteRowConfigSchema } from './config-schema-admission-request-note';
11
- import { coloredObsTagsCardRowConfigSchema } from './config-schema-extension-colored-obs-tags';
12
9
  import { moduleName } from './constant';
13
10
  import { createDashboardLink } from './createDashboardLink.component';
14
11
  import rootComponent from './root.component';
15
- import { motherChildRowConfigSchema } from './config-schema-mother-child-row';
16
- import { pendingItemsExtensionConfigSchema } from './config-schema-pending-items-extension';
17
12
 
18
13
  export const importTranslation = require.context('../translations', false, /.json$/, 'lazy');
19
14
 
@@ -60,26 +55,6 @@ export const wardPatientNotesActionButtonExtension = getAsyncLifecycle(
60
55
  options,
61
56
  );
62
57
 
63
- export const coloredObsTagCardRowExtension = getAsyncLifecycle(
64
- () => import('./ward-patient-card/card-rows/colored-obs-tags-card-row.extension'),
65
- options,
66
- );
67
-
68
- export const admissionRequestNoteRowExtension = getAsyncLifecycle(
69
- () => import('./ward-patient-card/card-rows/admission-request-note.extension'),
70
- options,
71
- );
72
-
73
- export const motherChildRowExtension = getAsyncLifecycle(
74
- () => import('./ward-patient-card/card-rows/mother-child-row.extension'),
75
- options,
76
- );
77
-
78
- export const pendingItemsCardRowExtension = getAsyncLifecycle(
79
- () => import('./ward-patient-card/card-rows/pending-items-car-row.extension'),
80
- options,
81
- );
82
-
83
58
  // t('transfers', 'Transfers')
84
59
  export const patientTransferAndSwapWorkspace = getAsyncLifecycle(
85
60
  () => import('./ward-workspace/patient-transfer-bed-swap/patient-transfer-swap.workspace'),
@@ -118,13 +93,19 @@ export const clinicalFormWorkspaceSideRailIcon = getAsyncLifecycle(
118
93
  options,
119
94
  );
120
95
 
96
+ export const defaultWardView = getAsyncLifecycle(
97
+ () => import('./ward-view/default-ward/default-ward-view.component'),
98
+ options,
99
+ );
100
+
101
+ export const maternalWardView = getAsyncLifecycle(
102
+ () => import('./ward-view/materal-ward/maternal-ward-view.component'),
103
+ options,
104
+ );
105
+
121
106
  export function startupApp() {
122
107
  registerBreadcrumbs([]);
123
108
  defineConfigSchema(moduleName, configSchema);
124
- defineExtensionConfigSchema('colored-obs-tags-card-row', coloredObsTagsCardRowConfigSchema);
125
- defineExtensionConfigSchema('admission-request-note-card-row', admissionRequestNoteRowConfigSchema);
126
- defineExtensionConfigSchema('mother-child-card-row', motherChildRowConfigSchema);
127
- defineExtensionConfigSchema('ward-patient-pending-items-card-row', pendingItemsExtensionConfigSchema);
128
109
 
129
110
  registerFeatureFlag(
130
111
  'bedmanagement-module',
@@ -1,3 +1,4 @@
1
+ import { WorkspaceContainer } from '@openmrs/esm-framework';
1
2
  import React from 'react';
2
3
  import { BrowserRouter, Route, Routes } from 'react-router-dom';
3
4
  import WardView from './ward-view/ward-view.component';
@@ -14,6 +15,8 @@ const Root: React.FC = () => {
14
15
  <Route path="/:locationUuid" element={<WardView />} />
15
16
  </Routes>
16
17
  </BrowserRouter>
18
+
19
+ <WorkspaceContainer overlay contextKey="ward" />
17
20
  </main>
18
21
  );
19
22
  };
package/src/routes.json CHANGED
@@ -61,19 +61,14 @@
61
61
  "slot": "action-menu-ward-patient-items-slot"
62
62
  },
63
63
  {
64
- "component": "admissionRequestNoteRowExtension",
65
- "name": "admission-request-note-card-row",
66
- "slot": "ward-patient-card-slot"
67
- },
68
- {
69
- "component": "motherChildRowExtension",
70
- "name": "mother-child-card-row",
71
- "slot": "ward-patient-card-slot"
64
+ "component": "defaultWardView",
65
+ "name": "default-ward",
66
+ "slot": "default-ward"
72
67
  },
73
68
  {
74
- "component": "pendingItemsCardRowExtension",
75
- "name": "ward-patient-pending-items-card-row",
76
- "slot": "ward-patient-card-pending-items-slot"
69
+ "component": "maternalWardView",
70
+ "name": "maternal-ward",
71
+ "slot": "maternal-ward"
77
72
  }
78
73
  ],
79
74
  "workspaces": [
@@ -11,7 +11,7 @@ import type {
11
11
  import type React from 'react';
12
12
  import type { useWardPatientGrouping } from '../hooks/useWardPatientGrouping';
13
13
 
14
- export type WardPatientCard = React.FC<WardPatient>;
14
+ export type WardPatientCardType = React.FC<WardPatient>;
15
15
 
16
16
  // WardPatient is a patient admitted to a ward, and/or in a bed on a ward
17
17
  export type WardPatient = {
@@ -44,10 +44,7 @@ export type WardPatient = {
44
44
 
45
45
  export interface WardPatientWorkspaceProps extends DefaultWorkspaceProps {
46
46
  wardPatient: WardPatient;
47
- }
48
- export interface MotherAndChildrenRelationships {
49
- motherByChildUuid: Map<string, Patient>;
50
- childrenByMotherUuid: Map<string, Array<Patient>>;
47
+ WardPatientHeader: React.FC<WardPatient>;
51
48
  }
52
49
 
53
50
  // server-side types defined in openmrs-module-bedmanagement:
@@ -70,6 +67,14 @@ export interface Bed {
70
67
  status: BedStatus;
71
68
  }
72
69
 
70
+ export interface BedDetail {
71
+ bedId: number;
72
+ bedNumber: number;
73
+ bedType: BedType;
74
+ physicalLocation: Location;
75
+ patients: Array<Patient>;
76
+ }
77
+
73
78
  export interface BedLayout {
74
79
  rowNumber: number;
75
80
  columnNumber: number;
@@ -144,9 +149,6 @@ export interface InpatientAdmission {
144
149
  // the current in patient request
145
150
  currentInpatientRequest: InpatientRequest;
146
151
  }
147
- export interface WardAppContext {
148
- allPatientsByPatientUuid: Map<string, Patient>;
149
- }
150
152
 
151
153
  export interface MotherAndChild {
152
154
  mother: Patient;
@@ -228,11 +230,24 @@ export interface ObsPayload {
228
230
  groupMembers?: Array<ObsPayload>;
229
231
  }
230
232
 
231
- export interface MotherAndChildren {
232
- childAdmission: InpatientAdmission;
233
- child: Patient;
234
- motherAdmission: InpatientAdmission;
235
- mother: Patient;
233
+ export type WardPatientGroupDetails = ReturnType<typeof useWardPatientGrouping>;
234
+ export interface WardViewContext {
235
+ wardPatientGroupDetails: WardPatientGroupDetails;
236
+ WardPatientHeader: React.FC<WardPatient>;
236
237
  }
237
238
 
238
- export type WardPatientGroupDetails = ReturnType<typeof useWardPatientGrouping>;
239
+ export interface PatientAndAdmission {
240
+ patient: Patient;
241
+ currentAdmission: InpatientAdmission;
242
+ }
243
+
244
+ export interface MotherChildRelationships {
245
+ motherByChildUuid: Map<string, PatientAndAdmission>;
246
+ childrenByMotherUuid: Map<string, PatientAndAdmission[]>;
247
+ }
248
+
249
+ export interface MaternalWardViewContext {
250
+ motherChildRelationships: MotherChildRelationships;
251
+ }
252
+
253
+ export type PatientWorkspaceAdditionalProps = Omit<WardPatientWorkspaceProps, keyof DefaultWorkspaceProps>;
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import { type ObsElementConfig } from '../../config-schema';
3
+ import { type WardPatient } from '../../types';
4
+ import { useElementConfig } from '../../ward-view/ward-view.resource';
5
+ import WardPatientObs from '../row-elements/ward-patient-obs';
6
+ import styles from '../ward-patient-card.scss';
7
+
8
+ interface AdmissionRequestNoteRowProps {
9
+ wardPatient: WardPatient;
10
+ id: string;
11
+ }
12
+
13
+ const AdmissionRequestNoteRow: React.FC<AdmissionRequestNoteRowProps> = ({ id, wardPatient }) => {
14
+ const { patient, visit, inpatientAdmission } = wardPatient;
15
+ const { conceptUuid } = useElementConfig('admissionRequestNote', id) ?? {};
16
+ const config: ObsElementConfig = {
17
+ conceptUuid,
18
+ limit: 0,
19
+ id: 'admission-note',
20
+ onlyWithinCurrentVisit: true,
21
+ orderBy: 'ascending',
22
+ label: 'Admission Note',
23
+ };
24
+
25
+ // only show if the patient has not been admitted yet
26
+ const admitted = inpatientAdmission != null;
27
+ if (admitted) {
28
+ return null;
29
+ } else {
30
+ return (
31
+ <div className={styles.wardPatientCardRow}>
32
+ <WardPatientObs id={id} configOverride={config} patient={patient} visit={visit} />
33
+ </div>
34
+ );
35
+ }
36
+ };
37
+
38
+ export default AdmissionRequestNoteRow;
@@ -0,0 +1,108 @@
1
+ import { Tag } from '@carbon/react';
2
+ import { type OpenmrsResource, type Patient, type Visit } from '@openmrs/esm-framework';
3
+ import React, { type ReactNode } from 'react';
4
+ import { useTranslation } from 'react-i18next';
5
+ import { useObs } from '../../hooks/useObs';
6
+ import { useElementConfig } from '../../ward-view/ward-view.resource';
7
+ import styles from '../ward-patient-card.scss';
8
+ import WardPatientSkeletonText from '../row-elements/ward-patient-skeleton-text';
9
+ import {
10
+ getObsEncounterString,
11
+ obsCustomRepresentation,
12
+ useConceptToTagColorMap,
13
+ } from '../row-elements/ward-patient-obs.resource';
14
+ import WardPatientResponsiveTooltip from '../row-elements/ward-patient-responsive-tooltip';
15
+
16
+ interface WardPatientCodedObsTagsRowProps {
17
+ id: string;
18
+ patient: Patient;
19
+ visit: Visit;
20
+ }
21
+
22
+ /**
23
+ * The WardPatientCodedObsTags displays observations of coded values of a particular concept in the active visit as tags.
24
+ * Typically, these are taken from checkbox fields from a form. Each answer value can either be configured
25
+ * to show as its own tag, or collapsed into a summary tag show the number of these values present.
26
+ *
27
+ * This is a rather specialized element;
28
+ * for a more general display of obs value, use WardPatientObs instead.
29
+ * @param config
30
+ * @returns
31
+ */
32
+ const CodedObsTagsRow: React.FC<WardPatientCodedObsTagsRowProps> = ({ id, patient, visit }) => {
33
+ const config = useElementConfig('coloredObsTags', id);
34
+ const { conceptUuid, summaryLabel, summaryLabelColor } = config ?? {};
35
+ const { data, isLoading } = useObs(
36
+ { patient: patient.uuid, concept: conceptUuid },
37
+ conceptUuid != null,
38
+ obsCustomRepresentation,
39
+ );
40
+ const { t } = useTranslation();
41
+ const conceptToTagColorMap = useConceptToTagColorMap(config?.tags ?? []);
42
+
43
+ if (isLoading) {
44
+ return (
45
+ <div className={styles.wardPatientCardRow}>
46
+ <WardPatientSkeletonText />
47
+ </div>
48
+ );
49
+ } else {
50
+ const obsToDisplay = data?.filter((o) => {
51
+ const matchVisit = o.encounter.visit?.uuid == visit?.uuid;
52
+ return matchVisit;
53
+ });
54
+
55
+ const summaryLabelToDisplay = summaryLabel != null ? t(summaryLabel) : obsToDisplay?.[0]?.concept?.display;
56
+
57
+ // for each obs configured to be displayed with a color, we create a tag for it
58
+ // for other obs not configured, we create a single summary tag for all of them.
59
+ const summaryTagTooltipText: ReactNode[] = [];
60
+ const coloredOpsTags = obsToDisplay
61
+ ?.map((o) => {
62
+ const { display, uuid } = o.value as OpenmrsResource;
63
+
64
+ const color = conceptToTagColorMap?.get(uuid);
65
+ if (color) {
66
+ return (
67
+ <WardPatientResponsiveTooltip tooltipContent={getObsEncounterString(o, t)}>
68
+ <Tag type={color} key={`ward-coded-obs-tag-${o.uuid}`}>
69
+ {display}
70
+ </Tag>
71
+ </WardPatientResponsiveTooltip>
72
+ );
73
+ } else {
74
+ summaryTagTooltipText.push(
75
+ <div key={uuid}>
76
+ {display} ({getObsEncounterString(o, t)})
77
+ </div>,
78
+ );
79
+ return null;
80
+ }
81
+ })
82
+ .filter((o) => o != null);
83
+
84
+ if (coloredOpsTags?.length > 0 || summaryTagTooltipText.length > 0) {
85
+ return (
86
+ <div className={styles.wardPatientCardRow}>
87
+ <span className={styles.wardPatientObsLabel}>
88
+ {coloredOpsTags}
89
+ {summaryTagTooltipText.length > 0 ? (
90
+ <WardPatientResponsiveTooltip tooltipContent={summaryTagTooltipText}>
91
+ <Tag type={summaryLabelColor}>
92
+ {t('countItems', '{{count}} {{item}}', {
93
+ count: summaryTagTooltipText.length,
94
+ item: summaryLabelToDisplay,
95
+ })}
96
+ </Tag>
97
+ </WardPatientResponsiveTooltip>
98
+ ) : null}
99
+ </span>
100
+ </div>
101
+ );
102
+ } else {
103
+ return null;
104
+ }
105
+ }
106
+ };
107
+
108
+ export default CodedObsTagsRow;
@@ -0,0 +1,84 @@
1
+ import { BabyIcon, MotherIcon, type Patient, useAppContext } from '@openmrs/esm-framework';
2
+ import classNames from 'classnames';
3
+ import React from 'react';
4
+ import { type InpatientAdmission, type MaternalWardViewContext } from '../../types';
5
+ import { type MaternalWardPatientCardProps } from '../../ward-view/materal-ward/maternal-ward-patient-card.component';
6
+ import WardPatientAge from '../row-elements/ward-patient-age';
7
+ import WardPatientIdentifier from '../row-elements/ward-patient-identifier';
8
+ import WardPatientLocation from '../row-elements/ward-patient-location';
9
+ import WardPatientName from '../row-elements/ward-patient-name';
10
+ import wardPatientCardStyles from '../ward-patient-card.scss';
11
+ import styles from './mother-child-row.scss';
12
+
13
+ /**
14
+ * This component displays the mother or children of the patient in the patient card. The patient's child is
15
+ * not displayed if it is in the same bed as the patient
16
+ *
17
+ * @param param0
18
+ * @returns
19
+ */
20
+ const MotherChildRow: React.FC<MaternalWardPatientCardProps> = ({ wardPatient, childrenOfWardPatientInSameBed }) => {
21
+ const { patient } = wardPatient;
22
+
23
+ const { motherChildRelationships } = useAppContext<MaternalWardViewContext>('maternal-ward-view-context') ?? {};
24
+
25
+ const { childrenByMotherUuid, motherByChildUuid } = motherChildRelationships ?? {};
26
+
27
+ const motherOfPatient = motherByChildUuid?.get(patient.uuid);
28
+ const childrenOfPatient = childrenByMotherUuid?.get(patient.uuid);
29
+ const childrenOfPatientNotInSameBed = childrenOfPatient?.filter((child) => {
30
+ return !childrenOfWardPatientInSameBed?.some((childInSameBed) => childInSameBed.patient.uuid == child.patient.uuid);
31
+ });
32
+
33
+ return (
34
+ <>
35
+ {motherOfPatient && (
36
+ <MotherOrChild
37
+ otherPatient={motherOfPatient.patient}
38
+ otherPatientAdmission={motherOfPatient.currentAdmission}
39
+ isOtherPatientTheMother={true}
40
+ />
41
+ )}
42
+ {childrenOfPatientNotInSameBed?.map((childOfPatient) => (
43
+ <MotherOrChild
44
+ key={childOfPatient.patient.uuid}
45
+ otherPatient={childOfPatient.patient}
46
+ otherPatientAdmission={childOfPatient.currentAdmission}
47
+ isOtherPatientTheMother={false}
48
+ />
49
+ ))}
50
+ </>
51
+ );
52
+ };
53
+
54
+ interface MotherOrChildProp {
55
+ otherPatient: Patient;
56
+ otherPatientAdmission: InpatientAdmission;
57
+ isOtherPatientTheMother: boolean;
58
+ }
59
+
60
+ const MotherOrChild: React.FC<MotherOrChildProp> = ({
61
+ otherPatient,
62
+ otherPatientAdmission,
63
+ isOtherPatientTheMother,
64
+ }) => {
65
+ const Icon = isOtherPatientTheMother ? MotherIcon : BabyIcon;
66
+
67
+ return (
68
+ <div
69
+ key={otherPatient.uuid}
70
+ className={classNames(styles.motherOrBabyRow, wardPatientCardStyles.wardPatientCardRow)}>
71
+ <div className={styles.motherOrBabyIconDiv}>
72
+ <Icon className={styles.motherOrBabyIcon} size={24} />
73
+ </div>
74
+ <div className={classNames(styles.motherOrBabyRowElementsDiv, wardPatientCardStyles.dotSeparatedChildren)}>
75
+ <WardPatientName patient={otherPatient} />
76
+ <WardPatientIdentifier id="patient-identifier" patient={otherPatient} />
77
+ <WardPatientAge patient={otherPatient} />
78
+ <WardPatientLocation inpatientAdmission={otherPatientAdmission} />
79
+ </div>
80
+ </div>
81
+ );
82
+ };
83
+
84
+ export default MotherChildRow;
@@ -1,15 +1,19 @@
1
- import React, { useCallback, useEffect } from 'react';
2
- import { type WardPatientCard } from '../../types';
3
1
  import { Hourglass } from '@carbon/react/icons';
2
+ import React, { useCallback, useEffect } from 'react';
3
+ import { type WardPatient } from '../../types';
4
4
 
5
- import { useConfig } from '@openmrs/esm-framework';
6
- import type { PendingItemsDefinition } from '../../config-schema';
5
+ import { useElementConfig } from '../../ward-view/ward-view.resource';
7
6
  import { WardPatientPendingOrder } from '../row-elements/ward-patient-pending-order.component';
8
- import styles from '../ward-patient-card.scss';
9
7
  import WardPatientPendingTransfer from '../row-elements/ward-patient-pending-transfer';
8
+ import styles from '../ward-patient-card.scss';
9
+
10
+ export interface PendingItemsRowProps {
11
+ id: string;
12
+ wardPatient: WardPatient;
13
+ }
10
14
 
11
- const PendingItemsCarRowExtension: WardPatientCard = (wardPatient) => {
12
- const { orders, showPendingItems } = useConfig<PendingItemsDefinition>();
15
+ const PendingItemsRow: React.FC<PendingItemsRowProps> = ({ id, wardPatient }) => {
16
+ const { orders, showPendingItems } = useElementConfig('pendingItems', id);
13
17
  const [hasPendingOrders, setHasPendingOrders] = React.useState(false);
14
18
 
15
19
  const hasPendingItems = !!wardPatient?.inpatientRequest || hasPendingOrders;
@@ -47,4 +51,4 @@ const PendingItemsCarRowExtension: WardPatientCard = (wardPatient) => {
47
51
  );
48
52
  };
49
53
 
50
- export default PendingItemsCarRowExtension;
54
+ export default PendingItemsRow;
@@ -2,15 +2,15 @@ import { Tag } from '@carbon/react';
2
2
  import { type OpenmrsResource, type Patient, type Visit } from '@openmrs/esm-framework';
3
3
  import React, { type ReactNode } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
- import { type ColoredObsTagsCardRowConfigObject } from '../../config-schema-extension-colored-obs-tags';
6
5
  import { useObs } from '../../hooks/useObs';
6
+ import { useElementConfig } from '../../ward-view/ward-view.resource';
7
7
  import styles from '../ward-patient-card.scss';
8
- import WardPatientSkeletonText from './ward-pateint-skeleton-text';
8
+ import WardPatientSkeletonText from './ward-patient-skeleton-text';
9
9
  import { getObsEncounterString, obsCustomRepresentation, useConceptToTagColorMap } from './ward-patient-obs.resource';
10
10
  import WardPatientResponsiveTooltip from './ward-patient-responsive-tooltip';
11
11
 
12
12
  interface WardPatientCodedObsTagsProps {
13
- config: ColoredObsTagsCardRowConfigObject;
13
+ id: string;
14
14
  patient: Patient;
15
15
  visit: Visit;
16
16
  }
@@ -25,11 +25,16 @@ interface WardPatientCodedObsTagsProps {
25
25
  * @param config
26
26
  * @returns
27
27
  */
28
- const WardPatientCodedObsTags: React.FC<WardPatientCodedObsTagsProps> = ({ config, patient, visit }) => {
29
- const { conceptUuid, summaryLabel, summaryLabelColor } = config;
30
- const { data, isLoading } = useObs({ patient: patient.uuid, concept: conceptUuid }, obsCustomRepresentation);
28
+ const WardPatientCodedObsTags: React.FC<WardPatientCodedObsTagsProps> = ({ id, patient, visit }) => {
29
+ const config = useElementConfig('coloredObsTags', id);
30
+ const { conceptUuid, summaryLabel, summaryLabelColor } = config ?? {};
31
+ const { data, isLoading } = useObs(
32
+ { patient: patient.uuid, concept: conceptUuid },
33
+ conceptUuid != null,
34
+ obsCustomRepresentation,
35
+ );
31
36
  const { t } = useTranslation();
32
- const conceptToTagColorMap = useConceptToTagColorMap(config.tags);
37
+ const conceptToTagColorMap = useConceptToTagColorMap(config?.tags ?? []);
33
38
 
34
39
  if (isLoading) {
35
40
  return (
@@ -1,15 +1,15 @@
1
- import React from 'react';
2
- import styles from '../ward-patient-card.scss';
3
1
  import { type Patient } from '@openmrs/esm-framework';
4
- import { type AddressElementDefinition } from '../../config-schema';
2
+ import React from 'react';
3
+ import { useElementConfig } from '../../ward-view/ward-view.resource';
5
4
 
6
5
  export interface WardPatientAddressProps {
7
6
  patient: Patient;
8
- config: AddressElementDefinition;
7
+ id: string;
9
8
  }
10
9
 
11
- const WardPatientAddress: React.FC<WardPatientAddressProps> = ({ patient, config }) => {
10
+ const WardPatientAddress: React.FC<WardPatientAddressProps> = ({ patient, id }) => {
12
11
  const preferredAddress = patient?.person?.preferredAddress;
12
+ const config = useElementConfig("patientAddress", id);
13
13
 
14
14
  return (
15
15
  <>
@@ -1,51 +1,29 @@
1
+ import { type Patient, type PatientIdentifier, PatientBannerPatientIdentifier } from '@openmrs/esm-framework';
1
2
  import React from 'react';
2
- import { type IdentifierElementDefinition } from '../../config-schema';
3
- import { Tag } from '@carbon/react';
4
- import { type Patient, translateFrom, type PatientIdentifier } from '@openmrs/esm-framework';
5
- import { moduleName } from '../../constant';
6
- import { useTranslation } from 'react-i18next';
7
-
8
- /** Sort the identifiers by preferred first. The identifier with value of true
9
- * takes precedence over false. If both identifiers have same preferred value,
10
- * sort them by most recently created or changed. */
11
- const identifierCompareFunction = (pi1: PatientIdentifier, pi2: PatientIdentifier) => {
12
- let comp = (pi2.preferred ? 1 : 0) - (pi1.preferred ? 1 : 0);
13
-
14
- if (comp == 0) {
15
- const date1 = pi1.auditInfo.dateChanged ?? pi1.auditInfo.dateCreated;
16
- const date2 = pi2.auditInfo.dateChanged ?? pi2.auditInfo.dateCreated;
17
- comp = date2.localeCompare(date1);
18
- }
19
- return comp;
20
- };
3
+ import { useElementConfig } from '../../ward-view/ward-view.resource';
21
4
 
22
5
  export interface WardPatientIdentifierProps {
23
6
  patient: Patient;
24
- /** If the config is not passed, this will be the default identifier element, which uses the preferred identifier type. */
25
- config?: IdentifierElementDefinition;
7
+ id?: string;
26
8
  }
27
9
 
28
- const defaultConfig: IdentifierElementDefinition = {
29
- id: 'patient-identifier',
30
- identifierTypeUuid: null,
31
- };
10
+ const WardPatientIdentifier: React.FC<WardPatientIdentifierProps> = ({ id, patient }) => {
11
+ const config = useElementConfig('patientIdentifier', id);
12
+
13
+ const fhirIdentifiers: fhir.Identifier[] = patient.identifiers.map((identifier: PatientIdentifier) => ({
14
+ value: identifier.identifier,
15
+ type: {
16
+ text: identifier.identifierType.name,
17
+ coding: [
18
+ {
19
+ code: identifier.identifierType.uuid,
20
+ },
21
+ ],
22
+ },
23
+ }));
32
24
 
33
- const WardPatientIdentifier: React.FC<WardPatientIdentifierProps> = ({ config: configProp, patient }) => {
34
- const { t } = useTranslation();
35
- const config = configProp ?? defaultConfig;
36
- const { identifierTypeUuid, label } = config;
37
- const patientIdentifiers = patient.identifiers.filter(
38
- (patientIdentifier: PatientIdentifier) =>
39
- identifierTypeUuid == null || patientIdentifier.identifierType?.uuid === identifierTypeUuid,
40
- );
41
- patientIdentifiers.sort(identifierCompareFunction);
42
- const patientIdentifier = patientIdentifiers[0];
43
- const labelToDisplay = label != null ? t(label) : patientIdentifier?.identifierType?.name;
44
25
  return (
45
- <div>
46
- {labelToDisplay ? <Tag>{t('identifierTypelabel', '{{label}}:', { label: labelToDisplay })}</Tag> : <></>}
47
- <span>{patientIdentifier?.identifier}</span>
48
- </div>
26
+ <PatientBannerPatientIdentifier identifier={fhirIdentifiers} showIdentifierLabel={config?.showIdentifierLabel} />
49
27
  );
50
28
  };
51
29
 
@@ -1,7 +1,7 @@
1
1
  import { restBaseUrl, useOpenmrsFetchAll, type Concept } from '@openmrs/esm-framework';
2
- import { type TagConfigObject } from '../../config-schema-extension-colored-obs-tags';
3
2
  import { type Observation } from '../../types';
4
3
  import { type TFunction } from 'i18next';
4
+ import { type ColoredObsTagConfig } from '../../config-schema';
5
5
 
6
6
  // prettier-ignore
7
7
  export const obsCustomRepresentation =
@@ -13,7 +13,7 @@ export const obsCustomRepresentation =
13
13
  // get the setMembers of a concept set
14
14
  const conceptSetCustomRepresentation = 'custom:(uuid,setMembers:(uuid))';
15
15
 
16
- export function useConceptToTagColorMap(tags: Array<TagConfigObject>) {
16
+ export function useConceptToTagColorMap(tags: Array<ColoredObsTagConfig> = []) {
17
17
  // The TacConfigObject allows us to specify the mapping of
18
18
  // concept sets to colors. However, we also need to build a map of
19
19
  // concepts to colors. This function does that.
@@ -1,23 +1,30 @@
1
- import { SkeletonText, Toggletip, ToggletipButton, ToggletipContent } from '@carbon/react';
2
- import { Information } from '@carbon/react/icons';
1
+ import { SkeletonText } from '@carbon/react';
3
2
  import { type OpenmrsResource, type Patient, type Visit } from '@openmrs/esm-framework';
4
3
  import React from 'react';
5
4
  import { useTranslation } from 'react-i18next';
6
- import { type ObsElementDefinition } from '../../config-schema';
5
+ import { type ObsElementConfig } from '../../config-schema';
7
6
  import { useObs } from '../../hooks/useObs';
8
7
  import styles from '../ward-patient-card.scss';
9
8
  import { getObsEncounterString, obsCustomRepresentation } from './ward-patient-obs.resource';
10
9
  import WardPatientResponsiveTooltip from './ward-patient-responsive-tooltip';
10
+ import { useElementConfig } from '../../ward-view/ward-view.resource';
11
11
 
12
12
  export interface WardPatientObsProps {
13
- config: ObsElementDefinition;
13
+ id: string;
14
+ configOverride?: ObsElementConfig;
14
15
  patient: Patient;
15
16
  visit: Visit;
16
17
  }
17
18
 
18
- const WardPatientObs: React.FC<WardPatientObsProps> = ({ config, patient, visit }) => {
19
- const { conceptUuid, onlyWithinCurrentVisit, orderBy, limit, label } = config;
20
- const { data, isLoading } = useObs({ patient: patient.uuid, concept: conceptUuid }, obsCustomRepresentation);
19
+ const WardPatientObs: React.FC<WardPatientObsProps> = ({ id, configOverride, patient, visit }) => {
20
+ const config: ObsElementConfig = useElementConfig('obs', id);
21
+ const configToUse = configOverride ?? config;
22
+ const { conceptUuid, onlyWithinCurrentVisit, orderBy, limit, label } = configToUse ?? {};
23
+ const { data, isLoading } = useObs(
24
+ { patient: patient.uuid, concept: conceptUuid },
25
+ conceptUuid != null,
26
+ obsCustomRepresentation,
27
+ );
21
28
  const { t } = useTranslation();
22
29
 
23
30
  if (isLoading) {
@@ -53,7 +60,7 @@ const WardPatientObs: React.FC<WardPatientObsProps> = ({ config, patient, visit
53
60
  <span className={styles.wardPatientObsLabel}>
54
61
  {labelToDisplay ? t('labelColon', '{{label}}:', { label: labelToDisplay }) : ''}
55
62
  </span>
56
- {obsNodes}
63
+ <div className={styles.dotSeparatedChildren}>{obsNodes}</div>
57
64
  </div>
58
65
  );
59
66
  } else {