diff --git a/package-lock.json b/package-lock.json index f8e14b3f..d449aebd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@marsidev/react-turnstile": "^1.3.1", "@novu/headless": "^2.6.6", "@novu/node": "^2.6.6", + "@novu/react": "^3.10.1", "@radix-ui/react-accordion": "^1.2.11", "@radix-ui/react-alert-dialog": "^1.1.14", "@radix-ui/react-aspect-ratio": "^1.1.7", @@ -160,6 +161,18 @@ "node": ">=6.9.0" } }, + "node_modules/@corvu/utils": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@corvu/utils/-/utils-0.4.2.tgz", + "integrity": "sha512-Ox2kYyxy7NoXdKWdHeDEjZxClwzO4SKM8plAaVwmAJPxHMqA0rLOoAsa+hBDwRLpctf+ZRnAd/ykguuJidnaTA==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.6.11" + }, + "peerDependencies": { + "solid-js": "^1.8" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", @@ -852,6 +865,24 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@internationalized/date": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.9.0.tgz", + "integrity": "sha512-yaN3brAnHRD+4KyyOsJyk49XUvj2wtbNACSqg0bz3u8t2VuzhC8Q5dfRnrSxjnnbDb+ienBnkn1TzQfE154vyg==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@internationalized/number": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/@internationalized/number/-/number-3.6.5.tgz", + "integrity": "sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -923,6 +954,43 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@kobalte/core": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/@kobalte/core/-/core-0.13.11.tgz", + "integrity": "sha512-hK7TYpdib/XDb/r/4XDBFaO9O+3ZHz4ZWryV4/3BfES+tSQVgg2IJupDnztKXB0BqbSRy/aWlHKw1SPtNPYCFQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.5.1", + "@internationalized/date": "^3.4.0", + "@internationalized/number": "^3.2.1", + "@kobalte/utils": "^0.9.1", + "@solid-primitives/props": "^3.1.8", + "@solid-primitives/resize-observer": "^2.0.26", + "solid-presence": "^0.1.8", + "solid-prevent-scroll": "^0.1.4" + }, + "peerDependencies": { + "solid-js": "^1.8.15" + } + }, + "node_modules/@kobalte/utils": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@kobalte/utils/-/utils-0.9.1.tgz", + "integrity": "sha512-eeU60A3kprIiBDAfv9gUJX1tXGLuZiKMajUfSQURAF2pk4ZoMYiqIzmrMBvzcxP39xnYttgTyQEVLwiTZnrV4w==", + "license": "MIT", + "dependencies": { + "@solid-primitives/event-listener": "^2.2.14", + "@solid-primitives/keyed": "^1.2.0", + "@solid-primitives/map": "^0.4.7", + "@solid-primitives/media": "^2.2.4", + "@solid-primitives/props": "^3.1.8", + "@solid-primitives/refs": "^1.0.5", + "@solid-primitives/utils": "^6.2.1" + }, + "peerDependencies": { + "solid-js": "^1.8.8" + } + }, "node_modules/@marsidev/react-turnstile": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@marsidev/react-turnstile/-/react-turnstile-1.3.1.tgz", @@ -933,6 +1001,70 @@ "react-dom": "^17.0.2 || ^18.0.0 || ^19.0" } }, + "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.18.0", + "resolved": "https://registry.npmjs.org/@motionone/dom/-/dom-10.18.0.tgz", + "integrity": "sha512-bKLP7E0eyO4B2UaHBBN55tnppwRnaE3KFfh3Ps9HhnAkar3Cb69kUCJY9as8LrccVYKgHA+JY5dOQqJLOPhF5A==", + "license": "MIT", + "dependencies": { + "@motionone/animation": "^10.18.0", + "@motionone/generators": "^10.18.0", + "@motionone/types": "^10.17.1", + "@motionone/utils": "^10.18.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", + "dependencies": { + "@motionone/utils": "^10.18.0", + "tslib": "^2.3.1" + } + }, + "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", + "dependencies": { + "@motionone/types": "^10.17.1", + "@motionone/utils": "^10.18.0", + "tslib": "^2.3.1" + } + }, + "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", + "dependencies": { + "@motionone/types": "^10.17.1", + "hey-listen": "^1.0.8", + "tslib": "^2.3.1" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1010,6 +1142,26 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@novu/js": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@novu/js/-/js-3.10.1.tgz", + "integrity": "sha512-ht8bwg5vPkmoNxHDbTqBMaAuNzO4bqhVpwxzbWLYUdauj2cPd3taI9yuvXYwln9C6utNe6O1UiEJECdJM8fafg==", + "license": "ISC", + "dependencies": { + "@floating-ui/dom": "^1.6.13", + "@kobalte/core": "^0.13.10", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "event-target-polyfill": "^0.0.4", + "mitt": "^3.0.1", + "partysocket": "^1.1.4", + "socket.io-client": "4.7.2", + "solid-floating-ui": "^0.3.1", + "solid-js": "^1.9.4", + "solid-motionone": "^1.0.3", + "tailwind-merge": "^2.4.0" + } + }, "node_modules/@novu/node": { "version": "2.6.6", "resolved": "https://registry.npmjs.org/@novu/node/-/node-2.6.6.tgz", @@ -1029,6 +1181,24 @@ "node": ">=10" } }, + "node_modules/@novu/react": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@novu/react/-/react-3.10.1.tgz", + "integrity": "sha512-fG76i7AzNyKWNqXIn1WyFnK7L2l1zVuaONj3tAia/iVjhnt7uNNRv6K46D0JPu34464+fK0/dOSbqqr89Tpk7w==", + "license": "ISC", + "dependencies": { + "@novu/js": "3.10.1" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, "node_modules/@novu/shared": { "version": "2.6.6", "resolved": "https://registry.npmjs.org/@novu/shared/-/shared-2.6.6.tgz", @@ -2821,6 +2991,147 @@ "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "license": "MIT" }, + "node_modules/@solid-primitives/event-listener": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@solid-primitives/event-listener/-/event-listener-2.4.3.tgz", + "integrity": "sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.3.2" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/keyed": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@solid-primitives/keyed/-/keyed-1.5.2.tgz", + "integrity": "sha512-BgoEdqPw48URnI+L5sZIHdF4ua4Las1eWEBBPaoSFs42kkhnHue+rwCBPL2Z9ebOyQ75sUhUfOETdJfmv0D6Kg==", + "license": "MIT", + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/map": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/@solid-primitives/map/-/map-0.4.13.tgz", + "integrity": "sha512-B1zyFbsiTQvqPr+cuPCXO72sRuczG9Swncqk5P74NCGw1VE8qa/Ry9GlfI1e/VdeQYHjan+XkbE3rO2GW/qKew==", + "license": "MIT", + "dependencies": { + "@solid-primitives/trigger": "^1.1.0" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/media": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@solid-primitives/media/-/media-2.3.3.tgz", + "integrity": "sha512-hQ4hLOGvfbugQi5Eu1BFWAIJGIAzztq9x0h02xgBGl2l0Jaa3h7tg6bz5tV1NSuNYVGio4rPoa7zVQQLkkx9dA==", + "license": "MIT", + "dependencies": { + "@solid-primitives/event-listener": "^2.4.3", + "@solid-primitives/rootless": "^1.5.2", + "@solid-primitives/static-store": "^0.1.2", + "@solid-primitives/utils": "^6.3.2" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/props": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@solid-primitives/props/-/props-3.2.2.tgz", + "integrity": "sha512-lZOTwFJajBrshSyg14nBMEP0h8MXzPowGO0s3OeiR3z6nXHTfj0FhzDtJMv+VYoRJKQHG2QRnJTgCzK6erARAw==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.3.2" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@solid-primitives/refs/-/refs-1.1.2.tgz", + "integrity": "sha512-K7tf2thy7L+YJjdqXspXOg5xvNEOH8tgEWsp0+1mQk3obHBRD6hEjYZk7p7FlJphSZImS35je3UfmWuD7MhDfg==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.3.2" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/resize-observer": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@solid-primitives/resize-observer/-/resize-observer-2.1.3.tgz", + "integrity": "sha512-zBLje5E06TgOg93S7rGPldmhDnouNGhvfZVKOp+oG2XU8snA+GoCSSCz1M+jpNAg5Ek2EakU5UVQqL152WmdXQ==", + "license": "MIT", + "dependencies": { + "@solid-primitives/event-listener": "^2.4.3", + "@solid-primitives/rootless": "^1.5.2", + "@solid-primitives/static-store": "^0.1.2", + "@solid-primitives/utils": "^6.3.2" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/rootless": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@solid-primitives/rootless/-/rootless-1.5.2.tgz", + "integrity": "sha512-9HULb0QAzL2r47CCad0M+NKFtQ+LrGGNHZfteX/ThdGvKIg2o2GYhBooZubTCd/RTu2l2+Nw4s+dEfiDGvdrrQ==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.3.2" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/static-store": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@solid-primitives/static-store/-/static-store-0.1.2.tgz", + "integrity": "sha512-ReK+5O38lJ7fT+L6mUFvUr6igFwHBESZF+2Ug842s7fvlVeBdIVEdTCErygff6w7uR6+jrr7J8jQo+cYrEq4Iw==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.3.2" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/transition-group": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@solid-primitives/transition-group/-/transition-group-1.1.2.tgz", + "integrity": "sha512-gnHS0OmcdjeoHN9n7Khu8KNrOlRc8a2weETDt2YT6o1zeW/XtUC6Db3Q9pkMU/9cCKdEmN4b0a/41MKAHRhzWA==", + "license": "MIT", + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/trigger": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@solid-primitives/trigger/-/trigger-1.2.2.tgz", + "integrity": "sha512-IWoptVc0SWYgmpBPpCMehS5b07+tpFcvw15tOQ3QbXedSYn6KP8zCjPkHNzMxcOvOicTneleeZDP7lqmz+PQ6g==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.3.2" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/utils": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/@solid-primitives/utils/-/utils-6.3.2.tgz", + "integrity": "sha512-hZ/M/qr25QOCcwDPOHtGjxTD8w2mNyVAYvcfgwzBHq2RwNqHNdDNsMZYap20+ruRwW4A3Cdkczyoz0TSxLCAPQ==", + "license": "MIT", + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, "node_modules/@supabase/auth-js": { "version": "2.71.1", "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.71.1.tgz", @@ -3111,6 +3422,15 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, "node_modules/@swc/types": { "version": "0.1.23", "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.23.tgz", @@ -5153,6 +5473,12 @@ "node": ">=0.10.0" } }, + "node_modules/event-target-polyfill": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/event-target-polyfill/-/event-target-polyfill-0.0.4.tgz", + "integrity": "sha512-Gs6RLjzlLRdT8X9ZipJdIZI/Y6/HhRLyq9RdDlCsnpxr/+Nn6bU2EFGuC94GjxqhM+Nmij2Vcq98yoHrU8uNFQ==", + "license": "MIT" + }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -5598,6 +5924,12 @@ "node": ">= 0.4" } }, + "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/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -6502,6 +6834,12 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -6735,6 +7073,15 @@ "node": ">=6" } }, + "node_modules/partysocket": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/partysocket/-/partysocket-1.1.6.tgz", + "integrity": "sha512-LkEk8N9hMDDsDT0iDK0zuwUDFVrVMUXFXCeN3850Ng8wtjPqPBeJlwdeY6ROlJSEh3tPoTTasXoSBYH76y118w==", + "license": "MIT", + "dependencies": { + "event-target-polyfill": "^0.0.4" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -7443,6 +7790,27 @@ "node": ">=10" } }, + "node_modules/seroval": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.3.2.tgz", + "integrity": "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/seroval-plugins": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.3.3.tgz", + "integrity": "sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "seroval": "^1.0" + } + }, "node_modules/shallow-equal": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-3.1.0.tgz", @@ -7513,6 +7881,71 @@ "node": ">=10.0.0" } }, + "node_modules/solid-floating-ui": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/solid-floating-ui/-/solid-floating-ui-0.3.1.tgz", + "integrity": "sha512-o/QmGsWPS2Z3KidAxP0nDvN7alI7Kqy0kU+wd85Fz+au5SYcnYm7I6Fk3M60Za35azsPX0U+5fEtqfOuk6Ao0Q==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@floating-ui/dom": "^1.5", + "solid-js": "^1.8" + } + }, + "node_modules/solid-js": { + "version": "1.9.9", + "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.9.tgz", + "integrity": "sha512-A0ZBPJQldAeGCTW0YRYJmt7RCeh5rbFfPZ2aOttgYnctHE7HgKeHCBB/PVc2P7eOfmNXqMFFFoYYdm3S4dcbkA==", + "license": "MIT", + "dependencies": { + "csstype": "^3.1.0", + "seroval": "~1.3.0", + "seroval-plugins": "~1.3.0" + } + }, + "node_modules/solid-motionone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/solid-motionone/-/solid-motionone-1.0.4.tgz", + "integrity": "sha512-aqEjgecoO9raDFznu/dEci7ORSmA26Kjj9J4Cn1Gyr0GZuOVdvsNxdxClTL9J40Aq/uYFx4GLwC8n70fMLHiuA==", + "license": "MIT", + "dependencies": { + "@motionone/dom": "^10.17.0", + "@motionone/utils": "^10.17.0", + "@solid-primitives/props": "^3.1.11", + "@solid-primitives/refs": "^1.0.8", + "@solid-primitives/transition-group": "^1.0.5", + "csstype": "^3.1.3" + }, + "peerDependencies": { + "solid-js": "^1.8.0" + } + }, + "node_modules/solid-presence": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/solid-presence/-/solid-presence-0.1.8.tgz", + "integrity": "sha512-pWGtXUFWYYUZNbg5YpG5vkQJyOtzn2KXhxYaMx/4I+lylTLYkITOLevaCwMRN+liCVk0pqB6EayLWojNqBFECA==", + "license": "MIT", + "dependencies": { + "@corvu/utils": "~0.4.0" + }, + "peerDependencies": { + "solid-js": "^1.8" + } + }, + "node_modules/solid-prevent-scroll": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/solid-prevent-scroll/-/solid-prevent-scroll-0.1.10.tgz", + "integrity": "sha512-KplGPX2GHiWJLZ6AXYRql4M127PdYzfwvLJJXMkO+CMb8Np4VxqDAg5S8jLdwlEuBis/ia9DKw2M8dFx5u8Mhw==", + "license": "MIT", + "dependencies": { + "@corvu/utils": "~0.4.1" + }, + "peerDependencies": { + "solid-js": "^1.8" + } + }, "node_modules/sonner": { "version": "1.7.4", "resolved": "https://registry.npmjs.org/sonner/-/sonner-1.7.4.tgz", diff --git a/package.json b/package.json index 3a9dd40b..e77f00b3 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@marsidev/react-turnstile": "^1.3.1", "@novu/headless": "^2.6.6", "@novu/node": "^2.6.6", + "@novu/react": "^3.10.1", "@radix-ui/react-accordion": "^1.2.11", "@radix-ui/react-alert-dialog": "^1.1.14", "@radix-ui/react-aspect-ratio": "^1.1.7", diff --git a/src/components/notifications/NotificationCenter.tsx b/src/components/notifications/NotificationCenter.tsx index 923fb2e7..d278c247 100644 --- a/src/components/notifications/NotificationCenter.tsx +++ b/src/components/notifications/NotificationCenter.tsx @@ -1,94 +1,30 @@ -import { useState } from 'react'; -import { Bell } from 'lucide-react'; -import { Button } from '@/components/ui/button'; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from '@/components/ui/popover'; -import { Badge } from '@/components/ui/badge'; -import { ScrollArea } from '@/components/ui/scroll-area'; +import { Inbox } from '@novu/react'; import { useNovuNotifications } from '@/hooks/useNovuNotifications'; -import { Separator } from '@/components/ui/separator'; +import { useNovuTheme } from '@/hooks/useNovuTheme'; +import { useNavigate } from 'react-router-dom'; export function NotificationCenter() { - const { notifications, unreadCount, markAsRead, markAllAsRead, isEnabled } = useNovuNotifications(); - const [open, setOpen] = useState(false); + const { applicationIdentifier, subscriberId, isEnabled } = useNovuNotifications(); + const appearance = useNovuTheme(); + const navigate = useNavigate(); if (!isEnabled) { return null; } + const handleNotificationClick = (notification: any) => { + // Handle navigation based on notification payload + if (notification.data?.url) { + navigate(notification.data.url); + } + }; + return ( - - - - - {unreadCount > 0 && ( - - {unreadCount > 9 ? '9+' : unreadCount} - - )} - - - - - Notifications - {unreadCount > 0 && ( - - Mark all as read - - )} - - - {notifications.length === 0 ? ( - - - No notifications yet - - ) : ( - - {notifications.map((notification) => ( - { - if (!notification.read) { - markAsRead(notification.id); - } - // Handle CTA action if exists - if (notification.cta) { - // Navigate or perform action based on notification.cta - } - }} - > - - {!notification.read && ( - - )} - - {notification.content} - - {new Date(notification.createdAt).toLocaleString()} - - - - - ))} - - )} - - - + ); } diff --git a/src/hooks/useNovuNotifications.ts b/src/hooks/useNovuNotifications.ts index 6abe5d71..28a81948 100644 --- a/src/hooks/useNovuNotifications.ts +++ b/src/hooks/useNovuNotifications.ts @@ -1,55 +1,15 @@ -import { useEffect, useState } from 'react'; import { useAuth } from '@/hooks/useAuth'; -export interface NotificationItem { - id: string; - content: string; - read: boolean; - createdAt: string; - cta?: { - type: string; - data: any; - }; -} - export function useNovuNotifications() { const { user } = useAuth(); - const [notifications, setNotifications] = useState([]); - const [unreadCount, setUnreadCount] = useState(0); - const [isLoading, setIsLoading] = useState(true); const applicationIdentifier = import.meta.env.VITE_NOVU_APPLICATION_IDENTIFIER; - const isEnabled = !!applicationIdentifier && !!user; - - useEffect(() => { - if (!isEnabled) { - setIsLoading(false); - return; - } - - // TODO: Initialize Novu Headless SDK when configuration is complete - // This will require the @novu/headless package to be properly configured - setIsLoading(false); - }, [isEnabled, user]); - - const markAsRead = async (notificationId: string) => { - setNotifications((prev) => - prev.map((n) => (n.id === notificationId ? { ...n, read: true } : n)) - ); - setUnreadCount((prev) => Math.max(0, prev - 1)); - }; - - const markAllAsRead = async () => { - setNotifications((prev) => prev.map((n) => ({ ...n, read: true }))); - setUnreadCount(0); - }; + const subscriberId = user?.id; + const isEnabled = !!applicationIdentifier && !!subscriberId; return { - notifications, - unreadCount, - isLoading, - markAsRead, - markAllAsRead, + applicationIdentifier, + subscriberId, isEnabled, }; } diff --git a/src/hooks/useNovuTheme.ts b/src/hooks/useNovuTheme.ts new file mode 100644 index 00000000..dfe2313b --- /dev/null +++ b/src/hooks/useNovuTheme.ts @@ -0,0 +1,131 @@ +import { useTheme } from '@/components/theme/ThemeProvider'; +import { useMemo } from 'react'; + +export function useNovuTheme() { + const { theme } = useTheme(); + + const appearance = useMemo(() => { + // Get computed styles to access CSS variables + const root = document.documentElement; + const style = getComputedStyle(root); + + return { + variables: { + // Colors + colorBackground: `hsl(var(--background))`, + colorForeground: `hsl(var(--foreground))`, + colorPrimary: `hsl(var(--primary))`, + colorPrimaryForeground: `hsl(var(--primary-foreground))`, + colorSecondary: `hsl(var(--secondary))`, + colorSecondaryForeground: `hsl(var(--secondary-foreground))`, + colorCounter: `hsl(var(--primary))`, + colorCounterForeground: `hsl(var(--primary-foreground))`, + + // Notification item colors + colorNeutral: `hsl(var(--muted))`, + colorNeutralForeground: `hsl(var(--muted-foreground))`, + + // Border and divider + colorBorder: `hsl(var(--border))`, + + // Border radius + borderRadius: `var(--radius)`, + + // Font + fontFamily: style.getPropertyValue('font-family') || 'inherit', + fontSize: '14px', + }, + elements: { + bellContainer: { + width: '40px', + height: '40px', + }, + bell: { + width: '20px', + height: '20px', + color: `hsl(var(--foreground))`, + }, + bellDot: { + backgroundColor: `hsl(var(--primary))`, + }, + popover: { + boxShadow: `var(--shadow-card)`, + border: `1px solid hsl(var(--border))`, + borderRadius: `calc(var(--radius) + 4px)`, + }, + notificationItem: { + transition: 'var(--transition-smooth)', + '&:hover': { + backgroundColor: `hsl(var(--muted) / 0.5)`, + }, + }, + notificationItemRead: { + opacity: '0.7', + }, + notificationItemUnread: { + backgroundColor: `hsl(var(--muted) / 0.3)`, + borderLeft: `3px solid hsl(var(--primary))`, + }, + notificationDot: { + backgroundColor: `hsl(var(--primary))`, + width: '8px', + height: '8px', + }, + notificationTitle: { + fontWeight: '500', + color: `hsl(var(--foreground))`, + }, + notificationDescription: { + color: `hsl(var(--muted-foreground))`, + }, + notificationTimestamp: { + fontSize: '12px', + color: `hsl(var(--muted-foreground))`, + }, + notificationPrimaryAction: { + backgroundColor: `hsl(var(--primary))`, + color: `hsl(var(--primary-foreground))`, + borderRadius: `var(--radius)`, + padding: '8px 16px', + transition: 'var(--transition-smooth)', + '&:hover': { + opacity: '0.9', + }, + }, + notificationSecondaryAction: { + backgroundColor: `hsl(var(--secondary))`, + color: `hsl(var(--secondary-foreground))`, + borderRadius: `var(--radius)`, + padding: '8px 16px', + transition: 'var(--transition-smooth)', + '&:hover': { + backgroundColor: `hsl(var(--secondary) / 0.8)`, + }, + }, + loader: { + color: `hsl(var(--primary))`, + }, + emptyNotifications: { + color: `hsl(var(--muted-foreground))`, + textAlign: 'center', + padding: '32px 16px', + }, + header: { + borderBottom: `1px solid hsl(var(--border))`, + padding: '16px', + }, + headerTitle: { + fontSize: '16px', + fontWeight: '600', + color: `hsl(var(--foreground))`, + }, + footer: { + borderTop: `1px solid hsl(var(--border))`, + padding: '12px 16px', + }, + }, + }; + }, [theme]); + + return appearance; +}
No notifications yet
{notification.content}
- {new Date(notification.createdAt).toLocaleString()} -