From 8a021a8d3a3645a356a0daf1f9a3397a5e3ffd4f Mon Sep 17 00:00:00 2001 From: MdAnas <144697531+Anas-github-acc@users.noreply.github.com> Date: Sat, 27 Jul 2024 12:36:02 +0530 Subject: [PATCH] some changes to authentication + styling form_create page (#69) lil changes in authentication --- package-lock.json | 939 ++++++++++++++++-- package.json | 7 +- public/placeholder-user.jpg | Bin 0 -> 1635 bytes public/profile-pic.jpg | Bin 0 -> 18531 bytes src/app/api/logout/route.ts | 14 + src/app/api/rest/v1/isUsername/route.ts | 29 + src/app/api/rest/v1/users/route.ts | 39 + src/app/auth/action.tsx | 62 +- src/app/auth/callback/route.ts | 1 + src/app/auth/component/component.tsx | 27 +- src/app/auth/component/oauth.tsx | 9 +- src/app/auth/confirm/route.ts | 15 +- src/app/auth/confirm_email/page.tsx | 52 +- src/app/auth/page.tsx | 29 +- .../form_create/components/dropdown_menu.tsx | 67 ++ src/app/form_create/components/form.tsx | 63 ++ src/app/form_create/components/loggingout.tsx | 39 + .../form_create/components/styles.module.css | 27 + src/app/form_create/components/userform.tsx | 120 +++ src/app/form_create/page.tsx | 133 ++- src/app/globals.css | 47 +- src/app/layout.tsx | 22 +- src/components/error_dialog.tsx | 96 ++ src/components/ui/alertv2.tsx | 59 ++ src/components/ui/avatar.tsx | 50 + src/components/ui/button.tsx | 12 +- src/components/ui/card.tsx | 79 ++ src/components/ui/dialog.tsx | 122 +++ src/components/ui/dropdown-menu.tsx | 200 ++++ src/components/ui/input.tsx | 2 +- src/components/ui/loader.tsx | 20 + src/utils/supabase/middleware.ts | 43 +- tailwind.config.ts | 9 +- 33 files changed, 2209 insertions(+), 224 deletions(-) create mode 100644 public/placeholder-user.jpg create mode 100644 public/profile-pic.jpg create mode 100644 src/app/api/logout/route.ts create mode 100644 src/app/api/rest/v1/isUsername/route.ts create mode 100644 src/app/api/rest/v1/users/route.ts create mode 100644 src/app/form_create/components/dropdown_menu.tsx create mode 100644 src/app/form_create/components/form.tsx create mode 100644 src/app/form_create/components/loggingout.tsx create mode 100644 src/app/form_create/components/styles.module.css create mode 100644 src/app/form_create/components/userform.tsx create mode 100644 src/components/error_dialog.tsx create mode 100644 src/components/ui/alertv2.tsx create mode 100644 src/components/ui/avatar.tsx create mode 100644 src/components/ui/card.tsx create mode 100644 src/components/ui/dialog.tsx create mode 100644 src/components/ui/dropdown-menu.tsx create mode 100644 src/components/ui/loader.tsx diff --git a/package-lock.json b/package-lock.json index 9a68993..036096c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,9 @@ "@emotion/react": "^11.12.0", "@emotion/styled": "^11.12.0", "@mui/material": "^5.16.4", + "@radix-ui/react-avatar": "^1.1.0", + "@radix-ui/react-dialog": "^1.1.1", + "@radix-ui/react-dropdown-menu": "^2.1.1", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.1.0", "@radix-ui/react-slot": "^1.1.0", @@ -18,8 +21,10 @@ "@supabase/ssr": "^0.4.0", "@vercel/analytics": "^1.3.1", "@vercel/speed-insights": "^1.0.12", + "axios": "^1.7.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", + "ldrs": "^1.0.2", "lucide-react": "^0.408.0", "next": "14.2.5", "next-client-cookies": "^1.1.1", @@ -399,6 +404,44 @@ "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", "license": "MIT" }, + "node_modules/@floating-ui/core": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.5.tgz", + "integrity": "sha512-8GrTWmoFhm5BsMZOTHeGD2/0FLKLQQHvO/ZmQga4tKempYRLz8aqJGqXVuQgisnMObq2YZ2SgkwctN1LOOxcqA==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.5" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.8.tgz", + "integrity": "sha512-kx62rP19VZ767Q653wsP1XZCGIirkE09E0QUGNYTM/ttbbQHqcGPdSfWFxUyyNLc/W6aoJRBajOSXhP6GXjC0Q==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.5" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", + "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.5.tgz", + "integrity": "sha512-sTcG+QZ6fdEUObICavU+aB3Mp8HY4n14wYHdxK4fXjPmv3PXZZeY5RaguJmGyeH/CJQhX3fqKUtS4qc1LoHwhQ==", + "license": "MIT" + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -845,43 +888,543 @@ "node": ">= 8" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz", + "integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "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-avatar": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.0.tgz", + "integrity": "sha512-Q/PbuSMk/vyAd/UoIShVGZ7StHHeRFYU7wXmi5GV+8cLXflZAEpHL/F697H1klrzxKXNtZ97vWiC0q3RKUH8UA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "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-collection": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.0.tgz", + "integrity": "sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0" + }, + "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-compose-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.1.tgz", + "integrity": "sha512-zysS+iU4YP3STKNS6USvFVqI4qqx8EpiwmT5TuCApVEBca+eRCbONi4EgzfNSuVnOXvC5UPHHMjs8RXO6DH9Bg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-focus-guards": "1.1.0", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.7" + }, + "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-direction": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", + "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.0.tgz", + "integrity": "sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" + }, + "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-dropdown-menu": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.1.tgz", + "integrity": "sha512-y8E+x9fBq9qvteD2Zwa4397pUVhYsh9iq44b5RD5qu1GMJWBCBuVg1hMyItbc6+zH00TxGRqd9Iot4wzf3OoBQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-menu": "2.1.1", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "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-focus-guards": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz", + "integrity": "sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz", + "integrity": "sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "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-icons": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.0.tgz", + "integrity": "sha512-jQxj/0LKgp+j9BiTXz3O3sgs26RNet2iLWmsPyRz2SIcR4q/4SbazXfnYwbAr+vLYKSfc7qxzyGQA1HLlYiuNw==", + "license": "MIT", + "peerDependencies": { + "react": "^16.x || ^17.x || ^18.x" + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", + "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.0.tgz", + "integrity": "sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "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-menu": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.1.tgz", + "integrity": "sha512-oa3mXRRVjHi6DZu/ghuzdylyjaMXLymx83irM7hTxutQbD+7IhPKdMdRHD26Rm+kHRrWcrUkkRPv5pd47a2xFQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-focus-guards": "1.1.0", + "@radix-ui/react-focus-scope": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-roving-focus": "1.1.0", + "@radix-ui/react-slot": "1.1.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.7" + }, + "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.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz", + "integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-rect": "1.1.0", + "@radix-ui/react-use-size": "1.1.0", + "@radix-ui/rect": "1.1.0" + }, + "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-portal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.1.tgz", + "integrity": "sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "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-presence": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.0.tgz", + "integrity": "sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "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-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.0" + }, + "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-roving-focus": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz", + "integrity": "sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "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.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", "license": "MIT", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@radix-ui/react-compose-refs": "1.1.0" }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@radix-ui/react-compose-refs": { + "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", - "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -893,68 +1436,82 @@ } } }, - "node_modules/@radix-ui/react-icons": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.0.tgz", - "integrity": "sha512-jQxj/0LKgp+j9BiTXz3O3sgs26RNet2iLWmsPyRz2SIcR4q/4SbazXfnYwbAr+vLYKSfc7qxzyGQA1HLlYiuNw==", + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, "peerDependencies": { - "react": "^16.x || ^17.x || ^18.x" + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@radix-ui/react-label": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.0.tgz", - "integrity": "sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==", + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", + "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.0.0" + "@radix-ui/react-use-callback-ref": "1.1.0" }, "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" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { "optional": true } } }, - "node_modules/@radix-ui/react-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", - "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz", + "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.1.0" + "@radix-ui/rect": "1.1.0" }, "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" + "react": "^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": { + "node_modules/@radix-ui/react-use-size": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", - "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", + "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0" + "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { "@types/react": "*", @@ -966,6 +1523,12 @@ } } }, + "node_modules/@radix-ui/rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", + "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==", + "license": "MIT" + }, "node_modules/@reduxjs/toolkit": { "version": "2.2.6", "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.6.tgz", @@ -1305,6 +1868,24 @@ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", "license": "MIT" }, + "node_modules/aria-hidden": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", + "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, "node_modules/autoprefixer": { "version": "10.4.19", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", @@ -1343,6 +1924,17 @@ "postcss": "^8.1.0" } }, + "node_modules/axios": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/babel-plugin-macros": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", @@ -1652,6 +2244,18 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -1759,6 +2363,21 @@ } } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -1909,6 +2528,26 @@ "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", "license": "MIT" }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/foreground-child": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", @@ -1925,6 +2564,20 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/formdata-polyfill": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", @@ -1974,6 +2627,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -2111,6 +2773,15 @@ "node": ">=0.8.19" } }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -2246,6 +2917,12 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "license": "MIT" }, + "node_modules/ldrs": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ldrs/-/ldrs-1.0.2.tgz", + "integrity": "sha512-sYJmivdkIiHrUEqTrEWccBoLdaENpzbzkABI5rk8rRxTXrg9i2xVuDvUUuhOhJY3RmQyaoxs046pM1DCRdcIpg==", + "license": "MIT" + }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -2310,6 +2987,27 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -2864,6 +3562,12 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -2947,6 +3651,76 @@ } } }, + "node_modules/react-remove-scroll": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz", + "integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.4", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.0", + "use-sidecar": "^1.1.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz", + "integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", + "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "invariant": "^2.2.4", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -3574,6 +4348,49 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/use-callback-ref": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz", + "integrity": "sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", + "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/use-sync-external-store": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", diff --git a/package.json b/package.json index 4251344..f5234fc 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,9 @@ "@emotion/react": "^11.12.0", "@emotion/styled": "^11.12.0", "@mui/material": "^5.16.4", + "@radix-ui/react-avatar": "^1.1.0", + "@radix-ui/react-dialog": "^1.1.1", + "@radix-ui/react-dropdown-menu": "^2.1.1", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.1.0", "@radix-ui/react-slot": "^1.1.0", @@ -19,8 +22,10 @@ "@supabase/ssr": "^0.4.0", "@vercel/analytics": "^1.3.1", "@vercel/speed-insights": "^1.0.12", + "axios": "^1.7.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", + "ldrs": "^1.0.2", "lucide-react": "^0.408.0", "next": "14.2.5", "next-client-cookies": "^1.1.1", @@ -45,4 +50,4 @@ "tailwindcss": "^3.4.1", "typescript": "^5" } -} \ No newline at end of file +} diff --git a/public/placeholder-user.jpg b/public/placeholder-user.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6fa7543d38ed8fdb38f03b5c0f40ad2d66827d4a GIT binary patch literal 1635 zcmex=cRarq{jAqGJXh7$}Ym>C5bm;@P_1sVSzVUPwol9>?*7~p`Fjh%&&i5Vyo`r#xP0%qgXfnHy zn7E>$Lug{-LIb0a!ifhj3W%7RB^MNLx}>0_tP&7BY4IaqjBo(siP4_n_ky5FEmL(` zmhdc@Jb`OxUUPQK!#sq(C`ZJd3YCA-U zh)gnS;tOzhJ@#Yf$SRGl2DVF#R;SL@d2ijhdh5m?{S3~XPpnp*$)2k2D4JJuYTMD;n0K36=Y8OJ z-mS1ZZC1 z49BdqoLoM_v$9v)Hm?5W<`Stp{n4{)u7wjb{~fvi z!T;47&))dGMoGtVj(5+GENxwrz4z{INB>V}1-4JUxp@DgJ8LKAUAQWhoR~X5%Wp!~ z=~v%IB`XWv>j>XTei(%h-3q0fm1bY5udCHKmu^f&G@&$==-St!-gGk?J$~inXs)aj#q07WR4- zM=rxkFUy8C!QJtD_bgKux*|B+dhW6{-z2Xe?@~0Ks(ijMro-3a&Mj#N$xpGBRnmWt zTsUxz-_bhtPjF={K-%Z^57b<}UkWR&Lo)qWhnrV2yD?(SL?Q-l9d; zHS6^j9!_Ejaqqemoyn}=@ptvvS-S7I7N7FZ5}(WNv3l;#-@XTLOmcJGRz1a7FhcBC z-nPY(UsETGE4&Rdme=pC+jj2j;!j+6o-!m}7oD?jz2dGcAvK4%qSmfE=U+z7Z+`#j z$Mx4a@1yJ$R+zt@y0z(yW_ISH^4k|<^!Al@?-M=r`gz3ehXgqVyM1>}k-Q}GF<-;) z*LLGyVd)Qk|Ji$(J?dTY-07-((_=n_`3T&d5FiH|guzja;wny>q}tw+C34*a{8 zfJ9i0DbumfeTVp1E#|(wudjdSJE%AnL@H&$nSBB{^D;34Gp|fN9u>e68m!_b0O__- AD*ylh literal 0 HcmV?d00001 diff --git a/public/profile-pic.jpg b/public/profile-pic.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cbef0245865337bfa3a3db97b1183f89242d358f GIT binary patch literal 18531 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 literal 0 HcmV?d00001 diff --git a/src/app/api/logout/route.ts b/src/app/api/logout/route.ts new file mode 100644 index 0000000..e2bc148 --- /dev/null +++ b/src/app/api/logout/route.ts @@ -0,0 +1,14 @@ +import {NextRequest, NextResponse} from "next/server"; +import {createClient} from "@/utils/supabase/server"; + +export async function GET(req: NextRequest) { + const supabase = createClient() + + const { error } = await supabase.auth.signOut() + + if (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } + + return NextResponse.json({ data: 'Logout successful' }, { status: 200 }); +} \ No newline at end of file diff --git a/src/app/api/rest/v1/isUsername/route.ts b/src/app/api/rest/v1/isUsername/route.ts new file mode 100644 index 0000000..1be0ff4 --- /dev/null +++ b/src/app/api/rest/v1/isUsername/route.ts @@ -0,0 +1,29 @@ +import {NextRequest, NextResponse} from "next/server"; + +export async function POST(req: NextRequest): Promise { + let response = NextResponse.next({ + request: { + headers: req.headers, + }, + }) + + const body = await req.json() + + if ( !body.username ) { + return NextResponse.json({ error: 'username is required' }) + } + + let res = await fetch(`${process.env.NEXT_PUBLIC_SUPABASE_URL}/rest/v1/rpc/is_username_exist`, { + method: 'POST', + headers: { + "apikey": process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + "Authorization": `Bearer ${process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!}`, + "Content-Type": "application/json", + }, + body: JSON.stringify(body) + }); + + let data = await res.json(); + + return NextResponse.json({ state: data }); +} \ No newline at end of file diff --git a/src/app/api/rest/v1/users/route.ts b/src/app/api/rest/v1/users/route.ts new file mode 100644 index 0000000..024472b --- /dev/null +++ b/src/app/api/rest/v1/users/route.ts @@ -0,0 +1,39 @@ +import {NextRequest, NextResponse} from "next/server"; +import { createClient } from "@/utils/supabase/server"; +import { User } from "@supabase/supabase-js"; + +export async function POST(req: NextRequest): Promise { + let response = NextResponse.next({ + request: { + headers: req.headers, + }, + }) + + const body = await req.json() + const supabase = createClient(); + const searchParams = req.nextUrl.searchParams; + const option = searchParams.get('option'); + + let data: User | User[] | null = null; + + if ( option === 'insert' ) { + const { data: user, error: error } = await supabase + .from('users') + .insert([{id: body.id, username: body.username, admin: body.admin}]) + if (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } + data = user; + } else if ( option === 'update' ) { + const { data: user, error: error } = await supabase + .from('users') + .update({username: body.username}) + .match({id: body.id}) + if (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } + data = user; + } + + return NextResponse.json({ data: data }); +} \ No newline at end of file diff --git a/src/app/auth/action.tsx b/src/app/auth/action.tsx index 601847b..34cba23 100644 --- a/src/app/auth/action.tsx +++ b/src/app/auth/action.tsx @@ -21,61 +21,53 @@ export const Login = async ( export const SignUp = async ( credentials : { + username: string | null, email: string , password: string , }) => { const origin = headers().get("origin"); - const referer = headers().get("referer"); - const query = referer?.split('?')[1].split('&'); - const org = query?.find((q) => q.includes('organisation')) || ''; - + const username = credentials.username; const supabase = createClient(); - const { data: { session }, error, } = await supabase.auth.signUp({ + + const { data: { user, session }, error, } = await supabase.auth.signUp({ email: credentials.email as string, password: credentials.password as string, options: { - emailRedirectTo: `${origin}/auth/callback`, + emailRedirectTo: `${origin}/auth/confirm`, + data: { username: username }, }, }); + if (error) { + console.log(error); return { error: error.message }; } - if (session) { + if (session || user?.role !== 'authenticated') { return { error: 'Email already exists' }; } return { error: null }; }; export const AuthSignIn = async () => { - const origin = headers().get("origin"); - const gmail = cookies()?.get('email')?.value || ''; - - const supabase = createClient(); - const { data, error } = await supabase.auth.signInWithOAuth({ - provider: 'google', - options: { - redirectTo: `${origin}/auth/callback`, - queryParams: { - include_granted_scopes: 'true', - access_type: 'offline', - prompt: 'select_account', - login_hint: gmail, - }, - }, - }); - if (error) return { error: error.message, url: null }; - if (data.url) return { error: null, url: data.url }; - return { error: 'Error signing in', url: null }; -} - -export async function usernameExisits(username: string): Promise { + const origin = headers().get("origin"); + const gmail = cookies()?.get('email')?.value || ''; + const supabase = createClient(); - let { data, error } = await supabase - .rpc('is_username_exist', { - username: username, - }); - if (error) console.error(error) - return data; + const { data, error } = await supabase.auth.signInWithOAuth({ + provider: 'google', + options: { + redirectTo: `${origin}/auth/callback`, + queryParams: { + include_granted_scopes: 'true', + access_type: 'offline', + prompt: 'select_account', + login_hint: gmail, + }, + }, + }); + if (error) return { error: error.message, url: null }; + if (data.url) return { error: null, url: data.url }; + return { error: 'Error signing in', url: null }; } export const checkEmailForOrganisation = ( diff --git a/src/app/auth/callback/route.ts b/src/app/auth/callback/route.ts index 96cfad6..4bb206f 100644 --- a/src/app/auth/callback/route.ts +++ b/src/app/auth/callback/route.ts @@ -23,5 +23,6 @@ export async function GET(req: NextRequest, res: NextResponse) { console.log('x ',error); } } + return NextResponse.redirect(url); } \ No newline at end of file diff --git a/src/app/auth/component/component.tsx b/src/app/auth/component/component.tsx index 9b78845..3a5579f 100644 --- a/src/app/auth/component/component.tsx +++ b/src/app/auth/component/component.tsx @@ -1,15 +1,16 @@ -import { FormEvent, use, useEffect, useState } from "react"; -import { usernameExisits } from "@/app/auth/action"; +import React, { FormEvent, use, useEffect, useState } from "react"; +import axios from "axios"; import { Label } from "@/components/ui/label" import { Input } from "@/components/ui/input" import { Button } from "@/components/ui/button" +import Loader from '@/components/ui/loader' -import { VscEye, VscEyeClosed } from "react-icons/vsc"; -import CircularProgress from '@mui/material/CircularProgress'; +import { VscEye, VscEyeClosed } from "react-icons/vsc" import styles from './styles.module.css' import { cn } from "@/lib/utils" + interface Props { auth: string | null SignUp: (e: EventTarget & HTMLFormElement) => Promise @@ -89,23 +90,22 @@ export function Component( props : Props) { return ; } setLoading(true); - const data = await usernameExisits(username) - console.log('data = ',data); - if (data) { - const nextUserSibling = current.username.nextSibling as HTMLElement; + const res = await axios.post('/api/rest/v1/isUsername', {username: username}); + + if (res.data.state) { + const nextUserSibling = current.username.nextElementSibling as HTMLElement; nextUserSibling.innerText = 'Username already exists'; } else { - const nextUserSibling = current.username.nextSibling as HTMLElement; + const nextUserSibling = current.username.nextElementSibling as HTMLElement; nextUserSibling.innerText = ''; if (validatePassword(password) && password.length>=8) { - const bool = await props.SignUp(current) if (!bool) setLoading(false); - const nextSibling = current.password.nextSibling as HTMLElement; + const nextSibling = current.password.nextElementSibling as HTMLElement; nextSibling.innerText = ''; } else { - const nextSibling = current.password.nextSibling as HTMLElement; + const nextSibling = current.password.nextElementSibling as HTMLElement; if (!validatePassword(password, 1)) { nextSibling.innerText = 'Password must be at least 8 characters long'; } else if (!validatePassword(password, 2)) { @@ -171,7 +171,8 @@ export function Component( props : Props) { className="group relative flex w-full justify-center rounded-[8px] bg-primary py-6 px-4 text-md font-bold text-primary-foreground transition-colors focus:opacity-90 focus:outline-none" disabled={loading} > - {loading ? : structure.button.text} + {loading ? + : structure.button.text} diff --git a/src/app/auth/component/oauth.tsx b/src/app/auth/component/oauth.tsx index 9bc48cb..faba5ee 100644 --- a/src/app/auth/component/oauth.tsx +++ b/src/app/auth/component/oauth.tsx @@ -1,10 +1,9 @@ import React, { useState } from "react"; import { Button } from "@/components/ui/button" +import Loader from '@/components/ui/loader' // -- icons -- -import CircularProgress from '@mui/material/CircularProgress'; import { FcGoogle } from "react-icons/fc"; - import { JSX, SVGProps } from "react" interface Props{ @@ -34,10 +33,8 @@ export function OAuthComponent(props : Props) { variant="outline" className="group relative flex w-full justify-center rounded-[8px] border border-input bg-background py-6 px-4 text-md font-medium text-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus:outline-none focus:opacity-90" > - {loading ? : - <> - oogle - } + {loading ? : + <>oogle} ) diff --git a/src/app/auth/confirm/route.ts b/src/app/auth/confirm/route.ts index 55a8b92..b654759 100644 --- a/src/app/auth/confirm/route.ts +++ b/src/app/auth/confirm/route.ts @@ -1,6 +1,5 @@ import { type EmailOtpType } from '@supabase/supabase-js' import { type NextRequest, NextResponse } from 'next/server' -import { cookies } from 'next/headers' import { createClient } from '@/utils/supabase/server' @@ -8,7 +7,7 @@ export async function GET(req: NextRequest) { const { searchParams } = new URL(req.url) const token_hash = searchParams.get('token_hash') const type = searchParams.get('type') as EmailOtpType | null - const next = searchParams.get('next') ?? '/create_form' + const next = searchParams.get('next') ?? '/form_create' const redirectTo = req.nextUrl.clone() redirectTo.pathname = next @@ -21,18 +20,6 @@ export async function GET(req: NextRequest) { type: type || 'email', token_hash: token_hash , }) - const user = data?.user - if (!error && user) { - const getCookies = cookies(); - const username = getCookies?.get('username')?.value; - getCookies?.delete('username'); - const { error: insertError } = await supabase - .from('users') - .insert([ - { id: user?.id, username: username } - ]); - if (insertError) console.error('Error inserting user data:', insertError.message); - } if (!error) { redirectTo.searchParams.delete('next') return NextResponse.redirect(redirectTo) diff --git a/src/app/auth/confirm_email/page.tsx b/src/app/auth/confirm_email/page.tsx index 9928445..446091e 100644 --- a/src/app/auth/confirm_email/page.tsx +++ b/src/app/auth/confirm_email/page.tsx @@ -1,9 +1,11 @@ 'use client'; -import React, { useState, useEffect, use } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import Link from 'next/link'; -import { Button } from '@/components/ui/button'; -import { useSearchParams } from 'next/navigation'; + +import { useCookies } from 'next-client-cookies'; import { supabase } from '@/utils/supabase/client'; +import { Button } from '@/components/ui/button'; +import ErrorDialog from '@/components/error_dialog'; import Image from 'next/image'; @@ -12,10 +14,27 @@ export default function Confirm() { const [error, setError] = useState(null); const [countdown, setCountdown] = useState(10); - const searchParams = useSearchParams(); - const email = searchParams.get('email') || 'xxxx-xxxx-xxxx-xxxx'; + useEffect(() => { + supabase.auth.getUser().then(({ data , error }) => { + if (error) { + console.log(error.message); + return; + } + console.log(data); + }); + }, []); + + const cookies = useCookies(); + const user_email = cookies.get('email') || null; + + if (!user_email) return ( + + ) - if(!validateEmail(email)) { + if(!validateEmail(user_email)) { return (
@@ -23,7 +42,7 @@ export default function Confirm() { Invalid email address:

- {email} + {user_email}

); @@ -49,44 +68,47 @@ export default function Confirm() { }, [loading, countdown]); const resent = async () => { + const origin = window.location.origin; setLoading(true) const { error } = await supabase.auth.resend({ type: 'signup', - email: email, + email: user_email, options: { - emailRedirectTo: '/auth/confirm_email?email=' + email, + emailRedirectTo: `${origin}/auth/confirm`, } }) if (error) { setError(error.message) + } else { + setError(null) } } return (
-
+

Email Sent!

- We've sent a confirmation email to {email}. Click the link in + We've sent a confirmation email to {user_email}. Click the link in the email to verify your account.

- Return to Home + Return to Login
diff --git a/src/app/auth/page.tsx b/src/app/auth/page.tsx index d3f1d0f..8dffb20 100644 --- a/src/app/auth/page.tsx +++ b/src/app/auth/page.tsx @@ -26,6 +26,11 @@ export default function Auth(){ const auth = searchParams.get('auth'); const organisation = searchParams.get('organisation'); const oauthhidden = organisation==='iiitv'?true:false; + const err = searchParams.get('error'); + + useEffect(() => { + if (err) setError(err); + }, [err]); const cookies = useCookies(); const email = cookies.get('email') || null; @@ -48,22 +53,24 @@ export default function Auth(){ } else { router.push('/form_create'); } - } + } + const signup = async (cur: EventTarget & HTMLFormElement) => { const email = cur.email.value; const username = cur.username.value; const password = cur.password.value; - cookies.set('username', username); setError(null); - const { error } = await SignUp({email, password}) + const { error } = await SignUp({username, email, password}) + console.log(error); if (error) { setError(error); return false; } else { - router.push('/auth/confirm_email?email=' + email); + router.push(`/auth/confirm_email?type=signup`); } } + const Authsignin = async () => { setError(null); const { error, url } = await AuthSignIn(); @@ -88,13 +95,13 @@ export default function Auth(){ EmailSubmit={emailSubmit} email={email}> - { auth && -
- {auth === 'signup' ? -

Have an account? Login

: -

Don't have an account? Create here

} -
- } + { auth && (
+
+ {auth === 'signup' ? +

Have an account? Login

: +

Don't have an account? Create here

} +
+
)} {oauthhidden && } diff --git a/src/app/form_create/components/dropdown_menu.tsx b/src/app/form_create/components/dropdown_menu.tsx new file mode 100644 index 0000000..e92d885 --- /dev/null +++ b/src/app/form_create/components/dropdown_menu.tsx @@ -0,0 +1,67 @@ +import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuSeparator, DropdownMenuItem } from "@/components/ui/dropdown-menu" +import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar" +import { Button } from "@/components/ui/button" +import Link from "next/link" +import { JSX, SVGProps, useEffect, useState } from "react" + +interface Props + extends React.HTMLAttributes { + email: string | null, + username: string | null, + onLogout: () => void, +} + +export function Dropdown_Menu({ + email, + username, + onLogout: logout, +}: Props ) { + + return ( + <> + + + + + +
+ + + JD + +
+
{username || 'username'}
+
{email || 'user email'}
+
+
+ + + +
+ Profile + + + + +
+ Settings + + + + + +
+ Sign out + + + + + + ) +} diff --git a/src/app/form_create/components/form.tsx b/src/app/form_create/components/form.tsx new file mode 100644 index 0000000..babc943 --- /dev/null +++ b/src/app/form_create/components/form.tsx @@ -0,0 +1,63 @@ +import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar" +import { Card, CardContent, CardFooter, CardHeader, CardTitle, CardDescription } from "@/components/ui/card" +import { Label } from "@/components/ui/label" +import { Input } from "@/components/ui/input" +import { Button } from "@/components/ui/button" + +interface Props + extends React.HTMLAttributes { + username: string | null, + email: string | null, + disabled: boolean, +} + +export function Form({ + username, + email, + disabled, +}: Props) { + return ( +
+
+
+ + + JD + +
+
{username || 'Loading...'}
+
{email}
+
+
+
+

Create your Form

+

Enter your details below to get started.

+
+
+ + + Please fill out the details below to create questions. + + +
+ + +
+
+ + +
+
+ + +
+
+ + + +
+
+
+
+ ) +} diff --git a/src/app/form_create/components/loggingout.tsx b/src/app/form_create/components/loggingout.tsx new file mode 100644 index 0000000..117c5e6 --- /dev/null +++ b/src/app/form_create/components/loggingout.tsx @@ -0,0 +1,39 @@ +import React from 'react' +import Link from 'next/link' +import { SVGProps } from 'react' +import Loader from '@/components/ui/loader' + +export function LoggingOut() { + return ( +
+
+
+ +

Logging out...

+

You are being logged out of your account.

+
+
+
+ ) +} + +function LogOutIcon(props: JSX.IntrinsicAttributes & SVGProps) { + return ( + + + + + + ) +} \ No newline at end of file diff --git a/src/app/form_create/components/styles.module.css b/src/app/form_create/components/styles.module.css new file mode 100644 index 0000000..e13e8fd --- /dev/null +++ b/src/app/form_create/components/styles.module.css @@ -0,0 +1,27 @@ +.error { + position: absolute; + left:6px; + top: -17.5px; + height: fit-content !important; + color:red !important; + font-size:0.7rem !important; + word-wrap: no-wrap !important; + white-space: nowrap !important; + z-index: 10; +} +.inputicon { + position:absolute; + top: 50%; + color: rgba(var(--black-light), .45); + font-size: 1rem; + transform: translateY(-50%); + transition: 0.5s ease; +} +.eyeicon { + right: 15px; + padding: 3px; + cursor: pointer; +} +.eyeicon:hover { + color: rgba(var(--black-light), .65); +} \ No newline at end of file diff --git a/src/app/form_create/components/userform.tsx b/src/app/form_create/components/userform.tsx new file mode 100644 index 0000000..c8d6e9d --- /dev/null +++ b/src/app/form_create/components/userform.tsx @@ -0,0 +1,120 @@ +import React, { useState, useEffect, useCallback, use } from "react"; +import axios from "axios"; + +import { Input } from "@/components/ui/input"; +import { Button } from "@/components/ui/button"; +import { Label } from "@/components/ui/label"; +import Loader from '@/components/ui/loader' + +import styles from './styles.module.css' +import { cn } from "@/lib/utils"; + + +interface PropsType { + email: string | null, + user_id: string, +} + +export function UserForm( {user_id, email}: PropsType) { + const [username, setUsername] = useState(null); + const [error, setError] = useState(null); + const [disabled, setDisabled] = useState(true); + const [loading, setLoading] = useState(false); + + const controller = new AbortController(); + const signal = controller.signal; + + const isExist = useCallback(async () => { + const res = await axios.post('/api/rest/v1/isUsername', {username: username}, {signal}); + if (res.data.state) { + setDisabled(true); + setError('Username already exists'); + } else { + setDisabled(false); + setError(''); + } + }, [username]); + + + useEffect(() => { + let timer: NodeJS.Timeout; + if (username) { + timer = setTimeout(() => { + isExist(); + }, 400) + } + return () => { + controller.abort(); + clearTimeout(timer); + } + }, [username]); + + useEffect(() => { + if (!username) { + console.log('username is empty'); + setError(''); + setDisabled(true); + } + }, [username, disabled, error]); + + return ( +
+
+
+

+ Welcome, {email?.split('@')[0]} +

+

Please enter an username

+
+
{ + e.preventDefault(); + setLoading(true); + axios.post(`/api/rest/v1/users?option=insert`, {id: user_id, username: username}) + .then((res) => { + if (res.data.error) { + setError(res.data.error); + setLoading(false); + } else { + setLoading(false); + window.location.href = '/form_create'; + } + }) + .catch((error) => { + setError(error.message); + setLoading(false); + }); + }}> +
+ + setUsername(e.target.value)} + id={'username'} + name={'username'} + type={'text'} + autoComplete={'username'} + required + placeholder={'Username'} + disabled={loading} + className={cn("rounded-[8px] border border-input bg-background px-4 py-6 text-foreground placeholder-muted-foreground focus:z-10 focus:border-primary focus:outline-none sm:text-sm")} + /> + {error} +
+
+ +
+
+
+
+ ); +} \ No newline at end of file diff --git a/src/app/form_create/page.tsx b/src/app/form_create/page.tsx index be456f2..576f45c 100644 --- a/src/app/form_create/page.tsx +++ b/src/app/form_create/page.tsx @@ -1,25 +1,126 @@ 'use client'; -import React from 'react'; +import React, { useState, useEffect, useCallback, use } from 'react'; +import Link from 'next/link'; +import { useSearchParams, useRouter } from 'next/navigation'; import { supabase } from '@/utils/supabase/client'; +import { User } from '@supabase/supabase-js'; +import axios from 'axios'; + +import { UserForm } from './components/userform'; +import { Form } from './components/form'; +import { Dropdown_Menu } from "./components/dropdown_menu"; +import { LoggingOut } from './components/loggingout'; +import ErrorDialog from '@/components/error_dialog'; + import { cn } from '@/lib/utils'; -import { Button } from '@/components/ui/button'; +export default function Page() { + const [user, setUser] = useState(null); + const [username , setUsername] = useState(null); + const [useremail , setUserEmail] = useState(null); + const [error, setError] = useState(null); + + const [usernameInput, setUsernameInput] = useState(false); + + const [loading, setLoading] = useState(true); + const [loggingoff, setLogout] = useState(false); + + const searchParams = useSearchParams(); + const router = useRouter(); + + useEffect(() => { + const getUser = async () => { + const { data: { user }, error } = await supabase.auth.getUser(); + if (error) { + console.log(error.message); + return; + } + setUser(user); + setUserEmail(user?.email || null); + } + getUser(); + }, []); + + useEffect(() => { + return () => { + + if ( user ) { + getUserData(); + } + }; + }, [user]); + + const getUsernameFromUser = async () => { + if (searchParams.get('username')) { + const res = await axios.post('/api/rest/v1/isUsername', {username: searchParams.get('username')}); + if (!res.data.state) { + axios.post('/api/rest/v1/users?option=insert', {id: user?.id, username: searchParams.get('username')}) + .then((res) => { + if (res.data.error) { + setError(res.data.error); + return {error: res.data.error}; + } + setUsername(searchParams.get('username')); + }) + return {error: null}; + } + } + setUsernameInput(true); + return {error: null}; + } + + let getUserData = useCallback(async () => { + try { + if (!user) throw new Error('No user on the session'); + + const { data, error, status } = await supabase + .from('users') + .select('username') + .eq('id', user.id) + .single(); + + if (status === 406) { + const { error } = await getUsernameFromUser() + if (error) throw error;return; + } + if (error && status !== 406 ) throw error; + if (data) { + setUsername(data.username); + } + } + catch (error: any) { + console.log(error.message); + } + finally { + setLoading(false); + } + }, [user]); + + const logout = async () => { + setLogout(true); + axios.get('/api/logout') + .then(() => { + router.push('/auth'); + }) + } -export default async function Page() { - const { data : {user}} = await supabase.auth.getUser(); - const { data, error } = await supabase.from('users').select('username').eq('id', user?.id); - const userdata = data && data[0]; - const username = userdata && ( 'username' in userdata && userdata.username || user?.identities); - const Logout = async () => { - const { error } = await supabase.auth.signOut(); - if (error) console.error('Sign out error', error.message); - window.location.reload(); - }; return ( -
-

Welcome, {username}

- -
+ loggingoff ? + ( + + ):( + <> + {usernameInput ? ( + + ):( + <> + +
+ + )} + {error && } + + ) ); } \ No newline at end of file diff --git a/src/app/globals.css b/src/app/globals.css index 6aef8af..32f1f7c 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -6,19 +6,22 @@ :root { --background: #201F31; --foreground: #fcfdff; - --card: #ffffff; - --card-foreground: #1d0209; + --card: #201F31; + --card-foreground: #fcfdff; --popover: #ffffff; --popover-foreground: #1d0209; --primary: #ffbade; --primary-foreground: #1c2230; - --secondary: #f0f4f8; - --secondary-foreground: #201F31; + --secondary: #1c1b2b; + --secondary-foreground: #fcfdff; --muted: #f0f4f8; + --muted-hover: #e6eaf0; --muted-foreground: #707a8a; --accent: #f0f4f8; + --accent-hover: #e6eaf0; --accent-foreground: #1c2230; - --destructive: #e60000; + --destructive: #751a1a; + --destructive-hover: #8c1f1f; --destructive-foreground: #fcfdff; --border: #e6eaf0; --input: #e6eaf0; @@ -30,41 +33,19 @@ --chart-4: #ffcc33; --chart-5: #ff9933; } - - .dark { - --background: #201F31; - --foreground: #fcfdff; - --card: #0d020a; - --card-foreground: #fcfdff; - --popover: #0d020a; - --popover-foreground: #fcfdff; - --primary: #ffbade; - --primary-foreground: #1c2230; - --secondary: #2a2f3d; - --secondary-foreground: #fcfdff; - --muted: #2a2f3d; - --muted-foreground: #a4a9b5; - --accent: #2a2f3d; - --accent-foreground: #fcfdff; - --destructive: #e60000; - --destructive-foreground: #fcfdff; - --border: #2a2f3d; - --input: #2a2f3d; - --ring: #d9e1f2; - --chart-1: #5a9fd3; - --chart-2: #4c9a70; - --chart-3: #e6a23c; - --chart-4: #8a5aa2; - --chart-5: #d64161; - } } @layer base { * { @apply border-border; } + body { - @apply bg-background text-foreground; + @apply bg-background text-foreground font-body; + } + + h1, h2, h3, h4, h5, h6 { + @apply font-heading; } } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 3fbafd1..39afd73 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -5,10 +5,23 @@ import { Inter } from "next/font/google"; import "./globals.css"; import { Analytics } from "@vercel/analytics/react" import { SpeedInsights } from "@vercel/speed-insights/next" +import { cn } from "@/lib/utils" import Navbar from "@/components/navbar" const inter = Inter({ subsets: ["latin"] }); +const fontHeading = Inter({ + subsets: ['latin'], + display: 'swap', + variable: '--font-heading', +}) + +const fontBody = Inter({ + subsets: ['latin'], + display: 'swap', + variable: '--font-body', +}) + export const metadata: Metadata = { title: "Create Next App", description: "Generated by create next app", @@ -28,9 +41,12 @@ export default function RootLayout({ content="width=device-width, initial-scale=1, shrink-to-fit=no" /> - - - + + }>{children} diff --git a/src/components/error_dialog.tsx b/src/components/error_dialog.tsx new file mode 100644 index 0000000..caca38e --- /dev/null +++ b/src/components/error_dialog.tsx @@ -0,0 +1,96 @@ + +import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog" +import { useRouter } from "next/navigation" +import { Button } from "@/components/ui/button" +import { JSX, SVGProps } from "react" +import PropsTypes from "prop-types" + + +ErrorDialog.propTypes = { + status: PropsTypes.number, + error: PropsTypes.string +} + +ErrorDialog.defaultProps = { + status: 500, + error: null, + error_message: "unknown" +} + +export default function ErrorDialog({ status, error, error_message} : { status: number, error: string | null, error_message: string }) { + const router = useRouter() + const ReportError = () => { + if( !window.location.href.includes('report') ) { + router.push(`/report?status=${status}&error=${!error?error_message:error}&path=${window.location.href}`) + } + } + return ( + + +
+
+ +

Oops, something went wrong!

+
+
+
+ + +
+ + Oops, something went wrong! +
+ + {error_message == "unknown" ? "We're sorry, but an unexpected error has occurred. Please try again later or contact support if the issue persists." : error_message} + +
+ + + + +
+
+ ) +} + +function TriangleAlertIcon(props: JSX.IntrinsicAttributes & SVGProps) { + return ( + + + + + + ) +} + + +function XIcon(props: JSX.IntrinsicAttributes & SVGProps) { + return ( + + + + + ) +} \ No newline at end of file diff --git a/src/components/ui/alertv2.tsx b/src/components/ui/alertv2.tsx new file mode 100644 index 0000000..41fa7e0 --- /dev/null +++ b/src/components/ui/alertv2.tsx @@ -0,0 +1,59 @@ +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const alertVariants = cva( + "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", + { + variants: { + variant: { + default: "bg-background text-foreground", + destructive: + "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +const Alert = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes & VariantProps +>(({ className, variant, ...props }, ref) => ( +
+)) +Alert.displayName = "Alert" + +const AlertTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +AlertTitle.displayName = "AlertTitle" + +const AlertDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +AlertDescription.displayName = "AlertDescription" + +export { Alert, AlertTitle, AlertDescription } diff --git a/src/components/ui/avatar.tsx b/src/components/ui/avatar.tsx new file mode 100644 index 0000000..30a6485 --- /dev/null +++ b/src/components/ui/avatar.tsx @@ -0,0 +1,50 @@ +"use client" + +import * as React from "react" +import * as AvatarPrimitive from "@radix-ui/react-avatar" + +import { cn } from "@/lib/utils" + +const Avatar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +Avatar.displayName = AvatarPrimitive.Root.displayName + +const AvatarImage = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AvatarImage.displayName = AvatarPrimitive.Image.displayName + +const AvatarFallback = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName + +export { Avatar, AvatarImage, AvatarFallback } diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index 53250fd..c7102e4 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -5,22 +5,22 @@ import { cva, type VariantProps } from "class-variance-authority" import { cn } from "@/lib/utils" const buttonVariants = cva( - "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none", + "inline-flex items-center justify-center whitespace-nowrap rounded-md text-md font-medium ring-offset-background transition-colors focus-visible:outline-none disabled:pointer-events-none", { variants: { variant: { - default: "bg-primary text-primary-foreground hover:bg-primary/90", + default: "bg-primary text-primary-foreground hover:bg-primary-hover", destructive: - "bg-destructive text-destructive-foreground hover:bg-destructive/90", + "bg-destructive text-destructive-foreground hover:bg-destructive-hover", outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground", secondary: - "bg-secondary text-secondary-foreground hover:bg-secondary/80", - ghost: "hover:bg-accent hover:text-accent-foreground", + "bg-secondary text-secondary-foreground hover:bg-secondary", + ghost: "hover:bg-accent hover:text-accent-foreground", link: "text-primary underline-offset-4 hover:underline", }, size: { - default: "h-10 px-4 py-2", + default: "h-10 px-4 py-6", sm: "h-9 rounded-md px-3", lg: "h-11 rounded-md px-8", icon: "h-10 w-10", diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx new file mode 100644 index 0000000..afa13ec --- /dev/null +++ b/src/components/ui/card.tsx @@ -0,0 +1,79 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +Card.displayName = "Card" + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardHeader.displayName = "CardHeader" + +const CardTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardTitle.displayName = "CardTitle" + +const CardDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardDescription.displayName = "CardDescription" + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardContent.displayName = "CardContent" + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardFooter.displayName = "CardFooter" + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx new file mode 100644 index 0000000..01ff19c --- /dev/null +++ b/src/components/ui/dialog.tsx @@ -0,0 +1,122 @@ +"use client" + +import * as React from "react" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { X } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Dialog = DialogPrimitive.Root + +const DialogTrigger = DialogPrimitive.Trigger + +const DialogPortal = DialogPrimitive.Portal + +const DialogClose = DialogPrimitive.Close + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)) +DialogContent.displayName = DialogPrimitive.Content.displayName + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogHeader.displayName = "DialogHeader" + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogFooter.displayName = "DialogFooter" + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogTitle.displayName = DialogPrimitive.Title.displayName + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogDescription.displayName = DialogPrimitive.Description.displayName + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogClose, + DialogTrigger, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +} diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..f69a0d6 --- /dev/null +++ b/src/components/ui/dropdown-menu.tsx @@ -0,0 +1,200 @@ +"use client" + +import * as React from "react" +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" +import { Check, ChevronRight, Circle } from "lucide-react" + +import { cn } from "@/lib/utils" + +const DropdownMenu = DropdownMenuPrimitive.Root + +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger + +const DropdownMenuGroup = DropdownMenuPrimitive.Group + +const DropdownMenuPortal = DropdownMenuPrimitive.Portal + +const DropdownMenuSub = DropdownMenuPrimitive.Sub + +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup + +const DropdownMenuSubTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, children, ...props }, ref) => ( + + {children} + + +)) +DropdownMenuSubTrigger.displayName = + DropdownMenuPrimitive.SubTrigger.displayName + +const DropdownMenuSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DropdownMenuSubContent.displayName = + DropdownMenuPrimitive.SubContent.displayName + +const DropdownMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + + + +)) +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName + +const DropdownMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName + +const DropdownMenuCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, checked, ...props }, ref) => ( + + + + + + + {children} + +)) +DropdownMenuCheckboxItem.displayName = + DropdownMenuPrimitive.CheckboxItem.displayName + +const DropdownMenuRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)) +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName + +const DropdownMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName + +const DropdownMenuSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName + +const DropdownMenuShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ) +} +DropdownMenuShortcut.displayName = "DropdownMenuShortcut" + +export { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuGroup, + DropdownMenuPortal, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuRadioGroup, +} diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx index 8b55b6a..8d953bd 100644 --- a/src/components/ui/input.tsx +++ b/src/components/ui/input.tsx @@ -12,7 +12,7 @@ const Input = React.forwardRef( { + async function getLoader() { + const { ring } = await import('ldrs') + ring.register() + } + getLoader() + }, []) + return ( + + ) +} \ No newline at end of file diff --git a/src/utils/supabase/middleware.ts b/src/utils/supabase/middleware.ts index 608131a..cce4279 100644 --- a/src/utils/supabase/middleware.ts +++ b/src/utils/supabase/middleware.ts @@ -1,5 +1,5 @@ import { createServerClient, type CookieOptions } from '@supabase/ssr' -import { NextResponse, type NextRequest } from 'next/server' +import { NextRequest, NextResponse } from 'next/server' export async function updateSession(request: NextRequest) { let response = NextResponse.next({ @@ -54,18 +54,45 @@ export async function updateSession(request: NextRequest) { } ) - const { data: {user}} = await supabase.auth.getUser() - if (user && !user?.confirmed_at && request.nextUrl.pathname === '/form_create') { - response = NextResponse.redirect(new URL('/auth/confirm_email', request.nextUrl.href)) - } else if (user?.confirmed_at && request.nextUrl.pathname === '/auth/confirm_email') { - response = NextResponse.redirect(new URL('/form_create', request.nextUrl.href)) - } else if (user && request.nextUrl.pathname === '/auth') { + + if (request.nextUrl.pathname === '/auth/callback' || request.nextUrl.pathname === '/auth/confirm') return response + + + let { data: {user}, error} = await supabase.auth.getUser() + + + if (user && (request.nextUrl.pathname === '/auth/confirm_email' || request.nextUrl.pathname === '/auth')) { response = NextResponse.redirect(new URL('/form_create', request.nextUrl.href)) - } else if (!user && request.nextUrl.pathname === '/form_create') { + } else if (!user && ( request.nextUrl.pathname === '/form_create' )) { response = NextResponse.redirect(new URL('/auth', request.nextUrl.href)) }else if (!user && request.nextUrl.pathname === '/test_api') { response = NextResponse.redirect(new URL('/auth', request.nextUrl.href)) } + // const searchParams = request.nextUrl.searchParams + + // if (request.nextUrl.pathname === '/auth/confirm_email') { + // if (searchParams.get('user_email')) { + // if (!searchParams.get('id')) return NextResponse.redirect(new URL('/auth?error=No+ID+provided', request.nextUrl.href)) + // let res = await fetch(`${process.env.NEXT_PUBLIC_SUPABASE_URL}/auth/v1/admin/users/${searchParams.get('id')}`, { + // method: 'GET', + // headers: { + // "apikey": process.env.SERVICE_KEY!, + // "Authorization": `Bearer ${process.env.SERVICE_KEY!}`, + // "Content-Type": "application/json", + // } + // }); + + // const res_user = await res.json(); + // if (res.status === 404 || !res_user?.email ) return NextResponse.redirect(new URL('/auth?error=user+not+found', request.nextUrl.href)) + // if ( request.nextUrl.searchParams.get('user_email') !== res_user?.email ) { + // request.nextUrl.searchParams.set('user_email', res_user?.email as string) + // response = NextResponse.redirect(new URL(request.nextUrl.href)) + // return response + // } + // if (res_user?.email_confirmed_at) return NextResponse.redirect(new URL('/auth?auth=login', request.nextUrl.href)) + // } + // } + return response } \ No newline at end of file diff --git a/tailwind.config.ts b/tailwind.config.ts index f1b8c32..a3c9505 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,4 +1,5 @@ import type { Config } from "tailwindcss"; +import { fontFamily } from "tailwindcss/defaultTheme"; const config: Config = { content: [ @@ -8,12 +9,15 @@ const config: Config = { ], theme: { extend: { + fontFamily: { + heading: ['var(--font-heading)', ...fontFamily.sans], + body: ['var(--font-body)', ...fontFamily.sans], + }, backgroundImage: { "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", "gradient-conic": "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", }, - }, colors: { "border": "var(--border)", "input": "var(--input)", @@ -30,6 +34,7 @@ const config: Config = { }, "destructive": { "DEFAULT": "var(--destructive)", + "hover": "var(--destructive-hover)", "foreground": "var(--destructive-foreground)" }, "muted": { @@ -38,6 +43,7 @@ const config: Config = { }, "accent": { "DEFAULT": "var(--accent)", + "hover": "var(--accent-hover)", "foreground": "var(--accent-foreground)" }, "popover": { @@ -72,6 +78,7 @@ const config: Config = { } } } + }, }, plugins: [ require("tailwindcss-animate"),