diff --git a/.cursorrules b/.cursorrules index b14270a50b4..5abb1146f3c 100644 --- a/.cursorrules +++ b/.cursorrules @@ -31,7 +31,7 @@ UI and Styling General Guidelines -- Care uses a custom useQuery hook to fetch data from the API. (Docs @ /Utils/request/useQuery) +- Care uses TanStack Query for data fetching from the API along with query and mutate utilities for the queryFn and mutationFn. (Docs @ /Utils/request/README.md) - APIs are defined in the api.tsx file. - Use raviger for routing. - Use care icons for icons. diff --git a/cypress/e2e/facility_spec/FacilityCreation.cy.ts b/cypress/e2e/facility_spec/FacilityCreation.cy.ts index f644c9829d3..d2893166745 100644 --- a/cypress/e2e/facility_spec/FacilityCreation.cy.ts +++ b/cypress/e2e/facility_spec/FacilityCreation.cy.ts @@ -1,20 +1,25 @@ -import { advanceFilters } from "pageobject/utils/advanceFilterHelpers"; +import { + generateFacilityName, + generatePhoneNumber, + generateRandomAddress, +} from "pageobject/utils/constants"; import FacilityPage, { FacilityData, } from "../../pageobject/Facility/FacilityCreation"; -import FacilityHome from "../../pageobject/Facility/FacilityHome"; import LoginPage from "../../pageobject/Login/LoginPage"; -import ManageUserPage from "../../pageobject/Users/ManageUserPage"; import { nonAdminRoles } from "../../pageobject/utils/userConfig"; -describe("Facility Creation", () => { - let facilityUrl1: string; +describe("Facility Creation with multiple user roles", () => { const facilityPage = new FacilityPage(); const loginPage = new LoginPage(); - const facilityHome = new FacilityHome(); - const manageUserPage = new ManageUserPage(); - const facilityFeature = [ + const facilityName = generateFacilityName(); + const facilityNumber = generatePhoneNumber(); + const facilityAddress = generateRandomAddress(false); + const facilityUpdatedNumber = generatePhoneNumber(); + const facilityUpdatedName = generateFacilityName(); + const facilityUpdatedAddress = generateRandomAddress(true); + const facilityFeatures = [ "CT Scan", "X-Ray", "Maternity Care", @@ -22,22 +27,6 @@ describe("Facility Creation", () => { "Operation Theater", "Blood Bank", ]; - const bedCapacity = "10"; - const bedOccupancy = "5"; - const oxygenCapacity = "100"; - const oxygenExpected = "80"; - const totalCapacity = "20"; - const totalOccupancy = "10"; - const doctorCapacity = "5"; - const totalDoctor = "10"; - const facilityName = "Cypress Facility"; - const facilityName2 = "Dummy Facility 40"; - const facilityAddress = "cypress address"; - const facilityUpdateAddress = "cypress updated address"; - const facilityNumber = "9898469865"; - const triageDate = "02122023"; - const initialTriageValue = "60"; - const modifiedTriageValue = "50"; const facilityErrorMessage = [ "Required", "Required", @@ -50,22 +39,11 @@ describe("Facility Creation", () => { "Required", "Invalid Phone Number", ]; - const bedErrorMessage = [ - "This field is required", - "Total capacity cannot be 0", - "This field is required", - ]; - const doctorErrorMessage = [ - "This field is required", - "This field is required", - ]; - const triageErrorMessage = ["This field is required"]; const facilityType = "Primary Health Centres"; const testFacilityData: FacilityData = { basic: { name: facilityName, type: facilityType, - features: facilityFeature, address: facilityAddress, phoneNumber: facilityNumber, location: "Kochi, Kerala", @@ -77,44 +55,6 @@ describe("Facility Creation", () => { localBody: "Aluva", ward: "4", }, - oxygen: { - capacity: oxygenCapacity, - expected: oxygenExpected, - bType: { - capacity: oxygenCapacity, - expected: oxygenExpected, - }, - cType: { - capacity: oxygenCapacity, - expected: oxygenExpected, - }, - dType: { - capacity: oxygenCapacity, - expected: oxygenExpected, - }, - }, - beds: [ - { - type: "Oxygen Supported Bed", - totalCapacity: bedCapacity, - occupied: bedOccupancy, - }, - { - type: "Ordinary Bed", - totalCapacity: bedCapacity, - occupied: bedOccupancy, - }, - ], - doctors: [ - { - specialization: "General Medicine", - count: doctorCapacity, - }, - { - specialization: "Pulmonology", - count: doctorCapacity, - }, - ], }; before(() => { @@ -128,262 +68,72 @@ describe("Facility Creation", () => { cy.awaitUrl("/facility"); }); - it("Verify Facility Triage Function", () => { - // mandatory field error throw - facilityHome.typeFacilitySearch(facilityName2); - advanceFilters.verifyFilterBadgePresence( - "Facility/District Name", - facilityName2, - true, - ); - facilityHome.assertFacilityInCard(facilityName2); - facilityHome.verifyURLContains(facilityName2); - facilityPage.visitAlreadyCreatedFacility(); - facilityPage.scrollToFacilityTriage(); - facilityPage.clickAddFacilityTriage(); - manageUserPage.clickSubmit(); - cy.verifyErrorMessages(triageErrorMessage); - // create a entry and verify reflection - facilityPage.fillEntryDate(triageDate); - facilityPage.fillTriageEntryFields( - initialTriageValue, - initialTriageValue, - initialTriageValue, - initialTriageValue, - initialTriageValue, - ); - manageUserPage.clickSubmit(); - // edit the entry and verify reflection - facilityPage.scrollToFacilityTriage(); - facilityPage.verifyTriageTableContains(initialTriageValue); - facilityPage.clickEditButton(); - facilityPage.fillTriageEntryFields( - modifiedTriageValue, - modifiedTriageValue, - modifiedTriageValue, - modifiedTriageValue, - modifiedTriageValue, - ); - manageUserPage.clickSubmit(); - facilityPage.scrollToFacilityTriage(); - facilityPage.verifyTriageTableContains(modifiedTriageValue); - // validate error of filling data on same date already data exist and verify reflection - facilityPage.scrollToFacilityTriage(); - facilityPage.clickAddFacilityTriage(); - facilityPage.fillEntryDate(triageDate); - facilityPage.clickButtonsMultipleTimes("button#submit"); - }); - - it("Create a new facility with multiple bed and doctor capacity", () => { - // create facility with multiple capacity and verify form error message for facility form + it("Create a new facility with all fields | Edit Existing Data | Verify its reflection", () => { + // Create a new facility facilityPage.visitCreateFacilityPage(); - facilityPage.submitForm(); - cy.verifyErrorMessages(facilityErrorMessage); - facilityPage.fillBasicDetails(testFacilityData.basic); + facilityPage.fillBasicDetails({ + ...testFacilityData.basic, + features: facilityFeatures, + }); facilityPage.fillLocationDetails(testFacilityData.location); - facilityPage.fillOxygenDetails(testFacilityData.oxygen); - facilityPage.submitForm(); - cy.closeNotification(); - // add the bed capacity - facilityPage.selectBedType("Oxygen Supported Bed"); - facilityPage.fillTotalCapacity(bedCapacity); - facilityPage.fillCurrentlyOccupied(bedOccupancy); - facilityPage.clickbedcapcityaddmore(); - cy.closeNotification(); - facilityPage.selectBedType("Ordinary Bed"); - facilityPage.fillTotalCapacity(bedCapacity); - facilityPage.fillCurrentlyOccupied(bedOccupancy); - facilityPage.clickbedcapcityaddmore(); - cy.closeNotification(); - facilityPage.getTotalBedCapacity().contains(totalCapacity); - facilityPage.getTotalBedCapacity().contains(totalOccupancy); - facilityPage.clickcancelbutton(); - // create multiple bed capacity and verify card reflection - facilityPage.selectAreaOfSpecialization("General Medicine"); - facilityPage.fillDoctorCount(doctorCapacity); - facilityPage.clickdoctorcapacityaddmore(); - cy.closeNotification(); - facilityPage.selectAreaOfSpecialization("Pulmonology"); - facilityPage.fillDoctorCount(doctorCapacity); - facilityPage.clickdoctorcapacityaddmore(); - cy.closeNotification(); - facilityPage.getTotalDoctorCapacity().contains(doctorCapacity); - facilityPage.clickcancelbutton(); - facilityPage.verifyfacilitynewurl(); - // verify the facility card - facilityPage.getFacilityName().contains(facilityName).should("be.visible"); - facilityPage - .getAddressDetailsView() - .contains(facilityAddress) - .should("be.visible"); - facilityPage - .getPhoneNumberView() - .contains(facilityNumber) - .should("be.visible"); - facilityPage - .getFacilityAvailableFeatures() - .invoke("text") - .then((text) => { - facilityFeature.forEach((feature) => { - expect(text).to.contain(feature); - }); - }); - facilityPage.getFacilityOxygenInfo().scrollIntoView(); - facilityPage - .getFacilityOxygenInfo() - .contains(oxygenCapacity) - .should("be.visible"); - facilityPage.getFacilityTotalBedCapacity().scrollIntoView(); - facilityPage.getFacilityTotalBedCapacity().contains(totalCapacity); - facilityPage.getFacilityTotalBedCapacity().contains(totalOccupancy); - facilityPage.getFacilityTotalDoctorCapacity().scrollIntoView(); - facilityPage.getFacilityTotalDoctorCapacity().contains(totalDoctor); - // verify the delete functionality - cy.get("#manage-facility-dropdown button").scrollIntoView(); - facilityPage.clickManageFacilityDropdown(); - facilityPage.clickDeleteFacilityOption(); - facilityPage.confirmDeleteFacility(); - cy.verifyNotification("Facility deleted successfully"); - }); - - it("Create a new facility with single bed and doctor capacity", () => { - const singleCapacityData = { - ...testFacilityData, - // Remove features, location, and oxygen that aren't used in this test - basic: { - ...testFacilityData.basic, - features: undefined, - location: undefined, - }, - oxygen: undefined, - // Override with single bed capacity - beds: [ - { - type: "Oxygen Supported Bed", - totalCapacity: oxygenCapacity, - occupied: oxygenExpected, - }, - ], - // Override with single doctor capacity - doctors: [ - { - specialization: "General Medicine", - count: doctorCapacity, - }, - ], - }; - facilityPage.createNewFacility(singleCapacityData); - // verify the created facility details - facilityPage.getFacilityName().contains(facilityName).should("be.visible"); - facilityPage - .getAddressDetailsView() - .contains(facilityAddress) - .should("be.visible"); - facilityPage - .getPhoneNumberView() - .contains(facilityNumber) - .should("be.visible"); - // verify the facility homepage - facilityHome.navigateToFacilityHomepage(); - facilityHome.typeFacilitySearch(facilityName); - advanceFilters.verifyFilterBadgePresence( - "Facility/District Name", + facilityPage.selectLocation("Kochi, Kerala"); + facilityPage.clickSaveFacilityButton(); + facilityPage.verifyFacilityCreatedNotification(); + // verify the facility card info + cy.verifyContentPresence("#facility-details-card", [ facilityName, - true, - ); - facilityHome.assertFacilityInCard(facilityName); - facilityHome.verifyURLContains(facilityName); - }); - - it("Create a new facility with no bed and doctor capacity", () => { - const noCapacityData = { - ...testFacilityData, - basic: { - ...testFacilityData.basic, - features: undefined, - location: undefined, - }, - oxygen: undefined, - beds: [], - doctors: [], - }; - facilityPage.visitCreateFacilityPage(); - facilityPage.fillBasicDetails(noCapacityData.basic); - facilityPage.fillLocationDetails(noCapacityData.location); - facilityPage.submitForm(); - // add no bed capacity and verify form error message - facilityPage.isVisibleselectBedType(); - facilityPage.saveAndExitBedCapacityForm(); - cy.verifyErrorMessages(bedErrorMessage); - facilityPage.clickcancelbutton(); - // add no doctor capacity and verify form error message - facilityPage.isVisibleAreaOfSpecialization(); - facilityPage.clickdoctorcapacityaddmore(); - cy.verifyErrorMessages(doctorErrorMessage); - facilityPage.clickcancelbutton(); - cy.url().then((newUrl) => { - facilityUrl1 = newUrl; - }); - // verify the created facility details - facilityPage.getFacilityName().contains(facilityName).should("be.visible"); - facilityPage - .getAddressDetailsView() - .contains(facilityAddress) - .should("be.visible"); - facilityPage - .getPhoneNumberView() - .contains(facilityNumber) - .should("be.visible"); - }); - - it("Update the existing facility", () => { - // update a existing dummy data facility - facilityPage.visitUpdateFacilityPage(facilityUrl1); + facilityAddress, + facilityNumber, + ]); + // Edit the facility data facilityPage.clickManageFacilityDropdown(); facilityPage.clickUpdateFacilityOption(); - facilityPage.selectFacilityType(facilityType); - facilityPage.fillAddress(facilityUpdateAddress); - facilityPage.fillOxygenCapacity(oxygenCapacity); - facilityPage.fillExpectedOxygenRequirement(oxygenExpected); - facilityPage.selectLocation("Kochi, Kerala"); - facilityPage.submitForm(); - cy.url().should("not.include", "/update"); - // verify the updated data - facilityPage.getFacilityOxygenInfo().scrollIntoView(); - facilityPage - .getFacilityOxygenInfo() - .contains(oxygenCapacity) - .should("be.visible"); - facilityPage.getAddressDetailsView().scrollIntoView(); - facilityPage - .getAddressDetailsView() - .contains(facilityUpdateAddress) - .should("be.visible"); + facilityPage.typeFacilityName(facilityUpdatedName, true); + facilityPage.typeFacilityPhoneNumber(facilityUpdatedNumber, true); + facilityPage.typeFacilityAddress(facilityUpdatedAddress, true); + facilityPage.clickUpdateFacilityButton(); + facilityPage.verifyFacilityUpdatedNotification(); + // verify the facility card updated info + cy.verifyContentPresence("#facility-details-card", [ + facilityUpdatedName, + facilityUpdatedAddress, + facilityUpdatedNumber, + ]); }); - it("Configure the existing facility", () => { - facilityPage.visitUpdateFacilityPage(facilityUrl1); + it("Create a new facility with only mandatory fields | Delete the facility", () => { + // Create a new facility + facilityPage.visitCreateFacilityPage(); + facilityPage.fillBasicDetails(testFacilityData.basic); + facilityPage.fillLocationDetails(testFacilityData.location); + facilityPage.clickSaveFacilityButton(); + facilityPage.verifyFacilityCreatedNotification(); + // verify the facility card info + cy.verifyContentPresence("#facility-details-card", [ + facilityName, + facilityAddress, + facilityNumber, + ]); + // verify the delete facility functionality facilityPage.clickManageFacilityDropdown(); - facilityPage.clickConfigureFacilityOption(); - facilityPage.fillMiddleWareAddress("dev_middleware.coronasafe.live"); - facilityPage.clickupdateMiddleWare(); - facilityPage.verifySuccessNotification( - "Facility middleware updated successfully", - ); + facilityPage.clickDeleteFacilityOption(); + facilityPage.confirmDeleteFacility(); + cy.verifyNotification(`${facilityName} deleted successfully`); }); it("Should display error when district admin tries to create facility in a different district", () => { + // Verify the entire form error message facilityPage.visitCreateFacilityPage(); - facilityPage.fillFacilityName(facilityName); - facilityPage.selectFacilityType(facilityType); + facilityPage.clickSaveFacilityButton(); + cy.verifyErrorMessages(facilityErrorMessage); + // Verify the user access based error message + facilityPage.fillBasicDetails(testFacilityData.basic); facilityPage.fillPincode("682001"); facilityPage.selectStateOnPincode("Kerala"); facilityPage.selectDistrictOnPincode("Kottayam"); facilityPage.selectLocalBody("Arpookara"); facilityPage.selectWard("5"); - facilityPage.fillAddress(facilityAddress); - facilityPage.fillPhoneNumber(facilityNumber); - facilityPage.submitForm(); + facilityPage.clickSaveFacilityButton(); facilityPage.verifyErrorNotification( "You do not have permission to perform this action.", ); diff --git a/cypress/e2e/facility_spec/FacilityHomepage.cy.ts b/cypress/e2e/facility_spec/FacilityHomepage.cy.ts index 680ce6fa2ce..0aa8518a6d1 100644 --- a/cypress/e2e/facility_spec/FacilityHomepage.cy.ts +++ b/cypress/e2e/facility_spec/FacilityHomepage.cy.ts @@ -21,8 +21,6 @@ describe("Facility Homepage Function", () => { const patientPage = new PatientPage(); const facilityLocation = new FacilityLocation(); const facilitiesAlias = "downloadFacilitiesCSV"; - const doctorsAlias = "downloadDoctorsCSV"; - const triagesAlias = "downloadTriagesCSV"; const facilityName = "Dummy Facility 40"; const facilityLocaion = "Dummy Location"; const stateName = "Kerala"; @@ -118,23 +116,7 @@ describe("Facility Homepage Function", () => { // Verify Facility Export facilityHome.csvDownloadIntercept(facilitiesAlias, ""); facilityHome.clickExportButton(); - facilityHome.clickMenuItem("Facilities"); facilityHome.verifyDownload(facilitiesAlias); - // Verify Doctor Export - facilityHome.csvDownloadIntercept(doctorsAlias, "&doctors"); - facilityHome.clickExportButton(); - facilityHome.clickMenuItem("Doctors"); - facilityHome.verifyDownload(doctorsAlias); - // Verify Triage Export - facilityHome.csvDownloadIntercept(triagesAlias, "&triage"); - facilityHome.clickExportButton(); - facilityHome.clickMenuItem("Triages"); - facilityHome.verifyDownload(triagesAlias); - }); - - it("Verify Capacity Export Functionality", () => { - facilityHome.clickExportButton(); - facilityHome.clickMenuItem("Capacities"); }); it("Verify Facility Detail page redirection to CNS and Live Minitoring ", () => { diff --git a/cypress/e2e/facility_spec/FacilityManage.cy.ts b/cypress/e2e/facility_spec/FacilityManage.cy.ts index 9f1523768c1..3930f470160 100644 --- a/cypress/e2e/facility_spec/FacilityManage.cy.ts +++ b/cypress/e2e/facility_spec/FacilityManage.cy.ts @@ -21,12 +21,6 @@ describe("Facility Manage Functions", () => { /Health Facility config updated successfully|Health ID registration failed/; const facilityHfrId = "IN180000018"; const facilityUpdatedHfrId = "IN180000020"; - const doctorCapacity = "5"; - const doctorModifiedCapacity = "7"; - const totalCapacity = "100"; - const currentOccupied = "80"; - const totalUpdatedCapacity = "120"; - const currentUpdatedOccupied = "100"; before(() => { loginPage.loginByRole("districtAdmin"); @@ -116,64 +110,6 @@ describe("Facility Manage Functions", () => { facilityManage.verifyHfrIdValue(facilityUpdatedHfrId); }); - it("Modify doctor capacity in Facility detail page", () => { - // Add a doctor capacity - facilityManage.clickFacilityAddDoctorTypeButton(); - facilityPage.selectAreaOfSpecialization("Pulmonology"); - facilityPage.fillDoctorCount(doctorCapacity); - facilityPage.saveAndExitDoctorForm(); - facilityManage.verifySuccessMessageVisibilityAndContent( - "Staff count added successfully", - ); - facilityManage.verifyTotalDoctorCapacity(doctorCapacity); - // edit a existing doctor - facilityManage.clickEditFacilityDoctorCapacity(); - facilityPage.fillDoctorCount(doctorModifiedCapacity); - facilityPage.clickdoctorcapacityaddmore(); - facilityManage.verifySuccessMessageVisibilityAndContent( - "Staff count updated successfully", - ); - facilityManage.verifyTotalDoctorCapacity(doctorModifiedCapacity); - // delete a bed - facilityManage.clickDeleteFacilityDoctorCapacity(); - facilityManage.clickButtonWithText("Delete"); - facilityManage.verifySuccessMessageVisibilityAndContent( - "Staff specialization type deleted successfully", - ); - }); - - it("Modify bed capacity in Facility detail page", () => { - // add multiple new bed capacity - facilityManage.clickFacilityAddBedTypeButton(); - facilityPage.selectBedType("Isolation Bed"); - facilityPage.fillTotalCapacity(totalCapacity); - facilityPage.fillCurrentlyOccupied(currentOccupied); - facilityPage.saveAndExitBedCapacityForm(); - facilityManage.verifySuccessMessageVisibilityAndContent( - "Bed capacity added successfully", - ); - cy.closeNotification(); - facilityManage.verifyFacilityBedCapacity(totalCapacity); - facilityManage.verifyFacilityBedCapacity(currentOccupied); - // edit a existing bed - facilityManage.clickEditFacilityBedCapacity(); - facilityPage.fillTotalCapacity(totalUpdatedCapacity); - facilityPage.fillCurrentlyOccupied(currentUpdatedOccupied); - facilityPage.clickbedcapcityaddmore(); - facilityManage.verifySuccessMessageVisibilityAndContent( - "Bed capacity updated successfully", - ); - cy.closeNotification(); - facilityManage.verifyFacilityBedCapacity(totalUpdatedCapacity); - facilityManage.verifyFacilityBedCapacity(currentUpdatedOccupied); - // delete a bed - facilityManage.clickDeleteFacilityBedCapacity(); - facilityManage.clickButtonWithText("Delete"); - facilityManage.verifySuccessMessageVisibilityAndContent( - "Bed type deleted successfully", - ); - }); - afterEach(() => { cy.saveLocalStorage(); }); diff --git a/cypress/e2e/patient_spec/PatientHomepage.cy.ts b/cypress/e2e/patient_spec/PatientHomepage.cy.ts index a120e282a2d..8949fc3e324 100644 --- a/cypress/e2e/patient_spec/PatientHomepage.cy.ts +++ b/cypress/e2e/patient_spec/PatientHomepage.cy.ts @@ -54,7 +54,6 @@ describe("Patient Homepage present functionalities", () => { patientHome.verifyPatientAdmittedBeforeDate(patientToDateBadge); patientHome.verifyPatientAdmittedAfterDate(patientFromDateBadge); cy.clearAllFilters(); - patientHome.verifyTotalPatientCount("1"); }); it("Facility Geography based advance filters applied in the patient tab", () => { @@ -71,7 +70,6 @@ describe("Patient Homepage present functionalities", () => { patientHome.verifyFacilityLsgBadgeContent(facilityLsgBody); patientHome.verifyFacilityDistrictContent(facilityDistrict); cy.clearAllFilters(); - patientHome.verifyTotalPatientCount("1"); }); it("Patient diagnosis based advance filters applied in the patient tab", () => { @@ -104,7 +102,6 @@ describe("Patient Homepage present functionalities", () => { patientHome.verifyDifferentialDiagnosisBadgeContent(patientIcdDiagnosis); // Clear the badges and verify the patient count along with badges cy.clearAllFilters(); - patientHome.verifyTotalPatientCount("1"); // Apply Any and confirmed diagonsis to verify patient count 17 advanceFilters.clickAdvancedFiltersButton(); patientHome.selectAnyIcdDiagnosis(patientIcdDiagnosis, patientIcdDiagnosis); @@ -142,7 +139,6 @@ describe("Patient Homepage present functionalities", () => { patientHome.verifyMedicoBadgeContent("false"); // Clear the badges and verify the patient count along with badges cy.clearAllFilters(); - patientHome.verifyTotalPatientCount("1"); }); it("Export the live patient list based on a date range", () => { diff --git a/cypress/e2e/resource_spec/ResourcesHomepage.cy.ts b/cypress/e2e/resource_spec/ResourcesHomepage.cy.ts index 23077a71ed8..160884978fd 100644 --- a/cypress/e2e/resource_spec/ResourcesHomepage.cy.ts +++ b/cypress/e2e/resource_spec/ResourcesHomepage.cy.ts @@ -20,14 +20,15 @@ describe("Resource Page", () => { beforeEach(() => { cy.restoreLocalStorage(); cy.clearLocalStorage(/filters--.+/); - cy.awaitUrl("/resource"); }); it("Checks if all download button works", () => { + resourcePage.navigationToResourcePage(); resourcePage.verifyDownloadButtonWorks(); }); it("Switch between active/completed", () => { + resourcePage.navigationToResourcePage(); resourcePage.spyResourceApi(); resourcePage.clickCompletedResources(); resourcePage.verifyCompletedResources(); @@ -37,6 +38,7 @@ describe("Resource Page", () => { }); it("Switch between list view and board view", () => { + resourcePage.navigationToResourcePage(); resourcePage.clickListViewButton(); resourcePage.clickBoardViewButton(); }); @@ -68,7 +70,7 @@ describe("Resource Page", () => { }); it("Update the status of resource", () => { - cy.visit(createdResource); + cy.awaitUrl(createdResource); resourcePage.clickUpdateStatus(); resourcePage.updateStatus("APPROVED"); resourcePage.clickSubmitButton(); @@ -78,7 +80,7 @@ describe("Resource Page", () => { }); it("Post comment for a resource", () => { - cy.visit(createdResource); + cy.awaitUrl(createdResource); resourcePage.addCommentForResource("Test comment"); resourcePage.clickPostCommentButton(); resourcePage.verifySuccessNotification("Comment added successfully"); diff --git a/cypress/pageobject/Facility/FacilityCreation.ts b/cypress/pageobject/Facility/FacilityCreation.ts index e59dfef09f3..9776433e523 100644 --- a/cypress/pageobject/Facility/FacilityCreation.ts +++ b/cypress/pageobject/Facility/FacilityCreation.ts @@ -16,31 +16,6 @@ export interface FacilityData { localBody: string; ward: string; }; - oxygen?: { - capacity: string; - expected: string; - bType?: { - capacity: string; - expected: string; - }; - cType?: { - capacity: string; - expected: string; - }; - dType?: { - capacity: string; - expected: string; - }; - }; - beds?: Array<{ - type: string; - totalCapacity: string; - occupied: string; - }>; - doctors?: Array<{ - specialization: string; - count: string; - }>; } class FacilityPage { @@ -60,15 +35,8 @@ class FacilityPage { advanceFilters.selectLocalBody(localBody); } - visitUpdateFacilityPage(url: string) { - cy.intercept("GET", "**/api/v1/facility/**").as("getFacilities"); - cy.visit(url); - cy.wait("@getFacilities").its("response.statusCode").should("eq", 200); - cy.get("#manage-facility-dropdown button").should("be.visible"); - } - - fillFacilityName(name: string) { - cy.get("#name").click().clear().click().type(name); + typeFacilityName(name: string, clearBeforeTyping: boolean = false) { + cy.typeIntoField("#name", name, { clearBeforeTyping }); } fillPincode(pincode: string) { @@ -80,90 +48,29 @@ class FacilityPage { cy.get("[role='option']").contains(ward).click(); } - fillAddress(address: string) { - cy.get("#address").click().type(address); - } - - fillPhoneNumber(phoneNumber: string) { - cy.get("#phone_number").type(phoneNumber); - } - - submitForm() { - cy.get("button#submit").click(); - } - - selectBedType(bedType: string) { - cy.clickAndSelectOption("div#bed-type button", bedType); - } - - isVisibleselectBedType() { - cy.get("div#bed-type button").should("be.visible"); - } - - fillTotalCapacity(capacity: string) { - cy.get("input#total-capacity").click().clear().click().type(capacity); - } - - fillCurrentlyOccupied(occupied: string) { - cy.get("input#currently-occupied").click().clear().click().type(occupied); - } - - saveAndExitBedCapacityForm() { - cy.get("button#bed-capacity-save-and-exit").click(); - } - - selectAreaOfSpecialization(area: string) { - cy.get("div#area-of-specialization button").click(); - cy.get("[role='option']").contains(area).click(); + typeFacilityAddress(address: string, clearBeforeTyping: boolean = false) { + cy.typeIntoField("#address", address, { clearBeforeTyping }); } - isVisibleAreaOfSpecialization() { - cy.get("div#area-of-specialization button").should("be.visible"); - } - - fillDoctorCount(count: string) { - cy.get("input#count").click().clear().click().type(count); - } - - fillOxygenCapacity(capacity: string) { - cy.get("#oxygen_capacity").click().clear().type(capacity); - } - - fillExpectedOxygenRequirement(requirement: string) { - cy.get("#expected_oxygen_requirement").click().clear().type(requirement); - } - - fillBTypeCylinderCapacity(capacity: string) { - cy.get("#type_b_cylinders").click().clear().type(capacity); - } - - fillExpectedBTypeCylinderRequirement(requirement: string) { - cy.get("#expected_type_b_cylinders").focus().clear(); - cy.get("#expected_type_b_cylinders").focus().type(requirement); - } - - fillCTypeCylinderCapacity(capacity: string) { - cy.get("#type_c_cylinders").click().clear().type(capacity); - } - - fillExpectedCTypeCylinderRequirement(requirement: string) { - cy.get("#expected_type_c_cylinders").focus().clear(); - cy.get("#expected_type_c_cylinders").focus().type(requirement); + typeFacilityPhoneNumber( + phoneNumber: string, + clearBeforeTyping: boolean = false, + ) { + cy.typeIntoField("#phone_number", phoneNumber, { clearBeforeTyping }); } - fillDTypeCylinderCapacity(capacity: string) { - cy.get("#type_d_cylinders").click().clear().type(capacity); + clickSaveFacilityButton() { + cy.verifyAndClickElement("#submit", "Save Facility"); } - fillExpectedDTypeCylinderRequirement(requirement: string) { - cy.get("#expected_type_d_cylinders").focus().clear(); - cy.get("#expected_type_d_cylinders").focus().type(requirement); + verifyFacilityCreatedNotification() { + cy.verifyNotification("Facility added successfully"); + cy.closeNotification(); } - saveAndExitDoctorForm() { - cy.intercept("GET", "**/api/v1/facility/**").as("createFacilities"); - cy.get("button#save-and-exit").click(); - cy.wait("@createFacilities").its("response.statusCode").should("eq", 200); + verifyFacilityUpdatedNotification() { + cy.verifyNotification("Facility updated successfully"); + cy.closeNotification(); } clickManageFacilityDropdown() { @@ -178,6 +85,10 @@ class FacilityPage { cy.get("#update-facility").contains("Update Facility").click(); } + clickUpdateFacilityButton() { + cy.verifyAndClickElement("#submit", "Update Facility"); + } + clickConfigureFacilityOption() { cy.get("#configure-facility").contains("Configure Facility").click(); } @@ -199,22 +110,6 @@ class FacilityPage { cy.get("#inventory-management").click(); } - getTotalBedCapacity() { - return cy.get("#total-bed-capacity"); - } - - getFacilityTotalBedCapacity() { - return cy.get("#facility-bed-capacity-details"); - } - - getFacilityTotalDoctorCapacity() { - return cy.get("#facility-doctor-capacity-details"); - } - - getTotalDoctorCapacity() { - return cy.get("#total-doctor-capacity"); - } - getFacilityName() { return cy.get("#facility-name"); } @@ -231,10 +126,6 @@ class FacilityPage { return cy.get("#facility-available-features"); } - getFacilityOxygenInfo() { - return cy.get("#facility-oxygen-info"); - } - clickResourceRequestOption() { cy.get("#resource-request").contains("Resource Request").click(); } @@ -243,64 +134,10 @@ class FacilityPage { cy.get("#delete-facility").contains("Delete Facility").click(); } - scrollToFacilityTriage() { - cy.get("#add-facility-triage").scrollIntoView(); - } - - fillTriageEntryFields( - visited: string, - homeQuarantine: string, - isolation: string, - referred: string, - confirmedPositive: string, - ) { - cy.get("#num_patients_visited").clear().click().type(visited); - cy.get("#num_patients_home_quarantine") - .clear() - .click() - .type(homeQuarantine); - cy.get("#num_patients_isolation").clear().click().type(isolation); - cy.get("#num_patient_referred").clear().click().type(referred); - cy.get("#num_patient_confirmed_positive") - .clear() - .click() - .type(confirmedPositive); - } - - fillEntryDate(date: string) { - cy.clickAndTypeDate("#entry_date", date); - } - - clickEditButton() { - cy.get("#edit-button").click(); - } - - clickButtonsMultipleTimes(selector: string) { - cy.get(selector).each(($button) => { - cy.wrap($button).click(); - }); - } - - verifyTriageTableContains(value: string) { - cy.get("#triage-table").contains(value); - } - - clickAddFacilityTriage() { - cy.get("#add-facility-triage").click(); - } - clickfacilityfeatureoption() { cy.get("#features").click(); } - clickbedcapcityaddmore() { - cy.get("#bed-capacity-save").click(); - } - - clickdoctorcapacityaddmore() { - cy.get("#doctor-save").click(); - } - clickcancelbutton() { cy.get("#cancel").click(); } @@ -509,30 +346,15 @@ class FacilityPage { // Fill location details this.fillLocationDetails(data.location); - // Fill oxygen details if provided - if (data.oxygen) { - this.fillOxygenDetails(data.oxygen); - } - - this.submitForm(); + this.clickSaveFacilityButton(); cy.closeNotification(); - // Add bed capacity if provided - if (data.beds) { - this.addBedCapacities(data.beds); - } - - // Add doctor capacity if provided - if (data.doctors) { - this.addDoctorCapacities(data.doctors); - } - this.verifyfacilitynewurl(); return this; } fillBasicDetails(basic: FacilityData["basic"]) { - this.fillFacilityName(basic.name); + this.typeFacilityName(basic.name); this.selectFacilityType(basic.type); if (basic.features?.length) { @@ -543,8 +365,8 @@ class FacilityPage { this.clickfacilityfeatureoption(); } - this.fillAddress(basic.address); - this.fillPhoneNumber(basic.phoneNumber); + this.typeFacilityAddress(basic.address); + this.typeFacilityPhoneNumber(basic.phoneNumber); if (basic.location) { this.selectLocation(basic.location); @@ -558,47 +380,6 @@ class FacilityPage { this.selectLocalBody(location.localBody); this.selectWard(location.ward); } - - fillOxygenDetails(oxygen: NonNullable) { - this.fillOxygenCapacity(oxygen.capacity); - this.fillExpectedOxygenRequirement(oxygen.expected); - - if (oxygen.bType) { - this.fillBTypeCylinderCapacity(oxygen.bType.capacity); - this.fillExpectedBTypeCylinderRequirement(oxygen.bType.expected); - } - - if (oxygen.cType) { - this.fillCTypeCylinderCapacity(oxygen.cType.capacity); - this.fillExpectedCTypeCylinderRequirement(oxygen.cType.expected); - } - - if (oxygen.dType) { - this.fillDTypeCylinderCapacity(oxygen.dType.capacity); - this.fillExpectedDTypeCylinderRequirement(oxygen.dType.expected); - } - } - - addBedCapacities(beds: NonNullable) { - beds.forEach((bed) => { - this.selectBedType(bed.type); - this.fillTotalCapacity(bed.totalCapacity); - this.fillCurrentlyOccupied(bed.occupied); - this.clickbedcapcityaddmore(); - cy.closeNotification(); - }); - this.clickcancelbutton(); - } - - addDoctorCapacities(doctors: NonNullable) { - doctors.forEach((doctor) => { - this.selectAreaOfSpecialization(doctor.specialization); - this.fillDoctorCount(doctor.count); - this.clickdoctorcapacityaddmore(); - cy.closeNotification(); - }); - this.clickcancelbutton(); - } } export default FacilityPage; diff --git a/cypress/pageobject/Facility/FacilityHome.ts b/cypress/pageobject/Facility/FacilityHome.ts index bbf5945453e..24f7d321628 100644 --- a/cypress/pageobject/Facility/FacilityHome.ts +++ b/cypress/pageobject/Facility/FacilityHome.ts @@ -1,7 +1,6 @@ class FacilityHome { // Selectors exportButton = "#export-button"; - menuItem = "[role='menuitem']"; // Operations clickExportButton() { @@ -10,7 +9,7 @@ class FacilityHome { } navigateToFacilityHomepage() { - cy.visit("/facility"); + cy.awaitUrl("/facility"); } assertFacilityInCard(facilityName: string) { @@ -29,10 +28,6 @@ class FacilityHome { cy.get("#facility-search").click().clear().type(facilityName); } - clickMenuItem(itemName: string) { - cy.get(this.menuItem).contains(itemName).click(); - } - csvDownloadIntercept(alias: string, queryParam: string) { cy.intercept("GET", `**/api/v1/facility/?csv${queryParam}`).as(alias); } diff --git a/cypress/pageobject/Facility/FacilityManage.ts b/cypress/pageobject/Facility/FacilityManage.ts index e7eecddab3c..00d9f642bbc 100644 --- a/cypress/pageobject/Facility/FacilityManage.ts +++ b/cypress/pageobject/Facility/FacilityManage.ts @@ -18,30 +18,6 @@ class FacilityManage { cy.get("#save-cover-image").click(); } - verifyTotalDoctorCapacity(expectedCapacity: string) { - cy.get("#facility-doctor-totalcapacity").contains(expectedCapacity); - } - - verifyFacilityBedCapacity(expectedCapacity: string) { - cy.get("#facility-bed-capacity-details").contains(expectedCapacity); - } - - clickEditFacilityDoctorCapacity() { - cy.get("#edit-facility-doctorcapacity").click(); - } - - clickEditFacilityBedCapacity() { - cy.get("#edit-facility-bedcapacity").click(); - } - - clickDeleteFacilityDoctorCapacity() { - cy.get("#delete-facility-doctorcapacity").click(); - } - - clickDeleteFacilityBedCapacity() { - cy.get("#delete-facility-bedcapacity").click(); - } - clickFacilityConfigureButton() { cy.get("#configure-facility").should("be.visible"); cy.get("#configure-facility").click(); @@ -90,16 +66,6 @@ class FacilityManage { cy.get("#hf_id").should("have.value", expectedValue); } - clickFacilityAddDoctorTypeButton() { - cy.get("#facility-add-doctortype").scrollIntoView(); - cy.get("#facility-add-doctortype").click(); - } - - clickFacilityAddBedTypeButton() { - cy.get("#facility-add-bedtype").scrollIntoView(); - cy.get("#facility-add-bedtype").click(); - } - visitViewPatients() { cy.intercept("GET", "**/api/v1/facility/**").as("getFacilityPatients"); cy.get("#view-patient-facility-list").scrollIntoView().click(); diff --git a/cypress/pageobject/Resource/ResourcePage.ts b/cypress/pageobject/Resource/ResourcePage.ts index 730d3dd9148..c01c60baec5 100644 --- a/cypress/pageobject/Resource/ResourcePage.ts +++ b/cypress/pageobject/Resource/ResourcePage.ts @@ -28,6 +28,10 @@ class ResourcePage { cy.contains("button", "Active").click(); } + navigationToResourcePage() { + cy.awaitUrl("/resource"); + } + verifyActiveResources() { cy.wait("@resource").its("response.statusCode").should("eq", 200); cy.contains("button", "Active").should("have.class", "text-white"); diff --git a/cypress/pageobject/utils/constants.ts b/cypress/pageobject/utils/constants.ts index 053d0561ce8..90baf3b6d4b 100644 --- a/cypress/pageobject/utils/constants.ts +++ b/cypress/pageobject/utils/constants.ts @@ -1,10 +1,122 @@ -export function generatePhoneNumber(): string { +function generatePhoneNumber(): string { const array = new Uint32Array(1); window.crypto.getRandomValues(array); const randomNum = (array[0] % 900000000) + 100000000; return "9" + randomNum.toString(); } -export function generateEmergencyPhoneNumber(): string { +function generateEmergencyPhoneNumber(): string { return generatePhoneNumber(); } + +function generateFacilityName(): string { + const prefixes = [ + "GHC", + "NHC", + "SHC", + "Apollo", + "General", + "St. Mary's", + "Central", + "Kochi", + ]; + const locations = [ + "North", + "South", + "East", + "West", + "Downtown", + "Metro", + "Springfield", + "Ernakulam", + ]; + const identifiers = [ + () => Math.floor(Math.random() * 100), // Numeric IDs + () => `Zone-${Math.floor(Math.random() * 10)}`, // Zone IDs + () => `Block-${String.fromCharCode(65 + Math.floor(Math.random() * 26))}`, // Alphabetic Blocks + ]; + const suffixes = [ + "Meta", + "Prime", + "Care", + "Wellness", + "Clinic", + "Center", + "Specialists", + "Hospital", + ]; + + const randomPrefix = prefixes[Math.floor(Math.random() * prefixes.length)]; + const randomLocation = + locations[Math.floor(Math.random() * locations.length)]; + const randomIdentifier = + identifiers[Math.floor(Math.random() * identifiers.length)](); + const randomSuffix = suffixes[Math.floor(Math.random() * suffixes.length)]; + + // Randomize the format of the name + const formats = [ + `${randomPrefix} ${randomLocation}-${randomIdentifier} ${randomSuffix}`, + `${randomLocation} ${randomPrefix} ${randomSuffix}`, + `${randomPrefix} ${randomLocation} ${randomSuffix}`, + ]; + + return formats[Math.floor(Math.random() * formats.length)]; +} + +function generateRandomAddress(multiline: boolean = false): string { + const localities = [ + "Marine Drive", + "Fort Kochi", + "Thevara", + "Vyttila", + "Edappally", + "Palarivattom", + "Kakkanad", + "Mattancherry", + "Kaloor", + "Tripunithura", + ]; + const neighborhoods = [ + "Lane 1", + "Lane 2", + "North Block", + "East End", + "West Side", + "Central Area", + "Market Road", + "Garden Street", + "Highland Avenue", + ]; + const districts = ["Kochi", "Ernakulam"]; + const states = ["Kerala"]; + const pincode = Math.floor(682000 + Math.random() * 1000).toString(); // Generate random pincodes in the 682XXX range. + + const randomLocality = + localities[Math.floor(Math.random() * localities.length)]; + const randomNeighborhood = + neighborhoods[Math.floor(Math.random() * neighborhoods.length)]; + const randomDistrict = + districts[Math.floor(Math.random() * districts.length)]; + const randomState = states[Math.floor(Math.random() * states.length)]; + + // Create address components + const addressParts = [ + randomNeighborhood, + randomLocality, + randomDistrict, + randomState, + `Pincode: ${pincode}`, + ]; + + // Return address as single line or multiline + // If 'multiline' is false, return address as a single line + // If 'multiline' is true, return address with each component on a new line + return multiline ? addressParts.join("\n") : addressParts.join(", "); +} + +export { + generatePhoneNumber, + generateEmergencyPhoneNumber, + generateFacilityName, + generateRandomAddress, +}; diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index 0268beebc42..f5bbcf42290 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -241,3 +241,21 @@ Cypress.Commands.add("verifyErrorMessages", (errorMessages: string[]) => { }); }); }); + +Cypress.Commands.add( + "typeIntoField", + ( + selector: string, + value: string, + options: { clearBeforeTyping?: boolean } = {}, + ) => { + const { clearBeforeTyping = false } = options; + const inputField = cy.get(selector); + + if (clearBeforeTyping) { + inputField.clear(); // Clear the input field + } + + inputField.click().type(value); // Click and type the new value + }, +); diff --git a/cypress/support/index.ts b/cypress/support/index.ts index 831ee71a5bc..fa01326698c 100644 --- a/cypress/support/index.ts +++ b/cypress/support/index.ts @@ -46,6 +46,11 @@ declare global { texts: string[], ): Chainable; verifyErrorMessages(errorMessages: string[]): Chainable; + typeIntoField( + selector: string, + value: string, + options?: { clearBeforeTyping?: boolean }, + ): Chainable; } } } diff --git a/package-lock.json b/package-lock.json index 7953eb2e8e9..fde94c88b30 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,7 +55,7 @@ "events": "^3.3.0", "hi-profiles": "^1.1.0", "i18next": "^23.16.4", - "i18next-browser-languagedetector": "^8.0.0", + "i18next-browser-languagedetector": "^8.0.2", "i18next-http-backend": "^3.0.1", "lodash-es": "^4.17.21", "next-themes": "^0.4.3", @@ -11802,9 +11802,9 @@ } }, "node_modules/i18next-browser-languagedetector": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz", - "integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.2.tgz", + "integrity": "sha512-shBvPmnIyZeD2VU5jVGIOWP7u9qNG3Lj7mpaiPFpbJ3LVfHZJvVzKR4v1Cb91wAOFpNw442N+LGPzHOHsten2g==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.2" @@ -21716,4 +21716,4 @@ } } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index a1cd175fe52..109dee83d71 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "events": "^3.3.0", "hi-profiles": "^1.1.0", "i18next": "^23.16.4", - "i18next-browser-languagedetector": "^8.0.0", + "i18next-browser-languagedetector": "^8.0.2", "i18next-http-backend": "^3.0.1", "lodash-es": "^4.17.21", "next-themes": "^0.4.3", diff --git a/public/locale/en.json b/public/locale/en.json index 759c0318244..96af723ae62 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -1279,8 +1279,8 @@ "req_atleast_one_uppercase": "Require at least one upper case", "request-sample-test": "Service Request", "request_consent": "Request Consent", - "request_description": "Description of Request", - "request_description_placeholder": "Type your description here", + "request_reason": "Reason of Request", + "request_reason_placeholder": "Type your description here", "request_sample_test": "Request Sample Test", "request_title": "Request Title", "request_title_placeholder": "Type your title here", diff --git a/public/locale/hi.json b/public/locale/hi.json index 9e6a667ba23..568ce0499f6 100644 --- a/public/locale/hi.json +++ b/public/locale/hi.json @@ -643,8 +643,8 @@ "req_atleast_one_lowercase": "कम से कम एक लोअर केस अक्षर की आवश्यकता है", "req_atleast_one_symbol": "कम से कम एक प्रतीक की आवश्यकता है", "req_atleast_one_uppercase": "कम से कम एक अपर केस की आवश्यकता है", - "request_description": "अनुरोध का विवरण", - "request_description_placeholder": "अपना विवरण यहाँ लिखें", + "request_reason": "अनुरोध का विवरण", + "request_reason_placeholder": "अपना विवरण यहाँ लिखें", "request_title": "शीर्षक का अनुरोध करें", "request_title_placeholder": "अपना शीर्षक यहाँ लिखें", "required": "आवश्यक", diff --git a/public/locale/kn.json b/public/locale/kn.json index faf50da3a23..4907cdd2d8c 100644 --- a/public/locale/kn.json +++ b/public/locale/kn.json @@ -645,8 +645,8 @@ "req_atleast_one_lowercase": "ಕನಿಷ್ಠ ಒಂದು ಸಣ್ಣ ಅಕ್ಷರದ ಅಗತ್ಯವಿದೆ", "req_atleast_one_symbol": "ಕನಿಷ್ಠ ಒಂದು ಚಿಹ್ನೆಯ ಅಗತ್ಯವಿದೆ", "req_atleast_one_uppercase": "ಕನಿಷ್ಠ ಒಂದು ದೊಡ್ಡ ಪ್ರಕರಣದ ಅಗತ್ಯವಿದೆ", - "request_description": "ವಿನಂತಿಯ ವಿವರಣೆ", - "request_description_placeholder": "ನಿಮ್ಮ ವಿವರಣೆಯನ್ನು ಇಲ್ಲಿ ಟೈಪ್ ಮಾಡಿ", + "request_reason": "ವಿನಂತಿಯ ವಿವರಣೆ", + "request_reason_placeholder": "ನಿಮ್ಮ ವಿವರಣೆಯನ್ನು ಇಲ್ಲಿ ಟೈಪ್ ಮಾಡಿ", "request_title": "ವಿನಂತಿ ಶೀರ್ಷಿಕೆ", "request_title_placeholder": "ನಿಮ್ಮ ಶೀರ್ಷಿಕೆಯನ್ನು ಇಲ್ಲಿ ಟೈಪ್ ಮಾಡಿ", "required": "ಅಗತ್ಯವಿದೆ", diff --git a/public/locale/ml.json b/public/locale/ml.json index 33dadcf9fb7..b875a64dd02 100644 --- a/public/locale/ml.json +++ b/public/locale/ml.json @@ -644,8 +644,8 @@ "req_atleast_one_lowercase": "കുറഞ്ഞത് ഒരു ചെറിയ അക്ഷരമെങ്കിലും ആവശ്യമാണ്", "req_atleast_one_symbol": "കുറഞ്ഞത് ഒരു ചിഹ്നമെങ്കിലും ആവശ്യമാണ്", "req_atleast_one_uppercase": "കുറഞ്ഞത് ഒരു വലിയ കേസെങ്കിലും ആവശ്യമാണ്", - "request_description": "അഭ്യർത്ഥനയുടെ വിവരണം", - "request_description_placeholder": "നിങ്ങളുടെ വിവരണം ഇവിടെ ടൈപ്പ് ചെയ്യുക", + "request_reason": "അഭ്യർത്ഥനയുടെ വിവരണം", + "request_reason_placeholder": "നിങ്ങളുടെ വിവരണം ഇവിടെ ടൈപ്പ് ചെയ്യുക", "request_title": "പേര് അഭ്യർത്ഥിക്കുക", "request_title_placeholder": "നിങ്ങളുടെ തലക്കെട്ട് ഇവിടെ ടൈപ്പ് ചെയ്യുക", "required": "ആവശ്യമാണ്", diff --git a/public/locale/ta.json b/public/locale/ta.json index 694efd52e20..cfe12b5fa6a 100644 --- a/public/locale/ta.json +++ b/public/locale/ta.json @@ -643,8 +643,8 @@ "req_atleast_one_lowercase": "குறைந்தபட்சம் ஒரு சிறிய எழுத்து தேவை", "req_atleast_one_symbol": "குறைந்தது ஒரு சின்னம் தேவை", "req_atleast_one_uppercase": "குறைந்தபட்சம் ஒரு பெரிய வழக்கு தேவை", - "request_description": "கோரிக்கையின் விளக்கம்", - "request_description_placeholder": "உங்கள் விளக்கத்தை இங்கே தட்டச்சு செய்யவும்", + "request_reason": "கோரிக்கையின் விளக்கம்", + "request_reason_placeholder": "உங்கள் விளக்கத்தை இங்கே தட்டச்சு செய்யவும்", "request_title": "தலைப்பு கோரிக்கை", "request_title_placeholder": "உங்கள் தலைப்பை இங்கே தட்டச்சு செய்யவும்", "required": "தேவை", diff --git a/src/App.tsx b/src/App.tsx index 22edefc105c..b115f9f2f22 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,5 @@ import { + MutationCache, QueryCache, QueryClient, QueryClientProvider, @@ -17,17 +18,10 @@ import AuthUserProvider from "@/Providers/AuthUserProvider"; import HistoryAPIProvider from "@/Providers/HistoryAPIProvider"; import Routers from "@/Routers"; import { FeatureFlagsProvider } from "@/Utils/featureFlags"; -import { handleQueryError } from "@/Utils/request/errorHandler"; -import { QueryError } from "@/Utils/request/queryError"; +import { handleHttpError } from "@/Utils/request/errorHandler"; import { PubSubProvider } from "./Utils/pubsubContext"; -declare module "@tanstack/react-query" { - interface Register { - defaultError: QueryError; - } -} - const queryClient = new QueryClient({ defaultOptions: { queries: { @@ -36,7 +30,10 @@ const queryClient = new QueryClient({ }, }, queryCache: new QueryCache({ - onError: handleQueryError, + onError: handleHttpError, + }), + mutationCache: new MutationCache({ + onError: handleHttpError, }), }); diff --git a/src/Utils/request/README.md b/src/Utils/request/README.md index 3c1279e1554..75dfab6c10f 100644 --- a/src/Utils/request/README.md +++ b/src/Utils/request/README.md @@ -67,10 +67,12 @@ function FacilityDetails({ id }: { id: string }) { - Integrates with our global error handling. ```typescript -interface QueryOptions { +interface APICallOptions { pathParams?: Record; // URL parameters - queryParams?: Record; // Query string parameters + queryParams?: QueryParams; // Query string parameters + body?: TBody; // Request body silent?: boolean; // Suppress error notifications + headers?: HeadersInit; // Additional headers } // Basic usage @@ -100,6 +102,82 @@ are automatically handled. Use the `silent: true` option to suppress error notifications for specific queries. +## Using Mutations with TanStack Query + +For data mutations, we provide a `mutate` utility that works seamlessly with TanStack Query's `useMutation` hook. + +```tsx +import { useMutation } from "@tanstack/react-query"; +import mutate from "@/Utils/request/mutate"; + +function CreatePrescription({ consultationId }: { consultationId: string }) { + const { mutate: createPrescription, isPending } = useMutation({ + mutationFn: mutate(MedicineRoutes.createPrescription, { + pathParams: { consultationId }, + }), + onSuccess: () => { + toast.success("Prescription created successfully"); + }, + }); + + return ( + + ); +} + +// With path parameters and complex payload +function UpdatePatient({ patientId }: { patientId: string }) { + const { mutate: updatePatient } = useMutation({ + mutationFn: mutate(PatientRoutes.update, { + pathParams: { id: patientId }, + silent: true // Optional: suppress error notifications + }) + }); + + const handleSubmit = (data: PatientData) => { + updatePatient(data); + }; + + return ; +} +``` + +### mutate + +`mutate` is our wrapper around the API call functionality that works with TanStack Query's `useMutation`. It: +- Handles request body serialization +- Sets appropriate headers +- Integrates with our global error handling +- Provides TypeScript type safety for your mutation payload + +```typescript +interface APICallOptions { + pathParams?: Record; // URL parameters + queryParams?: QueryParams; // Query string parameters + body?: TBody; // Request body + silent?: boolean; // Suppress error notifications + headers?: HeadersInit; // Additional headers +} + +// Basic usage +useMutation({ + mutationFn: mutate(routes.users.create) +}); + +// With parameters +useMutation({ + mutationFn: mutate(routes.users.update, { + pathParams: { id }, + silent: true // Optional: suppress error notifications + }) +}); +``` + ## Migration Guide & Reference ### Understanding the Transition diff --git a/src/Utils/request/api.tsx b/src/Utils/request/api.tsx index f7a036f71a3..23676938942 100644 --- a/src/Utils/request/api.tsx +++ b/src/Utils/request/api.tsx @@ -569,23 +569,6 @@ const routes = { method: "GET", TRes: Type(), }, - downloadFacilityCapacity: { - path: "/api/v1/facility/?csv&capacity", - method: "GET", - TRes: Type(), - }, - downloadFacilityDoctors: { - path: "/api/v1/facility/?csv&doctors", - method: "GET", - TRes: Type(), - }, - - downloadFacilityTriage: { - path: "/api/v1/facility/?csv&triage", - method: "GET", - TRes: Type(), - }, - downloadPatients: { path: "/api/v1/patient/?csv", method: "GET", diff --git a/src/Utils/request/errorHandler.ts b/src/Utils/request/errorHandler.ts index 68d7e4600bb..c5609181f13 100644 --- a/src/Utils/request/errorHandler.ts +++ b/src/Utils/request/errorHandler.ts @@ -1,14 +1,14 @@ import { navigate } from "raviger"; import * as Notifications from "@/Utils/Notifications"; -import { QueryError } from "@/Utils/request/queryError"; +import { HTTPError } from "@/Utils/request/types"; -export function handleQueryError(error: Error) { +export function handleHttpError(error: Error) { if (error.name === "AbortError") { return; } - if (!(error instanceof QueryError)) { + if (!(error instanceof HTTPError)) { Notifications.Error({ msg: error.message || "Something went wrong!" }); return; } @@ -34,7 +34,7 @@ export function handleQueryError(error: Error) { }); } -function isSessionExpired(error: QueryError["cause"]) { +function isSessionExpired(error: HTTPError["cause"]) { return ( // If Authorization header is not valid error?.code === "token_not_valid" || @@ -49,6 +49,6 @@ function handleSessionExpired() { } } -function isBadRequest(error: QueryError) { +function isBadRequest(error: HTTPError) { return error.status === 400 || error.status === 406; } diff --git a/src/Utils/request/mutate.ts b/src/Utils/request/mutate.ts new file mode 100644 index 00000000000..2372920c162 --- /dev/null +++ b/src/Utils/request/mutate.ts @@ -0,0 +1,26 @@ +import { callApi } from "@/Utils/request/query"; +import { APICallOptions, Route } from "@/Utils/request/types"; + +/** + * Creates a TanStack Query compatible mutation function. + * + * Example: + * ```tsx + * const { mutate: createPrescription, isPending } = useMutation({ + * mutationFn: mutate(MedicineRoutes.createPrescription, { + * pathParams: { consultationId }, + * }), + * onSuccess: () => { + * toast.success(t("medication_request_prescribed")); + * }, + * }); + * ``` + */ +export default function mutate( + route: Route, + options?: APICallOptions, +) { + return (variables: TBody) => { + return callApi(route, { ...options, body: variables }); + }; +} diff --git a/src/Utils/request/query.ts b/src/Utils/request/query.ts index 3431f625728..dc79bd874ec 100644 --- a/src/Utils/request/query.ts +++ b/src/Utils/request/query.ts @@ -1,19 +1,18 @@ import careConfig from "@careConfig"; -import { QueryError } from "@/Utils/request/queryError"; import { getResponseBody } from "@/Utils/request/request"; -import { QueryOptions, Route } from "@/Utils/request/types"; +import { APICallOptions, HTTPError, Route } from "@/Utils/request/types"; import { makeHeaders, makeUrl } from "@/Utils/request/utils"; -async function queryRequest( +export async function callApi( { path, method, noAuth }: Route, - options?: QueryOptions, + options?: APICallOptions, ): Promise { const url = `${careConfig.apiUrl}${makeUrl(path, options?.queryParams, options?.pathParams)}`; const fetchOptions: RequestInit = { method, - headers: makeHeaders(noAuth ?? false), + headers: makeHeaders(noAuth ?? false, options?.headers), signal: options?.signal, }; @@ -32,7 +31,7 @@ async function queryRequest( const data = await getResponseBody(res); if (!res.ok) { - throw new QueryError({ + throw new HTTPError({ message: "Request Failed", status: res.status, silent: options?.silent ?? false, @@ -44,13 +43,27 @@ async function queryRequest( } /** - * Creates a TanStack Query compatible request function + * Creates a TanStack Query compatible query function. + * + * Example: + * ```tsx + * const { data, isLoading } = useQuery({ + * queryKey: ["prescription", consultationId], + * queryFn: query(MedicineRoutes.prescription, { + * pathParams: { consultationId }, + * queryParams: { + * limit: 10, + * offset: 0, + * }, + * }), + * }); + * ``` */ export default function query( route: Route, - options?: QueryOptions, + options?: APICallOptions, ) { return ({ signal }: { signal: AbortSignal }) => { - return queryRequest(route, { ...options, signal }); + return callApi(route, { ...options, signal }); }; } diff --git a/src/Utils/request/queryError.ts b/src/Utils/request/queryError.ts deleted file mode 100644 index cdfad312ef4..00000000000 --- a/src/Utils/request/queryError.ts +++ /dev/null @@ -1,24 +0,0 @@ -type QueryErrorCause = Record | undefined; - -export class QueryError extends Error { - status: number; - silent: boolean; - cause?: QueryErrorCause; - - constructor({ - message, - status, - silent, - cause, - }: { - message: string; - status: number; - silent: boolean; - cause?: Record; - }) { - super(message, { cause }); - this.status = status; - this.silent = silent; - this.cause = cause; - } -} diff --git a/src/Utils/request/types.ts b/src/Utils/request/types.ts index 075fab5e4be..46870ad3fdb 100644 --- a/src/Utils/request/types.ts +++ b/src/Utils/request/types.ts @@ -36,12 +36,44 @@ export interface RequestOptions { silent?: boolean; } -export interface QueryOptions { - pathParams?: Record; - queryParams?: Record; +export interface APICallOptions { + pathParams?: Record; + queryParams?: QueryParams; body?: TBody; silent?: boolean; signal?: AbortSignal; + headers?: HeadersInit; +} + +type HTTPErrorCause = Record | undefined; + +export class HTTPError extends Error { + status: number; + silent: boolean; + cause?: HTTPErrorCause; + + constructor({ + message, + status, + silent, + cause, + }: { + message: string; + status: number; + silent: boolean; + cause?: Record; + }) { + super(message, { cause }); + this.status = status; + this.silent = silent; + this.cause = cause; + } +} + +declare module "@tanstack/react-query" { + interface Register { + defaultError: HTTPError; + } } export interface PaginatedResponse { diff --git a/src/Utils/request/utils.ts b/src/Utils/request/utils.ts index 8fd7bc96bea..26d69672f53 100644 --- a/src/Utils/request/utils.ts +++ b/src/Utils/request/utils.ts @@ -50,28 +50,25 @@ const ensurePathNotMissingReplacements = (path: string) => { } }; -export function makeHeaders(noAuth: boolean) { - const headers = new Headers({ - "Content-Type": "application/json", - Accept: "application/json", - }); +export function makeHeaders(noAuth: boolean, additionalHeaders?: HeadersInit) { + const headers = new Headers(additionalHeaders); - if (!noAuth) { - const token = getAuthorizationHeader(); + headers.set("Content-Type", "application/json"); + headers.append("Accept", "application/json"); - if (token) { - headers.append("Authorization", token); - } + const authorizationHeader = getAuthorizationHeader(); + if (authorizationHeader && !noAuth) { + headers.append("Authorization", authorizationHeader); } return headers; } export function getAuthorizationHeader() { - const bearerToken = localStorage.getItem(LocalStorageKeys.accessToken); + const accessToken = localStorage.getItem(LocalStorageKeys.accessToken); - if (bearerToken) { - return `Bearer ${bearerToken}`; + if (accessToken) { + return `Bearer ${accessToken}`; } return null; diff --git a/src/components/Facility/ConsultationDetails/index.tsx b/src/components/Facility/ConsultationDetails/index.tsx index 918026a05fd..7a95e7da381 100644 --- a/src/components/Facility/ConsultationDetails/index.tsx +++ b/src/components/Facility/ConsultationDetails/index.tsx @@ -330,7 +330,7 @@ export const ConsultationDetails = (props: any) => {
-
+
Created:   {
-
+
Last Modified:   { url, formData, "POST", - { - Authorization: - "Bearer " + localStorage.getItem(LocalStorageKeys.accessToken), - }, + { Authorization: getAuthorizationHeader() }, async (xhr: XMLHttpRequest) => { if (xhr.status === 200) { await sleep(1000); @@ -211,7 +205,10 @@ export const FacilityHome = ({ facilityId }: Props) => { onClick={() => setEditCoverImage(true)} className="md:mr-2 lg:mr-6 lg:h-80 lg:w-80" /> -
+

diff --git a/src/components/Facility/FacilityList.tsx b/src/components/Facility/FacilityList.tsx index 0c1164649ca..f62f630dcaa 100644 --- a/src/components/Facility/FacilityList.tsx +++ b/src/components/Facility/FacilityList.tsx @@ -157,30 +157,17 @@ export const FacilityList = () => { options={
advancedFilter.setShow(true)} /> - +
+ +
} > diff --git a/src/components/Facility/PatientNotesList.tsx b/src/components/Facility/PatientNotesList.tsx index dcf84e8b708..8db68395744 100644 --- a/src/components/Facility/PatientNotesList.tsx +++ b/src/components/Facility/PatientNotesList.tsx @@ -58,18 +58,10 @@ const PatientNotesList = (props: PatientNotesProps) => { }; useEffect(() => { - if (reload) { + if (reload || thread) { fetchNotes(); } - }, [reload]); - - useEffect(() => { - fetchNotes(); - }, [thread]); - - useEffect(() => { - setReload(true); - }, []); + }, [reload, thread]); const handleNext = () => { if (state.cPage < state.totalPages) { diff --git a/src/components/Form/FormFields/PhoneNumberFormField.tsx b/src/components/Form/FormFields/PhoneNumberFormField.tsx index 8b6566de8f7..72a3e0c3076 100644 --- a/src/components/Form/FormFields/PhoneNumberFormField.tsx +++ b/src/components/Form/FormFields/PhoneNumberFormField.tsx @@ -3,6 +3,8 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import React from "react"; import { useTranslation } from "react-i18next"; +import { cn } from "@/lib/utils"; + import CareIcon from "@/CAREUI/icons/CareIcon"; import { @@ -20,7 +22,6 @@ import phoneCodesJson from "@/common/static/countryPhoneAndFlags.json"; import { CountryData, - classNames, formatPhoneNumber as formatPhoneNumberUtil, getCountryCode, humanizeStrings, @@ -138,7 +139,7 @@ const PhoneNumberFormField = React.forwardRef( id={field.id} name={field.name} autoComplete={props.autoComplete ?? "tel"} - className={classNames( + className={cn( "cui-input-base h-full pl-14 tracking-widest sm:leading-6", field.error && "border-danger-500", field.className, diff --git a/src/components/Patient/DailyRounds.tsx b/src/components/Patient/DailyRounds.tsx index f0c78522e40..cf43a5adab9 100644 --- a/src/components/Patient/DailyRounds.tsx +++ b/src/components/Patient/DailyRounds.tsx @@ -411,7 +411,7 @@ export const DailyRounds = (props: any) => { ); } else { navigate( - `/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}/log_updates/${obj.id}/update`, + `/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}/log_updates/${obj.id}/critical_care/update`, ); } } diff --git a/src/components/Patient/PatientDetailsTab/Demography.tsx b/src/components/Patient/PatientDetailsTab/Demography.tsx index e5bed5abfee..d6e1379cd7e 100644 --- a/src/components/Patient/PatientDetailsTab/Demography.tsx +++ b/src/components/Patient/PatientDetailsTab/Demography.tsx @@ -9,21 +9,21 @@ import AuthorizedChild from "@/CAREUI/misc/AuthorizedChild"; import { Button } from "@/components/ui/button"; +import { InsuranceDetailsCard } from "@/components/Patient/InsuranceDetailsCard"; +import { PatientProps } from "@/components/Patient/PatientDetailsTab"; +import { parseOccupation } from "@/components/Patient/PatientHome"; +import { AssignedToObjectModel } from "@/components/Patient/models"; + import useAuthUser from "@/hooks/useAuthUser"; import { GENDER_TYPES } from "@/common/constants"; import { NonReadOnlyUsers } from "@/Utils/AuthorizeFor"; +import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import useTanStackQueryInstead from "@/Utils/request/useQuery"; import { formatName, formatPatientAge } from "@/Utils/utils"; -import { PatientProps } from "."; -import * as Notification from "../../../Utils/Notifications"; -import { InsuranceDetailsCard } from "../InsuranceDetailsCard"; -import { parseOccupation } from "../PatientHome"; -import { AssignedToObjectModel } from "../models"; - export const Demography = (props: PatientProps) => { const { patientData, facilityId, id } = props; const authUser = useAuthUser(); @@ -64,9 +64,7 @@ export const Demography = (props: PatientProps) => { const { data: insuranceDetials } = useTanStackQueryInstead( routes.hcx.policies.list, { - query: { - patient: id, - }, + query: { patient: id }, }, ); diff --git a/src/components/Patient/PatientDetailsTab/EncounterHistory.tsx b/src/components/Patient/PatientDetailsTab/EncounterHistory.tsx index 393a892bf17..17f8915a088 100644 --- a/src/components/Patient/PatientDetailsTab/EncounterHistory.tsx +++ b/src/components/Patient/PatientDetailsTab/EncounterHistory.tsx @@ -1,5 +1,4 @@ import { Link } from "raviger"; -import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -8,53 +7,17 @@ import PaginatedList from "@/CAREUI/misc/PaginatedList"; import { Button } from "@/components/ui/button"; import CircularProgress from "@/components/Common/CircularProgress"; -import Loading from "@/components/Common/Loading"; import { ConsultationCard } from "@/components/Facility/ConsultationCard"; import { ConsultationModel } from "@/components/Facility/models"; +import { PatientProps } from "@/components/Patient/PatientDetailsTab"; -import useAuthUser from "@/hooks/useAuthUser"; - -import { triggerGoal } from "@/Integrations/Plausible"; import routes from "@/Utils/request/api"; -import useTanStackQueryInstead from "@/Utils/request/useQuery"; - -import { PatientProps } from "."; -import { PatientModel } from "../models"; const EncounterHistory = (props: PatientProps) => { - const { patientData: initialPatientData, facilityId, id } = props; - const [patientData, setPatientData] = - useState(initialPatientData); - const authUser = useAuthUser(); - - useEffect(() => { - setPatientData(initialPatientData); - }, [initialPatientData]); + const { patientData, id, refetch, facilityId } = props; const { t } = useTranslation(); - const { loading: isLoading, refetch } = useTanStackQueryInstead( - routes.getPatient, - { - pathParams: { - id, - }, - onResponse: ({ res, data }) => { - if (res?.ok && data) { - setPatientData(data); - } - triggerGoal("Patient Profile Viewed", { - facilityId: facilityId, - userId: authUser.id, - }); - }, - }, - ); - - if (isLoading) { - return ; - } - return ( { const { patientData, facilityId, id } = props; diff --git a/src/components/Patient/PatientDetailsTab/Notes.tsx b/src/components/Patient/PatientDetailsTab/Notes.tsx index 646e97d3bd5..4fccf7a1119 100644 --- a/src/components/Patient/PatientDetailsTab/Notes.tsx +++ b/src/components/Patient/PatientDetailsTab/Notes.tsx @@ -1,5 +1,5 @@ import { t } from "i18next"; -import { useEffect, useState } from "react"; +import { useState } from "react"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -11,6 +11,7 @@ import { PatientNotesModel, } from "@/components/Facility/models"; import AutoExpandingTextInputFormField from "@/components/Form/FormFields/AutoExpandingTextInputFormField"; +import { PatientProps } from "@/components/Patient/PatientDetailsTab"; import useAuthUser from "@/hooks/useAuthUser"; import { useMessageListener } from "@/hooks/useMessageListener"; @@ -18,19 +19,13 @@ import { useMessageListener } from "@/hooks/useMessageListener"; import { PATIENT_NOTES_THREADS } from "@/common/constants"; import { NonReadOnlyUsers } from "@/Utils/AuthorizeFor"; +import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; import request from "@/Utils/request/request"; import { classNames, keysOf } from "@/Utils/utils"; -import * as Notification from "../../../Utils/Notifications"; - -interface PatientNotesProps { - id: string; - facilityId: string; -} - -const PatientNotes = (props: PatientNotesProps) => { - const { id: patientId, facilityId } = props; +const PatientNotes = (props: PatientProps) => { + const { patientData, id: patientId, facilityId } = props; const authUser = useAuthUser(); const [thread, setThread] = useState( @@ -39,7 +34,6 @@ const PatientNotes = (props: PatientNotesProps) => { : PATIENT_NOTES_THREADS.Doctors, ); - const [patientActive, setPatientActive] = useState(true); const [noteField, setNoteField] = useState(""); const [reload, setReload] = useState(false); const [reply_to, setReplyTo] = useState( @@ -84,26 +78,6 @@ const PatientNotes = (props: PatientNotesProps) => { } }; - useEffect(() => { - async function fetchPatientName() { - if (patientId) { - try { - const { data } = await request(routes.getPatient, { - pathParams: { id: patientId }, - }); - if (data) { - setPatientActive(data.is_active ?? true); - } - } catch (error) { - Notification.Error({ - msg: "Failed to fetch patient status", - }); - } - } - } - fetchPatientName(); - }, [patientId]); - useMessageListener((data) => { const message = data?.message; if ( @@ -161,7 +135,7 @@ const PatientNotes = (props: PatientNotesProps) => { errorClassName="hidden" innerClassName="pr-10" placeholder={t("notes_placeholder")} - disabled={!patientActive} + disabled={!patientData.is_active} /> { className="absolute right-2" ghost size="small" - disabled={!patientActive} + disabled={!patientData.is_active} authorizeFor={NonReadOnlyUsers} > diff --git a/src/components/Patient/PatientDetailsTab/ShiftingHistory.tsx b/src/components/Patient/PatientDetailsTab/ShiftingHistory.tsx index b9f63da5512..6bd1bb5bbb7 100644 --- a/src/components/Patient/PatientDetailsTab/ShiftingHistory.tsx +++ b/src/components/Patient/PatientDetailsTab/ShiftingHistory.tsx @@ -4,6 +4,8 @@ import { useTranslation } from "react-i18next"; import CareIcon from "@/CAREUI/icons/CareIcon"; import ButtonV2 from "@/components/Common/ButtonV2"; +import { PatientProps } from "@/components/Patient/PatientDetailsTab"; +import { PatientModel } from "@/components/Patient/models"; import { formatFilter } from "@/components/Resource/ResourceCommons"; import ShiftingTable from "@/components/Shifting/ShiftingTable"; @@ -13,9 +15,6 @@ import { NonReadOnlyUsers } from "@/Utils/AuthorizeFor"; import routes from "@/Utils/request/api"; import useTanStackQueryInstead from "@/Utils/request/useQuery"; -import { PatientProps } from "."; -import { PatientModel } from "../models"; - const ShiftingHistory = (props: PatientProps) => { const { patientData, facilityId, id } = props; const { t } = useTranslation(); diff --git a/src/components/Patient/PatientDetailsTab/index.tsx b/src/components/Patient/PatientDetailsTab/index.tsx index 11024297091..aa27cbcd3d1 100644 --- a/src/components/Patient/PatientDetailsTab/index.tsx +++ b/src/components/Patient/PatientDetailsTab/index.tsx @@ -1,16 +1,18 @@ -import { PatientModel } from "../models"; -import { Demography } from "./Demography"; -import EncounterHistory from "./EncounterHistory"; -import { HealthProfileSummary } from "./HealthProfileSummary"; -import { ImmunisationRecords } from "./ImmunisationRecords"; -import PatientNotes from "./Notes"; +import EncounterHistory from "@/components/Patient/PatientDetailsTab//EncounterHistory"; +import { HealthProfileSummary } from "@/components/Patient/PatientDetailsTab//HealthProfileSummary"; +import { ImmunisationRecords } from "@/components/Patient/PatientDetailsTab//ImmunisationRecords"; +import PatientNotes from "@/components/Patient/PatientDetailsTab//Notes"; +import ShiftingHistory from "@/components/Patient/PatientDetailsTab//ShiftingHistory"; +import { Demography } from "@/components/Patient/PatientDetailsTab/Demography"; +import { PatientModel } from "@/components/Patient/models"; + import { ResourceRequests } from "./ResourceRequests"; -import ShiftingHistory from "./ShiftingHistory"; export interface PatientProps { facilityId: string; id: string; patientData: PatientModel; + refetch: () => void; } export const patientTabs = [ diff --git a/src/components/Patient/PatientHome.tsx b/src/components/Patient/PatientHome.tsx index b506ff5dd8f..86f5a759246 100644 --- a/src/components/Patient/PatientHome.tsx +++ b/src/components/Patient/PatientHome.tsx @@ -2,10 +2,24 @@ import { Link, navigate } from "raviger"; import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; +import Chip from "@/CAREUI/display/Chip"; +import CareIcon from "@/CAREUI/icons/CareIcon"; + import { Button } from "@/components/ui/button"; +import { Avatar } from "@/components/Common/Avatar"; +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 UserAutocomplete from "@/components/Common/UserAutocompleteFormField"; +import { patientTabs } from "@/components/Patient/PatientDetailsTab"; +import { isPatientMandatoryDataFilled } from "@/components/Patient/Utils"; +import { + AssignedToObjectModel, + PatientModel, +} from "@/components/Patient/models"; +import { SkillModel, UserBareMinimum } from "@/components/Users/models"; import useAuthUser from "@/hooks/useAuthUser"; @@ -15,16 +29,13 @@ import { OCCUPATION_TYPES, } from "@/common/constants"; +import { triggerGoal } from "@/Integrations/Plausible"; +import { NonReadOnlyUsers } from "@/Utils/AuthorizeFor"; +import * as Notification from "@/Utils/Notifications"; import dayjs from "@/Utils/dayjs"; import routes from "@/Utils/request/api"; - -import Chip from "../../CAREUI/display/Chip"; -import CareIcon from "../../CAREUI/icons/CareIcon"; -import { triggerGoal } from "../../Integrations/Plausible"; -import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor"; -import * as Notification from "../../Utils/Notifications"; -import request from "../../Utils/request/request"; -import useTanStackQueryInstead from "../../Utils/request/useQuery"; +import request from "@/Utils/request/request"; +import useTanStackQueryInstead from "@/Utils/request/useQuery"; import { formatDateTime, formatName, @@ -33,15 +44,7 @@ import { isAntenatal, isPostPartum, relativeDate, -} from "../../Utils/utils"; -import { Avatar } from "../Common/Avatar"; -import ButtonV2 from "../Common/ButtonV2"; -import Loading from "../Common/Loading"; -import Page from "../Common/Page"; -import { SkillModel, UserBareMinimum } from "../Users/models"; -import { patientTabs } from "./PatientDetailsTab"; -import { isPatientMandatoryDataFilled } from "./Utils"; -import { AssignedToObjectModel, PatientModel } from "./models"; +} from "@/Utils/utils"; export const parseOccupation = (occupation: string | undefined) => { return OCCUPATION_TYPES.find((i) => i.value === occupation)?.text; @@ -460,6 +463,7 @@ export const PatientHome = (props: { facilityId={facilityId || ""} id={id} patientData={patientData} + refetch={refetch} /> )}

diff --git a/src/components/Resource/ResourceCreate.tsx b/src/components/Resource/ResourceCreate.tsx index d563bf9642f..f8f57764720 100644 --- a/src/components/Resource/ResourceCreate.tsx +++ b/src/components/Resource/ResourceCreate.tsx @@ -305,11 +305,11 @@ export default function ResourceCreate(props: resourceProps) {
{ placeholder="Type your description here" value={state.form.reason} onChange={handleChange} - label="Description of request*" + label="Reason of Request*" error={state.errors.reason} />
diff --git a/src/components/Users/UserAvatar.tsx b/src/components/Users/UserAvatar.tsx index db3620b34aa..77b353846bc 100644 --- a/src/components/Users/UserAvatar.tsx +++ b/src/components/Users/UserAvatar.tsx @@ -9,14 +9,13 @@ import Loading from "@/components/Common/Loading"; import useAuthUser from "@/hooks/useAuthUser"; -import { LocalStorageKeys } from "@/common/constants"; - import * as Notification from "@/Utils/Notifications"; import { showAvatarEdit } from "@/Utils/permissions"; import routes from "@/Utils/request/api"; import request from "@/Utils/request/request"; import uploadFile from "@/Utils/request/uploadFile"; import useTanStackQueryInstead from "@/Utils/request/useQuery"; +import { getAuthorizationHeader } from "@/Utils/request/utils"; import { formatDisplayName, sleep } from "@/Utils/utils"; export default function UserAvatar({ username }: { username: string }) { @@ -47,10 +46,7 @@ export default function UserAvatar({ username }: { username: string }) { url, formData, "POST", - { - Authorization: - "Bearer " + localStorage.getItem(LocalStorageKeys.accessToken), - }, + { Authorization: getAuthorizationHeader() }, async (xhr: XMLHttpRequest) => { if (xhr.status === 200) { await sleep(1000); diff --git a/src/components/Users/UserProfile.tsx b/src/components/Users/UserProfile.tsx index 4dd98635510..786e569c4db 100644 --- a/src/components/Users/UserProfile.tsx +++ b/src/components/Users/UserProfile.tsx @@ -26,7 +26,7 @@ import { import useAuthUser, { useAuthContext } from "@/hooks/useAuthUser"; -import { GENDER_TYPES, LocalStorageKeys } from "@/common/constants"; +import { GENDER_TYPES } from "@/common/constants"; import { validateEmailAddress } from "@/common/validation"; import * as Notification from "@/Utils/Notifications"; @@ -35,6 +35,7 @@ import routes from "@/Utils/request/api"; import request from "@/Utils/request/request"; import uploadFile from "@/Utils/request/uploadFile"; import useTanStackQueryInstead from "@/Utils/request/useQuery"; +import { getAuthorizationHeader } from "@/Utils/request/utils"; import { dateQueryString, formatDate, @@ -507,10 +508,7 @@ export default function UserProfile() { url, formData, "POST", - { - Authorization: - "Bearer " + localStorage.getItem(LocalStorageKeys.accessToken), - }, + { Authorization: getAuthorizationHeader() }, async (xhr: XMLHttpRequest) => { if (xhr.status === 200) { await sleep(1000);