@kenyaemr/esm-ward-app 8.1.1-pre.123 → 8.1.1-pre.124

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 (54) hide show
  1. package/.turbo/turbo-build.log +8 -8
  2. package/dist/124.js +1 -1
  3. package/dist/124.js.map +1 -1
  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 -1
  9. package/dist/153.js.map +1 -1
  10. package/dist/303.js +2 -0
  11. package/dist/303.js.map +1 -0
  12. package/dist/471.js +1 -1
  13. package/dist/471.js.map +1 -1
  14. package/dist/53.js +1 -1
  15. package/dist/53.js.map +1 -1
  16. package/dist/574.js +1 -1
  17. package/dist/577.js +1 -1
  18. package/dist/577.js.map +1 -1
  19. package/dist/662.js +1 -1
  20. package/dist/662.js.map +1 -1
  21. package/dist/921.js +1 -1
  22. package/dist/921.js.map +1 -1
  23. package/dist/922.js +1 -1
  24. package/dist/922.js.map +1 -1
  25. package/dist/kenyaemr-esm-ward-app.js +1 -1
  26. package/dist/kenyaemr-esm-ward-app.js.buildmanifest.json +60 -60
  27. package/dist/kenyaemr-esm-ward-app.js.map +1 -1
  28. package/dist/main.js +1 -1
  29. package/dist/main.js.map +1 -1
  30. package/dist/routes.json +1 -1
  31. package/package.json +1 -1
  32. package/src/beds/ward-bed.test.tsx +16 -5
  33. package/src/hooks/useWardPatientGrouping.ts +5 -0
  34. package/src/ward-view/materal-ward/maternal-ward-patient-card.test.tsx +11 -0
  35. package/src/ward-view/ward-view.scss +1 -1
  36. package/src/ward-view/ward-view.test.tsx +8 -0
  37. package/src/ward-view-header/ward-metric.scss +5 -5
  38. package/src/ward-view-header/ward-metrics.scss +1 -2
  39. package/src/ward-workspace/admission-request-card/admission-request-card-actions.component.tsx +59 -6
  40. package/src/ward-workspace/admission-request-workspace/admission-requests-workspace.test.tsx +45 -1
  41. package/src/ward-workspace/admission-request-workspace/admission-requests.workspace.tsx +26 -5
  42. package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.test.tsx +30 -94
  43. package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.workspace.tsx +101 -189
  44. package/src/ward-workspace/bed-selector.component.tsx +119 -0
  45. package/src/ward-workspace/bed-selector.scss +15 -0
  46. package/src/ward-workspace/patient-discharge/patient-discharge.workspace.tsx +4 -11
  47. package/src/ward-workspace/patient-transfer-bed-swap/patient-bed-swap-form.component.tsx +56 -77
  48. package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-request-form.component.tsx +3 -10
  49. package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-swap.workspace.tsx +10 -6
  50. package/src/ward.resource.ts +32 -2
  51. package/translations/en.json +6 -5
  52. package/dist/67.js +0 -2
  53. package/dist/67.js.map +0 -1
  54. /package/dist/{67.js.LICENSE.txt → 303.js.LICENSE.txt} +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":"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.123"}
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.124"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kenyaemr/esm-ward-app",
3
- "version": "8.1.1-pre.123",
3
+ "version": "8.1.1-pre.124",
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,26 +1,37 @@
1
- import React from 'react';
2
- import { render, screen } from '@testing-library/react';
3
1
  import { getDefaultsFromConfigSchema, useConfig } from '@openmrs/esm-framework';
4
- import { configSchema, type WardConfigObject } from '../config-schema';
2
+ import { render, screen } from '@testing-library/react';
3
+ import React from 'react';
5
4
  import {
6
5
  mockAdmissionLocation,
7
6
  mockLocationInpatientWard,
8
7
  mockPatientAlice,
9
8
  mockPatientBrian,
10
9
  } from '../../../../__mocks__';
11
- import { bedLayoutToBed, filterBeds } from '../ward-view/ward-view.resource';
10
+ import { configSchema, type WardConfigObject } from '../config-schema';
11
+ import { useObs } from '../hooks/useObs';
12
12
  import useWardLocation from '../hooks/useWardLocation';
13
- import WardBed from './ward-bed.component';
14
13
  import { type WardPatient } from '../types';
15
14
  import DefaultWardPatientCard from '../ward-view/default-ward/default-ward-patient-card.component';
15
+ import { bedLayoutToBed, filterBeds } from '../ward-view/ward-view.resource';
16
+ import WardBed from './ward-bed.component';
16
17
 
17
18
  const defaultConfig: WardConfigObject = getDefaultsFromConfigSchema(configSchema);
18
19
 
19
20
  jest.mocked(useConfig).mockReturnValue(defaultConfig);
21
+ jest.mock('../hooks/useObs', () => ({
22
+ useObs: jest.fn(),
23
+ }));
24
+ jest.mock('../ward-patient-card/row-elements/ward-patient-obs.resource', () => ({
25
+ useConceptToTagColorMap: jest.fn(),
26
+ }));
20
27
 
21
28
  const mockBedLayouts = filterBeds(mockAdmissionLocation);
22
29
 
23
30
  jest.mock('../hooks/useWardLocation', () => jest.fn());
31
+ //@ts-ignore
32
+ jest.mocked(useObs).mockReturnValue({
33
+ data: [],
34
+ });
24
35
 
25
36
  const mockedUseWardLocation = useWardLocation as jest.Mock;
26
37
  mockedUseWardLocation.mockReturnValue({
@@ -23,5 +23,10 @@ export function useWardPatientGrouping() {
23
23
  inpatientRequestResponse,
24
24
  isLoading:
25
25
  admissionLocationResponse.isLoading || inpatientAdmissionResponse.isLoading || inpatientRequestResponse.isLoading,
26
+ mutate() {
27
+ admissionLocationResponse?.mutate();
28
+ inpatientAdmissionResponse?.mutate();
29
+ inpatientRequestResponse?.mutate();
30
+ },
26
31
  };
27
32
  }
@@ -7,14 +7,25 @@ import { mockInpatientAdmissionAlice } from '../../../../../__mocks__/inpatient-
7
7
  import { mockWardBeds } from '../../../../../__mocks__/wardBeds.mock';
8
8
  import { mockWardViewContext } from '../../../mock';
9
9
  import { configSchema, type WardConfigObject } from '../../config-schema';
10
+ import { useObs } from '../../hooks/useObs';
10
11
  import { type WardPatient, type WardViewContext } from '../../types';
11
12
  import MaternalWardPatientCard from './maternal-ward-patient-card.component';
12
13
 
13
14
  jest.mocked(useAppContext<WardViewContext>).mockReturnValue(mockWardViewContext);
15
+ jest.mock('../../hooks/useObs', () => ({
16
+ useObs: jest.fn(),
17
+ }));
18
+ jest.mock('../../ward-patient-card/row-elements/ward-patient-obs.resource', () => ({
19
+ useConceptToTagColorMap: jest.fn(),
20
+ }));
14
21
 
15
22
  const defaultConfig: WardConfigObject = getDefaultsFromConfigSchema(configSchema);
16
23
 
17
24
  jest.mocked(useConfig).mockReturnValue(defaultConfig);
25
+ //@ts-ignore
26
+ jest.mocked(useObs).mockReturnValue({
27
+ data: [],
28
+ });
18
29
 
19
30
  describe('MaternalWardPatientCard', () => {
20
31
  it('renders a patient with no child', () => {
@@ -1,5 +1,5 @@
1
1
  @use '@carbon/layout';
2
- @import '~@openmrs/esm-styleguide/src/vars';
2
+ @use '@openmrs/esm-styleguide/src/vars' as *;
3
3
 
4
4
  .wardView {
5
5
  background-color: #e4e4e4;
@@ -11,6 +11,7 @@ import { useParams } from 'react-router-dom';
11
11
  import { renderWithSwr } from 'tools';
12
12
  import { mockWardPatientGroupDetails, mockWardViewContext } from '../../mock';
13
13
  import { configSchema } from '../config-schema';
14
+ import { useObs } from '../hooks/useObs';
14
15
  import useWardLocation from '../hooks/useWardLocation';
15
16
  import { type WardViewContext } from '../types';
16
17
  import DefaultWardView from './default-ward/default-ward-view.component';
@@ -30,6 +31,9 @@ jest.mock('../hooks/useWardLocation', () =>
30
31
  invalidLocation: false,
31
32
  }),
32
33
  );
34
+ jest.mock('../hooks/useObs', () => ({
35
+ useObs: jest.fn(),
36
+ }));
33
37
 
34
38
  const mockUseWardLocation = jest.mocked(useWardLocation);
35
39
 
@@ -40,6 +44,10 @@ jest.mock('react-router-dom', () => ({
40
44
  const mockUseParams = useParams as jest.Mock;
41
45
 
42
46
  jest.mocked(useAppContext<WardViewContext>).mockReturnValue(mockWardViewContext);
47
+ //@ts-ignore
48
+ jest.mocked(useObs).mockReturnValue({
49
+ data: [],
50
+ });
43
51
 
44
52
  const intersectionObserverMock = () => ({
45
53
  observe: () => null,
@@ -1,9 +1,9 @@
1
- @use '@carbon/styles/scss/spacing';
1
+ @use '@carbon/layout';
2
2
  @use '@carbon/type';
3
- @import '~@openmrs/esm-styleguide/src/vars';
3
+ @use '@openmrs/esm-styleguide/src/vars' as *;
4
4
 
5
5
  .metric {
6
- margin-left: spacing.$spacing-05;
6
+ margin-left: layout.$spacing-05;
7
7
  display: flex;
8
8
  align-items: end;
9
9
  gap: 5px;
@@ -20,6 +20,6 @@
20
20
  }
21
21
 
22
22
  .skeleton {
23
- height: 15px;
24
- width: 15px;
23
+ height: layout.$spacing-05;
24
+ width: layout.$spacing-05;
25
25
  }
@@ -1,5 +1,4 @@
1
- @use '@carbon/styles/scss/spacing';
2
- @import '~@openmrs/esm-styleguide/src/vars';
1
+ @use '@openmrs/esm-styleguide/src/vars' as *;
3
2
 
4
3
  .metricsContainer {
5
4
  display: flex;
@@ -1,8 +1,18 @@
1
1
  import { Button } from '@carbon/react';
2
- import { ArrowRightIcon, launchWorkspace, useAppContext, useLayoutType } from '@openmrs/esm-framework';
3
- import React, { useCallback } from 'react';
2
+ import {
3
+ ArrowRightIcon,
4
+ launchWorkspace,
5
+ showSnackbar,
6
+ useAppContext,
7
+ useFeatureFlag,
8
+ useLayoutType,
9
+ } from '@openmrs/esm-framework';
10
+ import React, { useCallback, useContext } from 'react';
4
11
  import { useTranslation } from 'react-i18next';
5
- import type { WardPatientWorkspaceProps, WardPatientCardType, WardViewContext } from '../../types';
12
+ import useWardLocation from '../../hooks/useWardLocation';
13
+ import type { WardPatientCardType, WardPatientWorkspaceProps, WardViewContext } from '../../types';
14
+ import { useAdmitPatient } from '../../ward.resource';
15
+ import { AdmissionRequestsWorkspaceContext } from '../admission-request-workspace/admission-requests.workspace';
6
16
  import type { AdmitPatientFormWorkspaceProps } from '../admit-patient-form-workspace/types';
7
17
  import styles from './admission-request-card.scss';
8
18
 
@@ -10,8 +20,10 @@ const AdmissionRequestCardActions: WardPatientCardType = (wardPatient) => {
10
20
  const { patient, inpatientRequest } = wardPatient;
11
21
  const { dispositionType } = inpatientRequest;
12
22
  const { t } = useTranslation();
23
+ const { location } = useWardLocation();
13
24
  const responsiveSize = useLayoutType() === 'tablet' ? 'lg' : 'md';
14
- const {WardPatientHeader} = useAppContext<WardViewContext>('ward-view-context') ?? {};
25
+ const { WardPatientHeader, wardPatientGroupDetails } = useAppContext<WardViewContext>('ward-view-context') ?? {};
26
+ const { admitPatient, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } = useAdmitPatient();
15
27
 
16
28
  const launchPatientAdmissionForm = useCallback(
17
29
  () => launchWorkspace<AdmitPatientFormWorkspaceProps>('admit-patient-form-workspace', { patient, dispositionType }),
@@ -21,16 +33,57 @@ const AdmissionRequestCardActions: WardPatientCardType = (wardPatient) => {
21
33
  const launchPatientTransferForm = useCallback(() => {
22
34
  launchWorkspace<WardPatientWorkspaceProps>('patient-transfer-request-workspace', {
23
35
  wardPatient,
24
- WardPatientHeader
36
+ WardPatientHeader,
25
37
  });
26
38
  }, [wardPatient, WardPatientHeader]);
39
+ const isBedManagementModuleInstalled = useFeatureFlag('bedmanagement-module');
40
+ const { closeWorkspaceWithSavedChanges } = useContext(AdmissionRequestsWorkspaceContext);
41
+
42
+ // If bed management module is installed, open the next form
43
+ // for bed selection. If not, admit patient directly
44
+ const onAdmit = () => {
45
+ if (isBedManagementModuleInstalled) {
46
+ launchPatientAdmissionForm();
47
+ } else {
48
+ admitPatient(patient, dispositionType)
49
+ .then(
50
+ (response) => {
51
+ if (response && response?.ok) {
52
+ showSnackbar({
53
+ kind: 'success',
54
+ title: t('patientAdmittedSuccessfully', 'Patient admitted successfully'),
55
+ subtitle: t('patientAdmittedWoBed', 'Patient admitted successfully to {{location}}', {
56
+ location: location?.display,
57
+ }),
58
+ });
59
+ }
60
+ },
61
+ (err: Error) => {
62
+ showSnackbar({
63
+ kind: 'error',
64
+ title: t('errorCreatingEncounter', 'Failed to admit patient'),
65
+ subtitle: err.message,
66
+ });
67
+ },
68
+ )
69
+ .finally(() => {
70
+ wardPatientGroupDetails?.mutate?.();
71
+ closeWorkspaceWithSavedChanges();
72
+ });
73
+ }
74
+ };
27
75
 
28
76
  return (
29
77
  <div className={styles.admissionRequestActionBar}>
30
78
  <Button kind="ghost" size={responsiveSize} onClick={launchPatientTransferForm}>
31
79
  {t('transferElsewhere', 'Transfer elsewhere')}
32
80
  </Button>
33
- <Button kind="ghost" renderIcon={ArrowRightIcon} size={responsiveSize} onClick={launchPatientAdmissionForm}>
81
+ <Button
82
+ kind="ghost"
83
+ renderIcon={ArrowRightIcon}
84
+ size={responsiveSize}
85
+ disabled={isLoadingEmrConfiguration || errorFetchingEmrConfiguration}
86
+ onClick={onAdmit}>
34
87
  {t('admitPatient', 'Admit patient')}
35
88
  </Button>
36
89
  </div>
@@ -3,12 +3,16 @@ import { screen } from '@testing-library/react';
3
3
  import React from 'react';
4
4
  import { renderWithSwr } from '../../../../../tools';
5
5
  import { mockWardViewContext } from '../../../mock';
6
+ import useEmrConfiguration from '../../hooks/useEmrConfiguration';
6
7
  import { type WardViewContext } from '../../types';
7
8
  import DefaultWardPendingPatients from '../../ward-view/default-ward/default-ward-pending-patients.component';
8
9
  import AdmissionRequestsWorkspace, { type AdmissionRequestsWorkspaceProps } from './admission-requests.workspace';
9
10
 
10
11
  jest.mocked(useAppContext<WardViewContext>).mockReturnValue(mockWardViewContext);
11
12
 
13
+ jest.mock('../../hooks/useEmrConfiguration', () => jest.fn());
14
+ const mockedUseEmrConfiguration = jest.mocked(useEmrConfiguration);
15
+
12
16
  const workspaceProps: AdmissionRequestsWorkspaceProps = {
13
17
  closeWorkspace: jest.fn(),
14
18
  promptBeforeClosing: jest.fn(),
@@ -18,9 +22,49 @@ const workspaceProps: AdmissionRequestsWorkspaceProps = {
18
22
  };
19
23
 
20
24
  describe('Admission Requests Workspace', () => {
21
- it('should render a admission request card', () => {
25
+ beforeEach(() => {
26
+ mockedUseEmrConfiguration.mockReturnValue({
27
+ isLoadingEmrConfiguration: false,
28
+ errorFetchingEmrConfiguration: null,
29
+ // @ts-ignore - we only need these keys for now
30
+ emrConfiguration: {
31
+ admissionEncounterType: {
32
+ uuid: 'admission-encounter-type-uuid',
33
+ display: 'Admission Encounter',
34
+ },
35
+ transferWithinHospitalEncounterType: {
36
+ uuid: 'transfer-within-hospital-encounter-type-uuid',
37
+ display: 'Transfer Within Hospital Encounter Type',
38
+ },
39
+ clinicianEncounterRole: {
40
+ uuid: 'clinician-encounter-role-uuid',
41
+ },
42
+ },
43
+ mutateEmrConfiguration: jest.fn(),
44
+ });
45
+ });
46
+
47
+ it('should render an admission request card', () => {
22
48
  renderWithSwr(<AdmissionRequestsWorkspace {...workspaceProps} />);
23
49
  const alice = mockWardViewContext.wardPatientGroupDetails.inpatientRequestResponse.inpatientRequests[0].patient;
24
50
  expect(screen.getByText(alice.person?.preferredName?.display as string)).toBeInTheDocument();
25
51
  });
52
+
53
+ it('should render an admission request card with disabled "admit patient" button when emr config fails to load', () => {
54
+ mockedUseEmrConfiguration.mockReturnValue({
55
+ isLoadingEmrConfiguration: false,
56
+ errorFetchingEmrConfiguration: true,
57
+ emrConfiguration: null,
58
+ mutateEmrConfiguration: jest.fn(),
59
+ });
60
+
61
+ renderWithSwr(<AdmissionRequestsWorkspace {...workspaceProps} />);
62
+ expect(screen.getByText("Some parts of the form didn't load")).toBeInTheDocument();
63
+ expect(
64
+ screen.getByText(
65
+ 'Fetching EMR configuration failed. Try refreshing the page or contact your system administrator.',
66
+ ),
67
+ ).toBeInTheDocument();
68
+ expect(screen.getByRole('button', { name: /Admit patient/i })).toBeDisabled();
69
+ });
26
70
  });
@@ -1,18 +1,24 @@
1
- import { Search } from '@carbon/react';
1
+ import { InlineNotification, Search } from '@carbon/react';
2
2
  import { type DefaultWorkspaceProps } from '@openmrs/esm-framework';
3
- import React, { type ReactNode } from 'react';
3
+ import React, { createContext, type ReactNode } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
+ import useEmrConfiguration from '../../hooks/useEmrConfiguration';
5
6
  import styles from './admission-requests-workspace.scss';
6
7
 
7
8
  export interface AdmissionRequestsWorkspaceProps extends DefaultWorkspaceProps {
8
9
  wardPendingPatients: ReactNode;
9
10
  }
10
- const AdmissionRequestsWorkspace: React.FC<AdmissionRequestsWorkspaceProps> = ({ wardPendingPatients }) => {
11
+
12
+ export const AdmissionRequestsWorkspaceContext = createContext<AdmissionRequestsWorkspaceProps>(null);
13
+
14
+ const AdmissionRequestsWorkspace: React.FC<AdmissionRequestsWorkspaceProps> = (props) => {
15
+ const { wardPendingPatients } = props;
11
16
  const { t } = useTranslation();
12
17
  const [searchTerm, setSearchTerm] = React.useState('');
13
18
  const handleSearch = (event: React.ChangeEvent<HTMLInputElement>) => {
14
19
  setSearchTerm(event.target.value);
15
20
  };
21
+ const { errorFetchingEmrConfiguration } = useEmrConfiguration();
16
22
 
17
23
  return (
18
24
  <div className={styles.admissionRequestsWorkspaceContainer}>
@@ -24,8 +30,23 @@ const AdmissionRequestsWorkspace: React.FC<AdmissionRequestsWorkspaceProps> = ({
24
30
  placeholder={t('searchForPatient', 'Search for a patient')}
25
31
  disabled
26
32
  />
27
-
28
- <div className={styles.content}>{wardPendingPatients}</div>
33
+ {errorFetchingEmrConfiguration && (
34
+ <div className={styles.formError}>
35
+ <InlineNotification
36
+ kind="error"
37
+ title={t('somePartsOfTheFormDidntLoad', "Some parts of the form didn't load")}
38
+ subtitle={t(
39
+ 'fetchingEmrConfigurationFailed',
40
+ 'Fetching EMR configuration failed. Try refreshing the page or contact your system administrator.',
41
+ )}
42
+ lowContrast
43
+ hideCloseButton
44
+ />
45
+ </div>
46
+ )}
47
+ <AdmissionRequestsWorkspaceContext.Provider value={props}>
48
+ <div className={styles.content}>{wardPendingPatients}</div>
49
+ </AdmissionRequestsWorkspaceContext.Provider>
29
50
  </div>
30
51
  );
31
52
  };
@@ -2,14 +2,13 @@ import { showSnackbar, useAppContext, useFeatureFlag, useSession } from '@openmr
2
2
  import { screen } from '@testing-library/react';
3
3
  import userEvent from '@testing-library/user-event';
4
4
  import React from 'react';
5
- import { mockAdmissionLocation, mockLocationInpatientWard, mockPatientAlice } from '../../../../../__mocks__';
5
+ import { mockLocationInpatientWard, mockPatientAlice } from '../../../../../__mocks__';
6
6
  import { renderWithSwr } from '../../../../../tools';
7
7
  import { mockWardPatientGroupDetails, mockWardViewContext } from '../../../mock';
8
8
  import { useAssignedBedByPatient } from '../../hooks/useAssignedBedByPatient';
9
- import useEmrConfiguration from '../../hooks/useEmrConfiguration';
10
9
  import useWardLocation from '../../hooks/useWardLocation';
11
10
  import type { DispositionType, WardViewContext } from '../../types';
12
- import { assignPatientToBed, createEncounter, removePatientFromBed } from '../../ward.resource';
11
+ import { assignPatientToBed, removePatientFromBed, useAdmitPatient } from '../../ward.resource';
13
12
  import AdmitPatientFormWorkspace from './admit-patient-form.workspace';
14
13
  import type { AdmitPatientFormWorkspaceProps } from './types';
15
14
 
@@ -19,8 +18,6 @@ jest.mock('../../hooks/useAdmissionLocation', () => ({
19
18
 
20
19
  jest.mock('../../hooks/useWardLocation', () => jest.fn());
21
20
 
22
- jest.mock('../../hooks/useEmrConfiguration', () => jest.fn());
23
-
24
21
  jest.mock('../../hooks/useInpatientRequest', () => ({
25
22
  useInpatientRequest: jest.fn(),
26
23
  }));
@@ -39,22 +36,30 @@ jest.mock('../../hooks/useAssignedBedByPatient', () => ({
39
36
 
40
37
  jest.mock('../../ward.resource', () => ({
41
38
  createEncounter: jest.fn(),
39
+ useAdmitPatient: jest.fn(),
42
40
  assignPatientToBed: jest.fn(),
43
41
  removePatientFromBed: jest.fn(),
44
42
  }));
45
43
 
46
- const mockedUseEmrConfiguration = jest.mocked(useEmrConfiguration);
47
44
  const mockedUseWardLocation = jest.mocked(useWardLocation);
48
45
  const mockedUseFeatureFlag = jest.mocked(useFeatureFlag);
49
46
  const mockedShowSnackbar = jest.mocked(showSnackbar);
50
47
  const mockedUseSession = jest.mocked(useSession);
51
48
  const mockedUseAssignedBedByPatient = jest.mocked(useAssignedBedByPatient);
52
49
  const mockedAssignPatientToBed = jest.mocked(assignPatientToBed);
53
- const mockedCreateEncounter = jest.mocked(createEncounter);
54
50
  const mockedRemovePatientFromBed = jest.mocked(removePatientFromBed);
51
+ const mockedUseAdmitPatient = jest.mocked(useAdmitPatient);
55
52
 
56
53
  jest.mocked(useAppContext<WardViewContext>).mockReturnValue(mockWardViewContext);
57
54
 
55
+ const mockUseAdmitPatientObj: ReturnType<typeof useAdmitPatient> = {
56
+ admitPatient: jest.fn(),
57
+ isLoadingEmrConfiguration: false,
58
+ errorFetchingEmrConfiguration: false,
59
+ };
60
+ jest.mocked(useAdmitPatient).mockReturnValue(mockUseAdmitPatientObj);
61
+ const mockedAdmitPatient = mockUseAdmitPatientObj.admitPatient;
62
+
58
63
  const mockWorkspaceProps: AdmitPatientFormWorkspaceProps = {
59
64
  patient: mockPatientAlice,
60
65
  closeWorkspace: jest.fn(),
@@ -81,31 +86,15 @@ describe('Testing AdmitPatientForm', () => {
81
86
  sessionId: 'session-id',
82
87
  });
83
88
  mockedUseFeatureFlag.mockReturnValue(true);
84
- mockedUseEmrConfiguration.mockReturnValue({
85
- isLoadingEmrConfiguration: false,
86
- errorFetchingEmrConfiguration: null,
87
- // @ts-ignore - we only need these two keys for now
88
- emrConfiguration: {
89
- admissionEncounterType: {
90
- uuid: 'admission-encounter-type-uuid',
91
- display: 'Admission Encounter',
92
- },
93
- transferWithinHospitalEncounterType: {
94
- uuid: 'transfer-within-hospital-encounter-type-uuid',
95
- display: 'Transfer Within Hospital Encounter Type',
96
- },
97
- clinicianEncounterRole: {
98
- uuid: 'clinician-encounter-role-uuid',
99
- },
100
- },
101
- mutateEmrConfiguration: jest.fn(),
102
- });
89
+
103
90
  mockedUseWardLocation.mockReturnValue({
104
91
  location: mockLocationInpatientWard,
105
92
  invalidLocation: false,
106
93
  isLoadingLocation: false,
107
94
  errorFetchingLocation: null,
108
95
  });
96
+
97
+ // @ts-ignore - we don't need to mock the entire object
109
98
  mockedUseAssignedBedByPatient.mockReturnValue({
110
99
  data: {
111
100
  data: {
@@ -120,10 +109,10 @@ describe('Testing AdmitPatientForm', () => {
120
109
  ],
121
110
  },
122
111
  },
123
- } as ReturnType<typeof useAssignedBedByPatient>);
112
+ });
124
113
 
125
114
  // @ts-ignore - we only need these two keys for now
126
- mockedCreateEncounter.mockResolvedValue({
115
+ mockedAdmitPatient.mockResolvedValue({
127
116
  ok: true,
128
117
  data: {
129
118
  uuid: 'encounter-uuid',
@@ -151,43 +140,24 @@ describe('Testing AdmitPatientForm', () => {
151
140
  });
152
141
  screen.getByText('Admit');
153
142
  expect(screen.getByText('Select a bed')).toBeInTheDocument();
154
- await user.click(
155
- screen.getByRole('combobox', {
156
- name: 'Choose an option',
157
- }),
158
- );
159
- expect(screen.getByText('bed1 · Alice Johnson')).toBeInTheDocument();
160
- expect(screen.getByText('bed2 · Empty')).toBeInTheDocument();
161
- expect(screen.getByText('bed3 · Empty')).toBeInTheDocument();
162
- expect(screen.getByText('bed4 · Empty')).toBeInTheDocument();
143
+
144
+ expect(screen.getByRole('radio', { name: 'bed1 · Alice Johnson' })).toBeInTheDocument();
145
+ expect(screen.getByRole('radio', { name: 'bed2 · Empty' })).toBeInTheDocument();
146
+ expect(screen.getByRole('radio', { name: 'bed3 · Empty' })).toBeInTheDocument();
147
+ expect(screen.getByRole('radio', { name: 'bed4 · Empty' })).toBeInTheDocument();
163
148
  });
164
149
 
165
150
  it('should block the form if emr configuration is not fetched properly', () => {
166
- mockedUseEmrConfiguration.mockReturnValue({
151
+ mockedUseAdmitPatient.mockReturnValueOnce({
152
+ admitPatient: mockedAdmitPatient,
167
153
  isLoadingEmrConfiguration: false,
168
154
  errorFetchingEmrConfiguration: true,
169
- emrConfiguration: null,
170
- mutateEmrConfiguration: jest.fn(),
171
155
  });
172
156
 
173
157
  renderAdmissionForm();
174
158
 
175
159
  const admitButton = screen.getByText('Admit');
176
160
  expect(admitButton).toBeDisabled();
177
- expect(screen.getByText("Some parts of the form didn't load")).toBeInTheDocument();
178
- expect(
179
- screen.getByText(
180
- 'Fetching EMR configuration failed. Try refreshing the page or contact your system administrator.',
181
- ),
182
- ).toBeInTheDocument();
183
- });
184
-
185
- it('should render admit patient form if bed management module is not present', () => {
186
- mockedUseFeatureFlag.mockReturnValue(false);
187
- renderAdmissionForm();
188
- expect(screen.getByText('Select a bed')).toBeInTheDocument();
189
- expect(screen.getByText('Unable to select beds')).toBeInTheDocument();
190
- expect(screen.getByText('Bed management module is not present to allow bed selection')).toBeInTheDocument();
191
161
  });
192
162
 
193
163
  it('should render admit patient form if bed management module is present, but no beds are configured', () => {
@@ -202,27 +172,12 @@ describe('Testing AdmitPatientForm', () => {
202
172
  it('should submit the form, create encounter and submit bed', async () => {
203
173
  const user = userEvent.setup();
204
174
  renderAdmissionForm();
205
- const combobox = screen.getByRole('combobox', {
206
- name: 'Choose an option',
207
- });
208
- await user.click(combobox);
209
- const bedOption = screen.getByText('bed3 · Empty');
175
+ const bedOption = screen.getByRole('radio', { name: 'bed3 · Empty' });
210
176
  await user.click(bedOption);
211
177
  const admitButton = screen.getByRole('button', { name: 'Admit' });
212
178
  expect(admitButton).toBeEnabled();
213
179
  await user.click(admitButton);
214
- expect(mockedCreateEncounter).toHaveBeenCalledWith({
215
- patient: mockPatientAlice.uuid,
216
- encounterType: 'admission-encounter-type-uuid',
217
- location: mockAdmissionLocation.ward.uuid,
218
- obs: [],
219
- encounterProviders: [
220
- {
221
- provider: 'current-provider-uuid',
222
- encounterRole: 'clinician-encounter-role-uuid',
223
- },
224
- ],
225
- });
180
+ expect(mockedAdmitPatient).toHaveBeenCalledWith(mockPatientAlice, 'ADMIT');
226
181
  expect(mockedAssignPatientToBed).toHaveBeenCalledWith(3, mockPatientAlice.uuid, 'encounter-uuid');
227
182
  expect(mockedShowSnackbar).toHaveBeenCalledWith({
228
183
  kind: 'success',
@@ -232,14 +187,10 @@ describe('Testing AdmitPatientForm', () => {
232
187
  });
233
188
 
234
189
  it('should show snackbar if there was an issue creating an encounter', async () => {
235
- mockedCreateEncounter.mockRejectedValue(new Error('Failed to create encounter'));
190
+ mockedAdmitPatient.mockRejectedValue(new Error('Failed to create encounter'));
236
191
  const user = userEvent.setup();
237
192
  renderAdmissionForm();
238
- const combobox = screen.getByRole('combobox', {
239
- name: 'Choose an option',
240
- });
241
- await user.click(combobox);
242
- const bedOption = screen.getByText('bed3 · Empty');
193
+ const bedOption = screen.getByRole('radio', { name: 'bed3 · Empty' });
243
194
  await user.click(bedOption);
244
195
  const admitButton = screen.getByRole('button', { name: 'Admit' });
245
196
  expect(admitButton).toBeEnabled();
@@ -256,11 +207,7 @@ describe('Testing AdmitPatientForm', () => {
256
207
 
257
208
  const user = userEvent.setup();
258
209
  renderAdmissionForm();
259
- const combobox = screen.getByRole('combobox', {
260
- name: 'Choose an option',
261
- });
262
- await user.click(combobox);
263
- const bedOption = screen.getByText('bed3 · Empty');
210
+ const bedOption = screen.getByRole('radio', { name: 'bed3 · Empty' });
264
211
  await user.click(bedOption);
265
212
  const admitButton = screen.getByRole('button', { name: 'Admit' });
266
213
  expect(admitButton).toBeEnabled();
@@ -278,18 +225,7 @@ describe('Testing AdmitPatientForm', () => {
278
225
  const admitButton = screen.getByRole('button', { name: 'Admit' });
279
226
  expect(admitButton).toBeEnabled();
280
227
  await user.click(admitButton);
281
- expect(mockedCreateEncounter).toHaveBeenCalledWith({
282
- patient: mockPatientAlice.uuid,
283
- encounterType: 'admission-encounter-type-uuid',
284
- location: mockAdmissionLocation.ward.uuid,
285
- obs: [],
286
- encounterProviders: [
287
- {
288
- provider: 'current-provider-uuid',
289
- encounterRole: 'clinician-encounter-role-uuid',
290
- },
291
- ],
292
- });
228
+ expect(mockedAdmitPatient).toHaveBeenCalledWith(mockPatientAlice, 'ADMIT');
293
229
  expect(mockedRemovePatientFromBed).toHaveBeenCalledWith(1, mockPatientAlice.uuid);
294
230
  expect(mockedShowSnackbar).toHaveBeenCalledWith({
295
231
  kind: 'success',