diff --git a/cypress/e2e/assets_spec/AssetHomepage.cy.ts b/cypress/e2e/assets_spec/AssetHomepage.cy.ts index 67ad50e832f..dfb3249c243 100644 --- a/cypress/e2e/assets_spec/AssetHomepage.cy.ts +++ b/cypress/e2e/assets_spec/AssetHomepage.cy.ts @@ -1,9 +1,9 @@ import { advanceFilters } from "pageobject/utils/advanceFilterHelpers"; +import { pageNavigation } from "pageobject/utils/paginationHelpers"; import { v4 as uuidv4 } from "uuid"; import { AssetPage } from "../../pageobject/Asset/AssetCreation"; import { AssetFilters } from "../../pageobject/Asset/AssetFilters"; -import { AssetPagination } from "../../pageobject/Asset/AssetPagination"; import { AssetQRScanPage } from "../../pageobject/Asset/AssetQRScan"; import { AssetSearchPage } from "../../pageobject/Asset/AssetSearch"; import LoginPage from "../../pageobject/Login/LoginPage"; @@ -11,7 +11,6 @@ import LoginPage from "../../pageobject/Login/LoginPage"; describe("Asset Tab", () => { const assetSearchPage = new AssetSearchPage(); const assetQRScanPage = new AssetQRScanPage(); - const assetPagination = new AssetPagination(); const assetFilters = new AssetFilters(); const assetPage = new AssetPage(); const loginPage = new LoginPage(); @@ -79,10 +78,10 @@ describe("Asset Tab", () => { // Verify the pagination in the page it("Next/Previous Page", () => { - assetPagination.navigateToNextPage(); - assetPagination.verifyNextUrl(); - assetPagination.navigateToPreviousPage(); - assetPagination.verifyPreviousUrl(); + pageNavigation.navigateToNextPage(); + pageNavigation.verifyCurrentPageNumber(2); + pageNavigation.navigateToPreviousPage(); + pageNavigation.verifyCurrentPageNumber(1); }); it("Import new asset", () => { diff --git a/cypress/e2e/facility_spec/FacilityCreation.cy.ts b/cypress/e2e/facility_spec/FacilityCreation.cy.ts index 5e644238999..5fd988480fc 100644 --- a/cypress/e2e/facility_spec/FacilityCreation.cy.ts +++ b/cypress/e2e/facility_spec/FacilityCreation.cy.ts @@ -317,6 +317,39 @@ describe("Facility Creation", () => { ); }); + it("Should display error when district admin tries to create facility in a different district", () => { + facilityPage.visitCreateFacilityPage(); + facilityPage.fillFacilityName(facilityName); + facilityPage.selectFacilityType(facilityType); + facilityPage.fillPincode("682001"); + facilityPage.selectStateOnPincode("Kerala"); + facilityPage.selectDistrictOnPincode("Kottayam"); + facilityPage.selectLocalBody("Arpookara"); + facilityPage.selectWard("5"); + facilityPage.fillAddress(facilityAddress); + facilityPage.fillPhoneNumber(facilityNumber); + facilityPage.submitForm(); + facilityPage.verifyErrorNotification( + "You do not have permission to perform this action.", + ); + }); + + it("Access Restriction for Non-Admin Users to facility creation page", () => { + const nonAdminLoginMethods = [ + loginPage.loginAsDevDoctor.bind(loginPage), + loginPage.loginAsStaff.bind(loginPage), + ]; + + nonAdminLoginMethods.forEach((loginMethod) => { + loginMethod(); + cy.visit("/facility/create"); + facilityPage.verifyErrorNotification( + "You don't have permission to perform this action. Contact the admin", + ); + cy.clearCookies(); + }); + }); + afterEach(() => { cy.saveLocalStorage(); }); diff --git a/cypress/e2e/facility_spec/FacilityHomepage.cy.ts b/cypress/e2e/facility_spec/FacilityHomepage.cy.ts index 08ea39ee2c9..f4c7aaa90a0 100644 --- a/cypress/e2e/facility_spec/FacilityHomepage.cy.ts +++ b/cypress/e2e/facility_spec/FacilityHomepage.cy.ts @@ -1,5 +1,6 @@ // FacilityCreation -import { AssetPagination } from "../../pageobject/Asset/AssetPagination"; +import { pageNavigation } from "pageobject/utils/paginationHelpers"; + import FacilityPage from "../../pageobject/Facility/FacilityCreation"; import FacilityHome from "../../pageobject/Facility/FacilityHome"; import FacilityNotify from "../../pageobject/Facility/FacilityNotify"; @@ -15,7 +16,6 @@ describe("Facility Homepage Function", () => { const facilityPage = new FacilityPage(); const manageUserPage = new ManageUserPage(); const userPage = new UserPage(); - const assetPagination = new AssetPagination(); const facilitiesAlias = "downloadFacilitiesCSV"; const doctorsAlias = "downloadDoctorsCSV"; const triagesAlias = "downloadTriagesCSV"; @@ -83,10 +83,10 @@ describe("Facility Homepage Function", () => { it("Search a facility in homepage and pagination", () => { // pagination of the facility page - assetPagination.navigateToNextPage(); - assetPagination.verifyNextUrl(); - assetPagination.navigateToPreviousPage(); - assetPagination.verifyPreviousUrl(); + pageNavigation.navigateToNextPage(); + pageNavigation.verifyCurrentPageNumber(2); + pageNavigation.navigateToPreviousPage(); + pageNavigation.verifyCurrentPageNumber(1); // search for a facility manageUserPage.typeFacilitySearch(facilityName); facilityPage.verifyFacilityBadgeContent(facilityName); @@ -152,7 +152,7 @@ describe("Facility Homepage Function", () => { facilityNotify.verifyFacilityName(facilityName); facilityNotify.fillNotifyText(notificationMessage); facilityNotify.interceptPostNotificationReq(); - cy.submitButton("Notify"); + cy.clickSubmitButton("Notify"); facilityNotify.verifyPostNotificationReq(); cy.verifyNotification("Facility Notified"); cy.closeNotification(); @@ -160,7 +160,7 @@ describe("Facility Homepage Function", () => { // Verify the frontend error on empty message facilityHome.clickFacilityNotifyButton(); facilityNotify.verifyFacilityName(facilityName); - cy.submitButton("Notify"); + cy.clickSubmitButton("Notify"); facilityNotify.verifyErrorMessage(notificationErrorMsg); // close pop-up and verify facilityHome.verifyAndCloseNotifyModal(); diff --git a/cypress/e2e/facility_spec/FacilityLocation.cy.ts b/cypress/e2e/facility_spec/FacilityLocation.cy.ts index b700f5c75ae..9ac85e9ba4c 100644 --- a/cypress/e2e/facility_spec/FacilityLocation.cy.ts +++ b/cypress/e2e/facility_spec/FacilityLocation.cy.ts @@ -1,7 +1,7 @@ +import { pageNavigation } from "pageobject/utils/paginationHelpers"; import { v4 as uuidv4 } from "uuid"; import { AssetPage } from "../../pageobject/Asset/AssetCreation"; -import { AssetPagination } from "../../pageobject/Asset/AssetPagination"; import FacilityPage from "../../pageobject/Facility/FacilityCreation"; import FacilityHome from "../../pageobject/Facility/FacilityHome"; import FacilityLocation from "../../pageobject/Facility/FacilityLocation"; @@ -12,7 +12,6 @@ describe("Location Management Section", () => { const userCreationPage = new UserCreationPage(); const facilityPage = new FacilityPage(); const facilityLocation = new FacilityLocation(); - const assetPagination = new AssetPagination(); const facilityHome = new FacilityHome(); const EXPECTED_LOCATION_ERROR_MESSAGES = [ @@ -172,8 +171,8 @@ describe("Location Management Section", () => { facilityLocation.setMultipleBeds(numberOfModifiedBeds); assetPage.clickassetupdatebutton(); // pagination - assetPagination.navigateToNextPage(); - assetPagination.navigateToPreviousPage(); + pageNavigation.navigateToNextPage(); + pageNavigation.navigateToPreviousPage(); facilityLocation.closeNotification(); }); @@ -194,14 +193,14 @@ describe("Location Management Section", () => { facilityLocation.clickAddNewLocationButton(); facilityLocation.enterLocationName("Test Location with Beds"); facilityLocation.selectLocationType("OTHER"); - cy.submitButton("Add Location"); + cy.clickSubmitButton("Add Location"); cy.verifyNotification("Location created successfully"); cy.closeNotification(); facilityLocation.clickManageBedButton(); facilityLocation.clickAddBedButton(); facilityLocation.enterBedName("Bed 1"); facilityLocation.selectBedType("Regular"); - cy.submitButton("Add Bed(s)"); + cy.clickSubmitButton("Add Bed(s)"); cy.verifyNotification("1 Bed created successfully"); cy.closeNotification(); facilityLocation.loadLocationManagementPage("Dummy Shifting Center"); diff --git a/cypress/e2e/hcx_spec/HcxClaims.cy.ts b/cypress/e2e/hcx_spec/HcxClaims.cy.ts index 2c4a6b45df9..b698bb7ffd8 100644 --- a/cypress/e2e/hcx_spec/HcxClaims.cy.ts +++ b/cypress/e2e/hcx_spec/HcxClaims.cy.ts @@ -11,7 +11,7 @@ describe("HCX Claims configuration and approval workflow", () => { const patientConsultationPage = new PatientConsultationPage(); const patientInsurance = new PatientInsurance(); const hcxClaims = new HcxClaims(); - const hcxPatientName = "Dummy Patient 14"; + const hcxPatientName = "Dummy Patient Thirteen"; const firstInsuranceIdentifier = "insurance-details-0"; const patientMemberId = "001"; const patientPolicyId = "100"; @@ -48,7 +48,7 @@ describe("HCX Claims configuration and approval workflow", () => { firstInsuranceIdentifier, patientInsurerName, ); - cy.submitButton("Save Details"); + cy.clickSubmitButton("Save Details"); cy.verifyNotification("Patient updated successfully"); cy.closeNotification(); // Navigate to Consultation View and capture dynamic consultation ID @@ -80,6 +80,8 @@ describe("HCX Claims configuration and approval workflow", () => { // Raise a HCX Pre-auth patientConsultationPage.clickManagePatientButton(); patientConsultationPage.clickClaimsButton(); + cy.verifyAndClickElement("#edit-insurance-policy", "Edit Insurance Policy"); + cy.clickCancelButton(); hcxClaims.selectEligiblePolicy(patientInsurerName); hcxClaims.verifyPolicyEligibility(); cy.verifyNotification("Checking Policy Eligibility"); diff --git a/cypress/e2e/patient_spec/PatientBedManagement.cy.ts b/cypress/e2e/patient_spec/PatientBedManagement.cy.ts index 65adf131c87..94f0869db9b 100644 --- a/cypress/e2e/patient_spec/PatientBedManagement.cy.ts +++ b/cypress/e2e/patient_spec/PatientBedManagement.cy.ts @@ -11,8 +11,8 @@ describe("Patient swtich bed functionality", () => { const switchBedOne = "Dummy Bed 4"; const switchBedTwo = "Dummy Bed 1"; const switchBedThree = "Dummy Bed 7"; - const switchPatientOne = "Dummy Patient 6"; - const switchPatientTwo = "Dummy Patient 7"; + const switchPatientOne = "Dummy Patient Six"; + const switchPatientTwo = "Dummy Patient Seven"; before(() => { loginPage.loginAsDistrictAdmin(); diff --git a/cypress/e2e/patient_spec/PatientConsultationCreation.cy.ts b/cypress/e2e/patient_spec/PatientConsultationCreation.cy.ts index 4c84f7fad8f..3eacd9b718f 100644 --- a/cypress/e2e/patient_spec/PatientConsultationCreation.cy.ts +++ b/cypress/e2e/patient_spec/PatientConsultationCreation.cy.ts @@ -91,11 +91,11 @@ describe("Patient Consultation in multiple combination", () => { patientTreatmentPlan.typePatientGeneralInstruction(generalInstruction); patientTreatmentPlan.typeSpecialInstruction(specialInstruction); patientTreatmentPlan.fillTreatingPhysican(doctorName); - cy.submitButton("Create Consultation"); + cy.clickSubmitButton("Create Consultation"); // the above submit should fail as IP number is missing patientConsultationPage.typePatientNumber(patientIpNumber); patientConsultationPage.selectBed("Dummy Bed 6"); - cy.submitButton("Create Consultation"); + cy.clickSubmitButton("Create Consultation"); cy.verifyNotification("Consultation created successfully"); // Below code for the prescription module only present while creating a new consultation patientPrescription.clickAddPrescription(); @@ -104,7 +104,7 @@ describe("Patient Consultation in multiple combination", () => { patientPrescription.selectMedicine(medicineOne); patientPrescription.enterDosage("3"); patientPrescription.selectDosageFrequency("Twice daily"); - cy.submitButton("Submit"); + cy.clickSubmitButton("Submit"); cy.wait(2000); cy.verifyNotification("Medicine prescribed"); patientPrescription.clickReturnToDashboard(); @@ -189,7 +189,7 @@ describe("Patient Consultation in multiple combination", () => { "#encounter_date", "220220241230", ); - cy.submitButton("Create Consultation"); + cy.clickSubmitButton("Create Consultation"); cy.verifyNotification( "Create Diagnoses - Atleast one diagnosis is required", ); @@ -198,7 +198,7 @@ describe("Patient Consultation in multiple combination", () => { diagnosis4, "add-icd11-diagnosis-as-confirmed", ); - cy.submitButton("Create Consultation"); + cy.clickSubmitButton("Create Consultation"); cy.verifyNotification("Consultation created successfully"); // verify the data and death report patientConsultationPage.verifyTextInConsultation( @@ -215,7 +215,7 @@ describe("Patient Consultation in multiple combination", () => { "#cause_of_death", "Cause of Death", ); - cy.submitButton("Preview"); + cy.clickSubmitButton("Preview"); cy.preventPrint(); patientDeathReport.clickPrintDeathReport(); cy.get("@verifyPrevent").should("be.called"); @@ -261,7 +261,7 @@ describe("Patient Consultation in multiple combination", () => { // add telemedicine patientTreatmentPlan.clickTelemedicineCheckbox(); patientTreatmentPlan.assignTelemedicineDoctor(doctorName); - cy.submitButton("Create Consultation"); + cy.clickSubmitButton("Create Consultation"); cy.verifyNotification("Consultation created successfully"); // verify the data reflection - patientConsultationPage.verifyTextInConsultation( @@ -312,7 +312,7 @@ describe("Patient Consultation in multiple combination", () => { patientTreatmentPlan.typePatientGeneralInstruction(generalInstruction); // no review after and no action patientTreatmentPlan.fillTreatingPhysican(doctorName); - cy.submitButton("Create Consultation"); + cy.clickSubmitButton("Create Consultation"); cy.verifyNotification("Patient discharged successfully"); // verify the Discharge Reason, Diagnosis, treatment physican patientConsultationPage.verifyTextInConsultation( @@ -364,18 +364,18 @@ describe("Patient Consultation in multiple combination", () => { patientTreatmentPlan.typePatientGeneralInstruction(generalInstruction); patientTreatmentPlan.fillTreatingPhysican(doctorName); // no review after and no action - cy.submitButton("Create Consultation"); + cy.clickSubmitButton("Create Consultation"); // Create a shifting request cy.closeNotification(); shiftCreation.typeCurrentFacilityPerson("Current Facility Person"); shiftCreation.typeCurrentFacilityPhone("9999999999"); shiftCreation.typeShiftReason("reason for shift"); - cy.submitButton("Submit"); + cy.clickSubmitButton("Submit"); cy.verifyNotification("Shift request created successfully"); }); it("Edit created consultation to existing patient", () => { - patientPage.visitPatient("Dummy Patient 13"); + patientPage.visitPatient("Dummy Patient Thirteen"); patientConsultationPage.clickEditConsultationButton(); patientConsultationPage.typePatientIllnessHistory("editted"); patientConsultationPage.selectPatientDiagnosis( @@ -386,7 +386,7 @@ describe("Patient Consultation in multiple combination", () => { cy.get("#condition-verification-status-menu").click(); cy.get("#add-icd11-diagnosis-as-entered-in-error").click(); }); - cy.submitButton("Update Consultation"); + cy.clickSubmitButton("Update Consultation"); cy.verifyNotification("Consultation updated successfully"); cy.get("#diagnoses-view").should("not.contain.text", diagnosis5); patientConsultationPage.verifyTextInConsultation( diff --git a/cypress/e2e/patient_spec/PatientConsultationDischarge.cy.ts b/cypress/e2e/patient_spec/PatientConsultationDischarge.cy.ts index e2403fd56bd..9e234c860da 100644 --- a/cypress/e2e/patient_spec/PatientConsultationDischarge.cy.ts +++ b/cypress/e2e/patient_spec/PatientConsultationDischarge.cy.ts @@ -31,11 +31,11 @@ describe("Patient Discharge based on multiple reason", () => { }); it("Discharge a LAMA patient in the consultation", () => { - patientPage.visitPatient("Dummy Patient 12"); + patientPage.visitPatient("Discharge Patient One"); patientDischarge.clickDischarge(); patientDischarge.selectDischargeReason(patientDischargeReason4); - cy.submitButton("Confirm Discharge"); - cy.submitButton("Acknowledge & Submit"); + cy.clickSubmitButton("Confirm Discharge"); + cy.clickSubmitButton("Acknowledge & Submit"); cy.verifyNotification("Patient Discharged Successfully"); cy.closeNotification(); // Verify the consultation dashboard reflection @@ -47,13 +47,13 @@ describe("Patient Discharge based on multiple reason", () => { }); it("Discharge a expired patient in the consultation", () => { - patientPage.visitPatient("Dummy Patient 13"); + patientPage.visitPatient("Discharge Patient Two"); patientDischarge.clickDischarge(); patientDischarge.selectDischargeReason(patientDischargeReason3); patientDischarge.typeDischargeNote(patientDeathCause); patientDischarge.typeDoctorName(doctorName); - cy.submitButton("Confirm Discharge"); - cy.submitButton("Acknowledge & Submit"); + cy.clickSubmitButton("Confirm Discharge"); + cy.clickSubmitButton("Acknowledge & Submit"); cy.verifyNotification("Patient Discharged Successfully"); cy.closeNotification(); // Verify the consultation dashboard reflection @@ -67,7 +67,7 @@ describe("Patient Discharge based on multiple reason", () => { }); it("Discharge patient with referred reason to a facility", () => { - patientPage.visitPatient("Dummy Patient 16"); + patientPage.visitPatient("Discharge Patient Three"); patientDischarge.clickDischarge(); patientDischarge.selectDischargeReason(patientDischargeReason2); patientDischarge.typeDischargeNote(patientDischargeAdvice); @@ -77,8 +77,8 @@ describe("Patient Discharge based on multiple reason", () => { // select a non-registered facility and perform the discharge patientDischarge.typeReferringFacility(referringFreetextFacility); cy.wait(2000); - cy.submitButton("Confirm Discharge"); - cy.submitButton("Acknowledge & Submit"); + cy.clickSubmitButton("Confirm Discharge"); + cy.clickSubmitButton("Acknowledge & Submit"); cy.wait(2000); cy.verifyNotification("Patient Discharged Successfully"); cy.closeNotification(); @@ -93,7 +93,7 @@ describe("Patient Discharge based on multiple reason", () => { }); it("Discharge a recovered patient with all relevant fields", () => { - patientPage.visitPatient("Dummy Patient 15"); + patientPage.visitPatient("Discharge Patient Four"); patientDischarge.clickDischarge(); patientDischarge.selectDischargeReason(patientDischargeReason1); patientDischarge.typeDischargeNote(patientDischargeAdvice); @@ -104,13 +104,13 @@ describe("Patient Discharge based on multiple reason", () => { patientPrescription.selectMedicine(patientMedicine); patientPrescription.enterDosage("4"); patientPrescription.selectDosageFrequency("Twice daily"); - cy.submitButton("Submit"); + cy.clickSubmitButton("Submit"); cy.verifyNotification("Medicine prescribed"); cy.wait(2000); cy.closeNotification(); // submit the discharge pop-up - cy.submitButton("Confirm Discharge"); - cy.submitButton("Acknowledge & Submit"); + cy.clickSubmitButton("Confirm Discharge"); + cy.clickSubmitButton("Acknowledge & Submit"); cy.wait(2000); cy.verifyNotification("Patient Discharged Successfully"); cy.closeNotification(); diff --git a/cypress/e2e/patient_spec/PatientDoctorConnect.cy.ts b/cypress/e2e/patient_spec/PatientDoctorConnect.cy.ts index dd626f619ce..474af286b21 100644 --- a/cypress/e2e/patient_spec/PatientDoctorConnect.cy.ts +++ b/cypress/e2e/patient_spec/PatientDoctorConnect.cy.ts @@ -7,10 +7,10 @@ describe("Patient Doctor Connect in consultation page", () => { const loginPage = new LoginPage(); const patientPage = new PatientPage(); const doctorconnect = new DoctorConnect(); - const patientName = "Dummy Patient 11"; + const patientName = "Dummy Patient Eleven"; const doctorUser = "Dev Doctor"; const nurseUser = "Dev Staff"; - const teleIcuUser = "Dev Doctor Two"; + const teleIcuUser = "Tester Doctor"; before(() => { loginPage.loginAsDistrictAdmin(); diff --git a/cypress/e2e/patient_spec/PatientDoctorNotes.cy.ts b/cypress/e2e/patient_spec/PatientDoctorNotes.cy.ts index e35d3eb8961..d227d68ddcb 100644 --- a/cypress/e2e/patient_spec/PatientDoctorNotes.cy.ts +++ b/cypress/e2e/patient_spec/PatientDoctorNotes.cy.ts @@ -6,7 +6,7 @@ describe("Patient Discussion notes in the consultation page", () => { const loginPage = new LoginPage(); const patientPage = new PatientPage(); const patientDoctorNotes = new PatientDoctorNotes(); - const patientName = "Dummy Patient 4"; + const patientName = "Dummy Patient Four"; const patientNurseNote = "Test nurse Notes"; const patientNurseReplyNote = "Test nurse reply Notes"; const discussionNotesSubscribeWarning = diff --git a/cypress/e2e/patient_spec/PatientFileUpload.ts b/cypress/e2e/patient_spec/PatientFileUpload.ts index 110631551a1..dd3098163ec 100644 --- a/cypress/e2e/patient_spec/PatientFileUpload.ts +++ b/cypress/e2e/patient_spec/PatientFileUpload.ts @@ -14,9 +14,9 @@ function runTests( const cypressAudioName = "cypress audio"; const cypressFileName = "cypress name"; const newFileName = "cypress modified name"; - const patientNameOne = "Dummy Patient 3"; - const patientNameTwo = "Dummy Patient 4"; - const patientNameThree = "Dummy Patient 5"; + const patientNameOne = "Dummy Patient Three"; + const patientNameTwo = "Dummy Patient Four"; + const patientNameThree = "Dummy Patient Five"; before(() => { loginPage.loginAsDistrictAdmin(); cy.saveLocalStorage(); diff --git a/cypress/e2e/patient_spec/PatientHomepage.cy.ts b/cypress/e2e/patient_spec/PatientHomepage.cy.ts index e4e0f927952..e2c32098f1c 100644 --- a/cypress/e2e/patient_spec/PatientHomepage.cy.ts +++ b/cypress/e2e/patient_spec/PatientHomepage.cy.ts @@ -1,4 +1,5 @@ import { advanceFilters } from "pageobject/utils/advanceFilterHelpers"; +import { pageNavigation } from "pageobject/utils/paginationHelpers"; import LoginPage from "../../pageobject/Login/LoginPage"; import PatientHome from "../../pageobject/Patient/PatientHome"; @@ -163,15 +164,15 @@ describe("Patient Homepage present functionalities", () => { .invoke("text") .then((patientOne: string) => { firstPatientPageOne = patientOne.trim(); - patientHome.clickNextPage(); - patientHome.verifySecondPageUrl(); + pageNavigation.navigateToNextPage(); + pageNavigation.verifyCurrentPageNumber(2); cy.get('[data-cy="patient"]') .first() .invoke("text") .then((patientTwo: string) => { const firstPatientPageTwo = patientTwo.trim(); expect(firstPatientPageOne).not.to.eq(firstPatientPageTwo); - patientHome.clickPreviousPage(); + pageNavigation.navigateToPreviousPage(); }); }); }); diff --git a/cypress/e2e/patient_spec/PatientInvestigation.cy.ts b/cypress/e2e/patient_spec/PatientInvestigation.cy.ts index 7426890d5a6..350614d0c9a 100644 --- a/cypress/e2e/patient_spec/PatientInvestigation.cy.ts +++ b/cypress/e2e/patient_spec/PatientInvestigation.cy.ts @@ -7,7 +7,7 @@ describe("Patient Investigation Creation from Patient consultation page", () => const loginPage = new LoginPage(); const patientPage = new PatientPage(); const patientInvestigation = new PatientInvestigation(); - const patientName = "Dummy Patient 14"; + const patientName = "Dummy Patient Thirteen"; before(() => { loginPage.loginAsDistrictAdmin(); @@ -28,7 +28,7 @@ describe("Patient Investigation Creation from Patient consultation page", () => "Haematology", "Urine Test", ]); - cy.submitButton("Save Investigation"); + cy.clickSubmitButton("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 diff --git a/cypress/e2e/patient_spec/PatientLogUpdate.cy.ts b/cypress/e2e/patient_spec/PatientLogUpdate.cy.ts index b6399ff02ce..cfb739c8343 100644 --- a/cypress/e2e/patient_spec/PatientLogUpdate.cy.ts +++ b/cypress/e2e/patient_spec/PatientLogUpdate.cy.ts @@ -32,13 +32,13 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { const patientInsulinDosage = "56"; const patientFluidBalance = "500"; const patientNetBalance = "1000"; - const patientOne = "Dummy Patient 9"; + const patientOne = "Dummy Patient Nine"; const bedOne = "Dummy Bed 5"; - const patientTwo = "Dummy Patient 10"; + const patientTwo = "Dummy Patient Ten"; const bedTwo = "Dummy Bed 2"; - const patientThree = "Dummy Patient 8"; + const patientThree = "Dummy Patient Eight"; const bedThree = "Dummy Bed 3"; - const domicilaryPatient = "Dummy Patient 11"; + const domicilaryPatient = "Dummy Patient Eleven"; before(() => { loginPage.loginAsDistrictAdmin(); @@ -55,7 +55,7 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientPage.visitPatient(domicilaryPatient); patientConsultationPage.clickEditConsultationButton(); patientConsultationPage.selectPatientSuggestion("Domiciliary Care"); - cy.submitButton("Update Consultation"); + cy.clickSubmitButton("Update Consultation"); cy.verifyNotification("Consultation updated successfully"); cy.closeNotification(); patientLogupdate.clickLogupdate(); @@ -74,7 +74,7 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientLogupdate.selectRhythm(patientRhythmType); patientLogupdate.typeRhythm(patientRhythm); cy.get("#consciousness_level-option-RESPONDS_TO_PAIN").click(); - cy.submitButton("Save"); + cy.clickSubmitButton("Save"); cy.verifyNotification("Tele-medicine Log created successfully"); }); @@ -108,11 +108,11 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientPrescription.selectMedicine("DOLO"); patientPrescription.enterDosage("4"); patientPrescription.selectDosageFrequency("Twice daily"); - cy.submitButton("Submit"); + cy.clickSubmitButton("Submit"); cy.verifyNotification("Medicine prescribed"); cy.closeNotification(); // Submit the doctors log update - cy.submitButton("Save and Continue"); + cy.clickSubmitButton("Save and Continue"); cy.wait(2000); cy.verifyNotification("Progress Note created successfully"); cy.closeNotification(); @@ -120,13 +120,13 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientLogupdate.selectCriticalCareSection("Neurological Monitoring"); cy.get("#consciousness_level-option-RESPONDS_TO_PAIN").click(); cy.get("#left_pupil_light_reaction-option-FIXED").click(); - cy.submitButton("Update Details"); + cy.clickSubmitButton("Update Details"); cy.verifyNotification( "Neurological Monitoring details succesfully updated.", ); cy.closeNotification(); // Final Submission of the form - cy.submitButton("Complete"); + cy.clickSubmitButton("Complete"); cy.verifyNotification("Progress Note Log Update filed successfully"); cy.closeNotification(); // Verify the data reflection @@ -143,7 +143,7 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientLogupdate.clickUpdateDetail(); patientLogupdate.typeSystolic(patientModifiedSystolic); patientLogupdate.typeDiastolic(patientModifiedDiastolic); - cy.submitButton("Continue"); + cy.clickSubmitButton("Continue"); cy.verifyNotification("Progress Note updated successfully"); }); @@ -156,7 +156,7 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientLogupdate.clickLogupdate(); patientLogupdate.selectRoundType("Detailed Update"); patientLogupdate.selectPatientCategory(patientCategory); - cy.submitButton("Save and Continue"); + cy.clickSubmitButton("Save and Continue"); cy.verifyNotification("Detailed Update created successfully"); cy.closeNotification(); // Select two Section - First One is Respiratory Support @@ -166,7 +166,7 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientLogupdate.selectOxygenSupport(); patientLogupdate.typeOxygenFlowRate(patientOxygenFlowRate); patientLogupdate.typeVentilatorSpo2(patientSpo2); - cy.submitButton("Update Details"); + cy.clickSubmitButton("Update Details"); cy.verifyNotification("Respiratory Support details succesfully updated."); cy.closeNotification(); // Second Section will be Blood Sugar @@ -174,10 +174,10 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientLogupdate.typeBloodSugar(patientBloodSugar); patientLogupdate.typeInsulinDosage(patientInsulinDosage); cy.get("#insulin_intake_frequency-option-BD").click(); - cy.submitButton("Update Details"); + cy.clickSubmitButton("Update Details"); cy.verifyNotification("Blood Sugar details succesfully updated."); // Submit the form and verify the details - cy.submitButton("Complete"); + cy.clickSubmitButton("Complete"); cy.verifyNotification("Detailed Log Update filed successfully"); cy.closeNotification(); cy.contains("button", "Log Updates").click(); @@ -203,10 +203,10 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientLogupdate.selectCriticalCareSection("Dialysis"); patientLogupdate.typeFluidBalance(patientFluidBalance); patientLogupdate.typeNetBalance(patientNetBalance); - cy.submitButton("Update Details"); + cy.clickSubmitButton("Update Details"); cy.verifyNotification("Dialysis details succesfully updated."); cy.closeNotification(); - cy.submitButton("Complete"); + cy.clickSubmitButton("Complete"); cy.verifyNotification("Detailed Log Update filed successfully"); cy.closeNotification(); //Reverify the editted and newly added data @@ -251,7 +251,7 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientLogupdate.selectRhythm(patientRhythmType); patientLogupdate.typeRhythm(patientRhythm); cy.get("#consciousness_level-option-RESPONDS_TO_PAIN").click(); - cy.submitButton("Save"); + cy.clickSubmitButton("Save"); cy.wait(2000); cy.verifyNotification("Brief Update created successfully"); // Verify the card content @@ -263,7 +263,7 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientPage.visitPatient(domicilaryPatient); patientConsultationPage.clickEditConsultationButton(); patientConsultationPage.selectPatientSuggestion("Domiciliary Care"); - cy.submitButton("Update Consultation"); + cy.clickSubmitButton("Update Consultation"); cy.verifyNotification("Consultation updated successfully"); cy.closeNotification(); patientLogupdate.clickLogupdate(); @@ -281,7 +281,7 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientLogupdate.selectRhythm(patientRhythmType); patientLogupdate.typeRhythm(patientRhythm); cy.get("#consciousness_level-option-RESPONDS_TO_PAIN").click(); - cy.submitButton("Save"); + cy.clickSubmitButton("Save"); cy.verifyNotification("Brief Update created successfully"); cy.closeNotification(); // edit the card and verify the data. @@ -307,7 +307,7 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientLogupdate.typeSystolic(patientModifiedSystolic); patientLogupdate.clearIntoElementById("#diastolic"); patientLogupdate.typeDiastolic(patientModifiedDiastolic); - cy.submitButton("Continue"); + cy.clickSubmitButton("Continue"); cy.verifyNotification("Brief Update updated successfully"); cy.contains("button", "Log Updates").click(); patientLogupdate.clickLogUpdateViewDetails( @@ -324,7 +324,7 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientPage.visitPatient(domicilaryPatient); patientConsultationPage.clickEditConsultationButton(); patientConsultationPage.selectPatientSuggestion("Domiciliary Care"); - cy.submitButton("Update Consultation"); + cy.clickSubmitButton("Update Consultation"); cy.verifyNotification("Consultation updated successfully"); cy.closeNotification(); patientLogupdate.clickLogupdate(); @@ -336,7 +336,7 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientLogupdate.typeTemperature(patientTemperature); patientLogupdate.typeRespiratory(patientRespiratory); cy.get("#consciousness_level-option-RESPONDS_TO_PAIN").click(); - cy.submitButton("Save"); + cy.clickSubmitButton("Save"); cy.verifyNotification("Brief Update created successfully"); cy.closeNotification(); cy.verifyContentPresence("#consultation-buttons", ["9"]); @@ -346,7 +346,7 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { patientLogupdate.typeSystolic(patientSystolic); patientLogupdate.typeDiastolic(patientDiastolic); patientLogupdate.typePulse(patientPulse); - cy.submitButton("Save"); + cy.clickSubmitButton("Save"); cy.verifyNotification("Brief Update created successfully"); cy.closeNotification(); cy.verifyContentPresence("#consultation-buttons", ["-"]); diff --git a/cypress/e2e/patient_spec/PatientPrescription.cy.ts b/cypress/e2e/patient_spec/PatientPrescription.cy.ts index 53e67324199..96e6e23b1aa 100644 --- a/cypress/e2e/patient_spec/PatientPrescription.cy.ts +++ b/cypress/e2e/patient_spec/PatientPrescription.cy.ts @@ -26,7 +26,7 @@ describe("Patient Medicine Administration", () => { }); it("Add a new medicine | Verify the Edit and Discontinue Medicine workflow |", () => { - patientPage.visitPatient("Dummy Patient 9"); + patientPage.visitPatient("Dummy Patient Nine"); patientPrescription.visitMedicineTab(); patientPrescription.visitEditPrescription(); // Add a normal Medicine to the patient @@ -36,7 +36,7 @@ describe("Patient Medicine Administration", () => { patientPrescription.selectMedicine(medicineNameOne); patientPrescription.enterDosage(medicineBaseDosage); patientPrescription.selectDosageFrequency(medicineFrequency); - cy.submitButton("Submit"); + cy.clickSubmitButton("Submit"); cy.verifyNotification("Medicine prescribed"); cy.closeNotification(); // Edit the existing medicine & Verify they are properly moved to discontinue position @@ -44,16 +44,16 @@ describe("Patient Medicine Administration", () => { patientPrescription.visitMedicineTab(); cy.verifyAndClickElement("#0", medicineNameOne); cy.verifyContentPresence("#submit", ["Discontinue"]); // To verify the pop-up is open - cy.submitButton("Edit"); + cy.clickSubmitButton("Edit"); patientPrescription.enterDosage(medicineTargetDosage); - cy.submitButton("Submit"); + cy.clickSubmitButton("Submit"); cy.verifyNotification("Prescription edited successfully"); cy.closeNotification(); // Discontinue a medicine & Verify the notification cy.verifyAndClickElement("#0", medicineNameOne); - cy.submitButton("Discontinue"); + cy.clickSubmitButton("Discontinue"); patientPrescription.enterDiscontinueReason("Medicine is been discontinued"); - cy.submitButton("Confirm Discontinue"); + cy.clickSubmitButton("Confirm Discontinue"); cy.verifyNotification("Prescription discontinued"); cy.closeNotification(); // verify the discontinue medicine view @@ -63,7 +63,7 @@ describe("Patient Medicine Administration", () => { }); it("Add a PRN Prescription medicine | Group Administrate it |", () => { - patientPage.visitPatient("Dummy Patient 6"); + patientPage.visitPatient("Dummy Patient Six"); patientPrescription.visitMedicineTab(); patientPrescription.visitEditPrescription(); // Add First Medicine @@ -73,7 +73,7 @@ describe("Patient Medicine Administration", () => { patientPrescription.selectMedicine(medicineNameOne); patientPrescription.enterDosage(medicineBaseDosage); patientPrescription.enterIndicator(medicineIndicator); - cy.submitButton("Submit"); + cy.clickSubmitButton("Submit"); cy.verifyNotification("Medicine prescribed"); cy.closeNotification(); // Add Second Medicine @@ -83,7 +83,7 @@ describe("Patient Medicine Administration", () => { patientPrescription.selectMedicine(medicineNameTwo); patientPrescription.enterDosage(medicineBaseDosage); patientPrescription.enterIndicator(medicineIndicator); - cy.submitButton("Submit"); + cy.clickSubmitButton("Submit"); cy.verifyNotification("Medicine prescribed"); cy.closeNotification(); patientPrescription.clickReturnToDashboard(); @@ -97,7 +97,7 @@ describe("Patient Medicine Administration", () => { }); it("Add a new titrated medicine for a patient | Individual Administeration |", () => { - patientPage.visitPatient("Dummy Patient 5"); + patientPage.visitPatient("Dummy Patient Five"); patientPrescription.visitMedicineTab(); patientPrescription.visitEditPrescription(); patientPrescription.clickAddPrescription(); @@ -108,7 +108,7 @@ describe("Patient Medicine Administration", () => { patientPrescription.enterDosage(medicineBaseDosage); patientPrescription.enterTargetDosage(medicineTargetDosage); patientPrescription.selectDosageFrequency(medicineFrequency); - cy.submitButton("Submit"); + cy.clickSubmitButton("Submit"); cy.verifyNotification("Medicine prescribed"); cy.closeNotification(); // Administer the medicine in edit form @@ -116,7 +116,7 @@ describe("Patient Medicine Administration", () => { cy.wait(2000); patientPrescription.enterAdministerDosage(medicineBaseDosage); patientPrescription.enterAdministerNotes(medicineAdministerNote); - cy.submitButton("Administer Medicine"); + cy.clickSubmitButton("Administer Medicine"); cy.verifyNotification("Medicine(s) administered"); cy.closeNotification(); // Verify the Reflection on the Medicine @@ -129,14 +129,14 @@ describe("Patient Medicine Administration", () => { // Go to medicine tab and administer it again patientPrescription.visitMedicineTab(); cy.verifyAndClickElement("#0", medicineNameOne); - cy.submitButton("Administer"); + cy.clickSubmitButton("Administer"); patientPrescription.enterAdministerDosage(medicineBaseDosage); - cy.submitButton("Administer Medicine"); + cy.clickSubmitButton("Administer Medicine"); cy.verifyNotification("Medicine(s) administered"); }); it("Add a new medicine for a patient and verify the duplicate medicine validation", () => { - patientPage.visitPatient("Dummy Patient 4"); + patientPage.visitPatient("Dummy Patient Four"); patientPrescription.visitMedicineTab(); patientPrescription.visitEditPrescription(); patientPrescription.clickAddPrescription(); @@ -145,7 +145,7 @@ describe("Patient Medicine Administration", () => { patientPrescription.selectMedicine(medicineNameOne); patientPrescription.enterDosage(medicineBaseDosage); patientPrescription.selectDosageFrequency(medicineFrequency); - cy.submitButton("Submit"); + cy.clickSubmitButton("Submit"); cy.verifyNotification("Medicine prescribed"); cy.closeNotification(); // verify the duplicate medicine error message @@ -155,7 +155,7 @@ describe("Patient Medicine Administration", () => { patientPrescription.selectMedicine(medicineNameOne); patientPrescription.enterDosage(medicineBaseDosage); patientPrescription.selectDosageFrequency(medicineFrequency); - cy.submitButton("Submit"); + cy.clickSubmitButton("Submit"); cy.verifyNotification( "Medicine - This medicine is already prescribed to this patient. Please discontinue the existing prescription to prescribe again.", ); diff --git a/cypress/e2e/patient_spec/PatientRegistration.cy.ts b/cypress/e2e/patient_spec/PatientRegistration.cy.ts index 91810ffd273..c3647ceac3a 100644 --- a/cypress/e2e/patient_spec/PatientRegistration.cy.ts +++ b/cypress/e2e/patient_spec/PatientRegistration.cy.ts @@ -64,7 +64,7 @@ describe("Patient Creation with consultation", () => { const patientOneSecondInsurerName = "Care Payor"; const patientTransferPhoneNumber = "9849511866"; const patientTransferFacility = "Dummy Shifting Center"; - const patientTransferName = "Dummy Patient 10"; + const patientTransferName = "Dummy Patient Twelve"; const patientOccupation = "Student"; before(() => { @@ -243,7 +243,7 @@ describe("Patient Creation with consultation", () => { patientTransfer.clickTransferPatientYOB(yearOfBirth); patientTransfer.clickTransferSubmitButton(); cy.verifyNotification( - "Patient Dummy Patient 10 (Male) transferred successfully", + `Patient ${patientTransferName} (Male) transferred successfully`, ); patientTransfer.clickConsultationCancelButton(); // allow the transfer button of a patient diff --git a/cypress/e2e/sample_test_spec/SampleTestRequest.cy.ts b/cypress/e2e/sample_test_spec/SampleTestRequest.cy.ts new file mode 100644 index 00000000000..da4d8aabd20 --- /dev/null +++ b/cypress/e2e/sample_test_spec/SampleTestRequest.cy.ts @@ -0,0 +1,88 @@ +import LoginPage from "pageobject/Login/LoginPage"; +import { PatientConsultationPage } from "pageobject/Patient/PatientConsultation"; +import { PatientPage } from "pageobject/Patient/PatientCreation"; +import { SampleTestPage } from "pageobject/Sample/SampleTestCreate"; + +describe("Sample Test", () => { + const sampleTestPage = new SampleTestPage(); + const patientPage = new PatientPage(); + const loginPage = new LoginPage(); + const patientConsultationPage = new PatientConsultationPage(); + const patientName = "Dummy Patient Eleven"; + const sampleTestType = "BA/ETA"; + const icmrCategory = "Cat 0"; + const icmrLabel = "Test Icmr Label"; + const doctorName = "Dr John Doe"; + const atypicalDetails = "Patient showing unusual symptoms"; + const diagnosis = "Suspected respiratory infection"; + const etiologyIdentified = "Bacterial infection suspected"; + const differentialDiagnosis = "Possibly a viral infection"; + const fastTrackReason = + "The patient has a high risk of complications and requires immediate testing."; + const sampleTestStatus = "Request Submitted"; + const expectedSampleTestType = "ba/eta"; + const sampleTestResult = "Awaiting"; + + before(() => { + loginPage.loginAsDistrictAdmin(); + cy.saveLocalStorage(); + }); + + beforeEach(() => { + cy.restoreLocalStorage(); + cy.clearLocalStorage(/filters--.+/); + }); + + it("should request a new sample test", () => { + // Ensure patient list API is loaded before proceeding + cy.awaitUrl("/patients"); + patientPage.visitPatient(patientName); + patientConsultationPage.interceptPatientDetailsAPI(); + patientConsultationPage.clickPatientDetails(); + patientConsultationPage.verifyPatientDetailsResponse(); + // Visit SampleRequest Page + sampleTestPage.visitSampleRequestPage(); + // Fill Sample Test Request Form + sampleTestPage.selectSampleType(sampleTestType); + sampleTestPage.selectIcmrCategory(icmrCategory); + sampleTestPage.fillIcmrLabel(icmrLabel); + sampleTestPage.fillFastTrackReason(fastTrackReason); + sampleTestPage.fillDoctorName(doctorName); + sampleTestPage.fillAtypicalPresentation(atypicalDetails); + sampleTestPage.fillDiagnosis(diagnosis); + sampleTestPage.fillEtiology(etiologyIdentified); + sampleTestPage.fillDiffDiagnosis(differentialDiagnosis); + sampleTestPage.checkHasSari(); + sampleTestPage.checkHasAri(); + sampleTestPage.checkIsUnusualCourse(); + sampleTestPage.interceptSampleTestReq(); + // Submit the form and verify notification + cy.clickSubmitButton("Confirm your request to send sample for testing"); + sampleTestPage.verifySampleTestReq(); + cy.verifyNotification("Sample test created successfully"); + // Check the updated request history + sampleTestPage.checkRequestHistory( + sampleTestStatus, + expectedSampleTestType, + fastTrackReason, + sampleTestResult, + ); + // Checking Reflection on Sample Page + cy.awaitUrl("/sample"); + sampleTestPage.interceptGetSampleTestReq(); + sampleTestPage.searchPatientSample(patientName); + sampleTestPage.verifyGetSampleTestReq(); + sampleTestPage.verifyPatientName(patientName); + sampleTestPage.interceptGetSampleTestReq(); + sampleTestPage.clickOnSampleDetailsBtn(); + sampleTestPage.verifyGetSampleTestReq(); + sampleTestPage.verifyPatientTestDetails( + patientName, + fastTrackReason, + doctorName, + diagnosis, + differentialDiagnosis, + etiologyIdentified, + ); + }); +}); diff --git a/cypress/e2e/users_spec/UsersHomepage.cy.ts b/cypress/e2e/users_spec/UsersHomepage.cy.ts index d5825f58f20..b32bb859e4e 100644 --- a/cypress/e2e/users_spec/UsersHomepage.cy.ts +++ b/cypress/e2e/users_spec/UsersHomepage.cy.ts @@ -1,4 +1,5 @@ import { advanceFilters } from "pageobject/utils/advanceFilterHelpers"; +import { pageNavigation } from "pageobject/utils/paginationHelpers"; import LoginPage from "../../pageobject/Login/LoginPage"; import { UserPage } from "../../pageobject/Users/UserSearch"; @@ -16,7 +17,7 @@ describe("User Homepage", () => { const altPhoneNumber = "8878825662"; const homeFacility = "Dummy Facility 40"; const nurseUserName = "dummynurse1"; - const doctorUserName = "devdoctor1"; + const doctorUserName = "dev-doctor2"; before(() => { loginPage.loginAsDistrictAdmin(); @@ -84,10 +85,10 @@ describe("User Homepage", () => { }); it("Next/Previous Page Navigation", () => { - userPage.navigateToNextPage(); - userPage.verifyCurrentPageNumber(2); - userPage.navigateToPreviousPage(); - userPage.verifyCurrentPageNumber(1); + pageNavigation.navigateToNextPage(); + pageNavigation.verifyCurrentPageNumber(2); + pageNavigation.navigateToPreviousPage(); + pageNavigation.verifyCurrentPageNumber(1); }); afterEach(() => { diff --git a/cypress/e2e/users_spec/UsersManage.cy.ts b/cypress/e2e/users_spec/UsersManage.cy.ts index 22da938542d..40d436be0a6 100644 --- a/cypress/e2e/users_spec/UsersManage.cy.ts +++ b/cypress/e2e/users_spec/UsersManage.cy.ts @@ -60,6 +60,7 @@ describe("Manage User", () => { advanceFilters.clickAdvancedFiltersButton(); userPage.typeInFirstName(firstNameUserSkill); userPage.typeInLastName(lastNameUserSkill); + userPage.selectHomeFacility(facilitytolinkskill); advanceFilters.applySelectedFilter(); userPage.checkUsernameText(usernameToLinkSkill); manageUserPage.clicklinkedskillbutton(); diff --git a/cypress/pageobject/Asset/AssetPagination.ts b/cypress/pageobject/Asset/AssetPagination.ts index f2a4103b065..e69de29bb2d 100644 --- a/cypress/pageobject/Asset/AssetPagination.ts +++ b/cypress/pageobject/Asset/AssetPagination.ts @@ -1,19 +0,0 @@ -export class AssetPagination { - navigateToNextPage() { - // only works for desktop mode - cy.get("button#next-pages").click(); - } - - verifyNextUrl() { - cy.url().should("include", "page=2"); - } - - navigateToPreviousPage() { - // only works for desktop mode - cy.get("button#prev-pages").click(); - } - - verifyPreviousUrl() { - cy.url().should("include", "page=1"); - } -} diff --git a/cypress/pageobject/Facility/FacilityCreation.ts b/cypress/pageobject/Facility/FacilityCreation.ts index 6ce0cc6270e..0fddc3f9799 100644 --- a/cypress/pageobject/Facility/FacilityCreation.ts +++ b/cypress/pageobject/Facility/FacilityCreation.ts @@ -276,7 +276,7 @@ class FacilityPage { } confirmDeleteFacility() { - cy.submitButton("Delete"); + cy.clickSubmitButton("Delete"); } selectLocation(location: string) { @@ -302,6 +302,10 @@ class FacilityPage { cy.verifyNotification(message); } + verifyErrorNotification(message: string) { + cy.verifyNotification(message); + } + visitAlreadyCreatedFacility() { cy.intercept("GET", "**/api/v1/facility/**").as("getFacilities"); cy.get("[id='facility-details']").first().click(); diff --git a/cypress/pageobject/Login/LoginPage.ts b/cypress/pageobject/Login/LoginPage.ts index 07eb4486d17..714004023f7 100644 --- a/cypress/pageobject/Login/LoginPage.ts +++ b/cypress/pageobject/Login/LoginPage.ts @@ -20,13 +20,13 @@ class LoginPage { } else { cy.get("input[id='password']").type("Corona"); } - cy.submitButton("Login"); + cy.clickSubmitButton("Login"); } loginManuallyAsNurse(): void { cy.get("input[id='username']").click().type("dummynurse1"); cy.get("input[id='password']").click().type("Coronasafe@123"); - cy.submitButton("Login"); + cy.clickSubmitButton("Login"); } login(username: string, password: string): void { diff --git a/cypress/pageobject/Patient/PatientConsultation.ts b/cypress/pageobject/Patient/PatientConsultation.ts index 642eaf9e4d6..c8046a39a9e 100644 --- a/cypress/pageobject/Patient/PatientConsultation.ts +++ b/cypress/pageobject/Patient/PatientConsultation.ts @@ -113,6 +113,14 @@ export class PatientConsultationPage { cy.wait(3000); } + interceptPatientDetailsAPI(): void { + cy.intercept("GET", "**/api/v1/patient/**").as("patientDetails"); + } + + verifyPatientDetailsResponse(): void { + cy.wait("@patientDetails").its("response.statusCode").should("eq", 200); + } + clickViewConsultationButton() { cy.verifyAndClickElement( "#view_consultation_and_log_updates", diff --git a/cypress/pageobject/Patient/PatientCreation.ts b/cypress/pageobject/Patient/PatientCreation.ts index 8f46dec5560..a38b8ab6a5c 100644 --- a/cypress/pageobject/Patient/PatientCreation.ts +++ b/cypress/pageobject/Patient/PatientCreation.ts @@ -23,7 +23,7 @@ export class PatientPage { selectFacility(facilityName: string) { cy.typeAndSelectOption("input[name='facilities']", facilityName); - cy.submitButton("Select"); + cy.clickSubmitButton("Select"); } interceptCreatePatientAPI() { @@ -57,7 +57,7 @@ export class PatientPage { typePatientAge(age: string) { cy.clickAndSelectOption("#patientAge", "Age"); - cy.submitButton("Confirm"); + cy.clickSubmitButton("Confirm"); cy.get("#age").clear().type(age); } diff --git a/cypress/pageobject/Patient/PatientFileupload.ts b/cypress/pageobject/Patient/PatientFileupload.ts index 0616a19729c..6cde7d78568 100644 --- a/cypress/pageobject/Patient/PatientFileupload.ts +++ b/cypress/pageobject/Patient/PatientFileupload.ts @@ -58,7 +58,7 @@ export class PatientFileUpload { clickSaveArchiveFile() { cy.intercept("PATCH", "**/api/v1/files/**").as("saveArchiveFile"); - cy.submitButton("Proceed"); + cy.clickSubmitButton("Proceed"); cy.wait("@saveArchiveFile").its("response.statusCode").should("eq", 200); } @@ -89,7 +89,7 @@ export class PatientFileUpload { clickSaveFileName() { cy.intercept("PATCH", "**/api/v1/files/**").as("saveFileName"); - cy.submitButton("Proceed"); + cy.clickSubmitButton("Proceed"); cy.wait("@saveFileName").its("response.statusCode").should("eq", 200); } } diff --git a/cypress/pageobject/Patient/PatientHome.ts b/cypress/pageobject/Patient/PatientHome.ts index bc27977d561..36cad15f0e5 100644 --- a/cypress/pageobject/Patient/PatientHome.ts +++ b/cypress/pageobject/Patient/PatientHome.ts @@ -1,16 +1,4 @@ class PatientHome { - clickNextPage() { - cy.get("#next-pages").click(); - } - - verifySecondPageUrl() { - cy.url().should("include", "/patients?page=2"); - } - - clickPreviousPage() { - cy.get("#prev-pages").click(); - } - clickPatientExport() { cy.get("#patient-export").click(); } diff --git a/cypress/pageobject/Sample/SampleTestCreate.ts b/cypress/pageobject/Sample/SampleTestCreate.ts new file mode 100644 index 00000000000..cd2e93e5072 --- /dev/null +++ b/cypress/pageobject/Sample/SampleTestCreate.ts @@ -0,0 +1,114 @@ +export class SampleTestPage { + visitSampleRequestPage(): void { + cy.verifyAndClickElement("#sample-request-btn", "Request Sample Test"); + cy.url().should("include", "/sample-test"); + } + + selectSampleType(option: string): void { + cy.clickAndSelectOption("#sample-type", option); + } + + selectIcmrCategory(option: string): void { + cy.clickAndSelectOption("#icmr-category", option); + } + + fillIcmrLabel(label: string): void { + cy.get("#icmr-label").should("be.visible").type(label); + } + + fillFastTrackReason(value: string): void { + cy.get("#is_fast_track").should("be.visible").check(); + cy.get("#fast_track").should("be.visible").type(value); + } + + fillDoctorName(value: string): void { + cy.get("#doctor_name").should("be.visible").type(value); + } + + fillAtypicalPresentation(value: string): void { + cy.get("#is_atypical_presentation").should("be.visible").check(); + cy.get("#atypical_presentation").should("be.visible").type(value); + } + + fillDiagnosis(value: string): void { + cy.get("#diagnosis").should("be.visible").type(value); + } + + fillEtiology(value: string): void { + cy.get("#etiology_identified").should("be.visible").type(value); + } + + fillDiffDiagnosis(value: string): void { + cy.get("#diff_diagnosis").should("be.visible").type(value); + } + + checkHasSari(): void { + cy.get("#has_sari").should("be.visible").check(); + } + + checkHasAri(): void { + cy.get("#has_ari").should("be.visible").check(); + } + + checkIsUnusualCourse(): void { + cy.get("#is_unusual_course").should("be.visible").check(); + } + + checkRequestHistory( + sampleTestStatus: string, + sampleTestType: string, + fastTrack: string, + sampleTestResult: string, + ): void { + cy.verifyContentPresence("#sample-test-status", [sampleTestStatus]); + cy.verifyContentPresence("#sample-test-type", [sampleTestType]); + cy.verifyContentPresence("#sample-test-fast-track", [fastTrack]); + cy.verifyContentPresence("#sample-test-result", [sampleTestResult]); + } + + searchPatientSample(patientName: string): void { + cy.get("#search_patient_name").should("be.visible").type(patientName); + } + + verifyPatientName(patientName: string): void { + cy.verifyContentPresence("#sample-test-patient-name", [patientName]); + } + + clickOnSampleDetailsBtn(): void { + cy.get("#sample-details-btn").should("be.visible").first().click(); + } + + verifyPatientTestDetails( + patientName: string, + fastTrackReason: string, + doctorName: string, + diagnosis: string, + differentialDiagnosis: string, + etiologyIdentified: string, + ): void { + cy.verifyContentPresence("#patient_name", [patientName]); + cy.verifyContentPresence("#fast_track_reason", [fastTrackReason]); + cy.verifyContentPresence("#doctor_name", [doctorName]); + cy.verifyContentPresence("#diagnosis", [diagnosis]); + cy.verifyContentPresence("#diff_diagnosis", [differentialDiagnosis]); + cy.verifyContentPresence("#etiology_identified", [etiologyIdentified]); + } + + interceptSampleTestReq(): void { + cy.intercept("POST", "**/api/v1/patient/*/test_sample/").as( + "sampleDetails", + ); + } + + verifySampleTestReq(): void { + cy.wait("@sampleDetails").its("response.statusCode").should("eq", 201); + } + + interceptGetSampleTestReq(): void { + cy.intercept("GET", "**/api/v1/test_sample/**").as("getSampleTestReq"); + } + + verifyGetSampleTestReq(): void { + cy.wait("@getSampleTestReq").its("response.statusCode").should("eq", 200); + } +} diff --git a/cypress/pageobject/Users/UserSearch.ts b/cypress/pageobject/Users/UserSearch.ts index 85575398d0d..6b727aa2040 100644 --- a/cypress/pageobject/Users/UserSearch.ts +++ b/cypress/pageobject/Users/UserSearch.ts @@ -76,18 +76,6 @@ export class UserPage { cy.get(`[data-testid="${testId}"]`).should("not.be.visible"); } - navigateToNextPage() { - cy.get("button#next-pages").click(); - } - - navigateToPreviousPage() { - cy.get("button#prev-pages").click(); - } - - verifyCurrentPageNumber(pageNumber: number) { - cy.url().should("include", `page=${pageNumber}`); - } - verifyMultipleBadgesWithSameId(alreadylinkedusersviews: string[]) { cy.get("#user-view-name").then(($elements) => { const userViews = $elements diff --git a/cypress/pageobject/utils/paginationHelpers.ts b/cypress/pageobject/utils/paginationHelpers.ts new file mode 100644 index 00000000000..edbabec5523 --- /dev/null +++ b/cypress/pageobject/utils/paginationHelpers.ts @@ -0,0 +1,13 @@ +export const pageNavigation = { + navigateToNextPage() { + cy.get("button#next-pages").click(); + }, + + verifyCurrentPageNumber(pageNumber: number) { + cy.url().should("include", `page=${pageNumber}`); + }, + + navigateToPreviousPage() { + cy.get("button#prev-pages").click(); + }, +}; diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index 9af5f97e5d4..d97bb52732f 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -121,11 +121,16 @@ Cypress.Commands.add("clearAllFilters", () => { return cy.get("#clear-all-filters").click(); }); -Cypress.Commands.add("submitButton", (buttonText = "Submit") => { +Cypress.Commands.add("clickSubmitButton", (buttonText = "Submit") => { cy.get("button[type='submit']").contains(buttonText).scrollIntoView(); cy.get("button[type='submit']").contains(buttonText).click(); }); +Cypress.Commands.add("clickCancelButton", (buttonText = "Cancel") => { + cy.get("#cancel").contains(buttonText).scrollIntoView(); + cy.get("#cancel").contains(buttonText).click(); +}); + Cypress.Commands.add( "typeAndSelectOption", (element: string, referance: string) => { diff --git a/cypress/support/index.ts b/cypress/support/index.ts index b2895871872..6429ef5710f 100644 --- a/cypress/support/index.ts +++ b/cypress/support/index.ts @@ -14,7 +14,8 @@ declare global { ): Chainable; getAttached(selector: string): Chainable; clearAllFilters(): Chainable; - submitButton(buttonText?: string): Chainable; + clickSubmitButton(buttonText?: string): Chainable; + clickCancelButton(buttonText?: string): Chainable; typeAndSelectOption( element: string, referance: string, diff --git a/package-lock.json b/package-lock.json index f5edb998e4e..6ce89b1db1d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7247,9 +7247,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", diff --git a/package.json b/package.json index 60250c2209e..020d73f5e65 100644 --- a/package.json +++ b/package.json @@ -99,6 +99,7 @@ "xlsx": "^0.18.5" }, "devDependencies": { + "@julr/vite-plugin-validate-env": "^1.1.1", "@tailwindcss/container-queries": "^0.1.1", "@tailwindcss/forms": "^0.5.9", "@tailwindcss/typography": "^0.5.15", @@ -145,7 +146,8 @@ "vite": "^5.4.10", "vite-plugin-checker": "^0.8.0", "vite-plugin-pwa": "^0.20.5", - "vite-plugin-static-copy": "^2.0.0" + "vite-plugin-static-copy": "^2.0.0", + "zod": "^3.23.8" }, "browserslist": { "production": [ diff --git a/public/locale/en.json b/public/locale/en.json index e281d8239bf..5faa645b133 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -205,6 +205,10 @@ "SORT_OPTIONS__name": "Patient name A-Z", "SORT_OPTIONS__review_time": "Oldest review date first", "SORT_OPTIONS__taken_at": "Oldest taken date first", + "SPO2_LEVEL_MILD_HYPOXEMIA": "Mild Hypoxemia", + "SPO2_LEVEL_MODERATE_HYPOXEMIA": "Moderate Hypoxemia", + "SPO2_LEVEL_NORMAL": "Normal", + "SPO2_LEVEL_SEVERE_HYPOXEMIA": "Severe Hypoxemia", "Submit": "Submit", "TELEMEDICINE": "Telemedicine", "TRANSPORTATION TO BE ARRANGED": "Transportation", @@ -259,6 +263,7 @@ "abha_link_options__link_with_demographics__title": "Link with Demographics", "abha_link_options__link_with_otp__description": "Link Existing ABHA Number Using Mobile or Aadhaar OTP", "abha_link_options__link_with_otp__title": "Link with OTP", + "abha_link_options__link_with_qr__description": "Link Existing ABHA Number by Scanning the ABHA QR", "abha_link_options__link_with_qr__title": "Link with ABHA QR", "abha_number": "ABHA Number", "abha_number_exists": "ABHA Number already exists", @@ -746,6 +751,7 @@ "hi__record_not_fetched_title": "This record hasn't been fetched yet", "hi__waiting_for_record": "Waiting for the Host HIP to send the record.", "hide": "Hide", + "high": "High", "home_facility": "Home Facility", "hubs": "Hub Facilities", "i_declare": "I hereby declare that:", @@ -835,6 +841,7 @@ "log_updates": "Log Updates", "login": "Login", "longitude_invalid": "Longitude must be between -180 and 180", + "low": "Low", "lsg": "Lsg", "make_multiple_beds_label": "Do you want to make multiple beds?", "manage_bed_presets": "Manage Presets of Bed", diff --git a/src/CAREUI/interactive/FiltersSlideover.tsx b/src/CAREUI/interactive/FiltersSlideover.tsx index 959fd0621e8..6e35cc9de94 100644 --- a/src/CAREUI/interactive/FiltersSlideover.tsx +++ b/src/CAREUI/interactive/FiltersSlideover.tsx @@ -61,7 +61,7 @@ export const AdvancedFilterButton = ({ onClick }: { onClick: () => void }) => { diff --git a/src/CAREUI/interactive/LegendInput.tsx b/src/CAREUI/interactive/LegendInput.tsx index cb415d76ab1..064eb2ceb0f 100644 --- a/src/CAREUI/interactive/LegendInput.tsx +++ b/src/CAREUI/interactive/LegendInput.tsx @@ -130,7 +130,7 @@ export default function LegendInput(props: InputProps) { required={props.required} autoComplete={props.autoComplete} className={classNames( - "cui-input w-full rounded-md border-secondary-300 bg-secondary-50 shadow-sm focus:border-2 focus:border-primary-500 focus:bg-secondary-100 focus:outline-none focus:ring-0", + "cui-input w-full rounded-md border-2 border-secondary-300 border-transparent bg-secondary-50 shadow-sm focus:border-2 focus:border-primary-500 focus:bg-secondary-100 focus:outline-none focus:ring-0", props.size === "small" && "px-3 py-2 text-xs", (!props.size || !["small", "large"].includes(props.size)) && "px-4 py-3", diff --git a/src/Integrations/Plausible.tsx b/src/Integrations/Plausible.tsx index dfbb2942e5d..89d0572e9e4 100644 --- a/src/Integrations/Plausible.tsx +++ b/src/Integrations/Plausible.tsx @@ -10,6 +10,16 @@ export default function Plausible() { }); useEffect(() => { + const missingConfig = []; + if (!careConfig.plausible.domain) missingConfig.push("domain"); + if (!careConfig.plausible.server) missingConfig.push("server"); + if (missingConfig.length > 0) { + console.error( + `Plausible analytics disabled. Missing configuration: ${missingConfig.join(", ")}`, + ); + return; + } + plausible("pageview"); }, []); diff --git a/src/Integrations/Sentry.tsx b/src/Integrations/Sentry.tsx index 90a8e78f3a9..1fa3d7e6da1 100644 --- a/src/Integrations/Sentry.tsx +++ b/src/Integrations/Sentry.tsx @@ -7,7 +7,10 @@ interface Props { export default function Sentry({ disabled }: Props) { useEffect(() => { - if (disabled || !careConfig.sentry.dsn) { + if (disabled || !careConfig.sentry.dsn || !careConfig.sentry.environment) { + console.error( + "Sentry is not configured correctly. Please check your environment variables.", + ); return; } diff --git a/src/components/Auth/Login.tsx b/src/components/Auth/Login.tsx index aab5f8df179..4255161194a 100644 --- a/src/components/Auth/Login.tsx +++ b/src/components/Auth/Login.tsx @@ -350,7 +350,7 @@ const Login = (props: { forgot?: boolean }) => { diff --git a/src/components/Common/ButtonV2.tsx b/src/components/Common/ButtonV2.tsx index 11b6aa95d20..a4dab66a4e7 100644 --- a/src/components/Common/ButtonV2.tsx +++ b/src/components/Common/ButtonV2.tsx @@ -101,7 +101,7 @@ export const buttonStyles = ({ shadow = !ghost, }: ButtonStyleProps) => { return classNames( - "inline-flex h-min cursor-pointer items-center justify-center gap-2 whitespace-pre font-medium outline-offset-1 transition-all duration-200 ease-in-out disabled:cursor-not-allowed disabled:bg-secondary-200 disabled:text-secondary-500", + "inline-flex h-min cursor-pointer items-center justify-center gap-2 whitespace-pre mt-2 font-medium outline-offset-1 transition-all duration-200 ease-in-out disabled:cursor-not-allowed disabled:bg-secondary-200 disabled:text-secondary-500", `button-size-${size}`, `button-shape-${circle ? "circle" : "square"}`, ghost ? `button-${variant}-ghost` : `button-${variant}-default`, diff --git a/src/components/Facility/BedCapacity.tsx b/src/components/Facility/BedCapacity.tsx index 0bb405670fd..156dc6adce6 100644 --- a/src/components/Facility/BedCapacity.tsx +++ b/src/components/Facility/BedCapacity.tsx @@ -77,6 +77,8 @@ export const BedCapacity = (props: BedCapacityProps) => { const existingData = capacityQuery.data?.results; // if all options are diabled if (existingData.length === BED_TYPES.length) { + setBedTypes([]); + setIsLoading(false); return; } // disable existing bed types @@ -277,18 +279,20 @@ export const BedCapacity = (props: BedCapacityProps) => {
- {!isLastOptionType && headerText === "Add Bed Capacity" && ( + {headerText === "Add Bed Capacity" && ( handleSubmit(e, "Save and Exit")} label="Save Bed Capacity" /> )} - handleSubmit(e)} - label={buttonText} - /> + {!isLastOptionType && ( + handleSubmit(e)} + label={buttonText} + /> + )}
)} diff --git a/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx b/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx index 81078197a45..6a7e33c6c95 100644 --- a/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx +++ b/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx @@ -5,42 +5,18 @@ import Loading from "@/components/Common/Loading"; import PageTitle from "@/components/Common/PageTitle"; import Pagination from "@/components/Common/Pagination"; import { ConsultationTabProps } from "@/components/Facility/ConsultationDetails/index"; -import { NursingPlot } from "@/components/Facility/Consultations/NursingPlot"; +import LogUpdateAnalyseTable from "@/components/Facility/Consultations/LogUpdateAnalyseTable"; import { + NursingPlotFields, + NursingPlotRes, RoutineAnalysisRes, RoutineFields, } from "@/components/Facility/models"; -import { PAGINATION_LIMIT } from "@/common/constants"; +import { NURSING_CARE_PROCEDURES, PAGINATION_LIMIT } from "@/common/constants"; import routes from "@/Utils/request/api"; import request from "@/Utils/request/request"; -import { classNames, formatDate, formatTime } from "@/Utils/utils"; - -export default function ConsultationNursingTab(props: ConsultationTabProps) { - const { t } = useTranslation(); - return ( -
- -
-

{t("routine")}

- -
-
-

{t("nursing_care")}

- -
-
- ); -} const REVERSE_CHOICES = { appetite: { @@ -114,6 +90,92 @@ const ROUTINE_ROWS = [ { subField: true, field: "appetite" } as const, ]; +const NursingPlot = ({ consultationId }: ConsultationTabProps) => { + const { t } = useTranslation(); + const [results, setResults] = useState<{ [date: string]: NursingPlotRes }>( + {}, + ); + const [currentPage, setCurrentPage] = useState(1); + const [totalCount, setTotalCount] = useState(0); + + useEffect(() => { + const fetchDailyRounds = async ( + currentPage: number, + consultationId: string, + ) => { + const { res, data } = await request(routes.dailyRoundsAnalyse, { + body: { page: currentPage, fields: NursingPlotFields }, + pathParams: { consultationId }, + }); + if (res?.ok && data) { + setResults(data.results as { [date: string]: NursingPlotRes }); + setTotalCount(data.count); + } + }; + + fetchDailyRounds(currentPage, consultationId); + }, [consultationId, currentPage]); + + const handlePagination = (page: number) => setCurrentPage(page); + + let fieldsToDisplay = new Set(); + + /** + * Transforms nursing procedure results into a structured format where dates are mapped to procedures and their descriptions. + * Groups nursing data by date, collecting unique procedures and their corresponding descriptions. + */ + const tableData = Object.entries(results).reduce( + (acc: Record>, [date, result]) => { + if ("nursing" in result) { + result.nursing.forEach((field) => { + if (field.procedure && !acc[date]) acc[date] = {}; + acc[date][field.procedure] = field.description; + // Add procedure to the set of procedures to display + fieldsToDisplay.add(field.procedure); + }); + } + return acc; + }, + {}, + ); + + fieldsToDisplay = fieldsToDisplay.intersection( + new Set(NURSING_CARE_PROCEDURES), + ); + + const rows = Array.from(fieldsToDisplay).map((procedure) => ({ + field: procedure, + title: t(`NURSING_CARE_PROCEDURE__${procedure}`), + })); + + return ( +
+
+ {fieldsToDisplay.size == 0 ? ( +
+
+ {t("no_data_found")} +
+
+ ) : ( + + )} +
+ + {totalCount > PAGINATION_LIMIT && fieldsToDisplay.size > 0 && ( +
+ +
+ )} +
+ ); +}; + const RoutineSection = ({ consultationId }: ConsultationTabProps) => { const { t } = useTranslation(); const [page, setPage] = useState(1); @@ -158,65 +220,11 @@ const RoutineSection = ({ consultationId }: ConsultationTabProps) => { return (
-
- - - - - ))} - - - - {ROUTINE_ROWS.map((row) => ( - - - {row.field && - Object.values(results).map((obj, idx) => ( - - ))} - - ))} - -
- {Object.keys(results).map((date) => ( - -

{formatDate(date)}

-

{formatTime(date)}

-
- {row.title ?? t(`LOG_UPDATE_FIELD_LABEL__${row.field!}`)} - - {(() => { - const value = obj[row.field]; - if (value == null) { - return "-"; - } - if (typeof value === "boolean") { - return t(value ? "yes" : "no"); - } - const choices = REVERSE_CHOICES[row.field]; - const choice = `${row.field.toUpperCase()}__${choices[value as keyof typeof choices]}`; - return t(choice); - })()} -
-
+ {totalCount != null && totalCount > PAGINATION_LIMIT && (
@@ -231,3 +239,24 @@ const RoutineSection = ({ consultationId }: ConsultationTabProps) => {
); }; + +export default function ConsultationNursingTab(props: ConsultationTabProps) { + const { t } = useTranslation(); + return ( +
+ +
+

{t("routine")}

+ +
+
+

{t("nursing_care")}

+ +
+
+ ); +} diff --git a/src/components/Facility/Consultations/LogUpdateAnalyseTable.tsx b/src/components/Facility/Consultations/LogUpdateAnalyseTable.tsx new file mode 100644 index 00000000000..43e59bebe7d --- /dev/null +++ b/src/components/Facility/Consultations/LogUpdateAnalyseTable.tsx @@ -0,0 +1,93 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; + +import { classNames, formatDate, formatTime } from "@/Utils/utils"; + +interface SharedSectionTableProps { + data: Record>; + rows: Array<{ title?: string; field?: string; subField?: boolean }>; + choices?: Record>; +} + +const LogUpdateAnalyseTable: React.FC = ({ + data, + rows, + choices = {}, +}) => { + const { t } = useTranslation(); + + const dataValues = React.useMemo(() => Object.values(data), [data]); + + const getDisplayValue = ( + value: string | boolean | null | undefined, + field?: string, + ): string => { + if (typeof value === "boolean") { + return t(value ? "yes" : "no"); + } + + if (field && choices[field]) { + const choiceMap = choices[field]; + const choice = + typeof value === "string" || typeof value === "number" + ? choiceMap[value] + : undefined; + return choice ? t(`${field.toUpperCase()}__${choice}`) : "-"; + } + + return typeof value === "string" ? value : "-"; + }; + + return ( +
+ + + + + {Object.keys(data).map((date) => ( + + ))} + + + + {rows.map((row) => ( + + + {dataValues.map((obj, idx) => { + const value = row.field ? obj[row.field] : undefined; + return ( + + ); + })} + + ))} + +
+

{formatDate(date)}

+

{formatTime(date)}

+
+ {row.title ?? t(`LOG_UPDATE_FIELD_LABEL__${row.field!}`)} + + {row.field ? getDisplayValue(value, row.field) : "-"} +
+
+ ); +}; + +export default LogUpdateAnalyseTable; diff --git a/src/components/Facility/Consultations/NursingPlot.tsx b/src/components/Facility/Consultations/NursingPlot.tsx deleted file mode 100644 index 13f5bb64201..00000000000 --- a/src/components/Facility/Consultations/NursingPlot.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import { useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; - -import Pagination from "@/components/Common/Pagination"; -import { NursingPlotFields } from "@/components/Facility/models"; - -import { NURSING_CARE_PROCEDURES, PAGINATION_LIMIT } from "@/common/constants"; - -import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; -import { formatDateTime } from "@/Utils/utils"; - -export const NursingPlot = ({ consultationId }: any) => { - const { t } = useTranslation(); - const [results, setResults] = useState({}); - const [currentPage, setCurrentPage] = useState(1); - const [totalCount, setTotalCount] = useState(0); - - useEffect(() => { - const fetchDailyRounds = async ( - currentPage: number, - consultationId: string, - ) => { - const { res, data } = await request(routes.dailyRoundsAnalyse, { - body: { page: currentPage, fields: NursingPlotFields }, - pathParams: { - consultationId, - }, - }); - if (res && res.ok && data) { - setResults(data.results); - setTotalCount(data.count); - } - }; - - fetchDailyRounds(currentPage, consultationId); - }, [consultationId, currentPage]); - - const handlePagination = (page: number) => { - setCurrentPage(page); - }; - - const data = Object.entries(results).map((key: any) => { - return { - date: formatDateTime(key[0]), - nursing: key[1]["nursing"], - }; - }); - - const dataToDisplay = data - .map((x) => - x.nursing.map((f: any) => { - f["date"] = x.date; - return f; - }), - ) - .reduce((accumulator, value) => accumulator.concat(value), []); - - const filterEmpty = (field: (typeof NURSING_CARE_PROCEDURES)[number]) => { - const filtered = dataToDisplay.filter((i: any) => i.procedure === field); - return filtered.length > 0; - }; - - const areFieldsEmpty = () => { - let emptyFieldCount = 0; - for (const field of NURSING_CARE_PROCEDURES) { - if (!filterEmpty(field)) emptyFieldCount++; - } - if (emptyFieldCount === NURSING_CARE_PROCEDURES.length) return true; - else return false; - }; - - return ( -
-
-
-
- {areFieldsEmpty() && ( -
-
- {t("no_data_found")} -
-
- )} - {NURSING_CARE_PROCEDURES.map( - (f) => - filterEmpty(f) && ( -
-
-
-

- {t(`NURSING_CARE_PROCEDURE__${f}`)} -

-
-
-
- {dataToDisplay - .filter((i: any) => i.procedure === f) - .map((care: any, index: number) => ( -
-
- {care.date} -
-
- {care.description} -
-
- ))} -
-
- ), - )} -
-
-
- - {!areFieldsEmpty() && totalCount > PAGINATION_LIMIT && ( -
- -
- )} -
- ); -}; diff --git a/src/components/Facility/FacilityCard.tsx b/src/components/Facility/FacilityCard.tsx index 0d9c5678d4c..7aaf4c0eaf8 100644 --- a/src/components/Facility/FacilityCard.tsx +++ b/src/components/Facility/FacilityCard.tsx @@ -88,7 +88,7 @@ export const FacilityCard = (props: {
)}
@@ -220,7 +220,7 @@ export const FacilityCard = (props: {
-
+
{["DistrictAdmin", "StateAdmin"].includes(userType) && ( { {CameraFeedPermittedUserTypes.includes(authUser.user_type) && ( )} - navigate(`/facility/${facilityId}/patient`)} - authorizeFor={NonReadOnlyUsers} - > - - {t("add_details_of_patient")} - + {patientRegisterAuth(authUser, facilityData, facilityId) && ( + navigate(`/facility/${facilityId}/patient`)} + authorizeFor={NonReadOnlyUsers} + > + + {t("add_details_of_patient")} + + )} { const maxYear = new Date().getFullYear(); const handleChange = (e: FieldChangeEvent) => { - if ( - e.name === "year_of_birth" && - parseInt((e.value as string) || "0") > maxYear - ) { + const value = String(e.value); + + if (e.name === "year_of_birth") { + if (value.length <= 4) { + dispatch({ + type: "set_form", + form: { ...state.form, [e.name]: e.value }, + }); + } + } else { dispatch({ - type: "set_error", - errors: { - ...state.errors, - [e.name]: `Cannot be greater than ${maxYear}`, - }, + type: "set_form", + form: { ...state.form, [e.name]: e.value }, }); - return; + } + }; + + const handleOnBlur = (e: React.FocusEvent) => { + const yearValue = Number(state.form.year_of_birth); + if (!state.form.year_of_birth) return; + let errorMessage = ""; + if (yearValue > maxYear) { + errorMessage = `Cannot be greater than ${maxYear}`; + } else if (yearValue < 1900) { + errorMessage = `Cannot be smaller than 1900`; } dispatch({ - type: "set_form", - form: { ...state.form, [e.name]: e.value }, + type: "set_error", + errors: { + ...state.errors, + [e.target.name]: errorMessage, + }, }); }; @@ -115,6 +131,11 @@ const TransferPatientDialog = (props: Props) => { errors[field] = `Cannot be greater than ${maxYear}`; invalidForm = true; } + + if (parseInt(state.form[field] || "0") < 1900) { + errors[field] = `Cannot be smaller than 1900`; + invalidForm = true; + } return; default: return; @@ -193,9 +214,8 @@ const TransferPatientDialog = (props: Props) => { label="Year of birth" labelClassName="text-sm" value={state.form.year_of_birth} - min="1900" - max={maxYear} onChange={handleChange} + onBlur={handleOnBlur} placeholder="Enter year of birth" error={state.errors.year_of_birth} /> diff --git a/src/components/Facility/models.tsx b/src/components/Facility/models.tsx index 79272ac3de7..a984efe6283 100644 --- a/src/components/Facility/models.tsx +++ b/src/components/Facility/models.tsx @@ -391,7 +391,10 @@ export const NursingPlotFields = [ ] as const satisfies (keyof DailyRoundsModel)[]; export type NursingPlotRes = { - nursing: any[]; + nursing: Array<{ + procedure: string; + description: string; + }>; }; export const RoutineFields = [ diff --git a/src/components/Kanban/Board.tsx b/src/components/Kanban/Board.tsx index 337f98f1caf..5109599c840 100644 --- a/src/components/Kanban/Board.tsx +++ b/src/components/Kanban/Board.tsx @@ -58,7 +58,7 @@ export default function KanbanBoard(
-
+
{props.sections.map((section, i) => ( key={i} @@ -146,7 +146,7 @@ export function KanbanSection(
diff --git a/src/components/Notifications/NotificationsList.tsx b/src/components/Notifications/NotificationsList.tsx index 17033d67623..f9b65b35201 100644 --- a/src/components/Notifications/NotificationsList.tsx +++ b/src/components/Notifications/NotificationsList.tsx @@ -244,7 +244,10 @@ export default function NotificationsList({ const handleSubscribeClick = () => { const status = isSubscribed; - if (status === "NotSubscribed" || status === "SubscribedOnAnotherDevice") { + if (!navigator.serviceWorker) { + return; + } + if (["NotSubscribed", "SubscribedOnAnotherDevice"].includes(status)) { if (Notification.permission === "denied") { Warn({ msg: t("notification_permission_denied"), @@ -286,49 +289,47 @@ export default function NotificationsList({ let manageResults: any = null; - const unsubscribe = () => { - navigator.serviceWorker.ready - .then(function (reg) { - setIsSubscribing(true); - reg.pushManager - .getSubscription() - .then(function (subscription) { - subscription - ?.unsubscribe() - .then(async function (_successful) { - const data = { - pf_endpoint: "", - pf_p256dh: "", - pf_auth: "", - }; - - await request(routes.updateUserPnconfig, { - pathParams: { username: username }, - body: data, - }); - - Warn({ - msg: t("unsubscribed_successfully"), - }); - - setIsSubscribed("NotSubscribed"); - setIsSubscribing(false); - }) - .catch(function (_e) { - Error({ - msg: t("unsubscribe_failed"), - }); - }); - }) - .catch(function (_e) { - Error({ msg: t("subscription_error") }); + const unsubscribe = async () => { + try { + const reg = await navigator.serviceWorker.ready; + + if (!reg.pushManager) { + Error({ msg: t("unsubscribe_failed") }); + return; + } + + setIsSubscribing(true); + + const subscription = await reg.pushManager.getSubscription(); + + if (subscription) { + try { + await subscription.unsubscribe(); + + await request(routes.updateUserPnconfig, { + pathParams: { username }, + body: { + pf_endpoint: "", + pf_p256dh: "", + pf_auth: "", + }, }); - }) - .catch(function (_e) { - Sentry.captureException(_e); - }); - }; + setIsSubscribed("NotSubscribed"); + Warn({ + msg: t("unsubscribed_successfully"), + }); + } catch (e) { + Error({ msg: t("unsubscribe_failed") }); + } + } + } catch (e) { + Sentry.captureException(e); + Error({ msg: t("subscription_error") }); + } finally { + setIsSubscribing(false); + } + }; async function subscribe() { setIsSubscribing(true); try { diff --git a/src/components/Patient/DailyRounds.tsx b/src/components/Patient/DailyRounds.tsx index d9bcb1366d5..4e8573d6273 100644 --- a/src/components/Patient/DailyRounds.tsx +++ b/src/components/Patient/DailyRounds.tsx @@ -59,6 +59,7 @@ import request from "@/Utils/request/request"; import { formatDateTime } from "@/Utils/utils"; import { scrollTo } from "@/Utils/utils"; +import RangeAutocompleteFormField from "../Form/FormFields/RangeAutocompleteFormField"; import TextFormField from "../Form/FormFields/TextFormField"; export const DailyRounds = (props: any) => { @@ -702,6 +703,31 @@ export const DailyRounds = (props: any) => { }, ]} /> + + )} @@ -774,17 +800,22 @@ export const DailyRounds = (props: any) => { { value: 0, className: "text-danger-500", - label: "Low", + label: t("SPO2_LEVEL_SEVERE_HYPOXEMIA"), }, { - value: 90, - className: "text-primary-500", - label: "Normal", + value: 86, + className: "text-danger-500", + label: t("SPO2_LEVEL_MODERATE_HYPOXEMIA"), }, { - value: 100, - className: "text-danger-500", - label: "High", + value: 91, + className: "text-warning-400", + label: t("SPO2_LEVEL_MILD_HYPOXEMIA"), + }, + { + value: 95, + className: "text-primary-500", + label: t("SPO2_LEVEL_NORMAL"), }, ]} /> @@ -819,7 +850,6 @@ export const DailyRounds = (props: any) => { /> )} - {state.form.rounds_type === "COMMUNITY_NURSES_LOG" && (

diff --git a/src/components/Patient/ManagePatients.tsx b/src/components/Patient/ManagePatients.tsx index 0664532b0a1..a91e4ab416c 100644 --- a/src/components/Patient/ManagePatients.tsx +++ b/src/components/Patient/ManagePatients.tsx @@ -841,7 +841,7 @@ export const PatientManager = () => {

-
+
{ }); }, 500); }} - className="mr-5 w-full lg:w-fit" + className="mr-5 w-full lg:w-fit mt-2" > Export diff --git a/src/components/Patient/PatientConsentRecords.tsx b/src/components/Patient/PatientConsentRecords.tsx index 162dcb2ff77..f2b8c21d58f 100644 --- a/src/components/Patient/PatientConsentRecords.tsx +++ b/src/components/Patient/PatientConsentRecords.tsx @@ -232,7 +232,7 @@ export default function PatientConsentRecords(props: { <>
{sampleDetails?.facility_object && (
@@ -362,7 +362,7 @@ export const SampleDetails = ({ id }: DetailRoute) => { {t("fast_track_testing_reason")}:{" "} - {sampleDetails.fast_track} + {sampleDetails.fast_track}
)} {sampleDetails?.doctor_name && ( @@ -370,7 +370,9 @@ export const SampleDetails = ({ id }: DetailRoute) => { {t("doctors_name")}:{" "} - {startCase(camelCase(sampleDetails.doctor_name))} + + {startCase(camelCase(sampleDetails.doctor_name))} +
)} {sampleDetails?.diagnosis && ( @@ -378,7 +380,7 @@ export const SampleDetails = ({ id }: DetailRoute) => { {t("diagnosis")}:{" "} - {sampleDetails.diagnosis} + {sampleDetails.diagnosis}
)} {sampleDetails?.diff_diagnosis && ( @@ -386,7 +388,7 @@ export const SampleDetails = ({ id }: DetailRoute) => { {t("differential_diagnosis")}:{" "} - {sampleDetails?.diff_diagnosis} + {sampleDetails?.diff_diagnosis}
)} {sampleDetails?.etiology_identified && ( @@ -394,7 +396,9 @@ export const SampleDetails = ({ id }: DetailRoute) => { {t("etiology_identified")}:{" "} - {sampleDetails.etiology_identified} + + {sampleDetails.etiology_identified} +
)}
diff --git a/src/components/Patient/SampleTest.tsx b/src/components/Patient/SampleTest.tsx index 0714de28492..0933d03761e 100644 --- a/src/components/Patient/SampleTest.tsx +++ b/src/components/Patient/SampleTest.tsx @@ -216,6 +216,7 @@ export const SampleTest = ({ facilityId, patientId }: any) => { options={SAMPLE_TYPE_CHOICES} optionLabel={(option) => option.text} optionValue={(option) => option.id} + id="sample-type" /> {state.form.sample_type === "9" && ( @@ -230,6 +231,7 @@ export const SampleTest = ({ facilityId, patientId }: any) => { options={ICMR_CATEGORY} optionLabel={(option) => option} optionValue={(option) => option} + id="icmr-category" />

@@ -255,7 +257,11 @@ export const SampleTest = ({ facilityId, patientId }: any) => {

- +
Testing Facility { />
{state.form.isFastTrack && ( )} - + {state.form.is_atypical_presentation && (
{ />
)} - +
goBack()} /> - +
diff --git a/src/components/Patient/SampleTestCard.tsx b/src/components/Patient/SampleTestCard.tsx index fef2c9e4d08..a0303705eb7 100644 --- a/src/components/Patient/SampleTestCard.tsx +++ b/src/components/Patient/SampleTestCard.tsx @@ -79,6 +79,7 @@ export const SampleTestCard = (props: SampleDetailsProps) => { return (
{
Status{" "}
-
+
{startCase(camelCase(itemData.status))}
@@ -110,7 +114,10 @@ export const SampleTestCard = (props: SampleDetailsProps) => {
Sample Type{" "}
-
+
{itemData.sample_type?.toLowerCase()}
@@ -121,7 +128,10 @@ export const SampleTestCard = (props: SampleDetailsProps) => {
Fast-Track{" "}
-
+
{itemData.fast_track}
@@ -132,7 +142,10 @@ export const SampleTestCard = (props: SampleDetailsProps) => {
Result{" "}
-
+
{startCase(camelCase(itemData.result))}
diff --git a/src/components/Patient/SampleViewAdmin.tsx b/src/components/Patient/SampleViewAdmin.tsx index 43d03ad1d12..37d66bfb815 100644 --- a/src/components/Patient/SampleViewAdmin.tsx +++ b/src/components/Patient/SampleViewAdmin.tsx @@ -155,7 +155,10 @@ export default function SampleViewAdmin() {
-
+
{item.patient_name}
@@ -274,6 +277,7 @@ export default function SampleViewAdmin() { )}