Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(fix) - O3-4017 - Ward App - ward view should refresh data after actions on patients #1327

Merged
merged 3 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,6 @@ results.xml
moduleName

.env

# vim
.swp
Binary file removed packages/esm-ward-app/.fetch.swp
Binary file not shown.
54 changes: 54 additions & 0 deletions packages/esm-ward-app/mock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { mockAdmissionLocation, mockInpatientAdmissions, mockInpatientRequest } from '__mocks__';
import { useAdmissionLocation } from './src/hooks/useAdmissionLocation';
import { useInpatientAdmission } from './src/hooks/useInpatientAdmission';
import { createAndGetWardPatientGrouping } from './src/ward-view/ward-view.resource';
import { useInpatientRequest } from './src/hooks/useInpatientRequest';
import { useWardPatientGrouping } from './src/hooks/useWardPatientGrouping';

jest.mock('./src/hooks/useAdmissionLocation', () => ({
useAdmissionLocation: jest.fn(),
}));
jest.mock('./src/hooks/useInpatientAdmission', () => ({
useInpatientAdmission: jest.fn(),
}));
jest.mock('./src/hooks/useInpatientRequest', () => ({
useInpatientRequest: jest.fn(),
}));
jest.mock('./src/hooks/useWardPatientGrouping', () => ({
useWardPatientGrouping: jest.fn(),
}));
const mockAdmissionLocationResponse = jest.mocked(useAdmissionLocation).mockReturnValue({
error: undefined,
mutate: jest.fn(),
isValidating: false,
isLoading: false,
admissionLocation: mockAdmissionLocation,
});
const mockInpatientAdmissionResponse = jest.mocked(useInpatientAdmission).mockReturnValue({
data: mockInpatientAdmissions,
hasMore: false,
loadMore: jest.fn(),
isValidating: false,
isLoading: false,
error: undefined,
mutate: jest.fn(),
totalCount: mockInpatientAdmissions.length,
});

const mockInpatientRequestResponse = jest.mocked(useInpatientRequest).mockReturnValue({
inpatientRequests: mockInpatientRequest,
hasMore: false,
loadMore: jest.fn(),
isValidating: false,
isLoading: false,
error: undefined,
mutate: jest.fn(),
totalCount: mockInpatientRequest.length,
});

export const mockWardPatientGroupDetails = jest.mocked(useWardPatientGrouping).mockReturnValue({
admissionLocationResponse: mockAdmissionLocationResponse(),
inpatientAdmissionResponse: mockInpatientAdmissionResponse(),
inpatientRequestResponse: mockInpatientRequestResponse(),
...createAndGetWardPatientGrouping(mockInpatientAdmissions, mockAdmissionLocation, mockInpatientRequest),
});
3 changes: 1 addition & 2 deletions packages/esm-ward-app/src/hooks/useBeds.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { openmrsFetch, restBaseUrl, useOpenmrsFetchAll } from '@openmrs/esm-framework';
import useSWR from 'swr';
import { restBaseUrl, useOpenmrsFetchAll } from '@openmrs/esm-framework';
import { type Bed, type BedStatus } from '../types/index';

interface BedSearchCriteria {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import React from 'react';
import { Movement } from '@carbon/react/icons';
import { Button, InlineNotification } from '@carbon/react';
import { ArrowRightIcon, isDesktop, launchWorkspace, useLayoutType } from '@openmrs/esm-framework';
import { useInpatientRequest } from '../hooks/useInpatientRequest';
import { Movement } from '@carbon/react/icons';
import { ArrowRightIcon, isDesktop, launchWorkspace, useAppContext, useLayoutType } from '@openmrs/esm-framework';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { type WardPatientGroupDetails } from '../types';
import styles from './admission-requests.scss';

const AdmissionRequestsBar = () => {
const { inpatientRequests, isLoading, error } = useInpatientRequest(['ADMIT', 'TRANSFER']);
const wardPatientGrouping = useAppContext<WardPatientGroupDetails>('ward-patients-group');
const { inpatientRequests, isLoading, error } = wardPatientGrouping?.inpatientRequestResponse ?? {};
const { t } = useTranslation();
const layout = useLayoutType();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,23 @@
import React from 'react';
import userEvent from '@testing-library/user-event';
import { launchWorkspace, useAppContext } from '@openmrs/esm-framework';
import { screen } from '@testing-library/react';
import { launchWorkspace } from '@openmrs/esm-framework';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { renderWithSwr } from 'tools';
import { mockInpatientRequest } from '__mocks__';
import { useInpatientRequest } from '../hooks/useInpatientRequest';
import { mockWardPatientGroupDetails } from '../../mock';
import AdmissionRequestsBar from './admission-requests-bar.component';

jest.mock('../hooks/useInpatientRequest', () => ({
useInpatientRequest: jest.fn(),
}));

const mockInpatientRequestResponse = {
error: undefined,
mutate: jest.fn(),
isValidating: false,
isLoading: false,
inpatientRequests: [mockInpatientRequest],
};

jest.mocked(useInpatientRequest).mockReturnValue(mockInpatientRequestResponse);
jest.mocked(useAppContext).mockReturnValue(mockWardPatientGroupDetails());

describe('Admission Requests Button', () => {
it('call launch workspace when clicked on manage button', async () => {
it('should launch workspace when clicked on manage button', async () => {
const user = userEvent.setup();
renderWithSwr(<AdmissionRequestsBar />);

await user.click(screen.getByRole('button', { name: /manage/i }));
expect(launchWorkspace).toHaveBeenCalled();
});

it('there should be one admission request', () => {
it('should have one admission request', () => {
renderWithSwr(<AdmissionRequestsBar />);

expect(screen.getByText('1 admission request')).toBeInTheDocument();
Expand Down
50 changes: 7 additions & 43 deletions packages/esm-ward-app/src/ward-view-header/ward-metrics.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useInpatientAdmission } from '../hooks/useInpatientAdmission';
import useWardLocation from '../hooks/useWardLocation';
import { screen } from '@testing-library/react';
import { useAppContext } from '@openmrs/esm-framework';
import { mockWardPatientGroupDetails } from '../../mock';

const wardMetrics = [
{ name: 'patients', key: 'patients', defaultTranslation: 'Patients' },
Expand All @@ -35,66 +36,29 @@ jest.mock('../hooks/useWardLocation', () =>
}),
);

const mockUseWardLocation = jest.mocked(useWardLocation);

jest.mock('../hooks/useBeds', () => ({
useBeds: jest.fn(),
}));

jest.mock('../hooks/useAdmissionLocation', () => ({
useAdmissionLocation: jest.fn(),
}));
jest.mock('../hooks/useInpatientAdmission', () => ({
useInpatientAdmission: jest.fn(),
}));

jest.mock('../hooks/useInpatientRequest', () => ({
useInpatientRequest: jest.fn(),
}));

jest.mocked(useBeds).mockReturnValue({
error: undefined,
mutate: jest.fn(),
isValidating: false,
isLoading: false,
beds: mockWardBeds,
totalCount: mockWardBeds.length,
hasMore: false,
loadMore: jest.fn(),
});

const mockAdmissionLocationResponse = jest.mocked(useAdmissionLocation).mockReturnValue({
error: undefined,
mutate: jest.fn(),
isValidating: false,
isLoading: false,
admissionLocation: mockAdmissionLocation,
});
const mockInpatientAdmissionResponse = jest.mocked(useInpatientAdmission).mockReturnValue({
error: undefined,
mutate: jest.fn(),
isValidating: false,
isLoading: false,
inpatientAdmissions: mockInpatientAdmissions,
});

const inpatientAdmissionsUuidMap = getInpatientAdmissionsUuidMap(mockInpatientAdmissions);
const mockWardPatientGroupDetails = {
admissionLocationResponse: mockAdmissionLocationResponse(),
inpatientAdmissionResponse: mockInpatientAdmissionResponse(),
...createAndGetWardPatientGrouping(mockInpatientAdmissions, mockAdmissionLocation, mockInpatientRequest),
};
jest.mocked(useAppContext).mockReturnValue(mockWardPatientGroupDetails);
jest.mocked(useAppContext).mockReturnValue(mockWardPatientGroupDetails());
describe('Ward Metrics', () => {
it('Should display metrics of in the ward ', () => {
mockUseWardLocation.mockReturnValueOnce({
location: null,
isLoadingLocation: false,
errorFetchingLocation: null,
invalidLocation: true,
});
const bedMetrics = getWardMetrics(mockWardBeds, mockWardPatientGroupDetails);
const bedMetrics = getWardMetrics(mockWardBeds, mockWardPatientGroupDetails());
renderWithSwr(<WardMetrics />);
for (let [key, value] of Object.entries(bedMetrics)) {
const fieldName = wardMetrics.find((metric) => metric.name == key)?.defaultTranslation;
expect(screen.getByText(fieldName)).toBeInTheDocument();
expect(screen.getByText(fieldName!)).toBeInTheDocument();
}
});
});
17 changes: 7 additions & 10 deletions packages/esm-ward-app/src/ward-view/ward-view.component.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { InlineNotification } from '@carbon/react';
import {
useAppContext,
useDefineAppContext,
WorkspaceContainer
} from '@openmrs/esm-framework';
import { useAppContext, useDefineAppContext, useFeatureFlag, WorkspaceContainer } from '@openmrs/esm-framework';
import React, { useEffect, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import EmptyBedSkeleton from '../beds/empty-bed-skeleton';
Expand Down Expand Up @@ -50,11 +46,12 @@ const WardViewMain = () => {
const { isLoading: isLoadingAdmissionLocation, error: errorLoadingAdmissionLocation } =
wardPatientsGrouping?.admissionLocationResponse ?? {};
const {
isLoading: isLoadingInpatientAdmissions,
error: errorLoadingInpatientAdmissions,
hasMore: hasMoreInpatientAdmissions,
loadMore: loadMoreInpatientAdmissions
isLoading: isLoadingInpatientAdmissions,
error: errorLoadingInpatientAdmissions,
hasMore: hasMoreInpatientAdmissions,
loadMore: loadMoreInpatientAdmissions,
} = wardPatientsGrouping?.inpatientAdmissionResponse ?? {};
const isBedManagementModuleInstalled = useFeatureFlag('bedmanagement-module');

const scrollToLoadMoreTrigger = useRef<HTMLDivElement>(null);
useEffect(
Expand Down Expand Up @@ -126,7 +123,7 @@ const WardViewMain = () => {
return (
<div className={styles.wardViewMain}>
{wardBeds}
{bedLayouts?.length == 0 && (
{bedLayouts?.length == 0 && isBedManagementModuleInstalled && (
<InlineNotification
kind="warning"
lowContrast={true}
Expand Down
90 changes: 15 additions & 75 deletions packages/esm-ward-app/src/ward-view/ward-view.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,16 @@ import {
getDefaultsFromConfigSchema,
useAppContext,
useConfig,
useFeatureFlag
useFeatureFlag,
} from '@openmrs/esm-framework';
import { screen } from '@testing-library/react';
import { mockAdmissionLocation, mockInpatientAdmissions, mockInpatientRequest } from '__mocks__';
import React from 'react';
import { useParams } from 'react-router-dom';
import { renderWithSwr } from 'tools';
import { mockWardPatientGroupDetails } from '../../mock';
import { configSchema } from '../config-schema';
import { useAdmissionLocation } from '../hooks/useAdmissionLocation';
import { useInpatientAdmission } from '../hooks/useInpatientAdmission';
import { useInpatientRequest } from '../hooks/useInpatientRequest';
import useWardLocation from '../hooks/useWardLocation';
import { useWardPatientGrouping } from '../hooks/useWardPatientGrouping';
import WardView from './ward-view.component';
import { createAndGetWardPatientGrouping } from './ward-view.resource';

jest.mocked(useConfig).mockReturnValue({
...getDefaultsFromConfigSchema<ConfigSchema>(configSchema),
Expand All @@ -42,54 +37,6 @@ jest.mock('react-router-dom', () => ({
}));
const mockUseParams = useParams as jest.Mock;

jest.mock('../hooks/useAdmissionLocation', () => ({
useAdmissionLocation: jest.fn(),
}));
jest.mock('../hooks/useInpatientAdmission', () => ({
useInpatientAdmission: jest.fn(),
}));
jest.mock('../hooks/useInpatientRequest', () => ({
useInpatientRequest: jest.fn(),
}));
jest.mock('../hooks/useWardPatientGrouping', () => ({
useWardPatientGrouping: jest.fn(),
}));
const mockAdmissionLocationResponse = jest.mocked(useAdmissionLocation).mockReturnValue({
error: undefined,
mutate: jest.fn(),
isValidating: false,
isLoading: false,
admissionLocation: mockAdmissionLocation,
});
const mockInpatientAdmissionResponse = jest.mocked(useInpatientAdmission).mockReturnValue({
data: mockInpatientAdmissions,
hasMore: false,
loadMore: jest.fn(),
isValidating: false,
isLoading: false,
error: undefined,
mutate: jest.fn(),
totalCount: 1
});

const mockInpatientRequestResponse = jest.mocked(useInpatientRequest).mockReturnValue({
inpatientRequests: mockInpatientRequest,
hasMore: false,
loadMore: jest.fn(),
isValidating: false,
isLoading: false,
error: undefined,
mutate: jest.fn(),
totalCount: 1
})

const mockWardPatientGroupDetails = jest.mocked(useWardPatientGrouping).mockReturnValue({
admissionLocationResponse: mockAdmissionLocationResponse(),
inpatientAdmissionResponse: mockInpatientAdmissionResponse(),
inpatientRequestResponse: mockInpatientRequestResponse(),
...createAndGetWardPatientGrouping(mockInpatientAdmissions, mockAdmissionLocation, mockInpatientRequest),
});

jest.mocked(useAppContext).mockReturnValue(mockWardPatientGroupDetails());

const intersectionObserverMock = () => ({
Expand All @@ -98,6 +45,8 @@ const intersectionObserverMock = () => ({
window.IntersectionObserver = jest.fn().mockImplementation(intersectionObserverMock);

describe('WardView', () => {
let replacedProperty: jest.ReplaceProperty<any> | null = null;

it('renders the session location when no location provided in URL', () => {
renderWithSwr(<WardView />);
const header = screen.getByRole('heading', { name: 'mock location' });
Expand Down Expand Up @@ -145,38 +94,29 @@ describe('WardView', () => {
expect(invalidText).toBeInTheDocument();
});

it('screen should render warning if backend module installed and no beds configured', () => {
it('should render warning if backend module installed and no beds configured', () => {
// override the default response so that no beds are returned
jest.mocked(useAdmissionLocation).mockReturnValue({
error: undefined,
mutate: jest.fn(),
isValidating: false,
isLoading: false,
admissionLocation: { ...mockAdmissionLocation, bedLayouts: [] },
});
const replacedProperty = jest.replaceProperty(mockWardPatientGroupDetails(), 'bedLayouts', []);
replacedProperty = jest.replaceProperty(mockWardPatientGroupDetails(), 'bedLayouts', []);

mockUseFeatureFlag.mockReturnValueOnce(true);
mockUseFeatureFlag.mockReturnValue(true);

renderWithSwr(<WardView />);
const noBedsConfiguredForThisLocation = screen.queryByText('No beds configured for this location');
expect(noBedsConfiguredForThisLocation).toBeInTheDocument();
replacedProperty.restore();
});

it('screen not should render warning if backend module installed and no beds configured', () => {
it('should not render warning if backend module installed and no beds configured', () => {
// override the default response so that no beds are returned
jest.mocked(useAdmissionLocation).mockReturnValue({
error: undefined,
mutate: jest.fn(),
isValidating: false,
isLoading: false,
admissionLocation: { ...mockAdmissionLocation, bedLayouts: [] },
});
mockUseFeatureFlag.mockReturnValueOnce(false);
replacedProperty = jest.replaceProperty(mockWardPatientGroupDetails(), 'bedLayouts', []);
mockUseFeatureFlag.mockReturnValue(false);

renderWithSwr(<WardView />);
const noBedsConfiguredForThisLocation = screen.queryByText('No beds configured for this location');
expect(noBedsConfiguredForThisLocation).not.toBeInTheDocument();
});

afterEach(() => {
replacedProperty?.restore();
replacedProperty = null;
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { type InpatientRequest } from '../../types';

interface AdmissionRequestsWorkspaceProps {}
const AdmissionRequestsWorkspace: React.FC<AdmissionRequestsWorkspaceProps> = () => {
// note: useAppContext() does not work here for some reason, so we call `useInpatientRequest`
// directly. See: https://openmrs.atlassian.net/browse/O3-4020
const {
inpatientRequests,
isLoading: isLoadingInpatientRequests,
Expand Down
Loading
Loading