From a6828e3397228596aff2f2c3e4ea1fa3293e1b3a Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Mon, 27 Nov 2023 16:36:38 +0530 Subject: [PATCH 01/27] fix doctor notes test (#6728) --- cypress/pageobject/Patient/PatientConsultation.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/cypress/pageobject/Patient/PatientConsultation.ts b/cypress/pageobject/Patient/PatientConsultation.ts index 4fb299a4965..9c588f50c4e 100644 --- a/cypress/pageobject/Patient/PatientConsultation.ts +++ b/cypress/pageobject/Patient/PatientConsultation.ts @@ -203,7 +203,6 @@ export class PatientConsultationPage { } addDoctorsNotes(notes: string) { - cy.get("#expand_doctor_notes").click(); cy.get("#doctor_notes_textarea").type(notes); } From a6fd9f67cc714c8b572e2a961cfe79a3fac266d3 Mon Sep 17 00:00:00 2001 From: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> Date: Mon, 27 Nov 2023 18:00:37 +0530 Subject: [PATCH 02/27] facility csv download test (#6730) --- .../e2e/facility_spec/facility_homepage.cy.ts | 54 +++++++++++++++++++ cypress/pageobject/Facility/FacilityHome.ts | 31 +++++++++++ src/Components/Common/Export.tsx | 2 +- 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 cypress/e2e/facility_spec/facility_homepage.cy.ts create mode 100644 cypress/pageobject/Facility/FacilityHome.ts diff --git a/cypress/e2e/facility_spec/facility_homepage.cy.ts b/cypress/e2e/facility_spec/facility_homepage.cy.ts new file mode 100644 index 00000000000..6f53f554835 --- /dev/null +++ b/cypress/e2e/facility_spec/facility_homepage.cy.ts @@ -0,0 +1,54 @@ +// FacilityCreation +import { cy, describe, before, beforeEach, it, afterEach } from "local-cypress"; +import LoginPage from "../../pageobject/Login/LoginPage"; +import FacilityHome from "../../pageobject/Facility/FacilityHome"; + +describe("Facility Creation", () => { + const loginPage = new LoginPage(); + const facilityHome = new FacilityHome(); + const facilitiesAlias = "downloadFacilitiesCSV"; + const capacitiesAlias = "downloadCapacitiesCSV"; + const doctorsAlias = "downloadDoctorsCSV"; + const triagesAlias = "downloadTriagesCSV"; + + before(() => { + loginPage.loginAsDisctrictAdmin(); + cy.saveLocalStorage(); + }); + + beforeEach(() => { + cy.viewport(1280, 720); + cy.restoreLocalStorage(); + cy.awaitUrl("/facility"); + }); + + it("Verify Facility Export Functionality", () => { + // Download the Facilities CSV + facilityHome.csvDownloadIntercept(facilitiesAlias, ""); + facilityHome.clickExportButton(); + facilityHome.clickMenuItem("Facilities"); + facilityHome.verifyDownload(facilitiesAlias); + facilityHome.clickSearchButton(); // to avoid flaky test, as sometimes, the test is unable to focus on the object + // Download the Capacities CSV + facilityHome.csvDownloadIntercept(capacitiesAlias, "&capacity"); + facilityHome.clickExportButton(); + facilityHome.clickMenuItem("Capacities"); + facilityHome.verifyDownload(capacitiesAlias); + facilityHome.clickSearchButton(); + // Download the Doctors CSV + facilityHome.csvDownloadIntercept(doctorsAlias, "&doctors"); + facilityHome.clickExportButton(); + facilityHome.clickMenuItem("Doctors"); + facilityHome.verifyDownload(doctorsAlias); + facilityHome.clickSearchButton(); + // Download the Triages CSV + facilityHome.csvDownloadIntercept(triagesAlias, "&triage"); + facilityHome.clickExportButton(); + facilityHome.clickMenuItem("Triages"); + facilityHome.verifyDownload(triagesAlias); + facilityHome.clickSearchButton(); + }); + afterEach(() => { + cy.saveLocalStorage(); + }); +}); diff --git a/cypress/pageobject/Facility/FacilityHome.ts b/cypress/pageobject/Facility/FacilityHome.ts new file mode 100644 index 00000000000..faf6747e024 --- /dev/null +++ b/cypress/pageobject/Facility/FacilityHome.ts @@ -0,0 +1,31 @@ +// cypress/support/pageObjects/FacilityHome.ts + +class FacilityHome { + // Selectors + exportButton = "#export-button"; + searchButton = "#search"; + menuItem = "[role='menuitem']"; + + // Operations + clickExportButton() { + cy.get(this.exportButton).click(); + } + + clickSearchButton() { + cy.get(this.searchButton).click(); + } + + clickMenuItem(itemName: string) { + cy.get(this.menuItem).contains(itemName).click(); + } + + csvDownloadIntercept(alias: string, queryParam: string) { + cy.intercept("GET", `**/api/v1/facility/?csv${queryParam}`).as(alias); + } + + verifyDownload(alias: string) { + cy.wait(`@${alias}`).its("response.statusCode").should("eq", 200); + } +} + +export default FacilityHome; diff --git a/src/Components/Common/Export.tsx b/src/Components/Common/Export.tsx index f991c476aac..7ddaca115bd 100644 --- a/src/Components/Common/Export.tsx +++ b/src/Components/Common/Export.tsx @@ -40,7 +40,7 @@ export const ExportMenu = ({ const { isExporting, exportFile } = useExport(); return ( -
+
Date: Mon, 27 Nov 2023 18:15:00 +0530 Subject: [PATCH 03/27] Show "ICU Admission Date" only for Internal Transfer (#6729) * Show "ICU Admission Date" only for Internal Transfer * fix styling --- src/Components/Facility/ConsultationForm.tsx | 54 ++++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Components/Facility/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx index 091be6b5968..ed3934441a8 100644 --- a/src/Components/Facility/ConsultationForm.tsx +++ b/src/Components/Facility/ConsultationForm.tsx @@ -724,7 +724,10 @@ export const ConsultationForm = (props: any) => { : undefined, consultation_notes: state.form.consultation_notes, is_telemedicine: state.form.is_telemedicine, - icu_admission_date: state.form.icu_admission_date, + icu_admission_date: + state.form.route_to_facility === 30 + ? state.form.icu_admission_date + : undefined, action: state.form.action, review_interval: state.form.review_interval, assigned_to: @@ -1195,9 +1198,7 @@ export const ConsultationForm = (props: any) => {
@@ -1218,29 +1219,28 @@ export const ConsultationForm = (props: any) => {
)} - {state.form.route_to_facility && - [20, 30].includes(state.form.route_to_facility) && ( -
- -
- )} + {state.form.route_to_facility === 30 && ( +
+ +
+ )} {["A", "DC"].includes(state.form.suggestion) && !isUpdate && (
From 466d4ed196131d814677a444386459638cd4bc2e Mon Sep 17 00:00:00 2001 From: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> Date: Mon, 27 Nov 2023 20:22:22 +0530 Subject: [PATCH 04/27] test for search facility (#6733) --- cypress/e2e/facility_spec/facility_homepage.cy.ts | 14 +++++++++++++- cypress/pageobject/Facility/FacilityHome.ts | 9 +++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/cypress/e2e/facility_spec/facility_homepage.cy.ts b/cypress/e2e/facility_spec/facility_homepage.cy.ts index 6f53f554835..bf6ce12536e 100644 --- a/cypress/e2e/facility_spec/facility_homepage.cy.ts +++ b/cypress/e2e/facility_spec/facility_homepage.cy.ts @@ -2,14 +2,19 @@ import { cy, describe, before, beforeEach, it, afterEach } from "local-cypress"; import LoginPage from "../../pageobject/Login/LoginPage"; import FacilityHome from "../../pageobject/Facility/FacilityHome"; +import ManageUserPage from "../../pageobject/Users/ManageUserPage"; +import FacilityPage from "../../pageobject/Facility/FacilityCreation"; describe("Facility Creation", () => { const loginPage = new LoginPage(); const facilityHome = new FacilityHome(); + const facilityPage = new FacilityPage(); + const manageUserPage = new ManageUserPage(); const facilitiesAlias = "downloadFacilitiesCSV"; const capacitiesAlias = "downloadCapacitiesCSV"; const doctorsAlias = "downloadDoctorsCSV"; const triagesAlias = "downloadTriagesCSV"; + const facilityname = "Dummy Facility 1"; before(() => { loginPage.loginAsDisctrictAdmin(); @@ -17,11 +22,17 @@ describe("Facility Creation", () => { }); beforeEach(() => { - cy.viewport(1280, 720); cy.restoreLocalStorage(); cy.awaitUrl("/facility"); }); + it("Search a facility in homepage", () => { + manageUserPage.typeFacilitySearch(facilityname); + facilityPage.verifyFacilityBadgeContent(facilityname); + manageUserPage.assertFacilityInCard(facilityname); + facilityHome.verifyURLContains(facilityname); + }); + it("Verify Facility Export Functionality", () => { // Download the Facilities CSV facilityHome.csvDownloadIntercept(facilitiesAlias, ""); @@ -48,6 +59,7 @@ describe("Facility Creation", () => { facilityHome.verifyDownload(triagesAlias); facilityHome.clickSearchButton(); }); + afterEach(() => { cy.saveLocalStorage(); }); diff --git a/cypress/pageobject/Facility/FacilityHome.ts b/cypress/pageobject/Facility/FacilityHome.ts index faf6747e024..04dfe94d002 100644 --- a/cypress/pageobject/Facility/FacilityHome.ts +++ b/cypress/pageobject/Facility/FacilityHome.ts @@ -26,6 +26,15 @@ class FacilityHome { verifyDownload(alias: string) { cy.wait(`@${alias}`).its("response.statusCode").should("eq", 200); } + + getURL() { + return cy.url(); + } + + verifyURLContains(searchText) { + const encodedText = encodeURIComponent(searchText).replace(/%20/g, "+"); + this.getURL().should("include", `search=${encodedText}`); + } } export default FacilityHome; From 5cde45749e73ef99bd0554a2ebd925c3e4484ea1 Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Tue, 28 Nov 2023 15:34:20 +0530 Subject: [PATCH 05/27] Allow route to facility to be edited if null (#6742) --- src/Components/Facility/ConsultationForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Facility/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx index ed3934441a8..486adfa5170 100644 --- a/src/Components/Facility/ConsultationForm.tsx +++ b/src/Components/Facility/ConsultationForm.tsx @@ -946,7 +946,7 @@ export const ConsultationForm = (props: any) => { required label="Route to Facility" {...field("route_to_facility")} - disabled={isUpdate} + disabled={isUpdate && !!state.form.route_to_facility} // For backwards compatibility; Allow in edit form only if route_to_facility is not set previously />
From 4da37ba8437bf5483c3fae365e6f356f299568de Mon Sep 17 00:00:00 2001 From: Gampa Sri Harsh <114745442+sriharsh05@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:21:45 +0530 Subject: [PATCH 06/27] replace useDispatch with useQuery and request in FacilityCard, FacililyHome and FacilityUsers (#6575) * replace useDispatch with useQuery and request in facilityCard, facilityHome and facilityUsers * remove delete model and let useQuery handel delete response * remove unused useStates variables in FacilityUsers * replace useState variables with useQuery variables and also replaced useEffect with useQuery * handle loading states * Implemented a dedicated component for the triage table in FacilityHome * Implemented a dedicated component for the doctor list in FacilityHome * implemeted a dedicated component for bed capacity in facility home * remove trailing slash * Removed unused fire requests * Fix deleting bed and doctor capacity bug and remove redundant code * fix doctor capacity total count bug --------- Co-authored-by: Rithvik Nishad --- .../Facility/FacilityBedCapacity.tsx | 119 +++++ src/Components/Facility/FacilityCard.tsx | 21 +- .../Facility/FacilityDoctorList.tsx | 121 +++++ src/Components/Facility/FacilityHome.tsx | 460 +++--------------- .../Facility/FacilityHomeTriage.tsx | 88 ++++ src/Components/Facility/FacilityUsers.tsx | 205 ++++---- src/Components/Facility/models.tsx | 13 + src/Redux/actions.tsx | 7 - src/Redux/api.tsx | 23 +- 9 files changed, 529 insertions(+), 528 deletions(-) create mode 100644 src/Components/Facility/FacilityBedCapacity.tsx create mode 100644 src/Components/Facility/FacilityDoctorList.tsx create mode 100644 src/Components/Facility/FacilityHomeTriage.tsx diff --git a/src/Components/Facility/FacilityBedCapacity.tsx b/src/Components/Facility/FacilityBedCapacity.tsx new file mode 100644 index 00000000000..33583840643 --- /dev/null +++ b/src/Components/Facility/FacilityBedCapacity.tsx @@ -0,0 +1,119 @@ +import { useState } from "react"; +import { getBedTypes } from "../../Common/constants"; +import routes from "../../Redux/api"; +import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor"; +import useQuery from "../../Utils/request/useQuery"; +import DialogModal from "../Common/Dialog"; +import ButtonV2 from "../Common/components/ButtonV2"; +import { BedCapacity } from "./BedCapacity"; +import BedTypeCard from "./BedTypeCard"; +import useConfig from "../../Common/hooks/useConfig"; + +export const FacilityBedCapacity = (props: any) => { + const [bedCapacityModalOpen, setBedCapacityModalOpen] = useState(false); + const config = useConfig(); + + const capacityQuery = useQuery(routes.getCapacity, { + pathParams: { facilityId: props.facilityId }, + }); + + let capacityList: any = null; + if (!capacityQuery.data || !capacityQuery.data.results.length) { + capacityList = ( +
+ No Bed Types Found +
+ ); + } else { + const totalBedCount = capacityQuery.data.results.reduce( + (acc, x) => acc + (x.total_capacity ? x.total_capacity : 0), + 0 + ); + const totalOccupiedBedCount = capacityQuery.data.results.reduce( + (acc, x) => acc + (x.current_capacity ? x.current_capacity : 0), + 0 + ); + + capacityList = ( +
+ { + return; + }} + /> + {getBedTypes(config).map((x) => { + const res = capacityQuery.data?.results.find((data) => { + return data.room_type === x.id; + }); + if ( + res && + res.current_capacity !== undefined && + res.total_capacity !== undefined + ) { + const removeCurrentBedType = (bedTypeId: number | undefined) => { + if (capacityQuery.data !== undefined) { + capacityQuery.data.results.filter((i) => i.id !== bedTypeId); + capacityQuery.refetch(); + } + }; + return ( + { + capacityQuery.refetch(); + }} + /> + ); + } + })} +
+ ); + } + + return ( +
+
+
+
Bed Capacity
+ setBedCapacityModalOpen(true)} + authorizeFor={NonReadOnlyUsers} + > + + Add More Bed Types + +
+
{capacityList}
+
+ + {bedCapacityModalOpen && ( + setBedCapacityModalOpen(false)} + title="Add Bed Capacity" + className="max-w-md md:min-w-[600px]" + > + setBedCapacityModalOpen(false)} + handleUpdate={async () => { + capacityQuery.refetch(); + }} + /> + + )} +
+ ); +}; diff --git a/src/Components/Facility/FacilityCard.tsx b/src/Components/Facility/FacilityCard.tsx index e8e0dbef70f..900b6b00f47 100644 --- a/src/Components/Facility/FacilityCard.tsx +++ b/src/Components/Facility/FacilityCard.tsx @@ -1,9 +1,6 @@ import { useState } from "react"; -import { useDispatch } from "react-redux"; import { Link } from "raviger"; import { useTranslation } from "react-i18next"; - -import { sendNotificationMessages } from "../../Redux/actions"; import { FACILITY_FEATURE_TYPES } from "../../Common/constants"; import ButtonV2, { Cancel, Submit } from "../Common/components/ButtonV2"; import * as Notification from "../../Utils/Notifications.js"; @@ -14,26 +11,28 @@ import DialogModal from "../Common/Dialog"; import TextAreaFormField from "../Form/FormFields/TextAreaFormField"; import useConfig from "../../Common/hooks/useConfig"; import { classNames } from "../../Utils/utils"; +import request from "../../Utils/request/request"; +import routes from "../../Redux/api"; export const FacilityCard = (props: { facility: any; userType: any }) => { const { facility, userType } = props; const { kasp_string } = useConfig(); const { t } = useTranslation(); - const dispatchAction: any = useDispatch(); const [notifyModalFor, setNotifyModalFor] = useState(undefined); const [notifyMessage, setNotifyMessage] = useState(""); const [notifyError, setNotifyError] = useState(""); const handleNotifySubmit = async (id: any) => { - const data = { - facility: id, - message: notifyMessage, - }; - if (data.message.trim().length >= 1) { + if (notifyMessage.trim().length >= 1) { setNotifyError(""); - const res = await dispatchAction(sendNotificationMessages(data)); - if (res && res.status == 204) { + const { res } = await request(routes.sendNotificationMessages, { + body: { + facility: id, + message: notifyMessage, + }, + }); + if (res?.ok) { Notification.Success({ msg: "Facility Notified", }); diff --git a/src/Components/Facility/FacilityDoctorList.tsx b/src/Components/Facility/FacilityDoctorList.tsx new file mode 100644 index 00000000000..e6bbc7f7f3b --- /dev/null +++ b/src/Components/Facility/FacilityDoctorList.tsx @@ -0,0 +1,121 @@ +import { useState } from "react"; +import { DOCTOR_SPECIALIZATION } from "../../Common/constants"; +import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor"; +import ButtonV2 from "../Common/components/ButtonV2"; +import DialogModal from "../Common/Dialog"; +import { DoctorCapacity } from "./DoctorCapacity"; +import useQuery from "../../Utils/request/useQuery"; +import routes from "../../Redux/api"; +import { DoctorModal } from "./models"; +import DoctorsCountCard from "./DoctorsCountCard"; +import { DoctorIcon } from "../TeleIcu/Icons/DoctorIcon"; + +export const FacilityDoctorList = (props: any) => { + const [doctorCapacityModalOpen, setDoctorCapacityModalOpen] = useState(false); + const [totalDoctors, setTotalDoctors] = useState(0); + + const doctorQuery = useQuery(routes.listDoctor, { + pathParams: { facilityId: props.facilityId }, + onResponse: ({ res, data }) => { + if (res?.ok && data) { + let totalCount = 0; + data.results.map((doctor: DoctorModal) => { + if (doctor.count) { + totalCount += doctor.count; + } + }); + setTotalDoctors(totalCount); + } + }, + }); + + let doctorList: any = null; + if (!doctorQuery.data || !doctorQuery.data.results.length) { + doctorList = ( +
+ No Doctors Found +
+ ); + } else { + doctorList = ( +
+ {/* Total Doctors Count Card */} +
+
+
+
+ +
+
+
+ Total Doctors +
+

{totalDoctors}

+
+
+
+
+ + {doctorQuery.data.results.map((data: DoctorModal) => { + const removeCurrentDoctorData = (doctorId: number | undefined) => { + if (doctorQuery.data !== undefined) { + doctorQuery.data?.results.filter( + (i: DoctorModal) => i.id !== doctorId + ); + doctorQuery.refetch(); + } + }; + + return ( + { + doctorQuery.refetch(); + }} + {...data} + removeDoctor={removeCurrentDoctorData} + /> + ); + })} +
+ ); + } + + return ( +
+
+
+
Doctors List
+ setDoctorCapacityModalOpen(true)} + disabled={doctorList.length === DOCTOR_SPECIALIZATION.length} + authorizeFor={NonReadOnlyUsers} + > + + Add Doctor Types + +
+
{doctorList}
+
+ + {doctorCapacityModalOpen && ( + setDoctorCapacityModalOpen(false)} + title="Add Doctor Capacity" + className="max-w-md md:min-w-[600px]" + > + setDoctorCapacityModalOpen(false)} + handleUpdate={async () => { + doctorQuery.refetch(); + }} + /> + + )} +
+ ); +}; diff --git a/src/Components/Facility/FacilityHome.tsx b/src/Components/Facility/FacilityHome.tsx index f14057d4a91..e971f0f3b9d 100644 --- a/src/Components/Facility/FacilityHome.tsx +++ b/src/Components/Facility/FacilityHome.tsx @@ -1,50 +1,32 @@ import * as Notification from "../../Utils/Notifications.js"; import AuthorizeFor, { NonReadOnlyUsers } from "../../Utils/AuthorizeFor"; -import { - CapacityModal, - DoctorModal, - FacilityModel, - PatientStatsModel, -} from "./models"; -import { - DOCTOR_SPECIALIZATION, - FACILITY_FEATURE_TYPES, - USER_TYPES, - getBedTypes, -} from "../../Common/constants"; +import { FacilityModel } from "./models"; +import { FACILITY_FEATURE_TYPES, USER_TYPES } from "../../Common/constants"; import DropdownMenu, { DropdownItem } from "../Common/components/Menu"; -import { - deleteFacility, - getPermittedFacility, - getTriageInfo, - listCapacity, - listDoctor, -} from "../../Redux/actions"; -import { statusType, useAbortableEffect } from "../../Common/utils"; -import { lazy, useCallback, useState } from "react"; -import { useDispatch } from "react-redux"; -import { BedCapacity } from "./BedCapacity"; -import BedTypeCard from "./BedTypeCard"; +import { lazy, useState } from "react"; + import ButtonV2 from "../Common/components/ButtonV2"; import CareIcon from "../../CAREUI/icons/CareIcon"; import Chip from "../../CAREUI/display/Chip"; import ConfirmDialog from "../Common/ConfirmDialog"; import ContactLink from "../Common/components/ContactLink"; import CoverImageEditModal from "./CoverImageEditModal"; -import DialogModal from "../Common/Dialog"; -import { DoctorCapacity } from "./DoctorCapacity"; -import { DoctorIcon } from "../TeleIcu/Icons/DoctorIcon"; -import DoctorsCountCard from "./DoctorsCountCard"; + import Page from "../Common/components/Page"; import RecordMeta from "../../CAREUI/display/RecordMeta"; import Table from "../Common/components/Table"; import { navigate } from "raviger"; -import useConfig from "../../Common/hooks/useConfig"; import { useMessageListener } from "../../Common/hooks/useMessageListener"; import { useTranslation } from "react-i18next"; import useAuthUser from "../../Common/hooks/useAuthUser.js"; +import request from "../../Utils/request/request.js"; +import routes from "../../Redux/api.js"; +import useQuery from "../../Utils/request/useQuery.js"; +import { FacilityHomeTriage } from "./FacilityHomeTriage.js"; +import { FacilityDoctorList } from "./FacilityDoctorList.js"; +import { FacilityBedCapacity } from "./FacilityBedCapacity.js"; const Loading = lazy(() => import("../Common/Loading")); @@ -61,80 +43,25 @@ export const getFacilityFeatureIcon = (featureId: number) => { export const FacilityHome = (props: any) => { const { t } = useTranslation(); const { facilityId } = props; - const dispatch: any = useDispatch(); - const [facilityData, setFacilityData] = useState({}); - const [capacityData, setCapacityData] = useState>([]); - const [doctorData, setDoctorData] = useState>([]); - const [isLoading, setIsLoading] = useState(false); const [openDeleteDialog, setOpenDeleteDialog] = useState(false); const [editCoverImage, setEditCoverImage] = useState(false); const [imageKey, setImageKey] = useState(Date.now()); - const [totalDoctors, setTotalDoctors] = useState(0); - const [patientStatsData, setPatientStatsData] = useState< - Array - >([]); - const [bedCapacityModalOpen, setBedCapacityModalOpen] = useState(false); - const [doctorCapacityModalOpen, setDoctorCapacityModalOpen] = useState(false); const authUser = useAuthUser(); - const config = useConfig(); useMessageListener((data) => console.log(data)); - const fetchData = useCallback( - async (status: statusType) => { - setIsLoading(true); - const facilityRes = await dispatch(getPermittedFacility(facilityId)); - if (facilityRes) { - const [capacityRes, doctorRes, triageRes] = await Promise.all([ - dispatch(listCapacity({}, { facilityId })), - dispatch(listDoctor({}, { facilityId })), - dispatch(getTriageInfo({ facilityId })), - ]); - if (!status.aborted) { - setIsLoading(false); - if (!facilityRes.data) { - Notification.Error({ - msg: "Something went wrong..!", - }); - } else { - setFacilityData(facilityRes.data); - if (capacityRes && capacityRes.data) { - setCapacityData(capacityRes.data.results); - } - if (doctorRes && doctorRes.data) { - setDoctorData(doctorRes.data.results); - // calculating total doctors count - let totalCount = 0; - doctorRes.data.results.map((doctor: DoctorModal) => { - if (doctor.count) { - totalCount += doctor.count; - } - }); - setTotalDoctors(totalCount); - } - if ( - triageRes && - triageRes.data && - triageRes.data.results && - triageRes.data.results.length - ) { - setPatientStatsData(triageRes.data.results); - } - } + const { data: facilityData, loading: isLoading } = useQuery( + routes.getPermittedFacility, + { + pathParams: { + id: facilityId, + }, + onResponse: ({ res }) => { + if (!res?.ok) { + navigate("/not-found"); } - } else { - navigate("/not-found"); - setIsLoading(false); - } - }, - [dispatch, facilityId] - ); - - useAbortableEffect( - (status: statusType) => { - fetchData(status); - }, - [dispatch, fetchData] + }, + } ); const handleDeleteClose = () => { @@ -142,179 +69,24 @@ export const FacilityHome = (props: any) => { }; const handleDeleteSubmit = async () => { - const res = await dispatch(deleteFacility(facilityId)); - if (res?.status === 204) { - Notification.Success({ - msg: "Facility deleted successfully", - }); - } else { - Notification.Error({ - msg: "Error while deleting Facility: " + (res?.data?.detail || ""), - }); - } - navigate("/facility"); + await request(routes.deleteFacility, { + pathParams: { id: facilityId }, + onResponse: ({ res }) => { + if (res?.ok) { + Notification.Success({ + msg: "Facility deleted successfully", + }); + } + navigate("/facility"); + }, + }); }; if (isLoading) { return ; } - let capacityList: any = null; - let totalBedCount = 0; - let totalOccupiedBedCount = 0; - if (!capacityData || !capacityData.length) { - capacityList = ( -
- No Bed Types Found -
- ); - } else { - capacityData.forEach((x) => { - totalBedCount += x.total_capacity ? x.total_capacity : 0; - totalOccupiedBedCount += x.current_capacity ? x.current_capacity : 0; - }); - capacityList = ( -
- { - return; - }} - /> - {getBedTypes(config).map((x) => { - const res = capacityData.find((data) => { - return data.room_type === x.id; - }); - if ( - res && - res.current_capacity !== undefined && - res.total_capacity !== undefined - ) { - const removeCurrentBedType = (bedTypeId: number | undefined) => { - setCapacityData((state) => - state.filter((i) => i.id !== bedTypeId) - ); - }; - return ( - { - const capacityRes = await dispatch( - listCapacity({}, { facilityId }) - ); - if (capacityRes && capacityRes.data) { - setCapacityData(capacityRes.data.results); - } - }} - /> - ); - } - })} -
- ); - } - - let doctorList: any = null; - if (!doctorData || !doctorData.length) { - doctorList = ( -
- No Doctors Found -
- ); - } else { - doctorList = ( -
- {/* Total Doctors Count Card */} -
-
-
-
- -
-
-
- Total Doctors -
-

{totalDoctors}

-
-
-
-
- - {doctorData.map((data: DoctorModal) => { - const removeCurrentDoctorData = (doctorId: number | undefined) => { - setDoctorData((state) => - state.filter((i: DoctorModal) => i.id !== doctorId) - ); - }; - - return ( - { - const doctorRes = await dispatch( - listDoctor({}, { facilityId }) - ); - if (doctorRes && doctorRes.data) { - setDoctorData(doctorRes.data.results); - // update total doctors count - let totalCount = 0; - doctorRes.data.results.map((doctor: DoctorModal) => { - if (doctor.count) { - totalCount += doctor.count; - } - }); - setTotalDoctors(totalCount); - } - }} - {...data} - removeDoctor={removeCurrentDoctorData} - /> - ); - })} -
- ); - } - - const stats: (string | JSX.Element)[][] = []; - for (let i = 0; i < patientStatsData.length; i++) { - const temp: (string | JSX.Element)[] = []; - temp.push(String(patientStatsData[i].entry_date) || "0"); - temp.push(String(patientStatsData[i].num_patients_visited) || "0"); - temp.push(String(patientStatsData[i].num_patients_home_quarantine) || "0"); - temp.push(String(patientStatsData[i].num_patients_isolation) || "0"); - temp.push(String(patientStatsData[i].num_patient_referred) || "0"); - temp.push( - String(patientStatsData[i].num_patient_confirmed_positive) || "0" - ); - temp.push( - - navigate(`/facility/${facilityId}/triage/${patientStatsData[i].id}`) - } - authorizeFor={NonReadOnlyUsers} - > - Edit - - ); - stats.push(temp); - } - - const hasCoverImage = !!facilityData.read_cover_image_url; + const hasCoverImage = !!facilityData?.read_cover_image_url; const StaffUserTypeIndex = USER_TYPES.findIndex((type) => type === "Staff"); const hasPermissionToEditCoverImage = @@ -331,24 +103,25 @@ export const FacilityHome = (props: any) => { const CoverImage = () => ( {facilityData.name} ); return ( - Are you sure you want to delete {facilityData.name} + Are you sure you want to delete{" "} + {facilityData?.name} } action="Delete" @@ -360,13 +133,13 @@ export const FacilityHome = (props: any) => { - facilityData.read_cover_image_url + facilityData?.read_cover_image_url ? setImageKey(Date.now()) : window.location.reload() } onClose={() => setEditCoverImage(false)} onDelete={() => window.location.reload()} - facility={facilityData} + facility={facilityData ?? ({} as FacilityModel)} /> {hasCoverImage ? (
{ {editCoverImageTooltip}
-

{facilityData.name}

+

{facilityData?.name}

{facilityData?.modified_date && ( { Address

- {facilityData.address} + {facilityData?.address}

@@ -453,7 +226,7 @@ export const FacilityHome = (props: any) => {

Phone Number

- +
@@ -492,13 +265,13 @@ export const FacilityHome = (props: any) => {
- {facilityData.features?.some((feature: any) => + {facilityData?.features?.some((feature: any) => FACILITY_FEATURE_TYPES.some((f) => f.id === feature) ) && (

Available features

)}
- {facilityData.features?.map( + {facilityData?.features?.map( (feature: number, i: number) => FACILITY_FEATURE_TYPES.some((f) => f.id === feature) && ( { rows={[ [ "Capacity", - String(facilityData.oxygen_capacity), - String(facilityData.type_b_cylinders), - String(facilityData.type_c_cylinders), - String(facilityData.type_d_cylinders), + String(facilityData?.oxygen_capacity), + String(facilityData?.type_b_cylinders), + String(facilityData?.type_c_cylinders), + String(facilityData?.type_d_cylinders), ], [ "Daily Expected Consumption", - String(facilityData.expected_oxygen_requirement), - String(facilityData.expected_type_b_cylinders), - String(facilityData.expected_type_c_cylinders), - String(facilityData.expected_type_d_cylinders), + String(facilityData?.expected_oxygen_requirement), + String(facilityData?.expected_type_b_cylinders), + String(facilityData?.expected_type_c_cylinders), + String(facilityData?.expected_type_d_cylinders), ], ]} />
-
-
-
Bed Capacity
- setBedCapacityModalOpen(true)} - authorizeFor={NonReadOnlyUsers} - > - - Add More Bed Types - -
-
{capacityList}
-
-
-
-
Doctors List
- setDoctorCapacityModalOpen(true)} - disabled={doctorList.length === DOCTOR_SPECIALIZATION.length} - authorizeFor={NonReadOnlyUsers} - > - - Add Doctor Types - -
-
{doctorList}
-
-
-
-
-
Corona Triage
- navigate(`/facility/${facilityId}/triage`)} - authorizeFor={NonReadOnlyUsers} - > - - Add Triage - -
-
- - {stats.length === 0 && ( - <> -
-
- No Data Found -
- - )} - - - - {bedCapacityModalOpen && ( - setBedCapacityModalOpen(false)} - title="Add Bed Capacity" - className="max-w-md md:min-w-[600px]" - > - setBedCapacityModalOpen(false)} - handleUpdate={async () => { - const capacityRes = await dispatch( - listCapacity({}, { facilityId }) - ); - if (capacityRes && capacityRes.data) { - setCapacityData(capacityRes.data.results); - } - }} - /> - - )} - {doctorCapacityModalOpen && ( - setDoctorCapacityModalOpen(false)} - title="Add Doctor Capacity" - className="max-w-md md:min-w-[600px]" - > - setDoctorCapacityModalOpen(false)} - handleUpdate={async () => { - const doctorRes = await dispatch(listDoctor({}, { facilityId })); - if (doctorRes && doctorRes.data) { - setDoctorData(doctorRes.data.results); - // update total doctors count - setTotalDoctors( - doctorRes.data.results.reduce( - (acc: number, doctor: DoctorModal) => - acc + (doctor.count || 0), - 0 - ) - ); - } - }} - /> - - )} + + + + ); }; diff --git a/src/Components/Facility/FacilityHomeTriage.tsx b/src/Components/Facility/FacilityHomeTriage.tsx new file mode 100644 index 00000000000..f96a5181cfc --- /dev/null +++ b/src/Components/Facility/FacilityHomeTriage.tsx @@ -0,0 +1,88 @@ +import { navigate } from "raviger"; +import ButtonV2 from "../Common/components/ButtonV2"; +import Table from "../Common/components/Table"; +import useQuery from "../../Utils/request/useQuery"; +import routes from "../../Redux/api"; + +export const FacilityHomeTriage = (props: any) => { + const triageQuery = useQuery(routes.getTriage, { + pathParams: { facilityId: props.facilityId }, + }); + + const stats: (string | JSX.Element)[][] = []; + for ( + let i = 0; + triageQuery.data?.results && i < triageQuery.data.results.length; + i++ + ) { + const temp: (string | JSX.Element)[] = []; + temp.push(String(triageQuery.data.results[i].entry_date) || "0"); + temp.push(String(triageQuery.data.results[i].num_patients_visited) || "0"); + temp.push( + String(triageQuery.data.results[i].num_patients_home_quarantine) || "0" + ); + temp.push( + String(triageQuery.data.results[i].num_patients_isolation) || "0" + ); + temp.push(String(triageQuery.data.results[i].num_patient_referred) || "0"); + temp.push( + String(triageQuery.data.results[i].num_patient_confirmed_positive) || "0" + ); + temp.push( + + navigate( + `/facility/${props.facilityId}/triage/${triageQuery.data?.results[i].id}` + ) + } + authorizeFor={props.NonReadOnlyUsers} + > + Edit + + ); + stats.push(temp); + } + + return ( +
+
+
+
Corona Triage
+ navigate(`/facility/${props.facilityId}/triage`)} + authorizeFor={props.NonReadOnlyUsers} + > + + Add Triage + +
+
+
+ {stats.length === 0 && ( + <> +
+
+ No Data Found +
+ + )} + + + + ); +}; diff --git a/src/Components/Facility/FacilityUsers.tsx b/src/Components/Facility/FacilityUsers.tsx index 6963c4006db..aba12cc3833 100644 --- a/src/Components/Facility/FacilityUsers.tsx +++ b/src/Components/Facility/FacilityUsers.tsx @@ -1,18 +1,7 @@ -import { lazy, useCallback, useEffect, useState } from "react"; -import { useDispatch } from "react-redux"; +import { lazy, useState } from "react"; import CountBlock from "../../CAREUI/display/Count"; import CareIcon from "../../CAREUI/icons/CareIcon"; import { RESULTS_PER_PAGE_LIMIT } from "../../Common/constants"; -import useAuthUser from "../../Common/hooks/useAuthUser"; -import { statusType, useAbortableEffect } from "../../Common/utils"; -import { - addUserFacility, - deleteUser, - deleteUserFacility, - getAnyFacility, - getFacilityUsers, - getUserListFacility, -} from "../../Redux/actions"; import * as Notification from "../../Utils/Notifications.js"; import { classNames, isUserOnline, relativeTime } from "../../Utils/utils"; import Pagination from "../Common/Pagination"; @@ -23,25 +12,22 @@ import { FacilityModel } from "../Facility/models"; import LinkFacilityDialog from "../Users/LinkFacilityDialog"; import UnlinkFacilityDialog from "../Users/UnlinkFacilityDialog"; import UserDeleteDialog from "../Users/UserDeleteDialog"; +import useAuthUser from "../../Common/hooks/useAuthUser"; +import request from "../../Utils/request/request"; +import routes from "../../Redux/api"; +import useQuery from "../../Utils/request/useQuery"; const Loading = lazy(() => import("../Common/Loading")); export default function FacilityUsers(props: any) { const { facilityId } = props; - const dispatch: any = useDispatch(); - const initialData: any[] = []; let manageUsers: any = null; - const [users, setUsers] = useState(initialData); - const [isLoading, setIsLoading] = useState(false); - const [isFacilityLoading, setIsFacilityLoading] = useState(false); - const [totalCount, setTotalCount] = useState(0); + const [isUnlinkFacilityLoading, setIsUnlinkFacilityLoading] = useState(false); + const [isAddFacilityLoading, setIsAddFacilityLoading] = useState(false); + const [isLoadFacilityLoading, setIsLoadFacilityLoading] = useState(false); const [currentPage, setCurrentPage] = useState(1); // eslint-disable-next-line @typescript-eslint/no-unused-vars const [offset, setOffset] = useState(0); - const [facilityData, setFacilityData] = useState({ - name: "", - district_object_id: 0, - }); const authUser = useAuthUser(); const [linkFacility, setLinkFacility] = useState<{ @@ -63,48 +49,22 @@ export default function FacilityUsers(props: any) { const limit = RESULTS_PER_PAGE_LIMIT; - useEffect(() => { - async function fetchFacilityName() { - if (facilityId) { - const res = await dispatch(getAnyFacility(facilityId)); - setFacilityData({ - name: res?.data?.name || "", - district_object_id: res?.data?.district_object?.id || 0, - }); - } else { - setFacilityData({ - name: "", - district_object_id: 0, - }); - } - } - fetchFacilityName(); - }, [dispatch, facilityId]); - - const fetchData = useCallback( - async (status: statusType) => { - setIsLoading(true); - const res = await dispatch( - getFacilityUsers(facilityId, { offset, limit }) - ); - - if (!status.aborted) { - if (res && res.data) { - setUsers(res.data.results); - setTotalCount(res.data.count); - } - setIsLoading(false); - } + const { data: facilityData } = useQuery(routes.getAnyFacility, { + pathParams: { + id: facilityId, }, - [dispatch, facilityId, offset, limit] - ); + prefetch: facilityId !== undefined, + }); - useAbortableEffect( - (status: statusType) => { - fetchData(status); - }, - [fetchData] - ); + const { + data: facilityUserData, + refetch: facilityUserFetch, + loading: isLoading, + } = useQuery(routes.getFacilityUsers, { + query: { offset: offset, limit: limit }, + pathParams: { facility_id: facilityId }, + prefetch: facilityId !== undefined, + }); const handlePagination = (page: number, limit: number) => { const offset = (page - 1) * limit; @@ -113,23 +73,24 @@ export default function FacilityUsers(props: any) { }; const loadFacilities = async (username: string) => { - if (isFacilityLoading) { + if (isUnlinkFacilityLoading || isAddFacilityLoading) { return; } - setIsFacilityLoading(true); - const res = await dispatch(getUserListFacility({ username })); - if (res && res.data) { - const updated = users.map((user) => { + setIsLoadFacilityLoading(true); + const { res, data } = await request(routes.userListFacility, { + pathParams: { username: username }, + }); + if (res?.ok && data && facilityUserData) { + facilityUserData.results = facilityUserData.results.map((user) => { return user.username === username ? { ...user, - facilities: res.data, + facilities: data, } : user; }); - setUsers(updated); } - setIsFacilityLoading(false); + setIsLoadFacilityLoading(false); }; const showLinkFacilityModal = (username: string) => { @@ -155,14 +116,22 @@ export default function FacilityUsers(props: any) { }; const handleUnlinkFacilitySubmit = async () => { - setIsFacilityLoading(true); - await dispatch( - deleteUserFacility( - unlinkFacilityData.userName, - String(unlinkFacilityData?.facility?.id) - ) - ); - setIsFacilityLoading(false); + setIsUnlinkFacilityLoading(true); + await request(routes.deleteUserFacility, { + // body given in the dispatch call but there is no body in API documentation + body: { facility: String(unlinkFacilityData?.facility?.id) }, + pathParams: { + username: unlinkFacilityData.userName, + }, + onResponse: ({ res }) => { + if (res?.status === 204) { + Notification.Success({ + msg: "User Facility deleted successfully", + }); + } + }, + }); + setIsUnlinkFacilityLoading(false); loadFacilities(unlinkFacilityData.userName); hideUnlinkFacilityModal(); }; @@ -173,19 +142,18 @@ export default function FacilityUsers(props: any) { const handleSubmit = async () => { const username = userData.username; - const res = await dispatch(deleteUser(username)); - if (res?.status === 204) { - Notification.Success({ - msg: "User deleted successfully", - }); - } else { - Notification.Error({ - msg: "Error while deleting User: " + (res?.data?.detail || ""), - }); - } - + await request(routes.deleteUser, { + pathParams: { username: username }, + onResponse: ({ res }) => { + if (res?.status === 204) { + Notification.Success({ + msg: "User deleted successfully", + }); + } + }, + }); setUserData({ show: false, username: "", name: "" }); - fetchData({ aborted: false }); + facilityUserFetch(); }; const handleDelete = (user: any) => { @@ -198,7 +166,9 @@ export default function FacilityUsers(props: any) { const facilityClassname = classNames( "align-baseline text-sm font-bold", - isFacilityLoading ? "text-gray-500" : "text-blue-500 hover:text-blue-800" + isAddFacilityLoading || isUnlinkFacilityLoading || isLoadFacilityLoading + ? "text-gray-500" + : "text-blue-500 hover:text-blue-800" ); const showLinkFacility = (username: string) => { @@ -236,7 +206,7 @@ export default function FacilityUsers(props: any) { size="small" circle variant="secondary" - disabled={isFacilityLoading} + disabled={isUnlinkFacilityLoading} onClick={() => setUnlinkFacilityData({ show: true, @@ -267,17 +237,26 @@ export default function FacilityUsers(props: any) { const addFacility = async (username: string, facility: any) => { hideLinkFacilityModal(); - setIsFacilityLoading(true); - await dispatch(addUserFacility(username, String(facility.id))); - setIsFacilityLoading(false); + setIsAddFacilityLoading(true); + // Remaining props of request are not specified in dispatch request + await request(routes.addUserFacility, { + body: { + facility: String(facility.id), + }, + pathParams: { + username: username, + }, + }); + setIsAddFacilityLoading(false); loadFacilities(username); }; let userList: any[] = []; - users && - users.length && - (userList = users.map((user: any) => { + facilityUserData && + facilityUserData.results && + facilityUserData.results.length && + (userList = facilityUserData.results.map((user: any) => { return (
; - } else if (users && users.length) { + } else if (facilityUserData.results && facilityUserData.results.length) { manageUsers = (
{userList}
- {totalCount > limit && ( + {facilityUserData && facilityUserData.count > limit && (
)}
); - } else if (users && users.length === 0) { + } else if ( + facilityUserData.results && + facilityUserData.results.length === 0 + ) { manageUsers = (
@@ -443,15 +425,16 @@ export default function FacilityUsers(props: any) { )}
- + {facilityUserData && ( + + )}
-
{manageUsers}
diff --git a/src/Components/Facility/models.tsx b/src/Components/Facility/models.tsx index 8dcc5f71e0d..cdc7074c145 100644 --- a/src/Components/Facility/models.tsx +++ b/src/Components/Facility/models.tsx @@ -488,3 +488,16 @@ export interface PatientNotesModel { user_type?: string; created_date: string; } + +export type IFacilityNotificationRequest = { + facility: string; + message: string; +}; + +export type IFacilityNotificationResponse = { + [key: string]: string; +}; + +export type IUserFacilityRequest = { + facility: string; +}; diff --git a/src/Redux/actions.tsx b/src/Redux/actions.tsx index a120c384a3d..e380949887b 100644 --- a/src/Redux/actions.tsx +++ b/src/Redux/actions.tsx @@ -56,9 +56,6 @@ export const updateFacility = (id: string, params: object) => { export const partialUpdateFacility = (id: string, params: object) => { return fireRequest("partialUpdateFacility", [id], params); }; -export const deleteFacility = (id: string) => { - return fireRequest("deleteFacility", [id], {}); -}; export const deleteFacilityCoverImage = (id: string) => { return fireRequest("deleteFacilityCoverImage", [], {}, { id }); }; @@ -681,10 +678,6 @@ export const getPublicKey = () => { return fireRequest("getPublicKey", [], {}, {}); }; -export const sendNotificationMessages = (params: object) => { - return fireRequest("sendNotificationMessages", [], params, {}); -}; - // FileUpload export const createUpload = (params: object) => { diff --git a/src/Redux/api.tsx b/src/Redux/api.tsx index a69914bddb7..4172effe432 100644 --- a/src/Redux/api.tsx +++ b/src/Redux/api.tsx @@ -29,13 +29,19 @@ import { AssetUpdate, } from "../Components/Assets/AssetTypes"; import { + CapacityModal, ConsultationModel, CreateBedBody, CurrentBed, DailyRoundsBody, DailyRoundsRes, + DoctorModal, FacilityModel, + IFacilityNotificationRequest, + IFacilityNotificationResponse, + IUserFacilityRequest, LocationModel, + PatientStatsModel, WardModel, } from "../Components/Facility/models"; import { @@ -162,11 +168,14 @@ const routes = { userListFacility: { path: "/api/v1/users/{username}/get_facilities/", + TRes: Type(), }, addUserFacility: { path: "/api/v1/users/{username}/add_facility/", method: "PUT", + TBody: Type(), + TRes: Type(), }, addUserSkill: { @@ -177,6 +186,8 @@ const routes = { deleteUserFacility: { path: "/api/v1/users/{username}/delete_facility/", method: "DELETE", + TBody: Type(), + TRes: Type>(), }, clearHomeFacility: { @@ -206,8 +217,9 @@ const routes = { }, deleteUser: { - path: "/api/v1/users", + path: "/api/v1/users/{username}/", method: "DELETE", + TRes: Type>(), }, addUser: { @@ -288,6 +300,7 @@ const routes = { getFacilityUsers: { path: "/api/v1/facility/{facility_id}/get_users/", + TRes: Type>(), }, listFacilityAssetLocation: { @@ -403,8 +416,9 @@ const routes = { // Download Api deleteFacility: { - path: "/api/v1/facility", + path: "/api/v1/facility/{id}/", method: "DELETE", + TRes: Type>(), }, downloadFacility: { @@ -496,6 +510,7 @@ const routes = { getCapacity: { path: "/api/v1/facility/{facilityId}/capacity/", + TRes: Type>(), }, getCapacityBed: { @@ -509,6 +524,7 @@ const routes = { listDoctor: { path: "/api/v1/facility/{facilityId}/hospital_doctor/", + TRes: Type>(), }, getDoctor: { path: "/api/v1/facility/{facilityId}/hospital_doctor/{id}/", @@ -536,6 +552,7 @@ const routes = { }, getTriage: { path: "/api/v1/facility/{facilityId}/patient_stats/", + TRes: Type>(), }, getTriageDetails: { @@ -841,6 +858,8 @@ const routes = { sendNotificationMessages: { path: "/api/v1/notification/notify/", method: "POST", + TRes: Type(), + Tbody: Type(), }, // FileUpload Create From 8d9479b22495ba9e20cd6dc548d177e9a31dc58e Mon Sep 17 00:00:00 2001 From: Gampa Sri Harsh <114745442+sriharsh05@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:22:42 +0530 Subject: [PATCH 07/27] add validation for admission_date in consultation form (#6746) --- src/Components/Facility/ConsultationForm.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Components/Facility/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx index 486adfa5170..1d4abbedc39 100644 --- a/src/Components/Facility/ConsultationForm.tsx +++ b/src/Components/Facility/ConsultationForm.tsx @@ -491,6 +491,10 @@ export const ConsultationForm = (props: any) => { errors[field] = "Field is required"; invalidForm = true; } + if (dayjs(state.form.admission_date).isBefore(dayjs("2000-01-01"))) { + errors[field] = "Admission date cannot be before 01/01/2000"; + invalidForm = true; + } return; case "cause_of_death": if (state.form.suggestion === "DD" && !state.form[field]) { From fc1f1a93c9f4f01666e92111f21571cf7591ad8c Mon Sep 17 00:00:00 2001 From: konavivekramakrishna <101407963+konavivekramakrishna@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:22:53 +0530 Subject: [PATCH 08/27] Remove required attribute from SelectFormField (#6737) --- src/Components/Patient/DailyRounds.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Components/Patient/DailyRounds.tsx b/src/Components/Patient/DailyRounds.tsx index 72075939bd7..ce619370d03 100644 --- a/src/Components/Patient/DailyRounds.tsx +++ b/src/Components/Patient/DailyRounds.tsx @@ -501,7 +501,6 @@ export const DailyRounds = (props: any) => { Date: Wed, 29 Nov 2023 10:23:04 +0530 Subject: [PATCH 09/27] changed bed type text in constants file (#6721) * changed bed type text in constants file * made corresponding change in cypress test --------- Co-authored-by: Rithvik Nishad --- cypress/e2e/facility_spec/facility.cy.ts | 2 +- src/Common/constants.tsx | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cypress/e2e/facility_spec/facility.cy.ts b/cypress/e2e/facility_spec/facility.cy.ts index f2ff847c9d9..5ae5d7cb9db 100644 --- a/cypress/e2e/facility_spec/facility.cy.ts +++ b/cypress/e2e/facility_spec/facility.cy.ts @@ -31,7 +31,7 @@ describe("Facility Creation", () => { facilityPage.fillPhoneNumber("9898469865"); facilityPage.submitForm(); - facilityPage.selectBedType("Non-Covid Oxygen beds"); + facilityPage.selectBedType("Oxygen beds"); facilityPage.fillTotalCapacity("10"); facilityPage.fillCurrentlyOccupied("5"); facilityPage.saveAndExitBedCapacityForm(); diff --git a/src/Common/constants.tsx b/src/Common/constants.tsx index 065e7ccd759..069a39e1539 100644 --- a/src/Common/constants.tsx +++ b/src/Common/constants.tsx @@ -213,10 +213,10 @@ export const getBedTypes = ({ : []; return [ - { id: 1, text: "Non-Covid Ordinary Beds" }, - { id: 150, text: "Non-Covid Oxygen beds" }, - { id: 10, text: "Non-Covid ICU (ICU without ventilator)" }, - { id: 20, text: "Non-Covid Ventilator (ICU with ventilator)" }, + { id: 1, text: "Ordinary Beds" }, + { id: 150, text: "Oxygen beds" }, + { id: 10, text: "ICU (ICU without ventilator)" }, + { id: 20, text: "Ventilator (ICU with ventilator)" }, { id: 30, text: "Covid Ordinary Beds" }, { id: 120, text: "Covid Oxygen beds" }, { id: 110, text: "Covid ICU (ICU without ventilator)" }, From 88fa9a238c2fa57935ef039ecb04fa73717917d4 Mon Sep 17 00:00:00 2001 From: Gokulram A Date: Wed, 29 Nov 2023 10:23:45 +0530 Subject: [PATCH 10/27] Rearranging buttons in the Patient consultation page (#6674) * Rearranging buttons in the Patient consultation * fix discharge patient cypress * Remove unused imports in ConsultationDetails component --- .../pageobject/Patient/PatientConsultation.ts | 3 +- .../Facility/ConsultationDetails/index.tsx | 78 +---------- src/Components/Patient/PatientInfoCard.tsx | 130 +++++++++++++++++- 3 files changed, 131 insertions(+), 80 deletions(-) diff --git a/cypress/pageobject/Patient/PatientConsultation.ts b/cypress/pageobject/Patient/PatientConsultation.ts index 9c588f50c4e..26d75feba2e 100644 --- a/cypress/pageobject/Patient/PatientConsultation.ts +++ b/cypress/pageobject/Patient/PatientConsultation.ts @@ -213,7 +213,8 @@ export class PatientConsultationPage { } clickDischargePatient() { - cy.get("#discharge_patient_from_care").click(); + cy.get("#show-more").click(); + cy.contains("p", "Discharge from CARE").click(); } selectDischargeReason(reason: string) { diff --git a/src/Components/Facility/ConsultationDetails/index.tsx b/src/Components/Facility/ConsultationDetails/index.tsx index 7e7664707eb..534f253a416 100644 --- a/src/Components/Facility/ConsultationDetails/index.tsx +++ b/src/Components/Facility/ConsultationDetails/index.tsx @@ -13,10 +13,6 @@ import { } from "../../../Redux/actions"; import { statusType, useAbortableEffect } from "../../../Common/utils"; import { lazy, useCallback, useState } from "react"; -import ButtonV2 from "../../Common/components/ButtonV2"; -import CareIcon from "../../../CAREUI/icons/CareIcon"; -import DischargeModal from "../DischargeModal"; -import DischargeSummaryModal from "../DischargeSummaryModal"; import DoctorVideoSlideover from "../DoctorVideoSlideover"; import { make as Link } from "../../Common/components/Link.bs"; import PatientInfoCard from "../../Patient/PatientInfoCard"; @@ -25,7 +21,6 @@ import { formatDateTime, relativeTime } from "../../../Utils/utils"; import { navigate, useQueryParams } from "raviger"; import { useDispatch } from "react-redux"; -import { useTranslation } from "react-i18next"; import { triggerGoal } from "../../../Integrations/Plausible"; import useAuthUser from "../../../Common/hooks/useAuthUser"; import { ConsultationUpdatesTab } from "./ConsultationUpdatesTab"; @@ -73,7 +68,6 @@ const TABS = { }; export const ConsultationDetails = (props: any) => { - const { t } = useTranslation(); const { facilityId, patientId, consultationId } = props; const tab = props.tab.toUpperCase() as keyof typeof TABS; const dispatch: any = useDispatch(); @@ -86,9 +80,6 @@ export const ConsultationDetails = (props: any) => { ); const [patientData, setPatientData] = useState({}); const [activeShiftingData, setActiveShiftingData] = useState>([]); - const [openDischargeSummaryDialog, setOpenDischargeSummaryDialog] = - useState(false); - const [openDischargeDialog, setOpenDischargeDialog] = useState(false); const [isCameraAttached, setIsCameraAttached] = useState(false); const getPatientGender = (patientData: any) => @@ -197,19 +188,6 @@ export const ConsultationDetails = (props: any) => { const SelectedTab = TABS[tab]; - const hasActiveShiftingRequest = () => { - if (activeShiftingData.length > 0) { - return [ - "PENDING", - "APPROVED", - "DESTINATION APPROVED", - "PATIENT TO BE PICKED UP", - ].includes(activeShiftingData[activeShiftingData.length - 1].status); - } - - return false; - }; - if (isLoading) { return ; } @@ -272,18 +250,6 @@ export const ConsultationDetails = (props: any) => { return (
- setOpenDischargeSummaryDialog(false)} - /> - - setOpenDischargeDialog(false)} - consultationData={consultationData} - /> -
-
- setOpenDischargeSummaryDialog(true)}> - - {t("discharge_summary")} - - - setOpenDischargeDialog(true)} - disabled={!!consultationData.discharge_date} - > - - {t("discharge_from_care")} - -
diff --git a/src/Components/Patient/PatientInfoCard.tsx b/src/Components/Patient/PatientInfoCard.tsx index f3436fb8acc..bfcc4c23d96 100644 --- a/src/Components/Patient/PatientInfoCard.tsx +++ b/src/Components/Patient/PatientInfoCard.tsx @@ -10,7 +10,7 @@ import { import { ConsultationModel, PatientCategory } from "../Facility/models"; import { Switch, Menu } from "@headlessui/react"; -import { Link } from "raviger"; +import { Link, navigate } from "raviger"; import { useState } from "react"; import CareIcon from "../../CAREUI/icons/CareIcon"; import useConfig from "../../Common/hooks/useConfig"; @@ -29,27 +29,35 @@ import routes from "../../Redux/api.js"; import DropdownMenu from "../Common/components/Menu.js"; import { triggerGoal } from "../../Integrations/Plausible.js"; import useAuthUser from "../../Common/hooks/useAuthUser.js"; +import DischargeSummaryModal from "../Facility/DischargeSummaryModal.js"; +import DischargeModal from "../Facility/DischargeModal.js"; +import { useTranslation } from "react-i18next"; export default function PatientInfoCard(props: { patient: PatientModel; consultation?: ConsultationModel; fetchPatientData?: (state: { aborted: boolean }) => void; + activeShiftingData: any; consultationId: string; showAbhaProfile?: boolean; }) { const authUser = useAuthUser(); - + const { t } = useTranslation(); const [open, setOpen] = useState(false); const [showLinkABHANumber, setShowLinkABHANumber] = useState(false); const [showABHAProfile, setShowABHAProfile] = useState( !!props.showAbhaProfile ); + const [openDischargeSummaryDialog, setOpenDischargeSummaryDialog] = + useState(false); + const [openDischargeDialog, setOpenDischargeDialog] = useState(false); const { enable_hcx, enable_abdm } = useConfig(); const [showLinkCareContext, setShowLinkCareContext] = useState(false); const patient = props.patient; const consultation = props.consultation; + const activeShiftingData = props.activeShiftingData; const [medicoLegalCase, setMedicoLegalCase] = useState( consultation?.medico_legal_case ?? false @@ -86,6 +94,19 @@ export default function PatientInfoCard(props: { } }; + const hasActiveShiftingRequest = () => { + if (activeShiftingData.length > 0) { + return [ + "PENDING", + "APPROVED", + "DESTINATION APPROVED", + "PATIENT TO BE PICKED UP", + ].includes(activeShiftingData[activeShiftingData.length - 1].status); + } + + return false; + }; + return ( <> Invalid Patient Data
)} + + {consultation && ( + <> + setOpenDischargeSummaryDialog(false)} + /> + setOpenDischargeDialog(false)} + consultationData={consultation} + /> + + )} +
{/* Can support for patient picture in the future */} @@ -406,6 +443,7 @@ export default function PatientInfoCard(props: { ) )} } @@ -545,6 +583,94 @@ export default function PatientInfoCard(props: { ))}
+
+ {!consultation?.discharge_date && ( + + {({ close }) => ( + <> + {hasActiveShiftingRequest() ? ( +
{ + close(); + navigate( + `/shifting/${ + activeShiftingData[ + activeShiftingData.length - 1 + ].id + }` + ); + }} + > + + +

Track Shifting

+
+
+ ) : ( +
{ + close(); + navigate( + `/facility/${patient.facility}/patient/${patient.id}/shift/new` + ); + }} + > + + +

Shift Patient

+
+
+ )} + + )} +
+ )} + + {({ close }) => ( +
{ + close(); + setOpenDischargeSummaryDialog(true); + }} + > + + +

{t("discharge_summary")}

+
+
+ )} +
+ + {({ close }) => ( +
{ + if (!consultation?.discharge_date) { + close(); + setOpenDischargeDialog(true); + } + }} + > + + +

{t("discharge_from_care")}

+
+
+ )} +
+
Date: Wed, 29 Nov 2023 10:24:06 +0530 Subject: [PATCH 11/27] Hide KASP Advance Filter (#6687) * Hide KASP Advance Filter * removed KASP Advance Filter * removed unused filter --- .../Facility/FacilityFilter/index.tsx | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/Components/Facility/FacilityFilter/index.tsx b/src/Components/Facility/FacilityFilter/index.tsx index ff4d3f89508..fd6edd664d1 100644 --- a/src/Components/Facility/FacilityFilter/index.tsx +++ b/src/Components/Facility/FacilityFilter/index.tsx @@ -1,7 +1,6 @@ import { navigate } from "raviger"; import { FACILITY_TYPES } from "../../../Common/constants"; import useMergeState from "../../../Common/hooks/useMergeState"; -import useConfig from "../../../Common/hooks/useConfig"; import FiltersSlideover from "../../../CAREUI/interactive/FiltersSlideover"; import { useTranslation } from "react-i18next"; import StateAutocompleteFormField from "../../Common/StateAutocompleteFormField"; @@ -15,19 +14,17 @@ const clearFilterState = { district: "", local_body: "", facility_type: "", - kasp_empanelled: "", }; function FacilityFilter(props: any) { const { t } = useTranslation(); const { filter, onChange, closeFilter } = props; - const { kasp_string } = useConfig(); + const [filterState, setFilterState] = useMergeState({ state: filter.state || "", district: filter.district || "", local_body: filter.local_body || "", facility_type: filter.facility_type || "", - kasp_empanelled: filter.kasp_empanelled || "", }); const applyFilter = () => { @@ -36,7 +33,6 @@ function FacilityFilter(props: any) { district: Number(filterState.district) || "", local_body: Number(filterState.local_body) || "", facility_type: filterState.facility_type || "", - kasp_empanelled: filterState.kasp_empanelled || "", }; onChange(data); }; @@ -92,17 +88,6 @@ function FacilityFilter(props: any) { optionValue={(option) => option.id} placeholder={t("show_all")} /> - option.text} - optionValue={(option) => option.id} - placeholder={t("show_all")} - />
); From f5bc74173b463ffd0c89400576b6e5996e9b1303 Mon Sep 17 00:00:00 2001 From: Ayush Seth Date: Wed, 29 Nov 2023 10:24:19 +0530 Subject: [PATCH 12/27] hide location filter if facility is not selected (#6688) * make error optional and render only when required * fix markup and remove unnecessary tw classes * hide location filter if facility is not selected * revert changes to error component --- src/Components/Common/LocationSelect.tsx | 2 +- src/Components/Form/FormFields/FormField.tsx | 2 +- src/Components/Patient/PatientFilter.tsx | 89 ++++++++++---------- 3 files changed, 47 insertions(+), 46 deletions(-) diff --git a/src/Components/Common/LocationSelect.tsx b/src/Components/Common/LocationSelect.tsx index ef7280f1907..d20c843fad8 100644 --- a/src/Components/Common/LocationSelect.tsx +++ b/src/Components/Common/LocationSelect.tsx @@ -7,7 +7,7 @@ interface LocationSelectProps { name: string; disabled?: boolean; margin?: string; - errors: string; + errors?: string; className?: string; searchAll?: boolean; multiple?: boolean; diff --git a/src/Components/Form/FormFields/FormField.tsx b/src/Components/Form/FormFields/FormField.tsx index af5a3e91804..ffd42c0d50e 100644 --- a/src/Components/Form/FormFields/FormField.tsx +++ b/src/Components/Form/FormFields/FormField.tsx @@ -1,6 +1,6 @@ +import { classNames } from "../../../Utils/utils"; import { FieldError } from "../FieldValidators"; import { FormFieldBaseProps } from "./Utils"; -import { classNames } from "../../../Utils/utils"; type LabelProps = { id?: string | undefined; diff --git a/src/Components/Patient/PatientFilter.tsx b/src/Components/Patient/PatientFilter.tsx index 4ab7f14c895..10b170f4547 100644 --- a/src/Components/Patient/PatientFilter.tsx +++ b/src/Components/Patient/PatientFilter.tsx @@ -1,40 +1,40 @@ -import { useEffect, useCallback } from "react"; -import { FacilitySelect } from "../Common/FacilitySelect"; -import AutoCompleteAsync from "../Form/AutoCompleteAsync"; +import dayjs from "dayjs"; +import { navigate } from "raviger"; +import { useCallback, useEffect } from "react"; +import { useDispatch } from "react-redux"; +import CareIcon from "../../CAREUI/icons/CareIcon"; +import FiltersSlideover from "../../CAREUI/interactive/FiltersSlideover"; import { - GENDER_TYPES, - FACILITY_TYPES, - DISEASE_STATUS, - PATIENT_FILTER_CATEGORIES, ADMITTED_TO, DISCHARGE_REASONS, + DISEASE_STATUS, + FACILITY_TYPES, + GENDER_TYPES, + PATIENT_FILTER_CATEGORIES, } from "../../Common/constants"; +import useConfig from "../../Common/hooks/useConfig"; +import useMergeState from "../../Common/hooks/useMergeState"; import { getAllLocalBody, getAnyFacility, getDistrict, } from "../../Redux/actions"; -import { useDispatch } from "react-redux"; -import { navigate } from "raviger"; +import { dateQueryString } from "../../Utils/utils"; +import { DateRange } from "../Common/DateRangeInputV2"; +import { FacilitySelect } from "../Common/FacilitySelect"; +import { LocationSelect } from "../Common/LocationSelect"; +import AccordionV2 from "../Common/components/AccordionV2"; import DistrictSelect from "../Facility/FacilityFilter/DistrictSelect"; -import SelectMenuV2 from "../Form/SelectMenuV2"; +import AutoCompleteAsync from "../Form/AutoCompleteAsync"; +import DateRangeFormField from "../Form/FormFields/DateRangeFormField"; +import { FieldLabel } from "../Form/FormFields/FormField"; import TextFormField from "../Form/FormFields/TextFormField"; import { FieldChangeEvent, FieldChangeEventHandler, } from "../Form/FormFields/Utils"; -import { FieldLabel } from "../Form/FormFields/FormField"; import MultiSelectMenuV2 from "../Form/MultiSelectMenuV2"; -import DateRangeFormField from "../Form/FormFields/DateRangeFormField"; -import { DateRange } from "../Common/DateRangeInputV2"; -import CareIcon from "../../CAREUI/icons/CareIcon"; -import useMergeState from "../../Common/hooks/useMergeState"; -import useConfig from "../../Common/hooks/useConfig"; -import FiltersSlideover from "../../CAREUI/interactive/FiltersSlideover"; -import AccordionV2 from "../Common/components/AccordionV2"; -import { dateQueryString } from "../../Utils/utils"; -import dayjs from "dayjs"; -import { LocationSelect } from "../Common/LocationSelect"; +import SelectMenuV2 from "../Form/SelectMenuV2"; const getDate = (value: any) => value && dayjs(value).isValid() && dayjs(value).toDate(); @@ -587,10 +587,10 @@ export default function PatientFilter(props: any) { } expanded={true} - className="w-full rounded-md" + className="rounded-md" > -
-
+
+
Facility setFacility(obj, "facility")} />
-
- Location - - setFilterState({ - ...filterState, - last_consultation_current_bed__location: selected, - }) - } - /> -
-
+ {filterState.facility && ( +
+ Location + + setFilterState({ + ...filterState, + last_consultation_current_bed__location: selected, + }) + } + /> +
+ )} +
Facility type
-
+
LSG Body
-
+
District Date: Wed, 29 Nov 2023 10:24:33 +0530 Subject: [PATCH 13/27] Refactor onClick event in ConsultationDetails (#6704) component --- src/Components/Facility/ConsultationDetails/index.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Components/Facility/ConsultationDetails/index.tsx b/src/Components/Facility/ConsultationDetails/index.tsx index 534f253a416..2f6ca03ef06 100644 --- a/src/Components/Facility/ConsultationDetails/index.tsx +++ b/src/Components/Facility/ConsultationDetails/index.tsx @@ -309,7 +309,13 @@ export const ConsultationDetails = (props: any) => { setShowPatientNotesPopup(true)} + onClick={() => + showPatientNotesPopup + ? navigate( + `/facility/${facilityId}/patient/${patientId}/notes` + ) + : setShowPatientNotesPopup(true) + } className="btn btn-primary m-1 w-full hover:text-white" > Doctor's Notes From bf4920cef704efee5764b7bba66768524a14f15c Mon Sep 17 00:00:00 2001 From: Gampa Sri Harsh <114745442+sriharsh05@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:24:46 +0530 Subject: [PATCH 14/27] Remove blood group, weight and height badges on the top of patient info card (#6712) --- src/Common/utils.tsx | 10 ---------- src/Components/Patient/PatientInfoCard.tsx | 12 ------------ 2 files changed, 22 deletions(-) diff --git a/src/Common/utils.tsx b/src/Common/utils.tsx index 270e2f5efe6..3596469a6d5 100644 --- a/src/Common/utils.tsx +++ b/src/Common/utils.tsx @@ -44,16 +44,6 @@ export const parseOptionId: ( return textArray.join(", "); }; -export const getDimensionOrDash = ( - value: number | string | null | undefined, - unit: string -) => { - if (value === undefined || value === null || value === 0 || value === "0") { - return "-"; - } - return value + unit; -}; - export const deepEqual = (x: any, y: any): boolean => { if (x === y) return true; diff --git a/src/Components/Patient/PatientInfoCard.tsx b/src/Components/Patient/PatientInfoCard.tsx index bfcc4c23d96..e49607629fa 100644 --- a/src/Components/Patient/PatientInfoCard.tsx +++ b/src/Components/Patient/PatientInfoCard.tsx @@ -14,7 +14,6 @@ import { Link, navigate } from "raviger"; import { useState } from "react"; import CareIcon from "../../CAREUI/icons/CareIcon"; import useConfig from "../../Common/hooks/useConfig"; -import { getDimensionOrDash } from "../../Common/utils"; import dayjs from "../../Utils/dayjs"; import { classNames, formatDate, formatDateTime } from "../../Utils/utils.js"; import ABHAProfileModal from "../ABDM/ABHAProfileModal"; @@ -284,17 +283,6 @@ export default function PatientInfoCard(props: {
{[ - ["Blood Group", patient.blood_group, patient.blood_group], - [ - "Weight", - getDimensionOrDash(consultation?.weight, " kg"), - true, - ], - [ - "Height", - getDimensionOrDash(consultation?.height, "cm"), - true, - ], [ "Respiratory Support", RESPIRATORY_SUPPORT.find( From 9b2d9473712912950cb7f24c2373a0ef74e7f14a Mon Sep 17 00:00:00 2001 From: Khavin Shankar Date: Wed, 29 Nov 2023 19:53:55 +0530 Subject: [PATCH 15/27] Make facilityMiddlewareHostname as a state (#6753) --- src/Components/Facility/Consultations/Feed.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Components/Facility/Consultations/Feed.tsx b/src/Components/Facility/Consultations/Feed.tsx index 0389fe298dc..43d5b89cb38 100644 --- a/src/Components/Facility/Consultations/Feed.tsx +++ b/src/Components/Facility/Consultations/Feed.tsx @@ -55,15 +55,15 @@ export const Feed: React.FC = ({ consultationId, facilityId }) => { const [isFullscreen, setFullscreen] = useFullscreen(); const [videoStartTime, setVideoStartTime] = useState(null); const [statusReported, setStatusReported] = useState(false); + const [facilityMiddlewareHostname, setFacilityMiddlewareHostname] = + useState(""); const authUser = useAuthUser(); - let facilityMiddlewareHostname = ""; - useQuery(routes.getPermittedFacility, { pathParams: { id: facilityId || "" }, onResponse: ({ res, data }) => { if (res && res.status === 200 && data && data.middleware_address) { - facilityMiddlewareHostname = data.middleware_address; + setFacilityMiddlewareHostname(data.middleware_address); } }, }); From a18016b6b3d063d07ede0dd096c98ffb5b09803c Mon Sep 17 00:00:00 2001 From: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> Date: Wed, 29 Nov 2023 19:56:44 +0530 Subject: [PATCH 16/27] facility advance filter (#6736) --- cypress/e2e/facility_spec/facility.cy.ts | 2 +- .../e2e/facility_spec/facility_homepage.cy.ts | 24 ++++++++++++++++++- .../pageobject/Facility/FacilityCreation.ts | 16 +++++++++++-- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/cypress/e2e/facility_spec/facility.cy.ts b/cypress/e2e/facility_spec/facility.cy.ts index 5ae5d7cb9db..da06c65ed53 100644 --- a/cypress/e2e/facility_spec/facility.cy.ts +++ b/cypress/e2e/facility_spec/facility.cy.ts @@ -49,7 +49,7 @@ describe("Facility Creation", () => { facilityPage.visitUpdateFacilityPage(facilityUrl); facilityPage.clickManageFacilityDropdown(); facilityPage.clickUpdateFacilityOption(); - facilityPage.clickUpdateFacilityType(); + facilityPage.clickUpdateFacilityType("Request Approving Center"); facilityPage.fillFacilityName("cypress facility updated"); facilityPage.fillAddress("Cypress Facility Updated Address"); facilityPage.fillOxygenCapacity("100"); diff --git a/cypress/e2e/facility_spec/facility_homepage.cy.ts b/cypress/e2e/facility_spec/facility_homepage.cy.ts index bf6ce12536e..3d916b4ba47 100644 --- a/cypress/e2e/facility_spec/facility_homepage.cy.ts +++ b/cypress/e2e/facility_spec/facility_homepage.cy.ts @@ -4,17 +4,22 @@ import LoginPage from "../../pageobject/Login/LoginPage"; import FacilityHome from "../../pageobject/Facility/FacilityHome"; import ManageUserPage from "../../pageobject/Users/ManageUserPage"; import FacilityPage from "../../pageobject/Facility/FacilityCreation"; +import { UserPage } from "../../pageobject/Users/UserSearch"; -describe("Facility Creation", () => { +describe("Facility Homepage Function", () => { const loginPage = new LoginPage(); const facilityHome = new FacilityHome(); const facilityPage = new FacilityPage(); const manageUserPage = new ManageUserPage(); + const userPage = new UserPage(); const facilitiesAlias = "downloadFacilitiesCSV"; const capacitiesAlias = "downloadCapacitiesCSV"; const doctorsAlias = "downloadDoctorsCSV"; const triagesAlias = "downloadTriagesCSV"; const facilityname = "Dummy Facility 1"; + const statename = "Kerala"; + const district = "Ernakulam"; + const facilitytype = "Private Hospital"; before(() => { loginPage.loginAsDisctrictAdmin(); @@ -26,6 +31,23 @@ describe("Facility Creation", () => { cy.awaitUrl("/facility"); }); + it("Verify the functionality of advance filter", () => { + userPage.clickAdvancedFilters(); + facilityPage.selectState(statename); + facilityPage.selectDistrict(district); + // facilityPage.selectLocalBody("Anthikad Grama"); current dummy data have issue in local body + facilityPage.clickUpdateFacilityType(facilitytype); + userPage.applyFilter(); + facilityPage.verifyStateBadgeContent(statename); + facilityPage.verifyDistrictBadgeContent(district); + facilityPage.verifyFacilityTypeBadgeContent(facilitytype); + manageUserPage.assertFacilityInCard(facilityname); + userPage.clearFilters(); + userPage.verifyDataTestIdNotVisible("State"); + userPage.verifyDataTestIdNotVisible("District"); + userPage.verifyDataTestIdNotVisible("Facility type"); + }); + it("Search a facility in homepage", () => { manageUserPage.typeFacilitySearch(facilityname); facilityPage.verifyFacilityBadgeContent(facilityname); diff --git a/cypress/pageobject/Facility/FacilityCreation.ts b/cypress/pageobject/Facility/FacilityCreation.ts index d27433f04e7..8c20b808c98 100644 --- a/cypress/pageobject/Facility/FacilityCreation.ts +++ b/cypress/pageobject/Facility/FacilityCreation.ts @@ -17,11 +17,11 @@ class FacilityPage { cy.get("#manage-facility-dropdown button").should("be.visible"); } - clickUpdateFacilityType() { + clickUpdateFacilityType(facilityType) { cy.get("#facility_type") .click() .then(() => { - cy.get("[role='option']").contains("Request Approving Center").click(); + cy.get("[role='option']").contains(facilityType).click(); }); } @@ -195,6 +195,18 @@ class FacilityPage { ); } + verifyStateBadgeContent(expectedText: string) { + cy.get("[data-testid='State']").should("contain", expectedText); + } + + verifyDistrictBadgeContent(expectedText: string) { + cy.get("[data-testid='District']").should("contain", expectedText); + } + + verifyFacilityTypeBadgeContent(expectedText: string) { + cy.get("[data-testid='Facility type']").should("contain", expectedText); + } + verifyfacilitycreateassetredirection() { cy.url().should("include", "/assets/new"); } From fe28c4e029f38e84c2708b55a3a0d9997bc61431 Mon Sep 17 00:00:00 2001 From: Kshitij Verma <101321276+kshitijv256@users.noreply.github.com> Date: Thu, 30 Nov 2023 10:12:45 +0530 Subject: [PATCH 17/27] showing errors on wrong numbers in PhoneNumberFormField (#6675) * showing errors wrong number in PhoneNumberFormField * made error field show only when there is an error * Update src/Components/Form/FormFields/FormField.tsx Co-authored-by: Rithvik Nishad * changed margin to remove extra space in userfilter * Apply suggestions from code review --------- Co-authored-by: Rithvik Nishad --- src/Components/Shifting/ListFilter.tsx | 1 - src/Components/Users/UserFilter.tsx | 40 +++++++++++++------------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/Components/Shifting/ListFilter.tsx b/src/Components/Shifting/ListFilter.tsx index c5b3555e8c4..ef366d5b038 100644 --- a/src/Components/Shifting/ListFilter.tsx +++ b/src/Components/Shifting/ListFilter.tsx @@ -410,7 +410,6 @@ export default function ListFilter(props: any) { name="patient_phone_number" value={filterState.patient_phone_number} onChange={handleFormFieldChange} - errorClassName="hidden" types={["mobile", "landline"]} />
- - - - +
+ +
+
+ +
); } From f5a6ac3b46120d2c2da3ed8144a0b4e7e9bd1dab Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Thu, 30 Nov 2023 10:12:59 +0530 Subject: [PATCH 18/27] Show discharge reason for OP consultations (#6724) --- src/Components/Patient/PatientInfoCard.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Components/Patient/PatientInfoCard.tsx b/src/Components/Patient/PatientInfoCard.tsx index e49607629fa..78e299fe218 100644 --- a/src/Components/Patient/PatientInfoCard.tsx +++ b/src/Components/Patient/PatientInfoCard.tsx @@ -348,7 +348,11 @@ export default function PatientInfoCard(props: {
{!consultation?.discharge_reason ? ( - UNKNOWN + + {consultation.suggestion === "OP" + ? "OP file closed" + : "UNKNOWN"} + ) : consultation?.discharge_reason === "EXP" ? ( EXPIRED ) : ( From 31b7690ce92d5b07e6d52aa9dc8d0546c40a59f0 Mon Sep 17 00:00:00 2001 From: Gampa Sri Harsh <114745442+sriharsh05@users.noreply.github.com> Date: Thu, 30 Nov 2023 10:13:10 +0530 Subject: [PATCH 19/27] Convert the unit from grams to kg in inventory form (#6750) --- src/Components/Facility/AddInventoryForm.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Components/Facility/AddInventoryForm.tsx b/src/Components/Facility/AddInventoryForm.tsx index df217cad3ec..9e4f761b550 100644 --- a/src/Components/Facility/AddInventoryForm.tsx +++ b/src/Components/Facility/AddInventoryForm.tsx @@ -146,7 +146,7 @@ export const AddInventoryForm = (props: any) => { if (unitName === "Dozen") { return Number(unitData.quantity) * 12; } - if (unitName === "Gram") { + if (unitName === "gram") { return Number(unitData.quantity) / 1000; } return Number(unitData.quantity); @@ -238,6 +238,11 @@ export const AddInventoryForm = (props: any) => { }; // if user has selected "Add stock" or "stockValidation" function is true if (data.is_incoming || stockValidation(data)) { + // if user has selected grams as unit then convert it to kg + if (data.unit === 5) { + data.quantity = data.quantity / 1000; + data.unit = 6; + } const res = await dispatchAction(postInventory(data, { facilityId })); setIsLoading(false); From 747e5f130a08ba6e20d61b4a035a46a07a4fa203 Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Fri, 1 Dec 2023 10:47:45 +0530 Subject: [PATCH 20/27] Adds support for capturing time in Discharge Date (#6757) * Adds support for capturing time in Discharge Date * Refactor discharge form field labels and add conditional rendering for death-related fields * show time in patient card * fix minor issue * fix discharge prescriptions being shown --- src/Components/Facility/DischargeModal.tsx | 149 +++++++++------------ src/Components/Patient/PatientInfoCard.tsx | 3 +- 2 files changed, 62 insertions(+), 90 deletions(-) diff --git a/src/Components/Facility/DischargeModal.tsx b/src/Components/Facility/DischargeModal.tsx index 138e74fb9b9..3384efa686b 100644 --- a/src/Components/Facility/DischargeModal.tsx +++ b/src/Components/Facility/DischargeModal.tsx @@ -8,9 +8,7 @@ import ClaimDetailCard from "../HCX/ClaimDetailCard"; import { ConsultationModel } from "./models"; import CreateClaimCard from "../HCX/CreateClaimCard"; import { DISCHARGE_REASONS } from "../../Common/constants"; -import DateFormField from "../Form/FormFields/DateFormField"; import DialogModal from "../Common/Dialog"; -import { FieldChangeEvent } from "../Form/FormFields/Utils"; import { FieldLabel } from "../Form/FormFields/FormField"; import { HCXActions } from "../../Redux/actions"; import { HCXClaimModel } from "../HCX/models"; @@ -161,11 +159,6 @@ const DischargeModal = ({ setIsSendingDischargeApi(false); if (dischargeResponse?.status === 200) { - // TODO: check this later - // const dischargeData = Object.assign({}, patientData); - // dischargeData["discharge"] = value; - // setPatientData(dischargeData); - Notification.Success({ msg: "Patient Discharged Successfully", }); @@ -174,15 +167,6 @@ const DischargeModal = ({ } }; - const handleDateChange = (e: FieldChangeEvent) => { - setPreDischargeForm((form) => { - return { - ...form, - discharge_date: e.value.toString(), - }; - }); - }; - const handleFacilitySelect = (selected: FacilityModel) => { setFacility(selected); const { id, name } = selected || {}; @@ -248,11 +232,10 @@ const DischargeModal = ({ - {preDischargeForm.discharge_reason === "REC" && ( -
- + { + const updates: Record = { + discharge_date: undefined, + death_datetime: undefined, + }; + updates[e.name] = e.value; + setPreDischargeForm((form) => ({ ...form, ...updates })); + }} + required + min={dayjs( + consultationData?.admission_date ?? consultationData?.created_date + ).format("YYYY-MM-DDTHH:mm")} + max={dayjs().format("YYYY-MM-DDTHH:mm")} + error={ + preDischargeForm.discharge_reason === "EXP" + ? errors?.death_datetime + : errors?.discharge_date + } + /> + {preDischargeForm.discharge_reason === "REC" && ( + <>
Discharge Prescription Medications @@ -288,61 +296,24 @@ const DischargeModal = ({ Discharge PRN Prescriptions
-
+ )} {preDischargeForm.discharge_reason === "EXP" && ( -
- { - setPreDischargeForm((form) => { - return { - ...form, - death_datetime: e.value, - }; - }); - }} - required - min={dayjs(consultationData?.admission_date).format( - "YYYY-MM-DDTHH:mm" - )} - max={dayjs().format("YYYY-MM-DDTHH:mm")} - /> - { - setPreDischargeForm((form) => { - return { - ...form, - death_confirmed_doctor: e.value, - }; - }); - }} - required - placeholder="Attending Doctor's Name and Designation" - /> -
- )} - {["REF", "LAMA"].includes(preDischargeForm.discharge_reason) && ( -
- -
+ { + setPreDischargeForm((form) => { + return { + ...form, + death_confirmed_doctor: e.value, + }; + }); + }} + required + placeholder="Attending Doctor's Name and Designation" + /> )}
diff --git a/src/Components/Patient/PatientInfoCard.tsx b/src/Components/Patient/PatientInfoCard.tsx index 78e299fe218..8bf20a65f64 100644 --- a/src/Components/Patient/PatientInfoCard.tsx +++ b/src/Components/Patient/PatientInfoCard.tsx @@ -330,7 +330,8 @@ export default function PatientInfoCard(props: { ) : ( {" "} - Discharged on {formatDate(consultation?.discharge_date)} + Discharged on{" "} + {formatDateTime(consultation?.discharge_date)} )} From 47511a322f8bf3d79489e00f79285a46414f30da Mon Sep 17 00:00:00 2001 From: Ashesh <3626859+Ashesh3@users.noreply.github.com> Date: Fri, 1 Dec 2023 20:01:45 +0530 Subject: [PATCH 21/27] Update tooltip position in ConfigureHealthFacility (#6764) * Update tooltip position in ConfigureHealthFacility component * Update tooltip positioning in ConfigureHealthFacility component --- src/Components/ABDM/ConfigureHealthFacility.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/ABDM/ConfigureHealthFacility.tsx b/src/Components/ABDM/ConfigureHealthFacility.tsx index a84e4b6d4b9..bccf58e47c2 100644 --- a/src/Components/ABDM/ConfigureHealthFacility.tsx +++ b/src/Components/ABDM/ConfigureHealthFacility.tsx @@ -178,7 +178,7 @@ export const ConfigureHealthFacility = (props: any) => { > {state.form.health_facility?.registered ? ( <> -
+
The ABDM health facility is successfully linked with care{" "} @@ -192,7 +192,7 @@ export const ConfigureHealthFacility = (props: any) => { ) : ( <> -
+
The ABDM health facility is successfully linked with care{" "} From 737ef2dcbbcf835c766ca428c38324236d788d7f Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Fri, 1 Dec 2023 21:24:58 +0530 Subject: [PATCH 22/27] fixes #6766; Misaligned label in external results (#6769) --- src/Components/ExternalResult/ResultList.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/ExternalResult/ResultList.tsx b/src/Components/ExternalResult/ResultList.tsx index d148b26e3f5..9aa365c7303 100644 --- a/src/Components/ExternalResult/ResultList.tsx +++ b/src/Components/ExternalResult/ResultList.tsx @@ -264,11 +264,11 @@ export default function ResultList() { value={qParams.name} placeholder="Search by name" /> -
Search by number
setPhoneNum(e.value)} error={phoneNumberError} From 4ed48a96fedcebf5bd80683c2584ce836bdaea1d Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Fri, 1 Dec 2023 22:10:23 +0530 Subject: [PATCH 23/27] fixes #6774; vitals content overlapping bed dropdown (#6775) --- src/Components/VitalsMonitor/HL7PatientVitalsMonitor.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/VitalsMonitor/HL7PatientVitalsMonitor.tsx b/src/Components/VitalsMonitor/HL7PatientVitalsMonitor.tsx index 6533d133089..d91b0c56b2f 100644 --- a/src/Components/VitalsMonitor/HL7PatientVitalsMonitor.tsx +++ b/src/Components/VitalsMonitor/HL7PatientVitalsMonitor.tsx @@ -236,7 +236,7 @@ export const VitalsNonWaveformContent = ({ }: { children: JSX.Element | JSX.Element[]; }) => ( -
+
{children}
); From b49247cfc154db3f3d1adc6e5a8c18c3ecc4d65c Mon Sep 17 00:00:00 2001 From: Ashesh <3626859+Ashesh3@users.noreply.github.com> Date: Fri, 1 Dec 2023 23:07:04 +0530 Subject: [PATCH 24/27] Add middleware address to AssetLocationObject and (#6778) update HL7 and ventilator middleware --- src/Components/Assets/AssetTypes.tsx | 1 + .../ConsultationDetails/ConsultationUpdatesTab.tsx | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Components/Assets/AssetTypes.tsx b/src/Components/Assets/AssetTypes.tsx index 8b96b6beeb7..a4005404da1 100644 --- a/src/Components/Assets/AssetTypes.tsx +++ b/src/Components/Assets/AssetTypes.tsx @@ -8,6 +8,7 @@ export interface AssetLocationObject { description: string; created_date?: string; modified_date?: string; + middleware_address?: string; facility: { id: string; name: string; diff --git a/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx index 736a7c81575..bb584ae93e6 100644 --- a/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx +++ b/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx @@ -60,7 +60,10 @@ export const ConsultationUpdatesTab = (props: ConsultationTabProps) => { setMonitorBedData(monitorBedData); const assetDataForMonitor = monitorBedData?.asset_object; const hl7Meta = assetDataForMonitor?.meta; - const hl7Middleware = hl7Meta?.middleware_hostname || middleware_address; + const hl7Middleware = + hl7Meta?.middleware_hostname || + assetDataForMonitor?.location_object?.middleware_address || + middleware_address; if (hl7Middleware && hl7Meta?.local_ip_address) { setHL7SocketUrl( `wss://${hl7Middleware}/observations/${hl7Meta.local_ip_address}` @@ -85,7 +88,9 @@ export const ConsultationUpdatesTab = (props: ConsultationTabProps) => { setVentilatorBedData(ventilatorBedData); const ventilatorMeta = ventilatorBedData?.asset_object?.meta; const ventilatorMiddleware = - ventilatorMeta?.middleware_hostname || middleware_address; + ventilatorMeta?.middleware_hostname || + consultationBedVentilator?.location_object.middleware_address || + middleware_address; if (ventilatorMiddleware && ventilatorMeta?.local_ip_address) { setVentilatorSocketUrl( `wss://${ventilatorMiddleware}/observations/${ventilatorMeta?.local_ip_address}` From e9fbcc0e8ffc8e63c0007d21abc831b78ddb306b Mon Sep 17 00:00:00 2001 From: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> Date: Mon, 4 Dec 2023 09:41:34 +0530 Subject: [PATCH 25/27] Updated login credentials in README.md (#6786) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 002afc979bc..a6a2806558d 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Once the development server has started, open [localhost:4000](http://localhost: Authenticate to staging API with any of the following credentials ```yaml -- username: devdistrictadmin +- username: dev-districtadmin password: Coronasafe@123 role: District Admin From 9fea2d85c1c7b85323363f70a46ec89283d5bf27 Mon Sep 17 00:00:00 2001 From: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> Date: Mon, 4 Dec 2023 15:05:26 +0530 Subject: [PATCH 26/27] New Cypress Test | Create new Facility in multiple combination | Facility Tab (#6785) * Inital File Change * revert vite * Final converted remaining test part * minor fix * minor fix component change --- cypress/e2e/facility_spec/facility.cy.ts | 82 ------ .../e2e/facility_spec/facility_creation.cy.ts | 245 ++++++++++++++++++ .../pageobject/Facility/FacilityCreation.ts | 87 +++++++ .../Facility/FacilityBedCapacity.tsx | 4 +- src/Components/Facility/FacilityCreate.tsx | 9 +- .../Facility/FacilityDoctorList.tsx | 4 +- src/Components/Facility/FacilityHome.tsx | 16 +- 7 files changed, 354 insertions(+), 93 deletions(-) delete mode 100644 cypress/e2e/facility_spec/facility.cy.ts create mode 100644 cypress/e2e/facility_spec/facility_creation.cy.ts diff --git a/cypress/e2e/facility_spec/facility.cy.ts b/cypress/e2e/facility_spec/facility.cy.ts deleted file mode 100644 index da06c65ed53..00000000000 --- a/cypress/e2e/facility_spec/facility.cy.ts +++ /dev/null @@ -1,82 +0,0 @@ -// FacilityCreation -import { cy, describe, before, beforeEach, it, afterEach } from "local-cypress"; -import FacilityPage from "../../pageobject/Facility/FacilityCreation"; -import LoginPage from "../../pageobject/Login/LoginPage"; - -describe("Facility Creation", () => { - let facilityUrl: string; - const facilityPage = new FacilityPage(); - const loginPage = new LoginPage(); - - before(() => { - loginPage.loginAsDisctrictAdmin(); - cy.saveLocalStorage(); - }); - - beforeEach(() => { - cy.viewport(1280, 720); - cy.restoreLocalStorage(); - cy.awaitUrl("/facility"); - }); - - it("Create a new facility", () => { - facilityPage.visitCreateFacilityPage(); - facilityPage.fillFacilityName("cypress facility"); - facilityPage.fillPincode("682001"); - facilityPage.selectState("Kerala"); - facilityPage.selectDistrict("Ernakulam"); - facilityPage.selectLocalBody("Aluva"); - facilityPage.selectWard("4"); - facilityPage.fillAddress("Cypress Address"); - facilityPage.fillPhoneNumber("9898469865"); - facilityPage.submitForm(); - - facilityPage.selectBedType("Oxygen beds"); - facilityPage.fillTotalCapacity("10"); - facilityPage.fillCurrentlyOccupied("5"); - facilityPage.saveAndExitBedCapacityForm(); - - facilityPage.selectAreaOfSpecialization("General Medicine"); - facilityPage.fillDoctorCount("5"); - facilityPage.saveAndExitDoctorForm(); - facilityPage.verifyfacilitynewurl(); - cy.url().then((newUrl) => { - facilityUrl = newUrl; - }); - }); - - it("Update the existing facility", () => { - facilityPage.visitUpdateFacilityPage(facilityUrl); - facilityPage.clickManageFacilityDropdown(); - facilityPage.clickUpdateFacilityOption(); - facilityPage.clickUpdateFacilityType("Request Approving Center"); - facilityPage.fillFacilityName("cypress facility updated"); - facilityPage.fillAddress("Cypress Facility Updated Address"); - facilityPage.fillOxygenCapacity("100"); - facilityPage.fillExpectedOxygenRequirement("80"); - facilityPage.selectLocation("Kochi, Kerala"); - facilityPage.submitForm(); - - cy.url().should("not.include", "/update"); - }); - - it("Configure the existing facility", () => { - facilityPage.visitUpdateFacilityPage(facilityUrl); - facilityPage.clickManageFacilityDropdown(); - facilityPage.clickConfigureFacilityOption(); - facilityPage.fillMiddleWareAddress("dev_middleware.coronasafe.live"); - facilityPage.clickupdateMiddleWare(); - facilityPage.verifySuccessNotification("Facility updated successfully"); - }); - - it("Delete a facility", () => { - facilityPage.visitUpdateFacilityPage(facilityUrl); - facilityPage.clickManageFacilityDropdown(); - facilityPage.clickDeleteFacilityOption(); - facilityPage.confirmDeleteFacility(); - }); - - afterEach(() => { - cy.saveLocalStorage(); - }); -}); diff --git a/cypress/e2e/facility_spec/facility_creation.cy.ts b/cypress/e2e/facility_spec/facility_creation.cy.ts new file mode 100644 index 00000000000..d43aa093a69 --- /dev/null +++ b/cypress/e2e/facility_spec/facility_creation.cy.ts @@ -0,0 +1,245 @@ +// FacilityCreation +import { cy, describe, before, beforeEach, it, afterEach } from "local-cypress"; +import FacilityPage from "../../pageobject/Facility/FacilityCreation"; +import LoginPage from "../../pageobject/Login/LoginPage"; +import FacilityHome from "../../pageobject/Facility/FacilityHome"; +import ManageUserPage from "../../pageobject/Users/ManageUserPage"; +import { UserCreationPage } from "../../pageobject/Users/UserCreation"; + +describe("Facility Creation", () => { + let facilityUrl1: string; + const facilityPage = new FacilityPage(); + const loginPage = new LoginPage(); + const facilityHome = new FacilityHome(); + const manageUserPage = new ManageUserPage(); + const userCreationPage = new UserCreationPage(); + const facilityFeature = [ + "CT Scan", + "X-Ray", + "Maternity Care", + "Neonatal Care", + "Operation Theater", + "Blood Bank", + ]; + const bedCapacity = "10"; + const bedOccupancy = "5"; + const oxygenCapacity = "100"; + const oxygenExpected = "80"; + const totalCapacity = "20"; + const totalOccupancy = "10"; + const doctorCapacity = "5"; + const totalDoctor = "10"; + const facilityName = "cypress facility"; + const facilityAddress = "cypress address"; + const facilityNumber = "9898469865"; + const facilityErrorMessage = [ + "Required", + "Invalid Pincode", + "Required", + "Required", + "Required", + "Required", + "Required", + "Required", + "Invalid Phone Number", + ]; + const bedErrorMessage = [ + "Field is required", + "Total capacity cannot be 0", + "Field is required", + ]; + const doctorErrorMessage = ["Field is required", "Field is required"]; + + before(() => { + loginPage.loginAsDisctrictAdmin(); + cy.saveLocalStorage(); + }); + + beforeEach(() => { + cy.viewport(1280, 720); + cy.restoreLocalStorage(); + cy.awaitUrl("/facility"); + }); + + it("Create a new facility with multiple bed and doctor capacity", () => { + // create facility with multiple capacity and verify form error message for facility form + facilityPage.visitCreateFacilityPage(); + facilityPage.submitForm(); + userCreationPage.verifyErrorMessages(facilityErrorMessage); + facilityPage.fillFacilityName(facilityName); + facilityPage.clickfacilityfeatureoption(); + facilityFeature.forEach((featureText) => { + cy.get("[role='option']").contains(featureText).click(); + }); + facilityPage.fillPincode("682001"); + facilityPage.selectLocalBody("Aluva"); + facilityPage.selectWard("4"); + facilityPage.fillAddress(facilityAddress); + facilityPage.fillPhoneNumber(facilityNumber); + facilityPage.fillOxygenCapacity(oxygenCapacity); + facilityPage.fillExpectedOxygenRequirement(oxygenExpected); + facilityPage.fillBTypeCylinderCapacity(oxygenCapacity); + facilityPage.fillExpectedBTypeCylinderRequirement(oxygenExpected); + facilityPage.fillCTypeCylinderCapacity(oxygenCapacity); + facilityPage.fillExpectedCTypeCylinderRequirement(oxygenExpected); + facilityPage.fillDTypeCylinderCapacity(oxygenCapacity); + facilityPage.fillExpectedDTypeCylinderRequirement(oxygenExpected); + facilityPage.selectLocation("Kochi, Kerala"); + facilityPage.submitForm(); + // create multiple bed capacity and verify card reflection + facilityPage.selectBedType("Oxygen beds"); + facilityPage.fillTotalCapacity(bedCapacity); + facilityPage.fillCurrentlyOccupied(bedOccupancy); + facilityPage.clickbedcapcityaddmore(); + facilityPage.selectBedType("Ordinary Bed"); + facilityPage.fillTotalCapacity(bedCapacity); + facilityPage.fillCurrentlyOccupied(bedOccupancy); + facilityPage.clickbedcapcityaddmore(); + facilityPage.getTotalBedCapacity().contains(totalCapacity); + facilityPage.getTotalBedCapacity().contains(totalOccupancy); + facilityPage.clickcancelbutton(); + // create multiple bed capacity and verify card reflection + facilityPage.selectAreaOfSpecialization("General Medicine"); + facilityPage.fillDoctorCount(doctorCapacity); + facilityPage.clickdoctorcapacityaddmore(); + facilityPage.selectAreaOfSpecialization("Pulmonology"); + facilityPage.fillDoctorCount(doctorCapacity); + facilityPage.clickdoctorcapacityaddmore(); + facilityPage.getTotalDoctorCapacity().contains(doctorCapacity); + facilityPage.clickcancelbutton(); + facilityPage.verifyfacilitynewurl(); + // verify the facility card + facilityPage.getFacilityName().contains(facilityName).should("be.visible"); + facilityPage + .getAddressDetailsView() + .contains(facilityAddress) + .should("be.visible"); + facilityPage + .getPhoneNumberView() + .contains(facilityNumber) + .should("be.visible"); + facilityPage + .getFacilityAvailableFeatures() + .invoke("text") + .then((text) => { + facilityFeature.forEach((feature) => { + expect(text).to.contain(feature); + }); + }); + facilityPage.getFacilityOxygenInfo().scrollIntoView(); + facilityPage + .getFacilityOxygenInfo() + .contains(oxygenCapacity) + .should("be.visible"); + facilityPage.getFacilityTotalBedCapacity().scrollIntoView(); + facilityPage.getFacilityTotalBedCapacity().contains(totalCapacity); + facilityPage.getFacilityTotalBedCapacity().contains(totalOccupancy); + facilityPage.getFacilityTotalDoctorCapacity().scrollIntoView(); + facilityPage.getFacilityTotalDoctorCapacity().contains(totalDoctor); + }); + + it("Create a new facility with single bed and doctor capacity", () => { + facilityPage.visitCreateFacilityPage(); + facilityPage.fillFacilityName(facilityName); + facilityPage.fillPincode("682001"); + facilityPage.selectLocalBody("Aluva"); + facilityPage.selectWard("4"); + facilityPage.fillAddress(facilityAddress); + facilityPage.fillPhoneNumber(facilityNumber); + facilityPage.submitForm(); + // add the bed capacity + facilityPage.selectBedType("Oxygen beds"); + facilityPage.fillTotalCapacity(oxygenCapacity); + facilityPage.fillCurrentlyOccupied(oxygenExpected); + facilityPage.saveAndExitBedCapacityForm(); + // add the doctor capacity + facilityPage.selectAreaOfSpecialization("General Medicine"); + facilityPage.fillDoctorCount(doctorCapacity); + facilityPage.saveAndExitDoctorForm(); + facilityPage.verifyfacilitynewurl(); + // verify the created facility details + facilityPage.getFacilityName().contains(facilityName).should("be.visible"); + facilityPage + .getAddressDetailsView() + .contains(facilityAddress) + .should("be.visible"); + facilityPage + .getPhoneNumberView() + .contains(facilityNumber) + .should("be.visible"); + // verify the facility homepage + cy.visit("/facility"); + manageUserPage.typeFacilitySearch(facilityName); + facilityPage.verifyFacilityBadgeContent(facilityName); + manageUserPage.assertFacilityInCard(facilityName); + facilityHome.verifyURLContains(facilityName); + }); + + it("Create a new facility with no bed and doctor capacity", () => { + facilityPage.visitCreateFacilityPage(); + facilityPage.fillFacilityName(facilityName); + facilityPage.fillPincode("682001"); + facilityPage.selectLocalBody("Aluva"); + facilityPage.selectWard("4"); + facilityPage.fillAddress(facilityAddress); + facilityPage.fillPhoneNumber(facilityNumber); + facilityPage.submitForm(); + // add no bed capacity and verify form error message + facilityPage.isVisibleselectBedType(); + facilityPage.saveAndExitBedCapacityForm(); + userCreationPage.verifyErrorMessages(bedErrorMessage); + facilityPage.clickcancelbutton(); + // add no doctor capacity and verify form error message + facilityPage.isVisibleAreaOfSpecialization(); + facilityPage.clickdoctorcapacityaddmore(); + userCreationPage.verifyErrorMessages(doctorErrorMessage); + facilityPage.clickcancelbutton(); + cy.url().then((newUrl) => { + facilityUrl1 = newUrl; + }); + // verify the created facility details + facilityPage.getFacilityName().contains(facilityName).should("be.visible"); + facilityPage + .getAddressDetailsView() + .contains(facilityAddress) + .should("be.visible"); + facilityPage + .getPhoneNumberView() + .contains(facilityNumber) + .should("be.visible"); + }); + + it("Update the existing facility", () => { + facilityPage.visitUpdateFacilityPage(facilityUrl1); + facilityPage.clickManageFacilityDropdown(); + facilityPage.clickUpdateFacilityOption(); + facilityPage.clickUpdateFacilityType("Request Approving Center"); + facilityPage.fillFacilityName("cypress facility updated"); + facilityPage.fillAddress("Cypress Facility Updated Address"); + facilityPage.fillOxygenCapacity("100"); + facilityPage.fillExpectedOxygenRequirement("80"); + facilityPage.selectLocation("Kochi, Kerala"); + facilityPage.submitForm(); + cy.url().should("not.include", "/update"); + }); + + it("Configure the existing facility", () => { + facilityPage.visitUpdateFacilityPage(facilityUrl1); + facilityPage.clickManageFacilityDropdown(); + facilityPage.clickConfigureFacilityOption(); + facilityPage.fillMiddleWareAddress("dev_middleware.coronasafe.live"); + facilityPage.clickupdateMiddleWare(); + facilityPage.verifySuccessNotification("Facility updated successfully"); + }); + + it("Delete a facility", () => { + facilityPage.visitUpdateFacilityPage(facilityUrl1); + facilityPage.clickManageFacilityDropdown(); + facilityPage.clickDeleteFacilityOption(); + facilityPage.confirmDeleteFacility(); + }); + + afterEach(() => { + cy.saveLocalStorage(); + }); +}); diff --git a/cypress/pageobject/Facility/FacilityCreation.ts b/cypress/pageobject/Facility/FacilityCreation.ts index 8c20b808c98..b4d3808d645 100644 --- a/cypress/pageobject/Facility/FacilityCreation.ts +++ b/cypress/pageobject/Facility/FacilityCreation.ts @@ -70,6 +70,10 @@ class FacilityPage { cy.get("[role='option']").contains(bedType).click(); } + isVisibleselectBedType() { + cy.get("div#bed-type button").should("be.visible"); + } + fillTotalCapacity(capacity: string) { cy.get("input#total-capacity").click().type(capacity); } @@ -87,6 +91,10 @@ class FacilityPage { cy.get("[role='option']").contains(area).click(); } + isVisibleAreaOfSpecialization() { + cy.get("div#area-of-specialization button").should("be.visible"); + } + fillDoctorCount(count: string) { cy.get("input#count").click().type(count); } @@ -99,6 +107,33 @@ class FacilityPage { cy.get("#expected_oxygen_requirement").click().clear().type(requirement); } + fillBTypeCylinderCapacity(capacity: string) { + cy.get("#type_b_cylinders").click().clear().type(capacity); + } + + fillExpectedBTypeCylinderRequirement(requirement: string) { + cy.get("#expected_type_b_cylinders").focus().clear(); + cy.get("#expected_type_b_cylinders").focus().type(requirement); + } + + fillCTypeCylinderCapacity(capacity: string) { + cy.get("#type_c_cylinders").click().clear().type(capacity); + } + + fillExpectedCTypeCylinderRequirement(requirement: string) { + cy.get("#expected_type_c_cylinders").focus().clear(); + cy.get("#expected_type_c_cylinders").focus().type(requirement); + } + + fillDTypeCylinderCapacity(capacity: string) { + cy.get("#type_d_cylinders").click().clear().type(capacity); + } + + fillExpectedDTypeCylinderRequirement(requirement: string) { + cy.get("#expected_type_d_cylinders").focus().clear(); + cy.get("#expected_type_d_cylinders").focus().type(requirement); + } + saveAndExitDoctorForm() { cy.intercept("GET", "**/api/v1/facility/**").as("createFacilities"); cy.get("button#save-and-exit").click(); @@ -138,6 +173,42 @@ class FacilityPage { cy.get("#inventory-management").click(); } + getTotalBedCapacity() { + return cy.get("#total-bed-capacity"); + } + + getFacilityTotalBedCapacity() { + return cy.get("#facility-bed-capacity-details"); + } + + getFacilityTotalDoctorCapacity() { + return cy.get("#facility-doctor-capacity-details"); + } + + getTotalDoctorCapacity() { + return cy.get("#total-doctor-capacity"); + } + + getFacilityName() { + return cy.get("#facility-name"); + } + + getAddressDetailsView() { + return cy.get("#address-details-view"); + } + + getPhoneNumberView() { + return cy.get("#phone-number-view"); + } + + getFacilityAvailableFeatures() { + return cy.get("#facility-available-features"); + } + + getFacilityOxygenInfo() { + return cy.get("#facility-oxygen-info"); + } + clickResourceRequestOption() { cy.get("#resource-request").contains("Resource Request").click(); } @@ -146,6 +217,22 @@ class FacilityPage { cy.get("#delete-facility").contains("Delete Facility").click(); } + clickfacilityfeatureoption() { + cy.get("#features").click(); + } + + clickbedcapcityaddmore() { + cy.get("#bed-capacity-save").click(); + } + + clickdoctorcapacityaddmore() { + cy.get("#doctor-save").click(); + } + + clickcancelbutton() { + cy.get("#cancel").click(); + } + verifyfacilitynewurl() { cy.url().should("match", /facility\/[a-z\d-]+/); } diff --git a/src/Components/Facility/FacilityBedCapacity.tsx b/src/Components/Facility/FacilityBedCapacity.tsx index 33583840643..0c05fb022cb 100644 --- a/src/Components/Facility/FacilityBedCapacity.tsx +++ b/src/Components/Facility/FacilityBedCapacity.tsx @@ -82,7 +82,7 @@ export const FacilityBedCapacity = (props: any) => { } return ( -
+
Bed Capacity
@@ -114,6 +114,6 @@ export const FacilityBedCapacity = (props: any) => { /> )} -
+
); }; diff --git a/src/Components/Facility/FacilityCreate.tsx b/src/Components/Facility/FacilityCreate.tsx index e742caefb82..8a7887ebc25 100644 --- a/src/Components/Facility/FacilityCreate.tsx +++ b/src/Components/Facility/FacilityCreate.tsx @@ -570,7 +570,10 @@ export const FacilityCreate = (props: FacilityProps) => { }); capacityList = ( -
+
{
{t("doctors_list")}
-
{doctorList}
+
+ {doctorList} +
); diff --git a/src/Components/Facility/FacilityDoctorList.tsx b/src/Components/Facility/FacilityDoctorList.tsx index e6bbc7f7f3b..d9a8b0d1a37 100644 --- a/src/Components/Facility/FacilityDoctorList.tsx +++ b/src/Components/Facility/FacilityDoctorList.tsx @@ -83,7 +83,7 @@ export const FacilityDoctorList = (props: any) => { } return ( -
+
Doctors List
@@ -116,6 +116,6 @@ export const FacilityDoctorList = (props: any) => { /> )} -
+
); }; diff --git a/src/Components/Facility/FacilityHome.tsx b/src/Components/Facility/FacilityHome.tsx index e971f0f3b9d..3ad295a3df3 100644 --- a/src/Components/Facility/FacilityHome.tsx +++ b/src/Components/Facility/FacilityHome.tsx @@ -198,7 +198,7 @@ export const FacilityHome = (props: any) => { )} {editCoverImageTooltip}
-
+

{facilityData?.name}

{facilityData?.modified_date && ( {
-
+

Address

@@ -222,7 +222,7 @@ export const FacilityHome = (props: any) => {
-
+

Phone Number

@@ -270,7 +270,10 @@ export const FacilityHome = (props: any) => { ) && (

Available features

)} -
+
{facilityData?.features?.map( (feature: number, i: number) => FACILITY_FEATURE_TYPES.some((f) => f.id === feature) && ( @@ -426,7 +429,10 @@ export const FacilityHome = (props: any) => {

Oxygen Information

-
+
Date: Mon, 4 Dec 2023 17:40:19 +0530 Subject: [PATCH 27/27] Update cypress badge in README.md (#6788) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a6a2806558d..7f2c3e926bd 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=coronasafe_care_fe&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=coronasafe_care_fe) ![Code scanning - action](https://github.com/coronasafe/care_fe/workflows/Code%20scanning%20-%20action/badge.svg) ![OSSAR](https://github.com/coronasafe/care_fe/workflows/OSSAR/badge.svg) -[![Cypress Tests](https://github.com/coronasafe/care_fe/actions/workflows/cypress.yaml/badge.svg)](https://github.com/coronasafe/care_fe/actions/workflows/cypress.yaml) +[![Cypress Tests](https://img.shields.io/endpoint?url=https://cloud.cypress.io/badge/simple/wf7d2m/develop&style=flat&logo=cypress)](https://cloud.cypress.io/projects/wf7d2m/runs) ![Staging Release](https://github.com/coronasafe/care_fe/workflows/CARE%20Develop%20Registry/badge.svg) ![Production Release](https://github.com/coronasafe/care_fe/workflows/Production%20Release/badge.svg) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/200482ab117e4b5397ff3f5ae5719aa2)](https://www.codacy.com/gh/coronasafe/care_fe?utm_source=github.com&utm_medium=referral&utm_content=coronasafe/care_fe&utm_campaign=Badge_Grade)