From cd2c74a094f5ed231d3843fadd91ce28f26354d5 Mon Sep 17 00:00:00 2001 From: KenTheNoob Date: Sat, 12 Apr 2025 20:18:47 -0400 Subject: [PATCH 1/7] adding authentication and dashboard --- eslint.config.js | 28 + package-lock.json | 1278 ++++++----------- package.json | 4 +- src/app/(Dashboard)/dashboard/dashboard.css | 17 + src/app/(Dashboard)/dashboard/guests/page.tsx | 860 +++++++++++ src/app/(Dashboard)/dashboard/layout.tsx | 863 +++++++++++ src/app/(Dashboard)/dashboard/page.tsx | 25 + .../(Dashboard)/dashboard/profile/page.tsx | 933 ++++++++++++ .../(Dashboard)/dashboard/resources/page.tsx | 751 ++++++++++ src/app/(Dashboard)/dashboard/users/page.tsx | 731 ++++++++++ src/app/(Dashboard)/globals.css | 17 + src/app/(Dashboard)/layout.tsx | 15 + src/app/(Dashboard)/login/page.tsx | 8 + src/app/(Dashboard)/register/page.tsx | 8 + .../{ => (HomePage)}/about/[slug]/page.tsx | 0 .../about/living-lab/page.tsx | 0 src/app/{ => (HomePage)}/about/page.tsx | 0 .../api/characters/chat/route.ts | 0 .../{ => (HomePage)}/api/characters/route.ts | 0 .../{ => (HomePage)}/api/chat-proxy/route.ts | 0 src/app/{ => (HomePage)}/api/chat/route.ts | 0 src/app/{ => (HomePage)}/api/contact/route.ts | 0 src/app/{ => (HomePage)}/community/page.tsx | 0 src/app/{ => (HomePage)}/contact/page.tsx | 0 src/app/{ => (HomePage)}/error.tsx | 0 .../forge/ForgeClientPage.tsx | 0 .../forge/ForgeProjectsList.tsx | 0 .../forge/character-chat/page.tsx | 0 src/app/{ => (HomePage)}/forge/page.tsx | 0 .../forge/philosopher-graph/forceWorker.ts | 2 +- .../forge/philosopher-graph/metadata.ts | 0 .../forge/philosopher-graph/page.tsx | 2 +- src/app/{ => (HomePage)}/globals.css | 0 .../{ => (HomePage)}/insights/[slug]/page.tsx | 0 src/app/{ => (HomePage)}/insights/page.tsx | 0 src/app/{ => (HomePage)}/layout.tsx | 4 +- src/app/{ => (HomePage)}/not-found.tsx | 0 src/app/{ => (HomePage)}/page.tsx | 16 +- .../{ => (HomePage)}/services/[slug]/page.tsx | 0 src/app/{ => (HomePage)}/services/page.tsx | 0 src/components/AuthForm/AuthForm.tsx | 270 ++++ src/components/ChatBox/ChatBox.tsx | 971 +++++++++++++ src/components/Dashboard/AdminDashboard.tsx | 320 +++++ .../Dashboard/AnalyticsDashboard.tsx | 538 +++++++ src/components/Dashboard/AppContext.tsx | 172 +++ src/components/Dashboard/KnowledgeGraph.tsx | 433 ++++++ .../Dashboard/KnowledgeGraphPage.tsx | 285 ++++ .../Dashboard/ProjectManagement.tsx | 627 ++++++++ .../Dashboard/RealTimeDashboard.tsx | 912 ++++++++++++ src/components/Dashboard/UserDashboard.tsx | 731 ++++++++++ .../Graph/EnterprisePhilosopherGraph.tsx | 2 +- src/components/Layout/Header.tsx | 2 + src/lib/guestIdentifier.ts | 28 + src/utils/axiosConfig.ts | 52 + tailwind.config.js | 7 +- 55 files changed, 10082 insertions(+), 830 deletions(-) create mode 100644 eslint.config.js create mode 100644 src/app/(Dashboard)/dashboard/dashboard.css create mode 100644 src/app/(Dashboard)/dashboard/guests/page.tsx create mode 100644 src/app/(Dashboard)/dashboard/layout.tsx create mode 100644 src/app/(Dashboard)/dashboard/page.tsx create mode 100644 src/app/(Dashboard)/dashboard/profile/page.tsx create mode 100644 src/app/(Dashboard)/dashboard/resources/page.tsx create mode 100644 src/app/(Dashboard)/dashboard/users/page.tsx create mode 100644 src/app/(Dashboard)/globals.css create mode 100644 src/app/(Dashboard)/layout.tsx create mode 100644 src/app/(Dashboard)/login/page.tsx create mode 100644 src/app/(Dashboard)/register/page.tsx rename src/app/{ => (HomePage)}/about/[slug]/page.tsx (100%) rename src/app/{ => (HomePage)}/about/living-lab/page.tsx (100%) rename src/app/{ => (HomePage)}/about/page.tsx (100%) rename src/app/{ => (HomePage)}/api/characters/chat/route.ts (100%) rename src/app/{ => (HomePage)}/api/characters/route.ts (100%) rename src/app/{ => (HomePage)}/api/chat-proxy/route.ts (100%) rename src/app/{ => (HomePage)}/api/chat/route.ts (100%) rename src/app/{ => (HomePage)}/api/contact/route.ts (100%) rename src/app/{ => (HomePage)}/community/page.tsx (100%) rename src/app/{ => (HomePage)}/contact/page.tsx (100%) rename src/app/{ => (HomePage)}/error.tsx (100%) rename src/app/{ => (HomePage)}/forge/ForgeClientPage.tsx (100%) rename src/app/{ => (HomePage)}/forge/ForgeProjectsList.tsx (100%) rename src/app/{ => (HomePage)}/forge/character-chat/page.tsx (100%) rename src/app/{ => (HomePage)}/forge/page.tsx (100%) rename src/app/{ => (HomePage)}/forge/philosopher-graph/forceWorker.ts (99%) rename src/app/{ => (HomePage)}/forge/philosopher-graph/metadata.ts (100%) rename src/app/{ => (HomePage)}/forge/philosopher-graph/page.tsx (99%) rename src/app/{ => (HomePage)}/globals.css (100%) rename src/app/{ => (HomePage)}/insights/[slug]/page.tsx (100%) rename src/app/{ => (HomePage)}/insights/page.tsx (100%) rename src/app/{ => (HomePage)}/layout.tsx (95%) rename src/app/{ => (HomePage)}/not-found.tsx (100%) rename src/app/{ => (HomePage)}/page.tsx (78%) rename src/app/{ => (HomePage)}/services/[slug]/page.tsx (100%) rename src/app/{ => (HomePage)}/services/page.tsx (100%) create mode 100644 src/components/AuthForm/AuthForm.tsx create mode 100644 src/components/ChatBox/ChatBox.tsx create mode 100644 src/components/Dashboard/AdminDashboard.tsx create mode 100644 src/components/Dashboard/AnalyticsDashboard.tsx create mode 100644 src/components/Dashboard/AppContext.tsx create mode 100644 src/components/Dashboard/KnowledgeGraph.tsx create mode 100644 src/components/Dashboard/KnowledgeGraphPage.tsx create mode 100644 src/components/Dashboard/ProjectManagement.tsx create mode 100644 src/components/Dashboard/RealTimeDashboard.tsx create mode 100644 src/components/Dashboard/UserDashboard.tsx create mode 100644 src/lib/guestIdentifier.ts create mode 100644 src/utils/axiosConfig.ts diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..82c2e20 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,28 @@ +import js from '@eslint/js'; +import globals from 'globals'; +import reactHooks from 'eslint-plugin-react-hooks'; +import reactRefresh from 'eslint-plugin-react-refresh'; +import tseslint from 'typescript-eslint'; + +export default tseslint.config( + { ignores: ['dist'] }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ['**/*.{ts,tsx}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, + } +); diff --git a/package-lock.json b/package-lock.json index 6e18c31..e3081ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,8 +12,10 @@ "@fontsource/poppins": "^5.2.5", "@fontsource/public-sans": "^5.2.5", "@headlessui/react": "^2.2.1", + "@heroicons/react": "^2.1.1", "@langchain/core": "^0.3.44", "@langchain/openai": "^0.5.5", + "@material-tailwind/react": "^2.1.9", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-slot": "^1.1.2", @@ -61,7 +63,7 @@ "@types/d3-selection": "^3.0.11", "@types/d3-zoom": "^3.0.8", "@types/node": "^20", - "@types/react": "^18.3.5", + "@types/react": "^18.2.42", "@types/react-dom": "^18.3.0", "@types/react-slick": "^0.23.13", "@types/react-virtualized-auto-sizer": "^1.0.4", @@ -104,18 +106,6 @@ "integrity": "sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==", "license": "MIT" }, - "node_modules/@emnapi/core": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.0.tgz", - "integrity": "sha512-H+N/FqT07NmLmt6OFFtDfwe8PNygprzBikrEMyQfgqSmT0vzE515Pz7R8izwB9q/zsH/MA64AKoul3sA6/CzVg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.0.1", - "tslib": "^2.4.0" - } - }, "node_modules/@emnapi/runtime": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.0.tgz", @@ -126,17 +116,23 @@ "tslib": "^2.4.0" } }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.1.tgz", - "integrity": "sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==", - "dev": true, + "node_modules/@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", "license": "MIT", "optional": true, "dependencies": { - "tslib": "^2.4.0" + "@emotion/memoize": "0.7.4" } }, + "node_modules/@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", + "license": "MIT", + "optional": true + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.5.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz", @@ -387,6 +383,15 @@ "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, + "node_modules/@heroicons/react": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.1.1.tgz", + "integrity": "sha512-JyyN9Lo66kirbCMuMMRPtJxtKJoIsXKS569ebHGGRKbl8s4CtUfLnyKJxteA+vIKySocO4s1SkTkGS4xtG/yEA==", + "license": "MIT", + "peerDependencies": { + "react": ">= 16" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -453,364 +458,6 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.1.tgz", - "integrity": "sha512-pn44xgBtgpEbZsu+lWf2KNb6OAf70X68k+yk69Ic2Xz11zHR/w24/U49XT7AeRwJ0Px+mhALhU5LPci1Aymk7A==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.1.0" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.1.tgz", - "integrity": "sha512-VfuYgG2r8BpYiOUN+BfYeFo69nP/MIwAtSJ7/Zpxc5QF3KS22z8Pvg3FkrSFJBPNQ7mmcUcYQFBmEQp7eu1F8Q==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.1.0" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.1.0.tgz", - "integrity": "sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.1.0.tgz", - "integrity": "sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.1.0.tgz", - "integrity": "sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==", - "cpu": [ - "arm" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.1.0.tgz", - "integrity": "sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.1.0.tgz", - "integrity": "sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==", - "cpu": [ - "ppc64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.1.0.tgz", - "integrity": "sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==", - "cpu": [ - "s390x" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.1.0.tgz", - "integrity": "sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.1.0.tgz", - "integrity": "sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.1.0.tgz", - "integrity": "sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.1.tgz", - "integrity": "sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA==", - "cpu": [ - "arm" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.1.0" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.1.tgz", - "integrity": "sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.1.0" - } - }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.1.tgz", - "integrity": "sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA==", - "cpu": [ - "s390x" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.1.0" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.1.tgz", - "integrity": "sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.1.0" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.1.tgz", - "integrity": "sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.1.0" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.1.tgz", - "integrity": "sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.1.0" - } - }, - "node_modules/@img/sharp-wasm32": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.1.tgz", - "integrity": "sha512-YDybQnYrLQfEpzGOQe7OKcyLUCML4YOXl428gOOzBgN6Gw0rv8dpsJ7PqTHxBnXnwXr8S1mYFSLSa727tpz0xg==", - "cpu": [ - "wasm32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.4.0" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.1.tgz", - "integrity": "sha512-WKf/NAZITnonBf3U1LfdjoMgNO5JYRSlhovhRhMxXVdvWYveM4kM3L8m35onYIdh75cOMCo1BexgVQcCDzyoWw==", - "cpu": [ - "ia32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, "node_modules/@img/sharp-win32-x64": { "version": "0.34.1", "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.1.tgz", @@ -963,179 +610,206 @@ "@langchain/core": ">=0.2.21 <0.4.0" } }, - "node_modules/@mediapipe/tasks-vision": { - "version": "0.10.17", - "resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.17.tgz", - "integrity": "sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg==", - "license": "Apache-2.0" + "node_modules/@material-tailwind/react": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@material-tailwind/react/-/react-2.1.9.tgz", + "integrity": "sha512-3uPlJE9yK4JF9DEQO4I1QbjR8o05+4fysLqoZ0v38TDOLE2tvDRhTBVhn6Mp9vSsq5CoJOKgemG7kbkOFAji4A==", + "license": "MIT", + "dependencies": { + "@floating-ui/react": "0.19.0", + "classnames": "2.3.2", + "deepmerge": "4.2.2", + "framer-motion": "6.5.1", + "material-ripple-effects": "2.0.1", + "prop-types": "15.8.1", + "react": "18.2.0", + "react-dom": "18.2.0", + "tailwind-merge": "1.8.1" + }, + "peerDependencies": { + "react": "^16 || ^17 || ^18", + "react-dom": "^16 || ^17 || ^18" + } }, - "node_modules/@monogrid/gainmap-js": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@monogrid/gainmap-js/-/gainmap-js-3.1.0.tgz", - "integrity": "sha512-Obb0/gEd/HReTlg8ttaYk+0m62gQJmCblMOjHSMHRrBP2zdfKMHLCRbh/6ex9fSUJMKdjjIEiohwkbGD3wj2Nw==", + "node_modules/@material-tailwind/react/node_modules/@floating-ui/react": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.19.0.tgz", + "integrity": "sha512-fgYvN4ksCi5OvmPXkyOT8o5a8PSKHMzPHt+9mR6KYWdF16IAjWRLZPAAziI2sznaWT23drRFrYw64wdvYqqaQw==", "license": "MIT", "dependencies": { - "promise-worker-transferable": "^1.0.4" + "@floating-ui/react-dom": "^1.2.2", + "aria-hidden": "^1.1.3", + "tabbable": "^6.0.1" }, "peerDependencies": { - "three": ">= 0.159.0" + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.8.tgz", - "integrity": "sha512-OBlgKdX7gin7OIq4fadsjpg+cp2ZphvAIKucHsNfTdJiqdOmOEwQd/bHi0VwNrcw5xpBJyUw6cK/QilCqy1BSg==", - "dev": true, + "node_modules/@material-tailwind/react/node_modules/@floating-ui/react-dom": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-1.3.0.tgz", + "integrity": "sha512-htwHm67Ji5E/pROEAr7f8IKFShuiCKHwUC/UY4vC3I5jiSvGFAYnSYiZO5MlGmads+QqvUkR9ANHEguGrDv72g==", "license": "MIT", - "optional": true, "dependencies": { - "@emnapi/core": "^1.4.0", - "@emnapi/runtime": "^1.4.0", - "@tybys/wasm-util": "^0.9.0" + "@floating-ui/dom": "^1.2.1" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, - "node_modules/@next/env": { - "version": "14.2.28", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.28.tgz", - "integrity": "sha512-PAmWhJfJQlP+kxZwCjrVd9QnR5x0R3u0mTXTiZDgSd4h5LdXmjxCCWbN9kq6hkZBOax8Rm3xDW5HagWyJuT37g==", + "node_modules/@material-tailwind/react/node_modules/classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==", "license": "MIT" }, - "node_modules/@next/eslint-plugin-next": { - "version": "15.2.4", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.2.4.tgz", - "integrity": "sha512-O8ScvKtnxkp8kL9TpJTTKnMqlkZnS+QxwoQnJwPGBxjBbzd6OVVPEJ5/pMNrktSyXQD/chEfzfFzYLM6JANOOQ==", - "dev": true, + "node_modules/@material-tailwind/react/node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", "license": "MIT", - "dependencies": { - "fast-glob": "3.3.1" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@next/swc-darwin-arm64": { - "version": "14.2.28", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.28.tgz", - "integrity": "sha512-kzGChl9setxYWpk3H6fTZXXPFFjg7urptLq5o5ZgYezCrqlemKttwMT5iFyx/p1e/JeglTwDFRtb923gTJ3R1w==", - "cpu": [ - "arm64" - ], + "node_modules/@material-tailwind/react/node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "loose-envify": "^1.1.0" + }, "engines": { - "node": ">= 10" + "node": ">=0.10.0" } }, - "node_modules/@next/swc-darwin-x64": { - "version": "14.2.28", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.28.tgz", - "integrity": "sha512-z6FXYHDJlFOzVEOiiJ/4NG8aLCeayZdcRSMjPDysW297Up6r22xw6Ea9AOwQqbNsth8JNgIK8EkWz2IDwaLQcw==", - "cpu": [ - "x64" - ], + "node_modules/@material-tailwind/react/node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" } }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.2.28", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.28.tgz", - "integrity": "sha512-9ARHLEQXhAilNJ7rgQX8xs9aH3yJSj888ssSjJLeldiZKR4D7N08MfMqljk77fAwZsWwsrp8ohHsMvurvv9liQ==", - "cpu": [ - "arm64" - ], + "node_modules/@material-tailwind/react/node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" + "dependencies": { + "loose-envify": "^1.1.0" } }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.2.28", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.28.tgz", - "integrity": "sha512-p6gvatI1nX41KCizEe6JkF0FS/cEEF0u23vKDpl+WhPe/fCTBeGkEBh7iW2cUM0rvquPVwPWdiUR6Ebr/kQWxQ==", - "cpu": [ - "arm64" - ], + "node_modules/@material-tailwind/react/node_modules/tailwind-merge": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.8.1.tgz", + "integrity": "sha512-+fflfPxvHFr81hTJpQ3MIwtqgvefHZFUHFiIHpVIRXvG/nX9+gu2P7JNlFu2bfDMJ+uHhi/pUgzaYacMoXv+Ww==", + "license": "MIT" + }, + "node_modules/@mediapipe/tasks-vision": { + "version": "0.10.17", + "resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.17.tgz", + "integrity": "sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg==", + "license": "Apache-2.0" + }, + "node_modules/@monogrid/gainmap-js": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@monogrid/gainmap-js/-/gainmap-js-3.1.0.tgz", + "integrity": "sha512-Obb0/gEd/HReTlg8ttaYk+0m62gQJmCblMOjHSMHRrBP2zdfKMHLCRbh/6ex9fSUJMKdjjIEiohwkbGD3wj2Nw==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" + "dependencies": { + "promise-worker-transferable": "^1.0.4" + }, + "peerDependencies": { + "three": ">= 0.159.0" } }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.2.28", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.28.tgz", - "integrity": "sha512-nsiSnz2wO6GwMAX2o0iucONlVL7dNgKUqt/mDTATGO2NY59EO/ZKnKEr80BJFhuA5UC1KZOMblJHWZoqIJddpA==", - "cpu": [ - "x64" - ], + "node_modules/@motionone/animation": { + "version": "10.18.0", + "resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.18.0.tgz", + "integrity": "sha512-9z2p5GFGCm0gBsZbi8rVMOAJCtw1WqBTIPw3ozk06gDvZInBPIsQcHgYogEJ4yuHJ+akuW8g1SEIOpTOvYs8hw==", + "license": "MIT", + "dependencies": { + "@motionone/easing": "^10.18.0", + "@motionone/types": "^10.17.1", + "@motionone/utils": "^10.18.0", + "tslib": "^2.3.1" + } + }, + "node_modules/@motionone/dom": { + "version": "10.12.0", + "resolved": "https://registry.npmjs.org/@motionone/dom/-/dom-10.12.0.tgz", + "integrity": "sha512-UdPTtLMAktHiqV0atOczNYyDd/d8Cf5fFsd1tua03PqTwwCe/6lwhLSQ8a7TbnQ5SN0gm44N1slBfj+ORIhrqw==", + "license": "MIT", + "dependencies": { + "@motionone/animation": "^10.12.0", + "@motionone/generators": "^10.12.0", + "@motionone/types": "^10.12.0", + "@motionone/utils": "^10.12.0", + "hey-listen": "^1.0.8", + "tslib": "^2.3.1" + } + }, + "node_modules/@motionone/easing": { + "version": "10.18.0", + "resolved": "https://registry.npmjs.org/@motionone/easing/-/easing-10.18.0.tgz", + "integrity": "sha512-VcjByo7XpdLS4o9T8t99JtgxkdMcNWD3yHU/n6CLEz3bkmKDRZyYQ/wmSf6daum8ZXqfUAgFeCZSpJZIMxaCzg==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" + "dependencies": { + "@motionone/utils": "^10.18.0", + "tslib": "^2.3.1" } }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "14.2.28", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.28.tgz", - "integrity": "sha512-+IuGQKoI3abrXFqx7GtlvNOpeExUH1mTIqCrh1LGFf8DnlUcTmOOCApEnPJUSLrSbzOdsF2ho2KhnQoO0I1RDw==", - "cpu": [ - "x64" - ], + "node_modules/@motionone/generators": { + "version": "10.18.0", + "resolved": "https://registry.npmjs.org/@motionone/generators/-/generators-10.18.0.tgz", + "integrity": "sha512-+qfkC2DtkDj4tHPu+AFKVfR/C30O1vYdvsGYaR13W/1cczPrrcjdvYCj0VLFuRMN+lP1xvpNZHCRNM4fBzn1jg==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" + "dependencies": { + "@motionone/types": "^10.17.1", + "@motionone/utils": "^10.18.0", + "tslib": "^2.3.1" } }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.2.28", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.28.tgz", - "integrity": "sha512-l61WZ3nevt4BAnGksUVFKy2uJP5DPz2E0Ma/Oklvo3sGj9sw3q7vBWONFRgz+ICiHpW5mV+mBrkB3XEubMrKaA==", - "cpu": [ - "arm64" - ], + "node_modules/@motionone/types": { + "version": "10.17.1", + "resolved": "https://registry.npmjs.org/@motionone/types/-/types-10.17.1.tgz", + "integrity": "sha512-KaC4kgiODDz8hswCrS0btrVrzyU2CSQKO7Ps90ibBVSQmjkrt2teqta6/sOG59v7+dPnKMAg13jyqtMKV2yJ7A==", + "license": "MIT" + }, + "node_modules/@motionone/utils": { + "version": "10.18.0", + "resolved": "https://registry.npmjs.org/@motionone/utils/-/utils-10.18.0.tgz", + "integrity": "sha512-3XVF7sgyTSI2KWvTf6uLlBJ5iAgRgmvp3bpuOiQJvInd4nZ19ET8lX5unn30SlmRH7hXbBbH+Gxd0m0klJ3Xtw==", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" + "dependencies": { + "@motionone/types": "^10.17.1", + "hey-listen": "^1.0.8", + "tslib": "^2.3.1" } }, - "node_modules/@next/swc-win32-ia32-msvc": { + "node_modules/@next/env": { "version": "14.2.28", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.28.tgz", - "integrity": "sha512-+Kcp1T3jHZnJ9v9VTJ/yf1t/xmtFAc/Sge4v7mVc1z+NYfYzisi8kJ9AsY8itbgq+WgEwMtOpiLLJsUy2qnXZw==", - "cpu": [ - "ia32" - ], + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.28.tgz", + "integrity": "sha512-PAmWhJfJQlP+kxZwCjrVd9QnR5x0R3u0mTXTiZDgSd4h5LdXmjxCCWbN9kq6hkZBOax8Rm3xDW5HagWyJuT37g==", + "license": "MIT" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.2.4.tgz", + "integrity": "sha512-O8ScvKtnxkp8kL9TpJTTKnMqlkZnS+QxwoQnJwPGBxjBbzd6OVVPEJ5/pMNrktSyXQD/chEfzfFzYLM6JANOOQ==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" + "dependencies": { + "fast-glob": "3.3.1" } }, "node_modules/@next/swc-win32-x64-msvc": { @@ -1900,17 +1574,6 @@ "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", "license": "MIT" }, - "node_modules/@tybys/wasm-util": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", - "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@types/d3": { "version": "7.4.3", "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", @@ -2292,12 +1955,13 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.20", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.20.tgz", - "integrity": "sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg==", + "version": "18.2.42", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.42.tgz", + "integrity": "sha512-c1zEr96MjakLYus/wPnuWDo1/zErfdU9rNsIGmE+NV71nx88FG9Ttgo5dqorXTu/LImX2f63WBP986gJkMPNbA==", "license": "MIT", "dependencies": { "@types/prop-types": "*", + "@types/scheduler": "*", "csstype": "^3.0.2" } }, @@ -2356,6 +2020,12 @@ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "license": "MIT" }, + "node_modules/@types/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-WFHp9YUJQ6CKshqoC37iOlHnQSmxNc795UhB26CyBBttrN9svdIrUjl/NjnNmfcwtncN0h/0PPAFWv9ovP8mLA==", + "license": "MIT" + }, "node_modules/@types/stats.js": { "version": "0.17.3", "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.3.tgz", @@ -2556,284 +2226,85 @@ "micromatch": "^4.0.8" }, "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.29.1.tgz", - "integrity": "sha512-QAkFEbytSaB8wnmB+DflhUPz6CLbFWE2SnSCrRMEa+KnXIzDYbpsn++1HGvnfAsUY44doDXmvRkO5shlM/3UfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.29.1", - "@typescript-eslint/types": "8.29.1", - "@typescript-eslint/typescript-estree": "8.29.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.29.1.tgz", - "integrity": "sha512-RGLh5CRaUEf02viP5c1Vh1cMGffQscyHe7HPAzGpfmfflFg1wUz2rYxd+OZqwpeypYvZ8UxSxuIpF++fmOzEcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.29.1", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "license": "ISC" - }, - "node_modules/@unrs/resolver-binding-darwin-arm64": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.4.1.tgz", - "integrity": "sha512-8Tv+Bsd0BjGwfEedIyor4inw8atppRxM5BdUnIt+3mAm/QXUm7Dw74CHnXpfZKXkp07EXJGiA8hStqCINAWhdw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@unrs/resolver-binding-darwin-x64": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.4.1.tgz", - "integrity": "sha512-X8c3PhWziEMKAzZz+YAYWfwawi5AEgzy/hmfizAB4C70gMHLKmInJcp1270yYAOs7z07YVFI220pp50z24Jk3A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@unrs/resolver-binding-freebsd-x64": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.4.1.tgz", - "integrity": "sha512-UUr/nREy1UdtxXQnmLaaTXFGOcGxPwNIzeJdb3KXai3TKtC1UgNOB9s8KOA4TaxOUBR/qVgL5BvBwmUjD5yuVA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.4.1.tgz", - "integrity": "sha512-e3pII53dEeS8inkX6A1ad2UXE0nuoWCqik4kOxaDnls0uJUq0ntdj5d9IYd+bv5TDwf9DSge/xPOvCmRYH+Tsw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.4.1.tgz", - "integrity": "sha512-e/AKKd9gR+HNmVyDEPI/PIz2t0DrA3cyonHNhHVjrkxe8pMCiYiqhtn1+h+yIpHUtUlM6Y1FNIdivFa+r7wrEQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.4.1.tgz", - "integrity": "sha512-vtIu34luF1jRktlHtiwm2mjuE8oJCsFiFr8hT5+tFQdqFKjPhbJXn83LswKsOhy0GxAEevpXDI4xxEwkjuXIPA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm64-musl": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.4.1.tgz", - "integrity": "sha512-H3PaOuGyhFXiyJd+09uPhGl4gocmhyi1BRzvsP8Lv5AQO3p3/ZY7WjV4t2NkBksm9tMjf3YbOVHyPWi2eWsNYw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.4.1.tgz", - "integrity": "sha512-4+GmJcaaFntCi1S01YByqp8wLMjV/FyQyHVGm0vedIhL1Vfx7uHkz/sZmKsidRwokBGuxi92GFmSzqT2O8KcNA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.4.1.tgz", - "integrity": "sha512-6RDQVCmtFYTlhy89D5ixTqo9bTQqFhvNN0Ey1wJs5r+01Dq15gPHRXv2jF2bQATtMrOfYwv+R2ZR9ew1N1N3YQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.4.1.tgz", - "integrity": "sha512-XpU9uzIkD86+19NjCXxlVPISMUrVXsXo5htxtuG+uJ59p5JauSRZsIxQxzzfKzkxEjdvANPM/lS1HFoX6A6QeA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "node": ">=8.6.0" + } }, - "node_modules/@unrs/resolver-binding-linux-x64-musl": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.4.1.tgz", - "integrity": "sha512-3CDjG/spbTKCSHl66QP2ekHSD+H34i7utuDIM5gzoNBcZ1gTO0Op09Wx5cikXnhORRf9+HyDWzm37vU1PLSM1A==", - "cpu": [ - "x64" - ], + "node_modules/@typescript-eslint/typescript-estree/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } }, - "node_modules/@unrs/resolver-binding-wasm32-wasi": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.4.1.tgz", - "integrity": "sha512-50tYhvbCTnuzMn7vmP8IV2UKF7ITo1oihygEYq9wW2DUb/Y+QMqBHJUSCABRngATjZ4shOK6f2+s0gQX6ElENQ==", - "cpu": [ - "wasm32" - ], + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, - "license": "MIT", - "optional": true, + "license": "ISC", "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.8" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=14.0.0" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.4.1.tgz", - "integrity": "sha512-KyJiIne/AqV4IW0wyQO34wSMuJwy3VxVQOfIXIPyQ/Up6y/zi2P/WwXb78gHsLiGRUqCA9LOoCX+6dQZde0g1g==", - "cpu": [ - "arm64" - ], + "node_modules/@typescript-eslint/utils": { + "version": "8.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.29.1.tgz", + "integrity": "sha512-QAkFEbytSaB8wnmB+DflhUPz6CLbFWE2SnSCrRMEa+KnXIzDYbpsn++1HGvnfAsUY44doDXmvRkO5shlM/3UfA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.29.1", + "@typescript-eslint/types": "8.29.1", + "@typescript-eslint/typescript-estree": "8.29.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } }, - "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.4.1.tgz", - "integrity": "sha512-y2NUD7pygrBolN2NoXUrwVqBpKPhF8DiSNE5oB5/iFO49r2DpoYqdj5HPb3F42fPBH5qNqj6Zg63+xCEzAD2hw==", - "cpu": [ - "ia32" - ], + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.29.1.tgz", + "integrity": "sha512-RGLh5CRaUEf02viP5c1Vh1cMGffQscyHe7HPAzGpfmfflFg1wUz2rYxd+OZqwpeypYvZ8UxSxuIpF++fmOzEcg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "@typescript-eslint/types": "8.29.1", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" }, "node_modules/@unrs/resolver-binding-win32-x64-msvc": { "version": "1.4.1", @@ -5677,18 +5148,34 @@ "url": "https://github.com/sponsors/rawify" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, + "node_modules/framer-motion": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-6.5.1.tgz", + "integrity": "sha512-o1BGqqposwi7cgDrtg0dNONhkmPsUFDaLcKXigzuTFC5x58mE8iyTazxSudFzmT6MEyJKfjjU8ItoMe3W+3fiw==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "dependencies": { + "@motionone/dom": "10.12.0", + "framesync": "6.0.1", + "hey-listen": "^1.0.8", + "popmotion": "11.0.3", + "style-value-types": "5.0.0", + "tslib": "^2.1.0" + }, + "optionalDependencies": { + "@emotion/is-prop-valid": "^0.8.2" + }, + "peerDependencies": { + "react": ">=16.8 || ^17.0.0 || ^18.0.0", + "react-dom": ">=16.8 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/framesync": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/framesync/-/framesync-6.0.1.tgz", + "integrity": "sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.1.0" } }, "node_modules/function-bind": { @@ -6130,6 +5617,12 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hey-listen": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz", + "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==", + "license": "MIT" + }, "node_modules/hls.js": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.6.1.tgz", @@ -7309,6 +6802,12 @@ "three": ">=0.134.0" } }, + "node_modules/material-ripple-effects": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/material-ripple-effects/-/material-ripple-effects-2.0.1.tgz", + "integrity": "sha512-hHlUkZAuXbP94lu02VgrPidbZ3hBtgXBtjlwR8APNqOIgDZMV8MCIcsclL8FmGJQHvnORyvoQgC965vPsiyXLQ==", + "license": "MIT" + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -8706,6 +8205,18 @@ "node": ">=10" } }, + "node_modules/popmotion": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/popmotion/-/popmotion-11.0.3.tgz", + "integrity": "sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA==", + "license": "MIT", + "dependencies": { + "framesync": "6.0.1", + "hey-listen": "^1.0.8", + "style-value-types": "5.0.0", + "tslib": "^2.1.0" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -10273,6 +9784,16 @@ "inline-style-parser": "0.2.4" } }, + "node_modules/style-value-types": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-5.0.0.tgz", + "integrity": "sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA==", + "license": "MIT", + "dependencies": { + "hey-listen": "^1.0.8", + "tslib": "^2.1.0" + } + }, "node_modules/styled-jsx": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", @@ -10377,33 +9898,33 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.17", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", - "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", + "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", - "chokidar": "^3.6.0", + "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.3.2", + "fast-glob": "^3.3.0", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.21.6", - "lilconfig": "^3.1.3", - "micromatch": "^4.0.8", + "jiti": "^1.19.1", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", - "picocolors": "^1.1.1", - "postcss": "^8.4.47", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.2", - "postcss-nested": "^6.2.0", - "postcss-selector-parser": "^6.1.2", - "resolve": "^1.22.8", - "sucrase": "^3.35.0" + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" }, "bin": { "tailwind": "lib/cli.js", @@ -10459,6 +9980,15 @@ "jiti": "bin/jiti.js" } }, + "node_modules/tailwindcss/node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -11496,6 +11026,126 @@ "type": "github", "url": "https://github.com/sponsors/wooorm" } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "14.2.28", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.28.tgz", + "integrity": "sha512-kzGChl9setxYWpk3H6fTZXXPFFjg7urptLq5o5ZgYezCrqlemKttwMT5iFyx/p1e/JeglTwDFRtb923gTJ3R1w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.2.28", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.28.tgz", + "integrity": "sha512-z6FXYHDJlFOzVEOiiJ/4NG8aLCeayZdcRSMjPDysW297Up6r22xw6Ea9AOwQqbNsth8JNgIK8EkWz2IDwaLQcw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.2.28", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.28.tgz", + "integrity": "sha512-9ARHLEQXhAilNJ7rgQX8xs9aH3yJSj888ssSjJLeldiZKR4D7N08MfMqljk77fAwZsWwsrp8ohHsMvurvv9liQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.2.28", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.28.tgz", + "integrity": "sha512-p6gvatI1nX41KCizEe6JkF0FS/cEEF0u23vKDpl+WhPe/fCTBeGkEBh7iW2cUM0rvquPVwPWdiUR6Ebr/kQWxQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.2.28", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.28.tgz", + "integrity": "sha512-nsiSnz2wO6GwMAX2o0iucONlVL7dNgKUqt/mDTATGO2NY59EO/ZKnKEr80BJFhuA5UC1KZOMblJHWZoqIJddpA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.2.28", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.28.tgz", + "integrity": "sha512-+IuGQKoI3abrXFqx7GtlvNOpeExUH1mTIqCrh1LGFf8DnlUcTmOOCApEnPJUSLrSbzOdsF2ho2KhnQoO0I1RDw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.2.28", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.28.tgz", + "integrity": "sha512-l61WZ3nevt4BAnGksUVFKy2uJP5DPz2E0Ma/Oklvo3sGj9sw3q7vBWONFRgz+ICiHpW5mV+mBrkB3XEubMrKaA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.2.28", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.28.tgz", + "integrity": "sha512-+Kcp1T3jHZnJ9v9VTJ/yf1t/xmtFAc/Sge4v7mVc1z+NYfYzisi8kJ9AsY8itbgq+WgEwMtOpiLLJsUy2qnXZw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } } } } diff --git a/package.json b/package.json index 05e92e3..e022a80 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,10 @@ "@fontsource/poppins": "^5.2.5", "@fontsource/public-sans": "^5.2.5", "@headlessui/react": "^2.2.1", + "@heroicons/react": "^2.1.1", "@langchain/core": "^0.3.44", "@langchain/openai": "^0.5.5", + "@material-tailwind/react": "^2.1.9", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-slot": "^1.1.2", @@ -62,7 +64,7 @@ "@types/d3-selection": "^3.0.11", "@types/d3-zoom": "^3.0.8", "@types/node": "^20", - "@types/react": "^18.3.5", + "@types/react": "^18.2.42", "@types/react-dom": "^18.3.0", "@types/react-slick": "^0.23.13", "@types/react-virtualized-auto-sizer": "^1.0.4", diff --git a/src/app/(Dashboard)/dashboard/dashboard.css b/src/app/(Dashboard)/dashboard/dashboard.css new file mode 100644 index 0000000..5beafc7 --- /dev/null +++ b/src/app/(Dashboard)/dashboard/dashboard.css @@ -0,0 +1,17 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + } + + body { + margin: 0; + min-width: 320px; + min-height: 100vh; + } +} \ No newline at end of file diff --git a/src/app/(Dashboard)/dashboard/guests/page.tsx b/src/app/(Dashboard)/dashboard/guests/page.tsx new file mode 100644 index 0000000..988b981 --- /dev/null +++ b/src/app/(Dashboard)/dashboard/guests/page.tsx @@ -0,0 +1,860 @@ +'use client' + +import React, { useState, useEffect } from 'react'; +import { ArrowPathIcon, EyeIcon, HomeIcon, MagnifyingGlassIcon, MinusIcon, PencilIcon, PlusIcon, TrashIcon } from '@heroicons/react/24/outline'; +import axios from 'axios'; +import { + Card, + CardHeader, + CardBody, + Typography, + Input, + Chip, + IconButton, + Button, + Dialog, + DialogHeader, + DialogBody, + DialogFooter, + Alert, +} from "@material-tailwind/react"; +import { API_URL } from '@/utils/axiosConfig' +import { v4 as uuidv4 } from 'uuid'; + +interface Interaction { + event: string, + timestamp: string, +} + +interface Guest { + additional_notes?: string; + budget?: string; + company?: string; + contact_info?: string; + created_at?: string; + current_tech?: string[]; + first_visit_timestamp?: string; + id?: string; + industry?: string; + interaction_events?: string[]; + interaction_history?: Interaction[]; + name?: string; + page_views?: string[]; + pain_points?: string[]; + project_type?: string[]; + session_id?: string; + status?: 'NEW' | 'CONTACTED' | 'CONVERTED'; + timeline?: string; + updated_at?: string; +} + +const GuestsTable: React.FC = () => { + const [guests, setGuests] = useState([]); + const [loading, setLoading] = useState(true); + const [searchTerm, setSearchTerm] = useState(''); + const [currentPage, setCurrentPage] = useState(1); + const [selectedGuest, setSelectedGuest] = useState(null); + const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); + const [isViewModalOpen, setIsViewModalOpen] = useState(false); + const [isEditModalOpen, setIsEditModalOpen] = useState(false); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [createFormData, setCreateFormData] = useState({}); + const [numProjectTypeFields, setNumProjectTypeFields] = useState(1); + const [numPainPointFields, setNumPainPointFields] = useState(1); + const [numCurrentTechFields, setNumCurrentTechFields] = useState(1); + const [editFormData, setEditFormData] = useState({}); + const [showError, setShowError] = useState(false); + const itemsPerPage = 10; + + useEffect(() => { + fetchGuests(); + }, []); + + const fetchGuests = async () => { + setLoading(true); + try { + const res = await axios.get(`${API_URL}/guests/`); + if(!(Array.isArray(res.data) && res.data.every(guest => typeof guest === 'object'))) { + setShowError(true); + throw Error //Ensure an array of guests is returned + } else setShowError(false); + setGuests(res.data); + } catch { + setShowError(true); + } + setLoading(false); + }; + + const handleView = (guest: Guest) => { + setSelectedGuest(guest); + setIsViewModalOpen(true); + } + + const handleCreate = () => { + setNumProjectTypeFields(1); + setNumPainPointFields(1); + setNumCurrentTechFields(1); + setIsCreateModalOpen(true); + }; + + const handleEdit = (guest: Guest) => { + setSelectedGuest(guest); + setNumProjectTypeFields(guest.project_type ? guest.project_type.length : 0); + setNumPainPointFields(guest.pain_points ? guest.pain_points.length : 0); + setNumCurrentTechFields(guest.current_tech ? guest.current_tech.length: 0); + setEditFormData(guest); + setIsEditModalOpen(true); + }; + + const handleDelete = (guest: Guest) => { + setSelectedGuest(guest); + setIsDeleteModalOpen(true); + }; + + const handleCreateSubmit = async () => { + if (!createFormData) return; + + try { + createFormData.session_id = uuidv4(); + await axios.post(`${API_URL}/guests/`, createFormData); + + // Update guests + fetchGuests(); + + setIsCreateModalOpen(false); + setCreateFormData({}); + } catch (error) { + console.error('Error creating guest:', error); + // Handle error (show error message to user) + } + }; + + const handleEditSubmit = async () => { + if (!editFormData) return; + + try { + await axios.put(`${API_URL}/guests/${editFormData.id}`, editFormData); + + // Update guests + fetchGuests(); + + setIsEditModalOpen(false); + setEditFormData({}); + } catch (error) { + console.error('Error updating guest:', error); + // Handle error (show error message to user) + } + }; + + const handleDeleteConfirm = async () => { + if (!selectedGuest) return; + + try { + await axios.delete(`${API_URL}/guests/${selectedGuest.id}`); + + // Update guests + fetchGuests(); + + setIsDeleteModalOpen(false); + setSelectedGuest(null); + } catch (error) { + console.error('Error deleting guest:', error); + // Handle error (show error message to user) + } + }; + + const getStatusColor = (status: Guest['status']) => { + switch (status) { + case 'NEW': + return 'blue'; + case 'CONTACTED': + return 'amber'; + case 'CONVERTED': + return 'green'; + default: + return 'gray'; + } + }; + + const filteredGuests = guests.filter(guest => + searchTerm.toLowerCase() === '' ? true : + (guest.name ? guest.name.toLowerCase().includes(searchTerm.toLowerCase()) : false) || + (guest.company ? guest.company.toLowerCase().includes(searchTerm.toLowerCase()) : false) || + (guest.industry ? guest.industry.toLowerCase().includes(searchTerm.toLowerCase()) : false) || + (guest.budget ? guest.budget.toLowerCase().includes(searchTerm.toLowerCase()) : false) || + (guest.contact_info ? guest.contact_info.toLowerCase().includes(searchTerm.toLowerCase()) : false) || + (guest.status ? guest.status.toLowerCase().includes(searchTerm.toLowerCase()) : false) + ); + + const paginatedGuests = filteredGuests.slice( + (currentPage - 1) * itemsPerPage, + currentPage * itemsPerPage + ); + + const totalPages = Math.ceil(filteredGuests.length / itemsPerPage); + + const TABLE_HEAD = ["Name", "Company", "Industry", "Budget", "Contact", "Status", "Last Interaction", "Actions"]; + + const viewField = (field: string, value: string | undefined) => { + return ( +
+ + {field} + + 0 ? "overscroll-x-contain overflow-auto border-black border-2 h-min w-full" : + "overscroll-x-contain overflow-auto border-black border-2 w-full" : + "overscroll-x-contain overflow-auto w-full"}> + + {value ? value : ''} + + +
+ ) + } + if(showError) return ( + + + + } + > + Failed to retrieve guests + + ) + return ( + +
+
+ + Guest Management + + + View and manage guest accounts in your system + +
+ +
+ + +
+
+ + Guests list + + + See information about all guests + +
+
+
+ + + +
+
+ } + value={searchTerm} + onChange={(e) => setSearchTerm(e.target.value)} + crossOrigin={undefined} + /> +
+
+
+
+ + + + + {TABLE_HEAD.map((head) => ( + + ))} + + + + {loading ? ( + + + + ) : ( + paginatedGuests.map((guest, index) => { + const isLast = index === paginatedGuests.length - 1; + const classes = isLast ? "p-4" : "p-4 border-b border-blue-gray-50"; + return ( + + + + + + + + + + + ); + }) + )} + +
+ + {head} + +
+ + Loading... + +
+ + {guest.name ? guest.name : ''} + + + + {guest.company ? guest.company : ''} + + + + {guest.industry ? guest.industry : ''} + + + + {guest.budget ? guest.budget : ''} + + + + {guest.contact_info ? guest.contact_info : ''} + + +
+ +
+
+ + {guest.interaction_history && guest.interaction_history.length > 0 ? guest.interaction_history[guest.interaction_history.length-1].timestamp : 'None'} + + +
+ handleView(guest)} + > + + + handleEdit(guest)} + > + + + handleDelete(guest)} + > + + +
+
+
+
+ + Page {currentPage} of {totalPages} + +
+ + +
+
+ + {/* Create Modal */} + setIsCreateModalOpen(false)} + > + Create Guest + +
+ setCreateFormData({ ...createFormData, name: e.target.value })} + crossOrigin={undefined} + /> + setCreateFormData({ ...createFormData, company: e.target.value })} + crossOrigin={undefined} + /> + setCreateFormData({ ...createFormData, industry: e.target.value })} + crossOrigin={undefined} + /> + setCreateFormData({ ...createFormData, budget: e.target.value })} + crossOrigin={undefined} + /> + setCreateFormData({ ...createFormData, timeline: e.target.value })} + crossOrigin={undefined} + /> + setCreateFormData({ ...createFormData, contact_info: e.target.value })} + crossOrigin={undefined} + /> + setCreateFormData({ ...createFormData, additional_notes: e.target.value })} + crossOrigin={undefined} + /> + { + // Create project type fields based on numProjectTypeFields + Array.from({length: numProjectTypeFields}, (_, num) => num+1 && + setCreateFormData({ ...createFormData, project_type: createFormData.project_type ? createFormData.project_type.map((value, i) => (i === num ? e.target.value : value)) : [e.target.value] })} + crossOrigin={undefined} + />) + } +
+ + +
+ { + // Create pain point fields based on numPainPointFields + Array.from({length: numPainPointFields}, (_, num) => num+1 && + setCreateFormData({ ...createFormData, pain_points: createFormData.pain_points ? createFormData.pain_points.map((value, i) => (i === num ? e.target.value : value)) : [e.target.value] })} + crossOrigin={undefined} + />) + } +
+ + +
+ { + // Create current tech fields based on numCurrentTechFields + Array.from({length: numCurrentTechFields}, (_, num) => num+1 && + setCreateFormData({ ...createFormData, current_tech: createFormData.current_tech ? createFormData.current_tech.map((value, i) => (i === num ? e.target.value : value)) : [e.target.value] })} + crossOrigin={undefined} + />) + } +
+ + +
+
+ + Status + + +
+
+
+ + + + +
+ + {/* View Modal */} + setIsViewModalOpen(false)} + > + View Guest + +
{/*Fix jest detecting no children in DialogBody error*/}
+ {selectedGuest && ( +
+ {viewField('Name:', selectedGuest.name)} + {viewField('Id:', String(selectedGuest.id))} + {viewField('Session Id:', selectedGuest.session_id)} + {viewField('Company:', selectedGuest.company)} + {viewField('Industry:', selectedGuest.industry)} + {viewField('Budget:', selectedGuest.budget)} + {viewField('Contact:', selectedGuest.contact_info)} + {viewField('Timeline:', selectedGuest.timeline)} + {viewField('Additional Notes:', selectedGuest.additional_notes)} + {viewField('Status:', selectedGuest.status)} + {viewField('Created At:', selectedGuest.created_at)} + {viewField('Updated At:', selectedGuest.updated_at)} + {viewField('First Visit Time:', selectedGuest.first_visit_timestamp)} + {viewField('Interaction History:', selectedGuest.interaction_history ? selectedGuest.interaction_history.map(obj => `${obj.event} at ${obj.timestamp}`).join(', ') : undefined)} + {viewField('Interaction Events:', selectedGuest.interaction_events ? selectedGuest.interaction_events.join(', ') : undefined)} + {viewField('Project Types:', selectedGuest.project_type ? selectedGuest.project_type.join(', ') : undefined)} + {viewField('Pain Points:', selectedGuest.pain_points? selectedGuest.pain_points.join(', ') : undefined)} + {viewField('Current Tech:', selectedGuest.current_tech ? selectedGuest.current_tech.join(', ') : undefined)} + {viewField('Page Views:', selectedGuest.page_views ? selectedGuest.page_views.join(', ') : undefined)} +
+ )} +
+ + + +
+ + {/* Edit Modal */} + setIsEditModalOpen(false)} + > + Edit Guest + +
+ setEditFormData({ ...editFormData, name: e.target.value })} + crossOrigin={undefined} + /> + setEditFormData({ ...editFormData, company: e.target.value })} + crossOrigin={undefined} + /> + setEditFormData({ ...editFormData, industry: e.target.value })} + crossOrigin={undefined} + /> + setEditFormData({ ...editFormData, budget: e.target.value })} + crossOrigin={undefined} + /> + setEditFormData({ ...editFormData, timeline: e.target.value })} + crossOrigin={undefined} + /> + setEditFormData({ ...editFormData, contact_info: e.target.value })} + crossOrigin={undefined} + /> + setEditFormData({ ...editFormData, additional_notes: e.target.value })} + crossOrigin={undefined} + /> + { + // Create project type fields based on numProjectTypeFields + Array.from({length: numProjectTypeFields}, (_, num) => num+1 && + setEditFormData({ ...editFormData, project_type: editFormData.project_type ? editFormData.project_type.map((value, i) => (i === num ? e.target.value : value)) : [e.target.value] })} + crossOrigin={undefined} + />) + } +
+ + +
+ { + // Create pain point fields based on numPainPointFields + Array.from({length: numPainPointFields}, (_, num) => num+1 && + setEditFormData({ ...editFormData, pain_points: editFormData.pain_points ? editFormData.pain_points.map((value, i) => (i === num ? e.target.value : value)) : [e.target.value] })} + crossOrigin={undefined} + />) + } +
+ + +
+ { + // Create current tech fields based on numCurrentTechFields + Array.from({length: numCurrentTechFields}, (_, num) => num+1 && + setEditFormData({ ...editFormData, current_tech: editFormData.current_tech ? editFormData.current_tech.map((value, i) => (i === num ? e.target.value : value)) : [e.target.value] })} + crossOrigin={undefined} + />) + } +
+ + +
+
+ + Status + + +
+
+
+ + + + +
+ + {/* DeleteConfirmation Modal */} + setIsDeleteModalOpen(false)} + > + Confirm Deletion + + Are you sure you want to delete {selectedGuest?.name}? This action cannot be undone. + + + + + + +
+
+ ); +} + +export default GuestsTable; \ No newline at end of file diff --git a/src/app/(Dashboard)/dashboard/layout.tsx b/src/app/(Dashboard)/dashboard/layout.tsx new file mode 100644 index 0000000..a6bb849 --- /dev/null +++ b/src/app/(Dashboard)/dashboard/layout.tsx @@ -0,0 +1,863 @@ +'use client' +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable react-hooks/exhaustive-deps */ +import React, { useContext, useState, useEffect } from 'react'; +import { AuthContext, PrivateRoute } from '@/components/Dashboard/AppContext'; +import { + UsersIcon, + HomeIcon, + ShoppingBagIcon, + UserCircleIcon, + ChevronLeftIcon, + ChevronRightIcon, + Bars3Icon as MenuIcon, + ChartBarIcon, + BellIcon, + CheckCircleIcon, + ChatBubbleLeftRightIcon, + InformationCircleIcon, + XMarkIcon, + CpuChipIcon, + FolderIcon, + DocumentTextIcon, + BookOpenIcon, + ArrowRightStartOnRectangleIcon, +} from '@heroicons/react/24/outline'; +import { + Card, + Typography, + ListItem, + ListItemPrefix, + Drawer, + IconButton, + Menu, + MenuHandler, + MenuList, + MenuItem, + Navbar, + Dialog, + DialogHeader, + DialogBody, + DialogFooter, + Button, + Avatar, + Switch, + Badge, + Textarea, + Alert, +} from "@material-tailwind/react"; +import Link from 'next/link'; +import { useRouter } from 'next/navigation'; +import axios from 'axios'; +import { API_URL } from '@/utils/axiosConfig'; +import { cn } from '@/lib/utils'; +import { colors } from '@material-tailwind/react/types/generic'; +import './dashboard.css' + +interface User { + address: string | null; + card_number: string | null; + ccv: string | null; + city: string | null; + created_at: string; + email: string; + email_verified: boolean; + failed_login_attempts: number; + first_name: string | null; + hashed_password: string; + id: string; + is_locked: boolean; + last_name: string | null; + nickname: string | null; + phone_number: string | null; + role: "ADMIN" | "USER"; + security_code: string | null; + state: string | null; + subscription_plan: "PREMIUM" | "BASIC" | "FREE"; + updated_at: string; + verification_token: string | null; + zip_code: string | null +} + +interface AccountInfo { + nickname: string | null; + email: string; + first_name: string | null; + last_name: string | null; +} + +// User navigation - restricted options (no Analytics) +const userNavigation = [ + { + name: 'Dashboard', + href: '/dashboard', + icon: ChartBarIcon, + description: 'Overview of your activity' + }, + { + name: 'Projects', + href: '/dashboard/projects', + icon: DocumentTextIcon, + description: 'Manage your projects' + }, + { + name: 'Resources', + href: '/dashboard/resources', + icon: FolderIcon, + description: 'Manage files and documents' + }, + { + name: 'Marketplace', + href: '/dashboard/marketplace', + icon: ShoppingBagIcon, + description: 'Browse available services' + }, + { + name: 'Knowledge Graph', + href: '/dashboard/knowledge', + icon: BookOpenIcon, + description: 'Explore data relationships' + }, + { + name: 'Real-Time Analytics', + href: '/dashboard/realtime', + icon: CpuChipIcon, + description: 'Live system metrics' + } +]; + +// Admin navigation- full options (includes Analytics) +const adminNavigation = [ + { + name: 'Dashboard', + href: '/dashboard', + icon: ChartBarIcon, + description: 'Overview of your activity' + }, + { + name: 'Analytics', + href: '/dashboard/analytics', + icon: ChartBarIcon, + description: 'View performance metrics' + }, + { + name: 'Projects', + href: '/dashboard/projects', + icon: DocumentTextIcon, + description: 'Manage your projects' + }, + { + name: 'Users', + href: '/dashboard/users', + icon: UsersIcon, + description: 'Manage system users' + }, + { + name: 'Guests', + href: '/dashboard/guests', + icon: HomeIcon, + description: 'View guest accounts' + }, + { + name: 'Resources', + href: '/dashboard/resources', + icon: FolderIcon, + description: 'Manage files and documents' + }, + { + name: 'Marketplace', + href: '/dashboard/marketplace', + icon: ShoppingBagIcon, + description: 'Browse available services' + }, + { + name: 'Knowledge Graph', + href: '/dashboard/knowledge', + icon: BookOpenIcon, + description: 'Explore data relationships' + }, + { + name: 'Real-Time Analytics', + href: '/dashboard/realtime', + icon: CpuChipIcon, + description: 'Live system metrics' + } +]; + +// Notification structure +interface Notification { + id: number; + title: string; + message: string; + timestamp: string; + read: boolean; + type: 'alert' | 'info' | 'success'; +} + +export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) { + const { role, logout, accessToken } = useContext(AuthContext); + const navigate = useRouter(); + //const location = useLocation(); + const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false); + const [currentPage, setCurrentPage] = useState('/dashboard'); + const [isDrawerOpen, setIsDrawerOpen] = useState(false); + //const [isVisible, setIsVisible] = useState(false); + const [isLogoutModalOpen, setIsLogoutModalOpen] = useState(false); + const [isAdminView, setIsAdminView] = useState(role === "ADMIN"); // Default to admin view + const [isNotificationsOpen, setIsNotificationsOpen] = useState(false); + const [accountInfo, setAccountInfo] = useState({ + email: '', + nickname: null, + first_name: null, + last_name: null, + }); + const [avatarUrl, setAvatarUrl] = useState(''); + const loadAccount = async () => { + try { + const response = await axios.get(`${API_URL}/auth/auth`, { + headers: { 'Authorization' : `Bearer ${accessToken}` }, + }); + const user: User = response.data.username; + if(user) { + const localAvatarUrl = localStorage.getItem('Avatar:'+user.email); + if(localAvatarUrl) setAvatarUrl(localAvatarUrl); + setAccountInfo({ + email: user.email, + nickname: user.nickname, + first_name: user.first_name, + last_name: user.last_name + }); + } else console.error("User not found"); + } catch { + console.error("User not found"); + } + } + + useEffect(() => { + loadAccount(); + addEventListener('profileChange', function(event: any) { + setAccountInfo({...accountInfo, + email: event.detail.email, + first_name: event.detail.first_name, + last_name: event.detail.last_name, + nickname: event.detail.nickname + }) + const localAvatarUrl = localStorage.getItem('Avatar:'+event.detail.email); + if(localAvatarUrl) setAvatarUrl(localAvatarUrl); + }); + }, []); + + // Sample notifications + const [notifications, setNotifications] = useState([ + { + id: 1, + title: "New User Registration", + message: "A new user has registered on the platform.", + timestamp: new Date(Date.now() - 15 * 60000).toISOString(), + read: false, + type: 'info' + }, + { + id: 2, + title: "System Update", + message: "The system will undergo maintenance tonight at 2 AM EST.", + timestamp: new Date(Date.now() - 2 * 3600000).toISOString(), + read: false, + type: 'alert' + }, + { + id: 3, + title: "Project Completed", + message: "Sales Forecasting project has been completed successfully.", + timestamp: new Date(Date.now() - 1 * 86400000).toISOString(), + read: true, + type: 'success' + } + ]); + + // Get count of unread notifications + const unreadCount = notifications.filter(n => !n.read).length; + + // Get current navigation based on view mode + const navigation = isAdminView ? adminNavigation : userNavigation; + + // States for support and report modals + const [isSupportModalOpen, setIsSupportModalOpen] = useState(false); + const [showToast, setShowToast] = useState({ + show: false, + message: "", + color: "green" + }); + + // Function to show toast notifications + const showNotification = (message: string, color = "green") => { + setShowToast({ + show: true, + message, + color + }); + + setTimeout(() => { + setShowToast({...showToast, show: false}); + }, 3000); + }; + + const handleLogout = () => { + setIsLogoutModalOpen(true); + }; + + const handleCloseLogoutModal = () => { + setIsLogoutModalOpen(false); + }; + + const handleConfirmLogout = () => { + logout(); + navigate.push('/login'); + }; + + const handleNavigation = (path: string) => { + // Check if the path is available in current view mode + const isPathAvailable = navigation.some(item => item.href === path); + if (!isPathAvailable) { + // If trying to access a restricted page in user view, stay on dashboard + if (!isAdminView) { + path = '/dashboard'; + } + } + + //const page = path.split('/').pop() || 'dashboard'; + //setCurrentPage(page); + setCurrentPage(path); + navigate.push(path); + setIsDrawerOpen(false); // Close drawer on navigation + }; + + const handleToggleView = () => { + dispatchEvent(new CustomEvent("switch", {detail: isAdminView ? 'USESR' : 'ADMIN'})); + setIsAdminView(!isAdminView); + // If switching to user view while on an admin-only page, redirect to dashboard + if (isAdminView) { + const currentPath = location.pathname; + const isPathAvailable = userNavigation.some(item => item.href === currentPath); + if (!isPathAvailable) { + navigate.push('/dashboard'); + setCurrentPage('dashboard'); + } + } + }; + + const markNotificationAsRead = (id: number) => { + setNotifications(notifications.map(notification => + notification.id === id ? { ...notification, read: true } : notification + )); + }; + + const markAllNotificationsAsRead = () => { + setNotifications(notifications.map(notification => ({ ...notification, read: true }))); + }; + + const deleteNotification = (id: number) => { + setNotifications(notifications.filter(notification => notification.id !== id)); + }; + + const formatNotificationTime = (timestamp: string | number | Date) => { + const date = new Date(timestamp); + const now = new Date(); + const diffMs = now.getTime() - date.getTime(); + const diffMins = Math.floor(diffMs / 60000); + + if (diffMins < 60) { + return `${diffMins} min${diffMins !== 1 ? 's' : ''} ago`; + } + + const diffHours = Math.floor(diffMins / 60); + if (diffHours < 24) { + return `${diffHours} hour${diffHours !== 1 ? 's' : ''} ago`; + } + + const diffDays = Math.floor(diffHours / 24); + if (diffDays < 7) { + return `${diffDays} day${diffDays !== 1 ? 's' : ''} ago`; + } + + return date.toLocaleDateString(); + }; + + const getNotificationIcon = (type: string) => { + switch (type) { + case 'alert': + return ; + case 'success': + return ; + default: + return ; + } + }; +/* + const breadcrumbs = location.pathname + .split('/') + .filter(Boolean) + .map((path, index, array) => ({ + name: path.charAt(0).toUpperCase() + path.slice(1), + href: '/' + array.slice(0, index + 1).join('/'), + current: index === array.length - 1, + })); + */ + // Updated Sidebar with visible toggle button when collapsed + const Sidebar = () => ( +
+
+ {/* Phantom element to take up space of fixed sidebar */} +
+ + {/* Toggle button fixed position to always remain visible */} +
+ setIsSidebarCollapsed(!isSidebarCollapsed)} + className="mb-4" + > + {isSidebarCollapsed ? : } + +
+
+ {/* Role identifier */} + {!isSidebarCollapsed && ( +
+
+
+ + {isAdminView ? "Admin View" : "User View"} + +
+
+ )} + +
+ {navigation.map((item) => { + const isActive = /*location.pathname*/currentPage === item.href /*|| + (item.href === '/dashboard' && location.pathname === '/dashboard') || + (location.pathname.includes(item.href) && item.href !== '/dashboard');*/ + return ( + handleNavigation(item.href)} + > + + + + {!isSidebarCollapsed && ( +
+ + {item.name} + + {!isActive && ( + + {item.description} + + )} +
+ )} +
+ ); + })} +
+ + {!isSidebarCollapsed && ( +
+ + Need Help? + + Contact our support team for assistance with any issues. + + + + + +
+ )} +
+
+
+ ); + return ( + +
+ {/* Add blur overlay when logout modal is open */} + {isLogoutModalOpen && ( +
+ )} + + +
+
+ Theoforge Logo + + Theoforge + + +
+ +
+ {/* Admin/User View Toggle */} +
+ + Admin + + + + User + +
+ + {/* Notifications dropdown */} + + +
+ + + + {unreadCount > 0 && ( + {' '} + )} +
+
+ +
+ + Notifications + + {unreadCount > 0 ? ( + + ) : ( + + No new notifications + + )} +
+ {notifications.length > 0 ? ( + notifications.map((notification) => ( + +
+
+
+ {getNotificationIcon(notification.type)} +
+
+
+ + {notification.title} + + {!notification.read && ( +
+ )} +
+ + {notification.message} + + + {formatNotificationTime(notification.timestamp)} + +
+
+
+ {!notification.read && ( + { + e.stopPropagation(); + markNotificationAsRead(notification.id); + }} + > + + + )} + { + e.stopPropagation(); + deleteNotification(notification.id); + }} + > + + +
+
+
+ )) + ) : ( + + No notifications + + )} +
+
+ + + + + + + navigate.push('/dashboard/profile')} + > + + + Profile Settings + + + + + + + Learn More + + + + + + + Sign Out + + + + +
+
+
+ +
+
+ +
+ + setIsDrawerOpen(false)} + className="lg:hidden w-auto" + > + +
+
+ Theoforge Logo + {!isSidebarCollapsed ? ( + Theoforge + ) : <>} +
+
+ +
+
+
+ +
+
+ {children} +
+
+ {/* Logout Modal */} + + Confirm Logout + + Are you sure you want to log out of your account? + + + + + + + + {/* Toast notification */} + {showToast.show && ( + } + onClose={() => setShowToast({...showToast, show: false})} + > + {showToast.message} + + )} + + {/* Support Modal */} + setIsSupportModalOpen(false)} + size="md" + > + Contact Support + +
+
+ + Support Category + + +
+
+ + Priority + + +
+
+ + Description + +