From 0b3279fc9812afde4a2d552b0d5db733b633e9e2 Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Tue, 4 Feb 2025 23:45:38 +0530 Subject: [PATCH 01/19] Filter allergies by encounter if encounter is marked as completed --- src/components/Patient/allergy/list.tsx | 12 ++++++++++-- src/pages/Encounters/tabs/EncounterUpdatesTab.tsx | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/components/Patient/allergy/list.tsx b/src/components/Patient/allergy/list.tsx index a4a91bae6a1..61d4afbbfb2 100644 --- a/src/components/Patient/allergy/list.tsx +++ b/src/components/Patient/allergy/list.tsx @@ -22,24 +22,32 @@ import { Avatar } from "@/components/Common/Avatar"; import query from "@/Utils/request/query"; import { AllergyIntolerance } from "@/types/emr/allergyIntolerance/allergyIntolerance"; import allergyIntoleranceApi from "@/types/emr/allergyIntolerance/allergyIntoleranceApi"; +import { Encounter, completedEncounterStatus } from "@/types/emr/encounter"; interface AllergyListProps { facilityId?: string; patientId: string; encounterId?: string; + encounterStatus: Encounter["status"]; } export function AllergyList({ facilityId, patientId, encounterId, + encounterStatus, }: AllergyListProps) { const [showEnteredInError, setShowEnteredInError] = useState(false); const { data: allergies, isLoading } = useQuery({ - queryKey: ["allergies", patientId, encounterId], + queryKey: ["allergies", patientId, encounterId, encounterStatus], queryFn: query(allergyIntoleranceApi.getAllergy, { pathParams: { patientId }, + queryParams: { + encounter: completedEncounterStatus.includes(encounterStatus as string) + ? encounterId + : undefined, + }, }), }); @@ -233,7 +241,7 @@ const AllergyListLayout = ({ {t("allergies")} - {facilityId && encounterId && ( + {facilityId && ( From b816e20ad6c70565e6d49873db937e73460b4663 Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Tue, 4 Feb 2025 23:52:30 +0530 Subject: [PATCH 02/19] fix type --- src/components/Patient/allergy/list.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Patient/allergy/list.tsx b/src/components/Patient/allergy/list.tsx index 61d4afbbfb2..3eed3b32e40 100644 --- a/src/components/Patient/allergy/list.tsx +++ b/src/components/Patient/allergy/list.tsx @@ -28,7 +28,7 @@ interface AllergyListProps { facilityId?: string; patientId: string; encounterId?: string; - encounterStatus: Encounter["status"]; + encounterStatus?: Encounter["status"]; } export function AllergyList({ From c242c96ff7896981b2a0272bf00ad1312f1576c7 Mon Sep 17 00:00:00 2001 From: rithviknishad Date: Wed, 5 Feb 2025 00:00:17 +0530 Subject: [PATCH 03/19] show edit button only if encounter id is present --- src/components/Patient/allergy/list.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Patient/allergy/list.tsx b/src/components/Patient/allergy/list.tsx index 3eed3b32e40..623aaf416d8 100644 --- a/src/components/Patient/allergy/list.tsx +++ b/src/components/Patient/allergy/list.tsx @@ -241,7 +241,7 @@ const AllergyListLayout = ({ {t("allergies")} - {facilityId && ( + {facilityId && encounterId && ( Date: Wed, 5 Feb 2025 18:00:48 +0530 Subject: [PATCH 04/19] Logout API (#10416) --- src/Providers/AuthUserProvider.tsx | 17 ++++++++++++++++- src/Utils/request/api.tsx | 6 ++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Providers/AuthUserProvider.tsx b/src/Providers/AuthUserProvider.tsx index 7b94ba73e4a..a0e9aefeac2 100644 --- a/src/Providers/AuthUserProvider.tsx +++ b/src/Providers/AuthUserProvider.tsx @@ -9,7 +9,8 @@ import { AuthUserContext } from "@/hooks/useAuthUser"; import { LocalStorageKeys } from "@/common/constants"; -import routes from "@/Utils/request/api"; +import routes, { Type } from "@/Utils/request/api"; +import mutate from "@/Utils/request/mutate"; import query from "@/Utils/request/query"; import request from "@/Utils/request/request"; import { TokenData } from "@/types/auth/otpToken"; @@ -85,6 +86,20 @@ export default function AuthUserProvider({ }; const signOut = useCallback(async () => { + const accessToken = localStorage.getItem(LocalStorageKeys.accessToken); + const refreshToken = localStorage.getItem(LocalStorageKeys.refreshToken); + + if (accessToken && refreshToken) { + try { + await mutate({ + ...routes.logout, + TRes: Type>(), + })({ access: accessToken, refresh: refreshToken }); + } catch (error) { + console.error("Error during logout:", error); + } + } + localStorage.removeItem(LocalStorageKeys.accessToken); localStorage.removeItem(LocalStorageKeys.refreshToken); localStorage.removeItem(LocalStorageKeys.patientTokenKey); diff --git a/src/Utils/request/api.tsx b/src/Utils/request/api.tsx index c6edaeb3fb6..9066aab0e1f 100644 --- a/src/Utils/request/api.tsx +++ b/src/Utils/request/api.tsx @@ -103,6 +103,12 @@ const routes = { TBody: Type(), }, + logout: { + path: "/api/v1/auth/logout/", + method: "POST", + TBody: Type(), + }, + token_refresh: { path: "/api/v1/auth/token/refresh/", method: "POST", From 66a90fb67643c3d3dfe9005c5f7f8b67b4d44d72 Mon Sep 17 00:00:00 2001 From: Khavin Shankar Date: Wed, 5 Feb 2025 19:25:38 +0530 Subject: [PATCH 05/19] added PatientDetailsTabDemographyGeneralInfo plaggable (#10418) --- src/components/Facility/FacilityHome.tsx | 2 +- src/components/Patient/PatientDetailsTab/Demography.tsx | 6 ++++++ src/pluginTypes.ts | 7 +++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/components/Facility/FacilityHome.tsx b/src/components/Facility/FacilityHome.tsx index 4856911d5e7..be79cce3c63 100644 --- a/src/components/Facility/FacilityHome.tsx +++ b/src/components/Facility/FacilityHome.tsx @@ -251,7 +251,7 @@ export const FacilityHome = ({ facilityId }: Props) => {
- +
-
+
@@ -148,21 +154,6 @@ export const PatientHome = (props: {
- - -
+
-
- {t("last_updated_by")}{" "} - +
+ {t("last_updated_by")} +
{patientData.updated_by?.first_name}{" "} {patientData.updated_by?.last_name} - -
-
-
- - {patientData.modified_date - ? formatDateTime(patientData.modified_date) - : "--:--"} - - {patientData.modified_date - ? relativeDate(patientData.modified_date) - : "--:--"}
+ +
+ {patientData.modified_date ? ( + + + + + {relativeTime(patientData.modified_date)} + + + + {formatDateTime(patientData.modified_date)} + + + + ) : ( + "--:--" + )} +
- {t("patient_profile_created_by")}{" "} - + {t("patient_profile_created_by")} +
{patientData.created_by?.first_name}{" "} {patientData.created_by?.last_name} - -
-
-
- - {patientData.created_date - ? formatDateTime(patientData.created_date) - : "--:--"} - - {patientData.created_date - ? relativeDate(patientData.created_date) - : "--:--"}
+
+ {patientData.created_date ? ( + + + + + {relativeTime(patientData.created_date)} + + + + {formatDateTime(patientData.created_date)} + + + + ) : ( + "--:--" + )} +
diff --git a/src/pages/Appointments/AppointmentsPage.tsx b/src/pages/Appointments/AppointmentsPage.tsx index 6b939f54fac..5b227bdbe9b 100644 --- a/src/pages/Appointments/AppointmentsPage.tsx +++ b/src/pages/Appointments/AppointmentsPage.tsx @@ -677,6 +677,7 @@ function AppointmentColumn(props: { date_before: props.date_to, }, }), + enabled: !!props.date_from && !!props.date_to, }); let appointments = data?.results ?? []; @@ -801,6 +802,7 @@ function AppointmentRow(props: { date_before: props.date_to, }, }), + enabled: !!props.date_from && !!props.date_to, }); let appointments = data?.results ?? []; From 6bf2f6161c547a2a851d81e2327a1cdec5640745 Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Wed, 5 Feb 2025 14:14:25 +0000 Subject: [PATCH 07/19] API Erorr Handler: early exit if error can be silenced (#10409) --- src/Utils/request/errorHandler.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Utils/request/errorHandler.ts b/src/Utils/request/errorHandler.ts index e83973cfeeb..8d07981307d 100644 --- a/src/Utils/request/errorHandler.ts +++ b/src/Utils/request/errorHandler.ts @@ -6,7 +6,8 @@ import * as Notifications from "@/Utils/Notifications"; import { HTTPError, StructuredError } from "@/Utils/request/types"; export function handleHttpError(error: Error) { - if (error.name === "AbortError") { + // Skip handling silent errors and AbortError + if (("silent" in error && error.silent) || error.name === "AbortError") { return; } @@ -15,10 +16,6 @@ export function handleHttpError(error: Error) { return; } - if (error.silent) { - return; - } - const cause = error.cause; if (isNotFound(error)) { From a69c25e5b91df14b00cf3af0ea21d6c31545dedb Mon Sep 17 00:00:00 2001 From: Amjith Titus Date: Wed, 5 Feb 2025 19:44:58 +0530 Subject: [PATCH 08/19] Questionnaire hide tooltip (#10408) --- src/components/Questionnaire/QuestionTypes/QuestionGroup.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Questionnaire/QuestionTypes/QuestionGroup.tsx b/src/components/Questionnaire/QuestionTypes/QuestionGroup.tsx index d38be63abcb..37c95e324c6 100644 --- a/src/components/Questionnaire/QuestionTypes/QuestionGroup.tsx +++ b/src/components/Questionnaire/QuestionTypes/QuestionGroup.tsx @@ -119,7 +119,7 @@ export const QuestionGroup = memo(function QuestionGroup({ return (
)}
Date: Wed, 5 Feb 2025 19:45:13 +0530 Subject: [PATCH 09/19] new test for assign a user to a patient (#10394) --- .../e2e/patient_spec/patient_creation.cy.ts | 5 +- .../e2e/patient_spec/patient_details.cy.ts | 35 +++++++++++ .../pageObject/Patients/PatientDashboard.ts | 8 --- cypress/pageObject/Patients/PatientDetails.ts | 61 +++++++++++++++++++ .../pageObject/Patients/PatientEncounter.ts | 5 ++ .../PatientDetailsTab/PatientUsers.tsx | 16 +++-- src/components/Patient/PatientHome.tsx | 1 + 7 files changed, 115 insertions(+), 16 deletions(-) create mode 100644 cypress/e2e/patient_spec/patient_details.cy.ts delete mode 100644 cypress/pageObject/Patients/PatientDashboard.ts create mode 100644 cypress/pageObject/Patients/PatientDetails.ts diff --git a/cypress/e2e/patient_spec/patient_creation.cy.ts b/cypress/e2e/patient_spec/patient_creation.cy.ts index 9cec5afc0fd..8f2c1606c38 100644 --- a/cypress/e2e/patient_spec/patient_creation.cy.ts +++ b/cypress/e2e/patient_spec/patient_creation.cy.ts @@ -8,7 +8,6 @@ import { PatientFormData, patientCreation, } from "@/pageObject/Patients/PatientCreation"; -import { patientDashboard } from "@/pageObject/Patients/PatientDashboard"; import { PatientEncounter } from "@/pageObject/Patients/PatientEncounter"; import { patientVerify } from "@/pageObject/Patients/PatientVerify"; import { FacilityCreation } from "@/pageObject/facility/FacilityCreation"; @@ -126,7 +125,7 @@ describe("Patient Management", () => { .clickSubmitEncounter() .assertEncounterCreationSuccess(); - patientDashboard.verifyEncounterPatientInfo([ + patientEncounter.verifyEncounterPatientInfo([ ENCOUNTER_TYPE, ENCOUNTER_STATUS, ENCOUNTER_PRIORITY, @@ -154,7 +153,7 @@ describe("Patient Management", () => { .clickSubmitEncounter() .assertEncounterCreationSuccess(); - patientDashboard.verifyEncounterPatientInfo([ + patientEncounter.verifyEncounterPatientInfo([ ENCOUNTER_TYPE, ENCOUNTER_STATUS, ENCOUNTER_PRIORITY, diff --git a/cypress/e2e/patient_spec/patient_details.cy.ts b/cypress/e2e/patient_spec/patient_details.cy.ts new file mode 100644 index 00000000000..0f8d9c897a9 --- /dev/null +++ b/cypress/e2e/patient_spec/patient_details.cy.ts @@ -0,0 +1,35 @@ +import { PatientDetails } from "@/pageObject/Patients/PatientDetails"; +import { PatientEncounter } from "@/pageObject/Patients/PatientEncounter"; +import { FacilityCreation } from "@/pageObject/facility/FacilityCreation"; + +const facilityCreation = new FacilityCreation(); +const patientEncounter = new PatientEncounter(); +const patientDetails = new PatientDetails(); + +describe("Patient Management", () => { + beforeEach(() => { + cy.loginByApi("doctor"); + cy.visit("/"); + }); + + it("Assign users to a patient", () => { + const userName = "nihal-nurse"; + const userRole = "Nurse"; + facilityCreation.selectFacility("GHC Trikaripur"); + patientEncounter + .navigateToEncounters() + .openFirstEncounterDetails() + .clickPatientDetailsButton(); + patientDetails + .clickUsersTab() + .clickAssignUserButton() + .selectUserToAssign(userName) + .selectUserRole(userRole) + .confirmUserAssignment() + .verifyUserAssignmentSuccess() + .verifyUserContent([userName]) + .clickRemoveUserButton() + .confirmUserRemoval() + .verifyUserRemovalSuccess(); + }); +}); diff --git a/cypress/pageObject/Patients/PatientDashboard.ts b/cypress/pageObject/Patients/PatientDashboard.ts deleted file mode 100644 index 9d608b17ea6..00000000000 --- a/cypress/pageObject/Patients/PatientDashboard.ts +++ /dev/null @@ -1,8 +0,0 @@ -class PatientDashboard { - verifyEncounterPatientInfo(contents: string[]) { - cy.verifyContentPresence("#patient-infobadges", contents); - return this; - } -} - -export const patientDashboard = new PatientDashboard(); diff --git a/cypress/pageObject/Patients/PatientDetails.ts b/cypress/pageObject/Patients/PatientDetails.ts new file mode 100644 index 00000000000..1a5c2979fac --- /dev/null +++ b/cypress/pageObject/Patients/PatientDetails.ts @@ -0,0 +1,61 @@ +export class PatientDetails { + clickUsersTab() { + cy.verifyAndClickElement('[data-cy="tab-users"]', "Users"); + return this; + } + + clickAssignUserButton() { + cy.verifyAndClickElement('[data-cy="assign-user-button"]', "Assign User"); + return this; + } + + selectUserToAssign(username: string) { + cy.typeAndSelectOption( + '[data-cy="patient-user-selector-container"]', + username, + false, + ); + return this; + } + + selectUserRole(role: string) { + cy.clickAndSelectOption('[data-cy="patient-user-role-select"]', role); + return this; + } + + confirmUserAssignment() { + cy.verifyAndClickElement( + '[data-cy="patient-user-assign-button"]', + "Assign to Patient", + ); + return this; + } + + verifyUserAssignmentSuccess() { + cy.verifyNotification("User added to patient successfully"); + return this; + } + + clickRemoveUserButton() { + cy.get('[data-cy="patient-user-remove-button"]').first().click(); + return this; + } + + confirmUserRemoval() { + cy.verifyAndClickElement( + '[data-cy="patient-user-remove-confirm-button"]', + "Remove", + ); + return this; + } + + verifyUserContent(expectedTexts: string[]) { + cy.verifyContentPresence('[data-cy="patient-users"]', expectedTexts); + return this; + } + + verifyUserRemovalSuccess() { + cy.verifyNotification("User removed successfully"); + return this; + } +} diff --git a/cypress/pageObject/Patients/PatientEncounter.ts b/cypress/pageObject/Patients/PatientEncounter.ts index fd8dd325572..95e3b8c1fe0 100644 --- a/cypress/pageObject/Patients/PatientEncounter.ts +++ b/cypress/pageObject/Patients/PatientEncounter.ts @@ -22,6 +22,11 @@ export class PatientEncounter { return this; } + verifyEncounterPatientInfo(contents: string[]) { + cy.verifyContentPresence("#patient-infobadges", contents); + return this; + } + // Questionnaire actions addQuestionnaire(questionnaireName: string) { cy.get('[data-cy="add-questionnaire-button"]').click(); diff --git a/src/components/Patient/PatientDetailsTab/PatientUsers.tsx b/src/components/Patient/PatientDetailsTab/PatientUsers.tsx index 5e6f00494ab..5f0e90e8297 100644 --- a/src/components/Patient/PatientDetailsTab/PatientUsers.tsx +++ b/src/components/Patient/PatientDetailsTab/PatientUsers.tsx @@ -103,7 +103,7 @@ function AddUserSheet({ patientId }: AddUserSheetProps) { return ( - @@ -114,7 +114,7 @@ function AddUserSheet({ patientId }: AddUserSheetProps) { {t("search_user_description")}
-
+

{t("search_user")}

From d8270585d967623cece80e2575d9db394dea9fcf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 6 Feb 2025 12:41:34 +0530 Subject: [PATCH 14/19] Update all dependencies (minor, patch) (#10355) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 636 +++++++++++++++++++++++----------------------- package.json | 6 +- 2 files changed, 322 insertions(+), 320 deletions(-) diff --git a/package-lock.json b/package-lock.json index f6c19f9cbe5..794d8cd3670 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "care_fe", - "version": "2.9.0", + "version": "2.10.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "care_fe", - "version": "2.9.0", + "version": "2.10.0", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -143,8 +143,8 @@ "optionalDependencies": { "@esbuild/linux-arm64": "latest", "@esbuild/linux-x64": "latest", - "@rollup/rollup-linux-arm64-gnu": "4.32.1", - "@rollup/rollup-linux-x64-gnu": "4.32.1" + "@rollup/rollup-linux-arm64-gnu": "4.34.4", + "@rollup/rollup-linux-x64-gnu": "4.34.4" } }, "node_modules/@actions/core": { @@ -4467,17 +4467,17 @@ "license": "MIT" }, "node_modules/@radix-ui/react-alert-dialog": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.5.tgz", - "integrity": "sha512-1Y2sI17QzSZP58RjGtrklfSGIf3AF7U/HkD3aAcAnhOUJrm7+7GG1wRDFaUlSe0nW5B/t4mYd/+7RNbP2Wexug==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.6.tgz", + "integrity": "sha512-p4XnPqgej8sZAAReCAKgz1REYZEBLR8hU9Pg27wFnCWIMc8g1ccCs0FjBcy05V15VTu8pAePw/VDYeOm/uZ6yQ==", "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-dialog": "1.1.5", - "@radix-ui/react-primitive": "2.0.1", - "@radix-ui/react-slot": "1.1.1" + "@radix-ui/react-dialog": "1.1.6", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-slot": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -4495,12 +4495,12 @@ } }, "node_modules/@radix-ui/react-arrow": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.1.tgz", - "integrity": "sha512-NaVpZfmv8SKeZbn4ijN2V3jlHA9ngBG16VnIIm22nUR0Yk8KUALyBxT3KYEUnNuch9sTE8UTsS3whzBgKOL30w==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz", + "integrity": "sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.0.1" + "@radix-ui/react-primitive": "2.0.2" }, "peerDependencies": { "@types/react": "*", @@ -4518,12 +4518,13 @@ } }, "node_modules/@radix-ui/react-avatar": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.2.tgz", - "integrity": "sha512-GaC7bXQZ5VgZvVvsJ5mu/AEbjYLnhhkoidOboC50Z6FFlLA03wG2ianUoH+zgDQ31/9gCF59bE4+2bBgTyMiig==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.3.tgz", + "integrity": "sha512-Paen00T4P8L8gd9bNsRMw7Cbaz85oxiv+hzomsRZgFm2byltPFDtfcoqlWJ8GyZlIBWgLssJlzLCnKU0G0302g==", + "license": "MIT", "dependencies": { "@radix-ui/react-context": "1.1.1", - "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0" }, @@ -4543,16 +4544,16 @@ } }, "node_modules/@radix-ui/react-checkbox": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.1.3.tgz", - "integrity": "sha512-HD7/ocp8f1B3e6OHygH0n7ZKjONkhciy1Nh0yuBgObqThc3oyx+vuMfFHKAknXRHHWVE9XvXStxJFyjUmB8PIw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.1.4.tgz", + "integrity": "sha512-wP0CPAHq+P5I4INKe3hJrIa1WoNqqrejzW+zoU0rOvo1b9gDEJJFl2rYfO1PYJUQCc2H1WZxIJmyv9BS8i5fLw==", "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-presence": "1.1.2", - "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-previous": "1.1.0", "@radix-ui/react-use-size": "1.1.0" @@ -4573,9 +4574,9 @@ } }, "node_modules/@radix-ui/react-collapsible": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.2.tgz", - "integrity": "sha512-PliMB63vxz7vggcyq0IxNYk8vGDrLXVWw4+W4B8YnwI1s18x7YZYqlG9PLX7XxAJUi0g2DxP4XKJMFHh/iVh9A==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.3.tgz", + "integrity": "sha512-jFSerheto1X03MUC0g6R7LedNW9EEGWdg9W1+MlpkMLwGkgkbUXLPBH/KIuWKXUoeYRVY11llqbTBDzuLg7qrw==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.1", @@ -4583,7 +4584,7 @@ "@radix-ui/react-context": "1.1.1", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-presence": "1.1.2", - "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0" }, @@ -4603,15 +4604,15 @@ } }, "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==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.2.tgz", + "integrity": "sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==", "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" + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-slot": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -4659,25 +4660,25 @@ } }, "node_modules/@radix-ui/react-dialog": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.5.tgz", - "integrity": "sha512-LaO3e5h/NOEL4OfXjxD43k9Dx+vn+8n+PCFt6uhX/BADFflllyv3WJG6rgvvSVBxpTch938Qq/LGc2MMxipXPw==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.6.tgz", + "integrity": "sha512-/IVhJV5AceX620DUJ4uYVMymzsipdKBzo3edo+omeskCKGm9FRHM0ebIdbPnlQVJqyuHbuBltQUOG2mOTq2IYw==", "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.4", + "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-focus-guards": "1.1.1", - "@radix-ui/react-focus-scope": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.2", "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-portal": "1.1.3", + "@radix-ui/react-portal": "1.1.4", "@radix-ui/react-presence": "1.1.2", - "@radix-ui/react-primitive": "2.0.1", - "@radix-ui/react-slot": "1.1.1", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-slot": "1.1.2", "@radix-ui/react-use-controllable-state": "1.1.0", "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.2" + "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", @@ -4710,14 +4711,14 @@ } }, "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.4.tgz", - "integrity": "sha512-XDUI0IVYVSwjMXxM6P4Dfti7AH+Y4oS/TB+sglZ/EXc7cqLwGAmp1NlMrcUjj7ks6R5WTZuWKv44FBbLpwU3sA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz", + "integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==", "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-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-escape-keydown": "1.1.0" }, @@ -4737,17 +4738,17 @@ } }, "node_modules/@radix-ui/react-dropdown-menu": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.5.tgz", - "integrity": "sha512-50ZmEFL1kOuLalPKHrLWvPFMons2fGx9TqQCWlPwDVpbAnaUJ1g4XNcKqFNMQymYU0kKWR4MDDi+9vUQBGFgcQ==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.6.tgz", + "integrity": "sha512-no3X7V5fD487wab/ZYSHXq3H37u4NVeLDKI/Ks724X/eEFSSEFYZxWgsIlr1UBeEyDaM29HM5x9p1Nv8DuTYPA==", "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-id": "1.1.0", - "@radix-ui/react-menu": "2.1.5", - "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-menu": "2.1.6", + "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0" }, "peerDependencies": { @@ -4781,13 +4782,13 @@ } }, "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==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.2.tgz", + "integrity": "sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.1", - "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { @@ -4833,12 +4834,12 @@ } }, "node_modules/@radix-ui/react-label": { - "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==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.2.tgz", + "integrity": "sha512-zo1uGMTaNlHehDyFQcDZXRJhUPDuukcnHz0/jnrup0JA6qL+AFpAnty+7VKa9esuU5xTblAZzTGYJKSKaBxBhw==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.0.1" + "@radix-ui/react-primitive": "2.0.2" }, "peerDependencies": { "@types/react": "*", @@ -4856,29 +4857,29 @@ } }, "node_modules/@radix-ui/react-menu": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.5.tgz", - "integrity": "sha512-uH+3w5heoMJtqVCgYOtYVMECk1TOrkUn0OG0p5MqXC0W2ppcuVeESbou8PTHoqAjbdTEK19AGXBWcEtR5WpEQg==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.6.tgz", + "integrity": "sha512-tBBb5CXDJW3t2mo9WlO7r6GTmWV0F0uzHZVFmlRmYpiSK1CDU5IKojP1pm7oknpBOrFZx/YgBRW9oorPO2S/Lg==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.1", - "@radix-ui/react-collection": "1.1.1", + "@radix-ui/react-collection": "1.1.2", "@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-dismissable-layer": "1.1.4", + "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-focus-guards": "1.1.1", - "@radix-ui/react-focus-scope": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.2", "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-popper": "1.2.1", - "@radix-ui/react-portal": "1.1.3", + "@radix-ui/react-popper": "1.2.2", + "@radix-ui/react-portal": "1.1.4", "@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-primitive": "2.0.2", + "@radix-ui/react-roving-focus": "1.1.2", + "@radix-ui/react-slot": "1.1.2", "@radix-ui/react-use-callback-ref": "1.1.0", "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.2" + "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", @@ -4896,20 +4897,20 @@ } }, "node_modules/@radix-ui/react-menubar": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.5.tgz", - "integrity": "sha512-Kzbpcf2bxUmI/G+949+LvSvGkyzIaY7ctb8loydt6YpJR8pQF+j4QbVhYvjs7qxaWK0DEJL3XbP2p46YPRkS3A==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.6.tgz", + "integrity": "sha512-FHq7+3DlXwh/7FOM4i0G4bC4vPjiq89VEEvNF4VMLchGnaUuUbE5uKXMUCjdKaOghEEMeiKa5XCa2Pk4kteWmg==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.1", - "@radix-ui/react-collection": "1.1.1", + "@radix-ui/react-collection": "1.1.2", "@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-menu": "2.1.5", - "@radix-ui/react-primitive": "2.0.1", - "@radix-ui/react-roving-focus": "1.1.1", + "@radix-ui/react-menu": "2.1.6", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-roving-focus": "1.1.2", "@radix-ui/react-use-controllable-state": "1.1.0" }, "peerDependencies": { @@ -4928,26 +4929,26 @@ } }, "node_modules/@radix-ui/react-popover": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.5.tgz", - "integrity": "sha512-YXkTAftOIW2Bt3qKH8vYr6n9gCkVrvyvfiTObVjoHVTHnNj26rmvO87IKa3VgtgCjb8FAQ6qOjNViwl+9iIzlg==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.6.tgz", + "integrity": "sha512-NQouW0x4/GnkFJ/pRqsIS3rM/k97VzKnVb2jB7Gq7VEGPy5g7uNV1ykySFt7eWSp3i2uSGFwaJcvIRJBAHmmFg==", "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.4", + "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-focus-guards": "1.1.1", - "@radix-ui/react-focus-scope": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.2", "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-popper": "1.2.1", - "@radix-ui/react-portal": "1.1.3", + "@radix-ui/react-popper": "1.2.2", + "@radix-ui/react-portal": "1.1.4", "@radix-ui/react-presence": "1.1.2", - "@radix-ui/react-primitive": "2.0.1", - "@radix-ui/react-slot": "1.1.1", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-slot": "1.1.2", "@radix-ui/react-use-controllable-state": "1.1.0", "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.2" + "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", @@ -4965,16 +4966,16 @@ } }, "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==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.2.tgz", + "integrity": "sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==", "license": "MIT", "dependencies": { "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.1", + "@radix-ui/react-arrow": "1.1.2", "@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-primitive": "2.0.2", "@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", @@ -4997,12 +4998,12 @@ } }, "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==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz", + "integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { @@ -5045,12 +5046,12 @@ } }, "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==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz", + "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.1.1" + "@radix-ui/react-slot": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -5068,13 +5069,13 @@ } }, "node_modules/@radix-ui/react-progress": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.1.tgz", - "integrity": "sha512-6diOawA84f/eMxFHcWut0aE1C2kyE9dOyCTQOMRR2C/qPiXz/X0SaiA/RLbapQaXUCmy0/hLMf9meSccD1N0pA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.2.tgz", + "integrity": "sha512-u1IgJFQ4zNAUTjGdDL5dcl/U8ntOR6jsnhxKb5RKp5Ozwl88xKR9EqRZOe/Mk8tnx0x5tNUe2F+MzsyjqMg0MA==", "license": "MIT", "dependencies": { "@radix-ui/react-context": "1.1.1", - "@radix-ui/react-primitive": "2.0.1" + "@radix-ui/react-primitive": "2.0.2" }, "peerDependencies": { "@types/react": "*", @@ -5092,9 +5093,9 @@ } }, "node_modules/@radix-ui/react-radio-group": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.2.2.tgz", - "integrity": "sha512-E0MLLGfOP0l8P/NxgVzfXJ8w3Ch8cdO6UDzJfDChu4EJDy+/WdO5LqpdY8PYnCErkmZH3gZhDL1K7kQ41fAHuQ==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.2.3.tgz", + "integrity": "sha512-xtCsqt8Rp09FK50ItqEqTJ7Sxanz8EM8dnkVIhJrc/wkMMomSmXHvYbhv3E7Zx4oXh98aaLt9W679SUYXg4IDA==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.1", @@ -5102,8 +5103,8 @@ "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@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-primitive": "2.0.2", + "@radix-ui/react-roving-focus": "1.1.2", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-previous": "1.1.0", "@radix-ui/react-use-size": "1.1.0" @@ -5124,18 +5125,18 @@ } }, "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==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.2.tgz", + "integrity": "sha512-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.1", - "@radix-ui/react-collection": "1.1.1", + "@radix-ui/react-collection": "1.1.2", "@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.1", + "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-controllable-state": "1.1.0" }, @@ -5155,9 +5156,9 @@ } }, "node_modules/@radix-ui/react-scroll-area": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.2.tgz", - "integrity": "sha512-EFI1N/S3YxZEW/lJ/H1jY3njlvTd8tBmgKEn4GHi51+aMm94i6NmAJstsm5cu3yJwYqYc93gpCPm21FeAbFk6g==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.3.tgz", + "integrity": "sha512-l7+NNBfBYYJa9tNqVcP2AGvxdE3lmE6kFTBXdvHgUaZuy+4wGCL1Cl2AfaR7RKyimj7lZURGLwFO59k4eBnDJQ==", "license": "MIT", "dependencies": { "@radix-ui/number": "1.1.0", @@ -5166,7 +5167,7 @@ "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-presence": "1.1.2", - "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0" }, @@ -5186,32 +5187,32 @@ } }, "node_modules/@radix-ui/react-select": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.5.tgz", - "integrity": "sha512-eVV7N8jBXAXnyrc+PsOF89O9AfVgGnbLxUtBb0clJ8y8ENMWLARGMI/1/SBRLz7u4HqxLgN71BJ17eono3wcjA==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.6.tgz", + "integrity": "sha512-T6ajELxRvTuAMWH0YmRJ1qez+x4/7Nq7QIx7zJ0VK3qaEWdnWpNbEDnmWldG1zBDwqrLy5aLMUWcoGirVj5kMg==", "license": "MIT", "dependencies": { "@radix-ui/number": "1.1.0", "@radix-ui/primitive": "1.1.1", - "@radix-ui/react-collection": "1.1.1", + "@radix-ui/react-collection": "1.1.2", "@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-dismissable-layer": "1.1.4", + "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-focus-guards": "1.1.1", - "@radix-ui/react-focus-scope": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.2", "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-popper": "1.2.1", - "@radix-ui/react-portal": "1.1.3", - "@radix-ui/react-primitive": "2.0.1", - "@radix-ui/react-slot": "1.1.1", + "@radix-ui/react-popper": "1.2.2", + "@radix-ui/react-portal": "1.1.4", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-slot": "1.1.2", "@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-use-previous": "1.1.0", - "@radix-ui/react-visually-hidden": "1.1.1", + "@radix-ui/react-visually-hidden": "1.1.2", "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.2" + "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", @@ -5229,12 +5230,12 @@ } }, "node_modules/@radix-ui/react-separator": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.1.tgz", - "integrity": "sha512-RRiNRSrD8iUiXriq/Y5n4/3iE8HzqgLHsusUSg5jVpU2+3tqcUFPJXHDymwEypunc2sWxDUS3UC+rkZRlHedsw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.2.tgz", + "integrity": "sha512-oZfHcaAp2Y6KFBX6I5P1u7CQoy4lheCGiYj+pGFrHy8E/VNRb5E39TkTr3JrV520csPBTZjkuKFdEsjS5EUNKQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.0.1" + "@radix-ui/react-primitive": "2.0.2" }, "peerDependencies": { "@types/react": "*", @@ -5252,18 +5253,18 @@ } }, "node_modules/@radix-ui/react-slider": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.2.2.tgz", - "integrity": "sha512-sNlU06ii1/ZcbHf8I9En54ZPW0Vil/yPVg4vQMcFNjrIx51jsHbFl1HYHQvCIWJSr1q0ZmA+iIs/ZTv8h7HHSA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.2.3.tgz", + "integrity": "sha512-nNrLAWLjGESnhqBqcCNW4w2nn7LxudyMzeB6VgdyAnFLC6kfQgnAjSL2v6UkQTnDctJBlxrmxfplWS4iYjdUTw==", "license": "MIT", "dependencies": { "@radix-ui/number": "1.1.0", "@radix-ui/primitive": "1.1.1", - "@radix-ui/react-collection": "1.1.1", + "@radix-ui/react-collection": "1.1.2", "@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-primitive": "2.0.1", + "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0", "@radix-ui/react-use-previous": "1.1.0", @@ -5285,9 +5286,9 @@ } }, "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==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz", + "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.1" @@ -5303,15 +5304,15 @@ } }, "node_modules/@radix-ui/react-switch": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.1.2.tgz", - "integrity": "sha512-zGukiWHjEdBCRyXvKR6iXAQG6qXm2esuAD6kDOi9Cn+1X6ev3ASo4+CsYaD6Fov9r/AQFekqnD/7+V0Cs6/98g==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.1.3.tgz", + "integrity": "sha512-1nc+vjEOQkJVsJtWPSiISGT6OKm4SiOdjMo+/icLxo2G4vxz1GntC5MzfL4v8ey9OEfw787QCD1y3mUv0NiFEQ==", "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-primitive": "2.0.1", + "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-previous": "1.1.0", "@radix-ui/react-use-size": "1.1.0" @@ -5332,9 +5333,9 @@ } }, "node_modules/@radix-ui/react-tabs": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.2.tgz", - "integrity": "sha512-9u/tQJMcC2aGq7KXpGivMm1mgq7oRJKXphDwdypPd/j21j/2znamPU8WkXgnhUaTrSFNIt8XhOyCAupg8/GbwQ==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.3.tgz", + "integrity": "sha512-9mFyI30cuRDImbmFF6O2KUJdgEOsGh9Vmx9x/Dh9tOhL7BngmQPQfwW4aejKm5OHpfWIdmeV6ySyuxoOGjtNng==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.1", @@ -5342,8 +5343,8 @@ "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-id": "1.1.0", "@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-primitive": "2.0.2", + "@radix-ui/react-roving-focus": "1.1.2", "@radix-ui/react-use-controllable-state": "1.1.0" }, "peerDependencies": { @@ -5362,23 +5363,23 @@ } }, "node_modules/@radix-ui/react-toast": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.5.tgz", - "integrity": "sha512-ZzUsAaOx8NdXZZKcFNDhbSlbsCUy8qQWmzTdgrlrhhZAOx2ofLtKrBDW9fkqhFvXgmtv560Uj16pkLkqML7SHA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.6.tgz", + "integrity": "sha512-gN4dpuIVKEgpLn1z5FhzT9mYRUitbfZq9XqN/7kkBMUgFTzTG8x/KszWJugJXHcwxckY8xcKDZPz7kG3o6DsUA==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.1", - "@radix-ui/react-collection": "1.1.1", + "@radix-ui/react-collection": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.4", - "@radix-ui/react-portal": "1.1.3", + "@radix-ui/react-dismissable-layer": "1.1.5", + "@radix-ui/react-portal": "1.1.4", "@radix-ui/react-presence": "1.1.2", - "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-primitive": "2.0.2", "@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" + "@radix-ui/react-visually-hidden": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -5396,23 +5397,23 @@ } }, "node_modules/@radix-ui/react-tooltip": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.7.tgz", - "integrity": "sha512-ss0s80BC0+g0+Zc53MvilcnTYSOi4mSuFWBPYPuTOFGjx+pUU+ZrmamMNwS56t8MTFlniA5ocjd4jYm/CdhbOg==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.8.tgz", + "integrity": "sha512-YAA2cu48EkJZdAMHC0dqo9kialOcRStbtiY4nJPaht7Ptrhcvpo+eDChaM6BIs8kL6a8Z5l5poiqLnXcNduOkA==", "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.4", + "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-popper": "1.2.1", - "@radix-ui/react-portal": "1.1.3", + "@radix-ui/react-popper": "1.2.2", + "@radix-ui/react-portal": "1.1.4", "@radix-ui/react-presence": "1.1.2", - "@radix-ui/react-primitive": "2.0.1", - "@radix-ui/react-slot": "1.1.1", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-slot": "1.1.2", "@radix-ui/react-use-controllable-state": "1.1.0", - "@radix-ui/react-visually-hidden": "1.1.1" + "@radix-ui/react-visually-hidden": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -5547,12 +5548,12 @@ } }, "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==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.2.tgz", + "integrity": "sha512-1SzA4ns2M1aRlvxErqhLHsBHoS5eI5UUcI2awAMgGUp4LoaoWOKYmvqDY2s/tltuPkh3Yk77YF/r3IRj+Amx4Q==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.0.1" + "@radix-ui/react-primitive": "2.0.2" }, "peerDependencies": { "@types/react": "*", @@ -5875,9 +5876,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.32.1.tgz", - "integrity": "sha512-tZWc9iEt5fGJ1CL2LRPw8OttkCBDs+D8D3oEM8mH8S1ICZCtFJhD7DZ3XMGM8kpqHvhGUTvNUYVDnmkj4BDXnw==", + "version": "4.34.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.4.tgz", + "integrity": "sha512-7CwSJW+sEhM9sESEk+pEREF2JL0BmyCro8UyTq0Kyh0nu1v0QPNY3yfLPFKChzVoUmaKj8zbdgBxUhBRR+xGxg==", "cpu": [ "arm64" ], @@ -5953,9 +5954,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.32.1.tgz", - "integrity": "sha512-WQFLZ9c42ECqEjwg/GHHsouij3pzLXkFdz0UxHa/0OM12LzvX7DzedlY0SIEly2v18YZLRhCRoHZDxbBSWoGYg==", + "version": "4.34.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.4.tgz", + "integrity": "sha512-JGejzEfVzqc/XNiCKZj14eb6s5w8DdWlnQ5tWUbs99kkdvfq9btxxVX97AaxiUX7xJTKFA0LwoS0KU8C2faZRg==", "cpu": [ "x64" ], @@ -6018,50 +6019,50 @@ ] }, "node_modules/@sentry-internal/browser-utils": { - "version": "8.53.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.53.0.tgz", - "integrity": "sha512-TmW/UFtVm1I9tCCtRIGO3chuCVFE3jxOoV/q1HYiB+5rYk3ljVFxkUoch83IVMLJWz2hZtagKDaFoPhq65KSyQ==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.54.0.tgz", + "integrity": "sha512-DKWCqb4YQosKn6aD45fhKyzhkdG7N6goGFDeyTaJFREJDFVDXiNDsYZu30nJ6BxMM7uQIaARhPAC5BXfoED3pQ==", "license": "MIT", "dependencies": { - "@sentry/core": "8.53.0" + "@sentry/core": "8.54.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/feedback": { - "version": "8.53.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.53.0.tgz", - "integrity": "sha512-ZGqcxExSlezdy6gPu7ztvfrrgeUYYxvl90SC5cnNSAduNH4uHGySmYVLmCpz3HLkkYRGX7Na21A7Gx6ZLXLygw==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.54.0.tgz", + "integrity": "sha512-nQqRacOXoElpE0L0ADxUUII0I3A94niqG9Z4Fmsw6057QvyrV/LvTiMQBop6r5qLjwMqK+T33iR4/NQI5RhsXQ==", "license": "MIT", "dependencies": { - "@sentry/core": "8.53.0" + "@sentry/core": "8.54.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/replay": { - "version": "8.53.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.53.0.tgz", - "integrity": "sha512-aFhJYK2Ky1ByIXooYep13skE8yaHtEIfjA0cFY6UsU9nDR3woxv3CtXOH+le2y9lmZSbNNFcpFfAGEMgryM8zQ==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.54.0.tgz", + "integrity": "sha512-8xuBe06IaYIGJec53wUC12tY2q4z2Z0RPS2s1sLtbA00EvK1YDGuXp96IDD+HB9mnDMrQ/jW5f97g9TvPsPQUg==", "license": "MIT", "dependencies": { - "@sentry-internal/browser-utils": "8.53.0", - "@sentry/core": "8.53.0" + "@sentry-internal/browser-utils": "8.54.0", + "@sentry/core": "8.54.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/replay-canvas": { - "version": "8.53.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.53.0.tgz", - "integrity": "sha512-DvXf+gutg31O+VyuMhPIPF8wbWLrtWsyn+6npE32SdThRKp4YJdXdWRtinI9Y5VN0AR89saX2zFNqzCySzFZ7Q==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.54.0.tgz", + "integrity": "sha512-K/On3OAUBeq/TV2n+1EvObKC+WMV9npVXpVyJqCCyn8HYMm8FUGzuxeajzm0mlW4wDTPCQor6mK9/IgOquUzCw==", "license": "MIT", "dependencies": { - "@sentry-internal/replay": "8.53.0", - "@sentry/core": "8.53.0" + "@sentry-internal/replay": "8.54.0", + "@sentry/core": "8.54.0" }, "engines": { "node": ">=14.18" @@ -6097,25 +6098,25 @@ } }, "node_modules/@sentry/browser": { - "version": "8.53.0", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.53.0.tgz", - "integrity": "sha512-EUipXIq5Os5w1o17AAMg5Uy9wC2ah7WYbaBZjAyaxdXF7sMWF1OWwUo7BZxbYF44nvxZ69j+pjBKwqicjiJhcQ==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.54.0.tgz", + "integrity": "sha512-BgUtvxFHin0fS0CmJVKTLXXZcke0Av729IVfi+2fJ4COX8HO7/HAP02RKaSQGmL2HmvWYTfNZ7529AnUtrM4Rg==", "license": "MIT", "dependencies": { - "@sentry-internal/browser-utils": "8.53.0", - "@sentry-internal/feedback": "8.53.0", - "@sentry-internal/replay": "8.53.0", - "@sentry-internal/replay-canvas": "8.53.0", - "@sentry/core": "8.53.0" + "@sentry-internal/browser-utils": "8.54.0", + "@sentry-internal/feedback": "8.54.0", + "@sentry-internal/replay": "8.54.0", + "@sentry-internal/replay-canvas": "8.54.0", + "@sentry/core": "8.54.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry/core": { - "version": "8.53.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.53.0.tgz", - "integrity": "sha512-u6p5JeGSgvcoDqVcPve2gcJuhks8EQXPELzeYKuW3rHpsUfkLG6X5RVtk32dKOqqL2qzvMelnknBN7tyIf5PiA==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.54.0.tgz", + "integrity": "sha512-03bWf+D1j28unOocY/5FDB6bUHtYlm6m6ollVejhg45ZmK9iPjdtxNWbrLsjT1WRym0Tjzowu+A3p+eebYEv0Q==", "license": "MIT", "engines": { "node": ">=14.18" @@ -6614,9 +6615,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.13.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.0.tgz", - "integrity": "sha512-ClIbNe36lawluuvq3+YYhnIN2CELi+6q8NpnM7PYp4hBn/TatfboPgVSm2rwKRfnV2M+Ty9GWDFI64KEe+kysA==", + "version": "22.13.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.1.tgz", + "integrity": "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6739,21 +6740,21 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.22.0.tgz", - "integrity": "sha512-4Uta6REnz/xEJMvwf72wdUnC3rr4jAQf5jnTkeRQ9b6soxLxhDEbS/pfMPoJLDfFPNVRdryqWUIV/2GZzDJFZw==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.23.0.tgz", + "integrity": "sha512-vBz65tJgRrA1Q5gWlRfvoH+w943dq9K1p1yDBY2pc+a1nbBLZp7fB9+Hk8DaALUbzjqlMfgaqlVPT1REJdkt/w==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.22.0", - "@typescript-eslint/type-utils": "8.22.0", - "@typescript-eslint/utils": "8.22.0", - "@typescript-eslint/visitor-keys": "8.22.0", + "@typescript-eslint/scope-manager": "8.23.0", + "@typescript-eslint/type-utils": "8.23.0", + "@typescript-eslint/utils": "8.23.0", + "@typescript-eslint/visitor-keys": "8.23.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.0.0" + "ts-api-utils": "^2.0.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6769,9 +6770,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.22.0.tgz", - "integrity": "sha512-0S4M4baNzp612zwpD4YOieP3VowOARgK2EkN/GBn95hpyF8E2fbMT55sRHWBq+Huaqk3b3XK+rxxlM8sPgGM6A==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.23.0.tgz", + "integrity": "sha512-1sK4ILJbCmZOTt9k4vkoulT6/y5CHJ1qUYxqpF1K/DBAd8+ZUL4LlSCxOssuH5m4rUaaN0uS0HlVPvd45zjduQ==", "dev": true, "license": "MIT", "engines": { @@ -6783,13 +6784,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.22.0.tgz", - "integrity": "sha512-AWpYAXnUgvLNabGTy3uBylkgZoosva/miNd1I8Bz3SjotmQPbVqhO4Cczo8AsZ44XVErEBPr/CRSgaj8sG7g0w==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.23.0.tgz", + "integrity": "sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.22.0", + "@typescript-eslint/types": "8.23.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -6814,9 +6815,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/ts-api-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz", - "integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", + "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", "dev": true, "license": "MIT", "engines": { @@ -6827,16 +6828,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.22.0.tgz", - "integrity": "sha512-MqtmbdNEdoNxTPzpWiWnqNac54h8JDAmkWtJExBVVnSrSmi9z+sZUt0LfKqk9rjqmKOIeRhO4fHHJ1nQIjduIQ==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.23.0.tgz", + "integrity": "sha512-h2lUByouOXFAlMec2mILeELUbME5SZRN/7R9Cw2RD2lRQQY08MWMM+PmVVKKJNK1aIwqTo9t/0CvOxwPbRIE2Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.22.0", - "@typescript-eslint/types": "8.22.0", - "@typescript-eslint/typescript-estree": "8.22.0", - "@typescript-eslint/visitor-keys": "8.22.0", + "@typescript-eslint/scope-manager": "8.23.0", + "@typescript-eslint/types": "8.23.0", + "@typescript-eslint/typescript-estree": "8.23.0", + "@typescript-eslint/visitor-keys": "8.23.0", "debug": "^4.3.4" }, "engines": { @@ -6852,9 +6853,9 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.22.0.tgz", - "integrity": "sha512-0S4M4baNzp612zwpD4YOieP3VowOARgK2EkN/GBn95hpyF8E2fbMT55sRHWBq+Huaqk3b3XK+rxxlM8sPgGM6A==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.23.0.tgz", + "integrity": "sha512-1sK4ILJbCmZOTt9k4vkoulT6/y5CHJ1qUYxqpF1K/DBAd8+ZUL4LlSCxOssuH5m4rUaaN0uS0HlVPvd45zjduQ==", "dev": true, "license": "MIT", "engines": { @@ -6866,20 +6867,20 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.22.0.tgz", - "integrity": "sha512-SJX99NAS2ugGOzpyhMza/tX+zDwjvwAtQFLsBo3GQxiGcvaKlqGBkmZ+Y1IdiSi9h4Q0Lr5ey+Cp9CGWNY/F/w==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.23.0.tgz", + "integrity": "sha512-LcqzfipsB8RTvH8FX24W4UUFk1bl+0yTOf9ZA08XngFwMg4Kj8A+9hwz8Cr/ZS4KwHrmo9PJiLZkOt49vPnuvQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.22.0", - "@typescript-eslint/visitor-keys": "8.22.0", + "@typescript-eslint/types": "8.23.0", + "@typescript-eslint/visitor-keys": "8.23.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^2.0.0" + "ts-api-utils": "^2.0.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6893,13 +6894,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.22.0.tgz", - "integrity": "sha512-AWpYAXnUgvLNabGTy3uBylkgZoosva/miNd1I8Bz3SjotmQPbVqhO4Cczo8AsZ44XVErEBPr/CRSgaj8sG7g0w==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.23.0.tgz", + "integrity": "sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.22.0", + "@typescript-eslint/types": "8.23.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -6924,9 +6925,9 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/ts-api-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz", - "integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", + "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", "dev": true, "license": "MIT", "engines": { @@ -6937,14 +6938,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.22.0.tgz", - "integrity": "sha512-/lwVV0UYgkj7wPSw0o8URy6YI64QmcOdwHuGuxWIYznO6d45ER0wXUbksr9pYdViAofpUCNJx/tAzNukgvaaiQ==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.23.0.tgz", + "integrity": "sha512-OGqo7+dXHqI7Hfm+WqkZjKjsiRtFUQHPdGMXzk5mYXhJUedO7e/Y7i8AK3MyLMgZR93TX4bIzYrfyVjLC+0VSw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.22.0", - "@typescript-eslint/visitor-keys": "8.22.0" + "@typescript-eslint/types": "8.23.0", + "@typescript-eslint/visitor-keys": "8.23.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6955,9 +6956,9 @@ } }, "node_modules/@typescript-eslint/scope-manager/node_modules/@typescript-eslint/types": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.22.0.tgz", - "integrity": "sha512-0S4M4baNzp612zwpD4YOieP3VowOARgK2EkN/GBn95hpyF8E2fbMT55sRHWBq+Huaqk3b3XK+rxxlM8sPgGM6A==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.23.0.tgz", + "integrity": "sha512-1sK4ILJbCmZOTt9k4vkoulT6/y5CHJ1qUYxqpF1K/DBAd8+ZUL4LlSCxOssuH5m4rUaaN0uS0HlVPvd45zjduQ==", "dev": true, "license": "MIT", "engines": { @@ -6969,13 +6970,13 @@ } }, "node_modules/@typescript-eslint/scope-manager/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.22.0.tgz", - "integrity": "sha512-AWpYAXnUgvLNabGTy3uBylkgZoosva/miNd1I8Bz3SjotmQPbVqhO4Cczo8AsZ44XVErEBPr/CRSgaj8sG7g0w==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.23.0.tgz", + "integrity": "sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.22.0", + "@typescript-eslint/types": "8.23.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -7000,16 +7001,16 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.22.0.tgz", - "integrity": "sha512-NzE3aB62fDEaGjaAYZE4LH7I1MUwHooQ98Byq0G0y3kkibPJQIXVUspzlFOmOfHhiDLwKzMlWxaNv+/qcZurJA==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.23.0.tgz", + "integrity": "sha512-iIuLdYpQWZKbiH+RkCGc6iu+VwscP5rCtQ1lyQ7TYuKLrcZoeJVpcLiG8DliXVkUxirW/PWlmS+d6yD51L9jvA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.22.0", - "@typescript-eslint/utils": "8.22.0", + "@typescript-eslint/typescript-estree": "8.23.0", + "@typescript-eslint/utils": "8.23.0", "debug": "^4.3.4", - "ts-api-utils": "^2.0.0" + "ts-api-utils": "^2.0.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7024,9 +7025,9 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.22.0.tgz", - "integrity": "sha512-0S4M4baNzp612zwpD4YOieP3VowOARgK2EkN/GBn95hpyF8E2fbMT55sRHWBq+Huaqk3b3XK+rxxlM8sPgGM6A==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.23.0.tgz", + "integrity": "sha512-1sK4ILJbCmZOTt9k4vkoulT6/y5CHJ1qUYxqpF1K/DBAd8+ZUL4LlSCxOssuH5m4rUaaN0uS0HlVPvd45zjduQ==", "dev": true, "license": "MIT", "engines": { @@ -7038,20 +7039,20 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.22.0.tgz", - "integrity": "sha512-SJX99NAS2ugGOzpyhMza/tX+zDwjvwAtQFLsBo3GQxiGcvaKlqGBkmZ+Y1IdiSi9h4Q0Lr5ey+Cp9CGWNY/F/w==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.23.0.tgz", + "integrity": "sha512-LcqzfipsB8RTvH8FX24W4UUFk1bl+0yTOf9ZA08XngFwMg4Kj8A+9hwz8Cr/ZS4KwHrmo9PJiLZkOt49vPnuvQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.22.0", - "@typescript-eslint/visitor-keys": "8.22.0", + "@typescript-eslint/types": "8.23.0", + "@typescript-eslint/visitor-keys": "8.23.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^2.0.0" + "ts-api-utils": "^2.0.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7065,13 +7066,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.22.0.tgz", - "integrity": "sha512-AWpYAXnUgvLNabGTy3uBylkgZoosva/miNd1I8Bz3SjotmQPbVqhO4Cczo8AsZ44XVErEBPr/CRSgaj8sG7g0w==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.23.0.tgz", + "integrity": "sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.22.0", + "@typescript-eslint/types": "8.23.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -7096,9 +7097,9 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/ts-api-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz", - "integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", + "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", "dev": true, "license": "MIT", "engines": { @@ -7152,16 +7153,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.22.0.tgz", - "integrity": "sha512-T8oc1MbF8L+Bk2msAvCUzjxVB2Z2f+vXYfcucE2wOmYs7ZUwco5Ep0fYZw8quNwOiw9K8GYVL+Kgc2pETNTLOg==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.23.0.tgz", + "integrity": "sha512-uB/+PSo6Exu02b5ZEiVtmY6RVYO7YU5xqgzTIVZwTHvvK3HsL8tZZHFaTLFtRG3CsV4A5mhOv+NZx5BlhXPyIA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.22.0", - "@typescript-eslint/types": "8.22.0", - "@typescript-eslint/typescript-estree": "8.22.0" + "@typescript-eslint/scope-manager": "8.23.0", + "@typescript-eslint/types": "8.23.0", + "@typescript-eslint/typescript-estree": "8.23.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7176,9 +7177,9 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.22.0.tgz", - "integrity": "sha512-0S4M4baNzp612zwpD4YOieP3VowOARgK2EkN/GBn95hpyF8E2fbMT55sRHWBq+Huaqk3b3XK+rxxlM8sPgGM6A==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.23.0.tgz", + "integrity": "sha512-1sK4ILJbCmZOTt9k4vkoulT6/y5CHJ1qUYxqpF1K/DBAd8+ZUL4LlSCxOssuH5m4rUaaN0uS0HlVPvd45zjduQ==", "dev": true, "license": "MIT", "engines": { @@ -7190,20 +7191,20 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.22.0.tgz", - "integrity": "sha512-SJX99NAS2ugGOzpyhMza/tX+zDwjvwAtQFLsBo3GQxiGcvaKlqGBkmZ+Y1IdiSi9h4Q0Lr5ey+Cp9CGWNY/F/w==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.23.0.tgz", + "integrity": "sha512-LcqzfipsB8RTvH8FX24W4UUFk1bl+0yTOf9ZA08XngFwMg4Kj8A+9hwz8Cr/ZS4KwHrmo9PJiLZkOt49vPnuvQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.22.0", - "@typescript-eslint/visitor-keys": "8.22.0", + "@typescript-eslint/types": "8.23.0", + "@typescript-eslint/visitor-keys": "8.23.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^2.0.0" + "ts-api-utils": "^2.0.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7217,13 +7218,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.22.0.tgz", - "integrity": "sha512-AWpYAXnUgvLNabGTy3uBylkgZoosva/miNd1I8Bz3SjotmQPbVqhO4Cczo8AsZ44XVErEBPr/CRSgaj8sG7g0w==", + "version": "8.23.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.23.0.tgz", + "integrity": "sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.22.0", + "@typescript-eslint/types": "8.23.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -7248,9 +7249,9 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/ts-api-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz", - "integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", + "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", "dev": true, "license": "MIT", "engines": { @@ -8794,9 +8795,9 @@ "license": "MIT" }, "node_modules/cypress": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-14.0.1.tgz", - "integrity": "sha512-gBAvKZE3f6eBaW1v8OtrwAFP90rjNZjjOO40M2KvOvmwVXk96Ps5Yjyck1EzGkXmNCaC/8kXFOY/1KD/wsaWpQ==", + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-14.0.2.tgz", + "integrity": "sha512-3qqTU2JoVY262qkYg9I2nohwxcfsJk0dSVp/LXAjD94Jz2y6411Mf/l5uHEHiaANrOmMcHbzYgOd/ueDsZlS7A==", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -15533,16 +15534,16 @@ } }, "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==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.3.tgz", + "integrity": "sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==", "license": "MIT", "dependencies": { "react-remove-scroll-bar": "^2.3.7", - "react-style-singleton": "^2.2.1", + "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", - "use-sidecar": "^1.1.2" + "use-sidecar": "^1.1.3" }, "engines": { "node": ">=10" @@ -18249,9 +18250,10 @@ } }, "node_modules/unimported": { - "version": "1.31.0", - "resolved": "https://registry.npmjs.org/unimported/-/unimported-1.31.0.tgz", - "integrity": "sha512-QcbdHplhQzZfis6gs+IrbuSJ3hR7pN+w78p0WzvYwxU6SVjiwGZNOAlXbo6WFghA1MWmHPchi0L/2EfHnb549A==", + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/unimported/-/unimported-1.31.1.tgz", + "integrity": "sha512-VAElK/PkLS1qLCUDyptB7vPojaOCxdtvC8GyxF86f0qMvD5Ultoyqdormt9ndmUcQrf8j+66vqUbaB3zjtCemQ==", + "deprecated": "deprecated, please see readme for more info", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 8d2e5a37f1e..168877e8a25 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "care_fe", - "version": "2.9.0", + "version": "2.10.0", "description": "Care is a Digital Public Good enabling TeleICU & Decentralised Administration of Healthcare Capacity across States.", "private": true, "repository": { @@ -179,8 +179,8 @@ "optionalDependencies": { "@esbuild/linux-arm64": "latest", "@esbuild/linux-x64": "latest", - "@rollup/rollup-linux-arm64-gnu": "4.32.1", - "@rollup/rollup-linux-x64-gnu": "4.32.1" + "@rollup/rollup-linux-arm64-gnu": "4.34.4", + "@rollup/rollup-linux-x64-gnu": "4.34.4" }, "browserslist": { "production": [ From 3e0bbc4ffeee3095f571a8b6f39e98d6837b7f8a Mon Sep 17 00:00:00 2001 From: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> Date: Thu, 6 Feb 2025 13:01:53 +0530 Subject: [PATCH 15/19] fixed the users fixture (#10442) --- cypress/e2e/patient_spec/patient_details.cy.ts | 2 +- cypress/fixtures/users.json | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cypress/e2e/patient_spec/patient_details.cy.ts b/cypress/e2e/patient_spec/patient_details.cy.ts index 0f8d9c897a9..35732dbecd0 100644 --- a/cypress/e2e/patient_spec/patient_details.cy.ts +++ b/cypress/e2e/patient_spec/patient_details.cy.ts @@ -8,7 +8,7 @@ const patientDetails = new PatientDetails(); describe("Patient Management", () => { beforeEach(() => { - cy.loginByApi("doctor"); + cy.loginByApi("devdoctor"); cy.visit("/"); }); diff --git a/cypress/fixtures/users.json b/cypress/fixtures/users.json index c484f51b6f2..1c3799e32ba 100644 --- a/cypress/fixtures/users.json +++ b/cypress/fixtures/users.json @@ -18,5 +18,9 @@ "devnurse": { "username": "dev-nurse", "password": "Test@123" + }, + "devdoctor": { + "username": "developdoctor", + "password": "Test@123" } } From e326a7806f946af0b12bb2082fe92d3ea1286e22 Mon Sep 17 00:00:00 2001 From: Aditya Jindal Date: Thu, 6 Feb 2025 13:03:18 +0530 Subject: [PATCH 16/19] Replace Deprecated `request` (#10352) Co-authored-by: rithviknishad --- public/locale/en.json | 3 +- public/locale/hi.json | 4 +- public/locale/kn.json | 4 +- public/locale/ml.json | 4 +- public/locale/ta.json | 4 +- src/Providers/AuthUserProvider.tsx | 99 +++++++------------ src/Utils/request/api.tsx | 8 +- src/components/Auth/Login.tsx | 20 ++-- src/components/Auth/ResetPassword.tsx | 52 +++++----- src/components/Facility/FacilityHome.tsx | 59 ++++++----- src/components/Resource/ResourceCreate.tsx | 75 +++++++------- src/components/Users/UserAvatar.tsx | 41 +++++--- src/components/Users/UserSummary.tsx | 20 ++-- src/hooks/useAuthUser.ts | 6 +- .../PublicAppointments/auth/PatientLogin.tsx | 41 +------- 15 files changed, 185 insertions(+), 255 deletions(-) diff --git a/public/locale/en.json b/public/locale/en.json index fb0e5e3381d..fb066f9d360 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -685,7 +685,6 @@ "delete_facility": "Delete Facility", "delete_item": "Delete {{name}}", "delete_record": "Delete Record", - "deleted_successfully": "{{name}} deleted successfully", "deleting": "Deleting...", "demography": "Demography", "denied_on": "Denied On", @@ -929,6 +928,7 @@ "entered_in_error_warning": "This action cannot be undone. The appointment will be marked as entered in error and removed from the system.", "entity_count_one": "{{count}} {{entity}}", "entity_count_other": "{{count}} {{entity}}s", + "entity_deleted_successfully": "{{name}} deleted successfully", "environment": "Environment", "error_404": "Error 404", "error_deleting_shifting": "Error while deleting Shifting record", @@ -937,7 +937,6 @@ "error_fetching_user_data": "Error while fetching user data", "error_fetching_user_details": "Error while fetching user details: ", "error_loading_questionnaire_response": "Error loading questionnaire response", - "error_sending_otp": "Error while sending OTP, Please try again later", "error_updating_encounter": "Error to Updating Encounter", "error_verifying_otp": "Error while verifying OTP, Please request a new OTP", "error_while_deleting_record": "Error while deleting record", diff --git a/public/locale/hi.json b/public/locale/hi.json index 28b6d1f3531..a89ae61b137 100644 --- a/public/locale/hi.json +++ b/public/locale/hi.json @@ -262,7 +262,6 @@ "delete_facility": "सुविधा हटाएं", "delete_item": "{{name}}मिटाएँ", "delete_record": "रिकॉर्ड मिटाएँ", - "deleted_successfully": "{{name}} सफलतापूर्वक हटा दिया गया", "describe_why_the_asset_is_not_working": "बताएं कि परिसंपत्ति काम क्यों नहीं कर रही है", "description": "विवरण", "details_about_the_equipment": "उपकरण के बारे में विवरण", @@ -343,6 +342,7 @@ "enter_file_name": "फ़ाइल का नाम दर्ज करें", "enter_valid_age": "कृपया वैध आयु दर्ज करें", "entered_in_error": "त्रुटिवश प्रविष्ट हुआ", + "entity_deleted_successfully": "{{name}} सफलतापूर्वक हटा दिया गया", "error_404": "त्रुटि 404", "error_deleting_shifting": "शिफ्टिंग रिकॉर्ड हटाते समय त्रुटि", "error_while_deleting_record": "रिकॉर्ड हटाते समय त्रुटि हुई", @@ -801,4 +801,4 @@ "you_need_at_least_a_location_to_create_an_assest": "संपत्ति बनाने के लिए आपको कम से कम एक स्थान की आवश्यकता होगी।", "zoom_in": "ज़ूम इन", "zoom_out": "ज़ूम आउट" -} \ No newline at end of file +} diff --git a/public/locale/kn.json b/public/locale/kn.json index 45c08a5568a..99adca4c86f 100644 --- a/public/locale/kn.json +++ b/public/locale/kn.json @@ -264,7 +264,6 @@ "delete_facility": "ಸೌಲಭ್ಯವನ್ನು ಅಳಿಸಿ", "delete_item": "{{name}}ಅಳಿಸಿ", "delete_record": "ದಾಖಲೆ ಅಳಿಸಿ", - "deleted_successfully": "{{name}} ಅನ್ನು ಯಶಸ್ವಿಯಾಗಿ ಅಳಿಸಲಾಗಿದೆ", "describe_why_the_asset_is_not_working": "ಸ್ವತ್ತು ಏಕೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತಿಲ್ಲ ಎಂಬುದನ್ನು ವಿವರಿಸಿ", "description": "ವಿವರಣೆ", "details_about_the_equipment": "ಸಲಕರಣೆಗಳ ಬಗ್ಗೆ ವಿವರಗಳು", @@ -345,6 +344,7 @@ "enter_file_name": "ಫೈಲ್ ಹೆಸರನ್ನು ನಮೂದಿಸಿ", "enter_valid_age": "ದಯವಿಟ್ಟು ಮಾನ್ಯವಾದ ವಯಸ್ಸನ್ನು ನಮೂದಿಸಿ", "entered_in_error": "ತಪ್ಪಾಗಿ ನಮೂದಿಸಲಾಗಿದೆ", + "entity_deleted_successfully": "{{name}} ಅನ್ನು ಯಶಸ್ವಿಯಾಗಿ ಅಳಿಸಲಾಗಿದೆ", "error_404": "ದೋಷ 404", "error_deleting_shifting": "ಶಿಫ್ಟಿಂಗ್ ರೆಕಾರ್ಡ್ ಅನ್ನು ಅಳಿಸುವಾಗ ದೋಷ", "error_while_deleting_record": "ದಾಖಲೆಯನ್ನು ಅಳಿಸುವಾಗ ದೋಷ", @@ -802,4 +802,4 @@ "you_need_at_least_a_location_to_create_an_assest": "ಆಸ್ತಿಯನ್ನು ರಚಿಸಲು ನಿಮಗೆ ಕನಿಷ್ಠ ಸ್ಥಳದ ಅಗತ್ಯವಿದೆ.", "zoom_in": "ಜೂಮ್ ಇನ್", "zoom_out": "ಜೂಮ್ ಔಟ್" -} \ No newline at end of file +} diff --git a/public/locale/ml.json b/public/locale/ml.json index 75579c37355..23dfa4fc05f 100644 --- a/public/locale/ml.json +++ b/public/locale/ml.json @@ -686,7 +686,6 @@ "delete_facility": "സൗകര്യം ഇല്ലാതാക്കുക", "delete_item": "{{name}}ഇല്ലാതാക്കുക", "delete_record": "റെക്കോർഡ് ഇല്ലാതാക്കുക", - "deleted_successfully": "{{name}} വിജയകരമായി ഇല്ലാതാക്കി", "demography": "ജനസംഖ്യാശാസ്ത്രം", "denied_on": "നിരസിച്ചു", "describe_why_the_asset_is_not_working": "അസറ്റ് പ്രവർത്തിക്കാത്തത് എന്തുകൊണ്ടെന്ന് വിവരിക്കുക", @@ -901,12 +900,11 @@ "enter_valid_dob": "ഒരു സാധുവായ ജനനത്തീയതി നൽകുക", "enter_valid_dob_age": "ദയവായി 15 വയസ്സിൽ കൂടുതലുള്ള ഒരു പ്രായം നൽകുക", "enter_year_of_birth_to_verify": "സ്ഥിരീകരിക്കാൻ ജനന വർഷം നൽകുക", - "entered_in_error": "തെറ്റായി നൽകി", "entered_in_error": "പിശകിൽ പ്രവേശിച്ചു", + "entity_deleted_successfully": "{{name}} വിജയകരമായി ഇല്ലാതാക്കി", "error_404": "പിശക് 404", "error_deleting_shifting": "ഷിഫ്റ്റിംഗ് റെക്കോർഡ് ഇല്ലാതാക്കുന്നതിൽ പിശക്", "error_fetching_slots_data": "സ്ലോട്ടുകൾ ഡാറ്റ ലഭ്യമാക്കുന്നതിൽ പിശക്", - "error_sending_otp": "OTP അയയ്ക്കുമ്പോൾ പിശക്, ദയവായി പിന്നീട് വീണ്ടും ശ്രമിക്കുക", "error_updating_encounter": "എൻകൗണ്ടർ അപ്‌ഡേറ്റ് ചെയ്യുന്നതിൽ പിശക്", "error_verifying_otp": "OTP പരിശോധിക്കുന്നതിൽ പിശക്, ദയവായി ഒരു പുതിയ OTP അഭ്യർത്ഥിക്കുക", "error_while_deleting_record": "റെക്കോർഡ് ഇല്ലാതാക്കുന്നതിൽ പിശക്", diff --git a/public/locale/ta.json b/public/locale/ta.json index 2813031dc81..af20a93cd08 100644 --- a/public/locale/ta.json +++ b/public/locale/ta.json @@ -263,7 +263,6 @@ "delete_facility": "நீக்கு வசதி", "delete_item": "{{name}}ஐ நீக்கவும்", "delete_record": "பதிவை நீக்கு", - "deleted_successfully": "{{name}} வெற்றிகரமாக நீக்கப்பட்டது", "describe_why_the_asset_is_not_working": "சொத்து ஏன் வேலை செய்யவில்லை என்பதை விவரிக்கவும்", "description": "விளக்கம்", "details_about_the_equipment": "உபகரணங்கள் பற்றிய விவரங்கள்", @@ -344,6 +343,7 @@ "enter_file_name": "கோப்பு பெயரை உள்ளிடவும்", "enter_valid_age": "செல்லுபடியாகும் வயதை உள்ளிடவும்", "entered_in_error": "தவறுதலாக உள்ளிடப்பட்டது", + "entity_deleted_successfully": "{{name}} வெற்றிகரமாக நீக்கப்பட்டது", "error_404": "பிழை 404", "error_deleting_shifting": "பதிவை மாற்றுவதில் பிழை", "error_while_deleting_record": "பதிவை நீக்குவதில் பிழை", @@ -801,4 +801,4 @@ "you_need_at_least_a_location_to_create_an_assest": "ஒரு அசெஸ்ட்டை உருவாக்க குறைந்தபட்சம் ஒரு இருப்பிடமாவது தேவை.", "zoom_in": "பெரிதாக்கவும்", "zoom_out": "பெரிதாக்கவும்" -} \ No newline at end of file +} diff --git a/src/Providers/AuthUserProvider.tsx b/src/Providers/AuthUserProvider.tsx index a0e9aefeac2..2a24aea06c7 100644 --- a/src/Providers/AuthUserProvider.tsx +++ b/src/Providers/AuthUserProvider.tsx @@ -1,5 +1,5 @@ import careConfig from "@careConfig"; -import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { navigate } from "raviger"; import { useCallback, useEffect, useState } from "react"; @@ -9,10 +9,9 @@ import { AuthUserContext } from "@/hooks/useAuthUser"; import { LocalStorageKeys } from "@/common/constants"; -import routes, { Type } from "@/Utils/request/api"; +import routes, { JwtTokenObtainPair, Type } from "@/Utils/request/api"; import mutate from "@/Utils/request/mutate"; import query from "@/Utils/request/query"; -import request from "@/Utils/request/request"; import { TokenData } from "@/types/auth/otpToken"; interface Props { @@ -43,38 +42,44 @@ export default function AuthUserProvider({ enabled: !!localStorage.getItem(LocalStorageKeys.accessToken), }); + const refreshToken = localStorage.getItem(LocalStorageKeys.refreshToken); + + const tokenRefreshQuery = useQuery({ + queryKey: ["user-refresh-token"], + queryFn: query(routes.token_refresh, { + body: { refresh: refreshToken || "" }, + }), + refetchInterval: careConfig.auth.tokenRefreshInterval, + enabled: !!refreshToken && !!user, + }); + useEffect(() => { - if (!user) { + if (tokenRefreshQuery.isError) { + localStorage.removeItem(LocalStorageKeys.accessToken); + localStorage.removeItem(LocalStorageKeys.refreshToken); return; } - updateRefreshToken(true); - setInterval( - () => updateRefreshToken(), - careConfig.auth.tokenRefreshInterval, - ); - }, [user]); - - const signIn = useCallback( - async (creds: { username: string; password: string }) => { - const query = await request(routes.login, { body: creds }); - - if (query.res?.ok && query.data) { - setAccessToken(query.data.access); - localStorage.setItem(LocalStorageKeys.accessToken, query.data.access); - localStorage.setItem(LocalStorageKeys.refreshToken, query.data.refresh); - - await queryClient.invalidateQueries({ queryKey: ["currentUser"] }); - - if (location.pathname === "/" || location.pathname === "/login") { - navigate(getRedirectOr("/")); - } + if (tokenRefreshQuery.data) { + const { access, refresh } = tokenRefreshQuery.data; + localStorage.setItem(LocalStorageKeys.accessToken, access); + localStorage.setItem(LocalStorageKeys.refreshToken, refresh); + } + }, [tokenRefreshQuery.data, tokenRefreshQuery.isError]); + + const { mutateAsync: signIn, isPending: isAuthenticating } = useMutation({ + mutationFn: mutate(routes.login), + onSuccess: (data: JwtTokenObtainPair) => { + setAccessToken(data.access); + localStorage.setItem(LocalStorageKeys.accessToken, data.access); + localStorage.setItem(LocalStorageKeys.refreshToken, data.refresh); + queryClient.invalidateQueries({ queryKey: ["currentUser"] }); + + if (location.pathname === "/" || location.pathname === "/login") { + navigate(getRedirectOr("/")); } - - return query; }, - [queryClient], - ); + }); const patientLogin = (tokenData: TokenData, redirectUrl: string) => { setPatientToken(tokenData); @@ -103,6 +108,7 @@ export default function AuthUserProvider({ localStorage.removeItem(LocalStorageKeys.accessToken); localStorage.removeItem(LocalStorageKeys.refreshToken); localStorage.removeItem(LocalStorageKeys.patientTokenKey); + setAccessToken(null); setPatientToken(null); await queryClient.resetQueries({ queryKey: ["currentUser"] }); @@ -138,53 +144,22 @@ export default function AuthUserProvider({ return ; } - const SelectedRouter = () => { - if (user) { - return children; - } else if (patientToken?.token) { - return otpAuthorized; - } else { - return unauthorized; - } - }; - return ( - + {user ? children : patientToken?.token ? otpAuthorized : unauthorized} ); } -const updateRefreshToken = async (silent = false) => { - const refresh = localStorage.getItem(LocalStorageKeys.refreshToken); - - if (!refresh) { - return; - } - - const { res, data } = await request(routes.token_refresh, { - body: { refresh }, - silent, - }); - - if (res?.status !== 200 || !data) { - localStorage.removeItem(LocalStorageKeys.accessToken); - localStorage.removeItem(LocalStorageKeys.refreshToken); - return; - } - - localStorage.setItem(LocalStorageKeys.accessToken, data.access); - localStorage.setItem(LocalStorageKeys.refreshToken, data.refresh); -}; - const getRedirectURL = () => { return new URLSearchParams(window.location.search).get("redirect"); }; diff --git a/src/Utils/request/api.tsx b/src/Utils/request/api.tsx index 9066aab0e1f..fac0ede9be3 100644 --- a/src/Utils/request/api.tsx +++ b/src/Utils/request/api.tsx @@ -174,12 +174,14 @@ const routes = { path: "/api/v1/users/{username}/profile_picture/", method: "DELETE", TRes: Type(), + TBody: Type(), }, deleteUser: { path: "/api/v1/users/{username}/", method: "DELETE", TRes: Type>(), + TBody: Type(), }, // Facility Endpoints @@ -219,6 +221,7 @@ const routes = { path: "/api/v1/facility/{id}/cover_image/", method: "DELETE", TRes: Type>(), + TBody: Type(), }, getFacilityUsers: { @@ -241,6 +244,7 @@ const routes = { path: "/api/v1/facility/{id}/", method: "DELETE", TRes: Type>(), + TBody: Type(), }, // Patient @@ -622,9 +626,7 @@ const routes = { path: "/api/v1/otp/login/", method: "POST", TBody: Type<{ phone_number: string; otp: string }>(), - TRes: Type< - { access: string } | { errors: Array> } - >(), + TRes: Type<{ access: string }>(), }, getPatient: { path: "/api/v1/otp/patient/", diff --git a/src/components/Auth/Login.tsx b/src/components/Auth/Login.tsx index efd4403c23d..e1398cfdce7 100644 --- a/src/components/Auth/Login.tsx +++ b/src/components/Auth/Login.tsx @@ -35,7 +35,6 @@ import FiltersCache from "@/Utils/FiltersCache"; import ViewCache from "@/Utils/ViewCache"; import routes from "@/Utils/request/api"; import mutate from "@/Utils/request/mutate"; -import request from "@/Utils/request/request"; import { TokenData } from "@/types/auth/otpToken"; interface LoginFormData { @@ -71,7 +70,7 @@ interface LoginProps { } const Login = (props: LoginProps) => { - const { signIn, patientLogin } = useAuthContext(); + const { signIn, patientLogin, isAuthenticating } = useAuthContext(); const { reCaptchaSiteKey, urls, stateLogo, customLogo, customLogoAlt } = careConfig; const customDescriptionHtml = __CUSTOM_DESCRIPTION_HTML__; @@ -103,20 +102,14 @@ const Login = (props: LoginProps) => { FiltersCache.invaldiateAll(); return await signIn(data); }, - onSuccess: ({ res }) => { - setCaptcha(res?.status === 429); + onError: (error) => { + setCaptcha(error.status == 429); }, }); // Send OTP Mutation const { mutate: sendOtp, isPending: sendOtpPending } = useMutation({ - mutationFn: async (phone: string) => { - const response = await request(routes.otp.sendOtp, { - body: { phone_number: phone }, - silent: true, - }); - return response; - }, + mutationFn: mutate(routes.otp.sendOtp), onSuccess: () => { setIsOtpSent(true); setOtpError(""); @@ -280,7 +273,7 @@ const Login = (props: LoginProps) => { try { if (!isOtpSent) { - await sendOtp(phone); + await sendOtp({ phone_number: phone }); setIsOtpSent(true); } else { await verifyOtp({ phone_number: phone, otp }); @@ -303,8 +296,7 @@ const Login = (props: LoginProps) => { }; // Loading state derived from mutations - const isLoading = - staffLoginMutation.isPending || sendOtpPending || verifyOtpPending; + const isLoading = isAuthenticating || sendOtpPending || verifyOtpPending; const logos = [stateLogo, customLogo].filter( (logo) => logo?.light || logo?.dark, diff --git a/src/components/Auth/ResetPassword.tsx b/src/components/Auth/ResetPassword.tsx index 1f75e5a1ff6..5c15b8840af 100644 --- a/src/components/Auth/ResetPassword.tsx +++ b/src/components/Auth/ResetPassword.tsx @@ -1,5 +1,6 @@ +import { useMutation, useQuery } from "@tanstack/react-query"; import { navigate } from "raviger"; -import { useEffect, useState } from "react"; +import { useState } from "react"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; @@ -12,7 +13,8 @@ import { LocalStorageKeys } from "@/common/constants"; import { validatePassword } from "@/common/validation"; import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; +import mutate from "@/Utils/request/mutate"; +import query from "@/Utils/request/query"; interface ResetPasswordProps { token: string; @@ -69,40 +71,36 @@ const ResetPassword = (props: ResetPasswordProps) => { } return form; }; + const { mutate: resetPassword } = useMutation({ + mutationFn: mutate(routes.resetPassword), + onSuccess: () => { + localStorage.removeItem(LocalStorageKeys.accessToken); + toast.success(t("password_reset_success")); + navigate("/login"); + }, + onError: (error) => { + if (error.cause) { + setErrors(error.cause); + } + }, + }); const handleSubmit = async (e: any) => { e.preventDefault(); const valid = validateData(); if (valid) { valid.token = props.token; - const { res, error } = await request(routes.resetPassword, { - body: { ...valid }, - }); - if (res?.ok) { - localStorage.removeItem(LocalStorageKeys.accessToken); - toast.success(t("password_reset_success")); - navigate("/login"); - } else if (res && error) { - setErrors(error); - } + resetPassword(valid); } }; - useEffect(() => { - const checkResetToken = async () => { - const { res } = await request(routes.checkResetToken, { - body: { token: props.token }, - }); - if (!res || !res.ok) { - navigate("/invalid-reset"); - } - }; - if (props.token) { - checkResetToken(); - } else { - navigate("/invalid-reset"); - } - }, []); + const { isError } = useQuery({ + queryKey: ["checkResetToken", { token: props.token }], + queryFn: query(routes.checkResetToken, { body: { token: props.token } }), + enabled: !!props.token, + }); + + if (isError) navigate("/invalid-reset"); return (
diff --git a/src/components/Facility/FacilityHome.tsx b/src/components/Facility/FacilityHome.tsx index be79cce3c63..547d1b209d6 100644 --- a/src/components/Facility/FacilityHome.tsx +++ b/src/components/Facility/FacilityHome.tsx @@ -6,6 +6,7 @@ import { TooltipTrigger, } from "@radix-ui/react-tooltip"; import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { useMutation } from "@tanstack/react-query"; import { Hospital, MapPin, MoreVertical, Settings } from "lucide-react"; import { navigate } from "raviger"; import { useState } from "react"; @@ -33,8 +34,8 @@ import { FACILITY_FEATURE_TYPES } from "@/common/constants"; import { PLUGIN_Component } from "@/PluginEngine"; import routes from "@/Utils/request/api"; +import mutate from "@/Utils/request/mutate"; import query from "@/Utils/request/query"; -import request from "@/Utils/request/request"; import uploadFile from "@/Utils/request/uploadFile"; import { getAuthorizationHeader } from "@/Utils/request/utils"; import { sleep } from "@/Utils/utils"; @@ -105,24 +106,30 @@ export const FacilityHome = ({ facilityId }: Props) => { pathParams: { id: facilityId }, }), }); + const { mutate: deleteFacility } = useMutation({ + mutationFn: mutate(routes.deleteFacility, { + pathParams: { id: facilityId }, + }), + onSuccess: () => { + toast.success( + t("entity_deleted_successfully", { name: facilityData?.name }), + ); + navigate("/facility"); + }, + }); - const handleDeleteClose = () => { - setOpenDeleteDialog(false); - }; - - const handleDeleteSubmit = async () => { - await request(routes.deleteFacility, { + const { mutateAsync: deleteAvatar } = useMutation({ + mutationFn: mutate(routes.deleteFacilityCoverImage, { pathParams: { id: facilityId }, - onResponse: ({ res }) => { - if (res?.ok) { - toast.success( - t("deleted_successfully", { name: facilityData?.name }), - ); - } - navigate("/facility"); - }, - }); - }; + }), + onSuccess: () => { + toast.success(t("cover_image_deleted")); + queryClient.invalidateQueries({ + queryKey: ["facility", facilityId], + }); + setEditCoverImage(false); + }, + }); const handleCoverImageUpload = async (file: File, onError: () => void) => { const formData = new FormData(); @@ -152,18 +159,10 @@ export const FacilityHome = ({ facilityId }: Props) => { }, ); }; - const handleCoverImageDelete = async (onError: () => void) => { - const { res } = await request(routes.deleteFacilityCoverImage, { - pathParams: { id: facilityId }, - }); - if (res?.ok) { - toast.success(t("cover_image_deleted")); - queryClient.invalidateQueries({ - queryKey: ["facility", facilityId], - }); - setEditCoverImage(false); - } else { + try { + await deleteAvatar(); + } catch { onError(); } }; @@ -195,8 +194,8 @@ export const FacilityHome = ({ facilityId }: Props) => { action="Delete" variant="destructive" show={openDeleteDialog} - onClose={handleDeleteClose} - onConfirm={handleDeleteSubmit} + onClose={() => setOpenDeleteDialog(false)} + onConfirm={() => deleteFacility()} /> { - setIsLoading(true); - - try { - const resourceData: CreateResourceRequest = { - status: "PENDING", - category: data.category, - origin_facility: String(props.facilityId), - assigned_facility: data.assigned_facility?.id || null, - approving_facility: null, - emergency: data.emergency === "true", - title: data.title, - reason: data.reason, - referring_facility_contact_name: data.referring_facility_contact_name, - referring_facility_contact_number: - data.referring_facility_contact_number, - related_patient: related_patient, - priority: data.priority, - }; - - const { res, data: responseData } = await request(routes.createResource, { - body: resourceData, - }); + const { mutate: createResource, isPending } = useMutation({ + mutationFn: mutate(routes.createResource), + onSuccess: (data: ResourceRequest) => { + toast.success(t("resource_created_successfully")); + navigate(`/facility/${facilityId}/resource/${data.id}`); + }, + }); - if (res?.ok && responseData) { - toast.success(t("resource_created_successfully")); - navigate(`/facility/${facilityId}/resource/${responseData.id}`); - } - } catch (error) { - console.error(error); - toast.error(t("something_went_wrong")); - } finally { - setIsLoading(false); - } + const onSubmit = (data: ResourceFormValues) => { + createResource({ + status: "PENDING", + category: data.category, + origin_facility: String(props.facilityId), + assigned_facility: data.assigned_facility?.id || null, + approving_facility: null, + emergency: data.emergency === "true", + title: data.title, + reason: data.reason, + referring_facility_contact_name: data.referring_facility_contact_name, + referring_facility_contact_number: data.referring_facility_contact_number, + related_patient: related_patient, + priority: data.priority, + }); }; const fillMyDetails = () => { @@ -150,7 +137,7 @@ export default function ResourceCreate(props: ResourceProps) { } }; - if (isLoading) { + if (isPending) { return ; } @@ -414,8 +401,14 @@ export default function ResourceCreate(props: ResourceProps) { > {t("cancel")} -
diff --git a/src/components/Users/UserAvatar.tsx b/src/components/Users/UserAvatar.tsx index 74762953e3e..1d16f4ba8bd 100644 --- a/src/components/Users/UserAvatar.tsx +++ b/src/components/Users/UserAvatar.tsx @@ -1,5 +1,5 @@ import careConfig from "@careConfig"; -import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useState } from "react"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; @@ -15,8 +15,8 @@ import useAuthUser from "@/hooks/useAuthUser"; import { showAvatarEdit } from "@/Utils/permissions"; import routes from "@/Utils/request/api"; +import mutate from "@/Utils/request/mutate"; import query from "@/Utils/request/query"; -import request from "@/Utils/request/request"; import uploadFile from "@/Utils/request/uploadFile"; import { getAuthorizationHeader } from "@/Utils/request/utils"; import { formatDisplayName, sleep } from "@/Utils/utils"; @@ -27,12 +27,24 @@ export default function UserAvatar({ username }: { username: string }) { const authUser = useAuthUser(); const queryClient = useQueryClient(); + const { mutate: mutateAvatarDelete } = useMutation({ + mutationFn: mutate(routes.deleteProfilePicture, { + pathParams: { username }, + }), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ["getUserDetails", username] }); + if (authUser.username === username) { + queryClient.invalidateQueries({ queryKey: ["currentUser"] }); + } + toast.success(t("profile_picture_deleted")); + setEditAvatar(false); + }, + }); + const { data: userData, isLoading } = useQuery({ queryKey: ["getUserDetails", username], queryFn: query(routes.getUserDetails, { - pathParams: { - username: username, - }, + pathParams: { username }, }), }); @@ -53,7 +65,12 @@ export default function UserAvatar({ username }: { username: string }) { async (xhr: XMLHttpRequest) => { if (xhr.status === 200) { await sleep(1000); - queryClient.invalidateQueries({ queryKey: ["currentUser"] }); + queryClient.invalidateQueries({ + queryKey: ["getUserDetails", username], + }); + if (authUser.username === username) { + queryClient.invalidateQueries({ queryKey: ["currentUser"] }); + } toast.success(t("avatar_updated_success")); setEditAvatar(false); } @@ -66,18 +83,12 @@ export default function UserAvatar({ username }: { username: string }) { }; const handleAvatarDelete = async (onError: () => void) => { - const { res } = await request(routes.deleteProfilePicture, { - pathParams: { username }, - }); - if (res?.ok) { - queryClient.invalidateQueries({ queryKey: ["currentUser"] }); - toast.success(t("profile_picture_deleted")); - setEditAvatar(false); - } else { + try { + mutateAvatarDelete(); + } catch { onError(); } }; - return ( <> { - return await request(routes.deleteUser, { - pathParams: { username: userData?.username || "" }, - }); - }, + mutationFn: mutate(routes.deleteUser, { + pathParams: { username: userData?.username || "" }, + }), onSuccess: () => { toast.success(t("user_deleted_successfully")); - setshowDeleteDialog(false); + setShowDeleteDialog(false); navigate("/users"); }, onError: () => { - setshowDeleteDialog(false); + setShowDeleteDialog(false); toast.error(t("user_delete_error")); }, }); @@ -94,7 +92,7 @@ export default function UserSummaryTab({ userData }: { userData?: UserBase }) { name={userData.username} handleOk={handleSubmit} handleCancel={() => { - setshowDeleteDialog(false); + setShowDeleteDialog(false); }} /> )} @@ -185,7 +183,7 @@ export default function UserSummaryTab({ userData }: { userData?: UserBase }) {
sendOTP(phoneNumber)} + onClick={() => sendOTP({ phone_number: phoneNumber })} > {t("didnt_receive_a_message")} {t("resend_otp")} From b928147d6594f9997505dd9a56b42330348c1b27 Mon Sep 17 00:00:00 2001 From: Don Xavier <98073418+DonXavierdev@users.noreply.github.com> Date: Thu, 6 Feb 2025 13:18:40 +0530 Subject: [PATCH 17/19] Implement multiple file to pdf support (#9814) --- package-lock.json | 279 ++++++++++++++++---- package.json | 1 + public/locale/en.json | 4 + src/components/Common/FilePreviewDialog.tsx | 10 +- src/components/Common/PDFViewer.tsx | 7 +- src/components/Files/FilesTab.tsx | 169 +++++++++--- src/hooks/useFileUpload.tsx | 117 ++++++-- 7 files changed, 463 insertions(+), 124 deletions(-) diff --git a/package-lock.json b/package-lock.json index 794d8cd3670..498c38dec08 100644 --- a/package-lock.json +++ b/package-lock.json @@ -56,6 +56,7 @@ "i18next-http-backend": "^3.0.1", "i18next-resources-to-backend": "^1.2.1", "input-otp": "^1.4.2", + "jspdf": "^2.5.2", "libphonenumber-js": "^1.11.18", "lucide-react": "^0.474.0", "markdown-it": "^14.1.0", @@ -6638,6 +6639,13 @@ "devOptional": true, "license": "MIT" }, + "node_modules/@types/raf": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz", + "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==", + "license": "MIT", + "optional": true + }, "node_modules/@types/react": { "version": "18.3.18", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz", @@ -7799,6 +7807,18 @@ "node": ">= 4.0.0" } }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "license": "(MIT OR Apache-2.0)", + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, "node_modules/autoprefixer": { "version": "10.4.20", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", @@ -7926,6 +7946,16 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -8094,6 +8124,18 @@ "browserslist": ">=4.0.0" } }, + "node_modules/btoa": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", + "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==", + "license": "(MIT OR Apache-2.0)", + "bin": { + "btoa": "bin/btoa.js" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -8245,6 +8287,47 @@ ], "license": "CC-BY-4.0" }, + "node_modules/canvas": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-3.1.0.tgz", + "integrity": "sha512-tTj3CqqukVJ9NgSahykNwtGda7V33VLObwrHfzT0vqJXu7J4d4C/7kQQW3fOEGDfZZoILPut5H00gOjyttPGyg==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-addon-api": "^7.0.0", + "prebuild-install": "^7.1.1" + }, + "engines": { + "node": "^18.12.0 || >= 20.9.0" + } + }, + "node_modules/canvg": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz", + "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@types/raf": "^3.4.0", + "core-js": "^3.8.3", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.7", + "rgbcolor": "^1.0.1", + "stackblur-canvas": "^2.0.0", + "svg-pathdata": "^6.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/canvg/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT", + "optional": true + }, "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -8652,6 +8735,18 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "license": "MIT" }, + "node_modules/core-js": { + "version": "3.40.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.40.0.tgz", + "integrity": "sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-js-compat": { "version": "3.39.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.39.0.tgz", @@ -8762,6 +8857,25 @@ "node": ">=8" } }, + "node_modules/css-box-model": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz", + "integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==", + "license": "MIT", + "dependencies": { + "tiny-invariant": "^1.0.6" + } + }, + "node_modules/css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "license": "MIT", + "optional": true, + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -9148,19 +9262,6 @@ "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", "license": "MIT" }, - "node_modules/decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "license": "MIT", - "optional": true, - "dependencies": { - "mimic-response": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/deep-equal": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", @@ -10605,6 +10706,12 @@ "pend": "~1.2.0" } }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "license": "MIT" + }, "node_modules/figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -11512,6 +11619,20 @@ "integrity": "sha512-9gux8QhvjRO/erSnDPv28noDZcPZmYE7e1vFsBLKLlRlKDSqNJYebj6Qz1TGd5lsRV+X+xYyjCKjuZdABinWjA==", "license": "MIT" }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "license": "MIT", + "optional": true, + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -12654,6 +12775,31 @@ "node": ">=0.10.0" } }, + "node_modules/jspdf": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.2.tgz", + "integrity": "sha512-myeX9c+p7znDWPk0eTrujCzNjT+CXdXyk7YmJq5nD5V7uLLKmSXnlQ/Jn/kuo3X09Op70Apm0rQSnFWyGK8uEQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2", + "atob": "^2.1.2", + "btoa": "^1.2.1", + "fflate": "^0.8.1" + }, + "optionalDependencies": { + "canvg": "^3.0.6", + "core-js": "^3.6.0", + "dompurify": "^2.5.4", + "html2canvas": "^1.0.0-rc.5" + } + }, + "node_modules/jspdf/node_modules/dompurify": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.8.tgz", + "integrity": "sha512-o1vSNgrmYMQObbSSvF/1brBYEQPHhV1+gsmrusO7/GXtp1T9rCS8cXFqVxK/9crT1jA6Ccv+5MTSjBNqr7Sovw==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optional": true + }, "node_modules/jsprim": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", @@ -13770,19 +13916,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/mini-svg-data-uri": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", @@ -14597,22 +14730,6 @@ "path2d": "^0.2.1" } }, - "node_modules/pdfjs-dist/node_modules/canvas": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/canvas/-/canvas-3.0.0.tgz", - "integrity": "sha512-NtcIBY88FjymQy+g2g5qnuP5IslrbWCQ3A6rSr1PeuYxVRapRZ3BZCrDyAakvI6CuDYidgZaf55ygulFVwROdg==", - "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": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -15288,6 +15405,22 @@ "dev": true, "license": "MIT" }, + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "license": "MIT", + "optional": true, + "dependencies": { + "performance-now": "^2.1.0" + } + }, + "node_modules/raf-schd": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", + "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==", + "license": "MIT" + }, "node_modules/ramda": { "version": "0.29.1", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.29.1.tgz", @@ -16179,6 +16312,16 @@ "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "license": "MIT" }, + "node_modules/rgbcolor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz", + "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==", + "license": "MIT OR SEE LICENSE IN FEEL-FREE.md", + "optional": true, + "engines": { + "node": ">= 0.8.15" + } + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -16765,18 +16908,6 @@ "license": "MIT", "optional": true }, - "node_modules/simple-get": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", - "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", - "license": "MIT", - "optional": true, - "dependencies": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, "node_modules/simple-git": { "version": "3.27.0", "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.27.0.tgz", @@ -17012,6 +17143,16 @@ "node": ">=0.10.0" } }, + "node_modules/stackblur-canvas": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz", + "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.14" + } + }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -17442,6 +17583,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/svg-pathdata": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", + "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -17702,6 +17853,16 @@ "devOptional": true, "license": "MIT" }, + "node_modules/text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "license": "MIT", + "optional": true, + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -18906,6 +19067,16 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "license": "MIT", + "optional": true, + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, "node_modules/uuid": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.5.tgz", diff --git a/package.json b/package.json index 168877e8a25..a84562ddae6 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,7 @@ "i18next-http-backend": "^3.0.1", "i18next-resources-to-backend": "^1.2.1", "input-otp": "^1.4.2", + "jspdf": "^2.5.2", "libphonenumber-js": "^1.11.18", "lucide-react": "^0.474.0", "markdown-it": "^14.1.0", diff --git a/public/locale/en.json b/public/locale/en.json index fb066f9d360..12a3f1c63a8 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -566,6 +566,7 @@ "close": "Close", "close_scanner": "Close Scanner", "collapse_sidebar": "Collapse Sidebar", + "combine_files_pdf": "Combine Files To PDF", "comment_added_successfully": "Comment added successfully", "comment_min_length": "Comment Should Contain At Least 1 Character", "comments": "Comments", @@ -990,6 +991,8 @@ "fetching": "Fetching", "field_required": "This field is required", "file_archived_successfully": "File archived successfully", + "file_conversion_in_progress": "File conversion in progress", + "file_conversion_success": "File conversion successful", "file_download_completed": "File download completed", "file_download_failed": "Failed to download file", "file_download_started": "Downloading file...", @@ -998,6 +1001,7 @@ "file_error__file_name": "Please give a name for all files!", "file_error__file_size": "Maximum size of files is 100 MB", "file_error__file_type": "Invalid file type \".{{extension}}\" Allowed types: {{allowedExtensions}}", + "file_error__generate_pdf": "Failed to generate PDF", "file_error__mark_complete_failed": "Error while marking file upload as complete", "file_error__network": "Error Uploading File: Network Error", "file_error__single_file_name": "Please give a name for the file", diff --git a/src/components/Common/FilePreviewDialog.tsx b/src/components/Common/FilePreviewDialog.tsx index d9eb4db62b3..fbcaf9ae69a 100644 --- a/src/components/Common/FilePreviewDialog.tsx +++ b/src/components/Common/FilePreviewDialog.tsx @@ -82,6 +82,7 @@ const FilePreviewDialog = (props: FilePreviewProps) => { const [page, setPage] = useState(1); const [numPages, setNumPages] = useState(1); const [index, setIndex] = useState(currentIndex); + const [scale, setScale] = useState(1.0); useEffect(() => { if (uploadedFiles && show) { @@ -95,6 +96,7 @@ const FilePreviewDialog = (props: FilePreviewProps) => { ...file_state, zoom: !checkFull ? file_state.zoom + 1 : file_state.zoom, }); + setScale((prevScale) => Math.min(prevScale + 0.25, 2)); }; const handleZoomOut = () => { @@ -103,6 +105,7 @@ const FilePreviewDialog = (props: FilePreviewProps) => { ...file_state, zoom: !checkFull ? file_state.zoom - 1 : file_state.zoom, }); + setScale((prevScale) => Math.max(prevScale - 0.25, 0.5)); }; const fileName = file_state?.name @@ -133,6 +136,7 @@ const FilePreviewDialog = (props: FilePreviewProps) => { setPage(1); setNumPages(1); setIndex(-1); + setScale(1); onClose?.(); }; @@ -214,7 +218,7 @@ const FilePreviewDialog = (props: FilePreviewProps) => { )} -
@@ -249,6 +253,7 @@ const FilePreviewDialog = (props: FilePreviewProps) => { setNumPages(numPages); }} pageNumber={page} + scale={scale} /> ) : previewExtensions.includes(file_state.extension) ? ( @@ -341,6 +346,9 @@ const FilePreviewDialog = (props: FilePreviewProps) => { {file_state.extension === "pdf" && ( <> {[ + ["Zoom In", "l-search-plus", handleZoomIn, scale >= 2], + [`${Math.round(scale * 100)}%`, false, () => {}, false], + ["Zoom Out", "l-search-minus", handleZoomOut, scale <= 0.5], [ "Previous", "l-arrow-left", diff --git a/src/components/Common/PDFViewer.tsx b/src/components/Common/PDFViewer.tsx index 1a20fa9e133..6e135f7b673 100644 --- a/src/components/Common/PDFViewer.tsx +++ b/src/components/Common/PDFViewer.tsx @@ -7,6 +7,7 @@ export default function PDFViewer( url: string; pageNumber: number; onDocumentLoadSuccess: (numPages: number) => void; + scale: number; }>, ) { pdfjs.GlobalWorkerOptions.workerSrc = "/pdf.worker.min.mjs"; @@ -21,7 +22,11 @@ export default function PDFViewer( } className="w-full" > - +
diff --git a/src/components/Files/FilesTab.tsx b/src/components/Files/FilesTab.tsx index 8a3078ae2ec..723eb8f7119 100644 --- a/src/components/Files/FilesTab.tsx +++ b/src/components/Files/FilesTab.tsx @@ -7,6 +7,7 @@ import CareIcon, { IconName } from "@/CAREUI/icons/CareIcon"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; +import { Checkbox } from "@/components/ui/checkbox"; import { Dialog, DialogContent, @@ -153,7 +154,10 @@ export const FilesTab = (props: FilesTabProps) => { "pdf", ], allowNameFallback: false, - onUpload: () => refetch(), + onUpload: () => { + refetch(); + }, + compress: false, }); useEffect(() => { @@ -356,13 +360,13 @@ export const FilesTab = (props: FilesTabProps) => { e.preventDefault(); }} > - + {fileUpload.Input({ className: "hidden" })} @@ -573,15 +577,22 @@ const FileUploadDialog = ({ fileUpload: FileUploadReturn; associatingId: string; }) => { + const handleDialogClose = (open: boolean) => { + if (!open) { + setIsPdf(false); + } + onOpenChange(open); + }; const { t } = useTranslation(); + const [isPdf, setIsPdf] = useState(false); return ( @@ -590,60 +601,134 @@ const FileUploadDialog = ({
- {fileUpload.files.map((file, index) => ( -
-
- - - - {file.name} - - - -
-
+ {isPdf ? ( + <> + {fileUpload.files.map((file, index) => ( +
+
+ + + + {file.name.length > 40 + ? `${file.name.substring(0, 30)}...` + : file.name} + + + +
+
+ ))} +
- fileUpload.setFileName(e.target.value, index) - } + onChange={(e) => { + fileUpload.setFileName(e.target.value); + fileUpload.setError(null); + }} + className="ml-0.5 mb-1" /> - {index === 0 && fileUpload.error && ( -

+ {fileUpload.error && ( +

{fileUpload.error}

)}
-
- ))} + + ) : ( + fileUpload.files.map((file, index) => ( +
+
+ + + + {file.name.length > 40 + ? `${file.name.substring(0, 30)}...` + : file.name} + + + +
+
+ + + { + fileUpload.setFileName(e.target.value, index); + fileUpload.setError(null); + }} + className="ml-0.5 mb-0.5" + /> + {index === 0 && fileUpload.error && ( +

+ {fileUpload.error} +

+ )} +
+
+ )) + )}
+ {fileUpload.files.length > 1 && ( +
+ setIsPdf(checked)} + disabled={fileUpload.uploading} + className="cursor-pointer" + /> + +
+ )} +
diff --git a/src/pages/Facility/settings/organizations/components/FacilityOrganizationSelector.tsx b/src/pages/Facility/settings/organizations/components/FacilityOrganizationSelector.tsx index b9c32974a82..d2044e1abca 100644 --- a/src/pages/Facility/settings/organizations/components/FacilityOrganizationSelector.tsx +++ b/src/pages/Facility/settings/organizations/components/FacilityOrganizationSelector.tsx @@ -1,12 +1,11 @@ -import { useQuery } from "@tanstack/react-query"; +import { useQueries, useQuery } from "@tanstack/react-query"; +import { Building } from "lucide-react"; import { useState } from "react"; import { useTranslation } from "react-i18next"; import CareIcon from "@/CAREUI/icons/CareIcon"; import Autocomplete from "@/components/ui/autocomplete"; -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; import { Label } from "@/components/ui/label"; import routes from "@/Utils/request/api"; @@ -40,47 +39,40 @@ export default function FacilityOrganizationSelector( const [selectedOrganization, setSelectedOrganization] = useState(null); - const { data: getAllOrganizations } = useQuery({ + const { data: rootOrganizations } = useQuery({ queryKey: ["organizations-root"], queryFn: query(routes.facilityOrganization.list, { pathParams: { facilityId }, - queryParams: { - parent: "", - }, + queryParams: { parent: "" }, }), }); - const { data: currentLevelOrganizations } = useQuery<{ - results: FacilityOrganization[]; - }>({ - queryKey: [ - "organizations-current", - selectedLevels[selectedLevels.length - 1]?.id, - ], - queryFn: query(routes.facilityOrganization.list, { - pathParams: { facilityId }, - queryParams: { - parent: selectedLevels[selectedLevels.length - 1]?.id, - }, - }), - enabled: selectedLevels.length > 0, + const organizationQueries = useQueries({ + queries: selectedLevels.map((level, _index) => ({ + queryKey: ["organizations", level.id], + queryFn: query(routes.facilityOrganization.list, { + pathParams: { facilityId }, + queryParams: { parent: level.id }, + }), + enabled: !!level.id, + })), }); const handleLevelChange = (value: string, level: number) => { - const orgList = - level === 0 - ? getAllOrganizations?.results - : currentLevelOrganizations?.results; + let orgList: FacilityOrganization[] | undefined; + + if (level === 0) { + orgList = rootOrganizations?.results; + } else if (level - 1 < organizationQueries.length) { + orgList = organizationQueries[level - 1].data?.results; + } const selectedOrg = orgList?.find((org) => org.id === value); if (!selectedOrg) return; - const newLevels = selectedLevels.slice(0, level); newLevels.push(selectedOrg); setSelectedLevels(newLevels); setSelectedOrganization(selectedOrg); - - // Always update the selected value, regardless of children onChange(selectedOrg.id); }; @@ -104,92 +96,86 @@ export default function FacilityOrganizationSelector( onChange(lastOrg.id); } else { setSelectedOrganization(null); + onChange(""); + } + }; + + const renderOrganizationLevel = (level: number) => { + let orgList: FacilityOrganization[] | undefined; + + if (level === 0) { + orgList = rootOrganizations?.results; + } else if (level - 1 < organizationQueries.length) { + orgList = organizationQueries[level - 1].data?.results; } + + const getDropdownLabel = () => { + if (level < selectedLevels.length) { + return selectedLevels[level].name; + } + return level === 0 ? t("select_department") : t("select_sub_department"); + }; + + return ( +
+ {level > 0 && ( + + )} +
+
+ handleLevelChange(value, level)} + placeholder={getDropdownLabel()} + /> +
+ {level > 0 && level < selectedLevels.length && ( +
handleEdit(level)} + > + +
+ )} +
+
+ ); }; return ( <> -
+ + {encounter.hospitalization?.admit_source && ( + <> +
+ + {/* Hospitalisation Details */} +
+

+ {t("hospitalisation_details")} +

+
+
+ {t("admit_source")} + + {t( + `encounter_admit_sources__${encounter.hospitalization?.admit_source}`, + )} + +
+
+ {t("diet_preference")} + + {t( + `encounter_diet_preference__${encounter.hospitalization?.diet_preference}`, + )} + +
+
+ {t("re_admission")} + + {t( + `encounter_re_admission__${encounter.hospitalization?.re_admission}`, + )} + +
+ +
+
+ + )} +
+ ); +} diff --git a/src/components/Patient/PatientInfoCard.tsx b/src/components/Patient/PatientInfoCard.tsx index f73d9fbab3f..9ea75adc2c8 100644 --- a/src/components/Patient/PatientInfoCard.tsx +++ b/src/components/Patient/PatientInfoCard.tsx @@ -12,6 +12,8 @@ import { Link } from "raviger"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; +import CareIcon from "@/CAREUI/icons/CareIcon"; + import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { @@ -265,11 +267,25 @@ export default function PatientInfoCard(props: PatientInfoCardProps) { )} - {encounter.hospitalization?.discharge_disposition && ( - - {encounter.hospitalization.discharge_disposition} - - )} + { + // (encounter.status === "discharged" || + // encounter.status === "completed") && + encounter.hospitalization?.discharge_disposition && ( + + + {t( + `encounter_discharge_disposition__${encounter.hospitalization.discharge_disposition}`, + )} + + ) + } = { + food: , + medication: ( + + ), + environment: ( + + ), + biologic: ( + + ), +}; + export function AllergyList({ facilityId, patientId, @@ -88,81 +120,106 @@ export function AllergyList({ ); } - const getStatusBadgeStyle = (status: string | undefined) => { - switch (status?.toLowerCase()) { - case "active": - return "bg-green-100 text-green-800 border-green-200"; - case "inactive": - return "bg-gray-100 text-gray-800 border-gray-200"; - default: - return "bg-gray-100 text-gray-800 border-gray-200"; - } - }; - - const getCategoryBadgeStyle = (category: string) => { - switch (category?.toLowerCase()) { - case "food": - return "bg-orange-100 text-orange-800 border-orange-200"; - case "medication": - return "bg-blue-100 text-blue-800 border-blue-200"; - case "environment": - return "bg-green-100 text-green-800 border-green-200"; - default: - return "bg-gray-100 text-gray-800 border-gray-200"; - } - }; - interface AllergyRowProps { allergy: AllergyIntolerance; - isEnteredInError?: boolean; } - function AllergyRow({ allergy, isEnteredInError }: AllergyRowProps) { + function AllergyRow({ allergy }: AllergyRowProps) { + const MAX_NOTE_LENGTH = 15; + const note = allergy.note || ""; + const isLongNote = note.length > MAX_NOTE_LENGTH; + const displayNote = isLongNote + ? `${note.slice(0, MAX_NOTE_LENGTH)}..` + : note; + + useEffect(() => { + console.log( + "Allergy Note:", + allergy.note, + isLongNote, + displayNote, + note.length, + ); + }, [allergy.note, isLongNote, displayNote, note.length]); + return ( - {allergy.code.display} + +
+ {CATEGORY_ICONS[allergy.category ?? ""]} +
+
+ + {allergy.code.display} + - {t(allergy.category)} + {t(allergy.clinical_status)} - {t(allergy.clinical_status)} - - - - {t(allergy.criticality)} {t(allergy.verification_status)} - - - {allergy.created_by.username} + + {note && ( +
+ {displayNote} + {isLongNote && ( + + + + + +

+ {note} +

+
+
+ )} +
+ )} +
+ +
+ + {formatName(allergy.created_by)} +
); @@ -174,15 +231,28 @@ export function AllergyList({ patientId={patientId} encounterId={encounterId} > - +
- - {t("allergen")} - {t("category")} - {t("status")} - {t("criticality")} - {t("verification")} - {t("created_by")} + + + + {t("allergen")} + + + {t("status")} + + + {t("criticality")} + + + {t("verification")} + + + {t("notes")} + + + {t("logged_by")} + @@ -202,25 +272,24 @@ export function AllergyList({ (allergy) => allergy.verification_status === "entered_in_error", ) .map((allergy) => ( - + ))}
{hasEnteredInErrorRecords && !showEnteredInError && ( -
- -
+ <> +
+
+ +
+ )} ); @@ -238,15 +307,15 @@ const AllergyListLayout = ({ children: ReactNode; }) => { return ( - - + + {t("allergies")} {facilityId && encounterId && ( - + {t("edit")} )} diff --git a/src/components/Patient/diagnosis/DiagnosisTable.tsx b/src/components/Patient/diagnosis/DiagnosisTable.tsx index d9134f6d0c8..3f821d5d110 100644 --- a/src/components/Patient/diagnosis/DiagnosisTable.tsx +++ b/src/components/Patient/diagnosis/DiagnosisTable.tsx @@ -1,6 +1,12 @@ import { t } from "i18next"; import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; import { Table, TableBody, @@ -12,101 +18,133 @@ import { import { Avatar } from "@/components/Common/Avatar"; -import { formatName } from "@/Utils/utils"; -import { Diagnosis } from "@/types/emr/diagnosis/diagnosis"; - -export const getStatusBadgeStyle = (status: string) => { - switch (status?.toLowerCase()) { - case "active": - return "bg-green-100 text-green-800 border-green-200"; - case "inactive": - return "bg-gray-100 text-gray-800 border-gray-200"; - case "resolved": - return "bg-blue-100 text-blue-800 border-blue-200"; - case "recurrence": - return "bg-orange-100 text-orange-800 border-orange-200"; - default: - return "bg-gray-100 text-gray-800 border-gray-200"; - } -}; +import { + DIAGNOSIS_CLINICAL_STATUS_STYLES, + DIAGNOSIS_VERIFICATION_STATUS_STYLES, + Diagnosis, +} from "@/types/emr/diagnosis/diagnosis"; interface DiagnosisTableProps { diagnoses: Diagnosis[]; - showHeader?: boolean; } -export function DiagnosisTable({ - diagnoses, - showHeader = true, -}: DiagnosisTableProps) { +export function DiagnosisTable({ diagnoses }: DiagnosisTableProps) { return ( - - {showHeader && ( - - - {t("diagnosis")} - {t("status")} - {t("verification")} - {t("onset")} - {t("notes")} - {t("created_by")} - - - )} +
+ + + + {t("diagnosis")} + + + {t("status")} + + + {t("verification")} + + + {t("onset")} + + + {t("notes")} + + + {t("logged_by")} + + + - {diagnoses.map((diagnosis: Diagnosis, index) => { - const isEnteredInError = - diagnosis.verification_status === "entered_in_error"; + {diagnoses.map((diagnosis) => { + const note = diagnosis.note || ""; + const MAX_NOTE_LENGTH = 15; + const isLongNote = note.length > MAX_NOTE_LENGTH; + const displayNote = isLongNote + ? `${note.slice(0, MAX_NOTE_LENGTH)}..` + : note; return ( - <> - - - {diagnosis.code.display} - - - - {t(diagnosis.clinical_status)} - - - - - {t(diagnosis.verification_status)} - - - - {diagnosis.onset?.onset_datetime - ? new Date( - diagnosis.onset.onset_datetime, - ).toLocaleDateString() - : "-"} - - - {diagnosis.note || "-"} - - + + + {diagnosis.code.display} + + + + {t(diagnosis.clinical_status)} + + + + + {t(diagnosis.verification_status)} + + + + {diagnosis.onset?.onset_datetime + ? new Date( + diagnosis.onset.onset_datetime, + ).toLocaleDateString() + : "-"} + + + {note ? ( +
+ + {displayNote} + + {isLongNote && ( + + + + + +

+ {note} +

+
+
+ )} +
+ ) : ( + "-" + )} +
+ +
- {formatName(diagnosis.created_by)} + {diagnosis.created_by.username} - - - +
+
+
); })}
diff --git a/src/components/Patient/diagnosis/list.tsx b/src/components/Patient/diagnosis/list.tsx index 40ae25b3faf..8e7fe9f1c07 100644 --- a/src/components/Patient/diagnosis/list.tsx +++ b/src/components/Patient/diagnosis/list.tsx @@ -1,9 +1,10 @@ import { useQuery } from "@tanstack/react-query"; import { t } from "i18next"; -import { PencilIcon } from "lucide-react"; import { Link } from "raviger"; import { ReactNode, useState } from "react"; +import CareIcon from "@/CAREUI/icons/CareIcon"; + import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; @@ -41,7 +42,9 @@ export function DiagnosisList({ patientId={patientId} encounterId={encounterId} > - + + + ); } @@ -91,16 +94,19 @@ export function DiagnosisList({ /> {hasEnteredInErrorRecords && !showEnteredInError && ( -
- -
+ <> +
+
+ +
+ )} ); @@ -118,15 +124,15 @@ const DiagnosisListLayout = ({ children: ReactNode; }) => { return ( - - + + {t("diagnoses")} {facilityId && encounterId && ( - + {t("edit")} )} diff --git a/src/components/Patient/symptoms/SymptomTable.tsx b/src/components/Patient/symptoms/SymptomTable.tsx index b95e518d99d..8fc626918e9 100644 --- a/src/components/Patient/symptoms/SymptomTable.tsx +++ b/src/components/Patient/symptoms/SymptomTable.tsx @@ -1,6 +1,12 @@ import { t } from "i18next"; import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; import { Table, TableBody, @@ -12,107 +18,135 @@ import { import { Avatar } from "@/components/Common/Avatar"; -import { formatName } from "@/Utils/utils"; -import { Symptom } from "@/types/emr/symptom/symptom"; - -export const getStatusBadgeStyle = (status: string) => { - switch (status?.toLowerCase()) { - case "active": - return "bg-green-100 text-green-800 border-green-200"; - case "inactive": - return "bg-gray-100 text-gray-800 border-gray-200"; - case "resolved": - return "bg-blue-100 text-blue-800 border-blue-200"; - case "recurrence": - return "bg-orange-100 text-orange-800 border-orange-200"; - default: - return "bg-gray-100 text-gray-800 border-gray-200"; - } -}; +import { + SYMPTOM_CLINICAL_STATUS_STYLES, + SYMPTOM_SEVERITY_STYLES, + SYMPTOM_VERIFICATION_STATUS_STYLES, + Symptom, +} from "@/types/emr/symptom/symptom"; interface SymptomTableProps { symptoms: Symptom[]; - showHeader?: boolean; } -export function SymptomTable({ - symptoms, - showHeader = true, -}: SymptomTableProps) { +export function SymptomTable({ symptoms }: SymptomTableProps) { return ( -
- {showHeader && ( - - - {t("symptom")} - {t("status")} - {t("severity")} - {t("onset")} - {t("verification")} - {t("notes")} - {t("created_by")} - - - )} +
+ + + + {t("symptom")} + + + {t("severity")} + + + {t("status")} + + + {t("verification")} + + + {t("notes")} + + + {t("logged_by")} + + + - {symptoms.map((symptom: Symptom, index: number) => { - const isEnteredInError = - symptom.verification_status === "entered_in_error"; + {symptoms.map((symptom) => { + const note = symptom.note || ""; + const MAX_NOTE_LENGTH = 15; + const isLongNote = note.length > MAX_NOTE_LENGTH; + const displayNote = isLongNote + ? `${note.slice(0, MAX_NOTE_LENGTH)}..` + : note; return ( - <> - - - {symptom.code.display} - - - - {t(symptom.clinical_status)} - - - - - {t(symptom.severity)} - - - - {symptom.onset?.onset_datetime - ? new Date( - symptom.onset.onset_datetime, - ).toLocaleDateString() - : "-"} - - - - {t(symptom.verification_status)} - - - - {symptom.note || "-"} - - + + + {symptom.code.display} + + + + {t(symptom.severity)} + + + + + {t(symptom.clinical_status)} + + + + + {t(symptom.verification_status)} + + + + {note ? ( +
+ + {displayNote} + + {isLongNote && ( + + + + + +

+ {note} +

+
+
+ )} +
+ ) : ( + "-" + )} +
+ +
- - {formatName(symptom.created_by)} - - - - + {symptom.created_by.username} +
+
+
); })}
diff --git a/src/components/Patient/symptoms/list.tsx b/src/components/Patient/symptoms/list.tsx index d095b851330..e815a229e0d 100644 --- a/src/components/Patient/symptoms/list.tsx +++ b/src/components/Patient/symptoms/list.tsx @@ -1,9 +1,10 @@ import { useQuery } from "@tanstack/react-query"; import { t } from "i18next"; -import { PencilIcon } from "lucide-react"; import { Link } from "raviger"; import { ReactNode, useState } from "react"; +import CareIcon from "@/CAREUI/icons/CareIcon"; + import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; @@ -41,7 +42,9 @@ export function SymptomsList({ patientId={patientId} encounterId={encounterId} > - + + + ); } @@ -89,16 +92,19 @@ export function SymptomsList({ /> {hasEnteredInErrorRecords && !showEnteredInError && ( -
- -
+ <> +
+
+ +
+ )} ); @@ -116,15 +122,15 @@ const SymptomListLayout = ({ children: ReactNode; }) => { return ( - - + + {t("symptoms")} - {facilityId && ( + {facilityId && encounterId && ( - + {t("edit")} )} diff --git a/src/components/Questionnaire/QuestionTypes/AllergyQuestion.tsx b/src/components/Questionnaire/QuestionTypes/AllergyQuestion.tsx index 8270ae98c71..94ffe3b7626 100644 --- a/src/components/Questionnaire/QuestionTypes/AllergyQuestion.tsx +++ b/src/components/Questionnaire/QuestionTypes/AllergyQuestion.tsx @@ -8,12 +8,7 @@ import { Pencil2Icon, } from "@radix-ui/react-icons"; import { useQuery } from "@tanstack/react-query"; -import { - BeakerIcon, - CookingPotIcon, - HeartPulseIcon, - LeafIcon, -} from "lucide-react"; +import { t } from "i18next"; import React, { useEffect, useState } from "react"; import { Button } from "@/components/ui/button"; @@ -42,9 +37,11 @@ import { TableRow, } from "@/components/ui/table"; +import { CATEGORY_ICONS } from "@/components/Patient/allergy/list"; import ValueSetSelect from "@/components/Questionnaire/ValueSetSelect"; import query from "@/Utils/request/query"; +import { dateQueryString } from "@/Utils/utils"; import { ALLERGY_VERIFICATION_STATUS, AllergyIntolerance, @@ -88,13 +85,6 @@ const ALLERGY_CATEGORIES: Record = { biologic: "Biologic", }; -const CATEGORY_ICONS: Record = { - food: , - medication: , - environment: , - biologic: , -}; - function convertToAllergyRequest( allergy: AllergyIntolerance, ): AllergyIntoleranceRequest { @@ -105,7 +95,9 @@ function convertToAllergyRequest( verification_status: allergy.verification_status, category: allergy.category, criticality: allergy.criticality, - last_occurrence: allergy.last_occurrence, + last_occurrence: allergy.last_occurrence + ? dateQueryString(new Date(allergy.last_occurrence)) + : undefined, note: allergy.note, encounter: allergy.encounter, }; @@ -211,15 +203,15 @@ export function AllergyQuestion({ - Substance + {t("substance")} - Critical + {t("criticality")} - Status + {t("status")} - Occurrence + {t("occurrence")} @@ -315,7 +307,7 @@ export function AllergyQuestion({ } > - Mark Active + {t("mark_active")} )} {allergy.clinical_status !== "inactive" && ( @@ -327,7 +319,7 @@ export function AllergyQuestion({ } > - Mark Inactive + {t("mark_inactive")} )} {allergy.clinical_status !== "resolved" && ( @@ -339,7 +331,7 @@ export function AllergyQuestion({ } > - Mark Resolved + {t("mark_resolved")} )} @@ -348,7 +340,7 @@ export function AllergyQuestion({ onClick={() => handleRemoveAllergy(index)} > - Remove Allergy + {t("remove_allergy")} @@ -356,7 +348,9 @@ export function AllergyQuestion({
- + @@ -405,7 +401,9 @@ export function AllergyQuestion({
- + - + @@ -528,12 +528,14 @@ const AllergyTableRow = ({ disabled={disabled} > - + - Low - High - Unable to Assess + {t("low")} + {t("high")} + + {t("unable_to_assess")} + @@ -550,7 +552,7 @@ const AllergyTableRow = ({ disabled={disabled} > - + {Object.entries(ALLERGY_VERIFICATION_STATUS).map( @@ -566,7 +568,7 @@ const AllergyTableRow = ({ onUpdate?.({ last_occurrence: e.target.value })} disabled={disabled} className="h-7 text-sm w-[100px] px-1" @@ -587,14 +589,14 @@ const AllergyTableRow = ({ - {showNotes ? "Hide Notes" : "Add Notes"} + {showNotes ? t("hide_notes") : t("add_notes")} {allergy.clinical_status !== "active" && ( onUpdate?.({ clinical_status: "active" })} > - Mark Active + {t("mark_active")} )} {allergy.clinical_status !== "inactive" && ( @@ -602,7 +604,7 @@ const AllergyTableRow = ({ onClick={() => onUpdate?.({ clinical_status: "inactive" })} > - Mark Inactive + {t("mark_inactive")} )} {allergy.clinical_status !== "resolved" && ( @@ -610,7 +612,7 @@ const AllergyTableRow = ({ onClick={() => onUpdate?.({ clinical_status: "resolved" })} > - Mark Resolved + {t("mark_resolved")} )} @@ -619,7 +621,7 @@ const AllergyTableRow = ({ onClick={onRemove} > - Remove Allergy + {t("remove_allergy")} @@ -628,10 +630,10 @@ const AllergyTableRow = ({ {showNotes && ( - + onUpdate?.({ note: e.target.value })} disabled={disabled} diff --git a/src/pages/Encounters/tabs/EncounterUpdatesTab.tsx b/src/pages/Encounters/tabs/EncounterUpdatesTab.tsx index d6f8a1a08bd..5f6eaa151d9 100644 --- a/src/pages/Encounters/tabs/EncounterUpdatesTab.tsx +++ b/src/pages/Encounters/tabs/EncounterUpdatesTab.tsx @@ -1,4 +1,4 @@ -import ObservationsList from "@/components/Facility/ConsultationDetails/ObservationsList"; +import SideOverview from "@/components/Facility/ConsultationDetails/OverviewSideBar"; import QuestionnaireResponsesList from "@/components/Facility/ConsultationDetails/QuestionnaireResponsesList"; import { AllergyList } from "@/components/Patient/allergy/list"; import { DiagnosisList } from "@/components/Patient/diagnosis/list"; @@ -55,8 +55,8 @@ export const EncounterUpdatesTab = ({
{/* Right Column - Observations */} -
- +
+
diff --git a/src/types/emr/allergyIntolerance/allergyIntolerance.ts b/src/types/emr/allergyIntolerance/allergyIntolerance.ts index 6693664b0b5..b788729091b 100644 --- a/src/types/emr/allergyIntolerance/allergyIntolerance.ts +++ b/src/types/emr/allergyIntolerance/allergyIntolerance.ts @@ -51,4 +51,24 @@ export const ALLERGY_VERIFICATION_STATUS = { refuted: "Refuted", presumed: "Presumed", entered_in_error: "Entered in Error", -}; +} as const; + +export const ALLERGY_VERIFICATION_STATUS_STYLES = { + unconfirmed: "bg-yellow-100 text-yellow-800 border-yellow-200", + confirmed: "bg-green-100 text-green-800 border-green-200", + refuted: "bg-red-100 text-red-800 border-red-200", + presumed: "bg-blue-100 text-blue-800 border-blue-200", + entered_in_error: "bg-red-100 text-red-800 border-red-200", +} as const; + +export const ALLERGY_CLINICAL_STATUS_STYLES = { + active: "bg-green-100 text-green-800 border-green-200", + inactive: "bg-gray-100 text-gray-800 border-gray-200", + resolved: "bg-blue-100 text-blue-800 border-blue-200", +} as const; + +export const ALLERGY_CRITICALITY_STYLES = { + low: "bg-blue-100 text-blue-800 border-blue-200", + high: "bg-red-100 text-red-800 border-red-200", + unable_to_assess: "bg-gray-100 text-gray-800 border-gray-200", +} as const; diff --git a/src/types/emr/diagnosis/diagnosis.ts b/src/types/emr/diagnosis/diagnosis.ts index 29f7b250778..c9dc5035a0d 100644 --- a/src/types/emr/diagnosis/diagnosis.ts +++ b/src/types/emr/diagnosis/diagnosis.ts @@ -54,3 +54,21 @@ export interface DiagnosisRequest { note?: string; encounter: string; } + +export const DIAGNOSIS_CLINICAL_STATUS_STYLES = { + active: "bg-green-100 text-green-800 border-green-200", + recurrence: "bg-yellow-100 text-yellow-800 border-yellow-200", + relapse: "bg-red-100 text-red-800 border-red-200", + inactive: "bg-gray-100 text-gray-800 border-gray-200", + remission: "bg-blue-100 text-blue-800 border-blue-200", + resolved: "bg-emerald-100 text-emerald-800 border-emerald-200", +} as const; + +export const DIAGNOSIS_VERIFICATION_STATUS_STYLES = { + unconfirmed: "bg-yellow-100 text-yellow-800 border-yellow-200", + provisional: "bg-orange-100 text-orange-800 border-orange-200", + differential: "bg-purple-100 text-purple-800 border-purple-200", + confirmed: "bg-green-100 text-green-800 border-green-200", + refuted: "bg-red-100 text-red-800 border-red-200", + entered_in_error: "bg-red-100 text-red-800 border-red-200", +} as const; diff --git a/src/types/emr/symptom/symptom.ts b/src/types/emr/symptom/symptom.ts index d064fd320e4..2d3512a5b59 100644 --- a/src/types/emr/symptom/symptom.ts +++ b/src/types/emr/symptom/symptom.ts @@ -59,3 +59,27 @@ export interface SymptomRequest { note?: string; encounter: string; } + +export const SYMPTOM_CLINICAL_STATUS_STYLES = { + active: "bg-green-100 text-green-800 border-green-200", + recurrence: "bg-yellow-100 text-yellow-800 border-yellow-200", + relapse: "bg-red-100 text-red-800 border-red-200", + inactive: "bg-gray-100 text-gray-800 border-gray-200", + remission: "bg-blue-100 text-blue-800 border-blue-200", + resolved: "bg-emerald-100 text-emerald-800 border-emerald-200", +} as const; + +export const SYMPTOM_VERIFICATION_STATUS_STYLES = { + unconfirmed: "bg-yellow-100 text-yellow-800 border-yellow-200", + provisional: "bg-orange-100 text-orange-800 border-orange-200", + differential: "bg-purple-100 text-purple-800 border-purple-200", + confirmed: "bg-green-100 text-green-800 border-green-200", + refuted: "bg-red-100 text-red-800 border-red-200", + entered_in_error: "bg-red-100 text-red-800 border-red-200", +} as const; + +export const SYMPTOM_SEVERITY_STYLES = { + severe: "bg-red-100 text-red-800 border-red-200", + moderate: "bg-yellow-100 text-yellow-800 border-yellow-200", + mild: "bg-blue-100 text-blue-800 border-blue-200", +} as const;