diff --git a/.github/workflows/label-merge-conflict.yml b/.github/workflows/label-merge-conflict.yml index 0491a102b2c..a7c77d06910 100644 --- a/.github/workflows/label-merge-conflict.yml +++ b/.github/workflows/label-merge-conflict.yml @@ -1,6 +1,7 @@ name: Auto Label Conflicts permissions: + contents: read issues: write pull-requests: write diff --git a/cypress/e2e/patient_spec/PatientConsultationDischarge.cy.ts b/cypress/e2e/patient_spec/PatientConsultationDischarge.cy.ts index 846b937998b..fc5d26e006a 100644 --- a/cypress/e2e/patient_spec/PatientConsultationDischarge.cy.ts +++ b/cypress/e2e/patient_spec/PatientConsultationDischarge.cy.ts @@ -117,14 +117,6 @@ describe("Patient Discharge based on multiple reason", () => { patientDischarge.interceptDischargePatient(); cy.clickSubmitButton("Acknowledge & Submit"); patientDischarge.verifyDischargePatient(); - // 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/patient_spec/PatientDoctorNotes.cy.ts b/cypress/e2e/patient_spec/PatientDoctorNotes.cy.ts index 4fe19329af1..35e985012d1 100644 --- a/cypress/e2e/patient_spec/PatientDoctorNotes.cy.ts +++ b/cypress/e2e/patient_spec/PatientDoctorNotes.cy.ts @@ -11,7 +11,6 @@ describe("Patient Discussion notes in the consultation page", () => { const patientNurseReplyNote = "Test nurse reply Notes"; const discussionNotesSubscribeWarning = "Please subscribe to notifications to get live updates on discussion notes."; - const discussionNotesSuccessMessage = "Note added successfully"; before(() => { loginPage.loginByRole("districtAdmin"); @@ -34,8 +33,6 @@ describe("Patient Discussion notes in the consultation page", () => { patientDoctorNotes.selectNurseDiscussion(); patientDoctorNotes.addDiscussionNotes(patientNurseNote); patientDoctorNotes.postDiscussionNotes(); - cy.verifyNotification(discussionNotesSuccessMessage); - cy.closeNotification(); // verify the auto-switching of tab to nurse notes if the user is a nurse patientDoctorNotes.signout(); loginPage.loginManuallyAsNurse(); @@ -50,8 +47,6 @@ describe("Patient Discussion notes in the consultation page", () => { // Post a reply comment to the message patientDoctorNotes.addDiscussionNotes(patientNurseReplyNote); patientDoctorNotes.postDiscussionNotes(); - cy.verifyNotification(discussionNotesSuccessMessage); - cy.closeNotification(); patientDoctorNotes.verifyDiscussionMessage(patientNurseReplyNote); }); 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/package-lock.json b/package-lock.json index e2b5c5e311b..fa8c7e1aa72 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,18 +20,18 @@ "@pnotify/core": "^5.2.0", "@pnotify/mobile": "^5.2.0", "@radix-ui/react-dialog": "^1.1.4", - "@radix-ui/react-dropdown-menu": "^2.1.2", + "@radix-ui/react-dropdown-menu": "^2.1.4", "@radix-ui/react-icons": "^1.3.2", - "@radix-ui/react-label": "^2.1.0", - "@radix-ui/react-popover": "^1.1.2", + "@radix-ui/react-label": "^2.1.1", + "@radix-ui/react-popover": "^1.1.4", "@radix-ui/react-scroll-area": "^1.2.0", - "@radix-ui/react-slot": "^1.1.0", - "@radix-ui/react-toast": "^1.2.2", + "@radix-ui/react-slot": "^1.1.1", + "@radix-ui/react-toast": "^1.2.4", "@radix-ui/react-tooltip": "^1.1.6", - "@sentry/browser": "^8.45.1", - "@tanstack/react-query": "^5.62.3", + "@sentry/browser": "^8.47.0", + "@tanstack/react-query": "^5.62.8", "@tanstack/react-query-devtools": "^5.62.7", - "@yudiel/react-qr-scanner": "^2.0.8", + "@yudiel/react-qr-scanner": "^2.1.0", "bowser": "^2.11.0", "browser-image-compression": "^2.0.2", "browserslist": "^4.24.3", @@ -56,14 +56,14 @@ "react-copy-to-clipboard": "^5.1.0", "react-dom": "18.3.1", "react-google-recaptcha": "^3.1.0", - "react-i18next": "^15.1.3", + "react-i18next": "^15.2.0", "react-infinite-scroll-component": "^6.1.0", - "react-pdf": "^9.1.1", + "react-pdf": "^9.2.1", "react-webcam": "^7.2.0", "tailwind-merge": "^2.5.5", "tailwindcss-animate": "^1.0.7", "use-keyboard-shortcut": "^1.1.6", - "xlsx": "^0.18.5" + "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz" }, "devDependencies": { "@julr/vite-plugin-validate-env": "^1.1.1", @@ -2865,8 +2865,10 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "dev": true, "license": "BSD-3-Clause", "optional": true, + "peer": true, "dependencies": { "detect-libc": "^2.0.0", "https-proxy-agent": "^5.0.0", @@ -3624,12 +3626,12 @@ "license": "MIT" }, "node_modules/@radix-ui/react-arrow": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz", - "integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.1.tgz", + "integrity": "sha512-NaVpZfmv8SKeZbn4ijN2V3jlHA9ngBG16VnIIm22nUR0Yk8KUALyBxT3KYEUnNuch9sTE8UTsS3whzBgKOL30w==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.0.0" + "@radix-ui/react-primitive": "2.0.1" }, "peerDependencies": { "@types/react": "*", @@ -3646,16 +3648,13 @@ } } }, - "node_modules/@radix-ui/react-collection": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.0.tgz", - "integrity": "sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==", + "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-primitive": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", + "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-slot": "1.1.0" + "@radix-ui/react-slot": "1.1.1" }, "peerDependencies": { "@types/react": "*", @@ -3672,21 +3671,6 @@ } } }, - "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-context": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", - "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", @@ -3774,17 +3758,14 @@ } } }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.3.tgz", - "integrity": "sha512-onrWn/72lQoEucDmJnr8uczSNTujT0vJnA/X5+3AkChVPowr8n1yvIKIabhWyMQeMvvmdpsvcyDqx3X1LEXCPg==", + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-presence": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", + "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", - "@radix-ui/react-primitive": "2.0.1", - "@radix-ui/react-use-callback-ref": "1.1.0", - "@radix-ui/react-use-escape-keydown": "1.1.0" + "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { "@types/react": "*", @@ -3801,15 +3782,13 @@ } } }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.1.tgz", - "integrity": "sha512-01omzJAYRxXdG2/he/+xy+c8a8gCydoQ1yOxnWNcRhrrBW5W+RQJ22EK1SaO8tb3WoUsuEw7mJjBozPzihDFjA==", + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", + "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.1", - "@radix-ui/react-primitive": "2.0.1", - "@radix-ui/react-use-callback-ref": "1.1.0" + "@radix-ui/react-slot": "1.1.1" }, "peerDependencies": { "@types/react": "*", @@ -3826,14 +3805,32 @@ } } }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-portal": { + "node_modules/@radix-ui/react-direction": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", + "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.3.tgz", - "integrity": "sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.3.tgz", + "integrity": "sha512-onrWn/72lQoEucDmJnr8uczSNTujT0vJnA/X5+3AkChVPowr8n1yvIKIabhWyMQeMvvmdpsvcyDqx3X1LEXCPg==", "license": "MIT", "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-primitive": "2.0.1", - "@radix-ui/react-use-layout-effect": "1.1.0" + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" }, "peerDependencies": { "@types/react": "*", @@ -3850,31 +3847,28 @@ } } }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-presence": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", - "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", + "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.0" - }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": { + "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-primitive": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", @@ -3897,42 +3891,49 @@ } } }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz", - "integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==", + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.4.tgz", + "integrity": "sha512-iXU1Ab5ecM+yEepGAWK8ZhMyKX4ubFdCNtol4sT9D0OVErG9PNElfx3TQhjw7n7BC5nFVz68/5//clWy+8TXzA==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.1" + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-menu": "2.1.4", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-controllable-state": "1.1.0" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-dialog/node_modules/react-remove-scroll": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.2.tgz", - "integrity": "sha512-KmONPx5fnlXYJQqC62Q+lwIeAk64ws/cUw6omIumRzMRPqgnYqhSSti99nbj0Ry13bv7dF+BKn7NB+OqkdZGTw==", + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", "license": "MIT", - "dependencies": { - "react-remove-scroll-bar": "^2.3.7", - "react-style-singleton": "^2.2.1", - "tslib": "^2.1.0", - "use-callback-ref": "^1.3.3", - "use-sidecar": "^1.1.2" - }, - "engines": { - "node": ">=10" - }, "peerDependencies": { "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { @@ -3940,61 +3941,53 @@ } } }, - "node_modules/@radix-ui/react-direction": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", - "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==", + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-primitive": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", + "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.1" + }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-dismissable-layer": { + "node_modules/@radix-ui/react-focus-guards": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.1.tgz", - "integrity": "sha512-QSxg29lfr/xcev6kSz7MAlmDnzbP1eI/Dwn3Tp1ip0KT5CUELsxkekFEMVBEoykI3oV39hKT4TKZzBNMbcTZYQ==", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz", + "integrity": "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==", "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-callback-ref": "1.1.0", - "@radix-ui/react-use-escape-keydown": "1.1.0" - }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-dropdown-menu": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.2.tgz", - "integrity": "sha512-GVZMR+eqK8/Kes0a36Qrv+i20bAPXSn8rCBTHx30w+3ECnR5o3xixAlqcVaYvLeyKUsm0aqyhWfmUcqufM8nYA==", + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.1.tgz", + "integrity": "sha512-01omzJAYRxXdG2/he/+xy+c8a8gCydoQ1yOxnWNcRhrrBW5W+RQJ22EK1SaO8tb3WoUsuEw7mJjBozPzihDFjA==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.1", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-menu": "2.1.2", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-controllable-state": "1.1.0" + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { "@types/react": "*", @@ -4011,10 +4004,10 @@ } } }, - "node_modules/@radix-ui/react-focus-guards": { + "node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-compose-refs": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz", - "integrity": "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -4026,15 +4019,13 @@ } } }, - "node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz", - "integrity": "sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==", + "node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-primitive": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", + "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-callback-ref": "1.1.0" + "@radix-ui/react-slot": "1.1.1" }, "peerDependencies": { "@types/react": "*", @@ -4079,11 +4070,12 @@ } }, "node_modules/@radix-ui/react-label": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.0.tgz", - "integrity": "sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.1.tgz", + "integrity": "sha512-UUw5E4e/2+4kFMH7+YxORXGWggtY6sM8WIwh5RZchhLuUg2H1hc98Py+pr8HMz6rdaYrK2t296ZEjYLOCO5uUw==", + "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.0.0" + "@radix-ui/react-primitive": "2.0.1" }, "peerDependencies": { "@types/react": "*", @@ -4100,30 +4092,13 @@ } } }, - "node_modules/@radix-ui/react-menu": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.2.tgz", - "integrity": "sha512-lZ0R4qR2Al6fZ4yCCZzu/ReTFrylHFxIqy7OezIpWF4bL0o9biKo0pFIvkaew3TyZ9Fy5gYVrR5zCGZBVbO1zg==", + "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-primitive": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", + "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-collection": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.1", - "@radix-ui/react-direction": "1.1.0", - "@radix-ui/react-dismissable-layer": "1.1.1", - "@radix-ui/react-focus-guards": "1.1.1", - "@radix-ui/react-focus-scope": "1.1.0", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-popper": "1.2.0", - "@radix-ui/react-portal": "1.1.2", - "@radix-ui/react-presence": "1.1.1", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-roving-focus": "1.1.0", - "@radix-ui/react-slot": "1.1.0", - "@radix-ui/react-use-callback-ref": "1.1.0", - "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.6.0" + "@radix-ui/react-slot": "1.1.1" }, "peerDependencies": { "@types/react": "*", @@ -4140,26 +4115,30 @@ } } }, - "node_modules/@radix-ui/react-popover": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.2.tgz", - "integrity": "sha512-u2HRUyWW+lOiA2g0Le0tMmT55FGOEWHwPFt1EPfbLly7uXQExFo5duNKqG2DzmFXIdqOeNd+TpE8baHWJCyP9w==", + "node_modules/@radix-ui/react-menu": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.4.tgz", + "integrity": "sha512-BnOgVoL6YYdHAG6DtXONaR29Eq4nvbi8rutrV/xlr3RQCMMb3yqP85Qiw/3NReozrSW+4dfLkK+rc1hb4wPU/A==", + "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-collection": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.3", "@radix-ui/react-focus-guards": "1.1.1", - "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-focus-scope": "1.1.1", "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-popper": "1.2.0", - "@radix-ui/react-portal": "1.1.2", - "@radix-ui/react-presence": "1.1.1", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-slot": "1.1.0", - "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-popper": "1.2.1", + "@radix-ui/react-portal": "1.1.3", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-roving-focus": "1.1.1", + "@radix-ui/react-slot": "1.1.1", + "@radix-ui/react-use-callback-ref": "1.1.0", "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.6.0" + "react-remove-scroll": "^2.6.1" }, "peerDependencies": { "@types/react": "*", @@ -4176,17 +4155,216 @@ } } }, - "node_modules/@radix-ui/react-popper": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz", - "integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==", + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-collection": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.1.tgz", + "integrity": "sha512-LwT3pSho9Dljg+wY2KN2mrrh6y3qELfftINERIzBUO9e0N+t0oMTyn3k9iv+ZqgrwGkRnLpNJrsMv9BZlt2yuA==", "license": "MIT", "dependencies": { - "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-slot": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-presence": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", + "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-primitive": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", + "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.4.tgz", + "integrity": "sha512-aUACAkXx8LaFymDma+HQVji7WhvEhpFJ7+qPz17Nf4lLZqtreGOFRiNQWQmhzp7kEWg9cOyyQJpdIMUMPc/CPw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.3", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.1", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.1", + "@radix-ui/react-portal": "1.1.3", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-slot": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "^2.6.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-presence": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", + "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-primitive": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", + "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.1.tgz", + "integrity": "sha512-3kn5Me69L+jv82EKRuQCXdYyf1DqHwD2U/sxoNgBGCB7K9TRc3bQamQ+5EPM9EvyPdli0W41sROd+ZU1dTCztw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0", "@radix-ui/react-use-rect": "1.1.0", @@ -4208,10 +4386,10 @@ } } }, - "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-context": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", - "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -4223,13 +4401,36 @@ } } }, + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-primitive": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", + "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-portal": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.2.tgz", - "integrity": "sha512-WeDYLGPxJb/5EGBoedyJbT0MpoULmwnIPMJMSldkuiMsBAv7N1cRdsTWZWht9vpPOiN3qyiGAtbK2is47/uMFg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.3.tgz", + "integrity": "sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-primitive": "2.0.1", "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { @@ -4247,6 +4448,29 @@ } } }, + "node_modules/@radix-ui/react-portal/node_modules/@radix-ui/react-primitive": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", + "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-presence": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.1.tgz", @@ -4294,19 +4518,37 @@ } } }, - "node_modules/@radix-ui/react-roving-focus": { + "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz", - "integrity": "sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-collection": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.1.tgz", + "integrity": "sha512-QE1RoxPGJ/Nm8Qmk0PxP8ojmoaS67i0s7hVssS7KuI2FQoc/uzVlZsqKfQvxPE6D8hICCPHJ4D88zNhT3OOmkw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-collection": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-primitive": "2.0.1", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-controllable-state": "1.1.0" }, @@ -4319,24 +4561,79 @@ "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-collection": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.1.tgz", + "integrity": "sha512-LwT3pSho9Dljg+wY2KN2mrrh6y3qELfftINERIzBUO9e0N+t0oMTyn3k9iv+ZqgrwGkRnLpNJrsMv9BZlt2yuA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-slot": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true } } }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-context": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", - "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-primitive": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", + "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.1" + }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, @@ -4371,12 +4668,12 @@ } }, "node_modules/@radix-ui/react-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", - "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz", + "integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0" + "@radix-ui/react-compose-refs": "1.1.1" }, "peerDependencies": { "@types/react": "*", @@ -4388,57 +4685,38 @@ } } }, - "node_modules/@radix-ui/react-toast": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.2.tgz", - "integrity": "sha512-Z6pqSzmAP/bFJoqMAston4eSNa+ud44NSZTiZUmUen+IOZ5nBY8kzuU5WDBVyFXPtcW6yUalOHsxM/BP6Sv8ww==", + "node_modules/@radix-ui/react-slot/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-collection": "1.1.0", - "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.1", - "@radix-ui/react-portal": "1.1.2", - "@radix-ui/react-presence": "1.1.1", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-callback-ref": "1.1.0", - "@radix-ui/react-use-controllable-state": "1.1.0", - "@radix-ui/react-use-layout-effect": "1.1.0", - "@radix-ui/react-visually-hidden": "1.1.0" - }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-tooltip": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.6.tgz", - "integrity": "sha512-TLB5D8QLExS1uDn7+wH/bjEmRurNMTzNrtq7IjaS4kjion9NtzsTGkvR5+i7yc9q01Pi2KMM2cN3f8UG4IvvXA==", + "node_modules/@radix-ui/react-toast": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.4.tgz", + "integrity": "sha512-Sch9idFJHJTMH9YNpxxESqABcAFweJG4tKv+0zo0m5XBvUSL8FM5xKcJLFLXononpePs8IclyX1KieL5SDUNgA==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-collection": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.3", - "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-popper": "1.2.1", "@radix-ui/react-portal": "1.1.3", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.1", - "@radix-ui/react-slot": "1.1.1", + "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", "@radix-ui/react-visually-hidden": "1.1.1" }, "peerDependencies": { @@ -4456,19 +4734,22 @@ } } }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/primitive": { + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/primitive": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", "license": "MIT" }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-arrow": { + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-collection": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.1.tgz", - "integrity": "sha512-NaVpZfmv8SKeZbn4ijN2V3jlHA9ngBG16VnIIm22nUR0Yk8KUALyBxT3KYEUnNuch9sTE8UTsS3whzBgKOL30w==", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.1.tgz", + "integrity": "sha512-LwT3pSho9Dljg+wY2KN2mrrh6y3qELfftINERIzBUO9e0N+t0oMTyn3k9iv+ZqgrwGkRnLpNJrsMv9BZlt2yuA==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.0.1" + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-slot": "1.1.1" }, "peerDependencies": { "@types/react": "*", @@ -4485,7 +4766,7 @@ } } }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-compose-refs": { + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-compose-refs": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", @@ -4500,17 +4781,14 @@ } } }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.3.tgz", - "integrity": "sha512-onrWn/72lQoEucDmJnr8uczSNTujT0vJnA/X5+3AkChVPowr8n1yvIKIabhWyMQeMvvmdpsvcyDqx3X1LEXCPg==", + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-presence": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", + "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", - "@radix-ui/react-primitive": "2.0.1", - "@radix-ui/react-use-callback-ref": "1.1.0", - "@radix-ui/react-use-escape-keydown": "1.1.0" + "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { "@types/react": "*", @@ -4527,22 +4805,13 @@ } } }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-popper": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.1.tgz", - "integrity": "sha512-3kn5Me69L+jv82EKRuQCXdYyf1DqHwD2U/sxoNgBGCB7K9TRc3bQamQ+5EPM9EvyPdli0W41sROd+ZU1dTCztw==", + "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-primitive": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", + "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", "license": "MIT", "dependencies": { - "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.1", - "@radix-ui/react-compose-refs": "1.1.1", - "@radix-ui/react-context": "1.1.1", - "@radix-ui/react-primitive": "2.0.1", - "@radix-ui/react-use-callback-ref": "1.1.0", - "@radix-ui/react-use-layout-effect": "1.1.0", - "@radix-ui/react-use-rect": "1.1.0", - "@radix-ui/react-use-size": "1.1.0", - "@radix-ui/rect": "1.1.0" + "@radix-ui/react-slot": "1.1.1" }, "peerDependencies": { "@types/react": "*", @@ -4559,14 +4828,24 @@ } } }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-portal": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.3.tgz", - "integrity": "sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==", + "node_modules/@radix-ui/react-tooltip": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.6.tgz", + "integrity": "sha512-TLB5D8QLExS1uDn7+wH/bjEmRurNMTzNrtq7IjaS4kjion9NtzsTGkvR5+i7yc9q01Pi2KMM2cN3f8UG4IvvXA==", "license": "MIT", "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.3", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.1", + "@radix-ui/react-portal": "1.1.3", + "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.1", - "@radix-ui/react-use-layout-effect": "1.1.0" + "@radix-ui/react-slot": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.1" }, "peerDependencies": { "@types/react": "*", @@ -4583,6 +4862,27 @@ } } }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-presence": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", @@ -4630,47 +4930,6 @@ } } }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz", - "integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-visually-hidden": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.1.tgz", - "integrity": "sha512-vVfA2IZ9q/J+gEamvj761Oq1FpWgCDaNOOIfbPVp2MVPLEomUr5+Vf7kJGwQ24YxZSlQVar7Bes8kyTo5Dshpg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.0.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", @@ -4774,12 +5033,35 @@ } }, "node_modules/@radix-ui/react-visually-hidden": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.0.tgz", - "integrity": "sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.1.tgz", + "integrity": "sha512-vVfA2IZ9q/J+gEamvj761Oq1FpWgCDaNOOIfbPVp2MVPLEomUr5+Vf7kJGwQ24YxZSlQVar7Bes8kyTo5Dshpg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-primitive": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz", + "integrity": "sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.0.0" + "@radix-ui/react-slot": "1.1.1" }, "peerDependencies": { "@types/react": "*", @@ -5199,50 +5481,50 @@ ] }, "node_modules/@sentry-internal/browser-utils": { - "version": "8.45.1", - "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.45.1.tgz", - "integrity": "sha512-sZwtP3zAzDsjUS7WkMW5VGbvSl7hGKTMc8gAJbpEsrybMxllIP13zzMRwpeFF11RnnvbrZ/FtAeX58Mvj0jahA==", + "version": "8.47.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.47.0.tgz", + "integrity": "sha512-vOXzYzHTKkahTLDzWWIA4EiVCQ+Gk+7xGWUlNcR2ZiEPBqYZVb5MjsUozAcc7syrSUy6WicyFjcomZ3rlCVQhg==", "license": "MIT", "dependencies": { - "@sentry/core": "8.45.1" + "@sentry/core": "8.47.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/feedback": { - "version": "8.45.1", - "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.45.1.tgz", - "integrity": "sha512-zCKptzki4SLnG+s8je8dgnppOKFjiiO4GVBc4fh7uL8zjNPBnxW8wK4SrPfAEKVYaHUzkKc5vixwUqcpmfLLGw==", + "version": "8.47.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.47.0.tgz", + "integrity": "sha512-IAiIemTQIalxAOYhUENs9bZ8pMNgJnX3uQSuY7v0gknEqClOGpGkG04X/cxCmtJUj1acZ9ShTGDxoh55a+ggAQ==", "license": "MIT", "dependencies": { - "@sentry/core": "8.45.1" + "@sentry/core": "8.47.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/replay": { - "version": "8.45.1", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.45.1.tgz", - "integrity": "sha512-cOA9CodNSR9+hmICDaGIDUvWiwxQxeMHk/esbjB8uAW8HG4CYTG3CTYTZmlmou7DuysfMd4JNuFmDFBj+YU5/A==", + "version": "8.47.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.47.0.tgz", + "integrity": "sha512-G/S40ZBORj0HSMLw/uVC6YDEPN/dqVk901vf4VYfml686DEhJrZesfAfp5SydJumQ0NKZQrdtvny+BWnlI5H1w==", "license": "MIT", "dependencies": { - "@sentry-internal/browser-utils": "8.45.1", - "@sentry/core": "8.45.1" + "@sentry-internal/browser-utils": "8.47.0", + "@sentry/core": "8.47.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/replay-canvas": { - "version": "8.45.1", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.45.1.tgz", - "integrity": "sha512-qiPg6XwOwkiMMe/8Qf3EhXCqkSlSnWLlorYngIbdkV2klbWjd7vKnqkFJF4PnaS0g7kkZr7nh+MdzpyLyuj2Mw==", + "version": "8.47.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.47.0.tgz", + "integrity": "sha512-M4W9UGouEeELbGbP3QsXLDVtGiQSZoWJlKwqMWyqdQgZuLoKw0S33+60t6teLVMhuQZR0UI9VJTF5coiXysnnA==", "license": "MIT", "dependencies": { - "@sentry-internal/replay": "8.45.1", - "@sentry/core": "8.45.1" + "@sentry-internal/replay": "8.47.0", + "@sentry/core": "8.47.0" }, "engines": { "node": ">=14.18" @@ -5301,25 +5583,25 @@ } }, "node_modules/@sentry/browser": { - "version": "8.45.1", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.45.1.tgz", - "integrity": "sha512-/KvYhQSRg8m9kotG8h9FrfXCWRlebrvdfXKjj1oE9SyZ2LmR8Ze9AcEw1qzsBsa1F1D/a5FQbUJahSoLBkaQPA==", + "version": "8.47.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.47.0.tgz", + "integrity": "sha512-K6BzHisykmbFy/wORtGyfsAlw7ShevLALzu3ReZZZ18dVubO1bjSNjkZQU9MJD5Jcb9oLwkq89n3N9XIBfvdRA==", "license": "MIT", "dependencies": { - "@sentry-internal/browser-utils": "8.45.1", - "@sentry-internal/feedback": "8.45.1", - "@sentry-internal/replay": "8.45.1", - "@sentry-internal/replay-canvas": "8.45.1", - "@sentry/core": "8.45.1" + "@sentry-internal/browser-utils": "8.47.0", + "@sentry-internal/feedback": "8.47.0", + "@sentry-internal/replay": "8.47.0", + "@sentry-internal/replay-canvas": "8.47.0", + "@sentry/core": "8.47.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry/core": { - "version": "8.45.1", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.45.1.tgz", - "integrity": "sha512-1fGmkr0paZshh38mD29c4CfkRkgFoYDaAGyDLoGYfTbEph/lU8RHB2HWzN93McqNdMEhl1DRRyqIasUZoPlqSA==", + "version": "8.47.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.47.0.tgz", + "integrity": "sha512-iSEJZMe3DOcqBFZQAqgA3NB2lCWBc4Gv5x/SCri/TVg96wAlss4VrUunSI2Mp0J4jJ5nJcJ2ChqHSBAU48k3FA==", "license": "MIT", "engines": { "node": ">=14.18" @@ -5730,9 +6012,9 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.62.7", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.62.7.tgz", - "integrity": "sha512-fgpfmwatsrUal6V+8EC2cxZIQVl9xvL7qYa03gsdsCy985UTUlS4N+/3hCzwR0PclYDqisca2AqR1BVgJGpUDA==", + "version": "5.62.8", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.62.8.tgz", + "integrity": "sha512-4fV31vDsUyvNGrKIOUNPrZztoyL187bThnoQOvAXEVlZbSiuPONpfx53634MKKdvsDir5NyOGm80ShFaoHS/mw==", "license": "MIT", "funding": { "type": "github", @@ -5750,12 +6032,12 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.62.7", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.62.7.tgz", - "integrity": "sha512-+xCtP4UAFDTlRTYyEjLx0sRtWyr5GIk7TZjZwBu4YaNahi3Rt2oMyRqfpfVrtwsqY2sayP4iXVCwmC+ZqqFmuw==", + "version": "5.62.8", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.62.8.tgz", + "integrity": "sha512-8TUstKxF/fysHonZsWg/hnlDVgasTdHx6Q+f1/s/oPKJBJbKUWPZEHwLTMOZgrZuroLMiqYKJ9w69Abm8mWP0Q==", "license": "MIT", "dependencies": { - "@tanstack/query-core": "5.62.7" + "@tanstack/query-core": "5.62.8" }, "funding": { "type": "github", @@ -5992,9 +6274,9 @@ } }, "node_modules/@types/dom-webcodecs": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/@types/dom-webcodecs/-/dom-webcodecs-0.1.13.tgz", - "integrity": "sha512-O5hkiFIcjjszPIYyUSyvScyvrBoV3NOEEZx/pMlsu44TKzWNkLVBBxnxJz42in5n3QIolYOcBYFCPZZ0h8SkwQ==", + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/@types/dom-webcodecs/-/dom-webcodecs-0.1.11.tgz", + "integrity": "sha512-yPEZ3z7EohrmOxbk/QTAa0yonMFkNkjnVXqbGb7D4rMr+F1dGQ8ZUFxXkyLLJuiICPejZ0AZE9Rrk9wUCczx4A==", "license": "MIT" }, "node_modules/@types/dompurify": { @@ -6701,25 +6983,27 @@ "peer": true }, "node_modules/@yudiel/react-qr-scanner": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@yudiel/react-qr-scanner/-/react-qr-scanner-2.0.8.tgz", - "integrity": "sha512-/7WHsdC1a/Z909J2zZxqgpUQ1iI554fZxIagucH/tFu1MhZkNIeykYI1OdZgDEwV4CzuSi+h90wwNrhmETcmRw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@yudiel/react-qr-scanner/-/react-qr-scanner-2.1.0.tgz", + "integrity": "sha512-O3832Qk8YU+vnLO+tsJalfQcXRZ1pOB9l6WrI3OdwpxkQEzukpT48M6Hc2vUUe1rFE6qapQnV3RGRFNM0S7CHw==", "license": "MIT", "dependencies": { - "barcode-detector": "^2.2.7", + "barcode-detector": "^2.3.1", "webrtc-adapter": "9.0.1" }, "peerDependencies": { - "react": "^17 || ^18", - "react-dom": "^17 || ^18" + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" } }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true, "license": "ISC", - "optional": true + "optional": true, + "peer": true }, "node_modules/acorn": { "version": "8.13.0", @@ -6768,21 +7052,14 @@ "node": ">=0.4.0" } }, - "node_modules/adler-32": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", - "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", - "license": "Apache-2.0", - "engines": { - "node": ">=0.8" - } - }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "debug": "4" }, @@ -6921,8 +7198,10 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true, "license": "ISC", - "optional": true + "optional": true, + "peer": true }, "node_modules/arch": { "version": "2.2.0", @@ -6949,8 +7228,10 @@ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", "deprecated": "This package is no longer supported.", + "dev": true, "license": "ISC", "optional": true, + "peer": true, "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -7336,13 +7617,13 @@ "license": "MIT" }, "node_modules/barcode-detector": { - "version": "2.2.11", - "resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-2.2.11.tgz", - "integrity": "sha512-N50XZ6Rav2sxTgHXOc38/mkpVJMan11GZ8Yqi1pPMZpTJSXuZ/FpIee6OtLehZX/Vs4ZOzGbp1DgXzFCfKggWA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-2.3.1.tgz", + "integrity": "sha512-D9KEtrquS1tmBZduxBZl8qublIKnRrFqD8TAHDYcLCyrHQBo+vitIxmjMJ61LvXjXyAMalOlO7q0Oh/9Rl2PbQ==", "license": "MIT", "dependencies": { - "@types/dom-webcodecs": "^0.1.13", - "zxing-wasm": "1.2.14" + "@types/dom-webcodecs": "0.1.11", + "zxing-wasm": "1.3.4" } }, "node_modules/base64-js": { @@ -7386,6 +7667,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "optional": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "node_modules/blob-util": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", @@ -7610,9 +7903,11 @@ "version": "2.11.2", "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "@mapbox/node-pre-gyp": "^1.0.0", "nan": "^2.17.0", @@ -7639,19 +7934,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/cfb": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", - "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", - "license": "Apache-2.0", - "dependencies": { - "adler-32": "~1.3.0", - "crc-32": "~1.2.0" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -7773,8 +8055,10 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, "license": "ISC", "optional": true, + "peer": true, "engines": { "node": ">=10" } @@ -7917,15 +8201,6 @@ "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, - "node_modules/codepage": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", - "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", - "license": "Apache-2.0", - "engines": { - "node": ">=0.8" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -7948,8 +8223,10 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, "license": "ISC", "optional": true, + "peer": true, "bin": { "color-support": "bin.js" } @@ -7994,7 +8271,7 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/concat-stream": { @@ -8017,8 +8294,10 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true, "license": "ISC", - "optional": true + "optional": true, + "peer": true }, "node_modules/console.table": { "version": "0.10.0", @@ -8105,18 +8384,6 @@ } } }, - "node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "license": "Apache-2.0", - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -8519,6 +8786,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -8604,8 +8881,10 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/dependency-tree": { "version": "11.0.1", @@ -9853,6 +10132,16 @@ "node": ">=4" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "license": "(MIT OR WTFPL)", + "optional": true, + "engines": { + "node": ">=6" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -10275,15 +10564,6 @@ "node": ">= 6" } }, - "node_modules/frac": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", - "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", - "license": "Apache-2.0", - "engines": { - "node": ">=0.8" - } - }, "node_modules/fraction.js": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", @@ -10298,6 +10578,13 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT", + "optional": true + }, "node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -10317,8 +10604,10 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, "license": "ISC", "optional": true, + "peer": true, "dependencies": { "minipass": "^3.0.0" }, @@ -10330,8 +10619,10 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, "license": "ISC", "optional": true, + "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -10343,14 +10634,16 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, "license": "ISC", - "optional": true + "optional": true, + "peer": true }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/fsevents": { @@ -10410,8 +10703,10 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", "deprecated": "This package is no longer supported.", + "dev": true, "license": "ISC", "optional": true, + "peer": true, "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.2", @@ -10563,6 +10858,13 @@ "assert-plus": "^1.0.0" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "license": "MIT", + "optional": true + }, "node_modules/glob": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", @@ -10826,8 +11128,10 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true, "license": "ISC", - "optional": true + "optional": true, + "peer": true }, "node_modules/hasown": { "version": "2.0.2", @@ -10947,8 +11251,10 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "agent-base": "6", "debug": "4" @@ -11138,7 +11444,7 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -13002,8 +13308,10 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "semver": "^6.0.0" }, @@ -13018,8 +13326,10 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "optional": true, + "peer": true, "bin": { "semver": "bin/semver.js" } @@ -14656,8 +14966,10 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -14670,8 +14982,10 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, "license": "ISC", "optional": true, + "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -14683,15 +14997,19 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, "license": "ISC", - "optional": true + "optional": true, + "peer": true }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, "license": "MIT", "optional": true, + "peer": true, "bin": { "mkdirp": "bin/cmd.js" }, @@ -14699,6 +15017,13 @@ "node": ">=10" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "license": "MIT", + "optional": true + }, "node_modules/module-definition": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/module-definition/-/module-definition-6.0.0.tgz", @@ -14822,8 +15147,10 @@ "version": "2.22.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.0.tgz", "integrity": "sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==", + "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/nanoid": { "version": "3.3.8", @@ -14843,6 +15170,13 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "license": "MIT", + "optional": true + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -14858,6 +15192,26 @@ "optional": true, "peer": true }, + "node_modules/node-abi": { + "version": "3.71.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.71.0.tgz", + "integrity": "sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw==", + "license": "MIT", + "optional": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT", + "optional": true + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -14901,8 +15255,10 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, "license": "ISC", "optional": true, + "peer": true, "dependencies": { "abbrev": "1" }, @@ -15019,8 +15375,10 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", "deprecated": "This package is no longer supported.", + "dev": true, "license": "ISC", "optional": true, + "peer": true, "dependencies": { "are-we-there-yet": "^2.0.0", "console-control-strings": "^1.1.0", @@ -15340,7 +15698,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -15399,9 +15757,9 @@ } }, "node_modules/path2d": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/path2d/-/path2d-0.2.1.tgz", - "integrity": "sha512-Fl2z/BHvkTNvkuBzYTpTuirHZg6wW9z8+4SND/3mDTEcYbbNKWAy21dz9D3ePNNwrrK8pqZO5vLPZ1hLF6T7XA==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/path2d/-/path2d-0.2.2.tgz", + "integrity": "sha512-+vnG6S4dYcYxZd+CZxzXCNKdELYZSKfohrk98yajCo1PtRoDgCTrrwOvK1GT0UoAdVszagDVllQc0U1vaX4NUQ==", "license": "MIT", "optional": true, "engines": { @@ -15420,16 +15778,32 @@ } }, "node_modules/pdfjs-dist": { - "version": "4.4.168", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-4.4.168.tgz", - "integrity": "sha512-MbkAjpwka/dMHaCfQ75RY1FXX3IewBVu6NGZOcxerRFlaBiIkZmUoR0jotX5VUzYZEXAGzSFtknWs5xRKliXPA==", + "version": "4.8.69", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-4.8.69.tgz", + "integrity": "sha512-IHZsA4T7YElCKNNXtiLgqScw4zPd3pG9do8UrznC757gMd7UPeHSL2qwNNMJo4r79fl8oj1Xx+1nh2YkzdMpLQ==", "license": "Apache-2.0", "engines": { "node": ">=18" }, "optionalDependencies": { - "canvas": "^2.11.2", - "path2d": "^0.2.0" + "canvas": "^3.0.0-rc2", + "path2d": "^0.2.1" + } + }, + "node_modules/pdfjs-dist/node_modules/canvas": { + "version": "3.0.0-rc3", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-3.0.0-rc3.tgz", + "integrity": "sha512-LJVkMp4AH7/IRoLvhLS6R09uBt9O3O0mhCYL34AQV/+OC39jmTv22pJTF5Mgfa3V2JnzGl21MVrhEKmtmPtfQA==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-addon-api": "^7.0.0", + "prebuild-install": "^7.1.1", + "simple-get": "^3.0.3" + }, + "engines": { + "node": "^18.12.0 || >= 20.9.0" } }, "node_modules/pend": { @@ -15760,6 +16134,88 @@ "postcss": "^8.2.9" } }, + "node_modules/prebuild-install": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", + "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prebuild-install/node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prebuild-install/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prebuild-install/node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/precinct": { "version": "12.1.2", "resolved": "https://registry.npmjs.org/precinct/-/precinct-12.1.2.tgz", @@ -16107,6 +16563,39 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "optional": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC", + "optional": true + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -16172,9 +16661,9 @@ } }, "node_modules/react-i18next": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.1.3.tgz", - "integrity": "sha512-J11oA30FbM3NZegUZjn8ySK903z6PLBz/ZuBYyT1JMR0QPrW6PFXvl1WoUhortdGi9dM0m48/zJQlPskVZXgVw==", + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.2.0.tgz", + "integrity": "sha512-iJNc8111EaDtVTVMKigvBtPHyrJV+KblWG73cUxqp+WmJCcwkzhWNFXmkAD5pwP2Z4woeDj/oXDdbjDsb3Gutg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.25.0", @@ -16221,9 +16710,9 @@ "license": "MIT" }, "node_modules/react-pdf": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-9.1.1.tgz", - "integrity": "sha512-Cn3RTJZMqVOOCgLMRXDamLk4LPGfyB2Np3OwQAUjmHIh47EpuGW1OpAA1Z1GVDLoHx4d5duEDo/YbUkDbr4QFQ==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-9.2.1.tgz", + "integrity": "sha512-AJt0lAIkItWEZRA5d/mO+Om4nPCuTiQ0saA+qItO967DTjmGjnhmF+Bi2tL286mOTfBlF5CyLzJ35KTMaDoH+A==", "license": "MIT", "dependencies": { "clsx": "^2.0.0", @@ -16231,7 +16720,7 @@ "make-cancellable-promise": "^1.3.1", "make-event-props": "^1.6.0", "merge-refs": "^1.3.0", - "pdfjs-dist": "4.4.168", + "pdfjs-dist": "4.8.69", "tiny-invariant": "^1.0.0", "warning": "^4.0.0" }, @@ -16273,23 +16762,23 @@ } }, "node_modules/react-remove-scroll": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.0.tgz", - "integrity": "sha512-I2U4JVEsQenxDAKaVa3VZ/JeJZe0/2DxPWL8Tj8yLKctQJQiZM52pn/GWFpSp8dftjM3pSAHVJZscAnC/y+ySQ==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.2.tgz", + "integrity": "sha512-KmONPx5fnlXYJQqC62Q+lwIeAk64ws/cUw6omIumRzMRPqgnYqhSSti99nbj0Ry13bv7dF+BKn7NB+OqkdZGTw==", "license": "MIT", "dependencies": { - "react-remove-scroll-bar": "^2.3.6", + "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.1", "tslib": "^2.1.0", - "use-callback-ref": "^1.3.0", + "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.2" }, "engines": { "node": ">=10" }, "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { @@ -16953,7 +17442,7 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -16969,7 +17458,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -16981,7 +17470,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -17002,7 +17491,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -17316,8 +17805,10 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, "license": "ISC", - "optional": true + "optional": true, + "peer": true }, "node_modules/set-function-length": { "version": "1.2.2", @@ -17668,18 +18159,6 @@ "dev": true, "license": "BSD-3-Clause" }, - "node_modules/ssf": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", - "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", - "license": "Apache-2.0", - "dependencies": { - "frac": "~1.1.2" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/sshpk": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", @@ -18236,8 +18715,10 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, "license": "ISC", "optional": true, + "peer": true, "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -18250,12 +18731,51 @@ "node": ">=10" } }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "license": "MIT", + "optional": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-fs/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC", + "optional": true + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/tar/node_modules/minipass": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, "license": "ISC", "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -18264,8 +18784,10 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, "license": "ISC", - "optional": true + "optional": true, + "peer": true }, "node_modules/temp-dir": { "version": "2.0.0", @@ -20644,30 +21166,14 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, "license": "ISC", "optional": true, + "peer": true, "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } }, - "node_modules/wmf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", - "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", - "license": "Apache-2.0", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/word": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", - "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", - "license": "Apache-2.0", - "engines": { - "node": ">=0.8" - } - }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -21244,19 +21750,10 @@ } }, "node_modules/xlsx": { - "version": "0.18.5", - "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", - "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "version": "0.20.3", + "resolved": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz", + "integrity": "sha512-oLDq3jw7AcLqKWH2AhCpVTZl8mf6X2YReP+Neh0SJUzV/BdZYjth94tG5toiMB1PPrYtxOCfaoUCkvtuH+3AJA==", "license": "Apache-2.0", - "dependencies": { - "adler-32": "~1.3.0", - "cfb": "~1.2.1", - "codepage": "~1.15.0", - "crc-32": "~1.2.1", - "ssf": "~0.11.2", - "wmf": "~1.0.1", - "word": "~0.3.0" - }, "bin": { "xlsx": "bin/xlsx.njs" }, @@ -21361,9 +21858,9 @@ } }, "node_modules/zxing-wasm": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/zxing-wasm/-/zxing-wasm-1.2.14.tgz", - "integrity": "sha512-UaYfzSmFPIEmYDt/KyPvs/H02t8jO470BBFHUIlvtmloAm8f2zdAmOL93iWYQ5QYfSnTyFPg0yzZwznlBjfg4A==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/zxing-wasm/-/zxing-wasm-1.3.4.tgz", + "integrity": "sha512-9l0QymyATF19FmI92QHe7Dayb+BUN7P7zFAt5iDgTnUf0dFWokz6GVA/W9EepjW5q8s3e89fIE/7uxpX27yqEQ==", "license": "MIT", "dependencies": { "@types/emscripten": "^1.39.13" diff --git a/package.json b/package.json index fb8510950b7..b768b4893aa 100644 --- a/package.json +++ b/package.json @@ -59,18 +59,18 @@ "@pnotify/core": "^5.2.0", "@pnotify/mobile": "^5.2.0", "@radix-ui/react-dialog": "^1.1.4", - "@radix-ui/react-dropdown-menu": "^2.1.2", + "@radix-ui/react-dropdown-menu": "^2.1.4", "@radix-ui/react-icons": "^1.3.2", - "@radix-ui/react-label": "^2.1.0", - "@radix-ui/react-popover": "^1.1.2", + "@radix-ui/react-label": "^2.1.1", + "@radix-ui/react-popover": "^1.1.4", "@radix-ui/react-scroll-area": "^1.2.0", - "@radix-ui/react-slot": "^1.1.0", - "@radix-ui/react-toast": "^1.2.2", + "@radix-ui/react-slot": "^1.1.1", + "@radix-ui/react-toast": "^1.2.4", "@radix-ui/react-tooltip": "^1.1.6", - "@sentry/browser": "^8.45.1", - "@tanstack/react-query": "^5.62.3", + "@sentry/browser": "^8.47.0", + "@tanstack/react-query": "^5.62.8", "@tanstack/react-query-devtools": "^5.62.7", - "@yudiel/react-qr-scanner": "^2.0.8", + "@yudiel/react-qr-scanner": "^2.1.0", "bowser": "^2.11.0", "browser-image-compression": "^2.0.2", "browserslist": "^4.24.3", @@ -95,14 +95,14 @@ "react-copy-to-clipboard": "^5.1.0", "react-dom": "18.3.1", "react-google-recaptcha": "^3.1.0", - "react-i18next": "^15.1.3", + "react-i18next": "^15.2.0", "react-infinite-scroll-component": "^6.1.0", - "react-pdf": "^9.1.1", + "react-pdf": "^9.2.1", "react-webcam": "^7.2.0", "tailwind-merge": "^2.5.5", "tailwindcss-animate": "^1.0.7", "use-keyboard-shortcut": "^1.1.6", - "xlsx": "^0.18.5" + "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz" }, "devDependencies": { "@julr/vite-plugin-validate-env": "^1.1.1", diff --git a/public/locale/en.json b/public/locale/en.json index b9d5c60539c..758ef1965db 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -1046,6 +1046,7 @@ "notification_cancelled": "Notification cancelled", "notification_permission_denied": "Notification permission denied", "notification_permission_granted": "Notification permission granted", + "notify": "Notify", "number_of_aged_dependents": "Number of Aged Dependents (Above 60)", "number_of_beds": "Number of beds", "number_of_beds_out_of_range_error": "Number of beds cannot be greater than 100", @@ -1539,9 +1540,10 @@ "view_all_details": "View All Details", "view_asset": "View Assets", "view_cns": "View CNS", + "view_consultation": "View Latest Encounter", "view_consultation_and_log_updates": "View Consultation / Log Updates", "view_details": "View Details", - "view_faciliy": "View Facility", + "view_facility": "View Facility", "view_files": "View Files", "view_patients": "View Patients", "view_update_patient_files": "View/Update patient files", diff --git a/public/locale/hi.json b/public/locale/hi.json index 568ce0499f6..8816f1f2336 100644 --- a/public/locale/hi.json +++ b/public/locale/hi.json @@ -795,7 +795,7 @@ "view_abdm_records": "ABDM रिकॉर्ड देखें", "view_asset": "संपत्तियां देखें", "view_details": "विवरण देखें", - "view_faciliy": "सुविधा देखें", + "view_facility": "सुविधा देखें", "view_patients": "मरीज़ देखें", "view_users": "उपयोगकर्ता देखें", "virtual_nursing_assistant": "वर्चुअल नर्सिंग सहायक", diff --git a/public/locale/kn.json b/public/locale/kn.json index 4907cdd2d8c..65ced04bd3f 100644 --- a/public/locale/kn.json +++ b/public/locale/kn.json @@ -796,7 +796,7 @@ "view_abdm_records": "ABDM ದಾಖಲೆಗಳನ್ನು ವೀಕ್ಷಿಸಿ", "view_asset": "ಸ್ವತ್ತುಗಳನ್ನು ವೀಕ್ಷಿಸಿ", "view_details": "ವಿವರಗಳನ್ನು ವೀಕ್ಷಿಸಿ", - "view_faciliy": "ವೀಕ್ಷಣೆ ಸೌಲಭ್ಯ", + "view_facility": "ವೀಕ್ಷಣೆ ಸೌಲಭ್ಯ", "view_patients": "ರೋಗಿಗಳನ್ನು ವೀಕ್ಷಿಸಿ", "view_users": "ಬಳಕೆದಾರರನ್ನು ವೀಕ್ಷಿಸಿ", "virtual_nursing_assistant": "ವರ್ಚುವಲ್ ನರ್ಸಿಂಗ್ ಸಹಾಯಕ", diff --git a/public/locale/ml.json b/public/locale/ml.json index b875a64dd02..c69f4940657 100644 --- a/public/locale/ml.json +++ b/public/locale/ml.json @@ -796,7 +796,7 @@ "view_abdm_records": "ABDM റെക്കോർഡുകൾ കാണുക", "view_asset": "അസറ്റുകൾ കാണുക", "view_details": "വിശദാംശങ്ങൾ കാണുക", - "view_faciliy": "സൗകര്യം കാണുക", + "view_facility": "സൗകര്യം കാണുക", "view_patients": "രോഗികളെ കാണുക", "view_users": "ഉപയോക്താക്കളെ കാണുക", "virtual_nursing_assistant": "വെർച്വൽ നഴ്സിംഗ് അസിസ്റ്റൻ്റ്", diff --git a/public/locale/ta.json b/public/locale/ta.json index cfe12b5fa6a..8c84339177e 100644 --- a/public/locale/ta.json +++ b/public/locale/ta.json @@ -795,7 +795,7 @@ "view_abdm_records": "ABDM பதிவுகளைப் பார்க்கவும்", "view_asset": "சொத்துக்களைப் பார்க்கவும்", "view_details": "விவரங்களைக் காண்க", - "view_faciliy": "பார்வை வசதி", + "view_facility": "பார்வை வசதி", "view_patients": "நோயாளிகளைப் பார்க்கவும்", "view_users": "பயனர்களைக் காண்க", "virtual_nursing_assistant": "மெய்நிகர் நர்சிங் உதவியாளர்", 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/Assets/AssetWarrantyCard.tsx b/src/components/Assets/AssetWarrantyCard.tsx index ebaaca7e6c8..9f37394957a 100644 --- a/src/components/Assets/AssetWarrantyCard.tsx +++ b/src/components/Assets/AssetWarrantyCard.tsx @@ -31,7 +31,7 @@ export default function AssetWarrantyCard(props: { asset: AssetData }) { }, [isCopied]); return ( -
+
{asset.manufacturer}
@@ -78,7 +78,10 @@ export default function AssetWarrantyCard(props: { asset: AssetData }) { ["Phone", asset.support_phone, "l-phone"], ["Email", asset.support_email, "l-envelope"], ].map((item) => ( -
+
{item[1] && ( <>
diff --git a/src/components/Common/AuthorizedButton.tsx b/src/components/Common/AuthorizedButton.tsx new file mode 100644 index 00000000000..2b611a0c9f2 --- /dev/null +++ b/src/components/Common/AuthorizedButton.tsx @@ -0,0 +1,19 @@ +import { Button, ButtonProps } from "@headlessui/react"; + +import AuthorizedChild from "@/CAREUI/misc/AuthorizedChild"; + +import { AuthorizedElementProps } from "@/Utils/AuthorizeFor"; + +export const AuthorizedButton: React.FC< + AuthorizedElementProps & ButtonProps +> = ({ authorizeFor = () => true, ...props }) => { + return ( + + {({ isAuthorized }) => ( + + )} + + ); +}; 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/Common/DateInputV2.tsx b/src/components/Common/DateInputV2.tsx index 8debee7ac7b..26c6a702c50 100644 --- a/src/components/Common/DateInputV2.tsx +++ b/src/components/Common/DateInputV2.tsx @@ -348,7 +348,7 @@ const DateInputV2: React.FC = ({ const right = popOverX > viewportWidth - (allowTime ? 420 : 300); const top = popOverY > viewportHeight - 400; - return `${right ? "md:-translate-x-1/2" : ""} ${top ? "md:-translate-y-[calc(100%+50px)]" : ""}`; + return `${right ? "sm:-translate-x-1/2" : ""} ${top ? "md:-translate-y-[calc(100%+50px)]" : ""} ${right ? "max-sm:-translate-x-1/2" : ""} ${top ? "max-sm:-translate-y-[calc(100%+50px)]" : ""}`.trim(); }; const domValue = useValueInjectionObserver({ diff --git a/src/components/Facility/ConsultationCard.tsx b/src/components/Facility/ConsultationCard.tsx index a2ede9f2667..d67926a3c6b 100644 --- a/src/components/Facility/ConsultationCard.tsx +++ b/src/components/Facility/ConsultationCard.tsx @@ -30,6 +30,7 @@ export const ConsultationCard = (props: ConsultationProps) => { : !itemData.current_bed ? t("assign_bed") : t("switch_bed"); + return ( <> { )}
- -
- {dayjs(itemData.created_date).format("DD/MM/YYYY")} +
+
+ +
+ {dayjs(itemData.created_date).format("DD/MM/YYYY")} +
+
+ + {/* Patient Status Section */} +
+
+ {t("patient_status")} +
+ +
{itemData.is_kasp && ( diff --git a/src/components/Facility/ConsultationDoctorNotes/index.tsx b/src/components/Facility/ConsultationDoctorNotes/index.tsx index c1f3dc43072..00ca268a569 100644 --- a/src/components/Facility/ConsultationDoctorNotes/index.tsx +++ b/src/components/Facility/ConsultationDoctorNotes/index.tsx @@ -1,5 +1,6 @@ +import { useQuery } from "@tanstack/react-query"; import { t } from "i18next"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import useKeyboardShortcut from "use-keyboard-shortcut"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -13,6 +14,7 @@ import { PatientNoteStateType, } from "@/components/Facility/models"; import AutoExpandingTextInputFormField from "@/components/Form/FormFields/AutoExpandingTextInputFormField"; +import { useAddPatientNote } from "@/components/Patient/Utils"; import useAuthUser from "@/hooks/useAuthUser"; import { useMessageListener } from "@/hooks/useMessageListener"; @@ -22,8 +24,7 @@ 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 useTanStackQueryInstead from "@/Utils/request/useQuery"; +import query from "@/Utils/request/query"; import { classNames, isAppleDevice, keysOf } from "@/Utils/utils"; interface ConsultationDoctorNotesProps { @@ -54,53 +55,47 @@ const ConsultationDoctorNotes = (props: ConsultationDoctorNotesProps) => { const initialData: PatientNoteStateType = { notes: [], - cPage: 1, - totalPages: 1, facilityId: facilityId, patientId: patientId, }; const [state, setState] = useState(initialData); - const onAddNote = async () => { + const { mutate: addNote } = useAddPatientNote({ + patientId, + thread, + consultationId, + }); + + const onAddNote = () => { if (!/\S+/.test(noteField)) { Notification.Error({ msg: "Note Should Contain At Least 1 Character", }); return; } - - const { res } = await request(routes.addPatientNote, { - pathParams: { - patientId: patientId, - }, - body: { - note: noteField, - thread, - consultation: consultationId, - reply_to: reply_to?.id, - }, + setReplyTo(undefined); + setNoteField(""); + addNote({ + note: noteField, + reply_to: reply_to?.id, + thread, + consultation: consultationId, }); - - if (res?.status === 201) { - Notification.Success({ msg: "Note added successfully" }); - setState({ ...state, cPage: 1 }); - setNoteField(""); - setReload(true); - setReplyTo(undefined); - } }; - useTanStackQueryInstead(routes.getPatient, { - pathParams: { id: patientId }, - onResponse: ({ data }) => { - if (data) { - setPatientActive(data.is_active ?? true); - setPatientName(data.name ?? ""); - setFacilityName(data.facility_object?.name ?? ""); - } - }, + const { data } = useQuery({ + queryKey: ["patient", patientId], + queryFn: query(routes.getPatient, { + pathParams: { patientId }, + }), }); + useEffect(() => { + setPatientActive(data?.is_active ?? true); + setPatientName(data?.name ?? ""); + setFacilityName(data?.facility_object?.name ?? ""); + }, [data]); + useMessageListener((data) => { const message = data?.message; if ( @@ -147,13 +142,21 @@ const ConsultationDoctorNotes = (props: ConsultationDoctorNotesProps) => { ? "border-primary-500 font-bold text-secondary-800" : "border-secondary-300 text-secondary-800", )} - onClick={() => setThread(PATIENT_NOTES_THREADS[current])} + onClick={() => { + if (thread !== PATIENT_NOTES_THREADS[current]) { + setThread(PATIENT_NOTES_THREADS[current]); + setState(initialData); + setReplyTo(undefined); + setNoteField(""); + } + }} > {t(`patient_notes_thread__${current}`)} ))}
void; disableEdit?: boolean; setReplyTo?: (reply_to: PatientNotesModel | undefined) => void; + hasMore: boolean; } const DoctorNote = (props: DoctorNoteProps) => { - const { state, handleNext, setReload, disableEdit, setReplyTo } = props; + const { state, handleNext, setReload, disableEdit, setReplyTo, hasMore } = + props; return (
{ {state.notes.length ? ( diff --git a/src/components/Facility/FacilityCard.tsx b/src/components/Facility/FacilityCard.tsx index 2f6ecec204b..be00a21ece0 100644 --- a/src/components/Facility/FacilityCard.tsx +++ b/src/components/Facility/FacilityCard.tsx @@ -6,10 +6,11 @@ import { useTranslation } from "react-i18next"; import Chip from "@/CAREUI/display/Chip"; import CareIcon from "@/CAREUI/icons/CareIcon"; +import { Button } from "@/components/ui/button"; import { TooltipComponent, TooltipProvider } from "@/components/ui/tooltip"; import { Avatar } from "@/components/Common/Avatar"; -import ButtonV2, { Cancel, Submit } from "@/components/Common/ButtonV2"; +import { Cancel, Submit } from "@/components/Common/ButtonV2"; import DialogModal from "@/components/Common/Dialog"; import { FacilityModel } from "@/components/Facility/models"; import TextAreaFormField from "@/components/Form/FormFields/TextAreaFormField"; @@ -103,6 +104,7 @@ export const FacilityCard = (props: {
- - - {t("view_cns")} - + + + {t("view_cns")} + +
@@ -233,38 +236,81 @@ export const FacilityCard = (props: {
{["DistrictAdmin", "StateAdmin"].includes(userType) && ( - setNotifyModalFor(facility.id)} - > - - Notify - + + + + + )} - - - - {t("view_faciliy")} - - - - - {t("view_patients")} - + + + + + + + + + + {/*
*/}
diff --git a/src/components/Facility/PatientConsultationNotesList.tsx b/src/components/Facility/PatientConsultationNotesList.tsx index 243821b7d6d..adf922ad265 100644 --- a/src/components/Facility/PatientConsultationNotesList.tsx +++ b/src/components/Facility/PatientConsultationNotesList.tsx @@ -1,4 +1,5 @@ -import { Dispatch, SetStateAction, useEffect, useState } from "react"; +import { useInfiniteQuery } from "@tanstack/react-query"; +import { Dispatch, SetStateAction, useEffect } from "react"; import CircularProgress from "@/components/Common/CircularProgress"; import DoctorNote from "@/components/Facility/DoctorNote"; @@ -12,7 +13,7 @@ import useSlug from "@/hooks/useSlug"; import { RESULTS_PER_PAGE_LIMIT } from "@/common/constants"; import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; +import { callApi } from "@/Utils/request/query"; interface PatientNotesProps { state: PatientNoteStateType; @@ -24,80 +25,63 @@ interface PatientNotesProps { setReplyTo?: (value: PatientNotesModel | undefined) => void; } -const pageSize = RESULTS_PER_PAGE_LIMIT; - const PatientConsultationNotesList = (props: PatientNotesProps) => { const { state, setState, - reload, setReload, disableEdit, thread, setReplyTo, + reload, } = props; - const consultationId = useSlug("consultation") ?? ""; - - const [isLoading, setIsLoading] = useState(true); - - const fetchNotes = async () => { - setIsLoading(true); - const { data } = await request(routes.getPatientNotes, { - pathParams: { - patientId: props.state.patientId || "", - }, - query: { - consultation: consultationId, - thread, - offset: (state.cPage - 1) * RESULTS_PER_PAGE_LIMIT, - }, - }); + const consultationId = useSlug("consultation") ?? ""; - if (data) { - if (state.cPage === 1) { - setState((prevState) => ({ - ...prevState, - notes: data.results, - totalPages: Math.ceil(data.count / pageSize), - })); - } else { - setState((prevState) => ({ - ...prevState, - notes: [...prevState.notes, ...data.results], - totalPages: Math.ceil(data.count / pageSize), - })); + const { data, isLoading, fetchNextPage, hasNextPage } = useInfiniteQuery({ + queryKey: ["notes", state.patientId, thread, consultationId], + queryFn: async ({ pageParam = 0, signal }) => { + const response = await callApi(routes.getPatientNotes, { + pathParams: { patientId: state.patientId! }, + queryParams: { + thread, + offset: pageParam, + consultation: consultationId, + }, + signal, + }); + return { + results: response?.results ?? [], + nextPage: pageParam + RESULTS_PER_PAGE_LIMIT, + totalResults: response?.count ?? 0, + }; + }, + getNextPageParam: (lastPage, allPages) => { + const currentResults = allPages.flatMap((page) => page.results).length; + if (currentResults < lastPage.totalResults) { + return lastPage.nextPage; } - } - setIsLoading(false); - setReload?.(false); - }; + return undefined; + }, + initialPageParam: 0, + }); useEffect(() => { - if (reload) { - fetchNotes(); - } - }, [reload]); + if (data?.pages) { + const allNotes = data.pages.flatMap((page) => page.results); - useEffect(() => { - fetchNotes(); - }, [thread]); + const notesMap = new Map(allNotes.map((note) => [note.id, note])); - useEffect(() => { - setReload?.(true); - }, []); + const deduplicatedNotes = Array.from(notesMap.values()); - const handleNext = () => { - if (state.cPage < state.totalPages) { setState((prevState) => ({ ...prevState, - cPage: prevState.cPage + 1, + notes: deduplicatedNotes, })); - setReload?.(true); } - }; + }, [data]); - if (isLoading) { + if (isLoading || reload) { return (
@@ -108,10 +92,11 @@ const PatientConsultationNotesList = (props: PatientNotesProps) => { return ( ); }; diff --git a/src/components/Facility/PatientNoteCard.tsx b/src/components/Facility/PatientNoteCard.tsx index 7896cbada4d..49c8cf4204b 100644 --- a/src/components/Facility/PatientNoteCard.tsx +++ b/src/components/Facility/PatientNoteCard.tsx @@ -1,6 +1,7 @@ +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import dayjs from "dayjs"; import { t } from "i18next"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -19,7 +20,8 @@ import { USER_TYPES_MAP } from "@/common/constants"; import { Error, Success } from "@/Utils/Notifications"; import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; +import mutate from "@/Utils/request/mutate"; +import query from "@/Utils/request/query"; import { classNames, formatDateTime, @@ -29,7 +31,6 @@ import { const PatientNoteCard = ({ note, - setReload, disableEdit, setReplyTo, }: { @@ -44,15 +45,25 @@ const PatientNoteCard = ({ const [showEditHistory, setShowEditHistory] = useState(false); const [editHistory, setEditHistory] = useState([]); const authUser = useAuthUser(); + const queryClient = useQueryClient(); - const fetchEditHistory = async () => { - const { res, data } = await request(routes.getPatientNoteEditHistory, { + const { data, refetch } = useQuery({ + queryKey: [patientId, note.id], + queryFn: query(routes.getPatientNoteEditHistory, { pathParams: { patientId, noteId: note.id }, - }); - if (res?.status === 200) { - setEditHistory(data?.results ?? []); - } - }; + }), + }); + + const { mutate: updateNote } = useMutation({ + mutationFn: mutate(routes.updatePatientNote, { + pathParams: { patientId, noteId: note.id }, + }), + onSuccess: () => { + Success({ msg: "Note updated successfully" }); + queryClient.invalidateQueries({ queryKey: ["notes", patientId] }); + setIsEditing(false); + }, + }); const onUpdateNote = async () => { if (noteField === note.note) { @@ -69,20 +80,15 @@ const PatientNoteCard = ({ return; } - const { res } = await request(routes.updatePatientNote, { - pathParams: { patientId, noteId: note.id }, - body: payload, - }); - if (res?.status === 200) { - Success({ msg: "Note updated successfully" }); - setIsEditing(false); - setReload(true); - } + updateNote(payload); }; + useEffect(() => { + setEditHistory(data?.results ?? []); + }, [data]); + return ( <> - {" "}
{ - fetchEditHistory(); + refetch(); setShowEditHistory(true); }} > @@ -207,7 +213,9 @@ const PatientNoteCard = ({
) : ( -
{noteField}
+
+ {noteField} +
)}
} diff --git a/src/components/Facility/PatientNotesList.tsx b/src/components/Facility/PatientNotesList.tsx index 8db68395744..d4de60512d1 100644 --- a/src/components/Facility/PatientNotesList.tsx +++ b/src/components/Facility/PatientNotesList.tsx @@ -1,4 +1,5 @@ -import { useEffect, useState } from "react"; +import { useInfiniteQuery } from "@tanstack/react-query"; +import { useEffect } from "react"; import CircularProgress from "@/components/Common/CircularProgress"; import DoctorNote from "@/components/Facility/DoctorNote"; @@ -10,7 +11,7 @@ import { import { RESULTS_PER_PAGE_LIMIT } from "@/common/constants"; import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; +import { callApi } from "@/Utils/request/query"; interface PatientNotesProps { state: PatientNoteStateType; @@ -23,57 +24,51 @@ interface PatientNotesProps { setReplyTo?: (reply_to: PatientNotesModel | undefined) => void; } -const pageSize = RESULTS_PER_PAGE_LIMIT; - const PatientNotesList = (props: PatientNotesProps) => { - const { state, setState, reload, setReload, thread, setReplyTo } = props; - - const [isLoading, setIsLoading] = useState(true); + const { state, setState, thread, setReplyTo, setReload, patientId, reload } = + props; - const fetchNotes = async () => { - setIsLoading(true); - const { data }: any = await request(routes.getPatientNotes, { - pathParams: { patientId: props.patientId }, - query: { - offset: (state.cPage - 1) * RESULTS_PER_PAGE_LIMIT, - thread, - }, - }); + const { data, isLoading, fetchNextPage, hasNextPage } = useInfiniteQuery({ + queryKey: ["notes", patientId, thread], + queryFn: async ({ pageParam = 0, signal }) => { + const response = await callApi(routes.getPatientNotes, { + pathParams: { patientId }, + queryParams: { thread, offset: pageParam }, + signal, + }); - if (state.cPage === 1) { - setState((prevState: any) => ({ - ...prevState, - notes: data.results, - totalPages: Math.ceil(data.count / pageSize), - })); - } else { - setState((prevState: any) => ({ - ...prevState, - notes: [...prevState.notes, ...data.results], - totalPages: Math.ceil(data.count / pageSize), - })); - } - setIsLoading(false); - setReload(false); - }; + return { + results: response?.results ?? [], + nextPage: pageParam + RESULTS_PER_PAGE_LIMIT, + totalResults: response?.count ?? 0, + }; + }, + getNextPageParam: (lastPage, allPages) => { + const currentResults = allPages.flatMap((page) => page.results).length; + if (currentResults < lastPage.totalResults) { + return lastPage.nextPage; + } + return undefined; + }, + initialPageParam: 0, + }); useEffect(() => { - if (reload || thread) { - fetchNotes(); - } - }, [reload, thread]); + if (data?.pages) { + const allNotes = data.pages.flatMap((page) => page.results); + + const notesMap = new Map(allNotes.map((note) => [note.id, note])); + + const deduplicatedNotes = Array.from(notesMap.values()); - const handleNext = () => { - if (state.cPage < state.totalPages) { setState((prevState: any) => ({ ...prevState, - cPage: prevState.cPage + 1, + notes: deduplicatedNotes, })); - setReload(true); } - }; + }, [data]); - if (isLoading) { + if (isLoading || reload) { return (
@@ -84,9 +79,10 @@ const PatientNotesList = (props: PatientNotesProps) => { return ( ); }; diff --git a/src/components/Facility/PatientNotesSlideover.tsx b/src/components/Facility/PatientNotesSlideover.tsx index 89d38a5f168..5de161ad228 100644 --- a/src/components/Facility/PatientNotesSlideover.tsx +++ b/src/components/Facility/PatientNotesSlideover.tsx @@ -13,6 +13,7 @@ import { PatientNoteStateType, } from "@/components/Facility/models"; import AutoExpandingTextInputFormField from "@/components/Form/FormFields/AutoExpandingTextInputFormField"; +import { useAddPatientNote } from "@/components/Patient/Utils"; import useAuthUser from "@/hooks/useAuthUser"; import { useMessageListener } from "@/hooks/useMessageListener"; @@ -63,8 +64,6 @@ export default function PatientNotesSlideover(props: PatientNotesProps) { const initialData: PatientNoteStateType = { notes: [], - cPage: 1, - totalPages: 1, patientId: props.patientId, facilityId: props.facilityId, }; @@ -77,30 +76,27 @@ export default function PatientNotesSlideover(props: PatientNotesProps) { const [noteField, setNoteField] = useState( localStorage.getItem(localStorageKey) || "", ); + const { mutate: addNote } = useAddPatientNote({ + patientId, + thread, + consultationId, + }); - const onAddNote = async () => { + const onAddNote = () => { if (!/\S+/.test(noteField)) { Notification.Error({ msg: "Note Should Contain At Least 1 Character", }); return; } - const { res } = await request(routes.addPatientNote, { - pathParams: { patientId: patientId }, - body: { - note: noteField, - consultation: consultationId, - thread, - reply_to: reply_to?.id, - }, + setReplyTo(undefined); + setNoteField(""); + addNote({ + note: noteField, + reply_to: reply_to?.id, + thread, + consultation: consultationId, }); - if (res?.status === 201) { - Notification.Success({ msg: "Note added successfully" }); - setNoteField(""); - setState({ ...state, cPage: 1 }); - setReload(true); - setReplyTo(undefined); - } }; useMessageListener((data) => { @@ -235,13 +231,21 @@ export default function PatientNotesSlideover(props: PatientNotesProps) { ? "border-primary-500 font-medium text-white" : "border-primary-800 text-white/70", )} - onClick={() => setThread(PATIENT_NOTES_THREADS[current])} + onClick={() => { + if (thread !== PATIENT_NOTES_THREADS[current]) { + setThread(PATIENT_NOTES_THREADS[current]); + setState(initialData); + setReplyTo(undefined); + setNoteField(""); + } + }} > {t(`patient_notes_thread__${current}`)} ))}
({ return (
{ - if (e.key === "Enter") { - handleSubmit(e); - } - }} className={classNames( "mx-auto w-full", !props.noPadding && "px-8 py-5 md:px-16 md:py-11", diff --git a/src/components/Kanban/Board.tsx b/src/components/Kanban/Board.tsx index 337f98f1caf..0023c494609 100644 --- a/src/components/Kanban/Board.tsx +++ b/src/components/Kanban/Board.tsx @@ -4,12 +4,13 @@ import { Droppable, OnDragEndResponder, } from "@hello-pangea/dnd"; -import { ReactNode, RefObject, useEffect, useRef, useState } from "react"; +import { useInfiniteQuery } from "@tanstack/react-query"; +import { ReactNode, RefObject, useEffect, useRef } from "react"; import { useTranslation } from "react-i18next"; import CareIcon from "@/CAREUI/icons/CareIcon"; -import request from "@/Utils/request/request"; +import { callApi } from "@/Utils/request/query"; import { QueryRoute } from "@/Utils/request/types"; import { QueryOptions } from "@/Utils/request/useQuery"; @@ -57,7 +58,7 @@ export default function KanbanBoard(
-
+
{props.sections.map((section, i) => ( @@ -74,6 +75,12 @@ export default function KanbanBoard( ); } +interface QueryResponse { + results: T[]; + next: string | null; + count: number; +} + export function KanbanSection( props: Omit, "sections" | "onDragEnd"> & { section: KanbanBoardProps["sections"][number]; @@ -81,107 +88,104 @@ export function KanbanSection( }, ) { const { section } = props; - const [offset, setOffset] = useState(0); - const [pages, setPages] = useState([]); - const [fetchingNextPage, setFetchingNextPage] = useState(false); - const [hasMore, setHasMore] = useState(true); - const [totalCount, setTotalCount] = useState(); - - const options = section.fetchOptions(section.id); const sectionRef = useRef(null); const defaultLimit = 14; const { t } = useTranslation(); - - // should be replaced with useInfiniteQuery when we move over to react query - - const fetchNextPage = async (refresh: boolean = false) => { - if (!refresh && (fetchingNextPage || !hasMore)) return; - if (refresh) setPages([]); - const offsetToUse = refresh ? 0 : offset; - setFetchingNextPage(true); - const res = await request(options.route, { - ...options.options, - query: { ...options.options?.query, offsetToUse, limit: defaultLimit }, - }); - const newPages = refresh ? [] : [...pages]; - const page = Math.floor(offsetToUse / defaultLimit); - if (res.error) return; - newPages[page] = (res.data as any).results; - setPages(newPages); - setHasMore(!!(res.data as any)?.next); - setTotalCount((res.data as any)?.count); - setOffset(offsetToUse + defaultLimit); - setFetchingNextPage(false); + const options = section.fetchOptions(section.id); + const fetchPage = async ({ pageParam = 0 }) => { + try { + const data = await callApi(options.route, { + ...options.options, + queryParams: { + ...options.options?.query, + offset: pageParam, + limit: defaultLimit, + }, + }); + return data as QueryResponse; + } catch (error) { + console.error("Error fetching section data:", error); + return { results: [], next: null, count: 0 }; + } }; - const items = pages.flat(); + const { + data, + fetchNextPage, + hasNextPage, + isFetchingNextPage, + isLoading, + refetch, + } = useInfiniteQuery({ + queryKey: ["board", section.id, options.options?.query], + queryFn: fetchPage, + getNextPageParam: (lastPage, pages) => { + if (!lastPage.next) return undefined; + return pages.length * defaultLimit; + }, + initialPageParam: 0, + }); - useEffect(() => { - const onBoardReachEnd = async () => { - const sectionElementHeight = - sectionRef.current?.getBoundingClientRect().height; - const scrolled = props.boardRef.current?.scrollTop; - // if user has scrolled 3/4th of the current items - if ( - scrolled && - sectionElementHeight && - scrolled > sectionElementHeight * (3 / 4) - ) { - fetchNextPage(); - } - }; - - props.boardRef.current?.addEventListener("scroll", onBoardReachEnd); - return () => - props.boardRef.current?.removeEventListener("scroll", onBoardReachEnd); - }, [props.boardRef, fetchingNextPage, hasMore]); + const items = data?.pages?.flatMap((page) => page.results || []) ?? []; + const totalCount = data?.pages[0]?.count ?? 0; useEffect(() => { - fetchNextPage(true); - }, [props.section]); + refetch(); + }, [section.id, refetch]); return ( - {(provided) => ( + {(provided, _snapshot) => (
{section.title}
- {typeof totalCount === "undefined" ? "..." : totalCount} + {isLoading ? "..." : totalCount}
-
- {!fetchingNextPage && totalCount === 0 && ( +
{ + const target = e.target as HTMLDivElement; + if ( + target.scrollTop + target.clientHeight >= + target.scrollHeight - 100 + ) { + if (hasNextPage && !isFetchingNextPage) { + fetchNextPage(); + } + } + }} + > + {!isLoading && items.length === 0 && (
{t("no_results_found")}
)} - {items - .filter((item) => item) - .map((item, i) => ( - - {(provided) => ( -
- {props.itemRender(item)} -
- )} -
- ))} - {fetchingNextPage && ( + {items.map((item, index) => ( + + {(provided, _snapshot) => ( +
+ {props.itemRender(item)} +
+ )} +
+ ))} + {provided.placeholder} + {isFetchingNextPage && (
)}
diff --git a/src/components/Medicine/MedibaseAutocompleteFormField.tsx b/src/components/Medicine/MedibaseAutocompleteFormField.tsx index d2d57b1db85..185b3293b99 100644 --- a/src/components/Medicine/MedibaseAutocompleteFormField.tsx +++ b/src/components/Medicine/MedibaseAutocompleteFormField.tsx @@ -55,7 +55,7 @@ export default function MedibaseAutocompleteFormField( required onChange={field.handleChange} options={mergeQueryOptions( - field.value && !query ? [field.value] : [], + field.value ? [field.value] : [], data ?? [], (obj) => obj.id, )} diff --git a/src/components/Notifications/NoticeBoard.tsx b/src/components/Notifications/NoticeBoard.tsx index 452cd7f568e..4097ae030c4 100644 --- a/src/components/Notifications/NoticeBoard.tsx +++ b/src/components/Notifications/NoticeBoard.tsx @@ -45,7 +45,7 @@ export const NoticeBoard = () => { ); } else { notices = ( -
+
diff --git a/src/components/Patient/PatientDetailsTab/Demography.tsx b/src/components/Patient/PatientDetailsTab/Demography.tsx index d6e1379cd7e..95811be7361 100644 --- a/src/components/Patient/PatientDetailsTab/Demography.tsx +++ b/src/components/Patient/PatientDetailsTab/Demography.tsx @@ -3,7 +3,6 @@ import { navigate } from "raviger"; import { Fragment, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; -import Chip from "@/CAREUI/display/Chip"; import CareIcon from "@/CAREUI/icons/CareIcon"; import AuthorizedChild from "@/CAREUI/misc/AuthorizedChild"; @@ -356,23 +355,6 @@ export const Demography = (props: PatientProps) => {
-
-
- {t("patient_status")} -
-
- -
-
{({ isAuthorized }) => ( diff --git a/src/components/Patient/PatientDetailsTab/Notes.tsx b/src/components/Patient/PatientDetailsTab/Notes.tsx index 4fccf7a1119..5c877c2d734 100644 --- a/src/components/Patient/PatientDetailsTab/Notes.tsx +++ b/src/components/Patient/PatientDetailsTab/Notes.tsx @@ -12,6 +12,7 @@ import { } from "@/components/Facility/models"; import AutoExpandingTextInputFormField from "@/components/Form/FormFields/AutoExpandingTextInputFormField"; import { PatientProps } from "@/components/Patient/PatientDetailsTab"; +import { useAddPatientNote } from "@/components/Patient/Utils"; import useAuthUser from "@/hooks/useAuthUser"; import { useMessageListener } from "@/hooks/useMessageListener"; @@ -20,8 +21,6 @@ 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"; const PatientNotes = (props: PatientProps) => { @@ -39,43 +38,29 @@ const PatientNotes = (props: PatientProps) => { const [reply_to, setReplyTo] = useState( undefined, ); - + const { mutate: addNote } = useAddPatientNote({ + patientId, + thread, + }); const initialData: PatientNoteStateType = { notes: [], - cPage: 1, - totalPages: 1, }; const [state, setState] = useState(initialData); - const onAddNote = async () => { + const onAddNote = () => { if (!/\S+/.test(noteField)) { Notification.Error({ msg: "Note Should Contain At Least 1 Character", }); return; } - - try { - const { res } = await request(routes.addPatientNote, { - pathParams: { patientId: patientId }, - body: { - note: noteField, - thread, - reply_to: reply_to?.id, - }, - }); - if (res?.status === 201) { - setNoteField(""); - setReload(!reload); - setState({ ...state, cPage: 1 }); - setReplyTo(undefined); - Notification.Success({ msg: "Note added successfully" }); - } - } catch (error) { - Notification.Error({ - msg: "Failed to add note. Please try again.", - }); - } + addNote({ + note: noteField, + reply_to: reply_to?.id, + thread, + }); + setReplyTo(undefined); + setNoteField(""); }; useMessageListener((data) => { @@ -104,13 +89,21 @@ const PatientNotes = (props: PatientProps) => { ? "border-primary-500 font-bold text-secondary-800" : "border-secondary-300 text-secondary-800", )} - onClick={() => setThread(PATIENT_NOTES_THREADS[current])} + onClick={() => { + if (thread !== PATIENT_NOTES_THREADS[current]) { + setThread(PATIENT_NOTES_THREADS[current]); + setState(initialData); + setReplyTo(undefined); + setNoteField(""); + } + }} > {t(`patient_notes_thread__${current}`)} ))}
{ return OCCUPATION_TYPES.find((i) => i.value === occupation)?.text; @@ -218,29 +218,55 @@ export const PatientHome = (props: {
- {patientData?.is_active && - (!patientData?.last_consultation || - patientData?.last_consultation?.discharge_date) && ( -
- - navigate( - `/facility/${patientData?.facility}/patient/${id}/consultation`, - ) - } - > - - - {t("add_consultation")} - - -
+ {facilityId === + patientData.facility_object?.id.toString() && + patientData?.is_active && ( + <> + {patientData?.last_consultation && + !patientData?.last_consultation.discharge_date ? ( +
+ +
+ ) : ( +
+ +
+ )} + )}
@@ -366,7 +392,7 @@ export const PatientHome = (props: { className="tooltip-text tooltip-bottom flex flex-col text-xs font-medium" role="tooltip" > - {skillsQuery.data?.results.map((skill) => ( + {skillsQuery.data?.results.map((skill: any) => (
  • {skill.skill_object.name}
  • @@ -456,16 +482,15 @@ export const PatientHome = (props: {
    -
    +
    {t("actions")}
    - navigate(`/patient/${id}/investigation_reports`) } @@ -477,13 +502,12 @@ export const PatientHome = (props: { /> {t("investigations_summary")} - +
    - navigate( `/facility/${patientData?.facility}/patient/${id}/files`, @@ -494,18 +518,17 @@ export const PatientHome = (props: { {t("view_update_patient_files")} - +
    - {NonReadOnlyUsers && ( + {NonReadOnlyUsers(authUser.user_type) && (
    - setOpenAssignVolunteerDialog(true)} disabled={false} authorizeFor={NonReadOnlyUsers} className="w-full bg-white font-semibold text-green-800 hover:bg-secondary-200" - size="large" > {" "} @@ -513,15 +536,14 @@ export const PatientHome = (props: { ? t("update_volunteer") : t("assign_to_volunteer")} - +
    )}
    - - +
    @@ -661,7 +683,7 @@ export const PatientHome = (props: { {patientData.last_consultation?.new_discharge_reason === DISCHARGE_REASONS.find((i) => i.text == "Expired")?.id && (
    - {t("death_report")} - +
    )}
    diff --git a/src/components/Patient/PatientNotes.tsx b/src/components/Patient/PatientNotes.tsx index 70dfcd6c426..b1e0c557837 100644 --- a/src/components/Patient/PatientNotes.tsx +++ b/src/components/Patient/PatientNotes.tsx @@ -12,6 +12,7 @@ import { PatientNotesModel, } from "@/components/Facility/models"; import AutoExpandingTextInputFormField from "@/components/Form/FormFields/AutoExpandingTextInputFormField"; +import { useAddPatientNote } from "@/components/Patient/Utils"; import useAuthUser from "@/hooks/useAuthUser"; import { useMessageListener } from "@/hooks/useMessageListener"; @@ -50,34 +51,28 @@ const PatientNotes = (props: PatientNotesProps) => { const initialData: PatientNoteStateType = { notes: [], - cPage: 1, - totalPages: 1, }; const [state, setState] = useState(initialData); - const onAddNote = async () => { + const { mutate: addNote } = useAddPatientNote({ + patientId, + thread, + }); + + const onAddNote = () => { if (!/\S+/.test(noteField)) { Notification.Error({ msg: "Note Should Contain At Least 1 Character", }); return; } - - const { res } = await request(routes.addPatientNote, { - pathParams: { patientId: patientId }, - body: { - note: noteField, - thread, - reply_to: reply_to?.id, - }, + addNote({ + note: noteField, + reply_to: reply_to?.id, + thread, }); - if (res?.status === 201) { - Notification.Success({ msg: "Note added successfully" }); - setNoteField(""); - setReload(!reload); - setState({ ...state, cPage: 1 }); - setReplyTo(undefined); - } + setReplyTo(undefined); + setNoteField(""); }; useEffect(() => { @@ -130,13 +125,21 @@ const PatientNotes = (props: PatientNotesProps) => { ? "border-primary-500 font-bold text-secondary-800" : "border-secondary-300 text-secondary-800", )} - onClick={() => setThread(PATIENT_NOTES_THREADS[current])} + onClick={() => { + if (thread !== PATIENT_NOTES_THREADS[current]) { + setThread(PATIENT_NOTES_THREADS[current]); + setState(initialData); + setReplyTo(undefined); + setNoteField(""); + } + }} > {t(`patient_notes_thread__${current}`)} ))}
    { + const queryClient = useQueryClient(); + const { patientId, thread, consultationId } = options; + + return useMutation({ + mutationFn: mutate(routes.addPatientNote, { + pathParams: { patientId }, + }), + onSuccess: (data) => { + queryClient.invalidateQueries({ + queryKey: ["notes", patientId, thread, consultationId], + }); + return data; + }, + }); +}; diff --git a/src/components/Shifting/ShiftingTable.tsx b/src/components/Shifting/ShiftingTable.tsx index de186a13d56..f7d75e13db2 100644 --- a/src/components/Shifting/ShiftingTable.tsx +++ b/src/components/Shifting/ShiftingTable.tsx @@ -134,8 +134,8 @@ export default function ShiftingTable(props: {
    -
    -
    +
    +
    -
    +
    -
    +
    {shift.origin_facility_object?.name}
    @@ -197,17 +197,17 @@ export default function ShiftingTable(props: {
    -
    +
    {shift.assigned_facility_external || shift.assigned_facility_object?.name || t("yet_to_be_decided")}
    -
    +
    navigate(`/shifting/${shift.external_id}`)} variant="secondary" @@ -219,7 +219,7 @@ export default function ShiftingTable(props: { {shift.status === "COMPLETED" && shift.assigned_facility && (
    )}
    - +
    @@ -274,6 +277,7 @@ export default function LinkedFacilities({ onClick={() => handleOnClick("clear_home_facility", homeFacility) } + disabled={authUser.user_type == "Volunteer"} title={t("clear_home_facility")} aria-label={t("clear_home_facility")} > 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/UserListAndCard.tsx b/src/components/Users/UserListAndCard.tsx index ee1ac5e9874..d8194853570 100644 --- a/src/components/Users/UserListAndCard.tsx +++ b/src/components/Users/UserListAndCard.tsx @@ -134,30 +134,33 @@ export const UserStatusIndicator = ({ className?: string; addPadding?: boolean; }) => { - const cur_online = isUserOnline(user); + const authUser = useAuthUser(); + const isAuthUser = user.id === authUser.id; + const isOnline = isUserOnline(user) || isAuthUser; const { t } = useTranslation(); + return (
    - {cur_online + {isOnline ? t("online") : user.last_login ? relativeTime(user.last_login) 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) =>