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

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 (143) hide show
  1. package/.turbo/turbo-build.log +18 -17
  2. package/dist/109.js +1 -0
  3. package/dist/109.js.map +1 -0
  4. package/dist/125.js +1 -0
  5. package/dist/125.js.map +1 -0
  6. package/dist/126.js +1 -0
  7. package/dist/126.js.map +1 -0
  8. package/dist/130.js +1 -1
  9. package/dist/130.js.map +1 -1
  10. package/dist/146.js +1 -0
  11. package/dist/146.js.map +1 -0
  12. package/dist/15.js +1 -0
  13. package/dist/15.js.map +1 -0
  14. package/dist/161.js +2 -0
  15. package/dist/161.js.map +1 -0
  16. package/dist/269.js +1 -1
  17. package/dist/269.js.map +1 -1
  18. package/dist/466.js +1 -1
  19. package/dist/466.js.map +1 -1
  20. package/dist/500.js +1 -0
  21. package/dist/500.js.map +1 -0
  22. package/dist/53.js +1 -0
  23. package/dist/53.js.map +1 -0
  24. package/dist/557.js +1 -0
  25. package/dist/557.js.map +1 -0
  26. package/dist/559.js +1 -0
  27. package/dist/559.js.map +1 -0
  28. package/dist/574.js +1 -1
  29. package/dist/577.js +1 -1
  30. package/dist/577.js.map +1 -1
  31. package/dist/659.js +1 -1
  32. package/dist/659.js.map +1 -1
  33. package/dist/701.js +1 -0
  34. package/dist/701.js.map +1 -0
  35. package/dist/749.js +1 -1
  36. package/dist/749.js.map +1 -1
  37. package/dist/908.js +1 -0
  38. package/dist/908.js.map +1 -0
  39. package/dist/922.js +1 -0
  40. package/dist/922.js.map +1 -0
  41. package/dist/969.js +1 -0
  42. package/dist/969.js.map +1 -0
  43. package/dist/kenyaemr-esm-ward-app.js +1 -1
  44. package/dist/kenyaemr-esm-ward-app.js.buildmanifest.json +294 -74
  45. package/dist/kenyaemr-esm-ward-app.js.map +1 -1
  46. package/dist/main.js +1 -1
  47. package/dist/main.js.map +1 -1
  48. package/dist/routes.json +1 -1
  49. package/mock.tsx +54 -0
  50. package/package.json +1 -1
  51. package/src/action-menu-buttons/clinical-forms-workspace-siderail.component.tsx +37 -0
  52. package/src/action-menu-buttons/discharge-workspace-siderail.component.tsx +20 -0
  53. package/src/beds/empty-bed-skeleton.tsx +2 -1
  54. package/src/beds/empty-bed.scss +0 -4
  55. package/src/beds/occupied-bed.scss +1 -0
  56. package/src/config-schema-mother-child-row.ts +26 -0
  57. package/src/config-schema-pending-items-extension.ts +29 -0
  58. package/src/config-schema.ts +12 -14
  59. package/src/hooks/useAdmissionLocation.ts +22 -4
  60. package/src/hooks/useBeds.ts +3 -4
  61. package/src/hooks/useConcept.ts +3 -4
  62. package/src/hooks/useEmrConfiguration.ts +5 -0
  63. package/src/hooks/useInpatientAdmission.ts +9 -14
  64. package/src/hooks/useInpatientRequest.ts +4 -15
  65. package/src/hooks/useLocations.ts +8 -51
  66. package/src/hooks/useMotherAndChildren.ts +46 -0
  67. package/src/hooks/useObs.ts +2 -6
  68. package/src/hooks/usePatientPendingOrders.ts +16 -0
  69. package/src/hooks/useWardPatientGrouping.ts +25 -0
  70. package/src/index.ts +50 -3
  71. package/src/location-selector/location-selector.component.tsx +18 -21
  72. package/src/routes.json +43 -0
  73. package/src/types/index.ts +34 -0
  74. package/src/ward-patient-card/card-rows/admission-request-note.extension.tsx +7 -2
  75. package/src/ward-patient-card/card-rows/mother-child-row.extension.tsx +110 -0
  76. package/src/ward-patient-card/card-rows/mother-child-row.scss +22 -0
  77. package/src/ward-patient-card/card-rows/pending-items-car-row.extension.tsx +50 -0
  78. package/src/ward-patient-card/row-elements/ward-pateint-skeleton-text.tsx +9 -0
  79. package/src/ward-patient-card/row-elements/ward-patient-age.tsx +1 -1
  80. package/src/ward-patient-card/row-elements/ward-patient-coded-obs-tags.tsx +54 -36
  81. package/src/ward-patient-card/row-elements/ward-patient-identifier.tsx +2 -3
  82. package/src/ward-patient-card/row-elements/ward-patient-location.tsx +19 -0
  83. package/src/ward-patient-card/row-elements/ward-patient-obs.resource.ts +36 -32
  84. package/src/ward-patient-card/row-elements/ward-patient-obs.tsx +15 -9
  85. package/src/ward-patient-card/row-elements/ward-patient-pending-order.component.tsx +45 -0
  86. package/src/ward-patient-card/row-elements/ward-patient-pending-transfer.tsx +38 -0
  87. package/src/ward-patient-card/row-elements/ward-patient-responsive-tooltip.tsx +32 -0
  88. package/src/ward-patient-card/ward-patient-card-element.component.tsx +4 -0
  89. package/src/ward-patient-card/ward-patient-card.component.tsx +21 -14
  90. package/src/ward-patient-card/ward-patient-card.scss +61 -8
  91. package/src/ward-patient-card/ward-patient-resource.ts +15 -0
  92. package/src/ward-view/ward-view.component.tsx +124 -132
  93. package/src/ward-view/ward-view.resource.ts +121 -1
  94. package/src/ward-view/ward-view.scss +16 -6
  95. package/src/ward-view/ward-view.test.tsx +27 -42
  96. package/src/ward-view-header/admission-requests-bar.component.tsx +8 -7
  97. package/src/ward-view-header/admission-requests-bar.test.tsx +8 -21
  98. package/src/ward-view-header/admission-requests.scss +1 -1
  99. package/src/ward-view-header/ward-metric.component.tsx +24 -0
  100. package/src/ward-view-header/ward-metric.scss +25 -0
  101. package/src/ward-view-header/ward-metrics.component.tsx +77 -0
  102. package/src/ward-view-header/ward-metrics.scss +8 -0
  103. package/src/ward-view-header/ward-metrics.test.tsx +91 -0
  104. package/src/ward-view-header/ward-view-header.component.tsx +3 -0
  105. package/src/ward-view-header/ward-view-header.scss +0 -1
  106. package/src/ward-workspace/admission-request-card/admission-request-card-actions.component.tsx +11 -3
  107. package/src/ward-workspace/admission-request-card/admission-request-card-header.component.tsx +4 -5
  108. package/src/ward-workspace/admission-request-card/admission-request-card.scss +8 -4
  109. package/src/ward-workspace/admission-request-workspace/admission-requests-workspace.test.tsx +8 -3
  110. package/src/ward-workspace/admission-request-workspace/admission-requests.workspace.tsx +2 -0
  111. package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.test.tsx +29 -61
  112. package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.workspace.tsx +37 -21
  113. package/src/ward-workspace/patient-banner/patient-banner.component.tsx +3 -3
  114. package/src/ward-workspace/patient-clinical-forms-workspace/patient-clinical-forms.workspace.tsx +23 -0
  115. package/src/{ward-patient-workspace → ward-workspace/patient-details}/ward-patient-action-button.extension.tsx +2 -1
  116. package/src/{ward-patient-workspace → ward-workspace/patient-details}/ward-patient.workspace.tsx +7 -5
  117. package/src/ward-workspace/patient-discharge/patient-discharge.scss +41 -0
  118. package/src/ward-workspace/patient-discharge/patient-discharge.workspace.tsx +120 -0
  119. package/src/ward-workspace/patient-transfer-bed-swap/patient-bed-swap-form.component.tsx +40 -30
  120. package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-request-form.component.tsx +29 -22
  121. package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-swap.scss +12 -2
  122. package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-swap.workspace.tsx +2 -2
  123. package/src/ward-workspace/patient-transfer-request-workspace/patient-transfer-request.workspace.tsx +11 -0
  124. package/src/ward-workspace/ward-patient-notes/form/notes-form.component.tsx +1 -1
  125. package/src/ward-workspace/ward-patient-notes/form/notes-form.test.tsx +1 -1
  126. package/src/ward-workspace/ward-patient-notes/history/notes-container.component.tsx +2 -2
  127. package/src/ward-workspace/ward-patient-notes/notes.resource.ts +5 -7
  128. package/src/ward-workspace/ward-patient-notes/notes.workspace.tsx +1 -1
  129. package/src/ward-workspace/ward-patient-notes/types.ts +0 -4
  130. package/src/ward.resource.ts +6 -0
  131. package/translations/en.json +18 -1
  132. package/dist/346.js +0 -1
  133. package/dist/346.js.map +0 -1
  134. package/dist/76.js +0 -1
  135. package/dist/76.js.map +0 -1
  136. package/dist/803.js +0 -1
  137. package/dist/803.js.map +0 -1
  138. package/dist/958.js +0 -2
  139. package/dist/958.js.map +0 -1
  140. package/dist/960.js +0 -1
  141. package/dist/960.js.map +0 -1
  142. /package/dist/{958.js.LICENSE.txt → 161.js.LICENSE.txt} +0 -0
  143. /package/src/{ward-patient-workspace → ward-workspace/patient-details}/ward-patient.style.scss +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"},{"component":"admissionRequestNoteRowExtension","name":"admission-request-note-card-row","slot":"ward-patient-card-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"}],"version":"8.1.1-pre.114"}
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"}
package/mock.tsx ADDED
@@ -0,0 +1,54 @@
1
+ import { mockAdmissionLocation, mockInpatientAdmissions, mockInpatientRequest } from '__mocks__';
2
+ import { useAdmissionLocation } from './src/hooks/useAdmissionLocation';
3
+ import { useInpatientAdmission } from './src/hooks/useInpatientAdmission';
4
+ import { createAndGetWardPatientGrouping } from './src/ward-view/ward-view.resource';
5
+ import { useInpatientRequest } from './src/hooks/useInpatientRequest';
6
+ import { useWardPatientGrouping } from './src/hooks/useWardPatientGrouping';
7
+
8
+ jest.mock('./src/hooks/useAdmissionLocation', () => ({
9
+ useAdmissionLocation: jest.fn(),
10
+ }));
11
+ jest.mock('./src/hooks/useInpatientAdmission', () => ({
12
+ useInpatientAdmission: jest.fn(),
13
+ }));
14
+ jest.mock('./src/hooks/useInpatientRequest', () => ({
15
+ useInpatientRequest: jest.fn(),
16
+ }));
17
+ jest.mock('./src/hooks/useWardPatientGrouping', () => ({
18
+ useWardPatientGrouping: jest.fn(),
19
+ }));
20
+ const mockAdmissionLocationResponse = jest.mocked(useAdmissionLocation).mockReturnValue({
21
+ error: undefined,
22
+ mutate: jest.fn(),
23
+ isValidating: false,
24
+ isLoading: false,
25
+ admissionLocation: mockAdmissionLocation,
26
+ });
27
+ const mockInpatientAdmissionResponse = jest.mocked(useInpatientAdmission).mockReturnValue({
28
+ data: mockInpatientAdmissions,
29
+ hasMore: false,
30
+ loadMore: jest.fn(),
31
+ isValidating: false,
32
+ isLoading: false,
33
+ error: undefined,
34
+ mutate: jest.fn(),
35
+ totalCount: mockInpatientAdmissions.length,
36
+ });
37
+
38
+ const mockInpatientRequestResponse = jest.mocked(useInpatientRequest).mockReturnValue({
39
+ inpatientRequests: mockInpatientRequest,
40
+ hasMore: false,
41
+ loadMore: jest.fn(),
42
+ isValidating: false,
43
+ isLoading: false,
44
+ error: undefined,
45
+ mutate: jest.fn(),
46
+ totalCount: mockInpatientRequest.length,
47
+ });
48
+
49
+ export const mockWardPatientGroupDetails = jest.mocked(useWardPatientGrouping).mockReturnValue({
50
+ admissionLocationResponse: mockAdmissionLocationResponse(),
51
+ inpatientAdmissionResponse: mockInpatientAdmissionResponse(),
52
+ inpatientRequestResponse: mockInpatientRequestResponse(),
53
+ ...createAndGetWardPatientGrouping(mockInpatientAdmissions, mockAdmissionLocation, mockInpatientRequest),
54
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kenyaemr/esm-ward-app",
3
- "version": "8.1.1-pre.114",
3
+ "version": "8.1.1-pre.118",
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",
@@ -0,0 +1,37 @@
1
+ import React from 'react';
2
+ import { Document } from '@carbon/react/icons';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { ActionMenuButton, launchWorkspace, useWorkspaces } from '@openmrs/esm-framework';
5
+ import type { WardPatientWorkspaceProps } from '../types';
6
+
7
+ const ClinicalFormsWorkspaceSideRailIcon: React.FC = () => {
8
+ const { t } = useTranslation();
9
+ const { workspaces } = useWorkspaces();
10
+
11
+ const formEntryWorkspaces = workspaces.filter((w) => w.name === 'ward-patient-form-entry-workspace');
12
+ const recentlyOpenedForm = formEntryWorkspaces[0];
13
+
14
+ const isClinicalFormOpen = formEntryWorkspaces?.length >= 1;
15
+
16
+ const launchPatientWorkspaceCb = () => {
17
+ if (isClinicalFormOpen) {
18
+ launchWorkspace('ward-patient-form-entry-workspace', {
19
+ workspaceTitle: recentlyOpenedForm?.additionalProps?.['workspaceTitle'],
20
+ });
21
+ } else {
22
+ launchWorkspace<WardPatientWorkspaceProps>('ward-patient-clinical-forms-workspace');
23
+ }
24
+ };
25
+
26
+ return (
27
+ <ActionMenuButton
28
+ getIcon={(props) => <Document {...props} />}
29
+ label={t('clinicalForms', 'Clinical forms')}
30
+ iconDescription={t('clinicalForms', 'Clinical forms')}
31
+ handler={launchPatientWorkspaceCb}
32
+ type="ward-patient-clinical-form"
33
+ />
34
+ );
35
+ };
36
+
37
+ export default ClinicalFormsWorkspaceSideRailIcon;
@@ -0,0 +1,20 @@
1
+ import { ActionMenuButton, launchWorkspace } from '@openmrs/esm-framework';
2
+ import React from 'react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { Exit } from '@carbon/react/icons';
5
+
6
+ export default function PatientDischargeSideRailIcon() {
7
+ const { t } = useTranslation();
8
+ const handler = () => {
9
+ launchWorkspace('patient-discharge-workspace');
10
+ };
11
+ return (
12
+ <ActionMenuButton
13
+ getIcon={(props) => <Exit {...props} />}
14
+ label={t('discharge', 'Discharge')}
15
+ iconDescription={t('discharge', 'Discharge')}
16
+ handler={handler}
17
+ type="patient-discharge-workspace"
18
+ />
19
+ );
20
+ }
@@ -1,12 +1,13 @@
1
1
  import { SkeletonIcon } from '@carbon/react';
2
2
  import React from 'react';
3
3
  import styles from './empty-bed.scss';
4
+ import WardPatientSkeletonText from '../ward-patient-card/row-elements/ward-pateint-skeleton-text';
4
5
 
5
6
  const EmptyBedSkeleton = () => {
6
7
  return (
7
8
  <div className={styles.container + ' ' + styles.skeleton}>
8
9
  <SkeletonIcon />
9
- <SkeletonIcon className={styles.skeletonText} />
10
+ <WardPatientSkeletonText />
10
11
  </div>
11
12
  );
12
13
  };
@@ -22,7 +22,3 @@
22
22
  @include type.type-style('heading-compact-01');
23
23
  color: $text-02;
24
24
  }
25
-
26
- .skeletonText {
27
- width: 6.25rem;
28
- }
@@ -5,6 +5,7 @@
5
5
  display: flex;
6
6
  flex-direction: column;
7
7
  background-color: vars.$ui-02;
8
+ height: fit-content;
8
9
  }
9
10
 
10
11
  .bedDivider {
@@ -0,0 +1,26 @@
1
+ import { Type } from '@openmrs/esm-framework';
2
+
3
+ export const motherChildRowConfigSchema = {
4
+ maternalLocations: {
5
+ _type: Type.Array,
6
+ _description: 'Defines obs display elements that can be included in the card header or footer.',
7
+ _default: [],
8
+ _elements: {
9
+ id: {
10
+ _type: Type.UUID,
11
+ _description: 'The unique identifier for this ward location',
12
+ },
13
+ }
14
+ },
15
+ childLocations: {
16
+ _type: Type.Array,
17
+ _description: 'Defines obs display elements that can be included in the card header or footer.',
18
+ _default: [],
19
+ _elements: {
20
+ id: {
21
+ _type: Type.UUID,
22
+ _description: 'The unique identifier for this ward location',
23
+ },
24
+ }
25
+ }
26
+ };
@@ -0,0 +1,29 @@
1
+ import { Type } from '@openmrs/esm-framework';
2
+
3
+ export const pendingItemsExtensionConfigSchema = {
4
+ orders: {
5
+ orderTypes: {
6
+ _type: Type.Array,
7
+ _description: 'Defines order types displayed on the ward patient card pending items section.',
8
+ _default: [{ label: 'Labs', uuid: '52a447d3-a64a-11e3-9aeb-50e549534c5e' }],
9
+ _elements: {
10
+ uuid: {
11
+ _type: Type.UUID,
12
+ _description: 'Identifies the order type.',
13
+ },
14
+ label: {
15
+ _type: Type.String,
16
+ _description:
17
+ "The label or i18n key to the translated label to display. If not provided, defaults to 'Orders'",
18
+ _default: null,
19
+ },
20
+ },
21
+ },
22
+ },
23
+ showPendingItems: {
24
+ _type: Type.Boolean,
25
+ _description:
26
+ 'Optional. If true, pending items (e.g., number of pending orders) will be displayed on the patient card.',
27
+ _default: true,
28
+ },
29
+ };
@@ -7,7 +7,7 @@ export const defaultWardPatientCard: WardPatientCardDefinition = {
7
7
  appliedTo: null,
8
8
  };
9
9
 
10
- export const builtInPatientCardElements = ['patient-age', 'time-on-ward', 'time-since-admission'];
10
+ export const builtInPatientCardElements = ['patient-age', 'time-on-ward', 'time-since-admission', 'patient-location'];
11
11
 
12
12
  export const addressFields = [
13
13
  'cityVillage',
@@ -58,12 +58,6 @@ export const configSchema: ConfigSchema = {
58
58
  "Optional. The custom label or i18n key to the translated label to display. If not provided, defaults to the concept's name. (Note that this can be set to an empty string to not show a label)",
59
59
  _default: null,
60
60
  },
61
- labelI18nModule: {
62
- _type: Type.String,
63
- _description:
64
- 'Optional. The custom module to use for translation of the label. If not provided, the label will not be translated.',
65
- _default: null,
66
- },
67
61
  orderBy: {
68
62
  _type: Type.String,
69
63
  _description:
@@ -110,11 +104,6 @@ export const configSchema: ConfigSchema = {
110
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.',
111
105
  _default: null,
112
106
  },
113
- labelI18nModule: {
114
- _type: Type.String,
115
- _description: 'Optional. The custom module to use for translation of the label',
116
- _default: null,
117
- },
118
107
  },
119
108
  },
120
109
  addressElementDefinitions: {
@@ -196,11 +185,22 @@ export interface WardConfigObject {
196
185
 
197
186
  export interface WardPatientCardsConfig {
198
187
  obsElementDefinitions: Array<ObsElementDefinition>;
188
+ pendingItemsDefinitions: Array<PendingItemsDefinition>;
199
189
  identifierElementDefinitions: Array<IdentifierElementDefinition>;
200
190
  addressElementDefinitions: Array<AddressElementDefinition>;
201
191
  cardDefinitions: Array<WardPatientCardDefinition>;
202
192
  }
203
193
 
194
+ export interface PendingItemsDefinition {
195
+ showPendingItems: boolean;
196
+ orders: {
197
+ orderTypes: Array<{
198
+ label?: string;
199
+ uuid: string;
200
+ }>;
201
+ };
202
+ }
203
+
204
204
  export interface ObsElementDefinition {
205
205
  id: string;
206
206
  conceptUuid: string;
@@ -208,14 +208,12 @@ export interface ObsElementDefinition {
208
208
  orderBy: 'ascending' | 'descending';
209
209
  limit: number;
210
210
  label?: string;
211
- labelI18nModule?: string;
212
211
  }
213
212
 
214
213
  export interface IdentifierElementDefinition {
215
214
  id: string;
216
215
  identifierTypeUuid: string;
217
216
  label?: string;
218
- labelI18nModule?: string;
219
217
  }
220
218
 
221
219
  export interface AddressElementDefinition {
@@ -1,16 +1,34 @@
1
- import { type FetchResponse, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
1
+ import { type FetchResponse, openmrsFetch, restBaseUrl, useFeatureFlag } from '@openmrs/esm-framework';
2
+ import useSWR from 'swr';
2
3
  import { type AdmissionLocationFetchResponse } from '../types/index';
3
- import useSWRImmutable from 'swr/immutable';
4
4
  import useWardLocation from './useWardLocation';
5
5
 
6
6
  const requestRep =
7
7
  'custom:(ward,totalBeds,occupiedBeds,bedLayouts:(rowNumber,columnNumber,bedNumber,bedId,bedUuid,status,location,patients:(person:full,identifiers,uuid)))';
8
8
 
9
- // note "admissionLocation" sn't the clearest name, but it matches the endpoint; endpoint fetches bed information (including info about patients in those beds) for a location (as provided by the bed management module)
9
+ /**
10
+ *
11
+ * Fetches bed information (including info about patients in those beds) for a location,
12
+ * as provided by the bed management module. If the bed management module is not installed,
13
+ * then no request will be made, the return object's
14
+ * `isLoading` field will be false, and the `admissionLocation` field will be undefined.
15
+ *
16
+ * Note that "admissionLocation" isn't the clearest name, but it matches the endpoint name
17
+ *
18
+ * @param rep the "v=" representation parameter
19
+ * @returns
20
+ */
10
21
  export function useAdmissionLocation(rep: string = requestRep) {
11
22
  const { location } = useWardLocation();
23
+
24
+ const isBedManagementModuleInstalled = useFeatureFlag('bedmanagement-module');
25
+
12
26
  const apiUrl = location?.uuid ? `${restBaseUrl}/admissionLocation/${location?.uuid}?v=${rep}` : null;
13
- const { data, ...rest } = useSWRImmutable<FetchResponse<AdmissionLocationFetchResponse>, Error>(apiUrl, openmrsFetch);
27
+ const { data, ...rest } = useSWR<FetchResponse<AdmissionLocationFetchResponse>, Error>(
28
+ isBedManagementModuleInstalled ? apiUrl : null,
29
+ openmrsFetch,
30
+ );
31
+
14
32
  return {
15
33
  admissionLocation: data?.data,
16
34
  ...rest,
@@ -1,5 +1,4 @@
1
- import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
- import useSWR from 'swr';
1
+ import { restBaseUrl, useOpenmrsFetchAll } from '@openmrs/esm-framework';
3
2
  import { type Bed, type BedStatus } from '../types/index';
4
3
 
5
4
  interface BedSearchCriteria {
@@ -17,10 +16,10 @@ export function useBeds(searchCriteria?: BedSearchCriteria) {
17
16
  }
18
17
 
19
18
  const apiUrl = `${restBaseUrl}/bed?${searchParam}`;
20
- const { data, ...rest } = useSWR<{ data: { results: Array<Bed> } }, Error>(apiUrl, openmrsFetch);
19
+ const { data, ...rest } = useOpenmrsFetchAll<Bed>(apiUrl);
21
20
 
22
21
  return {
23
- beds: data?.data?.results ?? [],
22
+ beds: data,
24
23
  ...rest,
25
24
  };
26
25
  }
@@ -1,11 +1,10 @@
1
- import { type Concept, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
- import useSWRImmutable from 'swr/immutable';
1
+ import { type Concept, restBaseUrl, useOpenmrsFetchAll } from '@openmrs/esm-framework';
3
2
 
4
3
  export function useConcepts(uuids: string[], rep = 'default') {
5
4
  const apiUrl = `${restBaseUrl}/concept?references=${uuids.join()}&v=${rep}`;
6
- const { data, ...rest } = useSWRImmutable<{ data: { results: Array<Concept> } }, Error>(apiUrl, openmrsFetch);
5
+ const { data, ...rest } = useOpenmrsFetchAll<Concept>(apiUrl, { immutable: true });
7
6
  return {
8
- concepts: data?.data?.results,
7
+ concepts: data,
9
8
  ...rest,
10
9
  };
11
10
  }
@@ -12,7 +12,10 @@ interface EmrApiConfigurationResponse {
12
12
  clinicianEncounterRole: OpenmrsResource;
13
13
  consultFreeTextCommentsConcept: OpenmrsResource;
14
14
  visitNoteEncounterType: OpenmrsResource;
15
+ inpatientNoteEncounterType: OpenmrsResource;
16
+ transferRequestEncounterType: OpenmrsResource;
15
17
  transferWithinHospitalEncounterType: OpenmrsResource;
18
+ exitFromInpatientEncounterType: OpenmrsResource;
16
19
  supportsTransferLocationTag: LocationTag;
17
20
  supportsAdmissionLocationTag: LocationTag;
18
21
  supportsLoginLocationTag: LocationTag;
@@ -64,6 +67,8 @@ const customRepProps = [
64
67
  ['diagnosisSets', 'ref'],
65
68
  ['personImageDirectory', 'ref'],
66
69
  ['visitNoteEncounterType', 'ref'],
70
+ ['inpatientNoteEncounterType', 'ref'],
71
+ ['transferRequestEncounterType', 'ref'],
67
72
  ['consultEncounterType', 'ref'],
68
73
  ['diagnosisMetadata', 'ref'],
69
74
  ['narrowerThanConceptMapType', 'ref'],
@@ -1,6 +1,5 @@
1
- import useSWR from 'swr';
2
- import { type FetchResponse, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
3
- import { type InpatientAdmissionFetchResponse } from '../types';
1
+ import { restBaseUrl, useOpenmrsFetchAll } from '@openmrs/esm-framework';
2
+ import { type InpatientAdmission } from '../types';
4
3
  import useWardLocation from './useWardLocation';
5
4
 
6
5
  export function useInpatientAdmission() {
@@ -9,20 +8,16 @@ export function useInpatientAdmission() {
9
8
  // prettier-ignore
10
9
  const customRepresentation =
11
10
  'custom:(visit,' +
12
- 'patient:(uuid,identifiers,voided,' +
13
- 'person:(uuid,display,gender,age,birthdate,birthtime,preferredName,preferredAddress,dead,deathDate)),' +
14
- 'encounterAssigningToCurrentInpatientLocation:(encounterDatetime),' +
15
- 'firstAdmissionOrTransferEncounter:(encounterDatetime),' +
11
+ 'patient:(uuid,identifiers,voided,' +
12
+ 'person:(uuid,display,gender,age,birthdate,birthtime,preferredName,preferredAddress,dead,deathDate)),' +
13
+ 'encounterAssigningToCurrentInpatientLocation:(encounterDatetime),' +
14
+ 'currentInpatientRequest:(dispositionLocation,dispositionType,disposition:(uuid,display),dispositionEncounter:(uuid,display),dispositionObsGroup:(uuid,display),visit:(uuid),patient:(uuid)),' +
15
+ 'firstAdmissionOrTransferEncounter:(encounterDatetime),' +
16
16
  ')';
17
- const { data, ...rest } = useSWR<FetchResponse<InpatientAdmissionFetchResponse>, Error>(
17
+
18
+ return useOpenmrsFetchAll<InpatientAdmission>(
18
19
  location
19
20
  ? `${restBaseUrl}/emrapi/inpatient/admission?currentInpatientLocation=${location.uuid}&v=${customRepresentation}`
20
21
  : null,
21
- openmrsFetch,
22
22
  );
23
-
24
- return {
25
- inpatientAdmissions: data?.data?.results,
26
- ...rest,
27
- };
28
23
  }
@@ -1,8 +1,6 @@
1
- import { type FetchResponse, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
- import type { DispositionType, InpatientRequestFetchResponse } from '../types';
3
- import useSWR from 'swr';
1
+ import { restBaseUrl, useOpenmrsFetchAll } from '@openmrs/esm-framework';
2
+ import type { DispositionType, InpatientRequest } from '../types';
4
3
  import useWardLocation from './useWardLocation';
5
- import { useMemo } from 'react';
6
4
 
7
5
  // prettier-ignore
8
6
  const defaultRep =
@@ -26,18 +24,9 @@ export function useInpatientRequest(
26
24
  searchParams.set('dispositionLocation', location?.uuid);
27
25
  searchParams.set('v', rep);
28
26
 
29
- const { data, ...rest } = useSWR<FetchResponse<InpatientRequestFetchResponse>, Error>(
27
+ const { data, ...rest } = useOpenmrsFetchAll<InpatientRequest>(
30
28
  location?.uuid ? `${restBaseUrl}/emrapi/inpatient/request?${searchParams.toString()}` : null,
31
- openmrsFetch,
32
29
  );
33
30
 
34
- const results = useMemo(
35
- () => ({
36
- inpatientRequests: data?.data?.results,
37
- ...rest,
38
- }),
39
- [data, rest],
40
- );
41
-
42
- return results;
31
+ return { inpatientRequests: data, ...rest };
43
32
  }
@@ -1,54 +1,11 @@
1
- import { type FetchResponse, fhirBaseUrl, openmrsFetch } from '@openmrs/esm-framework';
2
- import { useEffect, useMemo, useState } from 'react';
3
- import useSWRImmutable from 'swr/immutable';
1
+ import { fhirBaseUrl, useFhirPagination } from '@openmrs/esm-framework';
4
2
 
5
- interface FhirLocation {
6
- fullUrl: string;
7
- resource: {
8
- resourceType: 'Location';
9
- id: string;
10
- name: string;
11
- description: string;
12
- };
13
- }
14
-
15
- interface FhirResponse {
16
- resourceType: 'Bundle';
17
- id: '6a107c31-d760-4df0-bb70-89ad742225ca';
18
- meta: {
19
- lastUpdated: '2024-08-08T06:28:01.495+00:00';
20
- };
21
- type: 'searchset';
22
- total: number;
23
- link: Array<{
24
- relation: 'self' | 'prev' | 'next';
25
- url: string;
26
- }>;
27
- entry: Array<FhirLocation>;
28
- }
29
-
30
- export default function useLocations(filterCriteria: Array<Array<string>> = [], skip: boolean = false) {
31
- const [totalLocations, setTotalLocations] = useState(0);
32
- const [url, setUrl] = useState(`${fhirBaseUrl}/Location`);
3
+ export default function useLocations(
4
+ filterCriteria: Array<Array<string>> = [],
5
+ pageSize: number,
6
+ skip: boolean = false,
7
+ ) {
33
8
  const searchParams = new URLSearchParams(filterCriteria);
34
- const urlWithSearchParams = `${url}?${searchParams.toString()}`;
35
- const { data, ...rest } = useSWRImmutable<FetchResponse<FhirResponse>>(
36
- !skip ? urlWithSearchParams : null,
37
- openmrsFetch,
38
- );
39
-
40
- useEffect(() => {
41
- if (data?.data) {
42
- setTotalLocations(data.data.total);
43
- }
44
- }, [data]);
45
-
46
- const results = useMemo(() => {
47
- return {
48
- locations: data?.data?.entry?.map((entry) => entry.resource),
49
- totalLocations,
50
- ...rest,
51
- };
52
- }, [data, rest, totalLocations]);
53
- return results;
9
+ const urlWithSearchParams = `${fhirBaseUrl}/Location?${searchParams.toString()}`;
10
+ return useFhirPagination<fhir.Location>(skip ? null : urlWithSearchParams, pageSize, { immutable: true });
54
11
  }
@@ -0,0 +1,46 @@
1
+ import { makeUrl, restBaseUrl, useOpenmrsFetchAll } from '@openmrs/esm-framework';
2
+ import { type MotherAndChildren } from '../types';
3
+
4
+ export interface MothersAndChildrenSearchCriteria {
5
+ mothers?: Array<string>;
6
+ children?: Array<string>;
7
+ requireMotherHasActiveVisit?: boolean;
8
+ requireChildHasActiveVisit?: boolean;
9
+ requireChildBornDuringMothersActiveVisit?: boolean;
10
+ }
11
+
12
+ export function useMotherAndChildren(
13
+ criteria: MothersAndChildrenSearchCriteria,
14
+ fetch: boolean = true,
15
+ rep: string = null,
16
+ ) {
17
+ const url = makeUrlUrl(`${restBaseUrl}/emrapi/maternal/mothersAndChildren`);
18
+ const {
19
+ mothers,
20
+ children,
21
+ requireChildBornDuringMothersActiveVisit,
22
+ requireChildHasActiveVisit,
23
+ requireMotherHasActiveVisit,
24
+ } = criteria;
25
+
26
+ for (const m of mothers ?? []) {
27
+ url.searchParams.append('mother', m);
28
+ }
29
+
30
+ for (const c of children ?? []) {
31
+ url.searchParams.append('child', c);
32
+ }
33
+
34
+ url.searchParams.append('requireMotherHasActiveVisit', requireMotherHasActiveVisit?.toString() ?? 'false');
35
+ url.searchParams.append('requireChildHasActiveVisit', requireChildHasActiveVisit?.toString() ?? 'false');
36
+ url.searchParams.append(
37
+ 'requireChildBornDuringMothersActiveVisit',
38
+ requireChildBornDuringMothersActiveVisit?.toString() ?? 'false',
39
+ );
40
+ rep && url.searchParams.append('v', rep);
41
+ return useOpenmrsFetchAll<MotherAndChildren>(fetch ? url : null);
42
+ }
43
+
44
+ function makeUrlUrl(path: string) {
45
+ return new URL(makeUrl(path), window.location.toString());
46
+ }
@@ -1,6 +1,5 @@
1
- import useSWR from 'swr';
1
+ import { restBaseUrl, useOpenmrsFetchAll } from '@openmrs/esm-framework';
2
2
  import { type Observation } from '../types';
3
- import { type Link, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
4
3
 
5
4
  interface ObsSearchCriteria {
6
5
  patient: string;
@@ -14,8 +13,5 @@ export function useObs(criteria?: ObsSearchCriteria, representation = 'default')
14
13
  });
15
14
 
16
15
  const apiUrl = `${restBaseUrl}/obs?${params}`;
17
- return useSWR<{ data: { results: Array<Observation>; totalCount: number; links: Array<Link> } }, Error>(
18
- apiUrl,
19
- openmrsFetch,
20
- );
16
+ return useOpenmrsFetchAll<Observation>(apiUrl);
21
17
  }
@@ -0,0 +1,16 @@
1
+ import { type FetchResponse, openmrsFetch, type OpenmrsResource, restBaseUrl } from '@openmrs/esm-framework';
2
+ import useSWR from 'swr';
3
+
4
+ export function usePatientPendingOrders(patientUuid: string, orderTypeUUid: string, visitStartDate: string) {
5
+ const apiUrl =
6
+ patientUuid && orderTypeUUid && visitStartDate
7
+ ? `${restBaseUrl}/order?includeNullFulfillerStatus=true&patient=${patientUuid}&orderTypes=${orderTypeUUid}&activatedOnOrAfterDate=${visitStartDate}`
8
+ : null;
9
+ const { data, ...rest } = useSWR<FetchResponse<{ results: Array<OpenmrsResource> }>, Error>(apiUrl, openmrsFetch);
10
+
11
+ return {
12
+ orders: data?.data.results,
13
+ count: data?.data.results.length,
14
+ ...rest,
15
+ };
16
+ }
@@ -0,0 +1,25 @@
1
+ import { useMemo } from 'react';
2
+ import { createAndGetWardPatientGrouping } from '../ward-view/ward-view.resource';
3
+ import { useAdmissionLocation } from './useAdmissionLocation';
4
+ import { useInpatientAdmission } from './useInpatientAdmission';
5
+ import { useInpatientRequest } from './useInpatientRequest';
6
+
7
+ export function useWardPatientGrouping() {
8
+ const admissionLocationResponse = useAdmissionLocation();
9
+ const inpatientAdmissionResponse = useInpatientAdmission();
10
+ const inpatientRequestResponse = useInpatientRequest();
11
+
12
+ const { data: inpatientAdmissions } = inpatientAdmissionResponse;
13
+ const { admissionLocation } = admissionLocationResponse;
14
+ const { inpatientRequests } = inpatientRequestResponse;
15
+
16
+ const groupings = useMemo(() => {
17
+ return { ...createAndGetWardPatientGrouping(inpatientAdmissions, admissionLocation, inpatientRequests) };
18
+ }, [admissionLocation, inpatientAdmissions, inpatientRequests]) as ReturnType<typeof createAndGetWardPatientGrouping>;
19
+ return {
20
+ ...groupings,
21
+ admissionLocationResponse,
22
+ inpatientAdmissionResponse,
23
+ inpatientRequestResponse,
24
+ };
25
+ }