diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 00000000000..a561180ab91 --- /dev/null +++ b/.cursorrules @@ -0,0 +1,23 @@ +Care is a React Typescript Project, built with Vite and styled with TailwindCSS. + +Care uses a Plugin Architecture. Apps are installed in /apps. + +Care uses a custom useQuery hook to fetch data from the API. APIs are defined in the api.tsx file + +Here's an example of how to use the useQuery hook to fetch data from the API: + +``` +useQuery from "@/Common/hooks/useQuery"; +const { data, loading, error } = useQuery(routes.getFacilityUsers, { + facility_id: "1", +}); + +request from "@/Common/utils/request"; +const { res } = await request(routes.partialUpdateAsset, { + pathParams: { external_id: assetId }, + body: data, +}); +``` + + + diff --git a/.env.docker b/.env.docker new file mode 100644 index 00000000000..fb5179c6c50 --- /dev/null +++ b/.env.docker @@ -0,0 +1,2 @@ +# Care API URL without the /api prefix +REACT_CARE_API_URL=http://localhost:9000 \ No newline at end of file diff --git a/.example.env b/.example.env index f3f303bc1e3..0ce9043b9a3 100644 --- a/.example.env +++ b/.example.env @@ -16,6 +16,8 @@ REACT_PLAUSIBLE_SITE_DOMAIN= # Plausible server URL (default: https://plausible.10bedicu.in) REACT_PLAUSIBLE_SERVER_URL= +# Care Apps. repo@branch seperated by commas +REACT_ENABLED_APPS="ohcnetwork/care_livekit_fe@main,ohcnetwork/care_scribe" # Main logo (JSON string with light and dark properties) REACT_HEADER_LOGO= diff --git a/.gitignore b/.gitignore index d8e2615c727..000a965c44a 100644 --- a/.gitignore +++ b/.gitignore @@ -58,3 +58,7 @@ bun.lockb # Cypress cypress/downloads cypress/fixtures/token.json + +# Care Apps +/apps/* +src/pluginMap.ts diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000000..2edeafb09db --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +20 \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json index e3a9c2acae9..ba722afdd73 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -5,7 +5,6 @@ "semi": true, "jsxSingleQuote": false, "arrowParens": "always", - "tailwindFunctions": [ - "classNames" - ] -} \ No newline at end of file + "tailwindFunctions": ["classNames"], + "plugins": ["prettier-plugin-tailwindcss"] +} diff --git a/README.md b/README.md index 73ce06815d1..7ea8fe1a221 100644 --- a/README.md +++ b/README.md @@ -8,20 +8,22 @@

Our goal is to continuously improve the quality and accessibility of public healthcare services using digital tools.

-

🚀 Staging Deploy

-

+

🚀 Staging Deployment

+
+ +[![Netlify Status](https://api.netlify.com/api/v1/badges/de76351f-b1f0-4bf8-8445-d9faf6391b13/deploy-status)](https://app.netlify.com/sites/care-ohc/deploys) + +

Auto deployed to care.ohc.network for develop branch. All pull requests have preview builds powered by Netlify.

[![](https://sourcerer.io/fame/tomahawk-pilot/ohcnetwork/care_fe/images/0)](https://sourcerer.io/fame/tomahawk-pilot/ohcnetwork/care_fe/links/0)[![](https://sourcerer.io/fame/tomahawk-pilot/ohcnetwork/care_fe/images/1)](https://sourcerer.io/fame/tomahawk-pilot/ohcnetwork/care_fe/links/1)[![](https://sourcerer.io/fame/tomahawk-pilot/ohcnetwork/care_fe/images/2)](https://sourcerer.io/fame/tomahawk-pilot/ohcnetwork/care_fe/links/2)[![](https://sourcerer.io/fame/tomahawk-pilot/ohcnetwork/care_fe/images/3)](https://sourcerer.io/fame/tomahawk-pilot/ohcnetwork/care_fe/links/3)[![](https://sourcerer.io/fame/tomahawk-pilot/ohcnetwork/care_fe/images/4)](https://sourcerer.io/fame/tomahawk-pilot/ohcnetwork/care_fe/links/4)[![](https://sourcerer.io/fame/tomahawk-pilot/ohcnetwork/care_fe/images/5)](https://sourcerer.io/fame/tomahawk-pilot/ohcnetwork/care_fe/links/5)[![](https://sourcerer.io/fame/tomahawk-pilot/ohcnetwork/care_fe/images/6)](https://sourcerer.io/fame/tomahawk-pilot/ohcnetwork/care_fe/links/6)[![](https://sourcerer.io/fame/tomahawk-pilot/ohcnetwork/care_fe/images/7)](https://sourcerer.io/fame/tomahawk-pilot/ohcnetwork/care_fe/links/7) -[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=coronasafe_care_fe&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=coronasafe_care_fe) ![Code scanning - action](https://github.com/ohcnetwork/care_fe/workflows/Code%20scanning%20-%20action/badge.svg) ![OSSAR](https://github.com/ohcnetwork/care_fe/workflows/OSSAR/badge.svg) [![Cypress Tests](https://img.shields.io/endpoint?url=https://cloud.cypress.io/badge/simple/wf7d2m/develop&style=flat&logo=cypress)](https://cloud.cypress.io/projects/wf7d2m/runs) ![Staging Release](https://github.com/ohcnetwork/care_fe/workflows/CARE%20Develop%20Registry/badge.svg) ![Production Release](https://github.com/ohcnetwork/care_fe/workflows/Production%20Release/badge.svg) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/200482ab117e4b5397ff3f5ae5719aa2)](https://www.codacy.com/gh/ohcnetwork/care_fe?utm_source=github.com&utm_medium=referral&utm_content=ohcnetwork/care_fe&utm_campaign=Badge_Grade) -[![CircleCI](https://circleci.com/gh/ohcnetwork/care_fe.svg?style=svg)](https://circleci.com/gh/ohcnetwork/care_fe) [![Maintainability](https://api.codeclimate.com/v1/badges/f1438f693aa459805301/maintainability)](https://codeclimate.com/github/ohcnetwork/care_fe/maintainability) ## Getting started @@ -33,7 +35,14 @@ #### Install the required dependencies ```sh -npm install +npm run install-all +``` +#### First-time setup + +For first-time setup, run the following command to generate the pluginMap and install plugin configurations: + +```sh +npm run setup ``` #### 🏃 Run the app in development mode diff --git a/care.config.ts b/care.config.ts index c032ba613f3..ed82d69554a 100644 --- a/care.config.ts +++ b/care.config.ts @@ -103,6 +103,13 @@ const careConfig = { abdm: { enabled: (env.REACT_ENABLE_ABDM ?? "true") === "true", }, + + careApps: env.REACT_ENABLED_APPS + ? env.REACT_ENABLED_APPS.split(",").map((app) => ({ + branch: app.split("@")[1], + package: app.split("@")[0], + })) + : [], } as const; export default careConfig; diff --git a/cypress/e2e/facility_spec/FacilityLocation.cy.ts b/cypress/e2e/facility_spec/FacilityLocation.cy.ts index 113a5e3eaab..d29ee95e873 100644 --- a/cypress/e2e/facility_spec/FacilityLocation.cy.ts +++ b/cypress/e2e/facility_spec/FacilityLocation.cy.ts @@ -193,12 +193,16 @@ describe("Location Management Section", () => { facilityLocation.clickAddNewLocationButton(); facilityLocation.enterLocationName("Test Location with Beds"); facilityLocation.selectLocationType("OTHER"); - assetPage.clickassetupdatebutton(); + cy.submitButton("Add Location"); + cy.verifyNotification("Location created successfully"); + cy.closeNotification(); facilityLocation.clickManageBedButton(); facilityLocation.clickAddBedButton(); facilityLocation.enterBedName("Bed 1"); facilityLocation.selectBedType("Regular"); - assetPage.clickassetupdatebutton(); + cy.submitButton("Add Bed(s)"); + cy.verifyNotification("1 Bed created successfully"); + cy.closeNotification(); facilityLocation.loadLocationManagementPage("Dummy Shifting Center"); facilityLocation.deleteLocation("Test Location with Beds"); assetPage.clickassetupdatebutton(); diff --git a/cypress/e2e/patient_spec/PatientDoctorConnect.cy.ts b/cypress/e2e/patient_spec/PatientDoctorConnect.cy.ts new file mode 100644 index 00000000000..64d47db2cf1 --- /dev/null +++ b/cypress/e2e/patient_spec/PatientDoctorConnect.cy.ts @@ -0,0 +1,56 @@ +import { DoctorConnect } from "pageobject/Patient/PatientDoctorConnect"; +import LoginPage from "../../pageobject/Login/LoginPage"; +import { PatientPage } from "../../pageobject/Patient/PatientCreation"; + +describe("Patient Doctor Connect in consultation page", () => { + const loginPage = new LoginPage(); + const patientPage = new PatientPage(); + const doctorconnect = new DoctorConnect(); + const patientName = "Dummy Patient 11"; + const doctorUser = "Dev Doctor"; + const doctorUserNumber = "+919876543219"; + const nurseUser = "Dev Staff"; + const teleIcuUser = "Dev Doctor Two"; + + before(() => { + loginPage.loginAsDisctrictAdmin(); + cy.saveLocalStorage(); + }); + + beforeEach(() => { + cy.restoreLocalStorage(); + cy.clearLocalStorage(/filters--.+/); + cy.awaitUrl("/patients"); + }); + + it("Patient Doctor connect phone redirection and sort by filter", () => { + // click on the slideover and verify icon redirection + patientPage.visitPatient(patientName); + doctorconnect.clickDoctorConnectButton(); + // verify all the users are visible under the all section + cy.verifyContentPresence("#doctor-connect-home-doctor", [doctorUser]); + cy.verifyContentPresence("#doctor-connect-home-nurse", [nurseUser]); + cy.verifyContentPresence("#doctor-connect-remote-doctor", [teleIcuUser]); + // verify copy content button functionality + doctorconnect.CopyFunctionTrigger(); + doctorconnect.clickCopyPhoneNumber( + "#doctor-connect-home-doctor", + doctorUser, + ); + doctorconnect.verifyCopiedContent(doctorUserNumber); + // verify the whatsapp and phone number icon presence + doctorconnect.verifyIconVisible("#whatsapp-icon"); + doctorconnect.verifyIconVisible("#phone-icon"); + // sort the each datas based on user type + doctorconnect.clickUsersSortBy("Doctor"); + cy.verifyContentPresence("#doctor-connect-home-doctor", [doctorUser]); + doctorconnect.clickUsersSortBy("Nurse"); + cy.verifyContentPresence("#doctor-connect-home-nurse", [nurseUser]); + doctorconnect.clickUsersSortBy("TeleICU Doctor"); + cy.verifyContentPresence("#doctor-connect-remote-doctor", [teleIcuUser]); + }); + + afterEach(() => { + cy.saveLocalStorage(); + }); +}); diff --git a/cypress/e2e/users_spec/UsersHomepage.cy.ts b/cypress/e2e/users_spec/UsersHomepage.cy.ts index 0cf25cacfc8..634336a4ef9 100644 --- a/cypress/e2e/users_spec/UsersHomepage.cy.ts +++ b/cypress/e2e/users_spec/UsersHomepage.cy.ts @@ -14,7 +14,7 @@ describe("User Homepage", () => { const altPhoneNumber = "8878825662"; const homeFacility = "Dummy Facility 40"; const nurseUserName = "dummynurse1"; - const doctorUserName = "devdoctor"; + const doctorUserName = "devdoctor1"; before(() => { loginPage.loginAsDisctrictAdmin(); diff --git a/cypress/pageobject/Facility/FacilityCreation.ts b/cypress/pageobject/Facility/FacilityCreation.ts index 26f387935ac..fe838a88f41 100644 --- a/cypress/pageobject/Facility/FacilityCreation.ts +++ b/cypress/pageobject/Facility/FacilityCreation.ts @@ -297,7 +297,7 @@ class FacilityPage { selectLocation(location: string) { cy.intercept("https://maps.googleapis.com/**").as("mapApi"); - cy.get("span > svg.care-svg-icon__baseline.care-l-map-marker").click(); + cy.get("#facility-location-button").click(); cy.wait("@mapApi").its("response.statusCode").should("eq", 200); cy.get("input#pac-input").type(location).type("{enter}"); cy.wait(2000); diff --git a/cypress/pageobject/Patient/PatientDoctorConnect.ts b/cypress/pageobject/Patient/PatientDoctorConnect.ts new file mode 100644 index 00000000000..b8c33bb4b24 --- /dev/null +++ b/cypress/pageobject/Patient/PatientDoctorConnect.ts @@ -0,0 +1,32 @@ +export class DoctorConnect { + clickDoctorConnectButton() { + cy.get("#doctor-connect-button").scrollIntoView(); + cy.get("#doctor-connect-button").click(); + } + + CopyFunctionTrigger() { + cy.window().then((win) => { + cy.stub(win.navigator.clipboard, "writeText").as("clipboardStub"); + }); + } + + verifyCopiedContent(text: string) { + cy.get("@clipboardStub").should("be.calledWith", text); + } + + verifyIconVisible(selector: string) { + cy.get(selector).should("be.visible"); + } + + clickCopyPhoneNumber(element: string, text: string) { + cy.get(element) + .contains(text) // Find the element containing "dev doctor" + .parent() // Move up to the parent element (if necessary) + .find("#copy-phoneicon") // Find the #copy-phoneicon within that context + .click(); + } + + clickUsersSortBy(text: string) { + cy.get("#doctor-connect-filter-tabs").contains(text).click(); + } +} diff --git a/package-lock.json b/package-lock.json index 9554674c29b..e5bae3c6d02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,9 @@ "name": "care_fe", "version": "2.5.4", "license": "MIT", + "workspaces": [ + "apps/*" + ], "dependencies": { "@fontsource/figtree": "^5.1.0", "@googlemaps/react-wrapper": "^1.1.35", @@ -20,7 +23,7 @@ "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-toast": "^1.2.2", "@sentry/browser": "^8.33.0", - "@yudiel/react-qr-scanner": "^2.0.0-beta.3", + "@yudiel/react-qr-scanner": "^2.0.8", "axios": "^1.7.7", "bowser": "^2.11.0", "browser-image-compression": "^2.0.2", @@ -38,7 +41,6 @@ "i18next": "^23.11.4", "i18next-browser-languagedetector": "^7.2.1", "lodash-es": "^4.17.21", - "lucide-react": "^0.446.0", "postcss-loader": "^7.3.3", "qrcode.react": "^3.1.0", "raviger": "^4.1.2", @@ -69,7 +71,7 @@ "@types/lodash-es": "^4.17.12", "@types/node": "^22.7.4", "@types/qrcode.react": "^1.0.5", - "@types/react": "18.3.2", + "@types/react": "^18.3.11", "@types/react-copy-to-clipboard": "^5.0.7", "@types/react-csv": "^1.1.10", "@types/react-dom": "^18.3.0", @@ -80,13 +82,13 @@ "autoprefixer": "^10.4.19", "cypress-localstorage-commands": "^2.2.5", "cypress-split": "^1.23.2", + "dotenv": "^16.4.5", "eslint-config-prettier": "^9.1.0", "eslint-plugin-i18next": "^6.0.9", "eslint-plugin-mdx": "^3.1.5", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-react": "^7.35.0", "eslint-plugin-react-hooks": "^4.6.2", - "gentype": "^4.5.0", "glob": "^11.0.0", "husky": "^8.0.3", "lint-staged": "^13.2.3", @@ -94,7 +96,6 @@ "postcss": "^8.4.38", "prettier": "^3.3.3", "prettier-plugin-tailwindcss": "^0.6.5", - "prop-types": "^15.8.1", "redux-devtools-extension": "^2.13.9", "snyk": "^1.1291.0", "tailwindcss": "^3.4.3", @@ -109,6 +110,24 @@ "node": ">=20.12.0" } }, + "apps/care_livekit_fe": { + "name": "care-livekit", + "version": "0.0.1", + "license": "ISC", + "dependencies": { + "@livekit/components-react": "^2.6.2", + "@livekit/components-styles": "^1.1.3", + "livekit-client": "^2.5.5" + }, + "devDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependencies": { + "react": "18.3.1", + "react-dom": "18.3.1" + } + }, "node_modules/@actions/core": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz", @@ -181,18 +200,18 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.7.tgz", - "integrity": "sha512-9ickoLz+hcXCeh7jrcin+/SLWm+GkxE2kTvoYyp38p4WkdFXfQJxDFGWp/YHjiKLPx06z2A7W8XKuqbReXDzsw==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.8.tgz", + "integrity": "sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.7.tgz", - "integrity": "sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.8.tgz", + "integrity": "sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -201,10 +220,10 @@ "@babel/helper-compilation-targets": "^7.25.7", "@babel/helper-module-transforms": "^7.25.7", "@babel/helpers": "^7.25.7", - "@babel/parser": "^7.25.7", + "@babel/parser": "^7.25.8", "@babel/template": "^7.25.7", "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7", + "@babel/types": "^7.25.8", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -639,12 +658,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.7.tgz", - "integrity": "sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz", + "integrity": "sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==", "dev": true, "dependencies": { - "@babel/types": "^7.25.7" + "@babel/types": "^7.25.8" }, "bin": { "parser": "bin/babel-parser.js" @@ -744,69 +763,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-import-assertions": { "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.7.tgz", @@ -837,30 +793,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.7.tgz", @@ -876,108 +808,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-unicode-sets-regex": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", @@ -1010,14 +840,13 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.7.tgz", - "integrity": "sha512-4B6OhTrwYKHYYgcwErvZjbmH9X5TxQBsaBHdzEIB4l71gR5jh/tuHGlb9in47udL2+wVUcOz5XXhhfhVJwEpEg==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.8.tgz", + "integrity": "sha512-9ypqkozyzpG+HxlH4o4gdctalFGIjjdufzo7I2XPda0iBnZ6a+FO0rIEQcdSPXp02CkvGsII1exJhmROPQd5oA==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.25.7", "@babel/helper-remap-async-to-generator": "^7.25.7", - "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/traverse": "^7.25.7" }, "engines": { @@ -1091,14 +920,13 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.25.7.tgz", - "integrity": "sha512-rvUUtoVlkDWtDWxGAiiQj0aNktTPn3eFynBcMC2IhsXweehwgdI9ODe+XjWw515kEmv22sSOTp/rxIRuTiB7zg==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.25.8.tgz", + "integrity": "sha512-e82gl3TCorath6YLf9xUwFehVvjvfqFhdOo4+0iVIVju+6XOi5XHkqB3P2AXnSwoeTX0HBoXq5gJFtvotJzFnQ==", "dev": true, "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1215,13 +1043,12 @@ } }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.7.tgz", - "integrity": "sha512-UvcLuual4h7/GfylKm2IAA3aph9rwvAM2XBA0uPKU3lca+Maai4jBjjEVUS568ld6kJcgbouuumCBhMd/Yz17w==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.8.tgz", + "integrity": "sha512-gznWY+mr4ZQL/EWPcbBQUP3BXS5FwZp8RUOw06BaRn8tQLzN4XLIxXejpHN9Qo8x8jjBmAAKp6FoS51AgkSA/A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1247,13 +1074,12 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.7.tgz", - "integrity": "sha512-h3MDAP5l34NQkkNulsTNyjdaR+OiB0Im67VU//sFupouP8Q6m9Spy7l66DcaAQxtmCqGdanPByLsnwFttxKISQ==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.8.tgz", + "integrity": "sha512-sPtYrduWINTQTW7FtOy99VCTWp4H23UX7vYcut7S4CIMEXU+54zKX9uCoGkLsWXteyaMXzVHgzWbLfQ1w4GZgw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1296,13 +1122,12 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.7.tgz", - "integrity": "sha512-Ot43PrL9TEAiCe8C/2erAjXMeVSnE/BLEx6eyrKLNFCCw5jvhTHKyHxdI1pA0kz5njZRYAnMO2KObGqOCRDYSA==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.8.tgz", + "integrity": "sha512-4OMNv7eHTmJ2YXs3tvxAfa/I43di+VcF+M4Wt66c88EAED1RoGaf1D64cL5FkRpNL+Vx9Hds84lksWvd/wMIdA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1327,13 +1152,12 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.7.tgz", - "integrity": "sha512-iImzbA55BjiovLyG2bggWS+V+OLkaBorNvc/yJoeeDQGztknRnDdYfp2d/UPmunZYEnZi6Lg8QcTmNMHOB0lGA==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.8.tgz", + "integrity": "sha512-f5W0AhSbbI+yY6VakT04jmxdxz+WsID0neG7+kQZbCOjuyJNdL5Nn4WIBm4hRpKnUcO9lP0eipUhFN12JpoH8g==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1456,13 +1280,12 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.7.tgz", - "integrity": "sha512-FbuJ63/4LEL32mIxrxwYaqjJxpbzxPVQj5a+Ebrc8JICV6YX8nE53jY+K0RZT3um56GoNWgkS2BQ/uLGTjtwfw==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.8.tgz", + "integrity": "sha512-Z7WJJWdQc8yCWgAmjI3hyC+5PXIubH9yRKzkl9ZEG647O9szl9zvmKLzpbItlijBnVhTUf1cpyWBsZ3+2wjWPQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1472,13 +1295,12 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.7.tgz", - "integrity": "sha512-8CbutzSSh4hmD+jJHIA8vdTNk15kAzOnFLVVgBSMGr28rt85ouT01/rezMecks9pkU939wDInImwCKv4ahU4IA==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.8.tgz", + "integrity": "sha512-rm9a5iEFPS4iMIy+/A/PiS0QN0UyjPIeVvbU5EMZFKJZHt8vQnasbpo3T3EFcxzCeYO0BHfc4RqooCZc51J86Q==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1488,14 +1310,13 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.7.tgz", - "integrity": "sha512-1JdVKPhD7Y5PvgfFy0Mv2brdrolzpzSoUq2pr6xsR+m+3viGGeHEokFKsCgOkbeFOQxfB1Vt2F0cPJLRpFI4Zg==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.8.tgz", + "integrity": "sha512-LkUu0O2hnUKHKE7/zYOIjByMa4VRaV2CD/cdGz0AxU9we+VA3kDDggKEzI0Oz1IroG+6gUP6UmWEHBMWZU316g==", "dev": true, "dependencies": { "@babel/helper-compilation-targets": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-transform-parameters": "^7.25.7" }, "engines": { @@ -1522,13 +1343,12 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.7.tgz", - "integrity": "sha512-m9obYBA39mDPN7lJzD5WkGGb0GO54PPLXsbcnj1Hyeu8mSRz7Gb4b1A6zxNX32ZuUySDK4G6it8SDFWD1nCnqg==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.8.tgz", + "integrity": "sha512-EbQYweoMAHOn7iJ9GgZo14ghhb9tTjgOc88xFgYngifx7Z9u580cENCV159M4xDh3q/irbhSjZVpuhpC2gKBbg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1538,14 +1358,13 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.7.tgz", - "integrity": "sha512-h39agClImgPWg4H8mYVAbD1qP9vClFbEjqoJmt87Zen8pjqK8FTPUwrOXAvqu5soytwxrLMd2fx2KSCp2CHcNg==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.8.tgz", + "integrity": "sha512-q05Bk7gXOxpTHoQ8RSzGSh/LHVB9JEIkKnk3myAWwZHnYiTGYtbdrYkIsS8Xyh4ltKf7GNUSgzs/6P2bJtBAQg==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.25.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1586,15 +1405,14 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.7.tgz", - "integrity": "sha512-LzA5ESzBy7tqj00Yjey9yWfs3FKy4EmJyKOSWld144OxkTji81WWnUT8nkLUn+imN/zHL8ZQlOu/MTUAhHaX3g==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.8.tgz", + "integrity": "sha512-8Uh966svuB4V8RHHg0QJOB32QK287NBksJOByoKmHMp1TAobNniNalIkI2i5IPj5+S9NYCG4VIjbEuiSN8r+ow==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.7", "@babel/helper-create-class-features-plugin": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1789,12 +1607,12 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.7.tgz", - "integrity": "sha512-Gibz4OUdyNqqLj+7OAvBZxOD7CklCtMA5/j0JgUEwOnaRULsPDXmic2iKxL2DX2vQduPR5wH2hjZas/Vr/Oc0g==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.8.tgz", + "integrity": "sha512-58T2yulDHMN8YMUxiLq5YmWUnlDCyY1FsHM+v12VMx+1/FlrUj5tY50iDCpofFQEM8fMYOaY9YRvym2jcjn1Dg==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.25.7", + "@babel/compat-data": "^7.25.8", "@babel/helper-compilation-targets": "^7.25.7", "@babel/helper-plugin-utils": "^7.25.7", "@babel/helper-validator-option": "^7.25.7", @@ -1804,45 +1622,30 @@ "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.7", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.7", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", "@babel/plugin-syntax-import-assertions": "^7.25.7", "@babel/plugin-syntax-import-attributes": "^7.25.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.25.7", - "@babel/plugin-transform-async-generator-functions": "^7.25.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.8", "@babel/plugin-transform-async-to-generator": "^7.25.7", "@babel/plugin-transform-block-scoped-functions": "^7.25.7", "@babel/plugin-transform-block-scoping": "^7.25.7", "@babel/plugin-transform-class-properties": "^7.25.7", - "@babel/plugin-transform-class-static-block": "^7.25.7", + "@babel/plugin-transform-class-static-block": "^7.25.8", "@babel/plugin-transform-classes": "^7.25.7", "@babel/plugin-transform-computed-properties": "^7.25.7", "@babel/plugin-transform-destructuring": "^7.25.7", "@babel/plugin-transform-dotall-regex": "^7.25.7", "@babel/plugin-transform-duplicate-keys": "^7.25.7", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.7", - "@babel/plugin-transform-dynamic-import": "^7.25.7", + "@babel/plugin-transform-dynamic-import": "^7.25.8", "@babel/plugin-transform-exponentiation-operator": "^7.25.7", - "@babel/plugin-transform-export-namespace-from": "^7.25.7", + "@babel/plugin-transform-export-namespace-from": "^7.25.8", "@babel/plugin-transform-for-of": "^7.25.7", "@babel/plugin-transform-function-name": "^7.25.7", - "@babel/plugin-transform-json-strings": "^7.25.7", + "@babel/plugin-transform-json-strings": "^7.25.8", "@babel/plugin-transform-literals": "^7.25.7", - "@babel/plugin-transform-logical-assignment-operators": "^7.25.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.8", "@babel/plugin-transform-member-expression-literals": "^7.25.7", "@babel/plugin-transform-modules-amd": "^7.25.7", "@babel/plugin-transform-modules-commonjs": "^7.25.7", @@ -1850,15 +1653,15 @@ "@babel/plugin-transform-modules-umd": "^7.25.7", "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.7", "@babel/plugin-transform-new-target": "^7.25.7", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.7", - "@babel/plugin-transform-numeric-separator": "^7.25.7", - "@babel/plugin-transform-object-rest-spread": "^7.25.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.8", + "@babel/plugin-transform-numeric-separator": "^7.25.8", + "@babel/plugin-transform-object-rest-spread": "^7.25.8", "@babel/plugin-transform-object-super": "^7.25.7", - "@babel/plugin-transform-optional-catch-binding": "^7.25.7", - "@babel/plugin-transform-optional-chaining": "^7.25.7", + "@babel/plugin-transform-optional-catch-binding": "^7.25.8", + "@babel/plugin-transform-optional-chaining": "^7.25.8", "@babel/plugin-transform-parameters": "^7.25.7", "@babel/plugin-transform-private-methods": "^7.25.7", - "@babel/plugin-transform-private-property-in-object": "^7.25.7", + "@babel/plugin-transform-private-property-in-object": "^7.25.8", "@babel/plugin-transform-property-literals": "^7.25.7", "@babel/plugin-transform-regenerator": "^7.25.7", "@babel/plugin-transform-reserved-words": "^7.25.7", @@ -1961,9 +1764,9 @@ } }, "node_modules/@babel/types": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.7.tgz", - "integrity": "sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ==", + "version": "7.25.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.8.tgz", + "integrity": "sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.25.7", @@ -1974,6 +1777,11 @@ "node": ">=6.9.0" } }, + "node_modules/@bufbuild/protobuf": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-1.10.0.tgz", + "integrity": "sha512-QDdVFLoN93Zjg36NoQPZfsVH9tZew7wKDKyV5qRdj8ntT4wQCOradQjRaTdwMhWUYsgKsvCINKKm87FdEk96Ag==" + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -2542,9 +2350,9 @@ } }, "node_modules/@floating-ui/react": { - "version": "0.26.24", - "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.24.tgz", - "integrity": "sha512-2ly0pCkZIGEQUq5H8bBK0XJmc1xIK/RM3tvVzY3GBER7IOD1UgmC2Y2tjj4AuS+TC+vTE1KJv2053290jua0Sw==", + "version": "0.26.25", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.25.tgz", + "integrity": "sha512-hZOmgN0NTOzOuZxI1oIrDu3Gcl8WViIkvPMpB4xdd4QD6xAMtwgwr3VPoiyH/bLtRcS1cDnhxLSD1NsMJmwh/A==", "dependencies": { "@floating-ui/react-dom": "^2.1.2", "@floating-ui/utils": "^0.2.8", @@ -2599,9 +2407,9 @@ "integrity": "sha512-3iHuO8H0jPehftsMK0kgyJzPYU/g/oiTRw+wu/yltqSZ7wJPt3vfsJHkPiuRpQjbnnWygX+T3mkRGyK/eyZ/lw==" }, "node_modules/@headlessui/react": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.1.9.tgz", - "integrity": "sha512-ckWw7vlKtnoa1fL2X0fx1a3t/Li9MIKDVXn3SgG65YlxvDAsNrY39PPCxVM7sQRA7go2fJsuHSSauKFNaJHH7A==", + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.1.10.tgz", + "integrity": "sha512-6mLa2fjMDAFQi+/R10B+zU3edsUk/MDtENB2zHho0lqKU1uzhAfJLUduWds4nCo8wbl3vULtC5rJfZAQ1yqIng==", "dependencies": { "@floating-ui/react": "^0.26.16", "@react-aria/focus": "^3.17.1", @@ -2837,6 +2645,64 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@livekit/components-core": { + "version": "0.11.9", + "resolved": "https://registry.npmjs.org/@livekit/components-core/-/components-core-0.11.9.tgz", + "integrity": "sha512-LPE1BZ+YTaqsVqGy/GAlpiO5rEI8XpEaf1TQcGdZN1BCBas9hTHt7/aHMbHQJ0K5xuAFQx8is6dFe451T4qXIQ==", + "dependencies": { + "@floating-ui/dom": "1.6.11", + "loglevel": "1.9.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "livekit-client": "^2.5.7", + "tslib": "^2.6.2" + } + }, + "node_modules/@livekit/components-react": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@livekit/components-react/-/components-react-2.6.5.tgz", + "integrity": "sha512-G3BpBlKy+lWTV9MH3/oBTBC17Z8CWqZ9GnjcG/xmYI0IvqmY89tVWph7cj2Bq0taniA+mD3U9EMPr68fOb1m1g==", + "dependencies": { + "@livekit/components-core": "0.11.9", + "clsx": "2.1.1", + "usehooks-ts": "3.1.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@livekit/krisp-noise-filter": "^0.2.12", + "livekit-client": "^2.5.7", + "react": ">=18", + "react-dom": ">=18", + "tslib": "^2.6.2" + }, + "peerDependenciesMeta": { + "@livekit/krisp-noise-filter": { + "optional": true + } + } + }, + "node_modules/@livekit/components-styles": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@livekit/components-styles/-/components-styles-1.1.4.tgz", + "integrity": "sha512-QCupn7tQ/dy/WZclrfsgtDe8peiGYS6Ied1IGkKOysaXo04l90t62SIUTKyxgd0dNDhUDC0p34qCggGZs/44lQ==", + "engines": { + "node": ">=18" + } + }, + "node_modules/@livekit/protocol": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/@livekit/protocol/-/protocol-1.24.0.tgz", + "integrity": "sha512-9dCsqnkMn7lvbI4NGh18zhLDsrXyUcpS++TEFgEk5Xv1WM3R2kT3EzqgL1P/mr3jaabM6rJ8wZA/KJLuQNpF5w==", + "dependencies": { + "@bufbuild/protobuf": "^1.10.0" + } + }, "node_modules/@mapbox/node-pre-gyp": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", @@ -3559,11 +3425,11 @@ } }, "node_modules/@react-aria/focus": { - "version": "3.18.3", - "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.18.3.tgz", - "integrity": "sha512-WKUElg+5zS0D3xlVn8MntNnkzJql2J6MuzAMP8Sv5WTgFDse/XGR842dsxPTIyKKdrWVCRegCuwa4m3n/GzgJw==", + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.18.4.tgz", + "integrity": "sha512-91J35077w9UNaMK1cpMUEFRkNNz0uZjnSwiyBCFuRdaVuivO53wNC9XtWSDNDdcO5cGy87vfJRVAiyoCn/mjqA==", "dependencies": { - "@react-aria/interactions": "^3.22.3", + "@react-aria/interactions": "^3.22.4", "@react-aria/utils": "^3.25.3", "@react-types/shared": "^3.25.0", "@swc/helpers": "^0.5.0", @@ -3574,9 +3440,9 @@ } }, "node_modules/@react-aria/interactions": { - "version": "3.22.3", - "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.22.3.tgz", - "integrity": "sha512-RRUb/aG+P0IKTIWikY/SylB6bIbLZeztnZY2vbe7RAG5MgVaCgn5HQ45SI15GlTmhsFG8CnF6slJsUFJiNHpbQ==", + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.22.4.tgz", + "integrity": "sha512-E0vsgtpItmknq/MJELqYJwib+YN18Qag8nroqwjk1qOnBa9ROIkUhWJerLi1qs5diXq9LHKehZDXRlwPvdEFww==", "dependencies": { "@react-aria/ssr": "^3.9.6", "@react-aria/utils": "^3.25.3", @@ -3929,145 +3795,145 @@ ] }, "node_modules/@sentry-internal/browser-utils": { - "version": "8.33.1", - "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.33.1.tgz", - "integrity": "sha512-TW6/r+Gl5jiXv54iK1xZ3mlVgTS/jaBp4vcQ0xGMdgiQ3WchEPcFSeYovL+YHT3tSud0GZqVtDQCz+5i76puqA==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.34.0.tgz", + "integrity": "sha512-4AcYOzPzD1tL5eSRQ/GpKv5enquZf4dMVUez99/Bh3va8qiJrNP55AcM7UzZ7WZLTqKygIYruJTU5Zu2SpEAPQ==", "dependencies": { - "@sentry/core": "8.33.1", - "@sentry/types": "8.33.1", - "@sentry/utils": "8.33.1" + "@sentry/core": "8.34.0", + "@sentry/types": "8.34.0", + "@sentry/utils": "8.34.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/feedback": { - "version": "8.33.1", - "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.33.1.tgz", - "integrity": "sha512-qauMRTm3qDaLqZ3ibI03cj4gLF40y0ij65nj+cns6iWxGCtPrO8tjvXFWuQsE7Aye9dGMnBgmv7uN+NTUtC3RA==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.34.0.tgz", + "integrity": "sha512-aYSM2KPUs0FLPxxbJCFSwCYG70VMzlT04xepD1Y/tTlPPOja/02tSv2tyOdZbv8Uw7xslZs3/8Lhj74oYcTBxw==", "dependencies": { - "@sentry/core": "8.33.1", - "@sentry/types": "8.33.1", - "@sentry/utils": "8.33.1" + "@sentry/core": "8.34.0", + "@sentry/types": "8.34.0", + "@sentry/utils": "8.34.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/replay": { - "version": "8.33.1", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.33.1.tgz", - "integrity": "sha512-fm4coIOjmanU29NOVN9MyaP4fUCOYytbtFqVSKRFNZQ/xAgNeySiBIbUd6IjujMmnOk9bY0WEUMcdm3Uotjdog==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.34.0.tgz", + "integrity": "sha512-EoMh9NYljNewZK1quY23YILgtNdGgrkzJ9TPsj6jXUG0LZ0Q7N7eFWd0xOEDBvFxrmI3cSXF1i4d1sBb+eyKRw==", "dependencies": { - "@sentry-internal/browser-utils": "8.33.1", - "@sentry/core": "8.33.1", - "@sentry/types": "8.33.1", - "@sentry/utils": "8.33.1" + "@sentry-internal/browser-utils": "8.34.0", + "@sentry/core": "8.34.0", + "@sentry/types": "8.34.0", + "@sentry/utils": "8.34.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/replay-canvas": { - "version": "8.33.1", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.33.1.tgz", - "integrity": "sha512-nsxTFTPCT10Ty/v6+AiST3+yotGP1sUb8xqfKB9fPnS1hZHFryp0NnEls7xFjBsBbZPU1GpFkzrk/E6JFzixDQ==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.34.0.tgz", + "integrity": "sha512-x8KhZcCDpbKHqFOykYXiamX6x0LRxv6N1OJHoH+XCrMtiDBZr4Yo30d/MaS6rjmKGMtSRij30v+Uq+YWIgxUrg==", "dependencies": { - "@sentry-internal/replay": "8.33.1", - "@sentry/core": "8.33.1", - "@sentry/types": "8.33.1", - "@sentry/utils": "8.33.1" + "@sentry-internal/replay": "8.34.0", + "@sentry/core": "8.34.0", + "@sentry/types": "8.34.0", + "@sentry/utils": "8.34.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry-internal/tracing": { - "version": "7.119.1", - "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.119.1.tgz", - "integrity": "sha512-cI0YraPd6qBwvUA3wQdPGTy8PzAoK0NZiaTN1LM3IczdPegehWOaEG5GVTnpGnTsmBAzn1xnBXNBhgiU4dgcrQ==", + "version": "7.119.2", + "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.119.2.tgz", + "integrity": "sha512-V2W+STWrafyGJhQv3ulMFXYDwWHiU6wHQAQBShsHVACiFaDrJ2kPRet38FKv4dMLlLlP2xN+ss2e5zv3tYlTiQ==", "dev": true, "dependencies": { - "@sentry/core": "7.119.1", - "@sentry/types": "7.119.1", - "@sentry/utils": "7.119.1" + "@sentry/core": "7.119.2", + "@sentry/types": "7.119.2", + "@sentry/utils": "7.119.2" }, "engines": { "node": ">=8" } }, "node_modules/@sentry-internal/tracing/node_modules/@sentry/core": { - "version": "7.119.1", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.119.1.tgz", - "integrity": "sha512-YUNnH7O7paVd+UmpArWCPH4Phlb5LwrkWVqzFWqL3xPyCcTSof2RL8UmvpkTjgYJjJ+NDfq5mPFkqv3aOEn5Sw==", + "version": "7.119.2", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.119.2.tgz", + "integrity": "sha512-hQr3d2yWq/2lMvoyBPOwXw1IHqTrCjOsU1vYKhAa6w9vGbJZFGhKGGE2KEi/92c3gqGn+gW/PC7cV6waCTDuVA==", "dev": true, "dependencies": { - "@sentry/types": "7.119.1", - "@sentry/utils": "7.119.1" + "@sentry/types": "7.119.2", + "@sentry/utils": "7.119.2" }, "engines": { "node": ">=8" } }, "node_modules/@sentry-internal/tracing/node_modules/@sentry/types": { - "version": "7.119.1", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.119.1.tgz", - "integrity": "sha512-4G2mcZNnYzK3pa2PuTq+M2GcwBRY/yy1rF+HfZU+LAPZr98nzq2X3+mJHNJoobeHRkvVh7YZMPi4ogXiIS5VNQ==", + "version": "7.119.2", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.119.2.tgz", + "integrity": "sha512-ydq1tWsdG7QW+yFaTp0gFaowMLNVikIqM70wxWNK+u98QzKnVY/3XTixxNLsUtnAB4Y+isAzFhrc6Vb5GFdFeg==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/@sentry-internal/tracing/node_modules/@sentry/utils": { - "version": "7.119.1", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.119.1.tgz", - "integrity": "sha512-ju/Cvyeu/vkfC5/XBV30UNet5kLEicZmXSyuLwZu95hEbL+foPdxN+re7pCI/eNqfe3B2vz7lvz5afLVOlQ2Hg==", + "version": "7.119.2", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.119.2.tgz", + "integrity": "sha512-TLdUCvcNgzKP0r9YD7tgCL1PEUp42TObISridsPJ5rhpVGQJvpr+Six0zIkfDUxerLYWZoK8QMm9KgFlPLNQzA==", "dev": true, "dependencies": { - "@sentry/types": "7.119.1" + "@sentry/types": "7.119.2" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/browser": { - "version": "8.33.1", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.33.1.tgz", - "integrity": "sha512-c6zI/igexkLwZuGk+u8Rj26ChjxGgkhe6ZbKFsXCYaKAp5ep5X7HQRkkqgbxApiqlC0LduHdd/ymzh139JLg8w==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.34.0.tgz", + "integrity": "sha512-3HHG2NXxzHq1lVmDy2uRjYjGNf9NsJsTPlOC70vbQdOb+S49EdH/XMPy+J3ruIoyv6Cu0LwvA6bMOM6rHZOgNQ==", "dependencies": { - "@sentry-internal/browser-utils": "8.33.1", - "@sentry-internal/feedback": "8.33.1", - "@sentry-internal/replay": "8.33.1", - "@sentry-internal/replay-canvas": "8.33.1", - "@sentry/core": "8.33.1", - "@sentry/types": "8.33.1", - "@sentry/utils": "8.33.1" + "@sentry-internal/browser-utils": "8.34.0", + "@sentry-internal/feedback": "8.34.0", + "@sentry-internal/replay": "8.34.0", + "@sentry-internal/replay-canvas": "8.34.0", + "@sentry/core": "8.34.0", + "@sentry/types": "8.34.0", + "@sentry/utils": "8.34.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry/core": { - "version": "8.33.1", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.33.1.tgz", - "integrity": "sha512-3SS41suXLFzxL3OQvTMZ6q92ZapELVq2l2SoWlZopcamWhog2Ru0dp2vkunq97kFHb2TzKRTlFH4+4gbT8SJug==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.34.0.tgz", + "integrity": "sha512-adrXCTK/zsg5pJ67lgtZqdqHvyx6etMjQW3P82NgWdj83c8fb+zH+K79Z47pD4zQjX0ou2Ws5nwwi4wJbz4bfA==", "dependencies": { - "@sentry/types": "8.33.1", - "@sentry/utils": "8.33.1" + "@sentry/types": "8.34.0", + "@sentry/utils": "8.34.0" }, "engines": { "node": ">=14.18" } }, "node_modules/@sentry/integrations": { - "version": "7.119.1", - "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.119.1.tgz", - "integrity": "sha512-CGmLEPnaBqbUleVqrmGYjRjf5/OwjUXo57I9t0KKWViq81mWnYhaUhRZWFNoCNQHns+3+GPCOMvl0zlawt+evw==", + "version": "7.119.2", + "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.119.2.tgz", + "integrity": "sha512-dCuXKvbUE3gXVVa696SYMjlhSP6CxpMH/gl4Jk26naEB8Xjsn98z/hqEoXLg6Nab73rjR9c/9AdKqBbwVMHyrQ==", "dev": true, "dependencies": { - "@sentry/core": "7.119.1", - "@sentry/types": "7.119.1", - "@sentry/utils": "7.119.1", + "@sentry/core": "7.119.2", + "@sentry/types": "7.119.2", + "@sentry/utils": "7.119.2", "localforage": "^1.8.1" }, "engines": { @@ -4075,103 +3941,103 @@ } }, "node_modules/@sentry/integrations/node_modules/@sentry/core": { - "version": "7.119.1", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.119.1.tgz", - "integrity": "sha512-YUNnH7O7paVd+UmpArWCPH4Phlb5LwrkWVqzFWqL3xPyCcTSof2RL8UmvpkTjgYJjJ+NDfq5mPFkqv3aOEn5Sw==", + "version": "7.119.2", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.119.2.tgz", + "integrity": "sha512-hQr3d2yWq/2lMvoyBPOwXw1IHqTrCjOsU1vYKhAa6w9vGbJZFGhKGGE2KEi/92c3gqGn+gW/PC7cV6waCTDuVA==", "dev": true, "dependencies": { - "@sentry/types": "7.119.1", - "@sentry/utils": "7.119.1" + "@sentry/types": "7.119.2", + "@sentry/utils": "7.119.2" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/integrations/node_modules/@sentry/types": { - "version": "7.119.1", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.119.1.tgz", - "integrity": "sha512-4G2mcZNnYzK3pa2PuTq+M2GcwBRY/yy1rF+HfZU+LAPZr98nzq2X3+mJHNJoobeHRkvVh7YZMPi4ogXiIS5VNQ==", + "version": "7.119.2", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.119.2.tgz", + "integrity": "sha512-ydq1tWsdG7QW+yFaTp0gFaowMLNVikIqM70wxWNK+u98QzKnVY/3XTixxNLsUtnAB4Y+isAzFhrc6Vb5GFdFeg==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/@sentry/integrations/node_modules/@sentry/utils": { - "version": "7.119.1", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.119.1.tgz", - "integrity": "sha512-ju/Cvyeu/vkfC5/XBV30UNet5kLEicZmXSyuLwZu95hEbL+foPdxN+re7pCI/eNqfe3B2vz7lvz5afLVOlQ2Hg==", + "version": "7.119.2", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.119.2.tgz", + "integrity": "sha512-TLdUCvcNgzKP0r9YD7tgCL1PEUp42TObISridsPJ5rhpVGQJvpr+Six0zIkfDUxerLYWZoK8QMm9KgFlPLNQzA==", "dev": true, "dependencies": { - "@sentry/types": "7.119.1" + "@sentry/types": "7.119.2" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/node": { - "version": "7.119.1", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.119.1.tgz", - "integrity": "sha512-rpnoQCMxWh/ccjOe+qsmvXAdlTxQHXEWdaltSxnwj7QY+kOGKGP18WTQFLq/gdOBRw9aa6PEQGwhnLfhBXXaYg==", + "version": "7.119.2", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.119.2.tgz", + "integrity": "sha512-TPNnqxh+Myooe4jTyRiXrzrM2SH08R4+nrmBls4T7lKp2E5R/3mDSe/YTn5rRcUt1k1hPx1NgO/taG0DoS5cXA==", "dev": true, "dependencies": { - "@sentry-internal/tracing": "7.119.1", - "@sentry/core": "7.119.1", - "@sentry/integrations": "7.119.1", - "@sentry/types": "7.119.1", - "@sentry/utils": "7.119.1" + "@sentry-internal/tracing": "7.119.2", + "@sentry/core": "7.119.2", + "@sentry/integrations": "7.119.2", + "@sentry/types": "7.119.2", + "@sentry/utils": "7.119.2" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/node/node_modules/@sentry/core": { - "version": "7.119.1", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.119.1.tgz", - "integrity": "sha512-YUNnH7O7paVd+UmpArWCPH4Phlb5LwrkWVqzFWqL3xPyCcTSof2RL8UmvpkTjgYJjJ+NDfq5mPFkqv3aOEn5Sw==", + "version": "7.119.2", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.119.2.tgz", + "integrity": "sha512-hQr3d2yWq/2lMvoyBPOwXw1IHqTrCjOsU1vYKhAa6w9vGbJZFGhKGGE2KEi/92c3gqGn+gW/PC7cV6waCTDuVA==", "dev": true, "dependencies": { - "@sentry/types": "7.119.1", - "@sentry/utils": "7.119.1" + "@sentry/types": "7.119.2", + "@sentry/utils": "7.119.2" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/node/node_modules/@sentry/types": { - "version": "7.119.1", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.119.1.tgz", - "integrity": "sha512-4G2mcZNnYzK3pa2PuTq+M2GcwBRY/yy1rF+HfZU+LAPZr98nzq2X3+mJHNJoobeHRkvVh7YZMPi4ogXiIS5VNQ==", + "version": "7.119.2", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.119.2.tgz", + "integrity": "sha512-ydq1tWsdG7QW+yFaTp0gFaowMLNVikIqM70wxWNK+u98QzKnVY/3XTixxNLsUtnAB4Y+isAzFhrc6Vb5GFdFeg==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/@sentry/node/node_modules/@sentry/utils": { - "version": "7.119.1", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.119.1.tgz", - "integrity": "sha512-ju/Cvyeu/vkfC5/XBV30UNet5kLEicZmXSyuLwZu95hEbL+foPdxN+re7pCI/eNqfe3B2vz7lvz5afLVOlQ2Hg==", + "version": "7.119.2", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.119.2.tgz", + "integrity": "sha512-TLdUCvcNgzKP0r9YD7tgCL1PEUp42TObISridsPJ5rhpVGQJvpr+Six0zIkfDUxerLYWZoK8QMm9KgFlPLNQzA==", "dev": true, "dependencies": { - "@sentry/types": "7.119.1" + "@sentry/types": "7.119.2" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/types": { - "version": "8.33.1", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-8.33.1.tgz", - "integrity": "sha512-GjoAMvwtpIemoF/IiwZ7A60g4nQv3qwzR21GvJqDVUoKD0e8pv9OLX+HyXoUat4wEDGSuDUcUyUKD2G+od73QA==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-8.34.0.tgz", + "integrity": "sha512-zLRc60CzohGCo6zNsNeQ9JF3SiEeRE4aDCP9fDDdIVCOKovS+mn1rtSip0qd0Vp2fidOu0+2yY0ALCz1A3PJSQ==", "engines": { "node": ">=14.18" } }, "node_modules/@sentry/utils": { - "version": "8.33.1", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-8.33.1.tgz", - "integrity": "sha512-uzuYpiiJuFY3N4WNHMBWUQX5oNv2t/TbG0OHRp3Rr7yeu+HSfD542TIp9/gMZ+G0Cxd8AmVO3wkKIFbk0TL4Qg==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-8.34.0.tgz", + "integrity": "sha512-W1KoRlFUjprlh3t86DZPFxLfM6mzjRzshVfMY7vRlJFymBelJsnJ3A1lPeBZM9nCraOSiw6GtOWu6k5BAkiGIg==", "dependencies": { - "@sentry/types": "8.33.1" + "@sentry/types": "8.34.0" }, "engines": { "node": ">=14.18" @@ -4199,14 +4065,14 @@ } }, "node_modules/@swc/core": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.7.26.tgz", - "integrity": "sha512-f5uYFf+TmMQyYIoxkn/evWhNGuUzC730dFwAKGwBVHHVoPyak1/GvJUm6i1SKl+2Hrj9oN0i3WSoWWZ4pgI8lw==", + "version": "1.7.36", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.7.36.tgz", + "integrity": "sha512-bu7ymMX+LCJOSSrKank25Jaq66ymLVA9fOUuy4ck3/6rbXdLw+pIJPnIDKQ9uNcxww8KDxOuJk9Ui9pqR+aGFw==", "dev": true, "hasInstallScript": true, "dependencies": { "@swc/counter": "^0.1.3", - "@swc/types": "^0.1.12" + "@swc/types": "^0.1.13" }, "engines": { "node": ">=10" @@ -4216,16 +4082,16 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.7.26", - "@swc/core-darwin-x64": "1.7.26", - "@swc/core-linux-arm-gnueabihf": "1.7.26", - "@swc/core-linux-arm64-gnu": "1.7.26", - "@swc/core-linux-arm64-musl": "1.7.26", - "@swc/core-linux-x64-gnu": "1.7.26", - "@swc/core-linux-x64-musl": "1.7.26", - "@swc/core-win32-arm64-msvc": "1.7.26", - "@swc/core-win32-ia32-msvc": "1.7.26", - "@swc/core-win32-x64-msvc": "1.7.26" + "@swc/core-darwin-arm64": "1.7.36", + "@swc/core-darwin-x64": "1.7.36", + "@swc/core-linux-arm-gnueabihf": "1.7.36", + "@swc/core-linux-arm64-gnu": "1.7.36", + "@swc/core-linux-arm64-musl": "1.7.36", + "@swc/core-linux-x64-gnu": "1.7.36", + "@swc/core-linux-x64-musl": "1.7.36", + "@swc/core-win32-arm64-msvc": "1.7.36", + "@swc/core-win32-ia32-msvc": "1.7.36", + "@swc/core-win32-x64-msvc": "1.7.36" }, "peerDependencies": { "@swc/helpers": "*" @@ -4237,9 +4103,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.26.tgz", - "integrity": "sha512-FF3CRYTg6a7ZVW4yT9mesxoVVZTrcSWtmZhxKCYJX9brH4CS/7PRPjAKNk6kzWgWuRoglP7hkjQcd6EpMcZEAw==", + "version": "1.7.36", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.36.tgz", + "integrity": "sha512-8vDczXzCgv3ceTPhEivlpGprN44YlrCK1nbfU9g2TrhV/Aiqi09W/eM5zLesdoM1Z3mJl492gc/8nlTkpDdusw==", "cpu": [ "arm64" ], @@ -4253,9 +4119,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.7.26.tgz", - "integrity": "sha512-az3cibZdsay2HNKmc4bjf62QVukuiMRh5sfM5kHR/JMTrLyS6vSw7Ihs3UTkZjUxkLTT8ro54LI6sV6sUQUbLQ==", + "version": "1.7.36", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.7.36.tgz", + "integrity": "sha512-Pa2Gao7+Wf5m3SsK4abKRtd48AtoUnJInvaC3d077swBfgZjbjUbQvcpdc2dOeQtWwo49rFqUZJonMsL0jnPgQ==", "cpu": [ "x64" ], @@ -4269,9 +4135,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.26.tgz", - "integrity": "sha512-VYPFVJDO5zT5U3RpCdHE5v1gz4mmR8BfHecUZTmD2v1JeFY6fv9KArJUpjrHEEsjK/ucXkQFmJ0jaiWXmpOV9Q==", + "version": "1.7.36", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.36.tgz", + "integrity": "sha512-3YsMWd7V+WZEjbfBnLkkz/olcRBa8nyoK0iIOnNARJBMcYaJxjkJSMZpmSojCnIVwvjA1N83CPAbUL+W+fCnHg==", "cpu": [ "arm" ], @@ -4285,9 +4151,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.26.tgz", - "integrity": "sha512-YKevOV7abpjcAzXrhsl+W48Z9mZvgoVs2eP5nY+uoMAdP2b3GxC0Df1Co0I90o2lkzO4jYBpTMcZlmUXLdXn+Q==", + "version": "1.7.36", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.36.tgz", + "integrity": "sha512-lqM3aBB7kJazJYOwHeA5OGNLqXoQPZ/76b3dV+XcjN1GhD0CcXz6mW5PRYVin6OSN1eKrKBKJjtDA1mqADDEvw==", "cpu": [ "arm64" ], @@ -4301,9 +4167,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.26.tgz", - "integrity": "sha512-3w8iZICMkQQON0uIcvz7+Q1MPOW6hJ4O5ETjA0LSP/tuKqx30hIniCGOgPDnv3UTMruLUnQbtBwVCZTBKR3Rkg==", + "version": "1.7.36", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.36.tgz", + "integrity": "sha512-bqei2YDzvUfG0pth5W2xJaj0eG4XWYk0d/NJ75vBX6bkIzK6dC8iuKQ41jOfUWonnrAs7rTDDJW0sTn/evvRdw==", "cpu": [ "arm64" ], @@ -4317,9 +4183,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.26.tgz", - "integrity": "sha512-c+pp9Zkk2lqb06bNGkR2Looxrs7FtGDMA4/aHjZcCqATgp348hOKH5WPvNLBl+yPrISuWjbKDVn3NgAvfvpH4w==", + "version": "1.7.36", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.36.tgz", + "integrity": "sha512-03maXTUyaBjeCxlDltmdzHje1ryQt1C4OWmmNgSSRXjLb+GNnAenwOJMSrcvHP/aNClD2pwsFCnYKDGy+sYE6w==", "cpu": [ "x64" ], @@ -4333,9 +4199,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.26.tgz", - "integrity": "sha512-PgtyfHBF6xG87dUSSdTJHwZ3/8vWZfNIXQV2GlwEpslrOkGqy+WaiiyE7Of7z9AvDILfBBBcJvJ/r8u980wAfQ==", + "version": "1.7.36", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.36.tgz", + "integrity": "sha512-XXysqLkvjtQnXm1zHqLhy00UYPv/gk5OtwR732X+piNisnEbcJBqI8Qp9O7YvLWllRcoP8IMBGDWLGdGLSpViA==", "cpu": [ "x64" ], @@ -4349,9 +4215,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.26.tgz", - "integrity": "sha512-9TNXPIJqFynlAOrRD6tUQjMq7KApSklK3R/tXgIxc7Qx+lWu8hlDQ/kVPLpU7PWvMMwC/3hKBW+p5f+Tms1hmA==", + "version": "1.7.36", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.36.tgz", + "integrity": "sha512-k7+dmb13a/zPw+E4XYfPmLZFWJgcOcBRKIjYl9nQErtYsgsg3Ji6TBbsvJVETy23lNHyewZ17V5Vq6NzaG0hzg==", "cpu": [ "arm64" ], @@ -4365,9 +4231,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.26.tgz", - "integrity": "sha512-9YngxNcG3177GYdsTum4V98Re+TlCeJEP4kEwEg9EagT5s3YejYdKwVAkAsJszzkXuyRDdnHUpYbTrPG6FiXrQ==", + "version": "1.7.36", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.36.tgz", + "integrity": "sha512-ridD3ay6YM2PEYHZXXFN+edYEv0FOynaqOBP+NSnGNHA35azItIjoIe+KNi4WltGtAjpKCHSpjGCNfna12wdYQ==", "cpu": [ "ia32" ], @@ -4381,9 +4247,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.26.tgz", - "integrity": "sha512-VR+hzg9XqucgLjXxA13MtV5O3C0bK0ywtLIBw/+a+O+Oc6mxFWHtdUeXDbIi5AiPbn0fjgVJMqYnyjGyyX8u0w==", + "version": "1.7.36", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.36.tgz", + "integrity": "sha512-j1z2Z1Ln9d0E3dHsPkC1K9XDh0ojhRPwV+GfRTu4D61PE+aYhYLvbJC6xPvL4/204QrStRS7eDu3m+BcDp3rgQ==", "cpu": [ "x64" ], @@ -4411,9 +4277,9 @@ } }, "node_modules/@swc/types": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.12.tgz", - "integrity": "sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==", + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.13.tgz", + "integrity": "sha512-JL7eeCk6zWCbiYQg2xQSdLXQJl8Qoc9rXmG2cEKvHe3CKwMHwHGpfOb8frzNLmbycOo6I51qxnLnn9ESf4I20Q==", "dev": true, "dependencies": { "@swc/counter": "^0.1.3" @@ -4507,9 +4373,9 @@ } }, "node_modules/@types/dom-webcodecs": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/@types/dom-webcodecs/-/dom-webcodecs-0.1.12.tgz", - "integrity": "sha512-vEkwKEr0xAO2xwNNkYhaltT7jMGjrgAbfpRR3qKRN7eW3B7R7O5fm1scx2OKBY6wMACgjCewhu+ljbCdudY+5A==" + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/@types/dom-webcodecs/-/dom-webcodecs-0.1.13.tgz", + "integrity": "sha512-O5hkiFIcjjszPIYyUSyvScyvrBoV3NOEEZx/pMlsu44TKzWNkLVBBxnxJz42in5n3QIolYOcBYFCPZZ0h8SkwQ==" }, "node_modules/@types/emscripten": { "version": "1.39.13", @@ -4637,9 +4503,9 @@ } }, "node_modules/@types/react": { - "version": "18.3.2", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.2.tgz", - "integrity": "sha512-Btgg89dAnqD4vV7R3hlwOxgqobUQKgx3MmrQRi0yYbs/P0ym8XozIAlkqVilPqHQwXs4e9Tf63rrCgl58BcO4w==", + "version": "18.3.11", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.11.tgz", + "integrity": "sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ==", "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -4664,9 +4530,9 @@ } }, "node_modules/@types/react-dom": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", - "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", "devOptional": true, "dependencies": { "@types/react": "*" @@ -4941,39 +4807,39 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.11", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.11.tgz", - "integrity": "sha512-PwAdxs7/9Hc3ieBO12tXzmTD+Ln4qhT/56S+8DvrrZ4kLDn4Z/AMUr8tXJD0axiJBS0RKIoNaR0yMuQB9v9Udg==", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.12.tgz", + "integrity": "sha512-ISyBTRMmMYagUxhcpyEH0hpXRd/KqDU4ymofPgl2XAkY9ZhQ+h0ovEZJIiPop13UmR/54oA2cgMDjgroRelaEw==", "dev": true, "dependencies": { "@babel/parser": "^7.25.3", - "@vue/shared": "3.5.11", + "@vue/shared": "3.5.12", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.11", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.11.tgz", - "integrity": "sha512-pyGf8zdbDDRkBrEzf8p7BQlMKNNF5Fk/Cf/fQ6PiUz9at4OaUfyXW0dGJTo2Vl1f5U9jSLCNf0EZJEogLXoeew==", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.12.tgz", + "integrity": "sha512-9G6PbJ03uwxLHKQ3P42cMTi85lDRvGLB2rSGOiQqtXELat6uI4n8cNz9yjfVHRPIu+MsK6TE418Giruvgptckg==", "dev": true, "dependencies": { - "@vue/compiler-core": "3.5.11", - "@vue/shared": "3.5.11" + "@vue/compiler-core": "3.5.12", + "@vue/shared": "3.5.12" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.11", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.11.tgz", - "integrity": "sha512-gsbBtT4N9ANXXepprle+X9YLg2htQk1sqH/qGJ/EApl+dgpUBdTv3yP7YlR535uHZY3n6XaR0/bKo0BgwwDniw==", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.12.tgz", + "integrity": "sha512-2k973OGo2JuAa5+ZlekuQJtitI5CgLMOwgl94BzMCsKZCX/xiqzJYzapl4opFogKHqwJk34vfsaKpfEhd1k5nw==", "dev": true, "dependencies": { "@babel/parser": "^7.25.3", - "@vue/compiler-core": "3.5.11", - "@vue/compiler-dom": "3.5.11", - "@vue/compiler-ssr": "3.5.11", - "@vue/shared": "3.5.11", + "@vue/compiler-core": "3.5.12", + "@vue/compiler-dom": "3.5.12", + "@vue/compiler-ssr": "3.5.12", + "@vue/shared": "3.5.12", "estree-walker": "^2.0.2", "magic-string": "^0.30.11", "postcss": "^8.4.47", @@ -4981,19 +4847,19 @@ } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.11", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.11.tgz", - "integrity": "sha512-P4+GPjOuC2aFTk1Z4WANvEhyOykcvEd5bIj2KVNGKGfM745LaXGr++5njpdBTzVz5pZifdlR1kpYSJJpIlSePA==", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.12.tgz", + "integrity": "sha512-eLwc7v6bfGBSM7wZOGPmRavSWzNFF6+PdRhE+VFJhNCgHiF8AM7ccoqcv5kBXA2eWUfigD7byekvf/JsOfKvPA==", "dev": true, "dependencies": { - "@vue/compiler-dom": "3.5.11", - "@vue/shared": "3.5.11" + "@vue/compiler-dom": "3.5.12", + "@vue/shared": "3.5.12" } }, "node_modules/@vue/shared": { - "version": "3.5.11", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.11.tgz", - "integrity": "sha512-W8GgysJVnFo81FthhzurdRAWP/byq3q2qIw70e0JWblzVhjgOMiC2GyovXrZTFQJnFVryYaKGP3Tc9vYzYm6PQ==", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.12.tgz", + "integrity": "sha512-L2RPSAwUFbgZH20etwrXyVyCBu9OxRSi8T/38QsvnkJyvq2LufW2lDCOzm7t/U9C1mkhJGWYfCuFBCmIuNivrg==", "dev": true }, "node_modules/@webassemblyjs/ast": { @@ -5174,9 +5040,9 @@ "optional": true }, "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz", + "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==", "bin": { "acorn": "bin/acorn" }, @@ -5734,11 +5600,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/barcode-detector": { - "version": "2.2.10", - "resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-2.2.10.tgz", - "integrity": "sha512-fB6285Ahd6PIbru+PRw/CL+T1+dtPQmfCwBAwHmw+IWLLHrKH0q37qlAEHXWxPNM6bEmxgTMgGO+MJu/Si1uJQ==", + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-2.2.11.tgz", + "integrity": "sha512-N50XZ6Rav2sxTgHXOc38/mkpVJMan11GZ8Yqi1pPMZpTJSXuZ/FpIee6OtLehZX/Vs4ZOzGbp1DgXzFCfKggWA==", "dependencies": { - "@types/dom-webcodecs": "^0.1.12", + "@types/dom-webcodecs": "^0.1.13", "zxing-wasm": "1.2.14" } }, @@ -5964,9 +5830,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001667", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz", - "integrity": "sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==", + "version": "1.0.30001669", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz", + "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==", "funding": [ { "type": "opencollective", @@ -5997,6 +5863,10 @@ "node": ">=6" } }, + "node_modules/care-livekit": { + "resolved": "apps/care_livekit_fe", + "link": true + }, "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -6502,12 +6372,12 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/cypress": { - "version": "13.14.2", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.14.2.tgz", - "integrity": "sha512-lsiQrN17vHMB2fnvxIrKLAjOr9bPwsNbPZNrWf99s4u+DVmCY6U+w7O3GGG9FvP4EUVYaDu+guWeNLiUzBrqvA==", + "version": "13.15.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.15.0.tgz", + "integrity": "sha512-53aO7PwOfi604qzOkCSzNlWquCynLlKE/rmmpSPcziRH6LNfaDUAklQT6WJIsD8ywxlIy+uVZsnTMCCQVd2kTw==", "hasInstallScript": true, "dependencies": { - "@cypress/request": "^3.0.1", + "@cypress/request": "^3.0.4", "@cypress/xvfb": "^1.2.4", "@types/sinonjs__fake-timers": "8.1.1", "@types/sizzle": "^2.3.2", @@ -6570,9 +6440,9 @@ } }, "node_modules/cypress-split": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/cypress-split/-/cypress-split-1.24.0.tgz", - "integrity": "sha512-ZEFh1m6z+HwPWpB1h9YAF1L6K/wkPBR3vD+v8Rrg8BRm50sZ7oSx6Dw+sv6zfr5Pfqv247CnobLewdFBLlPIBQ==", + "version": "1.24.4", + "resolved": "https://registry.npmjs.org/cypress-split/-/cypress-split-1.24.4.tgz", + "integrity": "sha512-sKBFQB659Ss5B08GSESeMKXBEpPD2wKNGQR1HYbKT98rnM1x5E+MugzcicqEdsK4T2Ng0feuuZQkz8XniOA18A==", "dev": true, "dependencies": { "@actions/core": "^1.10.0", @@ -6580,7 +6450,7 @@ "console.table": "^0.10.0", "debug": "^4.3.4", "fast-shuffle": "^6.1.0", - "find-cypress-specs": "1.43.4", + "find-cypress-specs": "1.45.2", "globby": "^11.1.0", "humanize-duration": "^3.28.0" }, @@ -7054,6 +6924,18 @@ "node": ">=6.0.0" } }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -7122,9 +7004,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.33", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.33.tgz", - "integrity": "sha512-+cYTcFB1QqD4j4LegwLfpCNxifb6dDFUAwk6RsLusCwIaZI6or2f+q8rs5tTB2YC53HhOlIbEaqHMAAC8IOIwA==" + "version": "1.5.39", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.39.tgz", + "integrity": "sha512-4xkpSR6CjuiaNyvwiWDI85N9AxsvbPawB8xc7yzLPonYTuP19BVgYweKyUMFtHEZgIcHWMt1ks5Cqx2m+6/Grg==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -7289,9 +7171,9 @@ } }, "node_modules/es-iterator-helpers": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", - "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.1.0.tgz", + "integrity": "sha512-/SurEfycdyssORP/E+bj4sEu1CWw4EmLDsHynHwSXQ7utgbrMRWW195pTrCjFgFCddf/UkYm3oqKPRq5i8bJbw==", "dev": true, "dependencies": { "call-bind": "^1.0.7", @@ -7301,12 +7183,12 @@ "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", + "globalthis": "^1.0.4", "has-property-descriptors": "^1.0.2", "has-proto": "^1.0.3", "has-symbols": "^1.0.3", "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.2", + "iterator.prototype": "^1.1.3", "safe-array-concat": "^1.1.2" }, "engines": { @@ -8027,9 +7909,9 @@ } }, "node_modules/fast-uri": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.2.tgz", - "integrity": "sha512-GR6f0hD7XXyNJa25Tb9BuIdN0tdr+0BMi6/CJPH3wJO1JjNG3n/VsSw38AwRdKZABm8lGbPfakLRkYzx2V9row==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz", + "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", "dev": true }, "node_modules/fastq": { @@ -8167,16 +8049,16 @@ } }, "node_modules/find-cypress-specs": { - "version": "1.43.4", - "resolved": "https://registry.npmjs.org/find-cypress-specs/-/find-cypress-specs-1.43.4.tgz", - "integrity": "sha512-GAdz6lfBndbOq9OOJ3psThQ56hqgL8tZUCOLnl60d/l56bvHkC0TNwyqlLfBObiscirSZWSgyGL86jJkrpFMrA==", + "version": "1.45.2", + "resolved": "https://registry.npmjs.org/find-cypress-specs/-/find-cypress-specs-1.45.2.tgz", + "integrity": "sha512-D289NM0Dpqoz4+yl8oEtbioqm7zPKQo0hLcvwlg5Z9iBm7EioMIFiOYgluthDNPxUES/aJF+1xHRHAJpC3ejcA==", "dev": true, "dependencies": { "@actions/core": "^1.10.0", "arg": "^5.0.1", "console.table": "^0.10.0", "debug": "^4.3.3", - "find-test-names": "1.28.18", + "find-test-names": "1.28.30", "globby": "^11.1.0", "minimatch": "^3.0.4", "pluralize": "^8.0.0", @@ -8215,13 +8097,13 @@ } }, "node_modules/find-test-names": { - "version": "1.28.18", - "resolved": "https://registry.npmjs.org/find-test-names/-/find-test-names-1.28.18.tgz", - "integrity": "sha512-hhnGdkWK+qEA5Z02Tu0OqGQIUjFZNyOCE4WaJpbhW4hAF1+NZ7OCr0Bss9RCaj7BBtjoIjkU93utobQ8pg2iVg==", + "version": "1.28.30", + "resolved": "https://registry.npmjs.org/find-test-names/-/find-test-names-1.28.30.tgz", + "integrity": "sha512-b5PLJ5WnskdaYHBf+38FN/4TKh5lqwrltITkqxuARsN2bW6civrhqOXbVA+4727YNowYLt/jtIC9Dsn7eJSP6A==", "dev": true, "dependencies": { - "@babel/parser": "^7.23.0", - "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/parser": "^7.24.7", + "@babel/plugin-syntax-jsx": "^7.24.7", "acorn-walk": "^8.2.0", "debug": "^4.3.3", "globby": "^11.0.4", @@ -8335,9 +8217,9 @@ } }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -8496,16 +8378,6 @@ "node": ">=6.9.0" } }, - "node_modules/gentype": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/gentype/-/gentype-4.5.0.tgz", - "integrity": "sha512-XqHBQPS6Qb2HSgNJAwYRXbQJ4LSvz+MgNvuWnj8bz0teSorsy2kDxA6F1eZx5ft8cnfKAls4uNEgd5uNcPbQDg==", - "dev": true, - "hasInstallScript": true, - "bin": { - "gentype": "gentype.exe" - } - }, "node_modules/get-amd-module-type": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/get-amd-module-type/-/get-amd-module-type-6.0.0.tgz", @@ -9191,9 +9063,9 @@ } }, "node_modules/i18next": { - "version": "23.15.2", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.15.2.tgz", - "integrity": "sha512-zcPSWzCvw6uKnuYHIqs4W7hTuB9e3AFcSdZgvCWoPXIZsBjBd4djN2/2uOHIB+1DFFkQnMBXvhNg7J3WyCuywQ==", + "version": "23.16.0", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.16.0.tgz", + "integrity": "sha512-Ni3CG6c14teOogY19YNRl+kYaE/Rb59khy0VyHVn4uOZ97E2E/Yziyi6r3C3s9+wacjdLZiq/LLYyx+Cgd+FCw==", "funding": [ { "type": "individual", @@ -9935,9 +9807,9 @@ "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" }, "node_modules/iterator.prototype": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", - "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.3.tgz", + "integrity": "sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==", "dev": true, "dependencies": { "define-properties": "^1.2.1", @@ -9945,6 +9817,9 @@ "has-symbols": "^1.0.3", "reflect.getprototypeof": "^1.0.4", "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/jackspeak": { @@ -10704,6 +10579,26 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/livekit-client": { + "version": "2.5.9", + "resolved": "https://registry.npmjs.org/livekit-client/-/livekit-client-2.5.9.tgz", + "integrity": "sha512-oDpK6SKYB1F+mNO+25DA0bF0cD2XoOJeD8ji4YQpzDBQv2IxeyKrQhoqXAqrYgIKuiMNkImSf+yg2v7EHSl4Og==", + "dependencies": { + "@livekit/protocol": "1.24.0", + "events": "^3.3.0", + "loglevel": "^1.8.0", + "sdp-transform": "^2.14.1", + "ts-debounce": "^4.0.0", + "tslib": "2.7.0", + "typed-emitter": "^2.1.0", + "webrtc-adapter": "^9.0.0" + } + }, + "node_modules/livekit-client/node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" + }, "node_modules/load-plugin": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/load-plugin/-/load-plugin-6.0.3.tgz", @@ -10804,8 +10699,7 @@ "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, "node_modules/lodash.isplainobject": { "version": "4.0.6", @@ -10891,6 +10785,18 @@ "node": ">=8" } }, + "node_modules/loglevel": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.1.tgz", + "integrity": "sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg==", + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, "node_modules/long": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", @@ -10927,18 +10833,10 @@ "yallist": "^3.0.2" } }, - "node_modules/lucide-react": { - "version": "0.446.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.446.0.tgz", - "integrity": "sha512-BU7gy8MfBMqvEdDPH79VhOXSEgyG8TSPOKWaExWGCQVqnGH7wGgDngPbofu+KdtVjPQBWbEmnfMTq90CTiiDRg==", - "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" - } - }, "node_modules/magic-string": { - "version": "0.30.11", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", - "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "version": "0.30.12", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz", + "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" @@ -12844,9 +12742,9 @@ } }, "node_modules/nan": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", - "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.0.tgz", + "integrity": "sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==", "optional": true }, "node_modules/nanoid": { @@ -13593,9 +13491,9 @@ } }, "node_modules/postcss-load-config/node_modules/yaml": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", - "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", + "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", "bin": { "yaml": "bin.mjs" }, @@ -14087,9 +13985,9 @@ } }, "node_modules/react-i18next": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.0.2.tgz", - "integrity": "sha512-z0W3/RES9Idv3MmJUcf0mDNeeMOUXe+xoL0kPfQPbDoZHmni/XsIoq5zgT2MCFUiau283GuBUK578uD/mkAbLQ==", + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.0.3.tgz", + "integrity": "sha512-BlO1P+oLKjjIxDBQ0GkAIMacgjfMbnvops+3Y5nZXF7UJ99v4KCWr0Na1azJXC8AMiNWp4kgUcFCJM7U9ZsUDg==", "dependencies": { "@babel/runtime": "^7.25.0", "html-parse-stringify": "^3.0.1" @@ -15783,6 +15681,14 @@ "resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.0.tgz", "integrity": "sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw==" }, + "node_modules/sdp-transform": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/sdp-transform/-/sdp-transform-2.14.2.tgz", + "integrity": "sha512-icY6jVao7MfKCieyo1AyxFYm1baiM+fA00qW/KrNNVlkxHAd34riEKuEkUe4bBb3gJwLJZM+xT60Yj1QL8rHiA==", + "bin": { + "sdp-verify": "checker.js" + } + }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -16606,18 +16512,18 @@ "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" }, "node_modules/tailwind-merge": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.3.tgz", - "integrity": "sha512-d9ZolCAIzom1nf/5p4LdD5zvjmgSxY0BGgdSvmXIoMYAiPdAW/dSpP7joCDYFY7r/HkEa2qmPtkgsu0xjQeQtw==", + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.4.tgz", + "integrity": "sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q==", "funding": { "type": "github", "url": "https://github.com/sponsors/dcastil" } }, "node_modules/tailwindcss": { - "version": "3.4.13", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.13.tgz", - "integrity": "sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==", + "version": "3.4.14", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.14.tgz", + "integrity": "sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -17003,6 +16909,11 @@ "typescript": ">=4.2.0" } }, + "node_modules/ts-debounce": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ts-debounce/-/ts-debounce-4.0.0.tgz", + "integrity": "sha512-+1iDGY6NmOGidq7i7xZGA4cm8DAa6fqdYcvO5Z6yBevH++Bdo9Qt/mN0TzHUgcCcKv1gmh9+W5dHqz8pMWbCbg==" + }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", @@ -17023,9 +16934,9 @@ } }, "node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", + "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==" }, "node_modules/tsx": { "version": "4.19.1", @@ -17170,6 +17081,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/typed-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-2.1.0.tgz", + "integrity": "sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==", + "optionalDependencies": { + "rxjs": "*" + } + }, "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -17177,9 +17096,9 @@ "dev": true }, "node_modules/typescript": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", - "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "devOptional": true, "bin": { "tsc": "bin/tsc", @@ -17663,6 +17582,20 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/usehooks-ts": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-3.1.0.tgz", + "integrity": "sha512-bBIa7yUyPhE1BCc0GmR96VU/15l/9gP1Ch5mYdLcFBaFGQsdmXkvjV0TtOqW1yUd6VjIwDunm+flSciCQXujiw==", + "dependencies": { + "lodash.debounce": "^4.0.8" + }, + "engines": { + "node": ">=16.15.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -17958,9 +17891,9 @@ } }, "node_modules/vite": { - "version": "5.4.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz", - "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==", + "version": "5.4.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.9.tgz", + "integrity": "sha512-20OVpJHh0PAM0oSOELa5GaZNWeDjcAvQjGXy2Uyr+Tp+/D2/Hdz6NLgpJLsarPTA2QJ6v8mX2P1ZfbsSKvdMkg==", "dev": true, "dependencies": { "esbuild": "^0.21.3", diff --git a/package.json b/package.json index 50711943a85..7749374be44 100644 --- a/package.json +++ b/package.json @@ -26,12 +26,19 @@ ], "author": "Open Healthcare Network Contributors", "license": "MIT", + "workspaces": [ + "apps/*" + ], "scripts": { - "build:react": "cross-env NODE_ENV=production vite build", - "build": "npm run generate-build-meta && npm run supported-browsers && npm run build:react", "dev": "npm run supported-browsers && vite", + "local": "npm run supported-browsers && vite --mode docker", "preview": "cross-env NODE_ENV=production vite preview", - "generate-build-meta": "node ./scripts/generate-build-version.js", + "build:meta": "node ./scripts/generate-build-version.js", + "build:react": "cross-env NODE_ENV=production vite build", + "supported-browsers": "node ./scripts/generate-supported-browsers.mjs", + "build": "npm run install-all && npm run build:meta && npm run supported-browsers && npm run build:react", + "setup": "node scripts/setup-care-apps.js", + "install-all": "npm install && npm run setup && npm install", "test": "snyk test", "cypress:open": "cross-env NODE_ENV=development cypress open", "cypress:run": "cross-env NODE_ENV=development cypress run", @@ -40,8 +47,7 @@ "prepare": "husky install", "lint": "eslint ./src", "lint-fix": "eslint ./src --fix", - "format": "prettier ./src --write", - "supported-browsers": "node ./scripts/generate-supported-browsers.mjs" + "format": "prettier ./src --write" }, "dependencies": { "@fontsource/figtree": "^5.1.0", @@ -55,7 +61,7 @@ "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-toast": "^1.2.2", "@sentry/browser": "^8.33.0", - "@yudiel/react-qr-scanner": "^2.0.0-beta.3", + "@yudiel/react-qr-scanner": "^2.0.8", "axios": "^1.7.7", "bowser": "^2.11.0", "browser-image-compression": "^2.0.2", @@ -73,7 +79,6 @@ "i18next": "^23.11.4", "i18next-browser-languagedetector": "^7.2.1", "lodash-es": "^4.17.21", - "lucide-react": "^0.446.0", "postcss-loader": "^7.3.3", "qrcode.react": "^3.1.0", "raviger": "^4.1.2", @@ -104,7 +109,7 @@ "@types/lodash-es": "^4.17.12", "@types/node": "^22.7.4", "@types/qrcode.react": "^1.0.5", - "@types/react": "18.3.2", + "@types/react": "^18.3.11", "@types/react-copy-to-clipboard": "^5.0.7", "@types/react-csv": "^1.1.10", "@types/react-dom": "^18.3.0", @@ -115,13 +120,13 @@ "autoprefixer": "^10.4.19", "cypress-localstorage-commands": "^2.2.5", "cypress-split": "^1.23.2", + "dotenv": "^16.4.5", "eslint-config-prettier": "^9.1.0", "eslint-plugin-i18next": "^6.0.9", "eslint-plugin-mdx": "^3.1.5", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-react": "^7.35.0", "eslint-plugin-react-hooks": "^4.6.2", - "gentype": "^4.5.0", "glob": "^11.0.0", "husky": "^8.0.3", "lint-staged": "^13.2.3", @@ -129,7 +134,6 @@ "postcss": "^8.4.38", "prettier": "^3.3.3", "prettier-plugin-tailwindcss": "^0.6.5", - "prop-types": "^15.8.1", "redux-devtools-extension": "^2.13.9", "snyk": "^1.1291.0", "tailwindcss": "^3.4.3", diff --git a/public/favicon-light.ico b/public/favicon-light.ico deleted file mode 100644 index 244b9d6c1d3..00000000000 Binary files a/public/favicon-light.ico and /dev/null differ diff --git a/public/favicon.ico b/public/favicon.ico index 244b9d6c1d3..67a5686e32f 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/scripts/setup-care-apps.js b/scripts/setup-care-apps.js new file mode 100644 index 00000000000..4106775e63e --- /dev/null +++ b/scripts/setup-care-apps.js @@ -0,0 +1,113 @@ +// eslint-disable-next-line @typescript-eslint/no-var-requires +const { execSync } = require("child_process"); +// eslint-disable-next-line @typescript-eslint/no-var-requires +const fs = require("fs"); +// eslint-disable-next-line @typescript-eslint/no-var-requires +const path = require("path"); +// eslint-disable-next-line @typescript-eslint/no-var-requires +require("dotenv").config({ path: [".env.local", ".env"] }); + +console.log("Preinstall script running"); + +// Function to read apps.json or return an empty array if it doesn't exist +function readAppsConfig() { + const appsConfig = process.env.REACT_ENABLED_APPS + ? process.env.REACT_ENABLED_APPS.split(",").map((app) => ({ + branch: app.split("@")[1], + package: app.split("@")[0], + })) + : []; + console.log("Found apps: ", appsConfig); + return appsConfig; +} + +const appsConfig = readAppsConfig(); +const appsDir = path.join(__dirname, "..", "apps"); + +// Create apps directory if it doesn't exist +if (!fs.existsSync(appsDir)) { + fs.mkdirSync(appsDir); +} + +const installApp = (app) => { + const appDir = path.join(appsDir, app.package.split("/")[1]); + + console.log(`Cloning ${app.package}...`); + execSync( + `npx -y gitget ${app.package}${app.branch ? `#${app.branch}` : ""} apps/${app.package.split("/")[1]} `, + { + stdio: "inherit", + }, + ); + // Create a care-package.lock file + fs.writeFileSync( + path.join(appDir, "care-package.lock"), + JSON.stringify( + { + package: app.package, + branch: app.branch, + }, + null, + 2, + ), + ); +}; + +// Clone or pull care apps +appsConfig.forEach((app) => { + const appDir = path.join(appsDir, app.package.split("/")[1]); + if (fs.existsSync(appDir)) { + if (fs.existsSync(path.join(appDir, "care-package.lock"))) { + // verify if the branch and package match with the care-package.lock file + const lockFile = JSON.parse( + fs.readFileSync(path.join(appDir, "care-package.lock"), "utf8"), + ); + if (lockFile.package === app.package && lockFile.branch === app.branch) { + console.log(`Package already exists. Pulling latest changes...`); + execSync(`git -C "${appDir}" pull`, { stdio: "inherit" }); + return; + } else { + console.log(`Branch/package does not match. Recreating...`); + fs.rmSync(appDir, { recursive: true, force: true }); + } + } else { + console.log( + `Package already exists but care-package.lock file does not exist. Recreating...`, + ); + fs.rmSync(appDir, { recursive: true, force: true }); + } + } + + installApp(app); +}); + +console.log("All apps have been cloned or updated in apps directory."); + +const importApps = appsConfig.map((app) => ({ + ...app, + camelCaseName: app.package + .split("/")[1] + .replace(/[-_]/g, "") + .replace(/\b\w/g, (char, index) => + index === 0 ? char.toLowerCase() : char.toUpperCase(), + ), +})); + +// Generate pluginMap.ts +const pluginMapPath = path.join(__dirname, "..", "src", "pluginMap.ts"); +const pluginMapContent = `import { PluginManifest } from "./pluginTypes"; + +${importApps + .map( + (app) => + `import ${app.camelCaseName}Manifest from "@app-manifest/${app.package.split("/")[1]}";`, + ) + .join("\n")} + +export const pluginMap: PluginManifest[] = [ +${importApps.map((app) => ` ${app.camelCaseName}Manifest`).join(",\n")} +]; +`; + +fs.writeFileSync(pluginMapPath, pluginMapContent); +console.log("Generated pluginMap.ts"); diff --git a/src/App.tsx b/src/App.tsx index 98cf307f18a..0b2d20e805a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,29 +1,30 @@ import { Suspense } from "react"; import Routers from "./Routers"; -import ThemedFavicon from "./CAREUI/misc/ThemedFavicon"; import Integrations from "./Integrations"; import Loading from "./Components/Common/Loading"; import HistoryAPIProvider from "./Providers/HistoryAPIProvider"; import AuthUserProvider from "./Providers/AuthUserProvider"; +import PluginEngine from "./PluginEngine"; import { FeatureFlagsProvider } from "./Utils/featureFlags"; import { Toaster } from "./Components/ui/toaster"; const App = () => { return ( }> - - - }> - - - - + + + }> + + + + - {/* Integrations */} - - - - + {/* Integrations */} + + + + + ); }; diff --git a/src/CAREUI/display/Timeline.tsx b/src/CAREUI/display/Timeline.tsx index ee21b337724..6701d9a7511 100644 --- a/src/CAREUI/display/Timeline.tsx +++ b/src/CAREUI/display/Timeline.tsx @@ -55,7 +55,7 @@ export const TimelineNode = (props: TimelineNodeProps) => { const { t } = useTranslation(); return ( -
  • +
    { {props.children}
    -
  • + ); }; diff --git a/src/CAREUI/icons/CareIcon.tsx b/src/CAREUI/icons/CareIcon.tsx index 3bb67629bc2..a45117cc675 100644 --- a/src/CAREUI/icons/CareIcon.tsx +++ b/src/CAREUI/icons/CareIcon.tsx @@ -1,13 +1,12 @@ import iconData from "./UniconPaths.json"; -import { transformIcons } from "./icon"; -import { useEffect } from "react"; +import "./icon.css"; export type IconName = keyof typeof iconData; export interface CareIconProps { icon: IconName; - className?: string | undefined; - onClick?: React.MouseEventHandler | undefined; + className?: string; + onClick?: React.MouseEventHandler; id?: string; } @@ -25,14 +24,32 @@ export default function CareIcon({ className, onClick, }: CareIconProps) { - const effectiveClassName = icon - ? `care-${icon} ${className ?? ""}` - : className; + // TODO: fill & strokeWidth are defined for only one icon + // Rethink Implementation + const [viewBox, path, fill, strokeWidth] = iconData[icon] as [ + number, + string, + boolean | undefined, + number | undefined, + ]; + + const svgClassName = `care-svg-icon__baseline ${className || ""}`.trim(); - useEffect(() => transformIcons(), [effectiveClassName]); return ( - - - + + + ); } diff --git a/src/CAREUI/icons/icon.js b/src/CAREUI/icons/icon.js deleted file mode 100644 index c917e664351..00000000000 --- a/src/CAREUI/icons/icon.js +++ /dev/null @@ -1,49 +0,0 @@ -import "./icon.css"; -import iconData from "./UniconPaths.json"; - -const xmlns = "http://www.w3.org/2000/svg"; - -const findIconName = (className) => { - const iconName = className.match(/care-([a-zA-Z0-9-]+)/); - return iconName ? iconName[1] : "default"; -}; - -const getIconData = (className) => { - const data = iconData[findIconName(className)]; - return typeof data === "undefined" ? iconData["default"] : data; -}; - -const createSvg = (className) => { - const icon = getIconData(className); - const el = document.createElementNS(xmlns, "svg"); - el.setAttribute( - "class", - className.replace("care", "care-svg-icon__baseline"), - ); - el.setAttribute("role", "img"); - el.setAttribute("xmlns", xmlns); - el.setAttribute("viewBox", `0 0 ${icon[0]} ${icon[0]}`); - - const path = document.createElementNS(xmlns, "path"); - if (icon[2] === false) { - path.setAttribute("stroke", "currentColor"); - path.setAttribute("stroke-width", `${icon[3]}`); - } - path.setAttribute("fill", icon[2] === false ? "none" : "currentColor"); - path.setAttribute("d", icon[1]); - el.appendChild(path); - return el; -}; - -export const transformIcons = () => { - const elements = Array.from(document.getElementsByClassName("care")); - elements.forEach((element) => { - if (element.tagName == "I") { - element.parentNode.replaceChild(createSvg(element.className), element); - } - }); -}; - -export const addListener = () => { - window.addEventListener("load", transformIcons); -}; diff --git a/src/CAREUI/interactive/LegendInput.tsx b/src/CAREUI/interactive/LegendInput.tsx index e164e4d1b4e..83486095f7a 100644 --- a/src/CAREUI/interactive/LegendInput.tsx +++ b/src/CAREUI/interactive/LegendInput.tsx @@ -2,6 +2,7 @@ import CareIcon from "../icons/CareIcon"; import { classNames } from "../../Utils/utils"; import { RefObject, useRef, useState, useEffect } from "react"; import { useTranslation } from "react-i18next"; + type InputProps = { id?: string; name: string; @@ -12,12 +13,12 @@ type InputProps = { required?: boolean; placeholder?: string; value?: string; - onChange?: (e: any) => void; - onFocus?: (e: any) => void; - onBlur?: (e: any) => void; - onKeyUp?: (e: any) => void; - onKeyDown?: (e: any) => void; - onKeyPress?: (e: any) => void; + onChange?: (e: React.ChangeEvent) => void; + onFocus?: (e: React.FocusEvent) => void; + onBlur?: (e: React.FocusEvent) => void; + onKeyUp?: (e: React.KeyboardEvent) => void; + onKeyDown?: (e: React.KeyboardEvent) => void; + onKeyPress?: (e: React.KeyboardEvent) => void; disabled?: boolean; error?: string; className?: string; diff --git a/src/CAREUI/misc/PaginatedList.tsx b/src/CAREUI/misc/PaginatedList.tsx index ec270bf8134..3b68b23bd30 100644 --- a/src/CAREUI/misc/PaginatedList.tsx +++ b/src/CAREUI/misc/PaginatedList.tsx @@ -33,6 +33,8 @@ function useContextualized() { interface Props extends QueryOptions> { route: QueryRoute>; perPage?: number; + initialPage?: number; + onPageChange?: (page: number) => void; queryCB?: ( query: ReturnType>>, ) => void; @@ -49,7 +51,13 @@ export default function PaginatedList({ queryCB, ...queryOptions }: Props) { - const [currentPage, setPage] = useState(1); + const [currentPage, _setPage] = useState(queryOptions.initialPage ?? 1); + + const setPage = (page: number) => { + _setPage(page); + queryOptions.onPageChange?.(page); + }; + const query = useQuery(route, { ...queryOptions, query: { diff --git a/src/CAREUI/misc/ThemedFavicon.tsx b/src/CAREUI/misc/ThemedFavicon.tsx deleted file mode 100644 index b908f566b89..00000000000 --- a/src/CAREUI/misc/ThemedFavicon.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { useEffect } from "react"; - -export default function ThemedFavicon() { - useEffect(() => { - const darkThemeMq = window.matchMedia("(prefers-color-scheme: dark)"); - const favicon = document.querySelector( - "link[rel~='icon']", - ) as HTMLLinkElement; - - favicon.href = darkThemeMq.matches ? "/favicon-light.ico" : "/favicon.ico"; - }, []); - - return null; -} diff --git a/src/Common/hooks/useCareApps.ts b/src/Common/hooks/useCareApps.ts new file mode 100644 index 00000000000..77b5489052e --- /dev/null +++ b/src/Common/hooks/useCareApps.ts @@ -0,0 +1,35 @@ +import { createContext, useContext } from "react"; +import { INavItem } from "@/Components/Common/Sidebar/Sidebar"; +import { PluginManifest } from "@/pluginTypes"; + +export const CareAppsContext = createContext([]); + +export const useCareApps = () => { + const ctx = useContext(CareAppsContext); + if (!ctx) { + throw new Error( + "'useCareApps' must be used within 'CareAppsProvider' only", + ); + } + return ctx; +}; + +export const useCareAppNavItems = () => { + const careApps = useCareApps(); + const navItems = careApps.reduce((acc, plugin) => { + return [...acc, ...(plugin.navItems || [])]; + }, []); + return navItems; +}; + +// If required; Reduce plugin.routes to a single pluginRoutes object of type Record JSX.Element> +export function usePluginRoutes() { + const careApps = useCareApps(); + const routes = careApps.reduce((acc, plugin) => { + return { ...acc, ...plugin.routes }; + }, {}); + if (!routes) { + throw new Error("'usePluginRoutes' must be used within 'AppRouter' only"); + } + return routes; +} diff --git a/src/Components/ABDM/LinkABHANumberModal.tsx b/src/Components/ABDM/LinkABHANumberModal.tsx index 8d6365387cd..c2855ae7569 100644 --- a/src/Components/ABDM/LinkABHANumberModal.tsx +++ b/src/Components/ABDM/LinkABHANumberModal.tsx @@ -225,7 +225,6 @@ const ScanABHAQRSection = ({ Notify.Error({ msg: "Linking Failed" }); } } catch (e) { - console.log(e); Notify.Error({ msg: "Invalid ABHA QR" }); } finally { setIsLoading(false); diff --git a/src/Components/Assets/AssetsList.tsx b/src/Components/Assets/AssetsList.tsx index ee27c2a484f..77961d15b0d 100644 --- a/src/Components/Assets/AssetsList.tsx +++ b/src/Components/Assets/AssetsList.tsx @@ -159,7 +159,6 @@ const AssetsList = () => { }); } } catch (err) { - console.log(err); Notification.Error({ msg: t("invalid_asset_id_msg"), }); diff --git a/src/Components/CameraFeed/CentralLiveMonitoring/index.tsx b/src/Components/CameraFeed/CentralLiveMonitoring/index.tsx index 3cca4c00ec4..95e3b98c818 100644 --- a/src/Components/CameraFeed/CentralLiveMonitoring/index.tsx +++ b/src/Components/CameraFeed/CentralLiveMonitoring/index.tsx @@ -66,7 +66,7 @@ export default function CentralLiveMonitoring(props: { facilityId: string }) { fullscreen={isFullscreen} onExit={() => setFullscreen(false)} > -
    +
    {data.results.map((asset) => (
    diff --git a/src/Components/Common/Breadcrumbs.tsx b/src/Components/Common/Breadcrumbs.tsx index c092ecbbc93..aaee7ac0b64 100644 --- a/src/Components/Common/Breadcrumbs.tsx +++ b/src/Components/Common/Breadcrumbs.tsx @@ -58,8 +58,8 @@ export default function Breadcrumbs({ style: replacements[field]?.style || "", })); - const renderCrumb = (crumb: any, index: number, array: any[]) => { - const isLastItem = index === array.length - 1; + const renderCrumb = (crumb: any, index: number) => { + const isLastItem = index === crumbs!.length - 1; return (
  • )} - {crumbs && - crumbs.length > 0 && - renderCrumb(crumbs[crumbs.length - 1], crumbs.length - 1, crumbs)} + {crumbs?.length && + renderCrumb(crumbs[crumbs.length - 1], crumbs.length - 1)} ); diff --git a/src/Components/Common/ErrorBoundary.tsx b/src/Components/Common/ErrorBoundary.tsx new file mode 100644 index 00000000000..47172a240ef --- /dev/null +++ b/src/Components/Common/ErrorBoundary.tsx @@ -0,0 +1,36 @@ +import React, { Component, ErrorInfo, ReactNode } from "react"; + +interface Props { + children: ReactNode; + fallback?: ReactNode; +} + +interface State { + hasError: boolean; +} + +class ErrorBoundary extends Component { + public state: State = { + hasError: false, + }; + + public static getDerivedStateFromError(_: Error): State { + // Update state so the next render will show the fallback UI. + return { hasError: true }; + } + + public componentDidCatch(error: Error, errorInfo: ErrorInfo) { + console.error("Uncaught error:", error, errorInfo); + } + + public render() { + if (this.state.hasError) { + // You can render any custom fallback UI + return this.props.fallback ||

    Sorry.. there was an error

    ; + } + + return this.props.children; + } +} + +export default ErrorBoundary; diff --git a/src/Components/Common/Sidebar/Sidebar.tsx b/src/Components/Common/Sidebar/Sidebar.tsx index 0e9ee34b715..4e3929b187f 100644 --- a/src/Components/Common/Sidebar/Sidebar.tsx +++ b/src/Components/Common/Sidebar/Sidebar.tsx @@ -8,11 +8,18 @@ import SlideOver from "../../../CAREUI/interactive/SlideOver"; import { classNames } from "../../../Utils/utils"; import { Link } from "raviger"; import careConfig from "@careConfig"; +import { useCareAppNavItems } from "@/Common/hooks/useCareApps"; export const SIDEBAR_SHRINK_PREFERENCE_KEY = "sidebarShrinkPreference"; const LOGO_COLLAPSE = "/images/care_logo_mark.svg"; +export interface INavItem { + text: string; + to?: string; + icon: IconName; +} + type StatelessSidebarProps = | { shrinkable: true; @@ -32,11 +39,7 @@ const StatelessSidebar = ({ setShrinked, onItemClick, }: StatelessSidebarProps) => { - const NavItems: { - text: string; - to: string; - icon: IconName; - }[] = [ + const BaseNavItems: INavItem[] = [ { text: "Facilities", to: "/facility", icon: "l-hospital" }, { text: "Patients", to: "/patients", icon: "l-user-injured" }, { text: "Assets", to: "/assets", icon: "l-shopping-cart-alt" }, @@ -47,6 +50,10 @@ const StatelessSidebar = ({ { text: "Notice Board", to: "/notice_board", icon: "l-meeting-board" }, ]; + const PluginNavItems = useCareAppNavItems(); + + const NavItems = [...BaseNavItems, ...PluginNavItems]; + const activeLink = useActiveLink(); const Item = shrinked ? ShrinkedSidebarItem : SidebarItem; @@ -104,11 +111,11 @@ const StatelessSidebar = ({ : "overflow-y-auto overflow-x-hidden" }`} > - {shrinked && ( + {setShrinked && shrinked && (
    setShrinked && setShrinked(!shrinked)} + toggle={() => setShrinked(!shrinked)} />
    )} @@ -123,11 +130,11 @@ const StatelessSidebar = ({ src={shrinked ? LOGO_COLLAPSE : careConfig.mainLogo?.light} /> - {!shrinked && ( + {setShrinked && !shrinked && (
    setShrinked && setShrinked(!shrinked)} + toggle={() => setShrinked(!shrinked)} />
    )} @@ -151,7 +158,7 @@ const StatelessSidebar = ({ {...i} icon={} selected={i.to === activeLink} - do={() => onItemClick && onItemClick(false)} + onItemClick={() => onItemClick && onItemClick(false)} handleOverflow={handleOverflow} /> ); @@ -220,7 +227,7 @@ interface ToggleShrinkProps { const ToggleShrink = ({ shrinked, toggle }: ToggleShrinkProps) => (
    ; text: string; icon: SidebarIcon; + onItemClick?: () => void; external?: true | undefined; badgeCount?: number | undefined; selected?: boolean | undefined; handleOverflow?: any; -} & ({ to: string; do?: undefined } | { to?: string; do: () => void }); +} & ({ to?: string; do?: undefined } | { to?: string; do: () => void }); type SidebarItemBaseProps = SidebarItemProps & { shrinked?: boolean; - ref: Ref; }; -const SidebarItemBase = forwardRef( - ( - { shrinked, external, ...props }: SidebarItemBaseProps, - ref: Ref, - ) => { +const SidebarItemBase = forwardRef( + ({ shrinked, external, ...props }, ref) => { const { t } = useTranslation(); const { resetHistory } = useAppHistory(); return ( { + // On Review: Check if resetHistory is working as intended. + props.do?.(); + props.onItemClick?.(); + resetHistory(); + }} onMouseEnter={() => { props.handleOverflow(true); }} diff --git a/src/Components/Common/Sidebar/SidebarUserCard.tsx b/src/Components/Common/Sidebar/SidebarUserCard.tsx index 9e9b113c4aa..4630438ab70 100644 --- a/src/Components/Common/Sidebar/SidebarUserCard.tsx +++ b/src/Components/Common/Sidebar/SidebarUserCard.tsx @@ -43,13 +43,7 @@ const SidebarUserCard: React.FC = ({ shrinked }) => { id="sign-out-button" className={`flex h-full items-center justify-start transition-all duration-200 ease-in-out ${shrinked ? "pl-2" : "pl-5 pr-4"}`} > -
    - -
    - + {!shrinked && (
    {t("sign_out")} diff --git a/src/Components/Common/SortDropdown.tsx b/src/Components/Common/SortDropdown.tsx index b54edffa595..0c4fddec58c 100644 --- a/src/Components/Common/SortDropdown.tsx +++ b/src/Components/Common/SortDropdown.tsx @@ -29,6 +29,7 @@ export default function SortDropdownMenu(props: Props) { > {props.options.map(({ isAscending, value }) => (
    diff --git a/src/Components/ErrorPages/SessionExpired.tsx b/src/Components/ErrorPages/SessionExpired.tsx index 419c9c44dce..32036a0319d 100644 --- a/src/Components/ErrorPages/SessionExpired.tsx +++ b/src/Components/ErrorPages/SessionExpired.tsx @@ -1,23 +1,16 @@ import * as Notification from "../../Utils/Notifications"; -import { useNavigate } from "raviger"; import { useEffect } from "react"; import { useTranslation } from "react-i18next"; import { useAuthContext } from "../../Common/hooks/useAuthUser"; export default function SessionExpired() { - const { signOut, user } = useAuthContext(); - const isAuthenticated = !!user; - const navigate = useNavigate(); + const { signOut } = useAuthContext(); const { t } = useTranslation(); useEffect(() => { Notification.closeAllNotifications(); }, []); - if (isAuthenticated) { - navigate("/"); - } - return (
    diff --git a/src/Components/Facility/ConsultationDetails/index.tsx b/src/Components/Facility/ConsultationDetails/index.tsx index d9a8a03f480..3b34689221d 100644 --- a/src/Components/Facility/ConsultationDetails/index.tsx +++ b/src/Components/Facility/ConsultationDetails/index.tsx @@ -255,6 +255,7 @@ export const ConsultationDetails = (props: any) => { {!consultationData.discharge_date && ( <>
    diff --git a/src/Components/Facility/FacilityCard.tsx b/src/Components/Facility/FacilityCard.tsx index 0febe36e4b7..f3614d2685a 100644 --- a/src/Components/Facility/FacilityCard.tsx +++ b/src/Components/Facility/FacilityCard.tsx @@ -61,12 +61,7 @@ export const FacilityCard = (props: { facility: any; userType: any }) => { alt={facility.name} className="h-full max-h-32 w-full object-cover" /> - )) || ( - - )} + )) || }
    diff --git a/src/Components/Facility/FacilityHome.tsx b/src/Components/Facility/FacilityHome.tsx index 7edbb939b8a..6f73fee4a54 100644 --- a/src/Components/Facility/FacilityHome.tsx +++ b/src/Components/Facility/FacilityHome.tsx @@ -43,6 +43,7 @@ type Props = { }; import Loading from "@/Components/Common/Loading"; +import { Avatar } from "@/Components/Common/Avatar.js"; export const getFacilityFeatureIcon = (featureId: number) => { const feature = FACILITY_FEATURE_TYPES.find((f) => f.id === featureId); if (!feature?.icon) return null; @@ -124,7 +125,7 @@ export const FacilityHome = ({ facilityId }: Props) => { onClick={() => setEditCoverImage(true)} > - {`${hasCoverImage ? "Edit" : "Upload"}`} + {t(hasCoverImage ? "edit" : "upload")}
    ); @@ -181,11 +182,7 @@ export const FacilityHome = ({ facilityId }: Props) => { hasPermissionToEditCoverImage && setEditCoverImage(true) } > -
    )} @@ -210,13 +207,7 @@ export const FacilityHome = ({ facilityId }: Props) => { ) : (
    - - - +
    )} {editCoverImageTooltip} @@ -291,7 +282,10 @@ export const FacilityHome = ({ facilityId }: Props) => {
    {spokesQuery.data?.results.map((spoke) => ( - + ))}
    diff --git a/src/Components/Facility/HospitalList.tsx b/src/Components/Facility/FacilityList.tsx similarity index 99% rename from src/Components/Facility/HospitalList.tsx rename to src/Components/Facility/FacilityList.tsx index e7949440307..503f0fde34d 100644 --- a/src/Components/Facility/HospitalList.tsx +++ b/src/Components/Facility/FacilityList.tsx @@ -18,7 +18,7 @@ import routes from "../../Redux/api"; import CareIcon from "../../CAREUI/icons/CareIcon"; import Loading from "@/Components/Common/Loading"; -export const HospitalList = () => { +export const FacilityList = () => { const { qParams, updateQuery, diff --git a/src/Components/Facility/LocationManagement.tsx b/src/Components/Facility/LocationManagement.tsx index 1aaf57b7233..2223aa2e8fd 100644 --- a/src/Components/Facility/LocationManagement.tsx +++ b/src/Components/Facility/LocationManagement.tsx @@ -16,6 +16,7 @@ import useAuthUser from "../../Common/hooks/useAuthUser"; import useQuery from "../../Utils/request/useQuery"; import Loading from "@/Components/Common/Loading"; +import { cn } from "@/lib/utils"; interface Props { facilityId: string; } @@ -87,14 +88,14 @@ export default function LocationManagement({ facilityId }: Props) { id="add-new-location" href={`/facility/${facilityId}/location/add`} authorizeFor={NonReadOnlyUsers} - className="mr-4 hidden lg:block" + className="hidden lg:block" > Add New Location } > -
    +
    - className="my-8 grid gap-3 @4xl:grid-cols-2 @6xl:grid-cols-3 @[100rem]:grid-cols-4 lg:mx-8"> + className="my-8 grid gap-3 @4xl:grid-cols-2 @6xl:grid-cols-3 @[100rem]:grid-cols-4"> {(item) => ( { - const { loading, data } = useQuery(routes.listFacilityBeds, { + const bedsQuery = useQuery(routes.listFacilityBeds, { query: { facility: facilityId, location: id, }, }); - const totalBeds = data?.count ?? 0; - - if (loading) { - return ; - } + const totalBeds = bedsQuery.data?.count; return (
    @@ -290,13 +287,16 @@ const Location = ({ id="manage-bed-button" variant="secondary" border - className="mt-3 flex w-full items-center justify-between" + className={cn( + "mt-3 flex w-full items-center justify-between", + totalBeds != null && "opacity-50", + )} href={`location/${id}/beds`} > Manage Beds - {totalBeds} + {totalBeds ?? "--"}
    diff --git a/src/Components/Notifications/ShowPushNotification.tsx b/src/Components/Notifications/ShowPushNotification.tsx index 2d2faa5ff5f..ca465f98df7 100644 --- a/src/Components/Notifications/ShowPushNotification.tsx +++ b/src/Components/Notifications/ShowPushNotification.tsx @@ -1,9 +1,8 @@ -import { DetailRoute } from "../../Routers/types"; import useQuery from "../../Utils/request/useQuery"; import routes from "../../Redux/api"; import { NotificationData } from "./models"; -export default function ShowPushNotification({ id }: DetailRoute) { +export default function ShowPushNotification({ id }: { id: string }) { useQuery(routes.getNotificationData, { pathParams: { id }, onResponse(res) { diff --git a/src/Components/Patient/ManagePatients.tsx b/src/Components/Patient/ManagePatients.tsx index 0be6fe6b819..46dad347dd5 100644 --- a/src/Components/Patient/ManagePatients.tsx +++ b/src/Components/Patient/ManagePatients.tsx @@ -471,7 +471,7 @@ export const PatientManager = () => { let patientList: ReactNode[] = []; if (data?.count) { - patientList = data.results.map((patient: any) => { + patientList = data.results.map((patient) => { let patientUrl = ""; if ( patient.last_consultation && @@ -506,7 +506,7 @@ export const PatientManager = () => {
    -
    +
    {patient?.last_consultation?.current_bed && patient?.last_consultation?.discharge_date === null ? (
    @@ -541,9 +541,10 @@ export const PatientManager = () => {
    ) : ( -
    +
    diff --git a/src/Components/Patient/PatientConsentRecordBlock.tsx b/src/Components/Patient/PatientConsentRecordBlock.tsx index 07931380cb6..b66a6cbd8aa 100644 --- a/src/Components/Patient/PatientConsentRecordBlock.tsx +++ b/src/Components/Patient/PatientConsentRecordBlock.tsx @@ -70,10 +70,7 @@ export default function PatientConsentRecordBlockGroup(props: { { - console.log(e.value); - setPatientCodeStatus(e.value); - }} + onChange={(e) => setPatientCodeStatus(e.value)} value={ CONSENT_PATIENT_CODE_STATUS_CHOICES.find( (c) => c.id === patientCodeStatus, diff --git a/src/Components/Patient/PatientHome.tsx b/src/Components/Patient/PatientHome.tsx index f6fe4f28a72..4b88df5bd20 100644 --- a/src/Components/Patient/PatientHome.tsx +++ b/src/Components/Patient/PatientHome.tsx @@ -253,7 +253,7 @@ export const PatientHome = (props: any) => { return ( {
    {field("nationality").value === "India" && ( -
    +
    {
    )} -
    +
    {
    -
    +

    Insurance Details diff --git a/src/Components/Users/ManageUsers.tsx b/src/Components/Users/ManageUsers.tsx index 2a00a2a8305..801ffae03af 100644 --- a/src/Components/Users/ManageUsers.tsx +++ b/src/Components/Users/ManageUsers.tsx @@ -415,7 +415,7 @@ export default function ManageUsers() { }} > -

    Linked Facilities

    +

    {t("linked_facilities")}

    -

    Linked Skills

    +

    {t("linked_skills")}

    {["DistrictAdmin", "StateAdmin"].includes( @@ -781,7 +781,7 @@ export function UserFacilities(props: { user: any }) { selected={facility} setSelected={setFacility} errors="" - className="z-40" + className="z-40 w-full" /> { selected={selectedSkill} setSelected={setSelectedSkill} errors="" + className="w-full" userSkills={skills?.results || []} />

    - Personal Information + {t("personal_information")}

    - Local Body, District and State are Non Editable Settings. + {t("local_body")}, {t("district")}, {t("state")}{" "} + {t("are_non_editable_fields")}.

    - {showEdit ? "Cancel" : "Edit User Profile"} + {showEdit ? t("cancel") : t("edit_user_profile")} - Sign out + {t("sign_out")}
    @@ -498,7 +499,7 @@ export default function UserProfile() { id="username-profile-details" >
    - Username + {t("username")}
    {userData?.username || "-"} @@ -509,7 +510,7 @@ export default function UserProfile() { id="contactno-profile-details" >
    - Contact No + {t("phone_number")}
    {userData?.phone_number || "-"} @@ -521,7 +522,7 @@ export default function UserProfile() { id="whatsapp-profile-details" >
    - Whatsapp No + {t("whatsapp_number")}
    {userData?.alt_phone_number || "-"} @@ -532,7 +533,7 @@ export default function UserProfile() { id="emailid-profile-details" >
    - Email address + {t("email")}
    {userData?.email || "-"} @@ -543,7 +544,7 @@ export default function UserProfile() { id="firstname-profile-details" >
    - First Name + {t("first_name")}
    {userData?.first_name || "-"} @@ -554,7 +555,7 @@ export default function UserProfile() { id="lastname-profile-details" >
    - Last Name + {t("last_name")}
    {userData?.last_name || "-"} @@ -565,7 +566,7 @@ export default function UserProfile() { id="date_of_birth-profile-details" >
    - Date of Birth + {t("date_of_birth")}
    {userData?.date_of_birth @@ -575,7 +576,7 @@ export default function UserProfile() {
    - Access Level + {t("access_level")}
    {" "} @@ -587,7 +588,7 @@ export default function UserProfile() { id="gender-profile-details" >
    - Gender + {t("gender")}
    {userData?.gender || "-"} @@ -595,7 +596,7 @@ export default function UserProfile() {
    - Local Body + {t("local_body")}
    {userData?.local_body_object?.name || "-"} @@ -603,7 +604,7 @@ export default function UserProfile() {
    - District + {t("district")}
    {userData?.district_object?.name || "-"} @@ -611,7 +612,7 @@ export default function UserProfile() {
    - State + {t("state")}
    {userData?.state_object?.name || "-"} @@ -619,7 +620,7 @@ export default function UserProfile() {
    - Skills + {t("skills")}
    - Average weekly working hours + {t("average_weekly_working_hours")}
    {userData?.weekly_working_hours ?? "-"} @@ -656,7 +657,7 @@ export default function UserProfile() { id="videoconnectlink-profile-details" >
    - Video Connect Link + {t("video_conference_link")}
    {userData?.video_connect_link ? ( @@ -685,18 +686,18 @@ export default function UserProfile() { o.text} optionValue={(o) => o.text} - optionIcon={(o) => ( - {o.icon} - )} options={GENDER_TYPES} /> )}
    - +
    @@ -796,7 +798,7 @@ export default function UserProfile() {
    @@ -888,10 +890,10 @@ export default function UserProfile() {

    - Language Selection + {t("language_selection")}

    - Set your local language + {t("set_your_local_language")}

    @@ -903,10 +905,10 @@ export default function UserProfile() {

    - Software Update + {t("software_update")}

    - Check for an available update + {t("check_for_available_update")}

    @@ -915,7 +917,7 @@ export default function UserProfile() {
    - Update available + {t("update_available")}
    @@ -936,8 +938,8 @@ export default function UserProfile() { )} /> {updateStatus.isChecking - ? "Checking for update" - : "Check for update"} + ? t("checking_for_update") + : t("check_for_update")}
    )} diff --git a/src/Locale/en.json b/src/Locale/en.json index 5200361e1be..f23ec2f0fef 100644 --- a/src/Locale/en.json +++ b/src/Locale/en.json @@ -25,6 +25,7 @@ "last_name": "Last Name", "email": "Email Address", "phone_number": "Phone Number", + "whatsapp_number": "Whatsapp Number", "district": "District", "gender": "Gender", "age": "Age", @@ -277,6 +278,28 @@ "unsupported_browser": "Unsupported Browser", "unsupported_browser_description": "Your browser ({{name}} version {{version}}) is not supported. Please update your browser to the latest version or switch to a supported browser for the best experience.", "add_remarks": "Add remarks", + "middleware_hostname": "Middleware Hostname", + "personal_information": "Personal Information", + "are_non_editable_fields": "are non-editable fields", + "edit_user_profile": "Edit Profile", + "skills": "Skills", + "access_level": "Access Level", + "qualification": "Qualification", + "years_of_experience": "Years of Experience", + "years_of_experience_of_the_doctor": "Years of Experience of the Doctor", + "medical_council_registration": "Medical Council Registration", + "doctor_s_medical_council_registration": "Doctor's Medical Council Registration", + "video_conference_link": "Video Conference Link", + "new_password_confirmation": "Confirm New Password", + "current_password": "Current Password", + "change_password": "Change Password", + "language_selection": "Language Selection", + "set_your_local_language": "Set your local language", + "software_update": "Software Update", + "check_for_available_update": "Check for available update", + "update_available": "Update Available", + "checking_for_update": "Checking for update", + "check_for_update": "Check for Update", "SORT_OPTIONS__-created_date": "Latest created date first", "SORT_OPTIONS__created_date": "Oldest created date first", "SORT_OPTIONS__-category_severity": "Highest Severity category first", @@ -293,9 +316,7 @@ "SORT_OPTIONS__-name": "Patient name Z-A", "SORT_OPTIONS__bed__name": "Bed No. 1-N", "SORT_OPTIONS__-bed__name": "Bed No. N-1", - "middleware_hostname": "Middleware Hostname", "local_ip_address": "Local IP Address", - "qualification": "Qualification", "CONSULTATION_TAB__UPDATES": "Overview", "CONSULTATION_TAB__FEED": "Feed", "CONSULTATION_TAB__SUMMARY": "Vitals", @@ -1056,9 +1077,10 @@ "patient_body": "Patient Body", "vitals_monitor": "Vitals Monitor", "resource_origin_facility": "Origin Facility", - "resource_approving_facility" : "Resource approving facility", - "consultation_not_filed": "You have not filed any consultation for this patient yet.", - "consultation_not_filed_description": "Please file a consultation for this patient to continue.", + "resource_approving_facility": "Resource approving facility", + "create_consultation": "Create Consultation", + "patient_details": "Patient Details", "width": "Width ({{unit}})", - "length": "Length ({{unit}})" -} + "length": "Length ({{unit}})", + "linked_skills": "Linked Skills" +} \ No newline at end of file diff --git a/src/PluginEngine.tsx b/src/PluginEngine.tsx new file mode 100644 index 00000000000..3d47dba4d81 --- /dev/null +++ b/src/PluginEngine.tsx @@ -0,0 +1,51 @@ +/* eslint-disable i18next/no-literal-string */ +import React, { Suspense } from "react"; +import { CareAppsContext, useCareApps } from "./Common/hooks/useCareApps"; +import { pluginMap } from "./pluginTypes"; +import { UserAssignedModel } from "./Components/Users/models"; +import ErrorBoundary from "./Components/Common/ErrorBoundary"; + +export default function PluginEngine({ + children, +}: { + children: React.ReactNode; +}) { + return ( + Loading plugins...
    }> + + Error loading plugins +
    + } + > + + {children} + + + + ); +} + +export function PLUGIN_DoctorConnectButtons({ + user, +}: { + user: UserAssignedModel; +}) { + const plugins = useCareApps(); + return ( +
    + {plugins.map((plugin, index) => { + const DoctorConnectButtons = plugin.components.DoctorConnectButtons; + if (!DoctorConnectButtons) { + return null; + } + return ( +
    + +
    + ); + })} +
    + ); +} diff --git a/src/Redux/api.tsx b/src/Redux/api.tsx index 4775674084e..f1130345f46 100644 --- a/src/Redux/api.tsx +++ b/src/Redux/api.tsx @@ -1129,7 +1129,7 @@ const routes = { path: "/api/v1/notification/notify/", method: "POST", TRes: Type(), - Tbody: Type(), + TBody: Type(), }, // FileUpload Create diff --git a/src/Routers/AppRouter.tsx b/src/Routers/AppRouter.tsx index 87bd3b71d8a..df154ee7a5e 100644 --- a/src/Routers/AppRouter.tsx +++ b/src/Routers/AppRouter.tsx @@ -24,11 +24,26 @@ import HCXRoutes from "./routes/HCXRoutes"; import ShiftingRoutes from "./routes/ShiftingRoutes"; import AssetRoutes from "./routes/AssetRoutes"; import ResourceRoutes from "./routes/ResourceRoutes"; -import { DetailRoute } from "./types"; +import { usePluginRoutes } from "@/Common/hooks/useCareApps"; import careConfig from "@careConfig"; import IconIndex from "../CAREUI/icons/Index"; -const Routes = { +export type RouteParams = + T extends `${string}:${infer Param}/${infer Rest}` + ? { [K in Param | keyof RouteParams]: string } + : T extends `${string}:${infer Param}` + ? { [K in Param]: string } + : Record; + +export type RouteFunction = ( + params: RouteParams, +) => JSX.Element; + +export type AppRoutes = { + [K in string]: RouteFunction; +}; + +const Routes: AppRoutes = { "/": () => , ...AssetRoutes, @@ -40,15 +55,13 @@ const Routes = { ...ShiftingRoutes, ...UserRoutes, - "/notifications/:id": ({ id }: DetailRoute) => ( - - ), + "/notifications/:id": ({ id }) => , "/notice_board": () => , - "/abdm/health-information/:id": ({ id }: { id: string }) => ( + "/abdm/health-information/:id": ({ id }) => ( ), - "/facility/:facilityId/abdm": ({ facilityId }: any) => ( + "/facility/:facilityId/abdm": ({ facilityId }) => ( ), @@ -61,6 +74,8 @@ const Routes = { }; export default function AppRouter() { + const pluginRoutes = usePluginRoutes(); + let routes = Routes; if (careConfig.hcx.enabled) { @@ -68,7 +83,15 @@ export default function AppRouter() { } useRedirect("/user", "/users"); + + // Merge in Plugin Routes + routes = { + ...routes, + ...pluginRoutes, + }; + const pages = useRoutes(routes) || ; + const path = usePath(); const [sidebarOpen, setSidebarOpen] = useState(false); @@ -146,7 +169,7 @@ export default function AppRouter() { id="pages" className="flex-1 overflow-y-scroll bg-gray-100 pb-4 focus:outline-none md:py-0" > -
    +
    {pages}
    diff --git a/src/Routers/routes/AssetRoutes.tsx b/src/Routers/routes/AssetRoutes.tsx index d3bd96ca437..ee0537d6c58 100644 --- a/src/Routers/routes/AssetRoutes.tsx +++ b/src/Routers/routes/AssetRoutes.tsx @@ -2,20 +2,23 @@ import AssetConfigure from "../../Components/Assets/AssetConfigure"; import AssetManage from "../../Components/Assets/AssetManage"; import AssetsList from "../../Components/Assets/AssetsList"; import AssetCreate from "../../Components/Facility/AssetCreate"; +import { AppRoutes } from "../AppRouter"; -export default { +const AssetRoutes: AppRoutes = { "/assets": () => , - - "/facility/:facilityId/assets/new": (params: any) => ( - - ), - "/facility/:facilityId/assets/:assetId/update": (params: any) => ( - + "/facility/:facilityId/assets/new": ({ facilityId }) => ( + ), - "/facility/:facilityId/assets/:assetId": (params: any) => ( - + "/facility/:facilityId/assets/:assetId/update": ({ facilityId, assetId }) => ( + ), - "/facility/:facilityId/assets/:assetId/configure": (params: any) => ( - + "/facility/:facilityId/assets/:assetId": ({ facilityId, assetId }) => ( + ), + "/facility/:facilityId/assets/:assetId/configure": ({ + facilityId, + assetId, + }) => , }; + +export default AssetRoutes; diff --git a/src/Routers/routes/ConsultationRoutes.tsx b/src/Routers/routes/ConsultationRoutes.tsx index 598fd06adc3..77efe1081bc 100644 --- a/src/Routers/routes/ConsultationRoutes.tsx +++ b/src/Routers/routes/ConsultationRoutes.tsx @@ -5,30 +5,29 @@ import ManagePrescriptions from "../../Components/Medicine/ManagePrescriptions"; import { DailyRoundListDetails } from "../../Components/Patient/DailyRoundListDetails"; import { DailyRounds } from "../../Components/Patient/DailyRounds"; import { ConsultationDetails } from "../../Components/Facility/ConsultationDetails"; -import TreatmentSummary, { - ITreatmentSummaryProps, -} from "../../Components/Facility/TreatmentSummary"; +import TreatmentSummary from "../../Components/Facility/TreatmentSummary"; import ConsultationDoctorNotes from "../../Components/Facility/ConsultationDoctorNotes"; import PatientConsentRecords from "../../Components/Patient/PatientConsentRecords"; import CriticalCareEditor from "../../Components/LogUpdate/CriticalCareEditor"; import PrescriptionsPrintPreview from "../../Components/Medicine/PrintPreview"; import CriticalCarePreview from "../../Components/LogUpdate/CriticalCarePreview"; import FileUploadPage from "../../Components/Patient/FileUploadPage"; +import { AppRoutes } from "../AppRouter"; -export default { +const consultationRoutes: AppRoutes = { "/facility/:facilityId/patient/:patientId/consultation": ({ facilityId, patientId, - }: any) => , + }) => , "/facility/:facilityId/patient/:patientId/consultation/:id/update": ({ facilityId, patientId, id, - }: any) => ( + }) => ( ), "/facility/:facilityId/patient/:patientId/consultation/:id/consent-records": - ({ facilityId, patientId, id }: any) => ( + ({ facilityId, patientId, id }) => ( ( + }) => ( ), "/facility/:facilityId/patient/:patientId/consultation/:consultationId/prescriptions": - (path: any) => , + (path) => , "/facility/:facilityId/patient/:patientId/consultation/:consultationId/prescriptions/print": () => , "/facility/:facilityId/patient/:patientId/consultation/:id/investigation": ({ facilityId, patientId, id, - }: any) => ( + }) => ( ), "/facility/:facilityId/patient/:patientId/consultation/:id/investigation/:sessionId": - ({ facilityId, patientId, id, sessionId }: any) => ( + ({ facilityId, patientId, id, sessionId }) => ( ( + }) => ( ), "/facility/:facilityId/patient/:patientId/consultation/:consultationId/daily-rounds/:id/update": - ({ facilityId, patientId, consultationId, id }: any) => ( + ({ facilityId, patientId, consultationId, id }) => ( ), "/facility/:facilityId/patient/:patientId/consultation/:consultationId/daily-rounds/:id": - ({ facilityId, patientId, consultationId, id }: any) => ( + ({ facilityId, patientId, consultationId, id }) => ( ), - "/facility/:facilityId/patient/:patientId/consultation/:consultationId/daily_rounds/:id": - (params: { - facilityId: string; - patientId: string; - consultationId: string; - id: string; - }) => , + ({ facilityId, patientId, consultationId, id }) => ( + + ), "/facility/:facilityId/patient/:patientId/consultation/:consultationId/daily_rounds/:id/update": - (params: { - facilityId: string; - patientId: string; - consultationId: string; - id: string; - }) => , + ({ facilityId, patientId, consultationId, id }) => ( + + ), "/facility/:facilityId/patient/:patientId/consultation/:consultationId": ({ facilityId, patientId, consultationId, - }: any) => ( + }) => ( ), - "/consultation/:consultationId": ({ consultationId }: any) => ( + "/consultation/:consultationId": ({ consultationId }) => ( ), "/facility/:facilityId/patient/:patientId/consultation/:consultationId/treatment-summary": - ({ facilityId, patientId, consultationId }: ITreatmentSummaryProps) => ( + ({ facilityId, patientId, consultationId }) => ( ), "/facility/:facilityId/patient/:patientId/consultation/:consultationId/notes": - ({ facilityId, patientId, consultationId }: any) => ( + ({ facilityId, patientId, consultationId }) => ( ), "/facility/:facilityId/patient/:patientId/consultation/:consultationId/:tab": - ({ facilityId, patientId, consultationId, tab }: any) => ( + ({ facilityId, patientId, consultationId, tab }) => ( ), }; + +export default consultationRoutes; diff --git a/src/Routers/routes/FacilityInventoryRoutes.tsx b/src/Routers/routes/FacilityInventoryRoutes.tsx index 17e93b2bc60..99123d8f737 100644 --- a/src/Routers/routes/FacilityInventoryRoutes.tsx +++ b/src/Routers/routes/FacilityInventoryRoutes.tsx @@ -3,22 +3,25 @@ import InventoryList from "../../Components/Facility/InventoryList"; import InventoryLog from "../../Components/Facility/InventoryLog"; import MinQuantityList from "../../Components/Facility/MinQuantityList"; import { SetInventoryForm } from "../../Components/Facility/SetInventoryForm"; +import { AppRoutes } from "../AppRouter"; -export default { - "/facility/:facilityId/inventory": ({ facilityId }: any) => ( +const FacilityInventoryRoutes: AppRoutes = { + "/facility/:facilityId/inventory": ({ facilityId }) => ( ), - "/facility/:facilityId/inventory/min_quantity/set": ({ facilityId }: any) => ( + "/facility/:facilityId/inventory/min_quantity/set": ({ facilityId }) => ( ), - "/facility/:facilityId/inventory/min_quantity/list": ({ - facilityId, - }: any) => , - "/facility/:facilityId/inventory/min_quantity": ({ facilityId }: any) => ( + "/facility/:facilityId/inventory/min_quantity/list": ({ facilityId }) => ( + + ), + "/facility/:facilityId/inventory/min_quantity": ({ facilityId }) => ( ), "/facility/:facilityId/inventory/:inventoryId": ({ facilityId, inventoryId, - }: any) => , + }) => , }; + +export default FacilityInventoryRoutes; diff --git a/src/Routers/routes/FacilityLocationRoutes.tsx b/src/Routers/routes/FacilityLocationRoutes.tsx index 5d547ebd466..c2e1add4b10 100644 --- a/src/Routers/routes/FacilityLocationRoutes.tsx +++ b/src/Routers/routes/FacilityLocationRoutes.tsx @@ -6,41 +6,42 @@ import LocationManagement from "../../Components/Facility/LocationManagement"; import CentralLiveMonitoring from "../../Components/CameraFeed/CentralLiveMonitoring"; import { AuthorizeUserRoute } from "../../Utils/AuthorizeFor"; import { CameraFeedPermittedUserTypes } from "../../Utils/permissions"; +import { AppRoutes } from "../AppRouter"; -export default { - "/facility/:facilityId/location": ({ facilityId }: any) => ( +const FacilityLocationRoutes: AppRoutes = { + "/facility/:facilityId/location": ({ facilityId }) => ( ), "/facility/:facilityId/location/:locationId/beds": ({ facilityId, locationId, - }: any) => , - "/facility/:facilityId/inventory/add": ({ facilityId }: any) => ( + }) => , + "/facility/:facilityId/inventory/add": ({ facilityId }) => ( ), - "/facility/:facilityId/location/add": ({ facilityId }: any) => ( + "/facility/:facilityId/location/add": ({ facilityId }) => ( ), "/facility/:facilityId/location/:locationId/update": ({ facilityId, locationId, - }: any) => ( - - ), + }) => , "/facility/:facilityId/location/:locationId/beds/add": ({ facilityId, locationId, - }: any) => , + }) => , "/facility/:facilityId/location/:locationId/beds/:bedId/update": ({ facilityId, locationId, bedId, - }: any) => ( + }) => ( ), - "/facility/:facilityId/live-monitoring": (props: any) => ( + "/facility/:facilityId/live-monitoring": ({ facilityId }) => ( - + ), }; + +export default FacilityLocationRoutes; diff --git a/src/Routers/routes/FacilityRoutes.tsx b/src/Routers/routes/FacilityRoutes.tsx index 2c711cf48cb..16b202ae0ce 100644 --- a/src/Routers/routes/FacilityRoutes.tsx +++ b/src/Routers/routes/FacilityRoutes.tsx @@ -2,48 +2,47 @@ import { FacilityConfigure } from "../../Components/Facility/FacilityConfigure"; import { FacilityCreate } from "../../Components/Facility/FacilityCreate"; import { FacilityHome } from "../../Components/Facility/FacilityHome"; import FacilityUsers from "../../Components/Facility/FacilityUsers"; -import { HospitalList } from "../../Components/Facility/HospitalList"; +import { FacilityList } from "../../Components/Facility/FacilityList"; import { TriageForm } from "../../Components/Facility/TriageForm"; import ResourceCreate from "../../Components/Resource/ResourceCreate"; import CentralNursingStation from "../../Components/Facility/CentralNursingStation"; import FacilityLocationRoutes from "./FacilityLocationRoutes"; import FacilityInventoryRoutes from "./FacilityInventoryRoutes"; import DischargedPatientsList from "../../Components/Facility/DischargedPatientsList"; +import { AppRoutes } from "../AppRouter"; -export default { - "/facility": () => , +const FacilityRoutes: AppRoutes = { + "/facility": () => , "/facility/create": () => , - "/facility/:facilityId/update": ({ facilityId }: any) => ( + "/facility/:facilityId/update": ({ facilityId }) => ( ), - "/facility/:facilityId/configure": ({ facilityId }: any) => ( + "/facility/:facilityId/configure": ({ facilityId }) => ( ), - "/facility/:facilityId/cns": ({ facilityId }: any) => ( + "/facility/:facilityId/cns": ({ facilityId }) => ( ), - "/facility/:facilityId": ({ facilityId }: any) => ( + "/facility/:facilityId": ({ facilityId }) => ( ), - "/facility/:id/discharged-patients": ({ id }: any) => ( + "/facility/:id/discharged-patients": ({ id }) => ( ), - - "/facility/:facilityId/users": ({ facilityId }: any) => ( + "/facility/:facilityId/users": ({ facilityId }) => ( ), - "/facility/:facilityId/resource/new": ({ facilityId }: any) => ( + "/facility/:facilityId/resource/new": ({ facilityId }) => ( ), - - // Triage related routes - "/facility/:facilityId/triage": ({ facilityId }: any) => ( + "/facility/:facilityId/triage": ({ facilityId }) => ( ), - "/facility/:facilityId/triage/:id": ({ facilityId, id }: any) => ( + "/facility/:facilityId/triage/:id": ({ facilityId, id }) => ( ), - ...FacilityLocationRoutes, ...FacilityInventoryRoutes, }; + +export default FacilityRoutes; diff --git a/src/Routers/routes/HCXRoutes.tsx b/src/Routers/routes/HCXRoutes.tsx index 80378b24621..929cc3f12bb 100644 --- a/src/Routers/routes/HCXRoutes.tsx +++ b/src/Routers/routes/HCXRoutes.tsx @@ -1,10 +1,15 @@ -import ConsultationClaims, { - IConsultationClaimsProps, -} from "../../Components/Facility/ConsultationClaims"; +import ConsultationClaims from "../../Components/Facility/ConsultationClaims"; +import { AppRoutes } from "../AppRouter"; -export default { +const HCXRoutes: AppRoutes = { "/facility/:facilityId/patient/:patientId/consultation/:consultationId/claims": - (pathParams: IConsultationClaimsProps) => ( - + ({ facilityId, patientId, consultationId }) => ( + ), }; + +export default HCXRoutes; diff --git a/src/Routers/routes/PatientRoutes.tsx b/src/Routers/routes/PatientRoutes.tsx index fcfc9b04e37..45ff044e4d2 100644 --- a/src/Routers/routes/PatientRoutes.tsx +++ b/src/Routers/routes/PatientRoutes.tsx @@ -3,44 +3,44 @@ import { PatientManager } from "../../Components/Patient/ManagePatients"; import { PatientHome } from "../../Components/Patient/PatientHome"; import PatientNotes from "../../Components/Patient/PatientNotes"; import { PatientRegister } from "../../Components/Patient/PatientRegister"; -import { DetailRoute } from "../types"; import DeathReport from "../../Components/DeathReport/DeathReport"; import { InsuranceDetails } from "../../Components/Patient/InsuranceDetails"; import FileUploadPage from "../../Components/Patient/FileUploadPage"; +import { AppRoutes } from "../AppRouter"; -export default { +const PatientRoutes: AppRoutes = { "/patients": () => , - "/patient/:id": ({ id }: DetailRoute) => , - "/patient/:id/investigation_reports": ({ id }: DetailRoute) => ( + "/patient/:id": ({ id }) => , + "/patient/:id/investigation_reports": ({ id }) => ( ), - - // Facility Scoped Routes - "/facility/:facilityId/patient": ({ facilityId }: any) => ( + "/facility/:facilityId/patient": ({ facilityId }) => ( ), - "/facility/:facilityId/patient/:id": ({ facilityId, id }: any) => ( + "/facility/:facilityId/patient/:id": ({ facilityId, id }) => ( ), - "/facility/:facilityId/patient/:id/insurance": ({ facilityId, id }: any) => ( + "/facility/:facilityId/patient/:id/insurance": ({ facilityId, id }) => ( ), - "/facility/:facilityId/patient/:id/update": ({ facilityId, id }: any) => ( + "/facility/:facilityId/patient/:id/update": ({ facilityId, id }) => ( ), "/facility/:facilityId/patient/:patientId/notes": ({ facilityId, patientId, - }: any) => , + }) => , "/facility/:facilityId/patient/:patientId/files": ({ facilityId, patientId, - }: any) => ( + }) => ( ), - "/death_report/:id": ({ id }: any) => , + "/death_report/:id": ({ id }) => , }; + +export default PatientRoutes; diff --git a/src/Routers/routes/ResourceRoutes.tsx b/src/Routers/routes/ResourceRoutes.tsx index 6636d0d83ea..d75c933f760 100644 --- a/src/Routers/routes/ResourceRoutes.tsx +++ b/src/Routers/routes/ResourceRoutes.tsx @@ -3,17 +3,17 @@ import { ResourceDetailsUpdate } from "../../Components/Resource/ResourceDetails import ListView from "../../Components/Resource/ListView"; import BoardView from "../../Components/Resource/ResourceBoardView"; import { Redirect } from "raviger"; -import { DetailRoute } from "../types"; +import { AppRoutes } from "../AppRouter"; const getDefaultView = () => localStorage.getItem("defaultResourceView") === "list" ? "list" : "board"; -export default { +const ResourceRoutes: AppRoutes = { "/resource": () => , "/resource/board": () => , "/resource/list": () => , - "/resource/:id": ({ id }: DetailRoute) => , - "/resource/:id/update": ({ id }: DetailRoute) => ( - - ), + "/resource/:id": ({ id }) => , + "/resource/:id/update": ({ id }) => , }; + +export default ResourceRoutes; diff --git a/src/Routers/routes/SampleRoutes.tsx b/src/Routers/routes/SampleRoutes.tsx index 290a34fd4eb..cf296790a81 100644 --- a/src/Routers/routes/SampleRoutes.tsx +++ b/src/Routers/routes/SampleRoutes.tsx @@ -2,24 +2,22 @@ import { SampleDetails } from "../../Components/Patient/SampleDetails"; import SampleReport from "../../Components/Patient/SamplePreview"; import { SampleTest } from "../../Components/Patient/SampleTest"; import SampleViewAdmin from "../../Components/Patient/SampleViewAdmin"; -import { DetailRoute, RouteParams } from "../types"; +import { AppRoutes } from "../AppRouter"; -export default { +const SampleRoutes: AppRoutes = { "/sample": () => , - "/sample/:id": ({ id }: DetailRoute) => , + "/sample/:id": ({ id }) => , "/patient/:patientId/test_sample/:sampleId/icmr_sample": ({ patientId, sampleId, - }: RouteParams<"patientId" | "sampleId">) => ( - - ), + }) => , "/facility/:facilityId/patient/:patientId/sample-test": ({ facilityId, patientId, - }: RouteParams<"facilityId" | "patientId">) => ( - + }) => , + "/facility/:facilityId/patient/:patientId/sample/:id": ({ id }) => ( + ), - "/facility/:facilityId/patient/:patientId/sample/:id": ({ - id, - }: DetailRoute) => , }; + +export default SampleRoutes; diff --git a/src/Routers/routes/ShiftingRoutes.tsx b/src/Routers/routes/ShiftingRoutes.tsx index f2e12de4f25..dc11ff2b8ee 100644 --- a/src/Routers/routes/ShiftingRoutes.tsx +++ b/src/Routers/routes/ShiftingRoutes.tsx @@ -4,18 +4,21 @@ import { ShiftDetailsUpdate } from "../../Components/Shifting/ShiftDetailsUpdate import ListView from "../../Components/Shifting/ListView"; import BoardView from "../../Components/Shifting/BoardView"; import { Redirect } from "raviger"; +import { AppRoutes } from "../AppRouter"; const getDefaultView = () => localStorage.getItem("defaultShiftView") === "list" ? "list" : "board"; -export default { +const ShiftingRoutes: AppRoutes = { "/shifting": () => , "/shifting/board": () => , "/shifting/list": () => , - "/shifting/:id": ({ id }: any) => , - "/shifting/:id/update": ({ id }: any) => , + "/shifting/:id": ({ id }) => , + "/shifting/:id/update": ({ id }) => , "/facility/:facilityId/patient/:patientId/shift/new": ({ facilityId, patientId, - }: any) => , + }) => , }; + +export default ShiftingRoutes; diff --git a/src/Routers/routes/UserRoutes.tsx b/src/Routers/routes/UserRoutes.tsx index 56877ca4c78..24f355b201b 100644 --- a/src/Routers/routes/UserRoutes.tsx +++ b/src/Routers/routes/UserRoutes.tsx @@ -1,9 +1,12 @@ import ManageUsers from "../../Components/Users/ManageUsers"; import { UserAdd } from "../../Components/Users/UserAdd"; import UserProfile from "../../Components/Users/UserProfile"; +import { AppRoutes } from "../AppRouter"; -export default { +const UserRoutes: AppRoutes = { "/users": () => , "/users/add": () => , "/user/profile": () => , }; + +export default UserRoutes; diff --git a/src/Utils/useTimer.tsx b/src/Utils/useTimer.tsx index 6a8d8320c5e..f7a03ffefa0 100644 --- a/src/Utils/useTimer.tsx +++ b/src/Utils/useTimer.tsx @@ -27,7 +27,7 @@ export const useTimer = (autoStart = false) => { const [time, setTime] = useState(0); useEffect(() => { - let interval: number; + let interval: ReturnType; if (running) { interval = setInterval(() => { setTime((prevTime) => prevTime + 1); diff --git a/src/pluginTypes.ts b/src/pluginTypes.ts new file mode 100644 index 00000000000..26a07e4f141 --- /dev/null +++ b/src/pluginTypes.ts @@ -0,0 +1,54 @@ +import { LazyExoticComponent } from "react"; +import { UserAssignedModel } from "./Components/Users/models"; +import { AppRoutes } from "./Routers/AppRouter"; +import { INavItem } from "./Components/Common/Sidebar/Sidebar"; +import { pluginMap } from "./pluginMap"; + +// Define the available plugins +export type AvailablePlugin = "@apps/care_livekit_fe"; + +export type AvailablePluginManifest = "@app-manifest/care_livekit_fe"; + +export type DoctorConnectButtonComponentType = React.FC<{ + user: UserAssignedModel; +}>; + +// Define supported plugin components +export type SupportedPluginComponents = { + DoctorConnectButtons: DoctorConnectButtonComponentType; +}; + +// Create a type for lazy-loaded components +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type LazyComponent> = LazyExoticComponent; + +// Define PluginComponentMap with lazy-loaded components +export type PluginComponentMap = { + [K in keyof SupportedPluginComponents]?: LazyComponent< + SupportedPluginComponents[K] + >; +}; + +type SupportedPluginExtensions = + | "DoctorConnectButtons" + | "PatientExternalRegistration"; + +export type PluginManifest = { + plugin: string; + routes: AppRoutes; + extends: SupportedPluginExtensions[]; + components: PluginComponentMap; + navItems: INavItem[]; +}; + +// Create a type that ensures only available plugins can be used +export type EnabledPluginConfig = { + plugin: string; + manifestPath: AvailablePluginManifest; + path: AvailablePlugin; + manifest: Promise; + // Components are a dictionary, with the key being the component name, and the value being the component type + components: PluginComponentMap; +}; + +export { pluginMap }; diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 7657f7da19e..f339922bfae 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -31,6 +31,7 @@ interface ImportMetaEnv { readonly REACT_JWT_TOKEN_REFRESH_INTERVAL?: string; readonly REACT_MIN_ENCOUNTER_DATE?: string; readonly REACT_ALLOWED_LOCALES?: string; + readonly REACT_ENABLED_APPS?: string; // Plugins related envs... readonly REACT_PLAUSIBLE_SERVER_URL?: string; diff --git a/tsconfig.json b/tsconfig.json index 531d6f800e1..51ffeb4a0ae 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,9 +19,12 @@ "baseUrl": ".", "paths": { "@/*": ["./src/*"], + "@core/*": ["src/*"], + "@apps/*": ["apps/*/src"], + "@app-manifest/*": ["apps/*/src/manifest.ts"], "@careConfig": ["./care.config.ts"] } }, - "include": ["src", "care.config.ts"], + "include": ["src/**/*", "apps/**/*", "care.config.ts"], "exclude": ["src/**/*.gen.tsx"] } diff --git a/vite.config.mts b/vite.config.mts index acb0cdf727b..905374eb923 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -1,10 +1,12 @@ -import path from "node:path"; +import path from "path"; import { createRequire } from "node:module"; import { VitePWA } from "vite-plugin-pwa"; import react from "@vitejs/plugin-react-swc"; import checker from "vite-plugin-checker"; import { viteStaticCopy } from "vite-plugin-static-copy"; import { treeShakeCareIcons } from "./plugins/treeShakeCareIcons"; +import fs from "fs"; +import { defineConfig } from "vite"; const pdfWorkerPath = path.join( path.dirname( @@ -22,8 +24,56 @@ const cdnUrls = "http://localhost:4566", ].join(" "); +function getPluginAliases() { + const pluginsDir = path.resolve(__dirname, "apps"); + // Make sure the `apps` folder exists + if (!fs.existsSync(pluginsDir)) { + return {}; + } + const pluginFolders = fs.readdirSync(pluginsDir); + + const aliases = {}; + + pluginFolders.forEach((pluginFolder) => { + const pluginSrcPath = path.join(pluginsDir, pluginFolder, "src"); + if (fs.existsSync(pluginSrcPath)) { + aliases[`@apps/${pluginFolder}`] = pluginSrcPath; + aliases[`@app-manifest/${pluginFolder}`] = path.join( + pluginSrcPath, + "manifest.ts", + ); + } + }); + + return aliases; +} + +function getPluginDependencies() { + const pluginsDir = path.resolve(__dirname, "apps"); + // Make sure the `apps` folder exists + if (!fs.existsSync(pluginsDir)) { + return []; + } + const pluginFolders = fs.readdirSync(pluginsDir); + + const dependencies = new Set(); + + pluginFolders.forEach((pluginFolder) => { + const packageJsonPath = path.join(pluginsDir, pluginFolder, "package.json"); + if (fs.existsSync(packageJsonPath)) { + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); + const pluginDependencies = packageJson.dependencies + ? Object.keys(packageJson.dependencies) + : []; + pluginDependencies.forEach((dep) => dependencies.add(dep)); + } + }); + + return Array.from(dependencies); +} + /** @type {import('vite').UserConfig} */ -export default { +export default defineConfig({ envPrefix: "REACT_", plugins: [ viteStaticCopy({ @@ -86,10 +136,15 @@ export default { ], resolve: { alias: { + ...getPluginAliases(), "@": path.resolve(__dirname, "./src"), "@careConfig": path.resolve(__dirname, "./care.config.ts"), + "@core": path.resolve(__dirname, "src/"), }, }, + optimizeDeps: { + include: getPluginDependencies(), + }, build: { outDir: "build", assetsDir: "bundle", @@ -118,4 +173,4 @@ export default { }, port: 4000, }, -}; +});