Skip to content

Commit

Permalink
BAH-3802 | Add. Provider Notification Tab In Clinical View
Browse files Browse the repository at this point in the history
* BAH-3802 | Arjun | setup notifications page

* add. components for provider notifications

* Abi | update. bahmni-carbon-ui version

* Srini | BAH-3802 |Provider Acknowledgement workflow for the Emergency medication administered by Ward Nurse

* [Sri] - fix styling issue for provider acknowledgement flow

* Srini | BAH-3802 | Refactor the patient list view in the provider acknowledgement flow

* Bindu | Fix build issue

* [Rahul] | BAH-3802 | Refactor. Provider Notification State Management

---------

Co-authored-by: Arjun-Go <[email protected]>
Co-authored-by: srinithishg <[email protected]>
Co-authored-by: Rahul Ramesh <[email protected]>
Co-authored-by: Rahul Ramesh <[email protected]>
  • Loading branch information
5 people authored Jun 9, 2024
1 parent 6a0195b commit 63ae301
Show file tree
Hide file tree
Showing 32 changed files with 1,705 additions and 42 deletions.
8 changes: 4 additions & 4 deletions micro-frontends/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
"@babel/core": "^7.15.5",
"@babel/plugin-transform-runtime": "^7.22.4",
"@babel/preset-env": "^7.22.4",
"bahmni-form-controls": "^0.93.12",
"@babel/preset-react": "^7.22.3",
"@testing-library/react": "12.1.5",
"axios": "1.4.0",
"babel-jest": "^29.5.0",
"babel-loader": "^9.1.2",
"bahmni-form-controls": "^0.93.12",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "5.2.6",
"eslint": "^8.42.0",
"eslint-config-prettier": "^8.8.0",
Expand All @@ -29,13 +30,12 @@
"sass": "^1.63.4",
"sass-loader": "10.1.0",
"webpack": "^5.86.0",
"webpack-cli": "^5.1.4",
"copy-webpack-plugin": "^11.0.0"
"webpack-cli": "^5.1.4"
},
"dependencies": {
"@carbon/icons-react": "^10.18.0",
"angular-component": "^0.1.3",
"bahmni-carbon-ui": "0.1.3",
"bahmni-carbon-ui": "0.1.6",
"carbon-components": "^10.19.0",
"carbon-components-react": "^7.25.0",
"classnames": "2.3.1",
Expand Down
5 changes: 4 additions & 1 deletion micro-frontends/public/i18n/locale_en.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,8 @@
"UPDATE_NOTE_TITLE": "Update Note",
"ADD_NOTE_TITLE": "Add Note",
"LOADING": "Loading...",
"UPDATE": "Update"
"UPDATE": "Update",
"AKNOWLEDGE_BUTTON": "Acknowledge",
"AKNOWLEDGEMENT_REQUIRED_TEXT": "Acknowledgement required",
"NO_DRUGS_TO_BE_AKNOWLEDGED_TEXT": "You have no new drugs to be acknowledged"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React, { useState } from 'react';
import { Button, TextArea } from "carbon-components-react";
import { FormattedMessage } from 'react-intl';
import "./PatientListContent.scss";
import { Title } from "bahmni-carbon-ui";
import { formatArrayDateToDefaultDateFormat } from "../../utils/utils";
import PropTypes from "prop-types";

const PatientListContent = ({ patientMedicationDetails, handleOnClick }) => {
const { administered_date_time, administered_drug_name, medication_administration_performer_uuid, medication_administration_uuid } = patientMedicationDetails;
const acknowledgementRequiredText = (<FormattedMessage id="AKNOWLEDGE_BUTTON" defaultMessage="Acknowledge" />);
const [providerNotes, setProviderNotes] = useState("");

function acknowledgeMedication() {
handleOnClick(medication_administration_performer_uuid, medication_administration_uuid, providerNotes);
setProviderNotes("");
}

const handleNotesChange = (e) => {
setProviderNotes(e.target.value);
};

return (
<div className="patient-list-content">
<span>{formatArrayDateToDefaultDateFormat(administered_date_time)}</span>
<div className="content-info">
<span>{administered_drug_name}</span>
<div className="notes">
<TextArea
className="patient-list-text-area"
labelText={<Title text="Note" isRequired />}
placeholder="Enter Notes"
rows={1}
required
value={providerNotes}
onChange={handleNotesChange}
/>
<Button
className="patient-list-button"
disabled={providerNotes.trim() === ""}
onClick={acknowledgeMedication}
>
{acknowledgementRequiredText}
</Button>
</div>
</div>
</div>
);
};

PatientListContent.propTypes = {
patientMedicationDetails: PropTypes.shape({
administered_date_time: PropTypes.array.isRequired,
administered_drug_name: PropTypes.string.isRequired,
medication_administration_performer_uuid: PropTypes.string.isRequired,
}).isRequired,
handleOnClick: PropTypes.func.isRequired
};

export default PatientListContent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.patient-list-content {
display: flex;
flex-flow: row nowrap;
justify-content: start;
padding: 10px;

.content-info {
margin-left: 20px;
display: flex;
flex-flow: column nowrap;
justify-content: start;
align-items: start;

.notes {
display: flex;
flex-flow: row wrap;
justify-content: start;
align-items: end;

.patient-list-text-area {
flex: 1;
min-height: 48px;
}

.patient-list-button {
width: 116px;
height: 48px;
margin-left: 10px;

@media screen and (max-width: 640px) {
margin-left: 0;
margin-top: 10px;
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import PatientListContent from './PatientListContent';

describe('PatientListContent Component', () => {
const patientMedicationDetails = {
administered_date_time: [2022,6,9],
administered_drug_name: 'Drug A',
medication_administration_performer_uuid: 'performer123',
medication_administration_uuid: 'medication123'
};

const handleOnClickMock = jest.fn();

it('renders the component without crashing', () => {
const {container} = render(
<PatientListContent
patientMedicationDetails={patientMedicationDetails}
handleOnClick={handleOnClickMock}

/>
);
expect(container).toMatchSnapshot();
});

it('displays the correct medication information', () => {
const { getByText } = render(
<PatientListContent
patientMedicationDetails={patientMedicationDetails}
handleOnClick={handleOnClickMock}
/>
);
expect(getByText('9/6/2022')).toBeTruthy();
expect(getByText('Drug A')).toBeTruthy();
});

it('calls handleOnClick with correct arguments when Acknowledge button is clicked', () => {
const { getByText, getByPlaceholderText } = render(
<PatientListContent
patientMedicationDetails={patientMedicationDetails}
handleOnClick={handleOnClickMock}
/>
);
const notesInput = getByPlaceholderText('Enter Notes');
fireEvent.change(notesInput, { target: { value: 'Some notes' } });
expect(notesInput.value).toBe('Some notes');
fireEvent.click(getByText('Acknowledge'));
expect(handleOnClickMock).toHaveBeenCalledTimes(1);
expect(handleOnClickMock).toHaveBeenCalledWith(
'performer123',
'medication123',
'Some notes'
);
});

it('updates providerNotes state when notes are entered', () => {
const { getByPlaceholderText } = render(
<PatientListContent
patientMedicationDetails={patientMedicationDetails}
handleOnClick={handleOnClickMock}
/>
);
const notesInput = getByPlaceholderText('Enter Notes');
fireEvent.change(notesInput, { target: { value: 'Some notes' } });
expect(notesInput.value).toBe('Some notes');
});

it('clears providerNotes state after Acknowledge button is clicked', () => {
const { getByPlaceholderText, getByText } = render(
<PatientListContent
patientMedicationDetails={patientMedicationDetails}
handleOnClick={handleOnClickMock}
/>
);
const notesInput = getByPlaceholderText('Enter Notes');
fireEvent.change(notesInput, { target: { value: 'Some notes' } });
expect(notesInput.value).toBe('Some notes');
fireEvent.click(getByText('Acknowledge'));
expect(handleOnClickMock).toHaveBeenCalledWith(
'performer123',
'medication123',
'Some notes'
);
expect(notesInput.value).toBe('');
});

it('disables Acknowledge button when no notes are entered', () => {
const { getByText } = render(
<PatientListContent
patientMedicationDetails={patientMedicationDetails}
handleOnClick={handleOnClickMock}
/>
);
const acknowledgeButton = getByText('Acknowledge');
expect(acknowledgeButton).toHaveProperty('disabled', true);
});

it('enables Acknowledge button when notes are entered', () => {
const { getByText, getByPlaceholderText } = render(
<PatientListContent
patientMedicationDetails={patientMedicationDetails}
handleOnClick={handleOnClickMock}
/>
);
const notesInput = getByPlaceholderText('Enter Notes');
fireEvent.change(notesInput, { target: { value: 'Some notes' } });
const acknowledgeButton = getByText('Acknowledge');
expect(acknowledgeButton).toHaveProperty('disabled', false);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
export const mockSortedData = [
[
{
name: 'Hanif Oreo',
date_of_birth: '2024-01-17',
gender: 'Male',
identifier: '123',
patient_uuid: 'patientUuid123',
visit_uuid: 'visitUuid123',
},
],
[
{
name: 'Aby K',
date_of_birth: '2024-01-30',
gender: 'Male',
identifier: '456',
patient_uuid: 'patientUuid456',
visit_uuid: 'visitUuid456',
},
],
];

export const mockData = [
{
"identifier": "ET904706",
"name": "Hanif Oreo",
"gender": "M",
"patient_uuid": "a319d19c-03bd-425e-83ef-6799507548f2",
"date_of_birth": 1389810600000,
"medication_administration_uuid": "ae7e79b9-e831-4602-944d-6739f491f7cf",
"administered_date_time": [
2024,
1,
17,
16,
17,
59
],
"administered_drug_name": "Azithromycin 500 mg Tablet",
"administered_dose": 1,
"administered_dose_units": "Tablet(s)",
"administered_route": "Oral",
"medication_administration_performer_uuid": "868c8723-ac15-4b34-b55e-35314a1e6e53",
"visit_uuid": "39d4c60f-dbfc-4290-a2ec-603fcb650d96"
},
{
"identifier": "ET904844",
"name": "Aby K",
"gender": "M",
"patient_uuid": "8755ff3f-1eb6-42f1-92cd-7fb6f6e428ef",
"date_of_birth": 1359484200000,
"medication_administration_uuid": "8fc88156-1212-4c01-8f2f-a6b872a85501",
"administered_date_time": [
2024,
1,
30,
16,
29,
33
],
"administered_drug_name": "Paracetamol 250 mg Suppository",
"administered_dose": 1,
"administered_dose_units": "Tablet(s)",
"administered_route": "Oral",
"medication_administration_performer_uuid": "0e56149a-fc47-448f-bd14-f0c8cc5826c4",
"visit_uuid": "6f0c44e9-9555-45d2-acd5-8d6721029b67"
},
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from "react";
import { WarningAlt16 } from "@carbon/icons-react";
import { Link } from "carbon-components-react";
import "./PatientListTitle.scss";
import { getPatientIPDDashboardUrl } from "../../utils/providerNotifications/ProviderNotificationUtils";
import { formatGender } from "../../utils/utils";
import PropTypes from "prop-types";

const PatientListTitle = ({ noOfDrugs, identifier, name, age, gender, patientUuid, visitUuid }) => (
<div className="patient-list-tile-content">
<div className="warning">
<WarningAlt16 />
<span className="drug-count">{noOfDrugs}</span>
</div>
<div className="patient-info">
<Link href={getPatientIPDDashboardUrl(patientUuid, visitUuid)} className="patient-id">
{`(${identifier})`}
</Link>
<span>{`${name} - ${formatGender(gender)}, ${age}`}</span>
</div>
</div>
);

PatientListTitle.propTypes = {
noOfDrugs: PropTypes.number.isRequired,
identifier: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
age: PropTypes.string.isRequired,
gender: PropTypes.string.isRequired,
patientUuid: PropTypes.string.isRequired,
visitUuid: PropTypes.string.isRequired,
};

export default PatientListTitle;
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.patient-list-tile-content {
display: flex;
align-items: center;
padding: 10px;

.patient-info {
display: flex;
flex-flow: row;
justify-content: start;
align-items: center;
margin-left: 15px;
font-size: .875rem;
}

a.bx--link.patient-id {
color: #2b95ff;
font-size: .875rem;
margin-right: 10px;
}
}

.warning {
display: flex;
color: red;
align-items: center;
}


.drug-count {
padding-left: 5px;
}
Loading

0 comments on commit 63ae301

Please sign in to comment.