NORY-1: add user session management (#5)
This commit is contained in:
commit
f62e915b98
9 changed files with 934 additions and 143 deletions
|
@ -7,6 +7,9 @@ const withSerwist = withSerwistInit({
|
|||
|
||||
export default withSerwist({
|
||||
output: 'standalone',
|
||||
experimental: {
|
||||
missingSuspenseWithCSRBailout: false,
|
||||
},
|
||||
env: {
|
||||
appVersion: process.env.npm_package_version,
|
||||
},
|
||||
|
|
527
authentication/package-lock.json
generated
527
authentication/package-lock.json
generated
|
@ -30,6 +30,7 @@
|
|||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"react-hook-form": "^7.51.0",
|
||||
"sharp": "^0.33.4",
|
||||
"sonner": "^1.4.3",
|
||||
"tailwind-merge": "^2.2.1",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
|
@ -102,6 +103,15 @@
|
|||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/runtime": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.2.0.tgz",
|
||||
"integrity": "sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint-community/eslint-utils": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
|
||||
|
@ -233,6 +243,437 @@
|
|||
"integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@img/sharp-darwin-arm64": {
|
||||
"version": "0.33.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.4.tgz",
|
||||
"integrity": "sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.26",
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-darwin-arm64": "1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-darwin-x64": {
|
||||
"version": "0.33.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.4.tgz",
|
||||
"integrity": "sha512-0l7yRObwtTi82Z6ebVI2PnHT8EB2NxBgpK2MiKJZJ7cz32R4lxd001ecMhzzsZig3Yv9oclvqqdV93jo9hy+Dw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.26",
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-darwin-x64": "1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-darwin-arm64": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.2.tgz",
|
||||
"integrity": "sha512-tcK/41Rq8IKlSaKRCCAuuY3lDJjQnYIW1UXU1kxcEKrfL8WR7N6+rzNoOxoQRJWTAECuKwgAHnPvqXGN8XfkHA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"macos": ">=11",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-darwin-x64": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.2.tgz",
|
||||
"integrity": "sha512-Ofw+7oaWa0HiiMiKWqqaZbaYV3/UGL2wAPeLuJTx+9cXpCRdvQhCLG0IH8YGwM0yGWGLpsF4Su9vM1o6aer+Fw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"macos": ">=10.13",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-arm": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.2.tgz",
|
||||
"integrity": "sha512-iLWCvrKgeFoglQxdEwzu1eQV04o8YeYGFXtfWU26Zr2wWT3q3MTzC+QTCO3ZQfWd3doKHT4Pm2kRmLbupT+sZw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.28",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-arm64": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.2.tgz",
|
||||
"integrity": "sha512-x7kCt3N00ofFmmkkdshwj3vGPCnmiDh7Gwnd4nUwZln2YjqPxV1NlTyZOvoDWdKQVDL911487HOueBvrpflagw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.26",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-s390x": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.2.tgz",
|
||||
"integrity": "sha512-cmhQ1J4qVhfmS6szYW7RT+gLJq9dH2i4maq+qyXayUSn9/3iY2ZeWpbAgSpSVbV2E1JUL2Gg7pwnYQ1h8rQIog==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.28",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-x64": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.2.tgz",
|
||||
"integrity": "sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.26",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.2.tgz",
|
||||
"integrity": "sha512-3CAkndNpYUrlDqkCM5qhksfE+qSIREVpyoeHIU6jd48SJZViAmznoQQLAv4hVXF7xyUB9zf+G++e2v1ABjCbEQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"musl": ">=1.2.2",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.2.tgz",
|
||||
"integrity": "sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"musl": ">=1.2.2",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-arm": {
|
||||
"version": "0.33.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.4.tgz",
|
||||
"integrity": "sha512-RUgBD1c0+gCYZGCCe6mMdTiOFS0Zc/XrN0fYd6hISIKcDUbAW5NtSQW9g/powkrXYm6Vzwd6y+fqmExDuCdHNQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.28",
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-arm": "1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-arm64": {
|
||||
"version": "0.33.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.4.tgz",
|
||||
"integrity": "sha512-2800clwVg1ZQtxwSoTlHvtm9ObgAax7V6MTAB/hDT945Tfyy3hVkmiHpeLPCKYqYR1Gcmv1uDZ3a4OFwkdBL7Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.26",
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-arm64": "1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-s390x": {
|
||||
"version": "0.33.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.4.tgz",
|
||||
"integrity": "sha512-h3RAL3siQoyzSoH36tUeS0PDmb5wINKGYzcLB5C6DIiAn2F3udeFAum+gj8IbA/82+8RGCTn7XW8WTFnqag4tQ==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.31",
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-s390x": "1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-x64": {
|
||||
"version": "0.33.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.4.tgz",
|
||||
"integrity": "sha512-GoR++s0XW9DGVi8SUGQ/U4AeIzLdNjHka6jidVwapQ/JebGVQIpi52OdyxCNVRE++n1FCLzjDovJNozif7w/Aw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"glibc": ">=2.26",
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-x64": "1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linuxmusl-arm64": {
|
||||
"version": "0.33.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.4.tgz",
|
||||
"integrity": "sha512-nhr1yC3BlVrKDTl6cO12gTpXMl4ITBUZieehFvMntlCXFzH2bvKG76tBL2Y/OqhupZt81pR7R+Q5YhJxW0rGgQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"musl": ">=1.2.2",
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linuxmusl-x64": {
|
||||
"version": "0.33.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.4.tgz",
|
||||
"integrity": "sha512-uCPTku0zwqDmZEOi4ILyGdmW76tH7dm8kKlOIV1XC5cLyJ71ENAAqarOHQh0RLfpIpbV5KOpXzdU6XkJtS0daw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"musl": ">=1.2.2",
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-wasm32": {
|
||||
"version": "0.33.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.4.tgz",
|
||||
"integrity": "sha512-Bmmauh4sXUsUqkleQahpdNXKvo+wa1V9KhT2pDA4VJGKwnKMJXiSTGphn0gnJrlooda0QxCtXc6RX1XAU6hMnQ==",
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/runtime": "^1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-win32-ia32": {
|
||||
"version": "0.33.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.4.tgz",
|
||||
"integrity": "sha512-99SJ91XzUhYHbx7uhK3+9Lf7+LjwMGQZMDlO/E/YVJ7Nc3lyDFZPGhjwiYdctoH2BOzW9+TnfqcaMKt0jHLdqw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-win32-x64": {
|
||||
"version": "0.33.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.4.tgz",
|
||||
"integrity": "sha512-3QLocdTRVIrFNye5YocZl+KKpYKP+fksi1QhmOArgx7GyhIbQp/WrJRu176jm8IxromS7RIkzMiMINVdBtC8Aw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
|
||||
"npm": ">=9.6.5",
|
||||
"pnpm": ">=7.1.0",
|
||||
"yarn": ">=3.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/cliui": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
||||
|
@ -2552,6 +2993,18 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/color": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
|
||||
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1",
|
||||
"color-string": "^1.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
|
@ -2568,6 +3021,15 @@
|
|||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"node_modules/color-string": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
|
||||
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
|
||||
"dependencies": {
|
||||
"color-name": "^1.0.0",
|
||||
"simple-swizzle": "^0.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
|
@ -2741,6 +3203,14 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
|
||||
"integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-node-es": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
|
||||
|
@ -4073,6 +4543,11 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-arrayish": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
|
||||
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
|
||||
},
|
||||
"node_modules/is-async-function": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz",
|
||||
|
@ -5860,7 +6335,6 @@
|
|||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
|
@ -5875,7 +6349,6 @@
|
|||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
|
@ -5920,6 +6393,45 @@
|
|||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/sharp": {
|
||||
"version": "0.33.4",
|
||||
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.4.tgz",
|
||||
"integrity": "sha512-7i/dt5kGl7qR4gwPRD2biwD2/SvBn3O04J77XKFgL2OnZtQw+AG9wnuS/csmu80nPRHLYE9E41fyEiG8nhH6/Q==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"color": "^4.2.3",
|
||||
"detect-libc": "^2.0.3",
|
||||
"semver": "^7.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"libvips": ">=8.15.2",
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-darwin-arm64": "0.33.4",
|
||||
"@img/sharp-darwin-x64": "0.33.4",
|
||||
"@img/sharp-libvips-darwin-arm64": "1.0.2",
|
||||
"@img/sharp-libvips-darwin-x64": "1.0.2",
|
||||
"@img/sharp-libvips-linux-arm": "1.0.2",
|
||||
"@img/sharp-libvips-linux-arm64": "1.0.2",
|
||||
"@img/sharp-libvips-linux-s390x": "1.0.2",
|
||||
"@img/sharp-libvips-linux-x64": "1.0.2",
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.0.2",
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.0.2",
|
||||
"@img/sharp-linux-arm": "0.33.4",
|
||||
"@img/sharp-linux-arm64": "0.33.4",
|
||||
"@img/sharp-linux-s390x": "0.33.4",
|
||||
"@img/sharp-linux-x64": "0.33.4",
|
||||
"@img/sharp-linuxmusl-arm64": "0.33.4",
|
||||
"@img/sharp-linuxmusl-x64": "0.33.4",
|
||||
"@img/sharp-wasm32": "0.33.4",
|
||||
"@img/sharp-win32-ia32": "0.33.4",
|
||||
"@img/sharp-win32-x64": "0.33.4"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
|
@ -5968,6 +6480,14 @@
|
|||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-swizzle": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
|
||||
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
|
||||
"dependencies": {
|
||||
"is-arrayish": "^0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/slash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
|
@ -6995,8 +7515,7 @@
|
|||
"node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.4.1",
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
"@radix-ui/react-scroll-area": "^1.0.5",
|
||||
"@radix-ui/react-separator": "^1.0.3",
|
||||
"@radix-ui/react-slot": "^1.0.2",
|
||||
"@radix-ui/react-tabs": "^1.1.1",
|
||||
"@serwist/next": "^9.0.0-preview.21",
|
||||
"@serwist/precaching": "^9.0.0-preview.21",
|
||||
"@serwist/sw": "^9.0.0-preview.21",
|
||||
|
@ -31,9 +32,11 @@
|
|||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"react-hook-form": "^7.51.0",
|
||||
"sharp": "^0.33.4",
|
||||
"sonner": "^1.4.3",
|
||||
"tailwind-merge": "^2.2.1",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"ua-parser-js": "^2.0.0",
|
||||
"usehooks-ts": "^3.1.0",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
'use client';
|
||||
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { SettingsFlow, UpdateSettingsFlowBody } from '@ory/client';
|
||||
import { kratos } from '@/ory/sdk/kratos';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import AccountSettings from '@/components/accountSettings';
|
||||
import { HandleError, kratos, LogoutLink } from '@/ory';
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import { toast } from 'sonner';
|
||||
import { AxiosError } from 'axios';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Flow, HandleError, LogoutLink } from '@/ory';
|
||||
import { ThemeToggle } from '@/components/themeToggle';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { LogOut } from 'lucide-react';
|
||||
import AccountSessions from '@/components/accountSessions';
|
||||
import { AxiosError } from 'axios';
|
||||
import { SettingsFlow, UpdateSettingsFlowBody } from '@ory/client';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
export default function Home() {
|
||||
export default function Page() {
|
||||
|
||||
const onLogout = LogoutLink();
|
||||
|
||||
const [flow, setFlow] = useState<SettingsFlow>();
|
||||
|
||||
|
@ -22,8 +25,6 @@ export default function Home() {
|
|||
const returnTo = params.get('return_to') ?? undefined;
|
||||
const flowId = params.get('flow') ?? undefined;
|
||||
|
||||
const onLogout = LogoutLink();
|
||||
|
||||
const getFlow = useCallback((flowId: string) => {
|
||||
return kratos
|
||||
.getSettingsFlow({ id: String(flowId) })
|
||||
|
@ -41,7 +42,7 @@ export default function Home() {
|
|||
.createBrowserSettingsFlow({ returnTo })
|
||||
.then(({ data }) => {
|
||||
setFlow(data);
|
||||
router.push(`?flow=${data.id}`);
|
||||
addQueryParam('flow', data.id);
|
||||
})
|
||||
.catch(handleError);
|
||||
}, [handleError]);
|
||||
|
@ -98,6 +99,14 @@ export default function Home() {
|
|||
|
||||
}, [flowId, router, returnTo, createFlow, getFlow]);
|
||||
|
||||
const addQueryParam = useCallback((name: string, value: string) => {
|
||||
const newParams = new URLSearchParams(params.toString());
|
||||
newParams.set(name, value);
|
||||
router.push('?' + newParams.toString());
|
||||
},
|
||||
[params],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col min-h-screen items-center text-3xl relative space-y-4">
|
||||
<div className="absolute flex flex-row w-fit items-center space-x-4 top-4 right-4">
|
||||
|
@ -106,135 +115,23 @@ export default function Home() {
|
|||
<LogOut className="h-[1.2rem] w-[1.2rem]"/>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-col items-center space-y-4 w-full max-w-md">
|
||||
<p className="mt-4 py-4 text-4xl">Settings</p>
|
||||
{
|
||||
flow?.ui.nodes.some(({ group }) => group === 'profile') && (
|
||||
<Card className="w-full max-w-md animate-fadeIn">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
Password
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Flow
|
||||
onSubmit={updateFlow}
|
||||
flow={flow}
|
||||
only="profile"
|
||||
hideGlobalMessages/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
{
|
||||
flow?.ui.nodes.some(({ group }) => group === 'password') && (
|
||||
<Card className="w-full max-w-md animate-fadeIn">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
Password
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Flow
|
||||
onSubmit={updateFlow}
|
||||
flow={flow}
|
||||
only="password"
|
||||
hideGlobalMessages/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
{
|
||||
flow?.ui.nodes.some(({ group }) => group === 'totp') && (
|
||||
<Card className="w-full max-w-md animate-fadeIn">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
MFA
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Flow
|
||||
onSubmit={updateFlow}
|
||||
flow={flow}
|
||||
only="totp"
|
||||
hideGlobalMessages/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
{
|
||||
flow?.ui.nodes.some(({ group }) => group === 'oidc') && (
|
||||
<Card className="w-full max-w-md animate-fadeIn">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
Connect Socials
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Flow
|
||||
onSubmit={updateFlow}
|
||||
flow={flow}
|
||||
only="oidc"
|
||||
hideGlobalMessages/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
{
|
||||
flow?.ui.nodes.some(({ group }) => group === 'link') && (
|
||||
<Card className="w-full max-w-md animate-fadeIn">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
Connect Socials
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Flow
|
||||
onSubmit={updateFlow}
|
||||
flow={flow}
|
||||
only="link"
|
||||
hideGlobalMessages/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
{
|
||||
flow?.ui.nodes.some(({ group }) => group === 'webauthn') && (
|
||||
<Card className="w-full max-w-md animate-fadeIn">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
Connect Socials
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Flow
|
||||
onSubmit={updateFlow}
|
||||
flow={flow}
|
||||
only="webauthn"
|
||||
hideGlobalMessages/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
{
|
||||
flow?.ui.nodes.some(({ group }) => group === 'lookup_secret') && (
|
||||
<Card className="w-full max-w-md animate-fadeIn">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
Recovery Codes
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Flow
|
||||
onSubmit={updateFlow}
|
||||
flow={flow}
|
||||
only="lookup_secret"
|
||||
hideGlobalMessages/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<Tabs
|
||||
defaultValue="account"
|
||||
value={params.get('tab') ?? undefined}
|
||||
className="w-full max-w-md"
|
||||
onValueChange={(value) => addQueryParam('tab', value)}>
|
||||
<TabsList className="grid w-full grid-cols-2 mt-16">
|
||||
<TabsTrigger value="account">Account</TabsTrigger>
|
||||
<TabsTrigger value="sessions">Sessions</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="account" className="mb-16">
|
||||
<AccountSettings flow={flow} updateFlow={updateFlow}/>
|
||||
</TabsContent>
|
||||
<TabsContent value="sessions" className="mb-16">
|
||||
<AccountSessions/>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
|
|
79
authentication/src/components/accountSessions.tsx
Normal file
79
authentication/src/components/accountSessions.tsx
Normal file
|
@ -0,0 +1,79 @@
|
|||
'use client';
|
||||
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { kratos } from '@/ory';
|
||||
import { Session } from '@ory/client';
|
||||
import SessionItem from '@/components/sessionItem';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
|
||||
export default function AccountSessions() {
|
||||
|
||||
const [current, setCurrent] = useState<Session>();
|
||||
const [sessions, setSessions] = useState<Session[]>();
|
||||
|
||||
const invalidateSession = useCallback(async (id: string) => {
|
||||
|
||||
console.log('Disabling session with id', id);
|
||||
|
||||
kratos.disableMySession({ id: id })
|
||||
.then(() => console.log('Disabled session with id', id))
|
||||
.catch(() => console.error('Error while disabling session with id', id))
|
||||
.finally(() => {
|
||||
loadSessions().then((response) => {
|
||||
setCurrent(response.current);
|
||||
setSessions(response.sessions);
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
|
||||
const loadSessions = useCallback(async () => {
|
||||
|
||||
console.log('Refreshing sessions');
|
||||
|
||||
const current = await kratos.toSession();
|
||||
const sessions = await kratos.listMySessions();
|
||||
|
||||
console.log(current.data);
|
||||
console.log(sessions.data);
|
||||
|
||||
return {
|
||||
current: current.data,
|
||||
sessions: sessions.data,
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
loadSessions().then(response => {
|
||||
setCurrent(response.current);
|
||||
setSessions(response.sessions);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center space-y-4 w-full max-w-md">
|
||||
{
|
||||
current ?
|
||||
<SessionItem session={current!!} showInvalidate={false} invalidateSession={invalidateSession}/>
|
||||
:
|
||||
<></>
|
||||
}
|
||||
{
|
||||
sessions && sessions.length > 0 ?
|
||||
<Separator/>
|
||||
:
|
||||
<></>
|
||||
}
|
||||
{
|
||||
sessions?.map(item => {
|
||||
return (
|
||||
<SessionItem
|
||||
key={item.id}
|
||||
session={item}
|
||||
showInvalidate={true}
|
||||
invalidateSession={invalidateSession}/>
|
||||
);
|
||||
})
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
145
authentication/src/components/accountSettings.tsx
Normal file
145
authentication/src/components/accountSettings.tsx
Normal file
|
@ -0,0 +1,145 @@
|
|||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import { SettingsFlow, UpdateSettingsFlowBody } from '@ory/client';
|
||||
import { Flow } from '@/ory';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
|
||||
interface AccountSettingsProps {
|
||||
flow: SettingsFlow | undefined;
|
||||
updateFlow: (body: UpdateSettingsFlowBody) => Promise<void>;
|
||||
}
|
||||
|
||||
export default function AccountSettings({ flow, updateFlow }: AccountSettingsProps) {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center space-y-4 w-full max-w-md">
|
||||
{
|
||||
flow?.ui.nodes.some(({ group }) => group === 'profile') && (
|
||||
<Card className="w-full max-w-md animate-fadeIn">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
Profile
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Flow
|
||||
onSubmit={updateFlow}
|
||||
flow={flow}
|
||||
only="profile"
|
||||
hideGlobalMessages/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
{
|
||||
flow?.ui.nodes.some(({ group }) => group === 'password') && (
|
||||
<Card className="w-full max-w-md animate-fadeIn">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
Password
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Flow
|
||||
onSubmit={updateFlow}
|
||||
flow={flow}
|
||||
only="password"
|
||||
hideGlobalMessages/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
{
|
||||
flow?.ui.nodes.some(({ group }) => group === 'totp') && (
|
||||
<Card className="w-full max-w-md animate-fadeIn">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
MFA
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Flow
|
||||
onSubmit={updateFlow}
|
||||
flow={flow}
|
||||
only="totp"
|
||||
hideGlobalMessages/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
{
|
||||
flow?.ui.nodes.some(({ group }) => group === 'oidc') && (
|
||||
<Card className="w-full max-w-md animate-fadeIn">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
Connect Socials
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Flow
|
||||
onSubmit={updateFlow}
|
||||
flow={flow}
|
||||
only="oidc"
|
||||
hideGlobalMessages/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
{
|
||||
flow?.ui.nodes.some(({ group }) => group === 'link') && (
|
||||
<Card className="w-full max-w-md animate-fadeIn">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
Connect Socials
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Flow
|
||||
onSubmit={updateFlow}
|
||||
flow={flow}
|
||||
only="link"
|
||||
hideGlobalMessages/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
{
|
||||
flow?.ui.nodes.some(({ group }) => group === 'webauthn') && (
|
||||
<Card className="w-full max-w-md animate-fadeIn">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
Connect Socials
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Flow
|
||||
onSubmit={updateFlow}
|
||||
flow={flow}
|
||||
only="webauthn"
|
||||
hideGlobalMessages/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
{
|
||||
flow?.ui.nodes.some(({ group }) => group === 'lookup_secret') && (
|
||||
<Card className="w-full max-w-md animate-fadeIn">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
Recovery Codes
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Flow
|
||||
onSubmit={updateFlow}
|
||||
flow={flow}
|
||||
only="lookup_secret"
|
||||
hideGlobalMessages/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
53
authentication/src/components/sessionItem.tsx
Normal file
53
authentication/src/components/sessionItem.tsx
Normal file
|
@ -0,0 +1,53 @@
|
|||
'use client';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { Session, SessionDevice } from '@ory/client';
|
||||
import { Card, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { UAParser } from 'ua-parser-js';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
|
||||
interface SessionItemProps {
|
||||
session: Session;
|
||||
showInvalidate: boolean;
|
||||
invalidateSession: (id: string) => void;
|
||||
}
|
||||
|
||||
export default function SessionItem({ session, showInvalidate, invalidateSession }: SessionItemProps) {
|
||||
|
||||
if (!session.devices || session.devices.length < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [device] = useState<SessionDevice>(session.devices[0]);
|
||||
|
||||
const parser = new UAParser(device.user_agent);
|
||||
const result = parser.getResult();
|
||||
|
||||
return (
|
||||
<Card className="relative w-full">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
{result.os.name}
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
{result.browser.name}, version {result.browser.version} <br/>
|
||||
Signed in since {new Date(session.authenticated_at!!).toLocaleString()}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
{
|
||||
showInvalidate ?
|
||||
<Button
|
||||
className="absolute top-4 right-4"
|
||||
onClick={() => invalidateSession(session.id)}>
|
||||
Invalidate
|
||||
</Button>
|
||||
:
|
||||
<Badge
|
||||
className="absolute top-4 right-4">
|
||||
This session
|
||||
</Badge>
|
||||
}
|
||||
</Card>
|
||||
);
|
||||
}
|
37
authentication/src/components/ui/badge.tsx
Normal file
37
authentication/src/components/ui/badge.tsx
Normal file
|
@ -0,0 +1,37 @@
|
|||
import * as React from 'react';
|
||||
import { cva, type VariantProps } from 'class-variance-authority';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const badgeVariants = cva(
|
||||
'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
'border-transparent bg-primary text-primary-foreground hover:bg-primary/80',
|
||||
secondary:
|
||||
'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||
destructive:
|
||||
'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80',
|
||||
outline: 'text-foreground',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
export interface BadgeProps
|
||||
extends React.HTMLAttributes<HTMLDivElement>,
|
||||
VariantProps<typeof badgeVariants> {
|
||||
}
|
||||
|
||||
function Badge({ className, variant, ...props }: BadgeProps) {
|
||||
return (
|
||||
<div className={cn(badgeVariants({ variant }), className)} {...props} />
|
||||
);
|
||||
}
|
||||
|
||||
export { Badge, badgeVariants };
|
55
authentication/src/components/ui/tabs.tsx
Normal file
55
authentication/src/components/ui/tabs.tsx
Normal file
|
@ -0,0 +1,55 @@
|
|||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import * as TabsPrimitive from '@radix-ui/react-tabs';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const Tabs = TabsPrimitive.Root;
|
||||
|
||||
const TabsList = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.List
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
TabsList.displayName = TabsPrimitive.List.displayName;
|
||||
|
||||
const TabsTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
|
||||
|
||||
const TabsContent = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
||||
|
||||
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
Loading…
Add table
Reference in a new issue