Skip to content

Commit

Permalink
(fix)O3-2197:Unable to remove a patient from a list
Browse files Browse the repository at this point in the history
  • Loading branch information
jwamalwa committed Oct 3, 2023
1 parent 40ca359 commit c8f859d
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 17 deletions.
22 changes: 21 additions & 1 deletion packages/esm-patient-list-app/src/api/api-remote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,24 @@ export async function getPatientListMembers(cohortUuid: string, ac = new AbortCo
throw error;
}

const currentDate = new Date();
const searchQuery = results.map((p) => p.patient.uuid).join(',');
const result = await openmrsFetch(`/ws/fhir2/R4/Patient/_search?_id=${searchQuery}`, {
method: 'POST',
signal: ac.signal,
});

const patients: Array<PatientListMember> = result.data.entry.map((e) => e.resource);
return patients;
const validPatients = patients.filter((patient) => {
if (!patient.endDate) {
return true;
}

const endDate = new Date(patient.endDate);
return endDate >= currentDate;
});

return validPatients;
}

export async function getPatientListIdsForPatient(patientUuid: string, ac = new AbortController()) {
Expand All @@ -136,6 +146,16 @@ export async function addPatientToList(data: AddPatientData, ac = new AbortContr
return postData(`${cohortUrl}/cohortmember`, data, ac);
}

export async function removePatientFromList(cohortMembershipUuid: string, ac = new AbortController()) {
return postData(
`${cohortUrl}/cohortmember/${cohortMembershipUuid}`,
{
endDate: new Date(),
},
ac,
);
}

export async function createPatientList(cohort: NewCohortDataPayload, ac = new AbortController()) {
return postData(
`${cohortUrl}/cohort/`,
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 @@ -34,6 +34,7 @@ export interface PatientListOption {
}

export interface PatientListMember {
endDate: string | number | Date;
id: string;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, useCallback, useMemo } from 'react';
import { navigate, formatDate, parseDate, showToast } from '@openmrs/esm-framework';
import { ExtensionSlot, showToast, navigate, formatDate, parseDate } from '@openmrs/esm-framework';
import { useParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { OverflowMenuItem } from '@carbon/react';
Expand All @@ -20,14 +20,14 @@ interface PatientListMemberRow {
}

const PatientListDetailComponent = () => {
const { t } = useTranslation();
const params = useParams();
const patientListUuid = params.patientListUuid;
const { t } = useTranslation();
const [currentPage, setPageCount] = useState(1);
const [currentPageSize, setCurrentPageSize] = useState(10);
const [searchString, setSearchString] = useState('');
const { data: patientListDetails, mutate: mutatePatientListDetails } = usePatientListDetails(patientListUuid);
const { data: patientListMembers } = usePatientListMembers(
const { data: patientListMembers, mutate: mutatePatientListMembers } = usePatientListMembers(
patientListUuid,
searchString,
(currentPage - 1) * currentPageSize,
Expand All @@ -45,6 +45,7 @@ const PatientListDetailComponent = () => {
sex: member?.patient?.person?.gender,
startDate: formatDate(parseDate(member?.startDate)),
uuid: `${member?.patient?.uuid}`,
membershipUuid: member?.uuid,
}))
: []
: [],
Expand Down Expand Up @@ -102,18 +103,23 @@ const PatientListDetailComponent = () => {
}, [patientListUuid, patientListDetails, t]);

return (
<main className={styles.container}>
<section className={styles.cohortHeader}>
<div data-testid="patientListHeader">
<h1 className={styles.productiveHeading03}>{patientListDetails?.name ?? '--'}</h1>
<h4 className={`${styles.bodyShort02} ${styles.marginTop}`}>{patientListDetails?.description ?? '--'}</h4>
<div className={` ${styles.text02} ${styles.bodyShort01} ${styles.marginTop}`}>
{patientListDetails?.size} {t('patients', 'patients')} &middot;{' '}
<span className={styles.label01}>{t('createdOn', 'Created on')}:</span>{' '}
{patientListDetails?.startDate ? formatDate(parseDate(patientListDetails.startDate)) : null}
<main className={`omrs-main-content ${styles.patientListDetailsPage}`}>
<section>
<ExtensionSlot name="breadcrumbs-slot" />
<div className={styles.cohortHeader} data-testid="patientListHeader">
<div>
{patientListDetails && (
<>
<h1 className={styles.productiveHeading03}>{patientListDetails?.name}</h1>
<h4 className={`${styles.bodyShort02} ${styles.marginTop}`}>{patientListDetails?.description}</h4>
<div className={` ${styles.text02} ${styles.bodyShort01} ${styles.marginTop}`}>
{patientListDetails?.size} {t('patients', 'patients')} &middot;{' '}
<span className={styles.label01}>{t('createdOn', 'Created on')}:</span>{' '}
{patientListDetails?.startDate ? formatDate(parseDate(patientListDetails.startDate)) : null}
</div>
</>
)}
</div>
</div>
<div className={styles.overflowMenu}>
<CustomOverflowMenuComponent
menuTitle={
<>
Expand All @@ -128,14 +134,21 @@ const PatientListDetailComponent = () => {
<OverflowMenuItem itemText={t('delete', 'Delete')} onClick={handleDelete} isDelete />
</CustomOverflowMenuComponent>
</div>
</section>
<section>
<div className={styles.tableContainer}>
<PatientListTable
patients={patients}
columns={headers}
isLoading={!patientListMembers && !patients}
isFetching={!patientListMembers}
cohortName={patientListDetails?.name}
<<<<<<< HEAD
<<<<<<< HEAD
mutatePatientListMembers={mutatePatientListMembers}
=======
>>>>>>> a4501159... remove cohort members whose end date is passed
=======
mutatePatientListMembers={mutatePatientListMembers}
>>>>>>> e17d04b1... Add mutate function to automatically update the list after removing a patient
search={{
onSearch: handleSearch,
placeHolder: 'Search',
Expand All @@ -155,6 +168,8 @@ const PatientListDetailComponent = () => {
}}
/>
</div>
</section>
<section>
{showEditPatientListDetailOverlay && (
<EditPatientListDetailsOverlay
close={() => setEditPatientListDetailOverlay(false)}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import React, { useCallback, useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { removePatientFromList } from '../api/api-remote';
import { ExtensionSlot, isDesktop, showToast, useLayoutType } from '@openmrs/esm-framework';
import { OverflowMenu, Layer, OverflowMenuItem, Modal } from '@carbon/react';
import overflowMenuStyles from './overflow-menu.scss';

interface OverflowMenuCellProps {
cohortMembershipUuid: string;
cohortName: string;
mutatePatientListMembers: () => void;
}

const OverflowMenuComponent: React.FC<OverflowMenuCellProps> = ({
cohortMembershipUuid,
cohortName,
mutatePatientListMembers,
}) => {
const { t } = useTranslation();
const layoutType = useLayoutType();
const desktopLayout = isDesktop(layoutType);
const [isDeleting, setIsDeleting] = useState(false);
const [showConfirmationModal, setShowConfirmationModal] = useState(false);

const confirmRemovePatientFromList = useCallback(async () => {
setIsDeleting(true);
try {
await removePatientFromList(cohortMembershipUuid);
mutatePatientListMembers();
showToast({
title: t('removed', 'Removed'),
description: `${t('successRemovePatientFromList', 'Successfully removed patient from list')}: ${cohortName}`,
});
} catch (error) {
showToast({
title: t('error', 'Error'),
kind: 'error',
description: `${t('errorRemovePatientFromList', 'Failed to remove patient from list')}: ${cohortName}`,
});
}

setIsDeleting(false);
setShowConfirmationModal(false);
}, [cohortMembershipUuid, cohortName, mutatePatientListMembers, t]);

return (
<Layer className={overflowMenuStyles.layer}>
<OverflowMenu
data-floating-menu-container
ariaLabel={`Remove patient from the ${cohortName} list`}
size={desktopLayout ? 'sm' : 'lg'}
flipped>
<ExtensionSlot name="cohort-member-action-items" />
<OverflowMenuItem
size={desktopLayout ? 'sm' : 'lg'}
className={overflowMenuStyles.menuItem}
onClick={() => setShowConfirmationModal(true)}
itemText={t('removePatient', 'Remove patient')}
isDelete
/>
</OverflowMenu>

{showConfirmationModal && (
<Modal
open
danger
modalHeading={t('confirmRemovePatient', 'Are you sure you want to remove this patient from {cohortName}?', {
cohortName: cohortName,
})}
modalLabel={t('removePatient', 'Remove patient')}
primaryButtonText="Remove patient"
secondaryButtonText="Cancel"
onRequestClose={() => setShowConfirmationModal(false)}
onRequestSubmit={confirmRemovePatientFromList}
primaryButtonDisabled={isDeleting}
/>
)}
</Layer>
);
};

export default OverflowMenuComponent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.layer {
height: 100%;
}
.menuItem {
max-width: none;
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ const PatientTable: React.FC<PatientTableProps> = ({
</TableHeader>
))}
</TableRow>

</TableHead>
<TableBody>
{rows.map((row) => (
Expand Down

0 comments on commit c8f859d

Please sign in to comment.