@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
package/dist/routes.json CHANGED
@@ -1 +1 @@
1
- {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"webservices.rest":"^2.2.0","emrapi":"^2.0.0 || 2.0.0-SNAPSHOT"},"optionalBackendDependencies":{"bedmanagement":{"version":"^6.0.0 || 6.0.0-SNAPSHOT","feature":{"flagName":"bedmanagement-module","label":"Ward App Patient Service","description":"This module, if installed, provides services for managing patients admitted to the ward."}}},"extensions":[{"name":"ward-dashboard-link","component":"wardDashboardLink","slot":"homepage-dashboard-slot","meta":{"name":"ward","slot":"ward-dashboard-slot","title":"Wards"}},{"component":"root","name":"ward-dashboard","slot":"ward-dashboard-slot"},{"component":"wardPatientActionButtonExtension","name":"ward-patient-action-button","slot":"action-menu-ward-patient-items-slot"},{"component":"wardPatientNotesActionButtonExtension","name":"ward-inpatient-notes-form-action-button","slot":"action-menu-ward-patient-items-slot"},{"component":"coloredObsTagCardRowExtension","name":"colored-obs-tags-card-row","slot":"ward-patient-card-slot"},{"name":"transfer-swap-patient-siderail-button","slot":"action-menu-ward-patient-items-slot","component":"patientTransferAndSwapWorkspaceSiderailIcon"},{"name":"patient-discharge-siderail-button","slot":"action-menu-ward-patient-items-slot","component":"patientDischargeWorkspaceSideRailIcon"},{"name":"clinical-forms-workspace-siderail-button","component":"clinicalFormWorkspaceSideRailIcon","slot":"action-menu-ward-patient-items-slot"},{"component":"admissionRequestNoteRowExtension","name":"admission-request-note-card-row","slot":"ward-patient-card-slot"},{"component":"motherChildRowExtension","name":"mother-child-card-row","slot":"ward-patient-card-slot"},{"component":"pendingItemsCardRowExtension","name":"ward-patient-pending-items-card-row","slot":"ward-patient-card-pending-items-slot"}],"workspaces":[{"name":"admission-requests-workspace","component":"admissionRequestWorkspace","title":"admissionRequests","type":"admission-requests"},{"name":"ward-patient-notes-workspace","component":"wardPatientNotesWorkspace","type":"ward-patient-notes","title":"inpatientNotesWorkspaceTitle","sidebarFamily":"ward-patient","hasOwnSidebar":true},{"name":"admit-patient-form-workspace","component":"admitPatientFormWorkspace","title":"admissionRequests","type":"admission-requests"},{"name":"ward-patient-workspace","component":"wardPatientWorkspace","type":"ward","title":"Ward Patient","width":"extra-wide","hasOwnSidebar":true,"sidebarFamily":"ward-patient"},{"name":"patient-transfer-swap-workspace","component":"patientTransferAndSwapWorkspace","title":"transfers","type":"transfer-swap-bed-form","hasOwnSidebar":true,"sidebarFamily":"ward-patient"},{"name":"patient-transfer-request-workspace","component":"patientTransferRequestWorkspace","title":"transferRequest","type":"transfer-request-form"},{"name":"patient-discharge-workspace","component":"patientDischargeWorkspace","title":"discharge","type":"ward-patient-discharge","hasOwnSidebar":true,"sidebarFamily":"ward-patient"},{"name":"ward-patient-clinical-forms-workspace","component":"patientClinicalFormsWorkspace","title":"clinicalForms","type":"ward-patient-clinical-forms","hasOwnSidebar":true,"sidebarFamily":"ward-patient","width":"wider"}],"version":"8.1.1-pre.118"}
1
+ {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"webservices.rest":"^2.2.0","emrapi":"^2.0.0 || 2.0.0-SNAPSHOT"},"optionalBackendDependencies":{"bedmanagement":{"version":"^6.0.0 || 6.0.0-SNAPSHOT","feature":{"flagName":"bedmanagement-module","label":"Ward App Patient Service","description":"This module, if installed, provides services for managing patients admitted to the ward."}}},"extensions":[{"name":"ward-dashboard-link","component":"wardDashboardLink","slot":"homepage-dashboard-slot","meta":{"name":"ward","slot":"ward-dashboard-slot","title":"Wards"}},{"component":"root","name":"ward-dashboard","slot":"ward-dashboard-slot"},{"component":"wardPatientActionButtonExtension","name":"ward-patient-action-button","slot":"action-menu-ward-patient-items-slot"},{"component":"wardPatientNotesActionButtonExtension","name":"ward-inpatient-notes-form-action-button","slot":"action-menu-ward-patient-items-slot"},{"component":"coloredObsTagCardRowExtension","name":"colored-obs-tags-card-row","slot":"ward-patient-card-slot"},{"name":"transfer-swap-patient-siderail-button","slot":"action-menu-ward-patient-items-slot","component":"patientTransferAndSwapWorkspaceSiderailIcon"},{"name":"patient-discharge-siderail-button","slot":"action-menu-ward-patient-items-slot","component":"patientDischargeWorkspaceSideRailIcon"},{"name":"clinical-forms-workspace-siderail-button","component":"clinicalFormWorkspaceSideRailIcon","slot":"action-menu-ward-patient-items-slot"},{"component":"defaultWardView","name":"default-ward","slot":"default-ward"},{"component":"maternalWardView","name":"maternal-ward","slot":"maternal-ward"}],"workspaces":[{"name":"admission-requests-workspace","component":"admissionRequestWorkspace","title":"admissionRequests","type":"admission-requests"},{"name":"ward-patient-notes-workspace","component":"wardPatientNotesWorkspace","type":"ward-patient-notes","title":"inpatientNotesWorkspaceTitle","sidebarFamily":"ward-patient","hasOwnSidebar":true},{"name":"admit-patient-form-workspace","component":"admitPatientFormWorkspace","title":"admissionRequests","type":"admission-requests"},{"name":"ward-patient-workspace","component":"wardPatientWorkspace","type":"ward","title":"Ward Patient","width":"extra-wide","hasOwnSidebar":true,"sidebarFamily":"ward-patient"},{"name":"patient-transfer-swap-workspace","component":"patientTransferAndSwapWorkspace","title":"transfers","type":"transfer-swap-bed-form","hasOwnSidebar":true,"sidebarFamily":"ward-patient"},{"name":"patient-transfer-request-workspace","component":"patientTransferRequestWorkspace","title":"transferRequest","type":"transfer-request-form"},{"name":"patient-discharge-workspace","component":"patientDischargeWorkspace","title":"discharge","type":"ward-patient-discharge","hasOwnSidebar":true,"sidebarFamily":"ward-patient"},{"name":"ward-patient-clinical-forms-workspace","component":"patientClinicalFormsWorkspace","title":"clinicalForms","type":"ward-patient-clinical-forms","hasOwnSidebar":true,"sidebarFamily":"ward-patient","width":"wider"}],"version":"8.1.1-pre.119"}
package/mock.tsx CHANGED
@@ -4,6 +4,8 @@ import { useInpatientAdmission } from './src/hooks/useInpatientAdmission';
4
4
  import { createAndGetWardPatientGrouping } from './src/ward-view/ward-view.resource';
5
5
  import { useInpatientRequest } from './src/hooks/useInpatientRequest';
6
6
  import { useWardPatientGrouping } from './src/hooks/useWardPatientGrouping';
7
+ import { type WardViewContext } from './src/types';
8
+ import DefaultWardPatientCardHeader from './src/ward-view/default-ward/default-ward-patient-card-header.component';
7
9
 
8
10
  jest.mock('./src/hooks/useAdmissionLocation', () => ({
9
11
  useAdmissionLocation: jest.fn(),
@@ -51,4 +53,10 @@ export const mockWardPatientGroupDetails = jest.mocked(useWardPatientGrouping).m
51
53
  inpatientAdmissionResponse: mockInpatientAdmissionResponse(),
52
54
  inpatientRequestResponse: mockInpatientRequestResponse(),
53
55
  ...createAndGetWardPatientGrouping(mockInpatientAdmissions, mockAdmissionLocation, mockInpatientRequest),
56
+ isLoading: false,
54
57
  });
58
+
59
+ export const mockWardViewContext: WardViewContext = {
60
+ wardPatientGroupDetails: mockWardPatientGroupDetails(),
61
+ WardPatientHeader: DefaultWardPatientCardHeader,
62
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kenyaemr/esm-ward-app",
3
- "version": "8.1.1-pre.118",
3
+ "version": "8.1.1-pre.119",
4
4
  "description": "Ward and bed management module for O3",
5
5
  "browser": "dist/kenyaemr-esm-ward-app.js",
6
6
  "main": "src/index.ts",
@@ -1,11 +1,11 @@
1
1
  import { SkeletonIcon } from '@carbon/react';
2
2
  import React from 'react';
3
- import styles from './empty-bed.scss';
4
- import WardPatientSkeletonText from '../ward-patient-card/row-elements/ward-pateint-skeleton-text';
3
+ import styles from './ward-bed.scss';
4
+ import WardPatientSkeletonText from '../ward-patient-card/row-elements/ward-patient-skeleton-text';
5
5
 
6
6
  const EmptyBedSkeleton = () => {
7
7
  return (
8
- <div className={styles.container + ' ' + styles.skeleton}>
8
+ <div className={styles.emptyBed + ' ' + styles.skeleton}>
9
9
  <SkeletonIcon />
10
10
  <WardPatientSkeletonText />
11
11
  </div>
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import styles from './empty-bed.scss';
2
+ import styles from './ward-bed.scss';
3
3
  import wardPatientCardStyles from '../ward-patient-card/ward-patient-card.scss';
4
4
  import { type Bed } from '../types';
5
5
  import { useTranslation } from 'react-i18next';
@@ -12,11 +12,11 @@ const EmptyBed: React.FC<EmptyBedProps> = ({ bed }) => {
12
12
  const { t } = useTranslation();
13
13
 
14
14
  return (
15
- <div className={styles.container}>
15
+ <div className={styles.emptyBed}>
16
16
  <span className={`${wardPatientCardStyles.wardPatientBedNumber} ${wardPatientCardStyles.empty}`}>
17
17
  {bed.bedNumber}
18
18
  </span>
19
- <p className={styles.emptyBed}>{t('emptyBed', 'Empty bed')}</p>
19
+ <p className={styles.emptyBedText}>{t('emptyBed', 'Empty bed')}</p>
20
20
  </div>
21
21
  );
22
22
  };
@@ -0,0 +1,41 @@
1
+ import React, { type ReactNode } from 'react';
2
+ import { type Bed } from '../types';
3
+ import EmptyBed from './empty-bed.component';
4
+ import styles from './ward-bed.scss';
5
+ import { useTranslation } from 'react-i18next';
6
+ import { Tag } from '@carbon/react';
7
+
8
+ export interface WardBedProps {
9
+ patientCards: Array<ReactNode>;
10
+ bed: Bed;
11
+ }
12
+
13
+ const WardBed: React.FC<WardBedProps> = ({ bed, patientCards }) => {
14
+ return patientCards?.length > 0 ? <OccupiedBed bed={bed} patientCards={patientCards} /> : <EmptyBed bed={bed} />;
15
+ };
16
+
17
+ const OccupiedBed: React.FC<WardBedProps> = ({ patientCards }) => {
18
+ // interlace patient card with bed dividers between each of them
19
+ const patientCardsWithDividers = patientCards.flatMap((patientCard, index) => {
20
+ if (index == 0) {
21
+ return [patientCard];
22
+ } else {
23
+ return [<BedShareDivider key={'divider-' + index} />, patientCard];
24
+ }
25
+ });
26
+
27
+ return <div className={styles.occupiedBed}>{patientCardsWithDividers}</div>;
28
+ };
29
+
30
+ const BedShareDivider = () => {
31
+ const { t } = useTranslation();
32
+ return (
33
+ <div className={styles.bedDivider}>
34
+ <div className={styles.bedDividerLine}></div>
35
+ <Tag>{t('bedShare', 'Bed share')}</Tag>
36
+ <div className={styles.bedDividerLine}></div>
37
+ </div>
38
+ );
39
+ };
40
+
41
+ export default WardBed;
@@ -0,0 +1,45 @@
1
+ @use '@carbon/layout';
2
+ @use '@openmrs/esm-styleguide/src/vars';
3
+ @use '@carbon/type';
4
+
5
+ .occupiedBed {
6
+ display: flex;
7
+ flex-direction: column;
8
+ background-color: vars.$ui-02;
9
+ height: fit-content;
10
+ }
11
+
12
+ .bedDivider {
13
+ background-color: vars.$ui-02;
14
+ color: vars.$text-02;
15
+ padding: layout.$spacing-01;
16
+ display: flex;
17
+ align-items: center;
18
+ justify-content: space-between;
19
+ }
20
+
21
+ .bedDividerLine {
22
+ height: 1px;
23
+ background-color: vars.$ui-05;
24
+ width: 30%;
25
+ }
26
+ .emptyBed {
27
+ display: flex;
28
+ gap: layout.$spacing-04;
29
+ justify-content: center;
30
+ align-items: center;
31
+ border: 1px dashed vars.$ui-04;
32
+ padding: layout.$spacing-03 layout.$spacing-04;
33
+ height: fit-content;
34
+ }
35
+
36
+ .emptyBed:hover:not(.skeleton) {
37
+ border: 1px solid transparent;
38
+ box-shadow: inset 0px 0px 0px 2px vars.$color-blue-60-2;
39
+ cursor: pointer;
40
+ }
41
+
42
+ .emptyBedText {
43
+ @include type.type-style('heading-compact-01');
44
+ color: vars.$text-02;
45
+ }
@@ -10,7 +10,9 @@ import {
10
10
  } from '../../../../__mocks__';
11
11
  import { bedLayoutToBed, filterBeds } from '../ward-view/ward-view.resource';
12
12
  import useWardLocation from '../hooks/useWardLocation';
13
- import OccupiedBed from './occupied-bed.component';
13
+ import WardBed from './ward-bed.component';
14
+ import { type WardPatient } from '../types';
15
+ import DefaultWardPatientCard from '../ward-view/default-ward/default-ward-patient-card.component';
14
16
 
15
17
  const defaultConfig: WardConfigObject = getDefaultsFromConfigSchema(configSchema);
16
18
 
@@ -31,34 +33,43 @@ mockedUseWardLocation.mockReturnValue({
31
33
  const mockBedToUse = mockBedLayouts[0];
32
34
  const mockBed = bedLayoutToBed(mockBedToUse);
33
35
 
34
- const mockWardPatientProps = {
35
- admitted: true,
36
+ const mockWardPatientAliceProps: WardPatient = {
36
37
  visit: null,
37
- encounterAssigningToCurrentInpatientLocation: null,
38
- firstAdmissionOrTransferEncounter: null,
38
+ patient: mockPatientAlice,
39
+ bed: mockBed,
40
+ inpatientAdmission: null,
41
+ inpatientRequest: null,
39
42
  };
40
43
 
41
- describe('Occupied bed', () => {
44
+ const mockWardPatientBrianProps: WardPatient = {
45
+ visit: null,
46
+ patient: mockPatientBrian,
47
+ bed: mockBed,
48
+ inpatientAdmission: null,
49
+ inpatientRequest: null,
50
+ };
51
+
52
+ describe('Ward bed', () => {
42
53
  it('renders a single bed with patient details', () => {
43
- render(<OccupiedBed wardPatients={[{ ...mockWardPatientProps, patient: mockPatientAlice }]} bed={mockBed} />);
54
+ render(
55
+ <WardBed
56
+ patientCards={[<DefaultWardPatientCard key={mockPatientAlice.uuid} {...mockWardPatientAliceProps} />]}
57
+ bed={mockBed}
58
+ />,
59
+ );
44
60
  const patientName = screen.getByText('Alice Johnson');
45
61
  expect(patientName).toBeInTheDocument();
46
62
  const patientAge = `${mockPatientAlice.person.age} yrs`;
47
63
  expect(screen.getByText(patientAge)).toBeInTheDocument();
48
- const defaultAddressFields = ['cityVillage', 'country'];
49
- defaultAddressFields.forEach((addressField) => {
50
- const addressFieldValue = mockPatientAlice.person.preferredAddress[addressField] as string;
51
- expect(screen.getByText(addressFieldValue)).toBeInTheDocument();
52
- });
53
64
  });
54
65
 
55
66
  it('renders a divider for shared patients', () => {
56
67
  render(
57
- <OccupiedBed
68
+ <WardBed
58
69
  bed={mockBed}
59
- wardPatients={[
60
- { ...mockWardPatientProps, patient: mockPatientAlice },
61
- { ...mockWardPatientProps, patient: mockPatientBrian },
70
+ patientCards={[
71
+ <DefaultWardPatientCard key={mockPatientAlice.uuid} {...mockWardPatientAliceProps} />,
72
+ <DefaultWardPatientCard key={mockPatientBrian.uuid} {...mockWardPatientBrianProps} />,
62
73
  ]}
63
74
  />,
64
75
  );
@@ -1,14 +1,5 @@
1
1
  import { type ConfigSchema, Type, validators } from '@openmrs/esm-framework';
2
2
 
3
- export const defaultWardPatientCard: WardPatientCardDefinition = {
4
- id: 'default',
5
- headerRowElements: ['patient-age', 'patient-address', 'patient-identifier'],
6
- footerRowElements: [],
7
- appliedTo: null,
8
- };
9
-
10
- export const builtInPatientCardElements = ['patient-age', 'time-on-ward', 'time-since-admission', 'patient-location'];
11
-
12
3
  export const addressFields = [
13
4
  'cityVillage',
14
5
  'stateProvince',
@@ -37,11 +28,12 @@ export const addressFields = [
37
28
  type AddressField = keyof typeof addressFields;
38
29
 
39
30
  export const configSchema: ConfigSchema = {
40
- wardPatientCards: {
41
- _description: 'Configure the display of ward patient cards',
42
- obsElementDefinitions: {
31
+ patientCardElements: {
32
+ _description:
33
+ 'Configuration of various patient card elements. Each configured element must have a unique id, defined in the ward React component being used.',
34
+ obs: {
43
35
  _type: Type.Array,
44
- _description: 'Defines obs display elements that can be included in the card header or footer.',
36
+ _description: 'Configures obs values to display.',
45
37
  _default: [],
46
38
  _elements: {
47
39
  id: {
@@ -79,12 +71,16 @@ export const configSchema: ConfigSchema = {
79
71
  },
80
72
  },
81
73
  },
82
- identifierElementDefinitions: {
74
+ pendingItems: {
83
75
  _type: Type.Array,
84
- _description: `Defines patient identifier elements that can be included in the card header or footer. The default element 'patient-identifier' displays the preferred identifier.`,
76
+ _description: 'Configures pending orders and transfers to display.',
85
77
  _default: [
86
78
  {
87
- id: 'patient-identifier',
79
+ id: 'pending-items',
80
+ orders: {
81
+ orderTypes: [{ label: 'Labs', uuid: '52a447d3-a64a-11e3-9aeb-50e549534c5e' }],
82
+ },
83
+ showPendingItems: true,
88
84
  },
89
85
  ],
90
86
  _elements: {
@@ -92,23 +88,55 @@ export const configSchema: ConfigSchema = {
92
88
  _type: Type.String,
93
89
  _description: 'The unique identifier for this patient card element',
94
90
  },
95
- identifierTypeUuid: {
96
- _type: Type.UUID,
91
+ orders: {
92
+ orderTypes: {
93
+ _type: Type.Array,
94
+ _description: 'Configures pending orders and transfers to display.',
95
+ _elements: {
96
+ uuid: {
97
+ _type: Type.UUID,
98
+ _description: 'Identifies the order type.',
99
+ },
100
+ label: {
101
+ _type: Type.String,
102
+ _description:
103
+ "The label or i18n key to the translated label to display. If not provided, defaults to 'Orders'",
104
+ _default: null,
105
+ },
106
+ },
107
+ },
108
+ },
109
+ showPendingItems: {
110
+ _type: Type.Boolean,
97
111
  _description:
98
- 'The UUID of the identifier type to display. If not provided, defaults to the preferred identifier.',
99
- _default: null,
112
+ 'Optional. If true, pending items (e.g., number of pending orders) will be displayed on the patient card.',
100
113
  },
101
- label: {
114
+ },
115
+ },
116
+ patientIdentifier: {
117
+ _type: Type.Array,
118
+ _description: `Configures patient identifier to display. An unconfigured element displays the preferred identifier.`,
119
+ _default: [
120
+ {
121
+ id: 'patient-identifier',
122
+ showIdentifierLabel: false,
123
+ },
124
+ ],
125
+ _elements: {
126
+ id: {
102
127
  _type: Type.String,
128
+ _description: 'The unique identifier for this patient card element',
129
+ },
130
+ showIdentifierLabel: {
131
+ _type: Type.Boolean,
103
132
  _description:
104
- 'the custom label or i18n key to the translated label to display for patient identifier. If not provided, defaults to the patient-identifier name.',
105
- _default: null,
133
+ 'If true, the identifier type (eg: "OpenMRS ID") is shown along with the identifier itself. Defaults to false',
106
134
  },
107
135
  },
108
136
  },
109
- addressElementDefinitions: {
137
+ patientAddress: {
110
138
  _type: Type.Array,
111
- _description: 'Defines patient address elements that can be included in the card header or footer.',
139
+ _description: 'Configures patient address elements.',
112
140
  _default: [
113
141
  {
114
142
  id: 'patient-address',
@@ -132,66 +160,116 @@ export const configSchema: ConfigSchema = {
132
160
  },
133
161
  },
134
162
  },
135
- cardDefinitions: {
163
+ admissionRequestNote: {
136
164
  _type: Type.Array,
137
- _default: [defaultWardPatientCard],
138
- _description: `An array of card configuration. A card configuration can be applied to different ward locations.
139
- If multiple card configurations apply to a location, only the first one is chosen.`,
165
+ _description: 'Configures admission request notes to display.',
166
+ _default: [
167
+ {
168
+ id: 'admission-request-note',
169
+ conceptUuid: '161011AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
170
+ },
171
+ ],
140
172
  _elements: {
141
- id: {
142
- _type: Type.String,
143
- _description:
144
- 'The unique identifier for this card definition. This is used to set the name of the extension slot the card has, where the rows go. The slot name is "ward-patient-card-<id>", unless the id is "default", in which case the slot name is "ward-patient-card".',
145
- _default: 'default',
146
- },
147
- headerRowElements: {
148
- _type: Type.Array,
149
- _description: `IDs of patient card elements to appear in the header row. These can be built-in, or custom ones can be defined in patientCardElementDefinitions. Built-in elements are: '${builtInPatientCardElements.join(
150
- "', '",
151
- )}'.`,
152
- _elements: {
173
+ fields: {
174
+ id: {
153
175
  _type: Type.String,
176
+ _description: 'The unique identifier for this patient card element',
177
+ },
178
+ conceptUuid: {
179
+ _type: Type.UUID,
180
+ _description: 'Required. Identifies the concept for the admission request note.',
154
181
  },
155
182
  },
156
- footerRowElements: {
157
- _type: Type.Array,
158
- _description: `IDs of patient card elements to appear in the footer row. These can be built-in, or custom ones can be defined in patientCardElementDefinitions. Built-in elements are: '${builtInPatientCardElements.join(
159
- "', '",
160
- )}'.`,
161
- _elements: {
183
+ },
184
+ coloredObsTags: {
185
+ _type: Type.Array,
186
+ _description: 'Configures observation values to display as Carbon tags.',
187
+ _elements: {
188
+ conceptUuid: {
189
+ _type: Type.UUID,
190
+ _description: 'Required. Identifies the concept to use to identify the desired observations.',
191
+ // Problem list
192
+ _default: '1284AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
193
+ },
194
+ summaryLabel: {
162
195
  _type: Type.String,
196
+ _description: `Optional. The custom label or i18n key to the translated label to display for the summary tag. The summary tag shows the count of the number of answers that are present but not configured to show as their own tags. If not provided, defaults to the name of the concept.`,
197
+ _default: null,
163
198
  },
164
- },
165
- appliedTo: {
166
- _type: Type.Array,
167
- _description:
168
- 'Conditions under which this card definition should be used. If not provided, the configuration is applied to all wards.',
169
- _elements: {
170
- location: {
171
- _type: Type.UUID,
172
- _description: 'The UUID of the location. If not provided, applies to all wards.',
173
- _default: null,
199
+ summaryLabelI18nModule: {
200
+ _type: Type.String,
201
+ _description: 'Optional. The custom module to use for translation of the summary label',
202
+ _default: null,
203
+ },
204
+ summaryLabelColor: {
205
+ _type: Type.String,
206
+ _description:
207
+ 'The color of the summary tag. See https://react.carbondesignsystem.com/?path=/docs/components-tag--overview for a list of supported colors',
208
+ _default: null,
209
+ },
210
+ tags: {
211
+ _type: Type.Array,
212
+ _description: `An array specifying concept sets and color. Observations with coded values that are members of the specified concept sets will be displayed as their own tags with the specified color. Any observation with coded values not belonging to any concept sets specified will be summarized as a count in the summary tag. If a concept set is listed multiple times, the first matching applied-to rule takes precedence.`,
213
+ _default: [],
214
+ _elements: {
215
+ color: {
216
+ _type: Type.String,
217
+ _description:
218
+ 'Color of the tag. See https://react.carbondesignsystem.com/?path=/docs/components-tag--overview for a list of supported colors.',
219
+ },
220
+ appliedToConceptSets: {
221
+ _type: Type.Array,
222
+ _description: `The concept sets which the color applies to. Observations with coded values that are members of the specified concept sets will be displayed as their own tag with the specified color. If an observation's coded value belongs to multiple concept sets, the first matching applied-to rule takes precedence.`,
223
+ _elements: {
224
+ _type: Type.UUID,
225
+ },
226
+ },
174
227
  },
175
228
  },
176
229
  },
177
230
  },
178
231
  },
179
232
  },
233
+ wards: {
234
+ _description: 'Configuration of what type of ward to use at different ward locations.',
235
+ _type: Type.Array,
236
+ _default: [{ id: 'default-ward' }],
237
+ _elements: {
238
+ id: {
239
+ _type: Type.String,
240
+ _description:
241
+ 'The ward type to use. Currently, "default-ward" and "maternal-ward" are supported. This string also serves as the extension slot name for the ward view.',
242
+ },
243
+ appliedTo: {
244
+ _type: Type.Array,
245
+ _description:
246
+ 'Optional. Conditions under which this card definition should be used. If not provided, the configuration is applied to all wards.',
247
+ _elements: {
248
+ location: {
249
+ _type: Type.UUID,
250
+ _description: 'The UUID of the location. If not provided, applies to all wards.',
251
+ _default: null,
252
+ },
253
+ },
254
+ },
255
+ },
256
+ },
180
257
  };
181
258
 
182
259
  export interface WardConfigObject {
183
- wardPatientCards: WardPatientCardsConfig;
184
- }
185
-
186
- export interface WardPatientCardsConfig {
187
- obsElementDefinitions: Array<ObsElementDefinition>;
188
- pendingItemsDefinitions: Array<PendingItemsDefinition>;
189
- identifierElementDefinitions: Array<IdentifierElementDefinition>;
190
- addressElementDefinitions: Array<AddressElementDefinition>;
191
- cardDefinitions: Array<WardPatientCardDefinition>;
260
+ patientCardElements: {
261
+ obs: Array<ObsElementConfig>;
262
+ pendingItems: Array<PendingItemsElementConfig>;
263
+ patientIdentifier: Array<IdentifierElementConfig>;
264
+ patientAddress: Array<PatientAddressElementConfig>;
265
+ coloredObsTags: Array<ColoredObsTagsElementConfig>;
266
+ admissionRequestNote: Array<AdmissionRequestNoteElementConfig>;
267
+ };
268
+ wards: Array<WardDefinition>;
192
269
  }
193
270
 
194
- export interface PendingItemsDefinition {
271
+ export interface PendingItemsElementConfig {
272
+ id: string;
195
273
  showPendingItems: boolean;
196
274
  orders: {
197
275
  orderTypes: Array<{
@@ -201,7 +279,7 @@ export interface PendingItemsDefinition {
201
279
  };
202
280
  }
203
281
 
204
- export interface ObsElementDefinition {
282
+ export interface ObsElementConfig {
205
283
  id: string;
206
284
  conceptUuid: string;
207
285
  onlyWithinCurrentVisit: boolean;
@@ -210,21 +288,23 @@ export interface ObsElementDefinition {
210
288
  label?: string;
211
289
  }
212
290
 
213
- export interface IdentifierElementDefinition {
291
+ export interface IdentifierElementConfig {
214
292
  id: string;
215
- identifierTypeUuid: string;
216
- label?: string;
293
+ showIdentifierLabel: boolean;
217
294
  }
218
295
 
219
- export interface AddressElementDefinition {
296
+ export interface PatientAddressElementConfig {
220
297
  id: string;
221
298
  fields: Array<AddressField>;
222
299
  }
223
300
 
224
- export interface WardPatientCardDefinition {
301
+ export interface AdmissionRequestNoteElementConfig {
302
+ id: string;
303
+ conceptUuid: string;
304
+ }
305
+
306
+ export interface WardDefinition {
225
307
  id: string;
226
- headerRowElements: Array<string>;
227
- footerRowElements: Array<string>;
228
308
  appliedTo?: Array<{
229
309
  /**
230
310
  * locationUuid. If given, only applies to patients at the specified ward locations. (If not provided, applies to all locations)
@@ -232,3 +312,44 @@ export interface WardPatientCardDefinition {
232
312
  location: string;
233
313
  }>;
234
314
  }
315
+ export interface ColoredObsTagsElementConfig {
316
+ /**
317
+ * Required. Identifies the concept to use to identify the desired observations.
318
+ */
319
+ conceptUuid: string;
320
+
321
+ /**
322
+ * Optional. The custom label or i18n key to the translated label to display for the summary tag. The summary tag
323
+ * shows the count of the number of answers that are present but not configured to show as their own tags. If not
324
+ * provided, defaults to the name of the concept.
325
+ */
326
+ summaryLabel?: string;
327
+
328
+ /**
329
+ * The color of the summary tag.
330
+ * See https://react.carbondesignsystem.com/?path=/docs/components-tag--overview for a list of supported colors
331
+ */
332
+ summaryLabelColor?: string;
333
+
334
+ /**
335
+ * An array specifying concept sets and color. Observations with coded values that are members of the specified concept sets
336
+ * will be displayed as their own tags with the specified color. Any observation with coded values not belonging to
337
+ * any concept sets specified will be summarized as a count in the summary tag. If a concept set is listed multiple times,
338
+ * the first matching applied-to rule takes precedence.
339
+ */
340
+ tags: Array<ColoredObsTagConfig>;
341
+ }
342
+
343
+ export interface ColoredObsTagConfig {
344
+ /**
345
+ * Color of the tag. See https://react.carbondesignsystem.com/?path=/docs/components-tag--overview for a list of supported colors.
346
+ */
347
+ color: string;
348
+
349
+ /**
350
+ * The concept sets which the color applies to. Observations with coded values that are members of the specified concept sets
351
+ * will be displayed as their own tag with the specified color.
352
+ * If an observation's coded value belongs to multiple concept sets, the first matching applied-to rule takes precedence.
353
+ */
354
+ appliedToConceptSets: Array<string>;
355
+ }
@@ -0,0 +1,9 @@
1
+ import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
+ import { type BedDetail } from '../types';
3
+ import useSWR from 'swr';
4
+
5
+ export function useAssignedBedByPatient(patientUuid: string) {
6
+ const url = `${restBaseUrl}/beds?patientUuid=${patientUuid}`;
7
+
8
+ return useSWR<{ data: { results: Array<BedDetail> } }, Error>(url, openmrsFetch);
9
+ }
@@ -8,7 +8,7 @@ export function useInpatientAdmission() {
8
8
  // prettier-ignore
9
9
  const customRepresentation =
10
10
  'custom:(visit,' +
11
- 'patient:(uuid,identifiers,voided,' +
11
+ 'patient:(uuid,identifiers:(uuid,display,identifier,identifierType),voided,' +
12
12
  'person:(uuid,display,gender,age,birthdate,birthtime,preferredName,preferredAddress,dead,deathDate)),' +
13
13
  'encounterAssigningToCurrentInpatientLocation:(encounterDatetime),' +
14
14
  'currentInpatientRequest:(dispositionLocation,dispositionType,disposition:(uuid,display),dispositionEncounter:(uuid,display),dispositionObsGroup:(uuid,display),visit:(uuid),patient:(uuid)),' +
@@ -1,5 +1,5 @@
1
1
  import { makeUrl, restBaseUrl, useOpenmrsFetchAll } from '@openmrs/esm-framework';
2
- import { type MotherAndChildren } from '../types';
2
+ import { type MotherAndChild } from '../types';
3
3
 
4
4
  export interface MothersAndChildrenSearchCriteria {
5
5
  mothers?: Array<string>;
@@ -38,7 +38,7 @@ export function useMotherAndChildren(
38
38
  requireChildBornDuringMothersActiveVisit?.toString() ?? 'false',
39
39
  );
40
40
  rep && url.searchParams.append('v', rep);
41
- return useOpenmrsFetchAll<MotherAndChildren>(fetch ? url : null);
41
+ return useOpenmrsFetchAll<MotherAndChild>(fetch ? url : null);
42
42
  }
43
43
 
44
44
  function makeUrlUrl(path: string) {
@@ -6,12 +6,12 @@ interface ObsSearchCriteria {
6
6
  concept: string;
7
7
  }
8
8
 
9
- export function useObs(criteria?: ObsSearchCriteria, representation = 'default') {
9
+ export function useObs(criteria?: ObsSearchCriteria, fetch: boolean = true, representation = 'default') {
10
10
  const params = new URLSearchParams({
11
11
  ...criteria,
12
12
  v: representation,
13
13
  });
14
14
 
15
15
  const apiUrl = `${restBaseUrl}/obs?${params}`;
16
- return useOpenmrsFetchAll<Observation>(apiUrl);
16
+ return useOpenmrsFetchAll<Observation>(fetch ? apiUrl : null);
17
17
  }