diff --git a/cypress/e2e/patient_spec/PatientConsultationDischarge.cy.ts b/cypress/e2e/patient_spec/PatientConsultationDischarge.cy.ts index 846b937998b..a3b4906e0ca 100644 --- a/cypress/e2e/patient_spec/PatientConsultationDischarge.cy.ts +++ b/cypress/e2e/patient_spec/PatientConsultationDischarge.cy.ts @@ -117,14 +117,8 @@ describe("Patient Discharge based on multiple reason", () => { patientDischarge.interceptDischargePatient(); cy.clickSubmitButton("Acknowledge & Submit"); patientDischarge.verifyDischargePatient(); + cy.verifyNotification("Patient Discharged Successfully"); // Verify the consultation dashboard reflection - cy.verifyContentPresence("#consultation-buttons", ["Recovered"]); - // Verify the dashboard and discharge information - cy.verifyContentPresence("#discharge-information", [ - patientDischargeReason1, - patientDischargeAdvice, - patientMedicine, - ]); }); afterEach(() => { diff --git a/cypress/e2e/users_spec/UsersCreation.cy.ts b/cypress/e2e/users_spec/UsersCreation.cy.ts index 38ad0c907c4..80520b73919 100644 --- a/cypress/e2e/users_spec/UsersCreation.cy.ts +++ b/cypress/e2e/users_spec/UsersCreation.cy.ts @@ -1,27 +1,21 @@ import FacilityHome from "pageobject/Facility/FacilityHome"; -import ManageUserPage from "pageobject/Users/ManageUserPage"; -import UserProfilePage from "pageobject/Users/UserProfilePage"; import { advanceFilters } from "pageobject/utils/advanceFilterHelpers"; import FacilityPage from "../../pageobject/Facility/FacilityCreation"; import LoginPage from "../../pageobject/Login/LoginPage"; +import { ManageUserPage } from "../../pageobject/Users/ManageUserPage"; import { UserCreationPage } from "../../pageobject/Users/UserCreation"; import { UserPage } from "../../pageobject/Users/UserSearch"; -import { - generateEmergencyPhoneNumber, - generatePhoneNumber, -} from "../../pageobject/utils/constants"; +import { generatePhoneNumber } from "../../pageobject/utils/constants"; describe("User Creation", () => { const userPage = new UserPage(); const loginPage = new LoginPage(); - const userProfilePage = new UserProfilePage(); - const manageUserPage = new ManageUserPage(); const userCreationPage = new UserCreationPage(); + const manageUserPage = new ManageUserPage(); const facilityPage = new FacilityPage(); const facilityHome = new FacilityHome(); const phoneNumber = generatePhoneNumber(); - const emergencyPhoneNumber = generateEmergencyPhoneNumber(); const fillFacilityName = "Dummy Facility 40"; const makeId = (length: number) => { let result = ""; @@ -54,14 +48,6 @@ describe("User Creation", () => { "Please select the local body", ]; - const EXPECTED_PROFILE_ERROR_MESSAGES = [ - "This field is required", - "This field is required", - "Please enter valid phone number", - ]; - const userName = "devdistrictadmin"; - const firstName = "District Editted"; - const lastName = "Cypress"; const gender = "Male"; const email = "test@test.com"; const password = "Test@123"; @@ -74,9 +60,6 @@ describe("User Creation", () => { const district = "Ernakulam"; const role = "Doctor"; const homeFacility = "Dummy Shifting Center"; - const weeklyWorkingHrs = "14"; - const dob = "01011998"; - const formattedDob = "01/01/1998"; const newUserDob = "25081999"; before(() => { @@ -90,55 +73,6 @@ describe("User Creation", () => { cy.awaitUrl("/users"); }); - it("Update the existing user profile and verify its reflection", () => { - manageUserPage.navigateToProfile(); - cy.verifyContentPresence("#username-profile-details", [userName]); - userProfilePage.clickEditProfileButton(); - userCreationPage.clearFirstName(); - userCreationPage.typeFirstName(firstName); - userCreationPage.clearLastName(); - userCreationPage.typeLastName(lastName); - userProfilePage.selectGender(gender); - userProfilePage.clearPhoneNumber(); - userProfilePage.typePhoneNumber(phoneNumber); - userProfilePage.clearAltPhoneNumber(); - userProfilePage.typeWhatsappNumber(emergencyPhoneNumber); - userProfilePage.clearEmail(); - userProfilePage.typeEmail(email); - userProfilePage.clearWorkingHours(); - userProfilePage.typeWorkingHours(weeklyWorkingHrs); - userProfilePage.typeDateOfBirth(dob); - userProfilePage.interceptUpdateUsers(); - userProfilePage.clickUpdateButton(); - userProfilePage.verifyUpdateUsersResponse(); - cy.verifyContentPresence("#contactno-profile-details", [ - "+91" + phoneNumber, - ]); - cy.verifyContentPresence("#whatsapp-profile-details", [ - "+91" + emergencyPhoneNumber, - ]); - cy.verifyContentPresence("#firstname-profile-details", [firstName]); - cy.verifyContentPresence("#lastname-profile-details", [lastName]); - cy.verifyContentPresence("#date_of_birth-profile-details", [formattedDob]); - cy.verifyContentPresence("#emailid-profile-details", [email]); - cy.verifyContentPresence("#gender-profile-details", [gender]); - cy.verifyContentPresence("#averageworkinghour-profile-details", [ - weeklyWorkingHrs, - ]); - }); - - it("Update the existing user profile Form Mandatory File Error", () => { - manageUserPage.navigateToProfile(); - userProfilePage.clickEditProfileButton(); - userCreationPage.clearFirstName(); - userCreationPage.clearLastName(); - userProfilePage.clearPhoneNumber(); - userProfilePage.clearAltPhoneNumber(); - userProfilePage.clearWorkingHours(); - userProfilePage.clickUpdateButton(); - cy.verifyErrorMessages(EXPECTED_PROFILE_ERROR_MESSAGES); - }); - it("create new user and verify reflection", () => { userCreationPage.clickAddUserButton(); userCreationPage.selectFacility(homeFacility); @@ -147,14 +81,14 @@ describe("User Creation", () => { userCreationPage.typeConfirmPassword(password); userCreationPage.selectHomeFacility(homeFacility); userPage.typeInPhoneNumber(phoneNumber); - userProfilePage.typeDateOfBirth(newUserDob); + manageUserPage.editDateOfBirth(newUserDob); userCreationPage.selectUserType(role); - userProfilePage.typeQualification(qualification); - userProfilePage.typeDoctorYoE(experience); - userProfilePage.typeMedicalCouncilRegistration(regNo); + manageUserPage.editQualification(qualification, false); + manageUserPage.editDoctorYoE(experience, false); + manageUserPage.editMedicalCouncilRegistration(regNo, false); userPage.typeInFirstName(newUserFirstName); userPage.typeInLastName(newUserLastName); - userProfilePage.typeEmail(email); + manageUserPage.editEmail(email, false); userCreationPage.selectGender(gender); userCreationPage.selectState(state); userCreationPage.selectDistrict(district); @@ -178,6 +112,7 @@ describe("User Creation", () => { }); it("view user redirection from facility page", () => { + loginPage.ensureLoggedIn(); facilityHome.navigateToFacilityHomepage(); facilityHome.typeFacilitySearch(fillFacilityName); advanceFilters.verifyFilterBadgePresence( diff --git a/cypress/e2e/users_spec/UsersManage.cy.ts b/cypress/e2e/users_spec/UsersManage.cy.ts index b1968ed2b4c..0d670d8c230 100644 --- a/cypress/e2e/users_spec/UsersManage.cy.ts +++ b/cypress/e2e/users_spec/UsersManage.cy.ts @@ -1,6 +1,7 @@ import * as dayjs from "dayjs"; import FacilityHome from "pageobject/Facility/FacilityHome"; import { advanceFilters } from "pageobject/utils/advanceFilterHelpers"; +import { generatePhoneNumber } from "pageobject/utils/constants"; import LoginPage from "../../pageobject/Login/LoginPage"; import ManageUserPage from "../../pageobject/Users/ManageUserPage"; @@ -50,28 +51,48 @@ describe("Manage User", () => { }); */ it("edit a nurse user's basic information and verify its reflection", () => { + const basicInfoErrorMessages = [ + "First Name is required", + "Last Name is required", + ]; + const modifiedFirstName = "Devo"; + const modifiedLastName = "Districto"; + const modifiedRawDOB = "11081999"; + const modifiedGender = "Female"; + const modifiedFormattedDOB = "11/08/1999"; userPage.typeInSearchInput(nurseUsername); userPage.checkUsernameText(nurseUsername); manageUserPage.clickMoreDetailsButton(nurseUsername); manageUserPage.verifyMoreDetailsPage(); - manageUserPage.clickBasicInfoViewButton(); + manageUserPage.clickBaicInfoViewButton(); manageUserPage.clickBasicInfoEditButton(); manageUserPage.clearUserBasicInfo(); - manageUserPage.clickSubmit(); - manageUserPage.verifyErrorText("First Name is required"); - manageUserPage.verifyErrorText("Last Name is required"); - manageUserPage.editUserBasicInfo("Devo", "Districto", "11081999", "Female"); - manageUserPage.clickSubmit(); - manageUserPage.clickBasicInfoViewButton(); + manageUserPage.clickUserInfoSubmitButton(); + cy.verifyErrorMessages(basicInfoErrorMessages); + manageUserPage.editUserBasicInfo( + modifiedFirstName, + modifiedLastName, + modifiedRawDOB, + modifiedGender, + ); + manageUserPage.clickUserInfoSubmitButton(); + manageUserPage.userInfoUpdateSuccessNotification(); + manageUserPage.clickBaicInfoViewButton(); manageUserPage.verifyEditUserDetails( - "Devo", - "Districto", - "11/08/1999", - "Female", + modifiedFirstName, + modifiedLastName, + modifiedFormattedDOB, + modifiedGender, ); }); it("edit a nurse user's contact information and verify its reflection", () => { + const contactInfoErrorMessages = [ + "Please enter a valid email address", + "Please enter valid phone number", + ]; + const modifiedEmail = "dev@gmail.com"; + const modifiedPhone = generatePhoneNumber(); userPage.typeInSearchInput(nurseUsername); userPage.checkUsernameText(nurseUsername); manageUserPage.clickMoreDetailsButton(nurseUsername); @@ -79,16 +100,18 @@ describe("Manage User", () => { manageUserPage.clickContactInfoViewButton(); manageUserPage.clickContactInfoEditButton(); manageUserPage.clearUserContactInfo(); - manageUserPage.clickSubmit(); - manageUserPage.verifyErrorText("Please enter a valid email address"); - manageUserPage.verifyErrorText("Please enter valid phone number"); - manageUserPage.editUserContactInfo("dev@gmail.com", "6234343435"); - manageUserPage.clickSubmit(); + manageUserPage.clickUserInfoSubmitButton(); + cy.verifyErrorMessages(contactInfoErrorMessages); + manageUserPage.editUserContactInfo(modifiedEmail, modifiedPhone); + manageUserPage.clickUserInfoSubmitButton(); + manageUserPage.userInfoUpdateSuccessNotification(); manageUserPage.clickContactInfoViewButton(); - manageUserPage.verifyEditUserContactInfo("dev@gmail.com", "6234343435"); + manageUserPage.verifyEditUserContactInfo(modifiedEmail, modifiedPhone); }); it("edit a nurse user's professional information and verify its reflection", () => { + const qualificationErrorMessages = ["Qualification is required"]; + const qualification = "Msc"; userPage.typeInSearchInput(nurseUsername); userPage.checkUsernameText(nurseUsername); manageUserPage.clickMoreDetailsButton(nurseUsername); @@ -100,16 +123,28 @@ describe("Manage User", () => { manageUserPage.verifyYoeAndCouncilRegistrationDoesntExist(); manageUserPage.clickProfessionalInfoEditButton(); manageUserPage.clearDoctorOrNurseProfessionalInfo(false); - manageUserPage.clickSubmit(); - manageUserPage.verifyErrorText("Qualification is required"); - manageUserPage.editUserProfessionalInfo("Msc"); - manageUserPage.clickSubmit(); + manageUserPage.clickUserInfoSubmitButton(); + cy.verifyErrorMessages(qualificationErrorMessages); + manageUserPage.editUserProfessionalInfo(qualification); + manageUserPage.clickUserInfoSubmitButton(); + manageUserPage.userInfoUpdateSuccessNotification(); manageUserPage.clickProfessionalInfoViewButton(); - manageUserPage.verifyEditUserProfessionalInfo("Msc"); + manageUserPage.verifyEditUserProfessionalInfo(qualification); }); it("edit a doctor user's professional information and verify its reflection", () => { // Should have qualification, years of experience and medical council registration + const qualificationErrorMessages = [ + "Qualification is required", + "Years of experience is required", + "Medical Council Registration is required", + ]; + const qualification = "Msc"; + const yoe = "120"; + const modifiedYoe = "10"; + const medicalRegistrationNumber = "1234567890"; + const experienceCommencedOn = dayjs().subtract(10, "year"); + const formattedDate = dayjs(experienceCommencedOn).format("YYYY-MM-DD"); userPage.typeInSearchInput(usernameToLinkFacilitydoc1); userPage.checkUsernameText(usernameToLinkFacilitydoc1); manageUserPage.clickMoreDetailsButton(usernameToLinkFacilitydoc1); @@ -119,25 +154,28 @@ describe("Manage User", () => { manageUserPage.verifyYoeAndCouncilRegistrationExist(); manageUserPage.clickProfessionalInfoEditButton(); manageUserPage.clearDoctorOrNurseProfessionalInfo(true); - manageUserPage.clickSubmit(); - manageUserPage.verifyErrorText("Qualification is required"); - manageUserPage.verifyErrorText("Years of experience is required"); - manageUserPage.verifyErrorText("Medical Council Registration is required"); - manageUserPage.editUserProfessionalInfo("Msc", "120", "1234567890"); - manageUserPage.clickSubmit(); - manageUserPage.verifyErrorText( - "Please enter a valid number between 0 and 100.", + manageUserPage.clickUserInfoSubmitButton(); + cy.verifyErrorMessages(qualificationErrorMessages); + manageUserPage.editUserProfessionalInfo( + qualification, + yoe, + medicalRegistrationNumber, ); + manageUserPage.clickUserInfoSubmitButton(); + cy.verifyErrorMessages(["Please enter a valid number between 0 and 100."]); manageUserPage.clearDoctorOrNurseProfessionalInfo(true); - manageUserPage.editUserProfessionalInfo("Msc", "10", "1234567890"); - manageUserPage.clickSubmit(); + manageUserPage.editUserProfessionalInfo( + qualification, + modifiedYoe, + medicalRegistrationNumber, + ); + manageUserPage.clickUserInfoSubmitButton(); + manageUserPage.userInfoUpdateSuccessNotification(); manageUserPage.clickProfessionalInfoViewButton(); - const experienceCommencedOn = dayjs().subtract(10, "year"); - const formattedDate = dayjs(experienceCommencedOn).format("YYYY-MM-DD"); manageUserPage.verifyEditUserProfessionalInfo( - "Msc", + qualification, formattedDate, - "1234567890", + medicalRegistrationNumber, ); }); @@ -151,7 +189,7 @@ describe("Manage User", () => { userPage.checkUsernameText(doctorUsername); manageUserPage.clickMoreDetailsButton(doctorUsername); manageUserPage.verifyMoreDetailsPage(false); - manageUserPage.verifyUsername(doctorUsername); + cy.verifyContentPresence("#view-username", [doctorUsername]); manageUserPage.verifyBasicInfoEditButtonNotExist(); manageUserPage.verifyContactInfoEditButtonNotExist(); manageUserPage.verifyProfessionalInfoEditButtonNotExist(); @@ -189,9 +227,11 @@ describe("Manage User", () => { userPage.checkUsernameText(nurseUsername); manageUserPage.clickMoreDetailsButton(nurseUsername); manageUserPage.verifyMoreDetailsPage(); - manageUserPage.clickPasswordEditButton(); + cy.verifyAndClickElement("#change-edit-password-button", "Change Password"); manageUserPage.changePassword("Coronasafe@123", "Coronasafe@1233"); - manageUserPage.clickSubmit(); + cy.clickSubmitButton(); + cy.verifyNotification("Password updated successfully"); + cy.closeNotification(); loginPage.ensureLoggedIn(); loginPage.clickSignOutBtn(); loginPage.loginManuallyAsNurse("Coronasafe@1233"); @@ -201,9 +241,11 @@ describe("Manage User", () => { userPage.checkUsernameText(nurseUsername); manageUserPage.clickMoreDetailsButton(nurseUsername); manageUserPage.verifyMoreDetailsPage(); - manageUserPage.clickPasswordEditButton(); + cy.verifyAndClickElement("#change-edit-password-button", "Change Password"); manageUserPage.changePassword("Coronasafe@1233", "Coronasafe@123"); - manageUserPage.clickSubmit(); + cy.clickSubmitButton(); + cy.verifyNotification("Password updated successfully"); + cy.closeNotification(); loginPage.ensureLoggedIn(); loginPage.clickSignOutBtn(); loginPage.loginManuallyAsDistrictAdmin(); @@ -217,7 +259,7 @@ describe("Manage User", () => { manageUserPage.verifyMoreDetailsPage(); manageUserPage.verifyDeleteButtonVisible(); manageUserPage.clickDeleteButton(); - manageUserPage.clickSubmit(); + cy.clickSubmitButton("Delete"); cy.verifyNotification("User Deleted Successfully"); cy.closeNotification(); userPage.typeInSearchInput(doctorToDelete); @@ -239,19 +281,6 @@ describe("Manage User", () => { manageUserPage.clickAddSkillButton(usernameforworkinghour); manageUserPage.verifyAddSkillResponse(); manageUserPage.assertSkillInAddedUserSkills(linkedskill); - manageUserPage.navigateToProfile(); - cy.verifyContentPresence("#username-profile-details", [ - usernameforworkinghour, - ]); - manageUserPage.assertSkillInAlreadyLinkedSkills(linkedskill); - // unlink the skill - manageUserPage.navigateToManageUser(); - userPage.typeInSearchInput(usernameforworkinghour); - userPage.checkUsernameText(usernameforworkinghour); - manageUserPage.clickMoreDetailsButton(usernameforworkinghour); - manageUserPage.verifyMoreDetailsPage(); - manageUserPage.clickLinkedSkillTab(); - manageUserPage.assertSkillInAddedUserSkills(linkedskill); manageUserPage.clickUnlinkSkill(); manageUserPage.verifyUnlinkSkillModal(); manageUserPage.clickConfirmUnlinkSkill(); @@ -283,7 +312,7 @@ describe("Manage User", () => { manageUserPage.assertSkillIndoctorconnect(linkedskill); }); - it("add working hour for a user and verify its reflection in card and user profile", () => { + it("add working hour and video connect link for a user and verify its reflection in card and user profile", () => { // verify qualification and yoe and council registration fields are not present // verify field error and add working hour userPage.typeInSearchInput(usernameforworkinghour); @@ -291,23 +320,28 @@ describe("Manage User", () => { manageUserPage.clickMoreDetailsButton(usernameforworkinghour); manageUserPage.verifyMoreDetailsPage(); manageUserPage.verifyProfileTabPage(); - manageUserPage.clickProfessionalInfoViewButton(); + cy.verifyAndClickElement("#professional-info-view-button", "View"); manageUserPage.verifyQualificationDoesntExist(); manageUserPage.verifyYoeAndCouncilRegistrationDoesntExist(); - manageUserPage.clickProfessionalInfoEditButton(); + cy.verifyAndClickElement("#professional-info-edit-button", "Edit"); manageUserPage.clearProfessionalInfo(); - manageUserPage.typeInWeeklyWorkingHours("200"); - manageUserPage.clickSubmit(); - manageUserPage.verifyErrorText( + manageUserPage.editWeeklyWorkingHours("200"); + cy.clickSubmitButton(); + cy.verifyErrorMessages([ "Average weekly working hours must be a number between 0 and 168", - ); + ]); manageUserPage.clearProfessionalInfo(); - manageUserPage.typeInWeeklyWorkingHours(workinghour); - manageUserPage.clickSubmit(); - // verify the data is reflected in the page - manageUserPage.verifyWorkingHours(workinghour); - manageUserPage.navigateToProfile(); - manageUserPage.verifyProfileWorkingHours(workinghour); + manageUserPage.editHoursAndVideoConnectLink( + workinghour, + "https://www.example.com", + ); + cy.clickSubmitButton(); + cy.verifyNotification("User details updated successfully"); + cy.closeNotification(); + manageUserPage.verifyHoursAndVideoConnectLink( + workinghour, + "https://www.example.com", + ); }); it("linking and unlinking facility for multiple users, and confirm reflection in user cards and doctor connect", () => { @@ -357,7 +391,7 @@ describe("Manage User", () => { manageUserPage.clickLinkFacility(); manageUserPage.clickLinkedFacilitySettings(); manageUserPage.clickUnlinkFacilityButton(); - manageUserPage.clickSubmit(); + cy.clickSubmitButton("Unlink"); manageUserPage.linkedfacilitylistnotvisible(); // Go to particular facility doctor connect and all user-id are reflected based on there access // Path will be facility page to patient page then doctor connect button diff --git a/cypress/e2e/users_spec/UsersProfile.cy.ts b/cypress/e2e/users_spec/UsersProfile.cy.ts deleted file mode 100644 index 551fba4c0f1..00000000000 --- a/cypress/e2e/users_spec/UsersProfile.cy.ts +++ /dev/null @@ -1,82 +0,0 @@ -import FacilityHome from "pageobject/Facility/FacilityHome"; - -import LoginPage from "../../pageobject/Login/LoginPage"; -import ManageUserPage from "../../pageobject/Users/ManageUserPage"; -import UserProfilePage from "../../pageobject/Users/UserProfilePage"; - -describe("Manage User Profile", () => { - const loginPage = new LoginPage(); - const userProfilePage = new UserProfilePage(); - const manageUserPage = new ManageUserPage(); - const facilityHome = new FacilityHome(); - - const date_of_birth = "01011999"; - const gender = "Male"; - const email = "test@example.com"; - const phone = "8899887788"; - const workinghours = "8"; - const qualification = "MBBS"; - const doctorYoE = "10"; - const medicalCouncilRegistration = "1234567890"; - - const facilitySearch = "Dummy Facility 40"; - - before(() => { - loginPage.loginByRole("devDoctor"); - cy.saveLocalStorage(); - }); - - beforeEach(() => { - cy.restoreLocalStorage(); - cy.clearLocalStorage(/filters--.+/); - cy.awaitUrl("/user/profile"); - }); - - it("Set Dob, Gender, Email, Phone and Working Hours for a user and verify its reflection in user profile", () => { - userProfilePage.clickEditProfileButton(); - - userProfilePage.typeDateOfBirth(date_of_birth); - userProfilePage.selectGender(gender); - userProfilePage.typeEmail(email); - userProfilePage.typePhoneNumber(phone); - userProfilePage.typeWhatsappNumber(phone); - userProfilePage.typeWorkingHours(workinghours); - userProfilePage.typeQualification(qualification); - userProfilePage.typeDoctorYoE(doctorYoE); - userProfilePage.typeMedicalCouncilRegistration(medicalCouncilRegistration); - userProfilePage.clickUpdateButton(); - cy.verifyNotification("Details updated successfully"); - userProfilePage.assertDateOfBirth("01/01/1999"); - userProfilePage.assertGender(gender); - userProfilePage.assertEmail(email); - userProfilePage.assertPhoneNumber(phone); - userProfilePage.assertAltPhoneNumber(phone); - userProfilePage.assertWorkingHours(workinghours); - }); - - it("Adding video connect link for a user and verify its reflection in user profile and doctor connect", () => { - // verify the user doesn't have any video connect link - userProfilePage.assertVideoConnectLink("-"); - // Link a new video connect link and ensure it is under video connect link - userProfilePage.clickEditProfileButton(); - userProfilePage.typeVideoConnectLink("https://www.example.com"); - userProfilePage.clickUpdateButton(); - userProfilePage.assertVideoConnectLink("https://www.example.com"); - // Edit the video connect link and ensure it is updated - userProfilePage.clickEditProfileButton(); - userProfilePage.typeVideoConnectLink("https://www.test.com"); - userProfilePage.clickUpdateButton(); - userProfilePage.assertVideoConnectLink("https://www.test.com"); - // Go to particular facility doctor connect and verify the video connect link is present - facilityHome.navigateToFacilityHomepage(); - facilityHome.typeFacilitySearch(facilitySearch); - facilityHome.assertFacilityInCard(facilitySearch); - manageUserPage.clickFacilityPatients(); - manageUserPage.clickDoctorConnectButton(); - manageUserPage.assertVideoConnectLink("Dev Doctor", "https://www.test.com"); - }); - - afterEach(() => { - cy.saveLocalStorage(); - }); -}); diff --git a/cypress/pageobject/Users/ManageUserPage.ts b/cypress/pageobject/Users/ManageUserPage.ts index 027357a0321..a4821466861 100644 --- a/cypress/pageobject/Users/ManageUserPage.ts +++ b/cypress/pageobject/Users/ManageUserPage.ts @@ -54,22 +54,6 @@ export class ManageUserPage { cy.get("#link-facility").click(); } - clickSubmit() { - cy.get("#submit").click(); - } - - verifyErrorText(expectedError: string) { - cy.get(".error-text").first().scrollIntoView(); - cy.get(".error-text") - .should("be.visible") - .then(($elements) => { - const errorTextArray = Array.from($elements).map( - (el) => el.textContent, - ); - expect(errorTextArray).to.include(expectedError); - }); - } - clearUserBasicInfo() { cy.get("input[name='first_name']").click().clear(); cy.get("input[name='last_name']").click().clear(); @@ -81,11 +65,35 @@ export class ManageUserPage { dateOfBirth: string, gender: string, ) { - cy.get("input[name='first_name']").click().type(fName); - cy.get("input[name='last_name']").click().type(lName); + this.editFirstName(fName); + this.editLastName(lName); + this.editDateOfBirth(dateOfBirth); + this.editGender(gender); + } + + clickUserInfoSubmitButton() { + cy.clickSubmitButton("Submit"); + } + + userInfoUpdateSuccessNotification() { + cy.verifyNotification("User details updated successfully"); + cy.closeNotification(); + } + + editFirstName(fName: string, clearBeforeTyping = true) { + cy.typeIntoField("#first_name", fName, { clearBeforeTyping }); + } + + editLastName(lName: string, clearBeforeTyping = true) { + cy.typeIntoField("#last_name", lName, { clearBeforeTyping }); + } + + editDateOfBirth(dateOfBirth: string) { cy.clickAndTypeDate("#date_of_birth", dateOfBirth); - cy.get("#gender").click(); - cy.get("[role='option']").contains(gender).click(); + } + + editGender(gender: string) { + cy.clickAndSelectOption("#gender", gender); } verifyEditUserDetails( @@ -94,10 +102,10 @@ export class ManageUserPage { dateOfBirth: string, gender: string, ) { - cy.get("#view-first_name").should("contain.text", fName); - cy.get("#view-last_name").should("contain.text", lName); - cy.get("#view-date_of_birth").should("contain.text", dateOfBirth); - cy.get("#view-gender").should("contain.text", gender); + cy.verifyContentPresence("#view-first_name", [fName]); + cy.verifyContentPresence("#view-last_name", [lName]); + cy.verifyContentPresence("#view-date_of_birth", [dateOfBirth]); + cy.verifyContentPresence("#view-gender", [gender]); } clearUserContactInfo() { @@ -107,15 +115,30 @@ export class ManageUserPage { } editUserContactInfo(email: string, phoneNumber: string) { - cy.get("input[name='email']").click().type(email); - cy.get("input[name='phone_number']").click().type(phoneNumber); + this.editEmail(email); + this.editPhoneNumber(phoneNumber); + } + + editEmail(email: string, clearBeforeTyping = true) { + cy.typeIntoField("input[name='email']", email, { clearBeforeTyping }); + } + + editPhoneNumber( + phoneNumber: string, + clearBeforeTyping = true, + skipVerification = true, + ) { + cy.typeIntoField("input[name='phone_number']", phoneNumber, { + clearBeforeTyping, + skipVerification, + }); cy.get("input[name='phone_number_is_whatsapp']").should("be.checked"); } verifyEditUserContactInfo(email: string, phoneNumber: string) { - cy.get("#view-email").should("contain.text", email); - cy.get("#view-phone_number").should("contain.text", phoneNumber); - cy.get("#view-whatsapp_number").should("contain.text", phoneNumber); + cy.verifyContentPresence("#view-email", [email]); + cy.verifyContentPresence("#view-phone_number", [phoneNumber]); + cy.verifyContentPresence("#view-whatsapp_number", [phoneNumber]); } clearDoctorOrNurseProfessionalInfo(yoeAndCouncilRegistration: boolean) { @@ -128,82 +151,119 @@ export class ManageUserPage { } } + editQualification(qualification: string, clearBeforeTyping = true) { + cy.typeIntoField("input[name='qualification']", qualification, { + clearBeforeTyping, + }); + } + + editDoctorYoE(doctorYoE: string, clearBeforeTyping = true) { + cy.typeIntoField( + "input[name='doctor_experience_commenced_on']", + doctorYoE, + { + clearBeforeTyping, + }, + ); + } + + editMedicalCouncilRegistration( + medicalCouncilRegistration: string, + clearBeforeTyping = true, + ) { + cy.typeIntoField( + "input[name='doctor_medical_council_registration']", + medicalCouncilRegistration, + { + clearBeforeTyping, + }, + ); + } + clearProfessionalInfo() { cy.get("input[name='weekly_working_hours']").scrollIntoView(); cy.get("input[name='weekly_working_hours']").click().clear(); cy.get("input[name='video_connect_link']").click().clear(); } + editWeeklyWorkingHours(weeklyWorkingHours: string, clearBeforeTyping = true) { + cy.get("input[name='weekly_working_hours']").scrollIntoView(); + cy.typeIntoField("input[name='weekly_working_hours']", weeklyWorkingHours, { + clearBeforeTyping, + }); + } + + editVideoConnectLink(videoConnectLink: string, clearBeforeTyping = true) { + cy.typeIntoField("input[name='video_connect_link']", videoConnectLink, { + clearBeforeTyping, + }); + } + editUserProfessionalInfo( qualification: string, yearsOfExperience?: string, medicalCouncilRegistration?: string, ) { - cy.get("input[name='qualification']").click().type(qualification); + this.editQualification(qualification); if (yearsOfExperience) { - cy.get("input[name='doctor_experience_commenced_on']") - .click() - .type(yearsOfExperience); + this.editDoctorYoE(yearsOfExperience); } if (medicalCouncilRegistration) { - cy.get("input[name='doctor_medical_council_registration']") - .click() - .type(medicalCouncilRegistration); + this.editMedicalCouncilRegistration(medicalCouncilRegistration); } } + editHoursAndVideoConnectLink( + weeklyWorkingHours: string, + videoConnectLink: string, + ) { + this.editWeeklyWorkingHours(weeklyWorkingHours); + this.editVideoConnectLink(videoConnectLink); + } + verifyEditUserProfessionalInfo( qualification: string, yearsOfExperience?: string, medicalCouncilRegistration?: string, ) { - cy.get("#view-qualification").should("contain.text", qualification); + cy.verifyContentPresence("#view-qualification", [qualification]); if (yearsOfExperience) { - cy.get("#view-years_of_experience").should( - "contain.text", + cy.verifyContentPresence("#view-years_of_experience", [ yearsOfExperience, - ); + ]); } if (medicalCouncilRegistration) { - cy.get("#view-doctor_medical_council_registration").should( - "contain.text", + cy.verifyContentPresence("#view-doctor_medical_council_registration", [ medicalCouncilRegistration, - ); + ]); } } + verifyHoursAndVideoConnectLink( + weeklyWorkingHours: string, + videoConnectLink: string, + ) { + cy.get("#view-average_weekly_working_hours").scrollIntoView(); + cy.verifyContentPresence("#view-average_weekly_working_hours", [ + weeklyWorkingHours, + ]); + cy.verifyContentPresence("#view-video_conference_link", [videoConnectLink]); + } + verifyPasswordEditButtonNotExist() { cy.get("#change-edit-password-button").should("not.exist"); } changePassword(oldPassword: string, newPassword: string) { - cy.get("input[name='old_password']").click().type(oldPassword); - cy.get("input[name='new_password_1']").click().type(newPassword); - cy.get("input[name='new_password_2']").click().type(newPassword); - } - - typeInWeeklyWorkingHours(hours: string) { - cy.get("input[name='weekly_working_hours']").scrollIntoView(); - cy.get("input[name='weekly_working_hours']").click().type(hours); - } - - navigateToProfile() { - cy.intercept("GET", "**/api/v1/users/**").as("getUsers"); - cy.get("#user-profile-name").click(); - cy.get("#profile-button").click(); - cy.wait("@getUsers").its("response.statusCode").should("eq", 200); - } - - verifyWorkingHours(expectedHours: string) { - cy.verifyContentPresence("#view-average_weekly_working_hours", [ - expectedHours, - ] as string[]); - } - - verifyProfileWorkingHours(expectedHours: string) { - cy.verifyContentPresence("#averageworkinghour-profile-details", [ - expectedHours, - ] as string[]); + cy.typeIntoField("input[name='old_password']", oldPassword, { + clearBeforeTyping: true, + }); + cy.typeIntoField("input[name='new_password_1']", newPassword, { + clearBeforeTyping: true, + }); + cy.typeIntoField("input[name='new_password_2']", newPassword, { + clearBeforeTyping: true, + }); } navigateToManageUser() { @@ -237,71 +297,45 @@ export class ManageUserPage { cy.wait("@getUserDetails"); } - verifyMoreDetailsPage(hasPermissions = true) { - cy.get("#username").should("be.visible"); - cy.get("#role").should("be.visible"); - cy.get("#usermanagement_tab_nav").should("be.visible"); - cy.get("#profile").should("be.visible"); - if (hasPermissions) { - cy.get("#facilities").should("be.visible"); - cy.get("#skills").should("be.visible"); - } - cy.get("#view-username").scrollIntoView(); - cy.get("#view-username").should("be.visible"); - } - - verifyChangeAvatarButtonVisible() { - cy.get("#change-avatar").should("be.visible"); - } - - clickChangeAvatarButton() { - cy.get("#change-avatar").click(); + clickBasicInfoEditButton() { + cy.verifyAndClickElement("#basic-info-edit-button", "Edit"); } - clickBasicInfoViewButton() { - cy.get("#basic-info-view-button").scrollIntoView(); - cy.get("#basic-info-view-button").should("be.visible"); - cy.get("#basic-info-view-button").click(); + clickBaicInfoViewButton() { + cy.verifyAndClickElement("#basic-info-view-button", "View"); } - clickBasicInfoEditButton() { - cy.get("#basic-info-edit-button").scrollIntoView(); - cy.get("#basic-info-edit-button").should("be.visible"); - cy.get("#basic-info-edit-button").click(); + clickContactInfoEditButton() { + cy.verifyAndClickElement("#contact-info-edit-button", "Edit"); } clickContactInfoViewButton() { - cy.get("#contact-info-view-button").scrollIntoView(); - cy.get("#contact-info-view-button").should("be.visible"); - cy.get("#contact-info-view-button").click(); - } - - clickContactInfoEditButton() { - cy.get("#contact-info-edit-button").scrollIntoView(); - cy.get("#contact-info-edit-button").should("be.visible"); - cy.get("#contact-info-edit-button").click(); + cy.verifyAndClickElement("#contact-info-view-button", "View"); } clickProfessionalInfoViewButton() { - cy.get("#professional-info-view-button").scrollIntoView(); - cy.get("#professional-info-view-button").should("be.visible"); - cy.get("#professional-info-view-button").click(); + cy.verifyAndClickElement("#professional-info-view-button", "View"); } clickProfessionalInfoEditButton() { - cy.get("#professional-info-edit-button").scrollIntoView(); - cy.get("#professional-info-edit-button").should("be.visible"); - cy.get("#professional-info-edit-button").click(); + cy.verifyAndClickElement("#professional-info-edit-button", "Edit"); } - clickPasswordEditButton() { - cy.get("#change-edit-password-button").scrollIntoView(); - cy.get("#change-edit-password-button").should("be.visible"); - cy.get("#change-edit-password-button").click(); + verifyMoreDetailsPage(hasPermissions = true) { + cy.get("#username").should("be.visible"); + cy.get("#role").should("be.visible"); + cy.get("#usermanagement_tab_nav").should("be.visible"); + cy.get("#profile").should("be.visible"); + if (hasPermissions) { + cy.get("#facilities").should("be.visible"); + cy.get("#skills").should("be.visible"); + } + cy.get("#view-username").scrollIntoView(); + cy.get("#view-username").should("be.visible"); } verifyQualificationDoesntExist() { - cy.get("input[name='qualification']").should("not.exist"); + cy.get("#view-qualification").should("not.exist"); } verifyQualificationExist() { @@ -318,10 +352,6 @@ export class ManageUserPage { cy.get("#view-doctor_medical_council_registration").should("be.visible"); } - verifyUsername(username: string) { - cy.get("#view-username").should("contain", username); - } - verifyBasicInfoEditButtonNotExist() { cy.get("#basic-info-edit-button").should("not.exist"); } @@ -338,14 +368,6 @@ export class ManageUserPage { cy.get("#user-edit-form").should("be.visible"); } - verifyDoctorQualification() { - cy.get("#view-qualification").should("be.visible"); - } - - verifyDoctorQualificationDoesNotExist() { - cy.get("#view-qualification").should("not.exist"); - } - verifyLinkedSkillsTabPage() { cy.get("#select-skill").scrollIntoView(); cy.get("#select-skill").should("be.visible"); @@ -380,11 +402,6 @@ export class ManageUserPage { verifyAddSkillResponse() { cy.wait("@getUserSkills").its("response.statusCode").should("eq", 200); } - assertSkillInAlreadyLinkedSkills(skillName: string) { - cy.get("#already-linked-skills") - .contains(skillName) - .should("have.length", 1); - } assertSkillIndoctorconnect(skillName: string) { cy.get("#doctor-connect-home-doctor") @@ -409,10 +426,6 @@ export class ManageUserPage { cy.get("#added-user-skills").should("contain", skillName); } - assertSkillNotInAddedUserSkills(skillName: string) { - cy.get("#added-user-skills").should("not.contain", skillName); - } - assertDoctorConnectVisibility(realName: string) { cy.get('*[id="doctor-connect-home-doctor"]').should( "contain.text", @@ -423,18 +436,6 @@ export class ManageUserPage { realName, ); } - - assertVideoConnectLink(docName: string, link: string) { - cy.get("ul#options") - .find("li") - .contains(docName) - .within(() => { - cy.get("a").should(($a) => { - const hrefs = $a.map((i, el) => Cypress.$(el).attr("href")).get(); - expect(hrefs).to.include(link); - }); - }); - } } export default ManageUserPage; diff --git a/cypress/pageobject/Users/UserProfilePage.ts b/cypress/pageobject/Users/UserProfilePage.ts deleted file mode 100644 index 50959bb7cf7..00000000000 --- a/cypress/pageobject/Users/UserProfilePage.ts +++ /dev/null @@ -1,105 +0,0 @@ -export default class UserProfilePage { - assertVideoConnectLink(link: string) { - cy.get("#videoconnectlink-profile-details").should("contain.text", link); - } - - clickEditProfileButton() { - cy.get("#edit-cancel-profile-button").click(); - } - - typeVideoConnectLink(link: string) { - cy.get("#video_connect_link").click().clear().type(link); - } - - interceptUpdateUsers() { - cy.intercept("PATCH", "/api/v1/users/*").as("updateUser"); - } - - verifyUpdateUsersResponse() { - cy.wait("@updateUser").its("response.statusCode").should("eq", 200); - } - - clickUpdateButton() { - cy.clickSubmitButton("Update"); - } - - typeDateOfBirth(dob: string) { - cy.clickAndTypeDate("#date_of_birth", dob); - } - - clearPhoneNumber() { - cy.get("#phoneNumber").click().clear(); - } - clearAltPhoneNumber() { - cy.get("#altPhoneNumber").click().clear(); - } - clearWorkingHours() { - cy.get("#weekly_working_hours").click().clear(); - } - clearEmail() { - cy.get("#email").click().clear(); - } - - selectGender(gender: string) { - cy.get("#gender").click(); - cy.get("#gender-option-" + gender).click(); - } - - typeEmail(email: string) { - cy.get("#email").click().clear().type(email); - } - - typePhoneNumber(phone: string) { - cy.get("#phoneNumber").click().clear().type(phone); - } - - typeWhatsappNumber(phone: string) { - cy.get("#altPhoneNumber").click().clear().type(phone); - } - - typeWorkingHours(workingHours: string) { - cy.get("#weekly_working_hours").click().clear().type(workingHours); - } - - typeQualification = (qualification: string) => { - cy.get("#qualification").click().clear().type(qualification); - }; - - typeDoctorYoE = (doctorYoE: string) => { - cy.get("#doctor_experience_commenced_on").click().clear().type(doctorYoE); - }; - - typeMedicalCouncilRegistration = (medicalCouncilRegistration: string) => { - cy.get("#doctor_medical_council_registration") - .click() - .clear() - .type(medicalCouncilRegistration); - }; - - assertDateOfBirth(dob: string) { - cy.get("#date_of_birth-profile-details").should("contain.text", dob); - } - - assertGender(gender: string) { - cy.get("#gender-profile-details").should("contain.text", gender); - } - - assertEmail(email: string) { - cy.get("#emailid-profile-details").should("contain.text", email); - } - - assertPhoneNumber(phone: string) { - cy.get("#contactno-profile-details").should("contain.text", phone); - } - - assertAltPhoneNumber(phone: string) { - cy.get("#whatsapp-profile-details").should("contain.text", phone); - } - - assertWorkingHours(workingHours: string) { - cy.get("#averageworkinghour-profile-details").should( - "contain.text", - workingHours, - ); - } -} diff --git a/src/Routers/routes/UserRoutes.tsx b/src/Routers/routes/UserRoutes.tsx index cc668e2fee6..826007c3b14 100644 --- a/src/Routers/routes/UserRoutes.tsx +++ b/src/Routers/routes/UserRoutes.tsx @@ -1,7 +1,6 @@ import ManageUsers from "@/components/Users/ManageUsers"; import UserAdd from "@/components/Users/UserAdd"; import UserHome from "@/components/Users/UserHome"; -import UserProfile from "@/components/Users/UserProfile"; import { AppRoutes } from "@/Routers/AppRouter"; @@ -14,7 +13,7 @@ const UserRoutes: AppRoutes = { "/users/:username/:tab": ({ username, tab }) => ( ), - "/user/profile": () => , + "/user/:tab": ({ tab }) => , }; export default UserRoutes; diff --git a/src/components/Common/Breadcrumbs.tsx b/src/components/Common/Breadcrumbs.tsx index c2c4aa57446..f55edd4ccf6 100644 --- a/src/components/Common/Breadcrumbs.tsx +++ b/src/components/Common/Breadcrumbs.tsx @@ -3,7 +3,19 @@ import { useState } from "react"; import CareIcon from "@/CAREUI/icons/CareIcon"; +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbList, + BreadcrumbSeparator, +} from "@/components/ui/breadcrumb"; import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; import useAppHistory from "@/hooks/useAppHistory"; @@ -69,76 +81,84 @@ export default function Breadcrumbs({ className={classNames("text-sm font-normal", crumb.style)} >
- - {isLastItem ? ( - {crumb.name} - ) : ( - - )} + + {isLastItem && {crumb.name}}
); }; return ( - + ); } diff --git a/src/components/Users/ManageUsers.tsx b/src/components/Users/ManageUsers.tsx index 0851a186728..d28a0aeea52 100644 --- a/src/components/Users/ManageUsers.tsx +++ b/src/components/Users/ManageUsers.tsx @@ -7,13 +7,8 @@ import CareIcon from "@/CAREUI/icons/CareIcon"; import { AdvancedFilterButton } from "@/CAREUI/interactive/FiltersSlideover"; import ButtonV2 from "@/components/Common/ButtonV2"; -import CircularProgress from "@/components/Common/CircularProgress"; -import { FacilitySelect } from "@/components/Common/FacilitySelect"; import Loading from "@/components/Common/Loading"; import Page from "@/components/Common/Page"; -import Pagination from "@/components/Common/Pagination"; -import { FacilityModel } from "@/components/Facility/models"; -import UnlinkFacilityDialog from "@/components/Users/UnlinkFacilityDialog"; import UserFilter from "@/components/Users/UserFilter"; import UserListView from "@/components/Users/UserListAndCard"; @@ -22,11 +17,8 @@ import useFilters from "@/hooks/useFilters"; import { USER_TYPES } from "@/common/constants"; -import * as Notification from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; import useTanStackQueryInstead from "@/Utils/request/useQuery"; -import { classNames } from "@/Utils/utils"; export default function ManageUsers() { const { t } = useTranslation(); @@ -183,314 +175,3 @@ export default function ManageUsers() { ); } - -export function UserFacilities(props: { user: any }) { - const { t } = useTranslation(); - const { user } = props; - const username = user.username; - const limit = 20; - const [isLoading, setIsLoading] = useState(false); - const [currentPage, setCurrentPage] = useState(1); - const [offset, setOffset] = useState(0); - const [totalCount, setTotalCount] = useState(0); - const [facility, setFacility] = useState(null); - const [unlinkFacilityData, setUnlinkFacilityData] = useState<{ - show: boolean; - userName: string; - facility?: FacilityModel; - isHomeFacility: boolean; - }>({ show: false, userName: "", facility: undefined, isHomeFacility: false }); - const authUser = useAuthUser(); - const hideUnlinkFacilityModal = () => { - setUnlinkFacilityData({ - show: false, - facility: undefined, - userName: "", - isHomeFacility: false, - }); - }; - - const { - data: userFacilities, - loading: userFacilitiesLoading, - refetch: refetchUserFacilities, - } = useTanStackQueryInstead(routes.userListFacility, { - pathParams: { username }, - query: { - limit, - offset, - }, - onResponse: ({ res, data }) => { - if (res?.status === 200 && data) { - setTotalCount(data.count); - } - }, - }); - - const handlePagination = (page: number, limit: number) => { - const offset = (page - 1) * limit; - setCurrentPage(page); - setOffset(offset); - }; - - const updateHomeFacility = async (username: string, facility: any) => { - setIsLoading(true); - const { res } = await request(routes.partialUpdateUser, { - pathParams: { username }, - body: { home_facility: facility.id.toString() }, - }); - if (!res?.ok) { - Notification.Error({ - msg: "Error while updating Home facility", - }); - } else { - user.home_facility_object = facility; - Notification.Success({ - msg: "Home Facility updated successfully", - }); - } - await refetchUserFacilities(); - setIsLoading(false); - }; - - const handleUnlinkFacilitySubmit = async () => { - setIsLoading(true); - if (unlinkFacilityData.isHomeFacility) { - const { res } = await request(routes.clearHomeFacility, { - pathParams: { username }, - }); - - if (!res?.ok) { - Notification.Error({ - msg: "Error while clearing home facility", - }); - } else { - user.home_facility_object = null; - Notification.Success({ - msg: "Home Facility cleared successfully", - }); - } - } else { - const { res } = await request(routes.deleteUserFacility, { - pathParams: { username }, - body: { facility: unlinkFacilityData?.facility?.id?.toString() }, - }); - if (!res?.ok) { - Notification.Error({ - msg: "Error while unlinking home facility", - }); - } else { - Notification.Success({ - msg: "Facility unlinked successfully", - }); - } - } - await refetchUserFacilities(); - hideUnlinkFacilityModal(); - setIsLoading(false); - }; - - const addFacility = async (username: string, facility: any) => { - setIsLoading(true); - const { res } = await request(routes.addUserFacility, { - pathParams: { username }, - body: { facility: facility.id.toString() }, - }); - - if (!res?.ok) { - Notification.Error({ - msg: "Error while linking facility", - }); - } else { - Notification.Success({ - msg: "Facility linked successfully", - }); - } - await refetchUserFacilities(); - setIsLoading(false); - setFacility(null); - }; - - return ( -
- {unlinkFacilityData.show && ( - - )} - -
- - addFacility(username, facility)} - > - {t("add")} - -
-
- - {isLoading || userFacilitiesLoading ? ( -
- -
- ) : ( -
- {/* Home Facility section */} - {user?.home_facility_object && ( -
-
-
- {user?.home_facility_object?.name} - - - Home Facility - - {(["DistrictAdmin", "StateAdmin"].includes( - authUser.user_type, - ) || - username === authUser.username) && ( -
- -
- )} -
-
-
- )} - - {/* Linked Facilities section */} - {!!userFacilities?.results.length && ( -
-
- {userFacilities.results.map( - (facility: FacilityModel, i: number) => { - if (user?.home_facility_object?.id === facility.id) { - // skip if it's a home facility - return null; - } - return ( -
-
- {facility.name} - {(["DistrictAdmin", "StateAdmin"].includes( - authUser.user_type, - ) || - username === authUser.username) && ( -
- {authUser.user_type !== "Nurse" && ( - - )} - -
- )} -
-
- ); - }, - )} -
- {totalCount > limit && ( -
- -
- )} -
- )} - {!user?.home_facility_object && !userFacilities?.results.length && ( -
-
- No linked facilities -
-

- {t("no_linked_facilities")} -

-
- )} -
- )} -
- ); -} diff --git a/src/components/Users/UserHome.tsx b/src/components/Users/UserHome.tsx index 8c12ad2c561..f441e66370d 100644 --- a/src/components/Users/UserHome.tsx +++ b/src/components/Users/UserHome.tsx @@ -38,6 +38,8 @@ export default function UserHome(props: UserHomeProps) { if (!username) { username = authUser.username; } + const loggedInUser = username === authUser.username; + const urlPrefix = loggedInUser ? "/user" : `/users/${username}`; const { loading, refetch: refetchUserDetails } = useTanStackQueryInstead( routes.getUserDetails, @@ -96,7 +98,11 @@ export default function UserHome(props: UserHomeProps) { <>
{t(`USERMANAGEMENT_TAB__${p}`)} diff --git a/src/components/Users/UserProfile.tsx b/src/components/Users/UserProfile.tsx deleted file mode 100644 index 786e569c4db..00000000000 --- a/src/components/Users/UserProfile.tsx +++ /dev/null @@ -1,1032 +0,0 @@ -import careConfig from "@careConfig"; -import { FormEvent, useEffect, useReducer, useState } from "react"; -import { useTranslation } from "react-i18next"; - -import CareIcon from "@/CAREUI/icons/CareIcon"; - -import AvatarEditModal from "@/components/Common/AvatarEditModal"; -import AvatarEditable from "@/components/Common/AvatarEditable"; -import ButtonV2, { Submit } from "@/components/Common/ButtonV2"; -import LanguageSelector from "@/components/Common/LanguageSelector"; -import Loading from "@/components/Common/Loading"; -import Page from "@/components/Common/Page"; -import UpdatableApp, { checkForUpdate } from "@/components/Common/UpdatableApp"; -import { PhoneNumberValidator } from "@/components/Form/FieldValidators"; -import DateFormField from "@/components/Form/FormFields/DateFormField"; -import PhoneNumberFormField from "@/components/Form/FormFields/PhoneNumberFormField"; -import { SelectFormField } from "@/components/Form/FormFields/SelectFormField"; -import TextFormField from "@/components/Form/FormFields/TextFormField"; -import { FieldChangeEvent } from "@/components/Form/FormFields/Utils"; -import { validateRule } from "@/components/Users/UserAddEditForm"; -import { - GenderType, - SkillModel, - UpdatePasswordForm, -} from "@/components/Users/models"; - -import useAuthUser, { useAuthContext } from "@/hooks/useAuthUser"; - -import { GENDER_TYPES } from "@/common/constants"; -import { validateEmailAddress } from "@/common/validation"; - -import * as Notification from "@/Utils/Notifications"; -import dayjs from "@/Utils/dayjs"; -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, - formatDisplayName, - isValidUrl, - parsePhoneNumber, - sleep, -} from "@/Utils/utils"; - -type EditForm = { - firstName: string; - lastName: string; - date_of_birth: Date | null | string; - gender: GenderType; - email: string; - video_connect_link: string | undefined; - phoneNumber: string; - altPhoneNumber: string; - user_type: string | undefined; - qualification: string | undefined; - doctor_experience_commenced_on: number | string | undefined; - doctor_medical_council_registration: string | undefined; - weekly_working_hours: string | null | undefined; -}; -type ErrorForm = { - firstName: string; - lastName: string; - date_of_birth: string | null; - gender: string; - email: string; - video_connect_link: string | undefined; - phoneNumber: string; - altPhoneNumber: string; - user_type: string | undefined; - qualification: string | undefined; - doctor_experience_commenced_on: number | string | undefined; - doctor_medical_council_registration: string | undefined; - weekly_working_hours: string | undefined; -}; -type State = { - form: EditForm; - errors: ErrorForm; -}; -type Action = - | { type: "set_form"; form: EditForm } - | { type: "set_error"; errors: ErrorForm }; - -const initForm: EditForm = { - firstName: "", - lastName: "", - date_of_birth: null, - gender: "Male", - video_connect_link: "", - email: "", - phoneNumber: "", - altPhoneNumber: "", - user_type: "", - qualification: undefined, - doctor_experience_commenced_on: undefined, - doctor_medical_council_registration: undefined, - weekly_working_hours: undefined, -}; - -const initError: ErrorForm = Object.assign( - {}, - ...Object.keys(initForm).map((k) => ({ [k]: "" })), -); - -const initialState: State = { - form: { ...initForm }, - errors: { ...initError }, -}; - -const editFormReducer = (state: State, action: Action) => { - switch (action.type) { - case "set_form": { - return { - ...state, - form: action.form, - }; - } - case "set_error": { - return { - ...state, - errors: action.errors, - }; - } - } -}; - -export default function UserProfile() { - const { t } = useTranslation(); - const { signOut, refetchUser } = useAuthContext(); - const [states, dispatch] = useReducer(editFormReducer, initialState); - const [editAvatar, setEditAvatar] = useState(false); - const [updateStatus, setUpdateStatus] = useState({ - isChecking: false, - isUpdateAvailable: false, - }); - const [dirty, setDirty] = useState(false); - - const authUser = useAuthUser(); - - const [changePasswordForm, setChangePasswordForm] = useState<{ - username: string; - old_password: string; - new_password_1: string; - new_password_2: string; - }>({ - username: authUser.username, - old_password: "", - new_password_1: "", - new_password_2: "", - }); - - const [changePasswordErrors] = useState<{ - old_password: string; - password_confirmation: string; - }>({ - old_password: "", - password_confirmation: "", - }); - - const [showEdit, setShowEdit] = useState(false); - - useEffect(() => { - const formData: EditForm = { - firstName: authUser.first_name, - lastName: authUser.last_name, - date_of_birth: authUser.date_of_birth || null, - gender: authUser.gender || "Male", - email: authUser.email, - video_connect_link: authUser.video_connect_link, - phoneNumber: authUser.phone_number?.toString() || "", - altPhoneNumber: authUser.alt_phone_number?.toString() || "", - user_type: authUser.user_type, - qualification: authUser.qualification, - doctor_experience_commenced_on: dayjs().diff( - dayjs(authUser.doctor_experience_commenced_on), - "years", - ), - doctor_medical_council_registration: - authUser.doctor_medical_council_registration, - weekly_working_hours: authUser.weekly_working_hours, - }; - dispatch({ - type: "set_form", - form: formData, - }); - setDirty(false); - }, [authUser]); - - const { data: skillsView, loading: isSkillsLoading } = - useTanStackQueryInstead(routes.userListSkill, { - pathParams: { username: authUser.username }, - }); - - const validatePassword = (password: string) => { - const rules = [ - { - test: (p: string) => p.length >= 8, - message: "Password should be at least 8 characters long", - }, - { - test: (p: string) => p !== p.toUpperCase(), - message: "Password should contain at least 1 lowercase letter", - }, - { - test: (p: string) => p !== p.toLowerCase(), - message: "Password should contain at least 1 uppercase letter", - }, - { - test: (p: string) => /\d/.test(p), - message: "Password should contain at least 1 number", - }, - ]; - return rules.map((rule) => - validateRule(rule.test(password), rule.message, !password), - ); - }; - - const validateNewPassword = (password: string) => { - if ( - password.length < 8 || - !/\d/.test(password) || - password === password.toUpperCase() || - password === password.toLowerCase() - ) { - return false; - } - return true; - }; - - const validateForm = () => { - const errors = { ...initError }; - let invalidForm = false; - Object.keys(states.form).forEach((field) => { - switch (field) { - case "firstName": - case "lastName": - case "gender": - if (!states.form[field]) { - errors[field] = t("field_required"); - invalidForm = true; - } - return; - case "date_of_birth": - if (!states.form[field]) { - errors[field] = "Enter a valid date of birth"; - invalidForm = true; - } else if ( - !dayjs(states.form[field]).isValid() || - dayjs(states.form[field]).isAfter(dayjs().subtract(17, "year")) - ) { - errors[field] = "Enter a valid date of birth"; - invalidForm = true; - } - return; - case "phoneNumber": - // eslint-disable-next-line no-case-declarations - const phoneNumber = parsePhoneNumber(states.form[field]); - - // eslint-disable-next-line no-case-declarations - let is_valid = false; - if (phoneNumber) { - is_valid = PhoneNumberValidator()(phoneNumber) === undefined; - } - - if (!states.form[field] || !is_valid) { - errors[field] = "Please enter valid phone number"; - invalidForm = true; - } - return; - case "altPhoneNumber": - // eslint-disable-next-line no-case-declarations - let alt_is_valid = false; - if (states.form[field] && states.form[field] !== "+91") { - const altPhoneNumber = parsePhoneNumber(states.form[field]); - if (altPhoneNumber) { - alt_is_valid = - PhoneNumberValidator(["mobile"])(altPhoneNumber) === undefined; - } - } - - if ( - states.form[field] && - states.form[field] !== "+91" && - !alt_is_valid - ) { - errors[field] = "Please enter valid mobile number"; - invalidForm = true; - } - return; - case "email": - if (!states.form[field]) { - errors[field] = t("field_required"); - invalidForm = true; - } else if (!validateEmailAddress(states.form[field])) { - errors[field] = "Enter a valid email address"; - invalidForm = true; - } - return; - case "doctor_experience_commenced_on": - if (states.form.user_type === "Doctor" && !states.form[field]) { - errors[field] = t("field_required"); - invalidForm = true; - } else if ( - (states.form.user_type === "Doctor" && - Number(states.form.doctor_experience_commenced_on) >= 100) || - Number(states.form.doctor_experience_commenced_on) < 0 - ) { - errors[field] = - "Doctor experience should be at least 0 years and less than 100 years."; - invalidForm = true; - } - return; - case "qualification": - if ( - (states.form.user_type === "Doctor" || - states.form.user_type === "Nurse") && - !states.form[field] - ) { - errors[field] = t("field_required"); - invalidForm = true; - } - return; - case "doctor_medical_council_registration": - if (states.form.user_type === "Doctor" && !states.form[field]) { - errors[field] = t("field_required"); - invalidForm = true; - } - return; - case "weekly_working_hours": - if ( - states.form[field] && - (Number(states.form[field]) < 0 || - Number(states.form[field]) > 168 || - !/^\d+$/.test(states.form[field] ?? "")) - ) { - errors[field] = - "Average weekly working hours must be a number between 0 and 168"; - invalidForm = true; - } - return; - case "video_connect_link": - if (states.form[field]) { - if (isValidUrl(states.form[field]) === false) { - errors[field] = "Please enter a valid url"; - invalidForm = true; - } - } - return; - } - }); - dispatch({ type: "set_error", errors }); - return !invalidForm; - }; - - const handleFieldChange = (event: FieldChangeEvent) => { - dispatch({ - type: "set_form", - form: { ...states.form, [event.name]: event.value }, - }); - setDirty(true); - }; - - const getDate = (value: any) => - value && dayjs(value).isValid() && dayjs(value).toDate(); - - const fieldProps = (name: string) => { - return { - name, - id: name, - value: (states.form as any)[name], - onChange: handleFieldChange, - error: (states.errors as any)[name], - }; - }; - - const handleSubmit = async (e: FormEvent) => { - e.preventDefault(); - const validForm = validateForm(); - if (validForm) { - const data = { - username: authUser.username, - first_name: states.form.firstName, - last_name: states.form.lastName, - email: states.form.email, - video_connect_link: states.form.video_connect_link, - phone_number: parsePhoneNumber(states.form.phoneNumber) ?? "", - alt_phone_number: parsePhoneNumber(states.form.altPhoneNumber) ?? "", - gender: states.form.gender, - date_of_birth: dateQueryString(states.form.date_of_birth), - qualification: - states.form.user_type === "Doctor" || - states.form.user_type === "Nurse" - ? states.form.qualification - : undefined, - doctor_experience_commenced_on: - states.form.user_type === "Doctor" - ? dayjs() - .subtract( - parseInt( - (states.form.doctor_experience_commenced_on as string) ?? - "0", - ), - "years", - ) - .format("YYYY-MM-DD") - : undefined, - doctor_medical_council_registration: - states.form.user_type === "Doctor" - ? states.form.doctor_medical_council_registration - : undefined, - weekly_working_hours: - states.form.weekly_working_hours && - states.form.weekly_working_hours !== "" - ? states.form.weekly_working_hours - : null, - }; - const { res } = await request(routes.partialUpdateUser, { - pathParams: { username: authUser.username }, - body: data, - }); - if (res?.ok) { - Notification.Success({ - msg: "Details updated successfully", - }); - await refetchUser(); - setShowEdit(false); - } - } - }; - - const isLoading = isSkillsLoading; - - if (isLoading) { - return ; - } - - const checkUpdates = async () => { - setUpdateStatus({ ...updateStatus, isChecking: true }); - await new Promise((resolve) => setTimeout(resolve, 500)); - if ((await checkForUpdate()) != null) { - setUpdateStatus({ - isUpdateAvailable: true, - isChecking: false, - }); - } else { - setUpdateStatus({ - isUpdateAvailable: false, - isChecking: false, - }); - Notification.Success({ - msg: "No update available", - }); - } - }; - - const changePassword = async (e: any) => { - e.preventDefault(); - //validating form - if ( - changePasswordForm.new_password_1 !== changePasswordForm.new_password_2 - ) { - Notification.Error({ - msg: "Passwords are different in new password and confirmation password column.", - }); - } else if (!validateNewPassword(changePasswordForm.new_password_1)) { - Notification.Error({ - msg: "Entered New Password is not valid, please check!", - }); - } else if ( - changePasswordForm.new_password_1 === changePasswordForm.old_password - ) { - Notification.Error({ - msg: "New password is same as old password, Please enter a different new password.", - }); - } else { - const form: UpdatePasswordForm = { - old_password: changePasswordForm.old_password, - username: authUser.username, - new_password: changePasswordForm.new_password_1, - }; - const { res, data, error } = await request(routes.updatePassword, { - body: form, - }); - if (res?.ok) { - Notification.Success({ msg: data?.message }); - } else if (!error) { - Notification.Error({ - msg: "There was some error. Please try again in some time.", - }); - } - setChangePasswordForm({ - ...changePasswordForm, - new_password_1: "", - new_password_2: "", - old_password: "", - }); - } - }; - - const handleAvatarUpload = async (file: File, onError: () => void) => { - const formData = new FormData(); - formData.append("profile_picture", file); - const url = `${careConfig.apiUrl}/api/v1/users/${authUser.username}/profile_picture/`; - - uploadFile( - url, - formData, - "POST", - { Authorization: getAuthorizationHeader() }, - async (xhr: XMLHttpRequest) => { - if (xhr.status === 200) { - await sleep(1000); - refetchUser(); - Notification.Success({ msg: "Profile picture updated." }); - setEditAvatar(false); - } else { - onError(); - } - }, - null, - () => { - onError(); - }, - ); - }; - - const handleAvatarDelete = async (onError: () => void) => { - const { res } = await request(routes.deleteProfilePicture, { - pathParams: { username: authUser.username }, - }); - if (res?.ok) { - Notification.Success({ msg: "Profile picture deleted" }); - await refetchUser(); - setEditAvatar(false); - } else { - onError(); - } - }; - - return ( - - setEditAvatar(false)} - /> -
-
-

- {t("local_body")}, {t("district")}, {t("state")}{" "} - {t("are_non_editable_fields")}. -

-
- setEditAvatar(!editAvatar)} - className="h-20 w-20" - /> -
-

- {authUser.first_name} {authUser.last_name} -

-

- @{authUser.username} -

-
-
-
- setShowEdit(!showEdit)} - type="button" - id="edit-cancel-profile-button" - > - {showEdit ? t("cancel") : t("edit_user_profile")} - - - - {t("sign_out")} - -
-
-
- {!showEdit && !isLoading && ( -
-
-
-
- {t("username")} -
-
- {authUser.username || "-"} -
-
-
-
- {t("phone_number")} -
-
- {authUser.phone_number || "-"} -
-
- -
-
- {t("whatsapp_number")} -
-
- {authUser.alt_phone_number || "-"} -
-
-
-
- {t("email")} -
-
- {authUser.email || "-"} -
-
-
-
- {t("first_name")} -
-
- {authUser.first_name || "-"} -
-
-
-
- {t("last_name")} -
-
- {authUser.last_name || "-"} -
-
-
-
- {t("date_of_birth")} -
-
- {authUser.date_of_birth - ? formatDate(authUser.date_of_birth) - : "-"} -
-
-
-
- {t("access_level")} -
-
- - {authUser.user_type || "-"} -
-
-
-
- {t("gender")} -
-
- {authUser.gender || "-"} -
-
-
-
- {t("local_body")} -
-
- {authUser.local_body_object?.name || "-"} -
-
-
-
- {t("district")} -
-
- {authUser.district_object?.name || "-"} -
-
-
-
- {t("state")} -
-
- {authUser.state_object?.name || "-"} -
-
-
-
- {t("skills")} -
-
-
- {skillsView?.results?.length - ? skillsView.results?.map((skill: SkillModel) => { - return ( - -

- {skill.skill_object.name} -

-
- ); - }) - : "-"} -
-
-
-
-
- {t("average_weekly_working_hours")} -
-
- {authUser.weekly_working_hours ?? "-"} -
-
- -
-
- )} - {showEdit && ( -
-
-
-
-
- - - - o.text} - optionValue={(o) => o.text} - options={GENDER_TYPES} - /> - - - - {(states.form.user_type === "Doctor" || - states.form.user_type === "Nurse") && ( - - )} - {states.form.user_type === "Doctor" && ( - <> - - - - )} - - -
-
-
- -
-
-
-
-
-
-
- - setChangePasswordForm({ - ...changePasswordForm, - old_password: e.value, - }) - } - error={changePasswordErrors.old_password} - required - /> -
- { - setChangePasswordForm({ - ...changePasswordForm, - new_password_1: e.value, - }); - }} - required - /> -
- {validatePassword(changePasswordForm.new_password_1)} -
-
-
- { - setChangePasswordForm({ - ...changePasswordForm, - new_password_2: e.value, - }); - }} - /> - {changePasswordForm.new_password_2.length > 0 && ( -
- {validateRule( - changePasswordForm.new_password_1 === - changePasswordForm.new_password_2, - "Confirm password should match the new password", - !changePasswordForm.new_password_2, - )} -
- )} -
-
-
-
- -
-
-
-
- )} -
-
- -
-
-
-

- {t("language_selection")} -

-

- {t("set_your_local_language")} -

-
-
-
- -
-
-
-
-
-

- {t("software_update")} -

-

- {t("check_for_available_update")} -

-
-
-
- {updateStatus.isChecking ? ( - // While checking for updates - -
- - {t("checking_for_update")} -
-
- ) : updateStatus.isUpdateAvailable ? ( - // When an update is available - - -
- - {t("update_available")} -
-
-
- ) : ( - // Default state to check for updates - -
- - {t("check_for_update")} -
-
- )} -
-
-
- ); -} diff --git a/src/components/Users/UserSoftwareUpdate.tsx b/src/components/Users/UserSoftwareUpdate.tsx new file mode 100644 index 00000000000..5cc685f575d --- /dev/null +++ b/src/components/Users/UserSoftwareUpdate.tsx @@ -0,0 +1,72 @@ +import { useState } from "react"; +import { useTranslation } from "react-i18next"; + +import CareIcon from "@/CAREUI/icons/CareIcon"; + +import { Button } from "@/components/ui/button"; + +import UpdatableApp, { checkForUpdate } from "@/components/Common/UpdatableApp"; + +import * as Notification from "@/Utils/Notifications"; + +export default function UserSoftwareUpdate() { + const [updateStatus, setUpdateStatus] = useState({ + isChecking: false, + isUpdateAvailable: false, + }); + const { t } = useTranslation(); + + const checkUpdates = async () => { + setUpdateStatus({ ...updateStatus, isChecking: true }); + await new Promise((resolve) => setTimeout(resolve, 500)); + if ((await checkForUpdate()) != null) { + setUpdateStatus({ + isUpdateAvailable: true, + isChecking: false, + }); + } else { + setUpdateStatus({ + isUpdateAvailable: false, + isChecking: false, + }); + Notification.Success({ + msg: "No update available", + }); + } + }; + + return ( + <> + {updateStatus.isChecking ? ( + // While checking for updates + + ) : updateStatus.isUpdateAvailable ? ( + // When an update is available + + + + ) : ( + // Default state to check for updates + + )} + + ); +} diff --git a/src/components/Users/UserSummary.tsx b/src/components/Users/UserSummary.tsx index f75aa066e65..9b703deddbd 100644 --- a/src/components/Users/UserSummary.tsx +++ b/src/components/Users/UserSummary.tsx @@ -15,6 +15,7 @@ import { UserProfessionalInfoView, } from "@/components/Users/UserEditDetails"; import UserResetPassword from "@/components/Users/UserResetPassword"; +import UserSoftwareUpdate from "@/components/Users/UserSoftwareUpdate"; import { BasicInfoDetails, ContactInfoDetails, @@ -200,12 +201,20 @@ export default function UserSummaryTab({ /> )} {authUser.username === userData.username && ( - + <> + + + )} {deletePermitted && (
diff --git a/src/components/ui/breadcrumb.tsx b/src/components/ui/breadcrumb.tsx new file mode 100644 index 00000000000..de505bc5833 --- /dev/null +++ b/src/components/ui/breadcrumb.tsx @@ -0,0 +1,118 @@ +import { ChevronRightIcon, DotsHorizontalIcon } from "@radix-ui/react-icons"; +import { Slot } from "@radix-ui/react-slot"; +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +const Breadcrumb = React.forwardRef< + HTMLElement, + React.ComponentPropsWithoutRef<"nav"> & { + separator?: React.ReactNode; + } +>(({ ...props }, ref) =>