Skip to content

Commit

Permalink
Kavitha | Upgrade allergies, OT notes and default locale support (#1008)
Browse files Browse the repository at this point in the history
* Kavitha|add allergy changes and locale support

* Removing locale param from concept search by SearchByFullName api call

* Remove duplicate imports

* fix update notes api call

* fix. add Allergy test

* add getByTestId import in test

---------

Co-authored-by: Arjun-Go <[email protected]>
  • Loading branch information
kavitha-sundararajan and Arjun-Go authored Oct 10, 2024
1 parent e84c014 commit 443c1ea
Show file tree
Hide file tree
Showing 19 changed files with 392 additions and 102 deletions.
75 changes: 30 additions & 45 deletions micro-frontends/src/next-ui/Components/AddAllergy/AddAllergy.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import React, {Fragment, useEffect} from "react";
import propTypes from "prop-types";
import { Close24 } from "@carbon/icons-react";
import SaveAndCloseButtons from "../SaveAndCloseButtons/SaveAndCloseButtons.jsx";
import "./AddAllergy.scss";
import "../../../styles/common.scss";
import { SearchAllergen } from "../SearchAllergen/SearchAllergen.jsx";
import { isEmpty } from "lodash";
import {
RadioButton,
Expand All @@ -13,9 +9,16 @@ import {
} from "carbon-components-react";
import { FormattedMessage, useIntl } from "react-intl";
import { ArrowLeft } from "@carbon/icons-react/next";
import propTypes from "prop-types";
import React, { Fragment, useEffect } from "react";
import "../../../styles/common.scss";
import {
saveAllergiesAPICall
} from "../../utils/PatientAllergiesControl/AllergyControlUtils";
import SaveAndCloseButtons from "../SaveAndCloseButtons/SaveAndCloseButtons.jsx";
import { SearchAllergen } from "../SearchAllergen/SearchAllergen.jsx";
import { SelectReactions } from "../SelectReactions/SelectReactions";
import { bahmniEncounter, getEncounterType } from "../../utils/PatientAllergiesControl/AllergyControlUtils";
import { getCookies } from "../../utils/cookieHandler/cookieHandler";
import "./AddAllergy.scss";

export function AddAllergy(props) {
const { patient, provider, onClose, allergens, reaction, severityOptions, onSave } = props;
Expand All @@ -25,62 +28,46 @@ export function AddAllergy(props) {
const [notes, setNotes] = React.useState("");
const intl = useIntl();
const backToAllergenText = (
<FormattedMessage
id={"BACK_TO_ALLERGEN"}
defaultMessage={"Back to Allergies"}
/>
<FormattedMessage id={"BACK_TO_ALLERGEN"} defaultMessage={"Back to Allergies"} />
);
const allergiesHeading = (
<FormattedMessage
id={"ALLERGIES_HEADING"}
defaultMessage={"Allergies and Reactions"}
/>
<FormattedMessage id={"ALLERGIES_HEADING"} defaultMessage={"Allergies and Reactions"} />
);
const additionalComments = (
intl.formatMessage({ id: "ADDITIONAL_COMMENT_ALLERGY", defaultMessage: "Additional comments such as onset date etc."})
);
const [isSaveEnabled, setIsSaveEnabled] = React.useState(false);
const [isSaveSuccess, setIsSaveSuccess] = React.useState(null);
const [error, setError] = React.useState(null);
const clearForm = () => {
setAllergen({});
setReactions([]);
setNotes("");
setSeverity("");
setError(null);
};
const saveAllergies = async (allergen, reactions, severity, notes) => {
const {uuid: consultationUuid} = await getEncounterType('Consultation');
const cookies = getCookies();
const {uuid:locationUuid} = JSON.parse(cookies["bahmni.user.location"])
const allergyReactions = reactions.map((reaction) => {
return {reaction: reaction}
return { reaction: { uuid: reaction } };
});
const payload = {
locationUuid,
patientUuid: patient.uuid,
providers: [{uuid: provider.uuid}],
encounterTypeUuid: consultationUuid,
allergy:{
allergen:{
allergenKind: allergen.kind.toUpperCase(),
codedAllergen: allergen.uuid
allergen: {
allergenType: allergen.kind.toUpperCase(),
codedAllergen: {
uuid: allergen.uuid,
},
reactions: allergyReactions,
severity: severity,
comment: notes
}
}
const response = await bahmniEncounter(payload);
if(response.status === 200){
},
reactions: allergyReactions,
severity: { uuid: severity },
comment: notes,
};
const response = await saveAllergiesAPICall(payload, patient.uuid);
if (response.status === 201) {
setIsSaveSuccess(true);
}else{
setError(response.response.data.error.message)
} else {
setIsSaveSuccess(false);
}
}
};
useEffect(() => {
onSave(isSaveSuccess, error);
onSave(isSaveSuccess);
}, [isSaveSuccess]);
return (
<div className={"next-ui"}>
Expand Down Expand Up @@ -118,10 +105,7 @@ export function AddAllergy(props) {

<div className={"section-next-ui"}>
<div className={"font-large bold"}>
<FormattedMessage
id={"SEVERITY"}
defaultMessage={"Severity"}
/>
<FormattedMessage id={"SEVERITY"} defaultMessage={"Severity"} />
<span className={"red-text"}>&nbsp;*</span>
</div>
<RadioButtonGroup
Expand All @@ -134,6 +118,7 @@ export function AddAllergy(props) {
setSeverity(e);
setIsSaveEnabled(reactions && reactions.length > 0 && e);
}}
className={"severity-options-group"}
>
{severityOptions.map((option) => {
return (
Expand All @@ -160,7 +145,7 @@ export function AddAllergy(props) {
<div>
<SaveAndCloseButtons
onSave={async () => {
await saveAllergies( allergen, reactions, severity, notes);
await saveAllergies(allergen, reactions, severity, notes);
}}
onClose={onClose}
isSaveDisabled={!isSaveEnabled}
Expand All @@ -178,5 +163,5 @@ AddAllergy.propTypes = {
onSave: propTypes.func.isRequired,
patient: propTypes.object.isRequired,
provider: propTypes.object.isRequired,
severityOptions: propTypes.array.isRequired
severityOptions: propTypes.array.isRequired,
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import React from "react";
import { render, fireEvent, screen, getByTestId, waitFor } from "@testing-library/react";
import { render, fireEvent, screen, waitFor, getByTestId } from "@testing-library/react";
import { AddAllergy } from "./AddAllergy";
import {
saveAllergiesAPICall
} from "../../utils/PatientAllergiesControl/AllergyControlUtils";

jest.mock('../../utils/PatientAllergiesControl/AllergyControlUtils', () => ({
saveAllergiesAPICall: jest.fn(),
}));
import { IntlProvider } from "react-intl";

const mockAllergensData = [
Expand Down Expand Up @@ -267,4 +274,74 @@ describe("AddAllergy", () => {
"Additional comments such as onset date etc."
);
});

it("should save allergies successfully and set isSaveSuccess to true", async () => {
const { container } = render(
<IntlProvider locale="en">
<AddAllergy
onClose={onClose}
onSave={onSave}
patient={patient}
provider={provider}
severityOptions={mockSeverityData}
allergens={mockAllergensData}
reaction={mockReactionsData}
/>
</IntlProvider>
);
saveAllergiesAPICall.mockResolvedValueOnce({ status: 201 });
searchAllergen();
selectAllergen();
selectReaction(container);
selectSeverity(container);
const textArea = screen.getByPlaceholderText("Additional comments such as onset date etc.");
expect(textArea).toBeTruthy();
fireEvent.change(textArea, { target: { value: "New notes" } });
fireEvent.blur(textArea);
fireEvent.click(screen.getByText("Save"));

expect(saveAllergiesAPICall).toHaveBeenCalledWith({
allergen: {
allergenType: "FOOD",
codedAllergen : {uuid: "162302AAAAAA"}
},
reactions: [{reaction: { uuid: "101AA"}}],
severity: { uuid: "162301AAAAAA"},
comment: "New notes",
}, "patient#1");
});

it("should set isSaveSuccess to false if saveAllergiesAPICall fails", async () => {
const { container } = render(
<IntlProvider locale="en">
<AddAllergy
onClose={onClose}
onSave={onSave}
patient={patient}
provider={provider}
severityOptions={mockSeverityData}
allergens={mockAllergensData}
reaction={mockReactionsData}
/>
</IntlProvider>
);
searchAllergen();
selectAllergen();
selectReaction(container);
selectSeverity(container);

saveAllergiesAPICall.mockResolvedValueOnce({ status: 400 });

fireEvent.click(screen.getByText("Save"));
expect(saveAllergiesAPICall).toHaveBeenCalledWith({
allergen: {
allergenType: "FOOD",
codedAllergen : {uuid: "162302AAAAAA"}
},
reactions: [{reaction: { uuid: "101AA"}}],
severity: { uuid: "162301AAAAAA"},
comment: "",
}, "patient#1");

});
});
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,24 @@ describe("SearchAllergen", function () {
fireEvent.click(searchBarCloseIcon);
expect(() => screen.getByText("No Allergen found")).toThrowError();
});
it('should call onChange function when an allergen is clicked', function () {
const { container } = render(
<IntlProvider locale="en">
<SearchAllergen onChange={onChange} allergens={mockAllergensData} />
</IntlProvider>
);

const searchInput = container.querySelector('.bx--search-input');
fireEvent.change(searchInput, { target: { value: 'nu' } });

const allergen = screen.getByText('Peanuts');
fireEvent.click(allergen);

expect(onChange).toHaveBeenCalledTimes(1);
expect(onChange).toHaveBeenCalledWith({
name: 'Peanuts',
kind: 'Food',
uuid: '162302AAAAAA'
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ export const SelectReactions = (props) => {
const [isSearchResultEmpty, setIsSearchResultEmpty] = useState(true);
const [selectedReactions, setSelectedReactions] = useState([]);
const [allReactions] = useState(cloneDeep(reactions));
const [searchKey, setSearchKey] = useState("");

const search = (key) => {
setSearchKey(key)
if (!key) {
setIsSearchResultEmpty(true);
setSearchResults(initialReactionIds);
Expand Down Expand Up @@ -48,6 +50,9 @@ export const SelectReactions = (props) => {
}
};
useEffect(() => {
if(selectedReactions.length > 0){
setSearchKey("")
}
onChange(selectedReactions);
}, [selectedReactions]);

Expand All @@ -60,6 +65,7 @@ export const SelectReactions = (props) => {
<Search
id={"reaction-search"}
placeholder={"Type to search Reactions"}
value={searchKey}
onChange={(e) => {
search(e.target.value);
}}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { fireEvent, render, screen } from "@testing-library/react";
import { fireEvent, render, screen, act } from "@testing-library/react";
import { SelectReactions } from "./SelectReactions";

describe("Select reactions", function () {
Expand Down Expand Up @@ -107,11 +107,27 @@ describe("Select reactions", function () {
/>
);
const searchInput = container.querySelector(".bx--search-input");
fireEvent.change(searchInput, { target: { value: "GI" } });
fireEvent.change(searchInput, { target: { value: "set" } });
expect(screen.getByText("GI Upset")).toBeTruthy();
expect(() => screen.getByText("Fever")).toThrowError();
});

it("should set isSearchResultEmpty to true and reset searchResults when key is empty", () => {
const { container } = render(
<SelectReactions
onChange={onChange}
reactions={mockReactions}
selectedAllergen={mockSelectedAllergen}
/>
);
const searchInput = container.querySelector(".bx--search-input");

fireEvent.change(searchInput, { target: { value: "vw" } });

const allCheckboxes = container.querySelectorAll(".bx--checkbox");
expect(allCheckboxes).toHaveLength(5); // Assuming mockReactions has 5 reactions
});

it("should show chiclets for selected reactions", function () {
const { container, getAllByText } = render(
<SelectReactions
Expand All @@ -125,4 +141,43 @@ describe("Select reactions", function () {
expect(tag).toBeTruthy();
expect(getAllByText("GI Upset").length).toEqual(2);
});

it("should set searchKey correctly", () => {
const { container } = render(
<SelectReactions
onChange={onChange}
reactions={mockReactions}
selectedAllergen={mockSelectedAllergen}
/>
);
const searchInput = container.querySelector(".bx--search-input");

fireEvent.change(searchInput, { target: { value: "GI" } });
expect(searchInput.value).toBe("GI");
});

it("should reset isSearchResultEmpty and searchResults when key is empty", () => {
const { container, rerender } = render(
<SelectReactions
onChange={onChange}
reactions={mockReactions}
selectedAllergen={mockSelectedAllergen}
/>
);
const searchInput = container.querySelector(".bx--search-input");

fireEvent.change(searchInput, { target: { value: "GI" } });
expect(container.querySelectorAll(".bx--checkbox")).toHaveLength(1);

fireEvent.change(searchInput, { target: { value: "" } });
rerender(
<SelectReactions
onChange={onChange}
reactions={mockReactions}
selectedAllergen={mockSelectedAllergen}
/>
);

expect(container.querySelectorAll(".bx--checkbox")).toHaveLength(5);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ exports[`Select reactions should render SelectReactions 1`] = `
placeholder="Type to search Reactions"
role="searchbox"
type="text"
value=""
/>
<button
aria-label="Clear search input"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ export const ViewAllergiesAndReactions = (props) => {
<div>
{allergies.map((allergy, index) => {
const title = <div key={index}
className={` allergies-row ${showTextAsAbnormal ? "allergies-red-text"
: allergy.severity === "severe" ? "allergies-red-text": ""}`}>
className={` allergies-row ${showTextAsAbnormal ? "red-text" : allergy.severity === "severe" ? "red-text": ""}`}>
<div>{allergy.allergen}</div>
<div>{allergy.reactions.join(", ")}</div>
<div className={"capitalize"}>{allergy.severity}</div>
Expand All @@ -31,7 +30,7 @@ export const ViewAllergiesAndReactions = (props) => {
{allergy.note}</div>}
</div>
<div className={"allergy-provider"}>
{allergy.provider + " " + allergy.datetime}
{allergy.provider}
</div>
</div>
</AccordionItem>
Expand Down
Loading

0 comments on commit 443c1ea

Please sign in to comment.