Skip to content

Commit

Permalink
Fixup
Browse files Browse the repository at this point in the history
  • Loading branch information
denniskigen committed Oct 27, 2023
1 parent 3e61990 commit b7d434b
Show file tree
Hide file tree
Showing 22 changed files with 361 additions and 209 deletions.
2 changes: 1 addition & 1 deletion e2e/pages/patient-lists-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class PatientListsPage {

async editPatientList(listName: string, description: string) {
await this.page.getByRole('button', { name: 'Actions' }).click();
await this.page.getByRole('menuitem', { name: 'Edit Name or Description' }).click();
await this.page.getByRole('menuitem', { name: 'Edit name or description' }).click();
await this.page.getByLabel('List name').fill(listName);
await this.page.getByLabel('Describe the purpose of this list in a few words').fill(description);
await this.page.getByRole('button', { name: 'Edit list' }).click();
Expand Down
1 change: 1 addition & 0 deletions packages/esm-appointments-app/translations/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"cancel": "Cancelar",
"cancelAppointment": "Cancelar cita",
"cancelled": "Cancelada",
"cancelledSuccessfully": "It has been cancelled successfully",
"checkedIn": "Checked in",
"checkedOut": "Completada",
"checkFilters": "Compruebe los filtros anteriores",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useState, useEffect, useMemo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { TFunction } from 'i18next';
import useSWR from 'swr';
import {
getDynamicOfflineDataEntries,
Expand All @@ -11,11 +12,10 @@ import {
navigate,
useConfig,
} from '@openmrs/esm-framework';
import { Button, Checkbox, Pagination, Search, SkeletonText, CheckboxSkeleton } from '@carbon/react';
import { Button, Checkbox, Pagination, Search, CheckboxSkeleton } from '@carbon/react';
import { addPatientToList, getAllPatientLists, getPatientListIdsForPatient } from '../api/api-remote';
import { TFunction } from 'i18next';
import styles from './add-patient.scss';
import { ConfigSchema } from '../config-schema';
import styles from './add-patient.scss';

interface AddPatientProps {
closeModal: () => void;
Expand Down
27 changes: 19 additions & 8 deletions packages/esm-patient-list-app/src/api/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import { useEffect, useState } from 'react';
import useSWR from 'swr';
import useSWRInfinite from 'swr/infinite';
import { openmrsFetch, FetchResponse, useConfig } from '@openmrs/esm-framework';
import { cohortUrl, getAllPatientLists, getPatientListIdsForPatient, getPatientListMembers } from './api-remote';
import { ConfigSchema } from '../config-schema';
import {
CohortResponse,
CohortType,
Expand All @@ -6,12 +12,6 @@ import {
PatientListFilter,
PatientListType,
} from './types';
import { openmrsFetch, FetchResponse, useConfig } from '@openmrs/esm-framework';
import useSWR from 'swr';
import useSWRInfinite from 'swr/infinite';
import { cohortUrl, getAllPatientLists, getPatientListIdsForPatient, getPatientListMembers } from './api-remote';
import { ConfigSchema } from '../config-schema';
import { useEffect, useState } from 'react';

interface PatientListResponse {
results: CohortResponse<OpenmrsCohort>;
Expand Down Expand Up @@ -134,11 +134,22 @@ export function usePatientListMembers(
pageSize: number = 10,
v: string = 'full',
) {
const swrResult = useSWR<FetchResponse<CohortResponse<OpenmrsCohortMember>>, Error>(
const { data, error, mutate } = useSWR<FetchResponse<CohortResponse<OpenmrsCohortMember>>, Error>(
`${cohortUrl}/cohortmember?cohort=${patientListUuid}&startIndex=${startIndex}&limit=${pageSize}&v=${v}&q=${searchQuery}`,
openmrsFetch,
);
return { ...swrResult, data: swrResult?.data?.data?.results };

// FIXME: This is a workaround for removing a patient from a list
const filterList = (listMembers: Array<OpenmrsCohortMember>) =>
listMembers.filter((member) => !member.endDate && !member.voided);

const filteredListMembers = filterList(data?.data?.results ?? []);

return {
listMembers: filteredListMembers,
error: error,
mutateListMembers: mutate,
};
}

export function useCohortTypes() {
Expand Down
1 change: 1 addition & 0 deletions packages/esm-patient-list-app/src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export interface OpenmrsCohortMember {
name: string;
uuid: string;
patient: OpenmrsResource;
voided: boolean;
}

export interface CohortResponse<T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const CustomOverflowMenuComponent: React.FC<CustomOverflowMenuComponentProps> =
onClick={toggleShowMenu}
style={{
boxShadow: showMenu ? '0 2px 6px 0 rgb(0 0 0 / 30%)' : 'none',
height: '2.5rem',
}}>
{menuTitle}
</button>
Expand All @@ -52,6 +53,7 @@ const CustomOverflowMenuComponent: React.FC<CustomOverflowMenuComponentProps> =
id="custom-actions-overflow-menu"
style={{
display: showMenu ? 'block' : 'none',
marginTop: '-0.475rem',
}}>
<ul className="cds--overflow-menu-options__content">{children}</ul>
<span />
Expand Down
9 changes: 5 additions & 4 deletions packages/esm-patient-list-app/src/overlay.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ const Overlay: React.FC<OverlayProps> = ({ close, children, header, buttonsGroup
<div className={isDesktop(layout) ? styles.desktopOverlay : styles.tabletOverlay}>
{isDesktop(layout) ? (
<div className={styles.desktopHeader}>
<div className={styles.headerContent}>{header}</div>
<span className={styles.headerContent}>{header}</span>
<Button
className={styles.closeButton}
onClick={close}
kind="ghost"
hasIconOnly
renderIcon={(props) => <Close size={16} {...props} />}
iconDescription="Close overlay"
kind="ghost"
onClick={close}
renderIcon={(props) => <Close size={16} {...props} />}
size="lg"
/>
</div>
) : (
Expand Down
15 changes: 15 additions & 0 deletions packages/esm-patient-list-app/src/overlay.scss
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
align-items: center;
background-color: $ui-03;
border-bottom: 1px solid $text-03;
height: 2.5rem;
}

.headerContent {
Expand All @@ -56,14 +57,28 @@
}

.closeButton {
border: none;
border-bottom: 1px solid $text-03;
background-color: $ui-02;
padding-block-start: 0.75rem;
// FIXME: Why are carbon's default button styles not working?
height: 2.5rem;
width: 2.5rem;
}

.overlayContent {
padding: spacing.$spacing-05;
overflow-y: auto;
}

:global(.omrs-breakpoint-lt-desktop) .overlayContent {
background-color: #ededed;
}

:global(.omrs-breakpoint-gt-tablet) .overlayContent {
background-color: white;
}

.buttonsGroup {
align-self: end;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { useParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { OverflowMenuItem, Modal } from '@carbon/react';
import { OverflowMenuVertical } from '@carbon/react/icons';
import { deletePatientList } from '../api/api-remote';
import { usePatientListDetails, usePatientListMembers } from '../api/hooks';
import CustomOverflowMenuComponent from '../overflow-menu/overflow-menu.component';
import EditPatientListDetailsOverlay from '../create-edit-patient-list/create-edit-list.component';
import PatientListTable from '../patient-table/patient-table.component';
import { deletePatientList } from '../api/api-remote';
import { usePatientListDetails, usePatientListMembers } from '../api/hooks';
import styles from './patient-list-detail.scss';

interface PatientListMemberRow {
Expand All @@ -27,20 +27,21 @@ const PatientListDetailComponent = () => {
const [currentPageSize, setCurrentPageSize] = useState(10);
const [searchString, setSearchString] = useState('');
const { data: patientListDetails, mutate: mutatePatientListDetails } = usePatientListDetails(patientListUuid);
const { data: patientListMembers, mutate: mutatePatientListMembers } = usePatientListMembers(
const { listMembers, mutateListMembers } = usePatientListMembers(
patientListUuid,
searchString,
(currentPage - 1) * currentPageSize,
currentPageSize,
);

const [showEditPatientListDetailOverlay, setEditPatientListDetailOverlay] = useState(false);
const [showDeleteConfirmationModal, setShowDeleteConfirmationModal] = useState(false);

const patients: PatientListMemberRow[] = useMemo(
() =>
patientListMembers
? patientListMembers?.length
? patientListMembers?.map((member) => ({
listMembers
? listMembers?.length
? listMembers?.map((member) => ({
name: member?.patient?.person?.display,
identifier: member?.patient?.identifiers[0]?.identifier ?? null,
sex: member?.patient?.person?.gender,
Expand All @@ -50,7 +51,7 @@ const PatientListDetailComponent = () => {
}))
: []
: [],
[patientListMembers],
[listMembers],
);

const headers = useMemo(
Expand Down Expand Up @@ -130,7 +131,7 @@ const PatientListDetailComponent = () => {
}>
<OverflowMenuItem
className={styles.menuItem}
itemText={t('editNameDescription', 'Edit Name or Description')}
itemText={t('editNameDescription', 'Edit name or description')}
onClick={() => setEditPatientListDetailOverlay(true)}
/>
<OverflowMenuItem
Expand All @@ -147,10 +148,9 @@ const PatientListDetailComponent = () => {
<PatientListTable
patients={patients}
columns={headers}
isLoading={!patientListMembers && !patients}
isFetching={!patientListMembers}
cohortName={patientListDetails?.name}
mutatePatientListMembers={mutatePatientListMembers}
isLoading={!listMembers && !patients}
isFetching={!listMembers}
mutateListMembers={mutateListMembers}
search={{
onSearch: handleSearch,
placeHolder: 'Search',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { usePatientListDetails, usePatientListMembers } from '../api/hooks';
import { showToast } from '@openmrs/esm-framework';
import { deletePatientList } from '../api/api-remote';
import { getByTextWithMarkup } from '../../../../tools/test-helpers';
import PatientListDetailComponent from './patient-list-detail.component';

const mockedUsePatientListDetails = usePatientListDetails as jest.Mock;
Expand All @@ -27,7 +27,7 @@ jest.mock('@openmrs/esm-framework', () => ({
const mockedPatientListDetails = {
name: 'Test Patient List',
description: 'This is a test patient list',
size: 5,
size: 1,
startDate: '2023-08-14',
};

Expand All @@ -51,7 +51,6 @@ const mockedPatientListMembers = [

describe('PatientListDetailComponent', () => {
beforeEach(() => {
jest.clearAllMocks();
mockedUsePatientListDetails.mockReturnValue({
data: mockedPatientListDetails,
});
Expand All @@ -63,30 +62,31 @@ describe('PatientListDetailComponent', () => {
mockedDeletePatientList.mockResolvedValue({});
});

it('renders patient list details', async () => {
it('renders patient list details page', async () => {
render(<PatientListDetailComponent />);

await waitFor(() => {
expect(screen.getByText('Test Patient List')).toBeInTheDocument();
expect(screen.getByText('This is a test patient list')).toBeInTheDocument();
});
expect(screen.getByRole('heading', { name: /^test patient list$/i })).toBeInTheDocument();
expect(screen.getByRole('heading', { name: /this is a test patient list/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /actions/i })).toBeInTheDocument();
expect(screen.getByRole('link', { name: /back to lists page/i })).toBeInTheDocument();
expect(screen.getByText(/1 patient/)).toBeInTheDocument();
expect(getByTextWithMarkup('Created on: 14-Aug-2023')).toBeInTheDocument();
expect(screen.getByText(/edit name or description/i)).toBeInTheDocument();
expect(screen.getByText(/delete patient list/i)).toBeInTheDocument();
});

it('displays patient list members', async () => {
it('renders an empty state view if a list has no patients', async () => {
render(<PatientListDetailComponent />);

await waitFor(() => {
expect(screen.getByText('John Doe')).toBeInTheDocument();
expect(screen.getByText('Male')).toBeInTheDocument();
expect(screen.getByText('100GEJ')).toBeInTheDocument();
});
expect(screen.getByTitle(/empty data illustration/i)).toBeInTheDocument();
expect(screen.getByText(/there are no patients in this list/i)).toBeInTheDocument();
});

it('opens edit overlay when "Edit Name or Description" is clicked', () => {
it('opens overlay with a form when the "Edit name or description" button is clicked', () => {
render(<PatientListDetailComponent />);

userEvent.click(screen.getByText('Actions'));
const editBtn = screen.getByText('Edit Name or Description');
const editBtn = screen.getByText('Edit name or description');
userEvent.click(editBtn);
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Layer, Button, Tile } from '@carbon/react';
import { Trans, useTranslation } from 'react-i18next';
import { Add } from '@carbon/react/icons';
import { EmptyDataIllustration } from './empty-data-illustration.component';
import styles from './empty-state.scss';
import { Add } from '@carbon/react/icons';

export interface EmptyStateProps {
listType: string;
Expand Down
Loading

0 comments on commit b7d434b

Please sign in to comment.