diff --git a/package-lock.json b/package-lock.json index 0f16e51..5129222 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,26 +8,34 @@ "name": "myuni-frontend-admin-new", "version": "0.0.0", "dependencies": { + "@floating-ui/react": "^0.27.15", "@radix-ui/react-avatar": "^1.1.10", "@radix-ui/react-checkbox": "^1.3.2", "@radix-ui/react-collapsible": "^1.1.11", "@radix-ui/react-dialog": "^1.1.14", "@radix-ui/react-dropdown-menu": "^2.1.15", "@radix-ui/react-label": "^2.1.7", + "@radix-ui/react-popover": "^1.1.14", "@radix-ui/react-select": "^2.2.5", + "@radix-ui/react-separator": "^1.1.7", "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-tabs": "^1.1.12", "@tailwindcss/vite": "^4.1.6", + "@tiptap/pm": "^3.1.0", + "@tiptap/react": "^3.1.0", + "@tiptap/starter-kit": "^3.1.0", "axios": "^1.11.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "dotenv": "^17.2.1", "input-otp": "^1.4.2", + "lodash.throttle": "^4.1.1", "lucide-react": "^0.510.0", "moment": "^2.30.1", "next-themes": "^0.4.6", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-hotkeys-hook": "^5.1.0", "react-router": "^7.6.0", "react-router-dom": "^7.7.1", "recoil": "^0.7.7", @@ -821,9 +829,9 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz", - "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", + "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -831,9 +839,9 @@ } }, "node_modules/@eslint/core": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", - "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -881,9 +889,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.32.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.32.0.tgz", - "integrity": "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==", + "version": "9.33.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.33.0.tgz", + "integrity": "sha512-5K1/mKhWaMfreBGJTwval43JJmkip0RmM+3+IuqupeSKNC/Th2Kc7ucaq5ovTSra/OOKB9c58CGSz3QMVbWt0A==", "dev": true, "license": "MIT", "engines": { @@ -904,13 +912,13 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.4.tgz", - "integrity": "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.15.1", + "@eslint/core": "^0.15.2", "levn": "^0.4.1" }, "engines": { @@ -936,6 +944,21 @@ "@floating-ui/utils": "^0.2.10" } }, + "node_modules/@floating-ui/react": { + "version": "0.27.15", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.15.tgz", + "integrity": "sha512-0LGxhBi3BB1DwuSNQAmuaSuertFzNAerlMdPbotjTVnvPtdOs7CkrHLaev5NIXemhzDXNC0tFzuseut7cWA5mw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.5", + "@floating-ui/utils": "^0.2.10", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=17.0.0", + "react-dom": ">=17.0.0" + } + }, "node_modules/@floating-ui/react-dom": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.5.tgz", @@ -1512,6 +1535,43 @@ } } }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.14.tgz", + "integrity": "sha512-ODz16+1iIbGUfFEfKx2HTPKizg2MN39uIOV8MXeHnmdd3i/N9Wt7vU46wbHsqA0xoaQyXVcs0KIlBdOA2Y95bw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.7", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popper": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz", @@ -1689,6 +1749,29 @@ } } }, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.7.tgz", + "integrity": "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-slot": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", @@ -1920,6 +2003,12 @@ "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", "license": "MIT" }, + "node_modules/@remirror/core-constants": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz", + "integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==", + "license": "MIT" + }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.27", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", @@ -2449,6 +2538,438 @@ "vite": "^5.2.0 || ^6 || ^7" } }, + "node_modules/@tiptap/core": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.1.0.tgz", + "integrity": "sha512-GDxoCrA+ggdzhUcelcWWVsMcmoOYXWmpjIviYXZTyHR/fds8G/mNjG0ZpFqXNmFnZ7Rs16bAsSX2tjDZ9MyTFg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/pm": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-blockquote": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.1.0.tgz", + "integrity": "sha512-BRhtu2p/EDU9L0uxTcdk9EBUVOI098F+vUbR4G8qiuVzAb7xbYS5d0h0SaynlL/JMi/VjiLHl7qA/iWBlYpylQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-bold": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.1.0.tgz", + "integrity": "sha512-wHiIR1u8QNBG30Ty0ZL34uKli7+nU4ArU5f/GN3BbhAD/gxQj13eo+TqLw1LjXd1yTzlW/EC4WNSPVy1qxChOg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-bubble-menu": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.1.0.tgz", + "integrity": "sha512-nuJTNL3OXskObeXElHMqeU9LIWBgfSIudcBMfm0Elj3/2orjd1Z3nLmoloO6zGPmZkpRMjQnTe41PvAGIMibOw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.1.0", + "@tiptap/pm": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-bullet-list": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-3.1.0.tgz", + "integrity": "sha512-lSuj0T/c/lAI01sgOdDUmFmnxItIC2WQHxzg16KOoDCzW/PtWBc6pNmCSexmqqGoTg9xNWytPWvKapZ/GCwhiQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-code": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.1.0.tgz", + "integrity": "sha512-GESYNG11tOm41DH3zhPuWaQU2slK37aC28erkZ1DvUNKlKMhJd+DzbFVNyWqBB2IyeHpgl0eLqZAYB4QApKO1A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-code-block": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-3.1.0.tgz", + "integrity": "sha512-4sVF9ZaHgfkNZJXduGecNzluLfpLdsYW80bVoFKKm2u7itlh2TnhwJZTSSU8h8spR1kFWYu/HOwOYmghKq6dMg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.1.0", + "@tiptap/pm": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-document": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.1.0.tgz", + "integrity": "sha512-n2X4ZeBsC2pORR1JXfyIFElJvAcQ0kAKqcblZlXzdewsZTS1GNd7NxFXTvuku1P2Op7CpP4X/lx8P7qSzUMFbA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-dropcursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-3.1.0.tgz", + "integrity": "sha512-zXyjLLcEYFl0pYQtSe12EKjByxS0qnycZhccpgQ7ePCusoDZTTyw4yE5pMxah5gkWK8N+qqynP+2oFcwcIWSLg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extensions": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-floating-menu": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.1.0.tgz", + "integrity": "sha512-dNhRw3gH9VHqaaSEZ5y7n8k5Ot1cH6jzTpXrKOFt0EhrwV+4P+knTHsvKe33AumpukailMpuSGhDr2/RQQCRTQ==", + "license": "MIT", + "optional": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@floating-ui/dom": "^1.0.0", + "@tiptap/core": "^3.1.0", + "@tiptap/pm": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-gapcursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-3.1.0.tgz", + "integrity": "sha512-9cm1ngE1SY26hCw/nzDNmWkyeZYRfidLamOuym7sg15pWj8BifTNuByrnK6fpQVSJWneV1y0npDj8WLpQ+t3CA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extensions": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-hard-break": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-3.1.0.tgz", + "integrity": "sha512-/4Ax5jX5l7mNd0XE93JNXSa1fWpsyqdSsM465XEsrvekoauaucuCgbWSP4qQ4v6eGBJpmI8o6aZFbQfOVDzVIQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-heading": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.1.0.tgz", + "integrity": "sha512-GQjuwGeb5PIbAEJ4ZdTly9B2emdrkLiVVXZDWjsWX2PXGL/k+ZK8rP+/+NNYI3fLw0+DAZENu2pNh7F9NaiWlg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-horizontal-rule": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.1.0.tgz", + "integrity": "sha512-EjYW72H3YAQ/yuvoMz5YtrChVesrgQ1UNB/6WynEg+frvVsfGUcNv6B9zkRT7b+XEnOVzXUW8rNlSlkrWFiSbQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.1.0", + "@tiptap/pm": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-italic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.1.0.tgz", + "integrity": "sha512-hsHNhnW5cJp/urTPIjG1C83Vov+gLFaaCsw3/Tdon9/uwAB5sLQ0Ig0iCEsKNh0KpckUnUmRjsPri5q5va7NLg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-link": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.1.0.tgz", + "integrity": "sha512-JRx3ZBnNqelbX+dBb2y2bSkjFqCLkLwZfjf55LHH4mQUFiPj7zUr6luXp9Ppq0WAFJEKXf+8tQQJrR+3eFUNlg==", + "license": "MIT", + "dependencies": { + "linkifyjs": "^4.3.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.1.0", + "@tiptap/pm": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-list": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.1.0.tgz", + "integrity": "sha512-6s0LjLzo01VojmUyohZcWiMi4njhYT76P+ESXL+3WIhHWKKVc0zNTMIWLE6Eu08wL+PoAwN2UufECNM7ZRxqkA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.1.0", + "@tiptap/pm": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-list-item": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-3.1.0.tgz", + "integrity": "sha512-bI8v+qnlrCGmU41j19W02NpNH3jPf3qzX7tw/LmlM8uVinvjlguZzbNSWzpUFOiscEjoUcuqzGr+Cwa2CaBrQw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-list-keymap": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-keymap/-/extension-list-keymap-3.1.0.tgz", + "integrity": "sha512-te50GvzfAaTV+SPR9iH/NGv/nDMaAKhYhr2m0XhuDaVmjgNIkWTKcTCxWt/9eljVJskFMvTHWXV3Tf/48basRg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-ordered-list": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-3.1.0.tgz", + "integrity": "sha512-bK85PC89/sUyGM3BL0dey8rGBkuDRYA2ynMGa/p+JG0Esqb0o5aKtNACTUKTYOdrDJw5kxNVE4BPzCkqO9/rsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/extension-list": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-paragraph": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.1.0.tgz", + "integrity": "sha512-UR0FUc38IsGkfQBHhSJ5V8UGJ4juZZqnn33BzrW1L7elhlVVUM3greBXxa7vdMFBE/IcjpvOM414vJRZoBgvzw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-strike": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.1.0.tgz", + "integrity": "sha512-7DzMXM5NrtTC3uVcjYgImNuXKMXonPZXwf0Q+No/sKqxtU+yXjusjVMmZqNLbzvtAFKghO0GDJGD4RxBNX9FgQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-text": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.1.0.tgz", + "integrity": "sha512-BW1FEG4upSfhqBpBiPdEi8IMMJDmu0ThvZWYF385WVveQ5/jFK98RS2Kz7qt82jVvw2oyhOUL4Yy63T0Bh6W1w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.1.0" + } + }, + "node_modules/@tiptap/extension-underline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.1.0.tgz", + "integrity": "sha512-M/gvRBleLzKeakcy62hWLsdUPE0TncuymwxvfSk8pY0L646vB1yQthH2x7b068mK8VmuNviPURMO35BAZYTYaA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.1.0" + } + }, + "node_modules/@tiptap/extensions": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.1.0.tgz", + "integrity": "sha512-b8mE6KA9CeyfhMOZPS+I4+Qp+aW6bNI/2mTRpDy0/WHM0XHZSh9/JOXCAuGzbz27Lcz9gp4FWwcpOICE39LPuQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.1.0", + "@tiptap/pm": "^3.1.0" + } + }, + "node_modules/@tiptap/pm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.1.0.tgz", + "integrity": "sha512-9Pjr+bC89/ATSl5J0UMVrr50TML3B5viDoMMpksgkSrnQSJyuGGfCc8DHd0TKydxucMcjVG/oq+evyCW9xXRRQ==", + "license": "MIT", + "dependencies": { + "prosemirror-changeset": "^2.3.0", + "prosemirror-collab": "^1.3.1", + "prosemirror-commands": "^1.6.2", + "prosemirror-dropcursor": "^1.8.1", + "prosemirror-gapcursor": "^1.3.2", + "prosemirror-history": "^1.4.1", + "prosemirror-inputrules": "^1.4.0", + "prosemirror-keymap": "^1.2.2", + "prosemirror-markdown": "^1.13.1", + "prosemirror-menu": "^1.2.4", + "prosemirror-model": "^1.24.1", + "prosemirror-schema-basic": "^1.2.3", + "prosemirror-schema-list": "^1.5.0", + "prosemirror-state": "^1.4.3", + "prosemirror-tables": "^1.6.4", + "prosemirror-trailing-node": "^3.0.0", + "prosemirror-transform": "^1.10.2", + "prosemirror-view": "^1.38.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, + "node_modules/@tiptap/react": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-3.1.0.tgz", + "integrity": "sha512-JjcdnzaMpmE0XcqMKBztscUoranbeJ+GXP9TkdDjJSMgZ5pKn/knFTEr5n0HtpWcBl8QnSDzrk1/B7ULulXpHQ==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "fast-deep-equal": "^3.1.3", + "use-sync-external-store": "^1.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "optionalDependencies": { + "@tiptap/extension-bubble-menu": "^3.1.0", + "@tiptap/extension-floating-menu": "^3.1.0" + }, + "peerDependencies": { + "@tiptap/core": "^3.1.0", + "@tiptap/pm": "^3.1.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tiptap/starter-kit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-3.1.0.tgz", + "integrity": "sha512-L+9WfA+XO4mwq4b0lEUr540q+jIENhZiVSNhOYdWlRyan+HCV60BkC8E/nBuqCk6tbM1jEqFQjVBqJWwjBsalQ==", + "license": "MIT", + "dependencies": { + "@tiptap/core": "^3.1.0", + "@tiptap/extension-blockquote": "^3.1.0", + "@tiptap/extension-bold": "^3.1.0", + "@tiptap/extension-bullet-list": "^3.1.0", + "@tiptap/extension-code": "^3.1.0", + "@tiptap/extension-code-block": "^3.1.0", + "@tiptap/extension-document": "^3.1.0", + "@tiptap/extension-dropcursor": "^3.1.0", + "@tiptap/extension-gapcursor": "^3.1.0", + "@tiptap/extension-hard-break": "^3.1.0", + "@tiptap/extension-heading": "^3.1.0", + "@tiptap/extension-horizontal-rule": "^3.1.0", + "@tiptap/extension-italic": "^3.1.0", + "@tiptap/extension-link": "^3.1.0", + "@tiptap/extension-list": "^3.1.0", + "@tiptap/extension-list-item": "^3.1.0", + "@tiptap/extension-list-keymap": "^3.1.0", + "@tiptap/extension-ordered-list": "^3.1.0", + "@tiptap/extension-paragraph": "^3.1.0", + "@tiptap/extension-strike": "^3.1.0", + "@tiptap/extension-text": "^3.1.0", + "@tiptap/extension-underline": "^3.1.0", + "@tiptap/extensions": "^3.1.0", + "@tiptap/pm": "^3.1.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -2514,10 +3035,32 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "license": "MIT" + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "license": "MIT" + }, "node_modules/@types/node": { - "version": "22.17.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.17.0.tgz", - "integrity": "sha512-bbAKTCqX5aNVryi7qXVMi+OkB3w/OyblodicMbvE38blyAz7GxXf6XYhklokijuPwwVg9sDLKRxt0ZHXQwZVfQ==", + "version": "22.17.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.17.1.tgz", + "integrity": "sha512-y3tBaz+rjspDTylNjAX37jEC3TETEFGNJL6uQDxwF9/8GLLIjW1rvVHlynyuUKMnMr1Roq8jOv3vkopBjC4/VA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -2567,18 +3110,24 @@ "@types/react-router": "*" } }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.38.0.tgz", - "integrity": "sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.39.0.tgz", + "integrity": "sha512-bhEz6OZeUR+O/6yx9Jk6ohX6H9JSFTaiY0v9/PuKT3oGK0rn0jNplLmyFUGV+a9gfYnVNwGDwS/UkLIuXNb2Rw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.38.0", - "@typescript-eslint/type-utils": "8.38.0", - "@typescript-eslint/utils": "8.38.0", - "@typescript-eslint/visitor-keys": "8.38.0", + "@typescript-eslint/scope-manager": "8.39.0", + "@typescript-eslint/type-utils": "8.39.0", + "@typescript-eslint/utils": "8.39.0", + "@typescript-eslint/visitor-keys": "8.39.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -2592,9 +3141,9 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.38.0", + "@typescript-eslint/parser": "^8.39.0", "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { @@ -2608,16 +3157,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.38.0.tgz", - "integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.39.0.tgz", + "integrity": "sha512-g3WpVQHngx0aLXn6kfIYCZxM6rRJlWzEkVpqEFLT3SgEDsp9cpCbxxgwnE504q4H+ruSDh/VGS6nqZIDynP+vg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.38.0", - "@typescript-eslint/types": "8.38.0", - "@typescript-eslint/typescript-estree": "8.38.0", - "@typescript-eslint/visitor-keys": "8.38.0", + "@typescript-eslint/scope-manager": "8.39.0", + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/typescript-estree": "8.39.0", + "@typescript-eslint/visitor-keys": "8.39.0", "debug": "^4.3.4" }, "engines": { @@ -2629,18 +3178,18 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.38.0.tgz", - "integrity": "sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.39.0.tgz", + "integrity": "sha512-CTzJqaSq30V/Z2Og9jogzZt8lJRR5TKlAdXmWgdu4hgcC9Kww5flQ+xFvMxIBWVNdxJO7OifgdOK4PokMIWPew==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.38.0", - "@typescript-eslint/types": "^8.38.0", + "@typescript-eslint/tsconfig-utils": "^8.39.0", + "@typescript-eslint/types": "^8.39.0", "debug": "^4.3.4" }, "engines": { @@ -2651,18 +3200,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.38.0.tgz", - "integrity": "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.39.0.tgz", + "integrity": "sha512-8QOzff9UKxOh6npZQ/4FQu4mjdOCGSdO3p44ww0hk8Vu+IGbg0tB/H1LcTARRDzGCC8pDGbh2rissBuuoPgH8A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.38.0", - "@typescript-eslint/visitor-keys": "8.38.0" + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/visitor-keys": "8.39.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2673,9 +3222,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.38.0.tgz", - "integrity": "sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.39.0.tgz", + "integrity": "sha512-Fd3/QjmFV2sKmvv3Mrj8r6N8CryYiCS8Wdb/6/rgOXAWGcFuc+VkQuG28uk/4kVNVZBQuuDHEDUpo/pQ32zsIQ==", "dev": true, "license": "MIT", "engines": { @@ -2686,19 +3235,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.38.0.tgz", - "integrity": "sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.39.0.tgz", + "integrity": "sha512-6B3z0c1DXVT2vYA9+z9axjtc09rqKUPRmijD5m9iv8iQpHBRYRMBcgxSiKTZKm6FwWw1/cI4v6em35OsKCiN5Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.38.0", - "@typescript-eslint/typescript-estree": "8.38.0", - "@typescript-eslint/utils": "8.38.0", + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/typescript-estree": "8.39.0", + "@typescript-eslint/utils": "8.39.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -2711,13 +3260,13 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.38.0.tgz", - "integrity": "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.39.0.tgz", + "integrity": "sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg==", "dev": true, "license": "MIT", "engines": { @@ -2729,16 +3278,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.38.0.tgz", - "integrity": "sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.39.0.tgz", + "integrity": "sha512-ndWdiflRMvfIgQRpckQQLiB5qAKQ7w++V4LlCHwp62eym1HLB/kw7D9f2e8ytONls/jt89TEasgvb+VwnRprsw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.38.0", - "@typescript-eslint/tsconfig-utils": "8.38.0", - "@typescript-eslint/types": "8.38.0", - "@typescript-eslint/visitor-keys": "8.38.0", + "@typescript-eslint/project-service": "8.39.0", + "@typescript-eslint/tsconfig-utils": "8.39.0", + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/visitor-keys": "8.39.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -2754,7 +3303,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { @@ -2797,16 +3346,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.38.0.tgz", - "integrity": "sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.39.0.tgz", + "integrity": "sha512-4GVSvNA0Vx1Ktwvf4sFE+exxJ3QGUorQG1/A5mRfRNZtkBT2xrA/BCO2H0eALx/PnvCS6/vmYwRdDA41EoffkQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.38.0", - "@typescript-eslint/types": "8.38.0", - "@typescript-eslint/typescript-estree": "8.38.0" + "@typescript-eslint/scope-manager": "8.39.0", + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/typescript-estree": "8.39.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2817,17 +3366,17 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.38.0.tgz", - "integrity": "sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.39.0.tgz", + "integrity": "sha512-ldgiJ+VAhQCfIjeOgu8Kj5nSxds0ktPOSO9p4+0VDH2R2pLvQraaM5Oen2d7NxzMCm+Sn/vJT+mv2H5u6b/3fA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/types": "8.39.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -2919,7 +3468,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, "license": "Python-2.0" }, "node_modules/aria-hidden": { @@ -2983,9 +3531,9 @@ } }, "node_modules/browserslist": { - "version": "4.25.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", - "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "version": "4.25.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.2.tgz", + "integrity": "sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA==", "dev": true, "funding": [ { @@ -3003,8 +3551,8 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001726", - "electron-to-chromium": "^1.5.173", + "caniuse-lite": "^1.0.30001733", + "electron-to-chromium": "^1.5.199", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, @@ -3039,9 +3587,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001731", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz", - "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==", + "version": "1.0.30001734", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001734.tgz", + "integrity": "sha512-uhE1Ye5vgqju6OI71HTQqcBCZrvHugk0MjLak7Q+HfoBgoq5Bi+5YnwjP4fjDgrtYr/l8MVRBvzz9dPD4KyK0A==", "dev": true, "funding": [ { @@ -3161,6 +3709,12 @@ "node": ">=18" } }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3259,16 +3813,16 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.194", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.194.tgz", - "integrity": "sha512-SdnWJwSUot04UR51I2oPD8kuP2VI37/CADR1OHsFOUzZIvfWJBO6q11k5P/uKNyTT3cdOsnyjkrZ+DDShqYqJA==", + "version": "1.5.199", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.199.tgz", + "integrity": "sha512-3gl0S7zQd88kCAZRO/DnxtBKuhMO4h0EaQIN3YgZfV6+pW+5+bf2AdQeHNESCoaQqo/gjGVYEf2YM4O5HJQqpQ==", "dev": true, "license": "ISC" }, "node_modules/enhanced-resolve": { - "version": "5.18.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz", - "integrity": "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==", + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -3278,6 +3832,18 @@ "node": ">=10.13.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -3378,7 +3944,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -3388,20 +3953,20 @@ } }, "node_modules/eslint": { - "version": "9.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.32.0.tgz", - "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", + "version": "9.33.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.33.0.tgz", + "integrity": "sha512-TS9bTNIryDzStCpJN93aC5VRSW3uTx9sClUn4B87pwiCaJh220otoI0X8mJKr+VcPtniMdN8GKjlwgWGUv5ZKA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.0", - "@eslint/config-helpers": "^0.3.0", - "@eslint/core": "^0.15.0", + "@eslint/config-helpers": "^0.3.1", + "@eslint/core": "^0.15.2", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.32.0", - "@eslint/plugin-kit": "^0.3.4", + "@eslint/js": "9.33.0", + "@eslint/plugin-kit": "^0.3.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -3569,7 +4134,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, "license": "MIT" }, "node_modules/fast-glob": { @@ -4325,6 +4889,21 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/linkifyjs": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.2.tgz", + "integrity": "sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==", + "license": "MIT" + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -4348,6 +4927,12 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "license": "MIT" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -4388,6 +4973,23 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -4397,6 +4999,12 @@ "node": ">= 0.4" } }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "license": "MIT" + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -4567,6 +5175,12 @@ "node": ">= 0.8.0" } }, + "node_modules/orderedmap": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz", + "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==", + "license": "MIT" + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -4689,6 +5303,201 @@ "node": ">= 0.8.0" } }, + "node_modules/prosemirror-changeset": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.3.1.tgz", + "integrity": "sha512-j0kORIBm8ayJNl3zQvD1TTPHJX3g042et6y/KQhZhnPrruO8exkTgG8X+NRpj7kIyMMEx74Xb3DyMIBtO0IKkQ==", + "license": "MIT", + "dependencies": { + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-collab": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz", + "integrity": "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0" + } + }, + "node_modules/prosemirror-commands": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz", + "integrity": "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.10.2" + } + }, + "node_modules/prosemirror-dropcursor": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.2.tgz", + "integrity": "sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0", + "prosemirror-view": "^1.1.0" + } + }, + "node_modules/prosemirror-gapcursor": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.3.2.tgz", + "integrity": "sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==", + "license": "MIT", + "dependencies": { + "prosemirror-keymap": "^1.0.0", + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-view": "^1.0.0" + } + }, + "node_modules/prosemirror-history": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.4.1.tgz", + "integrity": "sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.2.2", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.31.0", + "rope-sequence": "^1.3.0" + } + }, + "node_modules/prosemirror-inputrules": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.5.0.tgz", + "integrity": "sha512-K0xJRCmt+uSw7xesnHmcn72yBGTbY45vm8gXI4LZXbx2Z0jwh5aF9xrGQgrVPu0WbyFVFF3E/o9VhJYz6SQWnA==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-keymap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz", + "integrity": "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==", + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "w3c-keyname": "^2.2.0" + } + }, + "node_modules/prosemirror-markdown": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.2.tgz", + "integrity": "sha512-FPD9rHPdA9fqzNmIIDhhnYQ6WgNoSWX9StUZ8LEKapaXU9i6XgykaHKhp6XMyXlOWetmaFgGDS/nu/w9/vUc5g==", + "license": "MIT", + "dependencies": { + "@types/markdown-it": "^14.0.0", + "markdown-it": "^14.0.0", + "prosemirror-model": "^1.25.0" + } + }, + "node_modules/prosemirror-menu": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.2.5.tgz", + "integrity": "sha512-qwXzynnpBIeg1D7BAtjOusR+81xCp53j7iWu/IargiRZqRjGIlQuu1f3jFi+ehrHhWMLoyOQTSRx/IWZJqOYtQ==", + "license": "MIT", + "dependencies": { + "crelt": "^1.0.0", + "prosemirror-commands": "^1.0.0", + "prosemirror-history": "^1.0.0", + "prosemirror-state": "^1.0.0" + } + }, + "node_modules/prosemirror-model": { + "version": "1.25.3", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.3.tgz", + "integrity": "sha512-dY2HdaNXlARknJbrManZ1WyUtos+AP97AmvqdOQtWtrrC5g4mohVX5DTi9rXNFSk09eczLq9GuNTtq3EfMeMGA==", + "license": "MIT", + "dependencies": { + "orderedmap": "^2.0.0" + } + }, + "node_modules/prosemirror-schema-basic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.4.tgz", + "integrity": "sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.25.0" + } + }, + "node_modules/prosemirror-schema-list": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz", + "integrity": "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.7.3" + } + }, + "node_modules/prosemirror-state": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.3.tgz", + "integrity": "sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.27.0" + } + }, + "node_modules/prosemirror-tables": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.7.1.tgz", + "integrity": "sha512-eRQ97Bf+i9Eby99QbyAiyov43iOKgWa7QCGly+lrDt7efZ1v8NWolhXiB43hSDGIXT1UXgbs4KJN3a06FGpr1Q==", + "license": "MIT", + "dependencies": { + "prosemirror-keymap": "^1.2.2", + "prosemirror-model": "^1.25.0", + "prosemirror-state": "^1.4.3", + "prosemirror-transform": "^1.10.3", + "prosemirror-view": "^1.39.1" + } + }, + "node_modules/prosemirror-trailing-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-3.0.0.tgz", + "integrity": "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==", + "license": "MIT", + "dependencies": { + "@remirror/core-constants": "3.0.0", + "escape-string-regexp": "^4.0.0" + }, + "peerDependencies": { + "prosemirror-model": "^1.22.1", + "prosemirror-state": "^1.4.2", + "prosemirror-view": "^1.33.8" + } + }, + "node_modules/prosemirror-transform": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.10.4.tgz", + "integrity": "sha512-pwDy22nAnGqNR1feOQKHxoFkkUtepoFAd3r2hbEDsnf4wp57kKA36hXsB3njA9FtONBEwSDnDeCiJe+ItD+ykw==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.21.0" + } + }, + "node_modules/prosemirror-view": { + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.40.1.tgz", + "integrity": "sha512-pbwUjt3G7TlsQQHDiYSupWBhJswpLVB09xXm1YiJPdkjkh9Pe7Y51XdLh5VWIZmROLY8UpUpG03lkdhm9lzIBA==", + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.20.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -4705,6 +5514,15 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -4751,6 +5569,19 @@ "react": "^18.3.1" } }, + "node_modules/react-hotkeys-hook": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-5.1.0.tgz", + "integrity": "sha512-GCNGXjBzV9buOS3REoQFmSmE4WTvBhYQ0YrAeeMZI83bhXg3dRWsLHXDutcVDdEjwJqJCxk5iewWYX5LtFUd7g==", + "license": "MIT", + "workspaces": [ + "packages/*" + ], + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/react-refresh": { "version": "0.17.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", @@ -4809,9 +5640,9 @@ } }, "node_modules/react-router": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.7.1.tgz", - "integrity": "sha512-jVKHXoWRIsD/qS6lvGveckwb862EekvapdHJN/cGmzw40KnJH5gg53ujOJ4qX6EKIK9LSBfFed/xiQ5yeXNrUA==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.8.0.tgz", + "integrity": "sha512-r15M3+LHKgM4SOapNmsH3smAizWds1vJ0Z9C4mWaKnT9/wD7+d/0jYcj6LmOvonkrO4Rgdyp4KQ/29gWN2i1eg==", "license": "MIT", "dependencies": { "cookie": "^1.0.1", @@ -4831,12 +5662,12 @@ } }, "node_modules/react-router-dom": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.7.1.tgz", - "integrity": "sha512-bavdk2BA5r3MYalGKZ01u8PGuDBloQmzpBZVhDLrOOv1N943Wq6dcM9GhB3x8b7AbqPMEezauv4PeGkAJfy7FQ==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.8.0.tgz", + "integrity": "sha512-ntInsnDVnVRdtSu6ODmTQ41cbluak/ENeTif7GBce0L6eztFg6/e1hXAysFQI8X25C8ipKmT9cClbJwxx3Kaqw==", "license": "MIT", "dependencies": { - "react-router": "7.7.1" + "react-router": "7.8.0" }, "engines": { "node": ">=20.0.0" @@ -4948,6 +5779,12 @@ "fsevents": "~2.3.2" } }, + "node_modules/rope-sequence": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz", + "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==", + "license": "MIT" + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -5065,6 +5902,12 @@ "node": ">=8" } }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "license": "MIT" + }, "node_modules/tailwind-merge": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz", @@ -5228,16 +6071,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.38.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.38.0.tgz", - "integrity": "sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.39.0.tgz", + "integrity": "sha512-lH8FvtdtzcHJCkMOKnN73LIn6SLTpoojgJqDAxPm1jCR14eWSGPX8ul/gggBdPMk/d5+u9V854vTYQ8T5jF/1Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.38.0", - "@typescript-eslint/parser": "8.38.0", - "@typescript-eslint/typescript-estree": "8.38.0", - "@typescript-eslint/utils": "8.38.0" + "@typescript-eslint/eslint-plugin": "8.39.0", + "@typescript-eslint/parser": "8.39.0", + "@typescript-eslint/typescript-estree": "8.39.0", + "@typescript-eslint/utils": "8.39.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5248,9 +6091,15 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" + }, "node_modules/undici-types": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", @@ -5451,6 +6300,12 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "license": "MIT" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 2859513..e425084 100644 --- a/package.json +++ b/package.json @@ -10,26 +10,34 @@ "preview": "vite preview" }, "dependencies": { + "@floating-ui/react": "^0.27.15", "@radix-ui/react-avatar": "^1.1.10", "@radix-ui/react-checkbox": "^1.3.2", "@radix-ui/react-collapsible": "^1.1.11", "@radix-ui/react-dialog": "^1.1.14", "@radix-ui/react-dropdown-menu": "^2.1.15", "@radix-ui/react-label": "^2.1.7", + "@radix-ui/react-popover": "^1.1.14", "@radix-ui/react-select": "^2.2.5", + "@radix-ui/react-separator": "^1.1.7", "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-tabs": "^1.1.12", "@tailwindcss/vite": "^4.1.6", + "@tiptap/pm": "^3.1.0", + "@tiptap/react": "^3.1.0", + "@tiptap/starter-kit": "^3.1.0", "axios": "^1.11.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "dotenv": "^17.2.1", "input-otp": "^1.4.2", + "lodash.throttle": "^4.1.1", "lucide-react": "^0.510.0", "moment": "^2.30.1", "next-themes": "^0.4.6", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-hotkeys-hook": "^5.1.0", "react-router": "^7.6.0", "react-router-dom": "^7.7.1", "recoil": "^0.7.7", diff --git a/public/user.svg b/public/user.svg new file mode 100644 index 0000000..ba0b032 --- /dev/null +++ b/public/user.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/dash-navbar.tsx b/src/components/dash-navbar.tsx index ee4f57f..568c6eb 100644 --- a/src/components/dash-navbar.tsx +++ b/src/components/dash-navbar.tsx @@ -1,4 +1,4 @@ -import { BookOpen, User } from "lucide-react"; +import { BookOpen } from "lucide-react"; import { Button } from "@/components/ui/button"; import { DropdownMenu, @@ -7,8 +7,22 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { ModeToggle } from "./mode-toggle"; +import { useAdminData } from "@/store/hooks/useAdminData"; +import { Skeleton } from "./ui/skeleton"; +import { Link } from "react-router-dom"; export const DashboardHeader = () => { + const { adminInfo, loading, error } = useAdminData(); + const userInfo = adminInfo?.isUserExist; + + if (loading) + return ( +
+ +
+ ); + + if (error) return
Error loading admin data.
; return (
{/* Student Portal Title */} @@ -18,24 +32,30 @@ export const DashboardHeader = () => { {/* Header Actions */} -
+
- + - John Dow - Profile + {userInfo.firstname} + + Profile + Settings Logout diff --git a/src/components/dashboard-welcome.tsx b/src/components/dashboard-welcome.tsx index 49d7304..569a6b6 100644 --- a/src/components/dashboard-welcome.tsx +++ b/src/components/dashboard-welcome.tsx @@ -22,7 +22,7 @@ const DashboardWelcome = () => {
diff --git a/src/components/mode-toggle.tsx b/src/components/mode-toggle.tsx index 199d09f..6f30c7e 100644 --- a/src/components/mode-toggle.tsx +++ b/src/components/mode-toggle.tsx @@ -12,9 +12,10 @@ import { useTheme } from "@/components/theme-provider"; export function ModeToggle() { const { setTheme } = useTheme(); + return ( - +
+
+ + InputHandler(e, setCreateAnnouncement)} + name="description" + placeholder="Enter Announcement Description" + /> +
+
+ + InputHandler(e, setCreateAnnouncement)} + name="audience" + placeholder="Enter Announcement audience" + /> +
+
+ + +
+
+ + +
+
+ + InputHandler(e, setCreateAnnouncement)} + name="published" + placeholder="Enter Announcement published" + /> +
+ +
+ + +
+ + ); +}; + +export default CreateAnnouncement; diff --git a/src/features/announcement/edit-announcement.tsx b/src/features/announcement/edit-announcement.tsx new file mode 100644 index 0000000..7a26438 --- /dev/null +++ b/src/features/announcement/edit-announcement.tsx @@ -0,0 +1,187 @@ +"use client"; + +import UseModel from "@/components/models/useModel"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { FormateDate, InputHandler, SelectHandler } from "@/lib/utils"; +import axios from "axios"; +import { Edit } from "lucide-react"; +import { useState } from "react"; +import { toast } from "sonner"; +import type { AnnouncementData, EditAnnouncementData } from "@/types"; +import { Announcement } from "../../store/atoms/announcement/announcement"; +import { useRecoilRefresher_UNSTABLE } from "recoil"; + +const base_api = import.meta.env.VITE_SERVER_BASE_URL; + +const EditAnnouncement = ({ announcementInfo }: EditAnnouncementData) => { + const refreshAnnouncement = useRecoilRefresher_UNSTABLE(Announcement); + + const [editingAnnouncement, setEditingAnnouncement] = + useState(null); + const [isUpdateDialogOpen, setIsUpdateDialogOpen] = useState(false); + const [isLoading, setIsLoading] = useState(false); + + const handleUpdateSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setIsLoading(true); + + try { + const response = await axios.put( + `${base_api}/api/v1/update-announcement/${editingAnnouncement?.id}`, + editingAnnouncement, + { withCredentials: true } + ); + if (response.status === 200) { + toast.success("program updated successfully"); + setIsLoading(false); + refreshAnnouncement(); + setIsUpdateDialogOpen(false); + } + } catch (error: any) { + console.error(error?.message); + toast.error("Failed to update program"); + setIsUpdateDialogOpen(false); + setIsLoading(false); + } + }; + + // Handle edit button click + const handleEditClick = (announcementInfo: AnnouncementData) => { + setEditingAnnouncement({ ...announcementInfo }); + setIsUpdateDialogOpen(true); + }; + + return ( + handleEditClick(announcementInfo)} + > + + Update + + } + > + {editingAnnouncement && ( + <> +
+ + InputHandler(e, setEditingAnnouncement)} + name="title" + placeholder="Enter Announcement Title" + /> +
+
+ + InputHandler(e, setEditingAnnouncement)} + name="description" + placeholder="Enter Announcement Description" + /> +
+
+ + InputHandler(e, setEditingAnnouncement)} + name="audience" + placeholder="Enter Announcement audience" + /> +
+
+ + +
+
+ + +
+
+ + InputHandler(e, setEditingAnnouncement)} + name="published" + placeholder="Enter Announcement published" + /> +
+ +
+ + +
+ + )} +
+ ); +}; + +export default EditAnnouncement; diff --git a/src/features/announcement/index.tsx b/src/features/announcement/index.tsx new file mode 100644 index 0000000..ac86f54 --- /dev/null +++ b/src/features/announcement/index.tsx @@ -0,0 +1,186 @@ +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Skeleton } from "@/components/ui/skeleton"; +import { useAnnouncementData } from "@/store/hooks/announcement/announcement"; +import type { AnnouncementData } from "@/types"; +import { Eye, Search, Trash } from "lucide-react"; +import EditAnnouncement from "./edit-announcement"; +import { FormateDate } from "@/lib/utils"; +import { ConfirmDialog } from "@/components/confirm-dialog"; +import { useRecoilRefresher_UNSTABLE } from "recoil"; +import { Announcement as announcement } from "@/store/atoms/announcement/announcement"; +import { useState } from "react"; +import axios from "axios"; +import { toast } from "sonner"; + +const base_api = import.meta.env.VITE_SERVER_BASE_URL; + +const Announcement = () => { + const { announcementInfo, error, loading } = useAnnouncementData(); + + const refreshAnnouncement = useRecoilRefresher_UNSTABLE(announcement); + const [isLoading, setIsLoading] = useState(false); + + // handle Delete + + async function handleDelete(announcement: AnnouncementData) { + try { + const response = await axios.delete( + `${base_api}/api/v1/delete-announcement/${announcement?.id}`, + { + withCredentials: true, + } + ); + + if (response.status === 200) { + toast.success("Announcement deleted !!"); + setIsLoading(false); + refreshAnnouncement(); + } + } catch (error) { + console.log(error); + setIsLoading(false); + } + } + + if (loading) { + return ( +
+ +
+ ); + } + + if (error) { + return
error
; + } + + const announcementData: AnnouncementData[] = + announcementInfo?.announcementData; + + return ( + + + +

All Announcements

+
+
+
+ + +
+ +
+
+ +
+ {announcementData?.length > 0 ? ( + announcementData.map((announcement, index) => ( + + +
+
+
+

+ {announcement.title} +

+
+ + {announcement.category} + + + {announcement.priority} + + {announcement.status} +
+
+

+ {announcement.description} +

+
+
+ Category:{" "} + {announcement.category} +
+
+ Audience:{" "} + {announcement.audience} +
+ {/*
+ createdBy:{" "} + {announcement.} +
*/} +
+ Published:{" "} + {FormateDate(announcement.published)} +
+
+
+
+ + + handleDelete(announcement)} + destructive + trigger={ + + } + /> +
+
+
+
+ )) + ) : ( +
+ No Announcement Data available to show +
+ )} +
+
+
+ ); +}; + +export default Announcement; diff --git a/src/features/events/create-events.tsx b/src/features/events/create-events.tsx new file mode 100644 index 0000000..4377036 --- /dev/null +++ b/src/features/events/create-events.tsx @@ -0,0 +1,196 @@ +"use client"; + +import UseModel from "@/components/models/useModel"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { InputHandler, SelectHandler } from "@/lib/utils"; +import axios from "axios"; +import { Plus } from "lucide-react"; +import { useState } from "react"; +import { toast } from "sonner"; +import type { EventData } from "@/types"; +import { Events } from "../../store/atoms/events/event"; +import { useRecoilRefresher_UNSTABLE } from "recoil"; + +const base_api = import.meta.env.VITE_SERVER_BASE_URL; + +const CreateEvents = () => { + const refreshEvents = useRecoilRefresher_UNSTABLE(Events); + const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false); + const [isLoading, setIsLoading] = useState(false); + + const [createEvents, setCreateEvents] = useState({ + title: "", + description: "", + category: "", + status: "", + date: "", + location: "", + organizer: "", + time: "", + }); + + // Create Event submit + const handleCreateSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setIsLoading(true); + + try { + const response = await axios.post( + `${base_api}/api/v1/create-event`, + createEvents, + { withCredentials: true } + ); + if (response.status === 200) { + toast.success("Event created successfully"); + setCreateEvents({ + title: "", + description: "", + category: "", + status: "", + date: "", + location: "", + organizer: "", + time: "", + }); + refreshEvents(); + setIsCreateDialogOpen(false); + setIsLoading(false); + } + } catch (error: any) { + console.error(error?.message); + toast.error("Failed to create event"); + setIsCreateDialogOpen(false); + setIsLoading(false); + } + }; + + return ( + + + Add new + + } + > +
+ + InputHandler(e, setCreateEvents)} + name="title" + placeholder="Enter Event Title" + /> +
+
+ + InputHandler(e, setCreateEvents)} + name="description" + placeholder="Enter Event Description" + /> +
+
+ + +
+
+ + InputHandler(e, setCreateEvents)} + name="date" + placeholder="Enter Event date" + /> +
+
+ + InputHandler(e, setCreateEvents)} + name="time" + placeholder="Enter Event time" + /> +
+
+ + InputHandler(e, setCreateEvents)} + name="location" + placeholder="Enter Event location" + /> +
+
+ + InputHandler(e, setCreateEvents)} + name="organizer" + placeholder="Enter Event organizer" + /> +
+
+ + +
+
+ ); +}; + +export default CreateEvents; diff --git a/src/features/events/edit-events.tsx b/src/features/events/edit-events.tsx new file mode 100644 index 0000000..8dfe6b7 --- /dev/null +++ b/src/features/events/edit-events.tsx @@ -0,0 +1,191 @@ +"use client"; + +import UseModel from "@/components/models/useModel"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { FormateDate, InputHandler, SelectHandler } from "@/lib/utils"; +import axios from "axios"; +import { Edit } from "lucide-react"; +import { useState } from "react"; +import { toast } from "sonner"; +import type { EditEventData, EventData } from "@/types"; +import { Events } from "../../store/atoms/events/event"; +import { useRecoilRefresher_UNSTABLE } from "recoil"; + +const base_api = import.meta.env.VITE_SERVER_BASE_URL; + +const EditEvents = ({ eventInfo }: EditEventData) => { + const refreshEvents = useRecoilRefresher_UNSTABLE(Events); + + const [editingEvents, setEditingEvents] = useState(null); + const [isUpdateDialogOpen, setIsUpdateDialogOpen] = useState(false); + const [isLoading, setIsLoading] = useState(false); + + const handleUpdateSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setIsLoading(true); + + try { + const response = await axios.put( + `${base_api}/api/v1/update-event/${editingEvents?.id}`, + editingEvents, + { withCredentials: true } + ); + if (response.status === 200) { + toast.success("Event updated successfully"); + setIsLoading(false); + refreshEvents(); + setIsUpdateDialogOpen(false); + } + } catch (error: any) { + console.error(error?.message); + toast.error("Failed to update Event"); + setIsUpdateDialogOpen(false); + setIsLoading(false); + } + }; + + // Handle edit button click + const handleEditClick = (eventInfo: EventData) => { + setEditingEvents({ ...eventInfo }); + setIsUpdateDialogOpen(true); + }; + + return ( + handleEditClick(eventInfo)} + > + + Update + + } + > + {editingEvents && ( + <> +
+ + InputHandler(e, setEditingEvents)} + name="title" + placeholder="Enter Event Title" + /> +
+
+ + InputHandler(e, setEditingEvents)} + name="description" + placeholder="Enter Event Description" + /> +
+
+ + +
+
+ + InputHandler(e, setEditingEvents)} + name="date" + placeholder="Enter Event date" + /> +
+
+ + InputHandler(e, setEditingEvents)} + name="time" + placeholder="Enter Event time" + /> +
+
+ + InputHandler(e, setEditingEvents)} + name="location" + placeholder="Enter Event location" + /> +
+
+ + InputHandler(e, setEditingEvents)} + name="organizer" + placeholder="Enter Event organizer" + /> +
+
+ + +
+ + )} +
+ ); +}; + +export default EditEvents; diff --git a/src/features/events/index.tsx b/src/features/events/index.tsx new file mode 100644 index 0000000..837e3da --- /dev/null +++ b/src/features/events/index.tsx @@ -0,0 +1,166 @@ +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Skeleton } from "@/components/ui/skeleton"; +import { FormateDate } from "@/lib/utils"; +import { useEventData } from "@/store/hooks/events/event"; +import type { EventData } from "@/types"; +import { Calendar, Clock, Eye, MapPin, Search, Trash } from "lucide-react"; +import EditEvents from "./edit-events"; +import { ConfirmDialog } from "@/components/confirm-dialog"; +import { useRecoilRefresher_UNSTABLE } from "recoil"; +import { Events } from "../../store/atoms/events/event"; +import { useState } from "react"; +import { toast } from "sonner"; +import axios from "axios"; + +const base_api = import.meta.env.VITE_SERVER_BASE_URL; + +const EventsData = () => { + const { EventInfo, error, loading } = useEventData(); + + const refreshEvent = useRecoilRefresher_UNSTABLE(Events); + const [isLoading, setIsLoading] = useState(false); + + // handle Delete + + async function handleDelete(event: EventData) { + try { + const response = await axios.delete( + `${base_api}/api/v1/delete-event/${event?.id}`, + { + withCredentials: true, + } + ); + + if (response.status === 200) { + toast.success("Event deleted !!"); + setIsLoading(false); + refreshEvent(); + } + } catch (error) { + console.log(error); + setIsLoading(false); + } + } + + if (loading) { + return ( +
+ +
+ ); + } + if (error) { + return
error
; + } + + const eventData: EventData[] = EventInfo?.allEvents; + + return ( + + +
+ All Events +
+
+ + +
+ +
+
+
+ +
+ {eventData?.length > 0 ? ( + eventData.map((event, index) => ( + + +
+
+
+

{event.title}

+ {event.category} + {event.status} +
+

+ {event.description} +

+
+
+ + {FormateDate(event.date)} +
+
+ + {event.location} +
+
+ + {event.time} +
+
Organizer: {event.organizer}
+
+
+
+ + + handleDelete(event)} + destructive + trigger={ + + } + /> +
+
+
+
+ )) + ) : ( +
+ No Event Data available to show +
+ )} +
+
+
+ ); +}; + +export default EventsData; diff --git a/src/pages/dashboard/academic.tsx b/src/pages/dashboard/academic.tsx index b7bd9ff..ac17962 100644 --- a/src/pages/dashboard/academic.tsx +++ b/src/pages/dashboard/academic.tsx @@ -1,10 +1,10 @@ import { Card, CardContent, CardHeader } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import AcademinCoursesTab from "@/components/academic/courses"; +import AcademinCoursesTab from "@/features/academic/courses"; import ErrorBoundary from "@/components/error-boundary"; -import AcademicProgramsTab from "@/components/academic/programs"; -import AcademicDepartmentTab from "@/components/academic/departments"; -import AcademicSemesterTab from "@/components/academic/semester"; +import AcademicProgramsTab from "@/features/academic/programs"; +import AcademicDepartmentTab from "@/features/academic/departments"; +import AcademicSemesterTab from "@/features/academic/semester"; const Academic = () => { return ( diff --git a/src/pages/dashboard/announcement.tsx b/src/pages/dashboard/announcement.tsx index 9447170..cb08b7b 100644 --- a/src/pages/dashboard/announcement.tsx +++ b/src/pages/dashboard/announcement.tsx @@ -1,72 +1,9 @@ -import { useState } from "react"; -import { Plus, Search, Eye, Edit, Trash2 } from "lucide-react"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Badge } from "@/components/ui/badge"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; - -interface AnnouncementsData { - title: string; - description: string; - category: string; - audience: string; - author: string; - published: string; - views: number; - priority: string; - status: string; -} - -const announcementsData: AnnouncementsData[] = [ - { - title: "Course Registration Opens for Spring 2025", - description: - "Spring 2025 semester will begin on December 10th, 2024. Students are advised to meet with their academic advisors before registration.", - category: "Academic", - audience: "Students", - author: "Academic Office", - published: "2024-11-15", - views: 19523, - priority: "high", - status: "published", - }, - { - title: "Library Hours Extended During Exam Period", - description: - "The university library will extend its operating hours during the final exam period. New hours: Monday-Sunday 7:00 AM - 2:00 AM.", - category: "Facilities", - audience: "All", - author: "Library Services", - published: "2024-11-10", - views: 48623, - priority: "high", - status: "published", - }, - { - title: "Guest Lecture: Future of Artificial Intelligence", - description: - "Join us for an exciting guest lecture by Dr. Sarah Johnson on 'The Future of Artificial Intelligence in Education' on November 25th at 3:00 PM in the main auditorium.", - category: "Events", - audience: "Faculty & Students", - author: "Computer Science Department", - published: "2024-11-05", - views: 15523, - priority: "medium", - status: "published", - }, -]; +import { Eye } from "lucide-react"; +import { Card, CardContent } from "@/components/ui/card"; +import AnnouncementData from "../../features/announcement"; +import CreateAnnouncement from "@/features/announcement/create-announcement"; const Announcement = () => { - const [searchTerm, setSearchTerm] = useState(""); - const [selectedCategory, setSelectedCategory] = useState("all"); - return (
{/* Header */} @@ -80,10 +17,7 @@ const Announcement = () => { Create and manage university announcements

- +
@@ -146,111 +80,7 @@ const Announcement = () => {
{/* Announcements List */} - - - -

All Announcements

-
-
-
- - setSearchTerm(e.target.value)} - className="pl-10 w-full md:w-64" - /> -
- -
-
- -
- {announcementsData.map((announcement, index) => ( - - -
-
-
-

- {announcement.title} -

-
- - {announcement.category} - - - {announcement.priority} - - {announcement.status} -
-
-

- {announcement.description} -

-
-
- Category:{" "} - {announcement.category} -
-
- Audience:{" "} - {announcement.audience} -
-
- Author:{" "} - {announcement.author} -
-
- Published:{" "} - {announcement.published} -
-
- - {announcement.views} -
-
-
-
- - - -
-
-
-
- ))} -
-
-
+ ); }; diff --git a/src/pages/dashboard/content-editor.tsx b/src/pages/dashboard/content-editor.tsx new file mode 100644 index 0000000..173734a --- /dev/null +++ b/src/pages/dashboard/content-editor.tsx @@ -0,0 +1,3 @@ +export const AdminContentEditorPage = () => { + return
hi
; +}; diff --git a/src/pages/dashboard/content-management.tsx b/src/pages/dashboard/content-management.tsx index 161ec33..80b87ca 100644 --- a/src/pages/dashboard/content-management.tsx +++ b/src/pages/dashboard/content-management.tsx @@ -10,6 +10,7 @@ import { TableHeader, TableRow, } from "@/components/ui/table"; +import { Link } from "react-router-dom"; interface ContentData { title: string; @@ -73,9 +74,11 @@ const ContentManagement = () => { Monday, June 9, 2025

- diff --git a/src/pages/dashboard/events.tsx b/src/pages/dashboard/events.tsx index 40a1abe..9407083 100644 --- a/src/pages/dashboard/events.tsx +++ b/src/pages/dashboard/events.tsx @@ -1,77 +1,9 @@ -import { useState } from "react"; -import { - Plus, - Search, - Calendar, - MapPin, - Clock, - Edit, - Eye, - Trash2, -} from "lucide-react"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Badge } from "@/components/ui/badge"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; - -interface EventsData { - title: string; - description: string; - date: string; - location: string; - time: string; - organizer: string; - category: string; - status: string; -} - -const eventsData: EventsData[] = [ - { - title: "Orientation Week 2024", - description: - "Welcome new students to the university with a week-long orientation program including campus tours, academic sessions, and social activities.", - date: "2024-09-02", - location: "Main Campus", - time: "09:00", - organizer: "Student Services", - category: "academic", - status: "upcoming", - }, - { - title: "Career Fair 2024", - description: - "Annual career fair featuring top employers from various industries. Students can network, submit resumes, and explore job and internship opportunities.", - date: "2024-09-02", - location: "Main Campus", - time: "09:00", - organizer: "Student Services", - category: "academic", - status: "upcoming", - }, - { - title: "Alumni Networking Event", - description: - "Connect with successful alumni from various graduating classes and industries. Great opportunity for mentorship and career guidance.", - date: "2024-09-02", - location: "Main Campus", - time: "09:00", - organizer: "Student Services", - category: "academic", - status: "upcoming", - }, -]; +import { Calendar, Clock } from "lucide-react"; +import { Card, CardContent } from "@/components/ui/card"; +import EventsData from "@/features/events"; +import CreateEvents from "@/features/events/create-events"; const Events = () => { - const [searchTerm, setSearchTerm] = useState(""); - const [selectedCategory, setSelectedCategory] = useState("all"); - return (
{/* Header */} @@ -86,10 +18,7 @@ const Events = () => { Create and manage university events

- + @@ -154,89 +83,7 @@ const Events = () => { {/* Events List */} - - -
- All Events -
-
- - setSearchTerm(e.target.value)} - className="pl-10 w-full md:w-64" - /> -
- -
-
-
- -
- {eventsData.map((event, index) => ( - - -
-
-
-

{event.title}

- {event.category} - {event.status} -
-

- {event.description} -

-
-
- - {event.date} -
-
- - {event.location} -
-
- - {event.time} -
-
Organizer: {event.organizer}
-
-
-
- - - -
-
-
-
- ))} -
-
-
+ ); }; diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 8e8f97f..bb0052f 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -18,6 +18,7 @@ import NotFound from "@/pages/not-found"; import { Routes, Route } from "react-router-dom"; import { DashboardProtectedRoute } from "@/components/route-protection/dashboard-protected-route"; import { AuthProtectedRoute } from "@/components/route-protection/auth-protected-route"; +import { AdminContentEditorPage } from "@/pages/dashboard/content-editor"; const Paths = () => { return ( @@ -61,6 +62,7 @@ const Paths = () => { } /> } /> } /> + } /> {/* Not Found */} diff --git a/src/store/atoms/announcement/announcement.ts b/src/store/atoms/announcement/announcement.ts new file mode 100644 index 0000000..e66d65c --- /dev/null +++ b/src/store/atoms/announcement/announcement.ts @@ -0,0 +1,7 @@ +import { atom } from "recoil"; +import { announcementSelector } from "../../selectors/announcement/announcement"; + +export const Announcement = atom({ + key: "AnnouncementAtom", + default: announcementSelector, +}); diff --git a/src/store/atoms/events/event.ts b/src/store/atoms/events/event.ts new file mode 100644 index 0000000..e9f8ee7 --- /dev/null +++ b/src/store/atoms/events/event.ts @@ -0,0 +1,7 @@ +import { atom } from "recoil"; +import { eventSelector } from "../../selectors/events/event"; + +export const Events = atom({ + key: "EventsAtom", + default: eventSelector, +}); diff --git a/src/store/hooks/announcement/announcement.ts b/src/store/hooks/announcement/announcement.ts new file mode 100644 index 0000000..a5784ca --- /dev/null +++ b/src/store/hooks/announcement/announcement.ts @@ -0,0 +1,20 @@ +import { useRecoilStateLoadable } from "recoil"; +import { Announcement } from "../../atoms/announcement/announcement"; + +export const useAnnouncementData = () => { + const [AnnouncementData, setAnnouncementData] = + useRecoilStateLoadable(Announcement); + + if (AnnouncementData.state === "loading") { + return { loading: true, error: false, announcementInfo: null }; + } else if (AnnouncementData.state === "hasError") { + return { loading: false, error: true, announcementInfo: null }; + } + + return { + loading: false, + error: false, + announcementInfo: AnnouncementData.contents, + setAnnouncementData, + }; +}; diff --git a/src/store/hooks/events/event.ts b/src/store/hooks/events/event.ts new file mode 100644 index 0000000..bf2d9d5 --- /dev/null +++ b/src/store/hooks/events/event.ts @@ -0,0 +1,20 @@ +import { useRecoilStateLoadable } from "recoil"; +import { Events } from "../../atoms/events/event"; + +export const useEventData = () => { + const [EventData, setEventData] = + useRecoilStateLoadable(Events); + + if (EventData.state === "loading") { + return { loading: true, error: false, EventInfo: null }; + } else if (EventData.state === "hasError") { + return { loading: false, error: true, EventInfo: null }; + } + + return { + loading: false, + error: false, + EventInfo: EventData.contents, + setEventData, + }; +}; diff --git a/src/store/selectors/admin.ts b/src/store/selectors/admin.ts index 4e4c4cd..1232e1d 100644 --- a/src/store/selectors/admin.ts +++ b/src/store/selectors/admin.ts @@ -8,24 +8,12 @@ export const adminSelector = selector({ key: "AdminSelector", get: async () => { try { - console.log( - "adminSelector - Making request to:", - `${base_api}/api/v1/about-me` - ); - const response = await axios.get(`${base_api}/api/v1/about-me`, { withCredentials: true, }); - console.log("adminSelector - Response:", response.data); return response.data; } catch (error: any) { - console.log( - "adminSelector - Error:", - error.response?.status, - error.response?.data - ); - if (error?.response?.status === 401) { return { message: "User not authenticated", diff --git a/src/store/selectors/announcement/announcement.ts b/src/store/selectors/announcement/announcement.ts new file mode 100644 index 0000000..ac80c1d --- /dev/null +++ b/src/store/selectors/announcement/announcement.ts @@ -0,0 +1,27 @@ +import axios from "axios"; +import { selector } from "recoil"; + +const base_api = import.meta.env.VITE_SERVER_BASE_URL; + +export const announcementSelector = selector({ + key: "announcementSelector", + get: async () => { + try { + const response = await axios.get(`${base_api}/api/v1/get-announcement`, { + withCredentials: true, + }); + + return response.data; + } catch (error: any) { + if (error?.response?.status === 401) { + return { + message: "User not authenticated", + isUserExist: null, + }; + } + + console.error("announcement fetch failed:", error.message); + throw error; + } + }, +}); diff --git a/src/store/selectors/events/event.ts b/src/store/selectors/events/event.ts new file mode 100644 index 0000000..32db004 --- /dev/null +++ b/src/store/selectors/events/event.ts @@ -0,0 +1,27 @@ +import axios from "axios"; +import { selector } from "recoil"; + +const base_api = import.meta.env.VITE_SERVER_BASE_URL; + +export const eventSelector = selector({ + key: "eventSelector", + get: async () => { + try { + const response = await axios.get(`${base_api}/api/v1/get-event`, { + withCredentials: true, + }); + + return response.data; + } catch (error: any) { + if (error?.response?.status === 401) { + return { + message: "User not authenticated", + isUserExist: null, + }; + } + + console.error("event fetch failed:", error.message); + throw error; + } + }, +}); diff --git a/src/types/index.d.ts b/src/types/index.d.ts index eedcaa2..e7722f2 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -10,7 +10,7 @@ export interface CourseData { enddate: string; } -export interface EditCourseProps { +export interface EditCourseData { course: CourseData; } @@ -35,7 +35,7 @@ export interface ProgramData { }; } -export interface EditProgramProps { +export interface EditProgramData { program: ProgramData; } @@ -47,7 +47,7 @@ export interface DepartmentData { established: string; } -export interface EditDepartmentProps { +export interface EditDepartmentData { departmentInfo: DepartmentData; } @@ -60,6 +60,58 @@ export interface SemesterData { status: string; } -export interface EditSemesterProps { +export interface EditSemesterData { semesterInfo: SemesterData; } + +// announcement + +export interface AnnouncementData { + id?: string; + title: string; + description: string; + category: string; + audience: string; + priority: string; + status: string; + published: string; +} + +export interface EditAnnouncementData { + announcementInfo: AnnouncementData; +} + +// events + +export interface EventData { + id?: string; + title: string; + description: string; + category: string; + date: string; + location: string; + status: string; + organizer: string; + time: string; +} + +export interface EditEventData { + eventInfo: EventData; +} + +// cms + +export interface EditorData { + title: string; + subtitle: string; + coverImage: string; + content: string; + category: string; + tags: string[]; + status: string; +} + +export interface EditorData { + onBack: () => void; + initialData?: EditorData; +}