diff --git a/.github/workflows/auto-testing-label.yml b/.github/workflows/auto-testing-label.yml index 6c6fc1002a0..98cfd46dab3 100644 --- a/.github/workflows/auto-testing-label.yml +++ b/.github/workflows/auto-testing-label.yml @@ -38,7 +38,7 @@ jobs: } if (isChangesRequired) { - await github.issues.createComment({ + await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: pr.number, diff --git a/cypress/e2e/facility_spec/FacilityHomepage.cy.ts b/cypress/e2e/facility_spec/FacilityHomepage.cy.ts index bc84aea4882..7db3b308a53 100644 --- a/cypress/e2e/facility_spec/FacilityHomepage.cy.ts +++ b/cypress/e2e/facility_spec/FacilityHomepage.cy.ts @@ -2,6 +2,7 @@ import { AssetPagination } from "../../pageobject/Asset/AssetPagination"; import FacilityPage from "../../pageobject/Facility/FacilityCreation"; import FacilityHome from "../../pageobject/Facility/FacilityHome"; +import FacilityNotify from "../../pageobject/Facility/FacilityNotify"; import LoginPage from "../../pageobject/Login/LoginPage"; import ManageUserPage from "../../pageobject/Users/ManageUserPage"; import { UserPage } from "../../pageobject/Users/UserSearch"; @@ -9,6 +10,7 @@ import { UserPage } from "../../pageobject/Users/UserSearch"; describe("Facility Homepage Function", () => { const loginPage = new LoginPage(); const facilityHome = new FacilityHome(); + const facilityNotify = new FacilityNotify(); const facilityPage = new FacilityPage(); const manageUserPage = new ManageUserPage(); const userPage = new UserPage(); @@ -22,6 +24,8 @@ describe("Facility Homepage Function", () => { const district = "Ernakulam"; const localBody = "Aikaranad"; const facilityType = "Private Hospital"; + const notificationErrorMsg = "Message cannot be empty"; + const notificationMessage = "Test Notification"; before(() => { loginPage.loginAsDistrictAdmin(); @@ -30,6 +34,7 @@ describe("Facility Homepage Function", () => { beforeEach(() => { cy.restoreLocalStorage(); + cy.clearLocalStorage(/filters--.+/); cy.awaitUrl("/facility"); }); @@ -41,9 +46,6 @@ describe("Facility Homepage Function", () => { facilityHome.clickViewCnsButton(); facilityHome.verifyCnsUrl(); facilityHome.navigateBack(); - // view notify button - facilityHome.clickFacilityNotifyButton(); - facilityHome.verifyAndCloseNotifyModal(); // view facility button facilityHome.clickViewFacilityDetails(); facilityPage.getFacilityName().should("be.visible"); @@ -134,6 +136,51 @@ describe("Facility Homepage Function", () => { facilityHome.verifyLiveMonitorUrl(); }); + it("Verify Notice Board Functionality", () => { + // search facility and verify it's loaded or not + manageUserPage.interceptFacilitySearchReq(); + manageUserPage.typeFacilitySearch(facilityName); + manageUserPage.verifyFacilitySearchReq(); + // verify facility name and card reflection + facilityNotify.verifyUrlContains("Dummy+Facility+40"); + facilityPage.verifyFacilityBadgeContent(facilityName); + manageUserPage.assertFacilityInCard(facilityName); + // send notification to a facility + facilityHome.clickFacilityNotifyButton(); + facilityNotify.verifyFacilityName(facilityName); + facilityNotify.fillNotifyText(notificationMessage); + facilityNotify.interceptPostNotificationReq(); + cy.submitButton("Notify"); + facilityNotify.verifyPostNotificationReq(); + cy.verifyNotification("Facility Notified"); + cy.closeNotification(); + cy.wait(2000); + // Verify the frontend error on empty message + facilityHome.clickFacilityNotifyButton(); + facilityNotify.verifyFacilityName(facilityName); + cy.submitButton("Notify"); + facilityNotify.verifyErrorMessage(notificationErrorMsg); + // close pop-up and verify + facilityHome.verifyAndCloseNotifyModal(); + // signout as district admin and login as a Nurse + loginPage.ensureLoggedIn(); + loginPage.clickSignOutBtn(); + loginPage.loginManuallyAsNurse(); + // Verify Notice Board Reflection + facilityNotify.interceptGetNotificationReq("MESSAGE"); + facilityNotify.visitNoticeBoard(); + facilityNotify.verifyGetNotificationReq(); + facilityNotify.verifyFacilityNoticeBoardMessage(notificationMessage); + facilityNotify.interceptGetNotificationReq(); + // Verify Sidebar Notification Reflection + facilityNotify.openNotificationSlide(); + facilityNotify.verifyGetNotificationReq(); + cy.verifyContentPresence("#notification-slide-msg", [notificationMessage]); + facilityNotify.closeNotificationSlide(); + loginPage.ensureLoggedIn(); + loginPage.clickSignOutBtn(); + }); + afterEach(() => { cy.saveLocalStorage(); }); diff --git a/cypress/e2e/patient_spec/PatientHomepage.cy.ts b/cypress/e2e/patient_spec/PatientHomepage.cy.ts index 32d869b8f50..53fb8732712 100644 --- a/cypress/e2e/patient_spec/PatientHomepage.cy.ts +++ b/cypress/e2e/patient_spec/PatientHomepage.cy.ts @@ -43,7 +43,6 @@ describe("Patient Homepage present functionalities", () => { patientHome.typePatientAdmitedBeforeDate(patientFromDate); patientHome.typePatientAdmitedAfterDate(patientToDate); patientHome.clickPatientFilterApply(); - patientHome.verifyTotalPatientCount("1"); // verify the badge and clear the count patientHome.verifyPatientCreatedBeforeDate(patientToDateBadge); patientHome.verifyPatientCreatedAfterDate(patientFromDateBadge); diff --git a/cypress/e2e/patient_spec/PatientInvestigation.cy.ts b/cypress/e2e/patient_spec/PatientInvestigation.cy.ts new file mode 100644 index 00000000000..380adf2c37e --- /dev/null +++ b/cypress/e2e/patient_spec/PatientInvestigation.cy.ts @@ -0,0 +1,40 @@ +import { PatientPage } from "pageobject/Patient/PatientCreation"; +import PatientInvestigation from "pageobject/Patient/PatientInvestigation"; + +import LoginPage from "../../pageobject/Login/LoginPage"; + +describe("Patient Investigation Creation from Patient consultation page", () => { + const loginPage = new LoginPage(); + const patientPage = new PatientPage(); + const patientInvestigation = new PatientInvestigation(); + const patientName = "Dummy Patient 12"; + + before(() => { + loginPage.loginAsDistrictAdmin(); + cy.saveLocalStorage(); + }); + + beforeEach(() => { + cy.restoreLocalStorage(); + cy.clearLocalStorage(/filters--.+/); + cy.awaitUrl("/patients"); + }); + + it("Create a investigation for a patient and verify its reflection", () => { + patientPage.visitPatient(patientName); + patientInvestigation.clickInvestigationTab(); + patientInvestigation.clickLogLabResults(); + patientInvestigation.selectInvestigationOption([ + "Haematology", + "Urine Test", + ]); + cy.submitButton("Save Investigation"); + cy.verifyNotification("Please Enter at least one value"); + cy.closeNotification(); + // Temporary workflow for investigation since we dont have dummy data and moving away from existing module + }); + + afterEach(() => { + cy.saveLocalStorage(); + }); +}); diff --git a/cypress/pageobject/Facility/FacilityHome.ts b/cypress/pageobject/Facility/FacilityHome.ts index dea7de0e7b6..30f51052370 100644 --- a/cypress/pageobject/Facility/FacilityHome.ts +++ b/cypress/pageobject/Facility/FacilityHome.ts @@ -35,7 +35,8 @@ class FacilityHome { } clickFacilityNotifyButton() { - cy.get("#facility-notify").first().click(); + cy.get("#facility-notify", { timeout: 10000 }).should("be.visible"); + cy.get("#facility-notify").focus().click(); } clickLiveMonitorButton() { diff --git a/cypress/pageobject/Facility/FacilityNotify.ts b/cypress/pageobject/Facility/FacilityNotify.ts new file mode 100644 index 00000000000..08c44b32e84 --- /dev/null +++ b/cypress/pageobject/Facility/FacilityNotify.ts @@ -0,0 +1,58 @@ +export default class FacilityNotify { + verifyFacilityName(facilityName: string) { + cy.verifyContentPresence("#notify-facility-name", [facilityName]); + } + + verifyErrorMessage(errorMessage: string) { + cy.verifyContentPresence(".error-text", [errorMessage]); + } + + fillNotifyText(message: string) { + cy.get("#NotifyModalMessageInput").scrollIntoView(); + cy.get("#NotifyModalMessageInput").click().type(message); + } + + verifyFacilityNoticeBoardMessage(message: string) { + cy.get("#notification-message", { timeout: 10000 }).should("be.visible"); + cy.verifyContentPresence("#notification-message", [message]); + } + + openNotificationSlide() { + cy.get("#notification-slide-btn").should("be.visible").click(); + } + + closeNotificationSlide() { + cy.get("#close-slide-over").should("be.visible").click(); + } + + visitNoticeBoard() { + cy.get("a[href='/notice_board']").should("be.visible").click(); + } + + visitNotificationSideBar() { + cy.get("#notification-slide-btn").should("be.visible").click(); + } + + verifyUrlContains(substring: string) { + cy.url().should("include", substring); + } + + interceptPostNotificationReq() { + cy.intercept("POST", "**/api/v1/notification/notify").as("notifyFacility"); + } + + verifyPostNotificationReq() { + cy.wait("@notifyFacility").its("response.statusCode").should("eq", 204); + } + + interceptGetNotificationReq(event: string = "") { + cy.intercept( + "GET", + `**/api/v1/notification/?offset=0&event=${event}&*=SYSTEM`, + ).as("getNotifications"); + } + + verifyGetNotificationReq() { + cy.wait("@getNotifications").its("response.statusCode").should("eq", 200); + } +} diff --git a/cypress/pageobject/Login/LoginPage.ts b/cypress/pageobject/Login/LoginPage.ts index cd5230a7772..38b8aeee2af 100644 --- a/cypress/pageobject/Login/LoginPage.ts +++ b/cypress/pageobject/Login/LoginPage.ts @@ -34,6 +34,10 @@ class LoginPage { cy.get("#sign-out-button").scrollIntoView(); cy.get("#sign-out-button").contains("Sign Out").should("exist"); } + + clickSignOutBtn(): void { + cy.verifyAndClickElement("#sign-out-button", "Sign Out"); + } } export default LoginPage; diff --git a/cypress/pageobject/Patient/PatientInvestigation.ts b/cypress/pageobject/Patient/PatientInvestigation.ts index 8f73cf908bc..a9f8f38435a 100644 --- a/cypress/pageobject/Patient/PatientInvestigation.ts +++ b/cypress/pageobject/Patient/PatientInvestigation.ts @@ -1,11 +1,9 @@ class PatientInvestigation { clickAddInvestigation() { - cy.get("#investigation").scrollIntoView(); cy.verifyAndClickElement("#investigation", "Add Investigation"); } clickInvestigationTab() { - cy.get("#consultation_tab_nav").scrollIntoView(); cy.verifyAndClickElement("#consultation_tab_nav", "Investigations"); } @@ -19,6 +17,14 @@ class PatientInvestigation { cy.get("#investigation-checkbox").click(); } + selectInvestigationOption(options: string[]) { + cy.clickAndMultiSelectOption("#investigations", options); + } + + clickLogLabResults() { + cy.verifyAndClickElement("#log-lab-results", "Log Lab Results"); + } + selectInvestigationFrequency(frequency: string) { cy.get("#investigation-frequency").click(); cy.contains("button", frequency).should("be.visible").click(); diff --git a/cypress/pageobject/Users/ManageUserPage.ts b/cypress/pageobject/Users/ManageUserPage.ts index 470862693a8..a3a6e72fbc3 100644 --- a/cypress/pageobject/Users/ManageUserPage.ts +++ b/cypress/pageobject/Users/ManageUserPage.ts @@ -99,6 +99,14 @@ export class ManageUserPage { cy.get("#search").click().type(facilityName); } + interceptFacilitySearchReq() { + cy.intercept("GET", "**/api/v1/facility/**").as("searchFacility"); + } + + verifyFacilitySearchReq() { + cy.wait("@searchFacility").its("response.statusCode").should("eq", 200); + } + assertFacilityInCard(facilityName: string) { cy.get("#facility-name-card").should("contain", facilityName); } diff --git a/src/Utils/request/api.tsx b/src/Utils/request/api.tsx index 441b9a3d8c8..e1777364b3f 100644 --- a/src/Utils/request/api.tsx +++ b/src/Utils/request/api.tsx @@ -1065,11 +1065,6 @@ const routes = { TBody: Type(), TRes: Type(), }, - deleteShiftRecord: { - path: "/api/v1/shift/{id}/", - method: "DELETE", - TRes: Type<{ detail: string }>(), - }, listShiftRequests: { path: "/api/v1/shift/", method: "GET", @@ -1241,13 +1236,6 @@ const routes = { TRes: Type(), TBody: Type>(), }, - deleteResourceRecord: { - path: "/api/v1/resource/{id}/", - method: "DELETE", - TRes: Type<{ - detail?: string; - }>(), - }, listResourceRequests: { path: "/api/v1/resource/", method: "GET", diff --git a/src/components/Common/Sidebar/SidebarItem.tsx b/src/components/Common/Sidebar/SidebarItem.tsx index 31f64754ffd..7262c6a103b 100644 --- a/src/components/Common/Sidebar/SidebarItem.tsx +++ b/src/components/Common/Sidebar/SidebarItem.tsx @@ -9,6 +9,7 @@ import useAppHistory from "@/hooks/useAppHistory"; export type SidebarIcon = React.ReactNode; type SidebarItemProps = { + id?: string; ref?: React.Ref; text: string; icon: SidebarIcon; @@ -31,6 +32,7 @@ const SidebarItemBase = forwardRef( return ( {
diff --git a/src/components/Facility/ConsultationForm.tsx b/src/components/Facility/ConsultationForm.tsx index 34cc5973832..d6d94593049 100644 --- a/src/components/Facility/ConsultationForm.tsx +++ b/src/components/Facility/ConsultationForm.tsx @@ -936,7 +936,7 @@ export const ConsultationForm = ({ facilityId, patientId, id }: Props) => {
{ diff --git a/src/components/Facility/FacilityCard.tsx b/src/components/Facility/FacilityCard.tsx index d91bd624a88..0d9c5678d4c 100644 --- a/src/components/Facility/FacilityCard.tsx +++ b/src/components/Facility/FacilityCard.tsx @@ -185,7 +185,10 @@ export const FacilityCard = (props: { + Notify: {facility.name} } diff --git a/src/components/Facility/Investigations/ViewInvestigations.tsx b/src/components/Facility/Investigations/ViewInvestigations.tsx index 162fd6d87e0..3bd80b0bb28 100644 --- a/src/components/Facility/Investigations/ViewInvestigations.tsx +++ b/src/components/Facility/Investigations/ViewInvestigations.tsx @@ -62,6 +62,7 @@ export default function ViewInvestigations(props: {
navigate( `/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}/investigation/${investigationSession.session_external_id}`, @@ -73,6 +74,7 @@ export default function ViewInvestigations(props: { {t("view")} navigate( `/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}/investigation/${investigationSession.session_external_id}/print`, diff --git a/src/components/Facility/PatientNotesSlideover.tsx b/src/components/Facility/PatientNotesSlideover.tsx index 05deef36b91..89d38a5f168 100644 --- a/src/components/Facility/PatientNotesSlideover.tsx +++ b/src/components/Facility/PatientNotesSlideover.tsx @@ -161,15 +161,19 @@ export default function PatientNotesSlideover(props: PatientNotesProps) { id="expand_doctor_notes" className={classNames( "tooltip flex h-8 w-8 cursor-pointer items-center justify-center rounded bg-primary-800 text-secondary-100 text-opacity-70 hover:bg-primary-700 hover:text-opacity-100", - show && "rotate-180", )} onClick={() => setShow(!show)} > - + {t("minimize")}
@@ -181,7 +185,12 @@ export default function PatientNotesSlideover(props: PatientNotesProps) { icon="l-times" className="tooltip text-lg transition-all delay-150 duration-300 ease-out" /> - + {t("close")}
diff --git a/src/components/Form/SearchInput.tsx b/src/components/Form/SearchInput.tsx index bbf59305a0a..69334c0f4db 100644 --- a/src/components/Form/SearchInput.tsx +++ b/src/components/Form/SearchInput.tsx @@ -87,7 +87,7 @@ const SearchInput = ({ className={className} leading={ props.leading || ( - + ) } trailing={ diff --git a/src/components/Medicine/MedicineAdministrationSheet/AdministrationTable.tsx b/src/components/Medicine/MedicineAdministrationSheet/AdministrationTable.tsx index 86db7353832..b1eac32409d 100644 --- a/src/components/Medicine/MedicineAdministrationSheet/AdministrationTable.tsx +++ b/src/components/Medicine/MedicineAdministrationSheet/AdministrationTable.tsx @@ -31,17 +31,17 @@ export default function MedicineAdministrationTable({ -
- {t("medicine")} - -

Dosage &

-

- {prescriptions[0]?.dosage_type !== "PRN" - ? "Frequency" - : "Indicator"} -

-
-
+ {t("medicine")} + + + +

{t("dosage")} &

+

+ {prescriptions[0]?.dosage_type !== "PRN" + ? t("frequency") + : t("indicator")} +

+
diff --git a/src/components/Medicine/MedicineAdministrationSheet/AdministrationTableRow.tsx b/src/components/Medicine/MedicineAdministrationSheet/AdministrationTableRow.tsx index d08506d7fbe..7544f405b08 100644 --- a/src/components/Medicine/MedicineAdministrationSheet/AdministrationTableRow.tsx +++ b/src/components/Medicine/MedicineAdministrationSheet/AdministrationTableRow.tsx @@ -59,6 +59,25 @@ export default function MedicineAdministrationTableRow({ key: `${prescription.last_administration?.administered_date}`, }, ); + const DosageFrequencyInfo = () => ( +
+
+ {prescription.dosage_type !== "TITRATED" ? ( +

{prescription.base_dosage}

+ ) : ( +

+ {prescription.base_dosage} - {prescription.target_dosage} +

+ )} + +

+ {prescription.dosage_type !== "PRN" + ? t("PRESCRIPTION_FREQUENCY_" + prescription.frequency) + : prescription.indicator} +

+
+
+ ); return ( <> @@ -216,24 +235,14 @@ export default function MedicineAdministrationTableRow({ {prescription.medicine_object?.generic} - -
- {prescription.dosage_type !== "TITRATED" ? ( -

{prescription.base_dosage}

- ) : ( -

- {prescription.base_dosage} - {prescription.target_dosage} -

- )} - -

- {prescription.dosage_type !== "PRN" - ? t("PRESCRIPTION_FREQUENCY_" + prescription.frequency) - : prescription.indicator} -

+
+
+ + + diff --git a/src/components/Notifications/NoticeBoard.tsx b/src/components/Notifications/NoticeBoard.tsx index e4472107c8f..e1f00075000 100644 --- a/src/components/Notifications/NoticeBoard.tsx +++ b/src/components/Notifications/NoticeBoard.tsx @@ -26,7 +26,9 @@ export const NoticeBoard = () => { className="overflow-hidden rounded shadow-md" >
-
{item.message}
+
+ {item.message} +
{formatName(item.caused_by)} -{" "} diff --git a/src/components/Notifications/NotificationsList.tsx b/src/components/Notifications/NotificationsList.tsx index 5d88cc8d603..0808877a444 100644 --- a/src/components/Notifications/NotificationsList.tsx +++ b/src/components/Notifications/NotificationsList.tsx @@ -115,7 +115,9 @@ const NotificationTile = ({ />
-
{result.message}
+
+ {result.message} +
{formatDateTime(result.created_date)} @@ -474,6 +476,7 @@ export default function NotificationsList({ <> setOpen(!open)} icon={} badgeCount={unreadCount} diff --git a/src/components/Resource/ResourceDetails.tsx b/src/components/Resource/ResourceDetails.tsx index 2495c64433d..d77bdcc3fea 100644 --- a/src/components/Resource/ResourceDetails.tsx +++ b/src/components/Resource/ResourceDetails.tsx @@ -4,21 +4,16 @@ import { useState } from "react"; import CareIcon from "@/CAREUI/icons/CareIcon"; import ButtonV2 from "@/components/Common/ButtonV2"; -import ConfirmDialog from "@/components/Common/ConfirmDialog"; import Loading from "@/components/Common/Loading"; import Page from "@/components/Common/Page"; import CommentSection from "@/components/Resource/ResourceCommentSection"; -import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; import useQuery from "@/Utils/request/useQuery"; import { classNames, formatDateTime, formatName } from "@/Utils/utils"; export default function ResourceDetails(props: { id: string }) { const [isPrintMode, setIsPrintMode] = useState(false); - const [openDeleteResourceDialog, setOpenDeleteResourceDialog] = - useState(false); const { data, loading } = useQuery(routes.getResourceDetails, { pathParams: { id: props.id }, onResponse: ({ res, data }) => { @@ -27,25 +22,6 @@ export default function ResourceDetails(props: { id: string }) { } }, }); - - const handleResourceDelete = async () => { - setOpenDeleteResourceDialog(true); - const { res, data } = await request(routes.deleteResourceRecord, { - pathParams: { id: props.id }, - }); - if (res?.status === 204) { - Notification.Success({ - msg: "Resource record has been deleted successfully.", - }); - } else { - Notification.Error({ - msg: "Error while deleting Resource: " + (data?.detail || ""), - }); - } - - navigate("/resource"); - }; - const showFacilityCard = (facilityData: any) => { return (
@@ -329,28 +305,6 @@ export default function ResourceDetails(props: { id: string }) {
{data.reason || "--"}
- -
-
- setOpenDeleteResourceDialog(true)} - > - Delete Record - - - setOpenDeleteResourceDialog(false)} - onConfirm={handleResourceDelete} - /> -
-

Audit Log

diff --git a/src/components/Shifting/ShiftDetails.tsx b/src/components/Shifting/ShiftDetails.tsx index d5b251eeb8d..8e85fda3d19 100644 --- a/src/components/Shifting/ShiftDetails.tsx +++ b/src/components/Shifting/ShiftDetails.tsx @@ -9,7 +9,6 @@ import RecordMeta from "@/CAREUI/display/RecordMeta"; import CareIcon from "@/CAREUI/icons/CareIcon"; import ButtonV2 from "@/components/Common/ButtonV2"; -import ConfirmDialog from "@/components/Common/ConfirmDialog"; import Loading from "@/components/Common/Loading"; import Page from "@/components/Common/Page"; import { ConsultationModel } from "@/components/Facility/models"; @@ -22,16 +21,13 @@ import { SHIFTING_CHOICES_WARTIME, } from "@/common/constants"; -import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; import useQuery from "@/Utils/request/useQuery"; import { formatDateTime, formatName, formatPatientAge } from "@/Utils/utils"; export default function ShiftDetails(props: { id: string }) { const [isPrintMode, setIsPrintMode] = useState(false); const [isCopied, setIsCopied] = useState(false); - const [openDeleteShiftDialog, setOpenDeleteShiftDialog] = useState(false); const { t } = useTranslation(); const shiftStatusOptions = careConfig.wartimeShifting @@ -41,26 +37,6 @@ export default function ShiftDetails(props: { id: string }) { const { data, loading } = useQuery(routes.getShiftDetails, { pathParams: { id: props.id }, }); - - const handleShiftDelete = async () => { - setOpenDeleteShiftDialog(true); - - const { res, data } = await request(routes.deleteShiftRecord, { - pathParams: { id: props.id }, - }); - if (res?.status == 204) { - Notification.Success({ - msg: t("shifting_deleted"), - }); - } else { - Notification.Error({ - msg: t("error_deleting_shifting") + (data?.detail || ""), - }); - } - - navigate("/shifting"); - }; - const showCopyToclipBoard = (data: any) => { return ( @@ -732,25 +708,6 @@ export default function ShiftDetails(props: { id: string }) { time={data?.modified_date} /> - -
-
- setOpenDeleteShiftDialog(true)} - > - {t("delete_record")} - - setOpenDeleteShiftDialog(false)} - onConfirm={handleShiftDelete} - /> -
-