diff --git a/src/lib/email-template.tsx b/emails/email-template.tsx similarity index 100% rename from src/lib/email-template.tsx rename to emails/email-template.tsx diff --git a/emails/user-registration-email-template.tsx b/emails/user-registration-email-template.tsx new file mode 100644 index 0000000..9998f99 --- /dev/null +++ b/emails/user-registration-email-template.tsx @@ -0,0 +1,88 @@ +import { tedxsjecAssetsPrefix } from "@/lib/utils"; +import { + Body, + Button, + Container, + Head, + Heading, + Hr, + Html, + Img, + Preview, + Section, + Text, +} from "@react-email/components"; +import { Tailwind } from "@react-email/tailwind"; + +interface TedxRegistrationEmailProps { + name?: string; + registrationLink: string; +} + +export const TedxRegistrationEmail = ({ name, registrationLink }: TedxRegistrationEmailProps) => { + const previewText = `TEDxSJEC Talk Registration Successful!`; + + return ( + + + {previewText} + + + + {/* Logo Section */} +
+ TEDxSJEC Logo +
+ {/* Heading Section */} +
+ + TEDxSJEC Talk Registration Confirmed! + +
+ + Dear {name ?? "Participant"}, + + + We are excited to confirm your registration for TEDxSJEC Talk.
+ You are all set to join us for an inspiring day filled with ideas worth sharing. + Please bring this email on the event day for a smooth entry process. +
+ {/* QR Code Section */} +
+ + Below is your unique QR code for registration. Kindly keep it accessible on + event day for quick check-in: + + QR Code +
+ + We look forward to seeing you at TEDxSJEC!
+
+
+ + Thanks & Regards,
TEDxSJEC Team
+ For any queries, feel free to contact us at: tedxsjec@sjec.ac.in +
+
+ +  |  + +  |  + +
+
+ +
+ + ); +}; + +export default TedxRegistrationEmail; diff --git a/package-lock.json b/package-lock.json index c673e68..85a7ae8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,11 +26,14 @@ "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-tabs": "^1.1.0", "@react-email/components": "^0.0.25", + "@react-email/tailwind": "0.1.0", "@react-three/drei": "^9.114.0", "@tanstack/react-query": "^5.56.2", + "@types/canvas-confetti": "^1.6.4", "@types/ioredis": "^4.28.10", "@types/lodash.debounce": "^4.0.9", "@uploadthing/react": "^7.0.2", + "@yudiel/react-qr-scanner": "^2.0.8", "axios": "^1.7.7", "bullmq": "^5.13.0", "canvas-confetti": "^1.9.3", @@ -46,11 +49,12 @@ "next-auth": "^4.24.7", "nodemailer": "^6.9.15", "otp-generator": "^4.0.1", + "razorpay": "^2.9.4", "react": "^18.3.1", "react-dom": "^18", "react-email": "^3.0.1", - "react-icons": "^5.3.0", "react-hook-form": "^7.53.0", + "react-icons": "^5.3.0", "resend": "^4.0.0", "sonner": "^1.5.0", "tailwind-merge": "^2.5.2", @@ -66,6 +70,7 @@ "@types/otp-generator": "^4.0.2", "@types/react": "^18", "@types/react-dom": "^18", + "@types/react-qr-reader": "^2.1.7", "eslint": "^8", "eslint-config-next": "14.2.6", "postcss": "^8", @@ -3384,7 +3389,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/@react-email/tailwind/-/tailwind-0.1.0.tgz", "integrity": "sha512-qysVUEY+M3SKUvu35XDpzn7yokhqFOT3tPU6Mj/pgc62TL5tQFj6msEbBtwoKs2qO3WZvai0DIHdLhaOxBQSow==", - "license": "MIT", "engines": { "node": ">=18.0.0" }, @@ -3524,7 +3528,6 @@ "version": "8.17.9", "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.17.9.tgz", "integrity": "sha512-uZclikSqDdI15D0t8l8F8fyRyzl6BYwUOlEke2BIjAsjVzQy5MQPROVEc/9/Ef/PAezfl6lrLulMlYwgS1JGIg==", - "license": "MIT", "peer": true, "dependencies": { "@babel/runtime": "^7.17.8", @@ -3589,7 +3592,6 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "peer": true, "dependencies": { "base64-js": "^1.3.1", @@ -3600,7 +3602,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", - "license": "MIT", "peer": true }, "node_modules/@rushstack/eslint-patch": { @@ -3762,15 +3763,24 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/@types/debounce/-/debounce-1.2.4.tgz", "integrity": "sha512-jBqiORIzKDOToaF63Fm//haOCHuwQuLa2202RK4MozpA6lh93eCBc+/8+wZn5OzjJt3ySdc+74SXWXB55Ewtyw==", - "license": "MIT", "peer": true }, + "node_modules/@types/dom-webcodecs": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/@types/dom-webcodecs/-/dom-webcodecs-0.1.11.tgz", + "integrity": "sha512-yPEZ3z7EohrmOxbk/QTAa0yonMFkNkjnVXqbGb7D4rMr+F1dGQ8ZUFxXkyLLJuiICPejZ0AZE9Rrk9wUCczx4A==" + }, "node_modules/@types/draco3d": { "version": "1.4.10", "resolved": "https://registry.npmjs.org/@types/draco3d/-/draco3d-1.4.10.tgz", "integrity": "sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==", "license": "MIT" }, + "node_modules/@types/emscripten": { + "version": "1.39.13", + "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.13.tgz", + "integrity": "sha512-cFq+fO/isvhvmuP/+Sl4K4jtU6E23DoivtbO4r50e3odaxAiVdbfSYRDdJ4gCdxx+3aRjhphS5ZMwIH4hFy/Cw==" + }, "node_modules/@types/graceful-fs": { "version": "4.1.9", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", @@ -3886,11 +3896,19 @@ "@types/react": "*" } }, + "node_modules/@types/react-qr-reader": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/react-qr-reader/-/react-qr-reader-2.1.7.tgz", + "integrity": "sha512-6K6DQeqP7c2oohcfvBpExlOawVsB2/C+7ZZL/fkCkNzYYAKDJnNHnuP3F5ChMl0mpoYEdqkqkllxqfM0VslEiw==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-reconciler": { "version": "0.26.7", "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.26.7.tgz", "integrity": "sha512-mBDYl8x+oyPX/VBb3E638N0B7xG+SPk/EAMcVPeexqus/5aTpTphQi0curhhshOqRrc9t6OPoJfEUkbymse/lQ==", - "license": "MIT", "peer": true, "dependencies": { "@types/react": "*" @@ -3912,7 +3930,6 @@ "version": "0.169.0", "resolved": "https://registry.npmjs.org/@types/three/-/three-0.169.0.tgz", "integrity": "sha512-oan7qCgJBt03wIaK+4xPWclYRPG9wzcg7Z2f5T8xYTNEF95kh0t0lklxLLYBDo7gQiGLYzE6iF4ta7nXF2bcsw==", - "license": "MIT", "peer": true, "dependencies": { "@tweenjs/tween.js": "~23.1.3", @@ -4174,9 +4191,21 @@ "version": "0.1.47", "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.47.tgz", "integrity": "sha512-vOUHDxj0azl7BSj4YAy6cc6q5s7F1KfF5GI1er/w6togN0MqzS/d8U+H0LH1XpLbFup+UaA7aMtia/aSx3DE0w==", - "license": "BSD-3-Clause", "peer": true }, + "node_modules/@yudiel/react-qr-scanner": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@yudiel/react-qr-scanner/-/react-qr-scanner-2.0.8.tgz", + "integrity": "sha512-/7WHsdC1a/Z909J2zZxqgpUQ1iI554fZxIagucH/tFu1MhZkNIeykYI1OdZgDEwV4CzuSi+h90wwNrhmETcmRw==", + "dependencies": { + "barcode-detector": "^2.2.7", + "webrtc-adapter": "9.0.1" + }, + "peerDependencies": { + "react": "^17 || ^18", + "react-dom": "^17 || ^18" + } + }, "node_modules/abbrev": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", @@ -4681,6 +4710,15 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/barcode-detector": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-2.2.8.tgz", + "integrity": "sha512-m3YGKrcNBTYOIWD+FRDJzNU+qbVJ1xI4Th9OAZBITB4rZX13ShZVO8tnSM8ceglLV2yMovwiphr6P+SNIfjzOg==", + "dependencies": { + "@types/dom-webcodecs": "^0.1.11", + "zxing-wasm": "1.2.12" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -7954,7 +7992,6 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-1.2.5.tgz", "integrity": "sha512-fXtDA0X0t0eBYAGLVM5YsgJGsJ5jEmqZEPrGbzdf5awjv0xE7nqv3TVnvtUF060Tkes15DbDAKW/I48vsb6SyA==", - "license": "MIT", "peer": true, "dependencies": { "@types/react-reconciler": "^0.28.0" @@ -7967,7 +8004,6 @@ "version": "0.28.8", "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.8.tgz", "integrity": "sha512-SN9c4kxXZonFhbX4hJrZy37yw9e7EIxcpHCxQv5JUS18wDE5ovkQKlqQEkufdJCCMfuI9BnjUJvhYeJ9x5Ra7g==", - "license": "MIT", "peer": true, "dependencies": { "@types/react": "*" @@ -10111,7 +10147,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -10511,6 +10546,14 @@ } ] }, + "node_modules/razorpay": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/razorpay/-/razorpay-2.9.4.tgz", + "integrity": "sha512-CvOitdgM5HNr+zl174fHpZoJKVFYEfPoGx798kX+kg3haGDD3xinzxTzRUIOzLnL1/F4e7mUoIaGNn0h1E929Q==", + "dependencies": { + "axios": "^1.6.8" + } + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -10930,19 +10973,10 @@ "semver": "bin/semver.js" } }, - - "node_modules/react-icons": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.3.0.tgz", - "integrity": "sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==", - "peerDependencies": { - "react": "*" - }, "node_modules/react-hook-form": { "version": "7.53.0", "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.53.0.tgz", "integrity": "sha512-M1n3HhqCww6S2hxLxciEXy2oISPnAzxY7gvwVPrtlczTM/1dDadXgUxDpHMrMTblDOcm/AXtXxHwZ3jpg1mqKQ==", - "license": "MIT", "engines": { "node": ">=18.0.0" }, @@ -10954,17 +10988,23 @@ "react": "^16.8.0 || ^17 || ^18 || ^19" } }, + "node_modules/react-icons": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.3.0.tgz", + "integrity": "sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==", + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-promise-suspense": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/react-promise-suspense/-/react-promise-suspense-0.3.4.tgz", "integrity": "sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==", - "license": "MIT", "dependencies": { "fast-deep-equal": "^2.0.1" } @@ -10972,14 +11012,12 @@ "node_modules/react-promise-suspense/node_modules/fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==", - "license": "MIT" + "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==" }, "node_modules/react-reconciler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.27.0.tgz", "integrity": "sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==", - "license": "MIT", "peer": true, "dependencies": { "loose-envify": "^1.1.0", @@ -10996,7 +11034,6 @@ "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", @@ -11021,7 +11058,6 @@ "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" @@ -11043,7 +11079,6 @@ "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", @@ -11066,7 +11101,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "license": "MIT", "dependencies": { "pify": "^2.3.0" } @@ -11075,7 +11109,6 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -11089,7 +11122,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -11101,7 +11133,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", - "license": "MIT", "engines": { "node": ">=4" } @@ -11110,7 +11141,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", - "license": "MIT", "dependencies": { "redis-errors": "^1.0.0" }, @@ -11123,7 +11153,6 @@ "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -11143,15 +11172,13 @@ "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "license": "MIT" + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "define-properties": "^1.2.1", @@ -11169,7 +11196,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -11178,7 +11204,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -11187,7 +11212,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resend/-/resend-4.0.0.tgz", "integrity": "sha512-rDX0rspl/XcmC2JV2V5obQvRX2arzxXUvNFUDMOv5ObBLR68+7kigCOysb7+dlkb0JE3erhQG0nHrbBt/ZCWIg==", - "license": "MIT", "dependencies": { "@react-email/render": "0.0.17" }, @@ -11199,7 +11223,6 @@ "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -11216,7 +11239,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -11228,7 +11250,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "license": "MIT", "engines": { "node": ">=8" } @@ -11238,7 +11259,6 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } @@ -11248,7 +11268,6 @@ "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } @@ -11257,7 +11276,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", - "license": "MIT", "engines": { "node": ">=10" } @@ -11266,7 +11284,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "license": "MIT", "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -11278,14 +11295,12 @@ "node_modules/restore-cursor/node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -11297,7 +11312,6 @@ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, - "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -11314,7 +11328,6 @@ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, - "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -11348,7 +11361,6 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } @@ -11358,7 +11370,6 @@ "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "get-intrinsic": "^1.2.4", @@ -11389,15 +11400,13 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/safe-regex-test": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "es-errors": "^1.3.0", @@ -11414,17 +11423,20 @@ "version": "0.21.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz", "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", - "license": "MIT", "peer": true, "dependencies": { "loose-envify": "^1.1.0" } }, + "node_modules/sdp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.0.tgz", + "integrity": "sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw==" + }, "node_modules/selderee": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz", "integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==", - "license": "MIT", "dependencies": { "parseley": "^0.12.0" }, @@ -11436,7 +11448,6 @@ "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -11449,7 +11460,6 @@ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, - "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -11467,7 +11477,6 @@ "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, - "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -11482,7 +11491,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -11494,7 +11502,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", "engines": { "node": ">=8" } @@ -11504,7 +11511,6 @@ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -11522,7 +11528,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", "engines": { "node": ">=14" }, @@ -11533,14 +11538,12 @@ "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "license": "MIT" + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "license": "MIT", "engines": { "node": ">=8" } @@ -11549,7 +11552,6 @@ "version": "4.7.5", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", - "license": "MIT", "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", @@ -11567,7 +11569,6 @@ "version": "2.5.5", "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", - "license": "MIT", "dependencies": { "debug": "~4.3.4", "ws": "~8.17.1" @@ -11577,7 +11578,6 @@ "version": "8.17.1", "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -11598,7 +11598,6 @@ "version": "4.2.4", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", - "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" @@ -11611,7 +11610,6 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/sonner/-/sonner-1.5.0.tgz", "integrity": "sha512-FBjhG/gnnbN6FY0jaNnqZOMmB73R+5IiyYAw8yBj7L54ER7HB3fOSE5OFiQiE2iXWxeXKvg6fIP4LtVppHEdJA==", - "license": "MIT", "peerDependencies": { "react": "^18.0.0", "react-dom": "^18.0.0" @@ -11621,7 +11619,6 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -11630,7 +11627,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -11639,7 +11635,6 @@ "version": "0.5.13", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -11648,20 +11643,17 @@ "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "license": "BSD-3-Clause" + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, "node_modules/sqids": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/sqids/-/sqids-0.3.0.tgz", - "integrity": "sha512-lOQK1ucVg+W6n3FhRwwSeUijxe93b51Bfz5PMRMihVf1iVkl82ePQG7V5vwrhzB11v0NtsR25PSZRGiSomJaJw==", - "license": "MIT" + "integrity": "sha512-lOQK1ucVg+W6n3FhRwwSeUijxe93b51Bfz5PMRMihVf1iVkl82ePQG7V5vwrhzB11v0NtsR25PSZRGiSomJaJw==" }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -11673,7 +11665,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "license": "MIT", "engines": { "node": ">=8" } @@ -11681,14 +11672,12 @@ "node_modules/standard-as-callback": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", - "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", - "license": "MIT" + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" }, "node_modules/stats-gl": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/stats-gl/-/stats-gl-2.2.8.tgz", "integrity": "sha512-94G5nZvduDmzxBS7K0lYnynYwreZpkknD8g5dZmU6mpwIhy3caCrjAm11Qm1cbyx7mqix7Fp00RkbsonzKWnoQ==", - "license": "MIT", "dependencies": { "@types/three": "^0.163.0" } @@ -11697,7 +11686,6 @@ "version": "0.163.0", "resolved": "https://registry.npmjs.org/@types/three/-/three-0.163.0.tgz", "integrity": "sha512-uIdDhsXRpQiBUkflBS/i1l3JX14fW6Ot9csed60nfbZNXHDTRsnV2xnTVwXcgbvTiboAR4IW+t+lTL5f1rqIqA==", - "license": "MIT", "dependencies": { "@tweenjs/tween.js": "~23.1.1", "@types/stats.js": "*", @@ -11709,15 +11697,13 @@ "node_modules/stats.js": { "version": "0.17.0", "resolved": "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz", - "integrity": "sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==", - "license": "MIT" + "integrity": "sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==" }, "node_modules/stop-iteration-iterator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", "dev": true, - "license": "MIT", "dependencies": { "internal-slot": "^1.0.4" }, @@ -11737,7 +11723,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } @@ -11746,7 +11731,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "license": "MIT", "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" @@ -11759,7 +11743,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -11777,7 +11760,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -11790,14 +11772,12 @@ "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/string-width/node_modules/ansi-regex": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", "engines": { "node": ">=12" }, @@ -11809,7 +11789,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -11825,7 +11804,6 @@ "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz", "integrity": "sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==", "dev": true, - "license": "MIT", "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" @@ -11836,7 +11814,6 @@ "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -11863,7 +11840,6 @@ "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", "dev": true, - "license": "MIT", "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" @@ -11874,7 +11850,6 @@ "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -11893,7 +11868,6 @@ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -11908,7 +11882,6 @@ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -11925,7 +11898,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -11938,7 +11910,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -11951,7 +11922,6 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } @@ -11960,7 +11930,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "license": "MIT", "engines": { "node": ">=6" } @@ -11969,7 +11938,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "license": "MIT", "engines": { "node": ">=8" }, @@ -11981,7 +11949,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", - "license": "MIT", "dependencies": { "client-only": "0.0.1" }, @@ -12004,7 +11971,6 @@ "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", - "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", @@ -12026,7 +11992,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12038,7 +12003,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -12050,7 +12014,6 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/suspend-react/-/suspend-react-0.1.3.tgz", "integrity": "sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==", - "license": "MIT", "peerDependencies": { "react": ">=17.0" } @@ -12059,7 +12022,6 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.2.tgz", "integrity": "sha512-kjEBm+pvD+6eAwzJL2Bi+02/9LFLal1Gs61+QB7HvTfQQ0aXwC5LGT8PEt1gS0CWKktKe6ysPTAy3cBC5MeiIg==", - "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/dcastil" @@ -12069,7 +12031,6 @@ "version": "3.4.13", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.13.tgz", "integrity": "sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==", - "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -12106,7 +12067,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", - "license": "MIT", "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders" } @@ -12116,7 +12076,6 @@ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -12125,7 +12084,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -12140,7 +12098,6 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", - "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -12160,14 +12117,12 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "license": "MIT", "dependencies": { "any-promise": "^1.0.0" } @@ -12176,7 +12131,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "license": "MIT", "dependencies": { "thenify": ">= 3.1.0 < 4" }, @@ -12187,15 +12141,13 @@ "node_modules/three": { "version": "0.169.0", "resolved": "https://registry.npmjs.org/three/-/three-0.169.0.tgz", - "integrity": "sha512-Ed906MA3dR4TS5riErd4QBsRGPcx+HBDX2O5yYE5GqJeFQTPU+M56Va/f/Oph9X7uZo3W3o4l2ZhBZ6f6qUv0w==", - "license": "MIT" + "integrity": "sha512-Ed906MA3dR4TS5riErd4QBsRGPcx+HBDX2O5yYE5GqJeFQTPU+M56Va/f/Oph9X7uZo3W3o4l2ZhBZ6f6qUv0w==" }, "node_modules/three-mesh-bvh": { "version": "0.7.8", "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.7.8.tgz", "integrity": "sha512-BGEZTOIC14U0XIRw3tO4jY7IjP7n7v24nv9JXS1CyeVRWOCkcOMhRnmENUjuV39gktAw4Ofhr0OvIAiTspQrrw==", "deprecated": "Deprecated due to three.js version incompatibility. Please use v0.8.0, instead.", - "license": "MIT", "peerDependencies": { "three": ">= 0.151.0" } @@ -12204,7 +12156,6 @@ "version": "2.33.0", "resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.33.0.tgz", "integrity": "sha512-V/uycBuqQOP/3Z+FBtpMdj2Ds5PyfJ3VDfMzktEmG4niOIzv7q1y5uMSbMcng0+057m1l0N147FQxsodQo9zBg==", - "license": "MIT", "dependencies": { "@types/draco3d": "^1.4.0", "@types/offscreencanvas": "^2019.6.4", @@ -12220,45 +12171,17 @@ "node_modules/three-stdlib/node_modules/fflate": { "version": "0.6.10", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", - "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==", - "license": "MIT" - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "license": "BSD-3-Clause" - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } + "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==" }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "license": "BSD-3-Clause" + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "license": "MIT", "engines": { "node": ">=4" } @@ -12267,7 +12190,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -12279,7 +12201,6 @@ "version": "0.49.1", "resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.49.1.tgz", "integrity": "sha512-lXGWxgjJP9kw4i4Wh+0k0Q/7cRfS6iOME4knKht/KozPu9GcFA9NnNpRvehIhrUawq9B0ZRw+0oiFHgRO+4Wig==", - "license": "MIT", "dependencies": { "bidi-js": "^1.0.2", "troika-three-utils": "^0.49.0", @@ -12294,7 +12215,6 @@ "version": "0.49.0", "resolved": "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.49.0.tgz", "integrity": "sha512-umitFL4cT+Fm/uONmaQEq4oZlyRHWwVClaS6ZrdcueRvwc2w+cpNQ47LlJKJswpqtMFWbEhOLy0TekmcPZOdYA==", - "license": "MIT", "peerDependencies": { "three": ">=0.125.0" } @@ -12302,15 +12222,13 @@ "node_modules/troika-worker-utils": { "version": "0.49.0", "resolved": "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.49.0.tgz", - "integrity": "sha512-1xZHoJrG0HFfCvT/iyN41DvI/nRykiBtHqFkGaGgJwq5iXfIZFBiPPEHFpPpgyKM3Oo5ITHXP5wM2TNQszYdVg==", - "license": "MIT" + "integrity": "sha512-1xZHoJrG0HFfCvT/iyN41DvI/nRykiBtHqFkGaGgJwq5iXfIZFBiPPEHFpPpgyKM3Oo5ITHXP5wM2TNQszYdVg==" }, "node_modules/ts-api-utils": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=16" }, @@ -12321,15 +12239,13 @@ "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "license": "Apache-2.0" + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, - "license": "MIT", "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", @@ -12340,14 +12256,12 @@ "node_modules/tslib": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", - "license": "0BSD" + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" }, "node_modules/tunnel-rat": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/tunnel-rat/-/tunnel-rat-0.1.2.tgz", "integrity": "sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==", - "license": "MIT", "dependencies": { "zustand": "^4.3.2" } @@ -12356,7 +12270,6 @@ "version": "4.5.5", "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.5.tgz", "integrity": "sha512-+0PALYNJNgK6hldkgDq2vLrw5f6g/jCInz52n9RTpropGgeAf/ioFUCdtsjCqu4gNhW9D01rUQBROoRjdzyn2Q==", - "license": "MIT", "dependencies": { "use-sync-external-store": "1.2.2" }, @@ -12385,7 +12298,6 @@ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, - "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -12397,7 +12309,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "license": "MIT", "engines": { "node": ">=4" } @@ -12407,7 +12318,6 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -12420,7 +12330,6 @@ "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -12435,7 +12344,6 @@ "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", @@ -12455,7 +12363,6 @@ "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", "dev": true, - "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", @@ -12476,7 +12383,6 @@ "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", @@ -12493,11 +12399,10 @@ } }, "node_modules/typescript": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", - "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", "dev": true, - "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -12511,7 +12416,6 @@ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-bigints": "^1.0.2", @@ -12525,13 +12429,12 @@ "node_modules/undici-types": { "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "license": "MIT" + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" }, "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "funding": [ { "type": "opencollective", @@ -12546,10 +12449,9 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -12562,7 +12464,6 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/uploadthing/-/uploadthing-7.0.2.tgz", "integrity": "sha512-B5/r0nmOfWjo+cGvZLyDQ8jypJYWoW/VsmoL+VqkiGMg5yIkKzMGJ5InrDOJS+3WQBbW8KdhVrRyA+mGSZEGUw==", - "license": "MIT", "dependencies": { "@effect/platform": "0.63.2", "@effect/schema": "0.72.2", @@ -12604,7 +12505,6 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -12613,7 +12513,6 @@ "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" }, @@ -12634,7 +12533,6 @@ "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" @@ -12656,7 +12554,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", - "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } @@ -12664,14 +12561,12 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/utility-types": { "version": "3.11.0", "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", - "license": "MIT", "engines": { "node": ">= 4" } @@ -12684,7 +12579,6 @@ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], - "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -12693,7 +12587,6 @@ "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", - "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", @@ -12707,7 +12600,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -12716,7 +12608,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" } @@ -12725,7 +12616,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "license": "MIT", "dependencies": { "defaults": "^1.0.3" } @@ -12734,7 +12624,6 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "license": "MIT", "engines": { "node": ">= 8" } @@ -12747,14 +12636,24 @@ "node_modules/webgl-sdf-generator": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz", - "integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==", - "license": "MIT" + "integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==" + }, + "node_modules/webrtc-adapter": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-9.0.1.tgz", + "integrity": "sha512-1AQO+d4ElfVSXyzNVTOewgGT/tAomwwztX/6e3totvyyzXPvXIIuUUjAmyZGbKBKbZOXauuJooZm3g6IuFuiNQ==", + "dependencies": { + "sdp": "^3.2.0" + }, + "engines": { + "node": ">=6.0.0", + "npm": ">=3.10.0" + } }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -12770,7 +12669,6 @@ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, - "license": "MIT", "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -12787,7 +12685,6 @@ "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", "dev": true, - "license": "MIT", "dependencies": { "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", @@ -12814,7 +12711,6 @@ "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, - "license": "MIT", "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", @@ -12833,7 +12729,6 @@ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dev": true, - "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", @@ -12853,7 +12748,6 @@ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -12862,7 +12756,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -12880,7 +12773,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -12896,14 +12788,12 @@ "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -12917,7 +12807,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", "engines": { "node": ">=12" }, @@ -12929,7 +12818,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "license": "MIT", "engines": { "node": ">=12" }, @@ -12941,7 +12829,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -12955,14 +12842,12 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/write-file-atomic": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" @@ -12974,14 +12859,12 @@ "node_modules/write-file-atomic/node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/ws": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -13002,7 +12885,6 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "license": "ISC", "engines": { "node": ">=10" } @@ -13010,14 +12892,12 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", - "license": "ISC", "bin": { "yaml": "bin.mjs" }, @@ -13029,7 +12909,6 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -13047,7 +12926,6 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "license": "ISC", "engines": { "node": ">=12" } @@ -13055,14 +12933,12 @@ "node_modules/yargs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/yargs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -13076,7 +12952,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "license": "MIT", "engines": { "node": ">=10" }, @@ -13088,7 +12963,6 @@ "version": "3.23.8", "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", - "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -13097,7 +12971,6 @@ "version": "3.7.2", "resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz", "integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==", - "license": "MIT", "engines": { "node": ">=12.7.0" }, @@ -13109,7 +12982,14 @@ "optional": true } } + }, + "node_modules/zxing-wasm": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/zxing-wasm/-/zxing-wasm-1.2.12.tgz", + "integrity": "sha512-UzQvEA5Hv4Nd/jJoKq7UN/jfkQwEDMASqoi1unlXrEgOB9rseLpmNTywcv4/2d9aMqKjfczyk3T25r6DYxAb7g==", + "dependencies": { + "@types/emscripten": "^1.39.13" + } } } } -} diff --git a/package.json b/package.json index adf90f5..748273b 100644 --- a/package.json +++ b/package.json @@ -8,9 +8,9 @@ "build": "next build", "start": "next start", "lint": "next lint", + "email": "email dev", "migrate-latest": "export $(grep -v '^#' .env | xargs) && LATEST_MIGRATION=$(find prisma/migrations/*/ -type d -name '[0-9]*_*' | sort -r | head -n 1) && turso db shell $TURSO_DB_NAME < ${LATEST_MIGRATION}migration.sql", "migrate-latest-w": "wsl sh -c \"export $(grep -v '^#' .env.local | xargs) && LATEST_MIGRATION=$(find prisma/migrations/*/ -type d -name '[0-9]*_*' | sort -r | head -n 1) && turso db shell $TURSO_DB_NAME < '${LATEST_MIGRATION}migration.sql'\"" - }, "dependencies": { "@hookform/resolvers": "^3.9.0", @@ -31,12 +31,14 @@ "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-tabs": "^1.1.0", "@react-email/components": "^0.0.25", + "@react-email/tailwind": "0.1.0", "@react-three/drei": "^9.114.0", "@tanstack/react-query": "^5.56.2", "@types/canvas-confetti": "^1.6.4", "@types/ioredis": "^4.28.10", "@types/lodash.debounce": "^4.0.9", "@uploadthing/react": "^7.0.2", + "@yudiel/react-qr-scanner": "^2.0.8", "axios": "^1.7.7", "bullmq": "^5.13.0", "canvas-confetti": "^1.9.3", @@ -56,8 +58,8 @@ "react": "^18.3.1", "react-dom": "^18", "react-email": "^3.0.1", - "react-icons": "^5.3.0", "react-hook-form": "^7.53.0", + "react-icons": "^5.3.0", "resend": "^4.0.0", "sonner": "^1.5.0", "tailwind-merge": "^2.5.2", @@ -73,6 +75,7 @@ "@types/otp-generator": "^4.0.2", "@types/react": "^18", "@types/react-dom": "^18", + "@types/react-qr-reader": "^2.1.7", "eslint": "^8", "eslint-config-next": "14.2.6", "postcss": "^8", diff --git a/prisma/dev.db b/prisma/dev.db index 9628b63..7599d16 100644 Binary files a/prisma/dev.db and b/prisma/dev.db differ diff --git a/prisma/dev.db-journal b/prisma/dev.db-journal index 8f0ec3f..bbef202 100644 Binary files a/prisma/dev.db-journal and b/prisma/dev.db-journal differ diff --git a/prisma/migrations/20241002051550_fix_typo/migration.sql b/prisma/migrations/20241002051550_fix_typo/migration.sql new file mode 100644 index 0000000..9ce1315 --- /dev/null +++ b/prisma/migrations/20241002051550_fix_typo/migration.sql @@ -0,0 +1,27 @@ +/* + Warnings: + + - You are about to drop the column `formId` on the `Payment` table. All the data in the column will be lost. + - Added the required column `user_id` to the `Payment` table without a default value. This is not possible if the table is not empty. + +*/ +-- RedefineTables +PRAGMA defer_foreign_keys=ON; +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_Payment" ( + "signature" TEXT, + "user_id" TEXT NOT NULL, + "amount" REAL NOT NULL, + "order_creation_id" TEXT NOT NULL, + "razorpay_payment_id" TEXT NOT NULL PRIMARY KEY, + "created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" DATETIME NOT NULL, + "form_id" TEXT, + CONSTRAINT "Payment_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT "Payment_form_id_fkey" FOREIGN KEY ("form_id") REFERENCES "Form" ("id") ON DELETE SET NULL ON UPDATE CASCADE +); +INSERT INTO "new_Payment" ("amount", "created_at", "form_id", "order_creation_id", "razorpay_payment_id", "signature", "updated_at") SELECT "amount", "created_at", "form_id", "order_creation_id", "razorpay_payment_id", "signature", "updated_at" FROM "Payment"; +DROP TABLE "Payment"; +ALTER TABLE "new_Payment" RENAME TO "Payment"; +PRAGMA foreign_keys=ON; +PRAGMA defer_foreign_keys=OFF; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index cfec445..1534f8f 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -94,7 +94,7 @@ model Form { model Payment { signature String? - userId String @map("form_id") + userId String @map("user_id") amount Float orderCreationId String @map("order_creation_id") razorpayPaymentId String @id @map("razorpay_payment_id") @@ -102,6 +102,6 @@ model Payment { updated_at DateTime @updatedAt user User @relation(fields: [userId], references: [id], onDelete: Cascade) - formId String? + formId String? @map("form_id") Form Form? @relation(fields: [formId], references: [id]) } diff --git a/src/app/admin/razorpay/[id]/page.tsx b/src/app/admin/razorpay/[id]/page.tsx new file mode 100644 index 0000000..5e05abc --- /dev/null +++ b/src/app/admin/razorpay/[id]/page.tsx @@ -0,0 +1,177 @@ +"use client"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { Label } from "@radix-ui/react-label"; +import React, { useEffect, useState } from "react"; +import { toast } from "sonner"; + +export interface Root { + id: string; + entity: string; + amount: number; + currency: string; + status: string; + order_id: string; + invoice_id: any; + international: boolean; + method: string; + amount_refunded: number; + refund_status: any; + captured: boolean; + description: string; + card_id: any; + bank: any; + wallet: any; + vpa: string; + email: string; + contact: string; + notes: Notes; + fee: number; + tax: number; + error_code: any; + error_description: any; + error_source: any; + error_step: any; + error_reason: any; + acquirer_data: AcquirerData; + created_at: number; + upi: Upi; +} + +export interface AcquirerData { + rrn: string; + upi_transaction_id: string; +} + +export interface Upi { + vpa: string; +} +export interface Notes { + customerName: string; + customerEmail: string; + customerContact: string; +} + +function FetchRazorpayPaymentData({ params }: { params: { id: string } }) { + const { id } = params; + const [paymentData, setPaymentData] = useState(null); + const [loading, setLoading] = useState(true); + const [loadingForButton, setLoadingForButton] = useState(false); + + async function sendEmail(paymentId: string) { + setLoadingForButton(true); + try { + const response = await fetch(`/api/send-email/${paymentId}`, { + method: "POST", + }); + + if (response.status === 200) { + toast.success("Email sent successfully", { + description: "An email has been sent to the customer", + }); + } else { + toast.error("Error", { + description: "An error occurred while sending the email", + }); + } + } catch (error) { + toast.error("Error", { + description: "An error occurred while sending the email", + }); + } finally { + // Ensure the button is enabled again after the operation + setLoadingForButton(false); + } + } + + useEffect(() => { + const fetchData = async () => { + try { + const res = await fetch(`/api/verify-order/${id}`); + const data = await res.json(); + setPaymentData(data); + } catch (error) { + console.error("Error fetching payment data:", error); + } finally { + setLoading(false); + } + }; + fetchData(); + }, [id]); + + if (loading) { + return ( +
+

Loading...

+
+ ); + } + + if (!paymentData) { + return ( +
+

No payment data found.

+
+ ); + } + + return ( +
+ + + + Payment Data of {paymentData.notes.customerName || "Unknown"} + + + + + + + + + + + + + +
+ ); +} + +export default FetchRazorpayPaymentData; diff --git a/src/app/admin/razorpay/page.tsx b/src/app/admin/razorpay/page.tsx new file mode 100644 index 0000000..0468bc8 --- /dev/null +++ b/src/app/admin/razorpay/page.tsx @@ -0,0 +1,74 @@ +"use client"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useRouter } from "next/navigation"; +import React from "react"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; + +const formSchema = z.object({ + razorpayPaymentId: z.string().nonempty("Payment ID is required"), +}); + +const FetchRazorpayPaymentData = () => { + const form = useForm>({ + resolver: zodResolver(formSchema), + }); + const router = useRouter() + + const onSubmit = async (data: z.infer) => { + router.push(`/admin/razorpay/${data.razorpayPaymentId}`) + }; + + return ( +
+

+ Search by Razorpay Payment ID +

+
+ + ( + + Razorpay Payment ID: + + + + + Search for a payment by its Razorpay Payment ID + + + + )} + /> + + + +
+ ); +}; + +export default FetchRazorpayPaymentData; diff --git a/src/app/admin/verify/[id]/page.tsx b/src/app/admin/verify/[id]/page.tsx new file mode 100644 index 0000000..4dc66b8 --- /dev/null +++ b/src/app/admin/verify/[id]/page.tsx @@ -0,0 +1,79 @@ +/* eslint-disable react/no-unescaped-entities */ +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import { Button } from "@/components/ui/button" +import { AlertCircle, CheckCircle } from "lucide-react" +import Link from "next/link" +import React from "react" +async function getPaymentData(id: string) { + // Simulate API call + //Hardcoded the url because the other one just did'nt work + const response = await fetch(`http://localhost:3000/api/verify-order/${id}`) + const data = await response.json() + if (response.status === 200) { + return data + } + return null +} + +export default async function PaymentPage({ params }: { params: { id: string } }) { + const paymentData = await getPaymentData(params.id) + + return ( +
+ + + + {paymentData ? "Payment Found" : "Payment Not Found"} + + + +
+

+ Payment details for ID: {params.id} +

+ {paymentData ? ( + <> +
+ +
+

Payment Successful

+

Your payment has been processed successfully.

+
+
+
+

Amount Paid:

+

₹{(paymentData.amount / 100).toFixed(2)}

+
+
+

Paid By:

+

{paymentData.email}

+
+ + ) : ( +
+ +
+

Payment Not Found

+

We couldn't find any payment with the provided ID.

+
+
+ )} +
+ + + +
+
+
+
+
+ ) +} \ No newline at end of file diff --git a/src/app/admin/verify/page.tsx b/src/app/admin/verify/page.tsx new file mode 100644 index 0000000..2ff48ba --- /dev/null +++ b/src/app/admin/verify/page.tsx @@ -0,0 +1,82 @@ +"use client"; +import { useState, useEffect } from "react"; +import { Scanner } from "@yudiel/react-qr-scanner"; +import { useRouter } from "next/navigation"; +import { IDetectedBarcode } from "@yudiel/react-qr-scanner"; + +const QRCodeScanner = () => { + const [isMobile, setIsMobile] = useState(false); + const [error, setError] = useState(null); + const router = useRouter(); + + useEffect(() => { + // Check if the device is mobile + const checkMobile = () => { + const userAgent = navigator.userAgent || navigator.vendor || (window as any).opera; + return /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test( + userAgent.toLowerCase() + ); + }; + setIsMobile(checkMobile()); + }, []); + + const handleScan = (detectedCodes: IDetectedBarcode[]) => { + if (detectedCodes.length > 0) { + const result = detectedCodes[0].rawValue; + if (result) { + try { + // Validate if the scanned result is a valid URL + const url = new URL(result); + // Redirect to the scanned URL + router.push(url.toString()); + } catch { + setError("Invalid QR code. Please scan a valid URL."); + } + } + } + }; + + const handleError = (error: unknown) => { + if (error instanceof Error) { + setError("Error accessing camera: " + error.message); + } else { + setError("An unknown error occurred."); + } + }; + + if (isMobile) { + return ( +
+
+

Error

+

+ This feature is only available on mobile devices. Please access this page from your + smartphone or tablet. +

+
+
+ ); + } + + return ( +
+
+

QR Code Scanner

+ {error ? ( +

{error}

+ ) : ( + + )} +

+ Position the QR code within the frame to scan. +

+
+
+ ); +}; + +export default QRCodeScanner; diff --git a/src/app/api/create-order/route.ts b/src/app/api/create-order/route.ts index 86a01a4..6d35e7e 100644 --- a/src/app/api/create-order/route.ts +++ b/src/app/api/create-order/route.ts @@ -1,37 +1,32 @@ import { NextRequest, NextResponse } from "next/server"; -import Razorpay from "razorpay"; - -const razorpay = new Razorpay({ - key_id: process.env.RAZORPAY_KEY_ID!, - key_secret: process.env.RAZORPAY_KEY_SECRET!, -}); +import { razorpay } from "@/lib/razorpay"; export async function POST(request: NextRequest) { - const { amount } = await request.json(); - try { - const order = await razorpay.orders.create({ - amount: amount * 100, - currency: "INR", - receipt: "receipt_" + Math.random().toString(36).substring(7), - }); + const { amount } = await request.json(); + try { + const order = await razorpay.orders.create({ + amount: amount * 100, + currency: "INR", + receipt: "receipt_" + Math.random().toString(36).substring(7), + }); - return NextResponse.json( - { - orderId: order.id, - }, - { - status: 200, - }, - ); - } catch (error) { - console.log(error); - return NextResponse.json( - { - error: "Error creating order ", - }, - { - status: 500, - }, - ); - } + return NextResponse.json( + { + orderId: order.id, + }, + { + status: 200, + } + ); + } catch (error) { + console.log(error); + return NextResponse.json( + { + error: "Error creating order ", + }, + { + status: 500, + } + ); + } } diff --git a/src/app/api/send-email/[paymentId]/route.ts b/src/app/api/send-email/[paymentId]/route.ts new file mode 100644 index 0000000..0f755d5 --- /dev/null +++ b/src/app/api/send-email/[paymentId]/route.ts @@ -0,0 +1,60 @@ +import { getServerSideSession } from "@/lib/get-server-session"; +import { razorpay } from "@/lib/razorpay"; +import { NextRequest, NextResponse } from "next/server"; +import prisma from "@/server/db"; +import { sendRegistrationEmail } from "@/lib/send-registration-email"; +import { generatedSignature } from "@/lib/helper"; + +export async function POST(request: NextRequest, context: { params: { paymentId: string } }) { + const session = await getServerSideSession(); + if (!session) { + return NextResponse.json({ message: "Unauthorized", isOk: false }, { status: 401 }); + } + if (session.user.role !== "ADMIN") { + return NextResponse.json({ message: "Forbidden", isOk: false }, { status: 403 }); + } + + const { paymentId } = context.params; + const payment = await razorpay.payments.fetch(paymentId); + const signature = generatedSignature(payment.order_id, payment.id); + + const user = await prisma.user.findUnique({ + where: { + email: payment.email, + }, + }); + + const prismaPayment = prisma.payment.findUnique({ + where: { + razorpayPaymentId: payment.id, + }, + }); + try { + await sendRegistrationEmail({ + email: payment.email, + name: user?.name!, + registrationLink: `http://localhost:3000/admin/verify/${payment.id}`, + }); + } catch (error) { + console.log(error); + } + + if (!prismaPayment) { + await prisma.$transaction(async (prisma) => { + await prisma.payment.create({ + data: { + amount: parseFloat(payment.amount.toString()), + signature: signature, + razorpayPaymentId: payment.id, + orderCreationId: payment.order_id, + user: { + connect: { + email: session?.user.email!, + }, + }, + }, + }); + }); + } + return NextResponse.json({ message: "Payment verified successfully", isOk: true }, { status: 200 }); +} diff --git a/src/app/api/users/payment/route.ts b/src/app/api/users/payment/route.ts index 64fabec..5f35aed 100644 --- a/src/app/api/users/payment/route.ts +++ b/src/app/api/users/payment/route.ts @@ -4,9 +4,51 @@ import { NextRequest, NextResponse } from "next/server"; export async function GET(request: NextRequest) { const { searchParams } = new URL(request.url); + try { + const page = Math.max(1, parseInt(searchParams.get("page") || "1", 10)); + const search = searchParams.get("search") || ""; + const limit = 10; - const page = Math.max(1, parseInt(searchParams.get("page") || "1", 10)); - const search = searchParams.get("search") || ""; - const limit = 10; - const paymentDetails = await prisma.payment.findMany({}); + const [users, totalCount] = await Promise.all([ + prisma.payment.findMany({ + skip: (page - 1) * limit, + take: limit, + where: { + razorpayPaymentId: { + contains: search, + }, + }, + include: { + user: { + select: { + name: true, + email: true, + }, + }, + }, + }), + prisma.payment.count({ + where: { + razorpayPaymentId: { + contains: search, + }, + }, + }), + ]); + + const totalPages = Math.ceil(totalCount / limit); + + return NextResponse.json({ + users, + pagination: { + currentPage: page, + totalCount, + totalPages, + limit, + }, + }); + } catch (error) { + console.error("Error fetching payment details:", error); + return NextResponse.json({ error: "Failed to fetch data" }, { status: 500 }); + } } diff --git a/src/app/api/verify-order/[id]/route.ts b/src/app/api/verify-order/[id]/route.ts new file mode 100644 index 0000000..4739d03 --- /dev/null +++ b/src/app/api/verify-order/[id]/route.ts @@ -0,0 +1,22 @@ +import { getServerSideSession } from "@/lib/get-server-session"; +import { razorpay } from "@/lib/razorpay"; +import { NextRequest, NextResponse } from "next/server"; + +export async function GET(request: Request, context: { params: { id: string } }) { + // const session = await getServerSideSession(); + // if (!session) { + // return NextResponse.json({ message: "Unauthorized", isOk: false }, { status: 401 }); + // } + // if (session.user.role !== "ADMIN") { + // return NextResponse.json({ message: "Forbidden", isOk: false }, { status: 403 }); + // } + + const { id } = context.params; + try { + const paymentData = await razorpay.payments.fetch(id); + return NextResponse.json(paymentData, { status: 200 }); + } catch (error) { + console.error("Error fetching payment data:", error); + return NextResponse.json({ error: "Payment not found" }, { status: 404 }); + } +} diff --git a/src/app/api/verify-order/route.ts b/src/app/api/verify-order/route.ts index 72d2b82..57e5014 100644 --- a/src/app/api/verify-order/route.ts +++ b/src/app/api/verify-order/route.ts @@ -1,36 +1,48 @@ import { NextRequest, NextResponse } from "next/server"; -import crypto from "crypto"; import { getServerSideSession } from "@/lib/get-server-session"; import prisma from "@/server/db"; +import { sendRegistrationEmail } from "@/lib/send-registration-email"; +import { generatedSignature } from "@/lib/helper"; -const generatedSignature = (razorpayOrderId: string, razorpayPaymentId: string) => { - const keySecret = process.env.RAZORPAY_KEY_SECRET!; - const sig = crypto - .createHmac("sha256", keySecret) - .update(razorpayOrderId + "|" + razorpayPaymentId) - .digest("hex"); - return sig; -}; export async function POST(request: NextRequest) { const { orderId, razorpayPaymentId, razorpaySignature, amount } = await request.json(); const session = await getServerSideSession(); - if(!session){ + if (!session) { return NextResponse.json({ message: "No session", isOk: false }, { status: 400 }); } const signature = generatedSignature(orderId, razorpayPaymentId); if (signature !== razorpaySignature) { return NextResponse.json({ message: "payment verification failed", isOk: false }, { status: 400 }); } - await prisma.payment.create({ - data: { - signature: razorpaySignature as string, - userId: session?.user.id!, - amount, - orderCreationId: orderId, - razorpayPaymentId: razorpayPaymentId, - }, - }); - return NextResponse.json({ message: "payment verified successfully", isOk: true }, { status: 200 }); + if (signature === razorpaySignature) { + const user = await prisma.user.findUnique({ + where: { + email: session.user?.email!, + }, + }); + + try { + await sendRegistrationEmail({ + email: session.user?.email!, + name: session.user?.name!, + registrationLink: `http://localhost:3000/admin/verify/${razorpayPaymentId}`, + }); + } catch (error) { + console.log(error); + } + await prisma.$transaction(async (prisma) => { + await prisma.payment.create({ + data: { + amount: amount, + orderCreationId: orderId, + razorpayPaymentId: razorpayPaymentId, + signature: razorpaySignature, + user: { connect: { email: session.user?.email! } }, + }, + }); + }); + return NextResponse.json({ message: "payment verified successfully", isOk: true }, { status: 200 }); + } } diff --git a/src/components/Admin/Navbar/navbar.tsx b/src/components/Admin/Navbar/navbar.tsx index 31d6465..cd56ce0 100644 --- a/src/components/Admin/Navbar/navbar.tsx +++ b/src/components/Admin/Navbar/navbar.tsx @@ -4,217 +4,213 @@ import { IconType } from "react-icons"; import { FiChevronDown, FiChevronsRight, FiUser } from "react-icons/fi"; import { RiCoupon3Line } from "react-icons/ri"; import { MdPayment } from "react-icons/md"; +import { SiTicktick } from "react-icons/si"; +import { SiRazorpay } from "react-icons/si"; import { motion } from "framer-motion"; import Link from "next/link"; export const AdminNavbar = () => { - return ( -
- - -
- ); + return ( +
+ + +
+ ); }; const Sidebar = () => { - const [open, setOpen] = useState(true); - const [selected, setSelected] = useState("Dashboard"); + const [open, setOpen] = useState(true); + const [selected, setSelected] = useState("Dashboard"); - return ( - - + return ( + + -
-
+
+
- -
- ); + +
+ ); }; const Option = ({ - Icon, - title, - selected, - setSelected, - open, - notifs, - href, + Icon, + title, + selected, + setSelected, + open, + notifs, + href, }: { - Icon: IconType; - title: string; - selected: string; - setSelected: Dispatch>; - open: boolean; - notifs?: number; - href?: string; + Icon: IconType; + title: string; + selected: string; + setSelected: Dispatch>; + open: boolean; + notifs?: number; + href?: string; }) => { - return ( - - setSelected(title)} - className={`relative flex h-10 w-full items-center rounded-md transition-colors ${ - selected === title - ? "bg-indigo-100 text-indigo-800" - : "text-slate-500 hover:bg-slate-100" - }`} - > - - - - {open && ( - - {title} - - )} + return ( + + setSelected(title)} + className={`relative flex h-10 w-full items-center rounded-md transition-colors ${ + selected === title ? "bg-indigo-100 text-indigo-800" : "text-slate-500 hover:bg-slate-100" + }`} + > + + + + {open && ( + + {title} + + )} - {notifs && open && ( - - {notifs} - - )} - - - ); + {notifs && open && ( + + {notifs} + + )} + + + ); }; const TitleSection = ({ open }: { open: boolean }) => { - return ( -
-
-
- - {open && ( - - Tedxsjec - Admin Page - - )} + return ( +
+
+
+ + {open && ( + + Tedxsjec + Admin Page + + )} +
+ {open && } +
- {open && } -
-
- ); + ); }; const Logo = () => { - // Temp logo from https://logoipsum.com/ - return ( - - - - - - - ); + // Temp logo from https://logoipsum.com/ + return ( + + + + + + + ); }; -const ToggleClose = ({ - open, - setOpen, -}: { - open: boolean; - setOpen: Dispatch>; -}) => { - return ( - setOpen((pv) => !pv)} - className="absolute bottom-0 left-0 right-0 border-t border-slate-300 transition-colors hover:bg-slate-100" - > -
- - - - {open && ( - > }) => { + return ( + - Hide - - )} -
-
- ); + onClick={() => setOpen((pv) => !pv)} + className="absolute bottom-0 left-0 right-0 border-t border-slate-300 transition-colors hover:bg-slate-100" + > +
+ + + + {open && ( + + Hide + + )} +
+ + ); }; const NavbarContent = () =>
; diff --git a/src/components/Admin/user-list.tsx b/src/components/Admin/user-list.tsx index 66ba46b..75232bd 100644 --- a/src/components/Admin/user-list.tsx +++ b/src/components/Admin/user-list.tsx @@ -1,15 +1,9 @@ /* eslint-disable react-hooks/exhaustive-deps */ "use client"; -import { useState, useEffect, useRef, useCallback } from "react"; +import React, { useState, useEffect, useRef, useCallback } from "react"; import axios from "axios"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "../ui/card"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card"; import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar"; import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover"; import { Button } from "../ui/button"; @@ -19,161 +13,153 @@ import debounce from "lodash.debounce"; import ChangeRole from "./change-role"; export interface User { - id: string; - name: string | null; - email: string | null; - role: string; - image: string | null; + id: string; + name: string | null; + email: string | null; + role: string; + image: string | null; } interface UsersListProps { - initialUsers: User[]; - initialPage: number; + initialUsers: User[]; + initialPage: number; } export const dynamic = "force-dynamic"; const UsersList: React.FC = ({ initialUsers, initialPage }) => { - const [userList, setUserList] = useState(initialUsers); - const [currentPage, setCurrentPage] = useState(initialPage); - const [loading, setLoading] = useState(false); - const [hasMore, setHasMore] = useState(true); - const [searchQuery, setSearchQuery] = useState(""); // Search query state - const loader = useRef(null); + const [userList, setUserList] = useState(initialUsers); + const [currentPage, setCurrentPage] = useState(initialPage); + const [loading, setLoading] = useState(false); + const [hasMore, setHasMore] = useState(true); + const [searchQuery, setSearchQuery] = useState(""); // Search query state + const loader = useRef(null); - const fetchUsers = async (page: number, query: string) => { - if (loading) return; - setLoading(true); - try { - const response = await axios.get( - `/api/users?page=${page}&search=${encodeURIComponent(query)}`, - ); - if (response.data.users.length > 0) { - setUserList((prevUsers) => [...prevUsers, ...response.data.users]); - setCurrentPage(page); - } else { - setHasMore(false); - } - } catch (error) { - console.error("Error fetching users:", error); - } - setLoading(false); - }; - const loadMoreUsers = useCallback(() => { - if (hasMore) { - fetchUsers(currentPage + 1, searchQuery); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [currentPage, hasMore, searchQuery]); + const fetchUsers = async (page: number, query: string) => { + if (loading) return; + setLoading(true); + try { + const response = await axios.get(`/api/users?page=${page}&search=${encodeURIComponent(query)}`); + if (response.data.users.length > 0) { + setUserList((prevUsers) => [...prevUsers, ...response.data.users]); + setCurrentPage(page); + } else { + setHasMore(false); + } + } catch (error) { + console.error("Error fetching users:", error); + } + setLoading(false); + }; + const loadMoreUsers = useCallback(() => { + if (hasMore) { + fetchUsers(currentPage + 1, searchQuery); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [currentPage, hasMore, searchQuery]); - const debouncedFetchUsers = useCallback( - debounce(async (query: string) => { - setCurrentPage(1); // Reset page number - setHasMore(true); // Reset hasMore - try { - const response = await axios.get( - `/api/users?page=1&search=${encodeURIComponent(query)}`, - ); - setUserList(response.data.users); - } catch (error) { - console.error("Error fetching users:", error); - } - }, 500), - [], - ); - const handleSearchChange = (e: React.ChangeEvent) => { - const query = e.target.value; - setSearchQuery(query); - debouncedFetchUsers(query); // Use debounced fetch function - }; + const debouncedFetchUsers = useCallback( + debounce(async (query: string) => { + setCurrentPage(1); // Reset page number + setHasMore(true); // Reset hasMore + try { + const response = await axios.get(`/api/users?page=1&search=${encodeURIComponent(query)}`); + setUserList(response.data.users); + } catch (error) { + console.error("Error fetching users:", error); + } + }, 500), + [] + ); + const handleSearchChange = (e: React.ChangeEvent) => { + const query = e.target.value; + setSearchQuery(query); + debouncedFetchUsers(query); // Use debounced fetch function + }; - // Observe scroll and load more users when scrolled to the bottom - useEffect(() => { - if (loader.current) { - const observer = new IntersectionObserver( - (entries) => { - if (entries[0].isIntersecting && hasMore) { - loadMoreUsers(); - } - }, - { threshold: 1.0 }, - ); - observer.observe(loader.current); - return () => observer.disconnect(); - } - }, [loader.current, hasMore, loadMoreUsers]); + // Observe scroll and load more users when scrolled to the bottom + useEffect(() => { + if (loader.current) { + const observer = new IntersectionObserver( + (entries) => { + if (entries[0].isIntersecting && hasMore) { + loadMoreUsers(); + } + }, + { threshold: 1.0 } + ); + observer.observe(loader.current); + return () => observer.disconnect(); + } + }, [loader.current, hasMore, loadMoreUsers]); - return ( - <> -
-
- -
-
- - -
+ return ( + <> +
+
+ +
+
+ + +
+
+ + Users + Manage user roles and permissions. + + +
+ {userList.map((user) => ( +
+
+ + + + {user.name ? user.name[0] : "N/A"} + + +
+

+ {user.name || "Unknown"} +

+

+ {user.email || "No email"} +

+
+
+ + + + + + + + +
+ ))} +
+ {hasMore && ( +
+ {loading ? "Loading..." : "Load more"} +
+ )} +
+
+
- - Users - - Manage user roles and permissions. - - - -
- {userList.map((user) => ( -
-
- - - - {user.name ? user.name[0] : "N/A"} - - -
-

- {user.name || "Unknown"} -

-

- {user.email || "No email"} -

-
-
- - - - - - - - -
- ))} -
- {hasMore && ( -
- {loading ? "Loading..." : "Load more"} -
- )} -
- -
-
- - ); + + ); }; export default UsersList; diff --git a/src/components/HorizontalScrollCarousel.tsx b/src/components/HorizontalScrollCarousel.tsx index 661b919..196113f 100644 --- a/src/components/HorizontalScrollCarousel.tsx +++ b/src/components/HorizontalScrollCarousel.tsx @@ -1,112 +1,111 @@ +import { tedxsjecAssetsPrefix } from "@/lib/utils"; import { motion, useTransform, useScroll } from "framer-motion"; import { useRef } from "react"; const HorizontalScroll = () => { - return ( -
- -
- ); + return ( +
+ +
+ ); }; const HorizontalScrollCarousel = () => { - const targetRef = useRef(null); - const { scrollYProgress } = useScroll({ - target: targetRef, - }); + const targetRef = useRef(null); + const { scrollYProgress } = useScroll({ + target: targetRef, + }); - const x = useTransform(scrollYProgress, [0, 1], ["5%", "-50%"]); + const x = useTransform(scrollYProgress, [0, 1], ["5%", "-50%"]); - return ( -
-
- -

- The Team -

- {cards.map((card) => { - return ; - })} -
-
-
- ); + return ( +
+
+ +

The Team

+ {cards.map((card) => { + return ; + })} +
+
+
+ ); }; const Card = ({ card }: { card: CardType }) => { - return ( -
-
-
-
-

{card.name}

-

{card.title}

+ return ( +
+
+
+
+

{card.name}

+

{card.title}

+
+
-
-
- ); + ); }; export default HorizontalScroll; type CardType = { - url: string; - title: string; - id: number; - name: string; + url: string; + title: string; + id: number; + name: string; }; const cards: CardType[] = [ - // { - // url: "https://tedx-sjec.github.io/website-assets/team/dr-binu-k-g.avif", - // title: "Faculty Co-Ordinator", - // name: "Binu K G", - // id: 1, - // }, - { - url: "https://tedx-sjec.github.io/website-assets/team/sharon.avif", - title: "Licensee & Organizer", - id: 2, - name: "Sharon Tyana Menezes", - }, - { - url: "/imgs/abstract/3.jpg", - title: "Co-Organizer", - id: 3, - name: "Sasha Sajith", - }, - { - url: "/imgs/abstract/4.jpg", - title: "Curation Head", - id: 4, - name: "Vyasa M Nayak", - }, - { - url: "/imgs/abstract/5.jpg", - title: "Technical Head", - id: 5, - name: "Hanniel Andrede", - }, - { - url: "/imgs/abstract/6.jpg", - title: "Design Head", - id: 6, - name: "Lawrence Robert D'Souza", - }, - // { - // url: "/imgs/abstract/7.jpg", - // title: "Title 7", - // id: 7, - // name: "Binu K G", - // }, + // { + // url: "https://tedx-sjec.github.io/website-assets/team/dr-binu-k-g.avif", + // title: "Faculty Co-Ordinator", + // name: "Binu K G", + // id: 1, + // }, + { + url: `${tedxsjecAssetsPrefix}/team/sharon.avif`, + title: "Licensee & Organizer", + id: 2, + name: "Sharon Tyana Menezes", + }, + { + url: "/imgs/abstract/3.jpg", + title: "Co-Organizer", + id: 3, + name: "Sasha Sajith", + }, + { + url: "/imgs/abstract/4.jpg", + title: "Curation Head", + id: 4, + name: "Vyasa M Nayak", + }, + { + url: "/imgs/abstract/5.jpg", + title: "Technical Head", + id: 5, + name: "Hanniel Andrede", + }, + { + url: "/imgs/abstract/6.jpg", + title: "Design Head", + id: 6, + name: "Lawrence Robert D'Souza", + }, + // { + // url: "/imgs/abstract/7.jpg", + // title: "Title 7", + // id: 7, + // name: "Binu K G", + // }, ]; diff --git a/src/components/searchable-infinite-scroll-table.tsx b/src/components/searchable-infinite-scroll-table.tsx index 74509d9..05e190a 100644 --- a/src/components/searchable-infinite-scroll-table.tsx +++ b/src/components/searchable-infinite-scroll-table.tsx @@ -1,139 +1,169 @@ "use client"; -import { useEffect, useRef, useState } from "react"; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; +import { useEffect, useRef, useState, useCallback } from "react"; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Input } from "@/components/ui/input"; import { Loader2, Search } from "lucide-react"; +import axios from "axios"; +import debounce from "lodash.debounce"; interface TableData { - name: string; - email: string; - usn: string; - paymentId: string; - contactNumber: string; - amount: number; -} - -function generateMockData(count: number): TableData[] { - return Array.from({ length: count }, (_, i) => ({ - name: `User ${i + 1}`, - email: `user${i + 1}@example.com`, - usn: `USN${(1000 + i).toString().padStart(4, "0")}`, - paymentId: `PAY${(10000 + i).toString().padStart(5, "0")}`, - contactNumber: `+1 ${Math.floor(1000000000 + Math.random() * 9000000000)}`, - amount: Math.floor(10 + Math.random() * 990), - })); + user: { + name: string; + email: string; + }; + usn: string; + razorpayPaymentId: string; + contactNumber: string; + amount: number; } export function SearchableInfiniteScrollTable() { - const [data, setData] = useState([]); - const [filteredData, setFilteredData] = useState([]); - const [isLoading, setIsLoading] = useState(false); - const [page, setPage] = useState(1); - const [searchTerm, setSearchTerm] = useState(""); - const loaderRef = useRef(null); - - const loadMoreData = () => { - setIsLoading(true); - setTimeout(() => { - const newData = generateMockData(20); - setData((prevData) => [...prevData, ...newData]); - setPage((prevPage) => prevPage + 1); - setIsLoading(false); - }, 1000); // Simulating API delay - }; - - useEffect(() => { - loadMoreData(); - }, []); - - useEffect(() => { - const filtered = data.filter((item) => - Object.values(item).some((value) => - value.toString().toLowerCase().includes(searchTerm.toLowerCase()), - ), - ); - setFilteredData(filtered); - }, [data, searchTerm]); - - useEffect(() => { - const observer = new IntersectionObserver( - (entries) => { - if (entries[0].isIntersecting && !isLoading && searchTerm === "") { - loadMoreData(); + const [data, setData] = useState([]); + const [filteredData, setFilteredData] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [page, setPage] = useState(1); + const [searchTerm, setSearchTerm] = useState(""); + const [hasMoreData, setHasMoreData] = useState(true); + const loaderRef = useRef(null); + const observerRef = useRef(null); + + const getPaymentDetails = async (page: number, query: string) => { + if (isLoading || !hasMoreData) return; + + setIsLoading(true); + try { + const response = await axios.get( + `/api/users/payment?page=${page}&search=${encodeURIComponent(query)}` + ); + const users = response.data.users; + + if (users.length === 0) { + setHasMoreData(false); // No more data to load + } + + setData((prevData) => { + const newData = [...prevData, ...users]; + // Remove duplicates + const uniqueData = Array.from( + new Map(newData.map((item) => [item.razorpayPaymentId, item])).values() + ); + return uniqueData; + }); + setPage((prevPage) => prevPage + 1); + } catch (error) { + console.error("Error fetching payment details:", error); + } finally { + setIsLoading(false); + } + }; + + const loadMoreData = () => { + if (searchTerm === "") { + getPaymentDetails(page, ""); + } + }; + + const fetchSearchResults = useCallback(async (query: string) => { + setPage(1); // Reset page number + setHasMoreData(true); // Reset hasMoreData + try { + const response = await axios.get(`/api/users/payment?page=1&search=${encodeURIComponent(query)}`); + const users = response.data.users; + setData(users); // Set new data from search + setFilteredData(users); // Set filtered data to the same as new data + } catch (error) { + console.error("Error fetching payment details:", error); } - }, - { threshold: 1.0 }, + }, []); + + // eslint-disable-next-line react-hooks/exhaustive-deps + const debouncedFetch = useCallback( + debounce((query: string) => { + fetchSearchResults(query); + }, 500), + [] ); - if (loaderRef.current) { - observer.observe(loaderRef.current); - } + const handleSearch = (event: React.ChangeEvent) => { + const value = event.target.value; + setSearchTerm(value); + debouncedFetch(value); // Use debounced fetch function + }; - return () => { - if (loaderRef.current) { + useEffect(() => { + loadMoreData(); // Initial load // eslint-disable-next-line react-hooks/exhaustive-deps - observer.unobserve(loaderRef.current); - } - observer.disconnect(); - }; - }, [isLoading, searchTerm]); - - const handleSearch = (event: React.ChangeEvent) => { - setSearchTerm(event.target.value); - }; - - return ( -
-
- - -
- - - - Name - Email - USN - Payment ID - Contact Number - Amount - - - - {filteredData.map((item, index) => ( - - {item.name} - {item.email} - {item.usn} - {item.paymentId} - {item.contactNumber} - ${item.amount.toFixed(2)} - - ))} - -
- {searchTerm === "" && ( -
- {isLoading && } + }, []); + + useEffect(() => { + const observer = new IntersectionObserver( + (entries) => { + if (entries[0].isIntersecting && !isLoading) { + loadMoreData(); + } + }, + { threshold: 1.0 } + ); + + if (loaderRef.current) { + observer.observe(loaderRef.current); + } + + return () => { + if (loaderRef.current) { + // eslint-disable-next-line react-hooks/exhaustive-deps + observer.unobserve(loaderRef.current); + } + observer.disconnect(); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isLoading]); + + return ( +
+
+ + +
+ + + + Name + Email + USN + Payment ID + Contact Number + Amount + + + + {(searchTerm ? filteredData : data).map((item, index) => ( + + {item.user.name} + {item.user.email} + {item.usn} + {item.razorpayPaymentId} + {item.contactNumber} + ${item.amount.toFixed(2)} + + ))} + +
+ {searchTerm === "" && hasMoreData && ( +
+ {isLoading && } +
+ )}
- )} -
- ); + ); } diff --git a/src/lib/helper.ts b/src/lib/helper.ts index b7aa4e4..cebab00 100644 --- a/src/lib/helper.ts +++ b/src/lib/helper.ts @@ -1,3 +1,4 @@ +import crypto from "crypto"; export const generateCouponCode = (length: number) => { const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; @@ -10,3 +11,14 @@ export const generateCouponCode = (length: number) => { export const createCouponCode = () => { return generateCouponCode(10); }; + + +export const generatedSignature = (razorpayOrderId: string, razorpayPaymentId: string) => { + const keySecret = process.env.RAZORPAY_KEY_SECRET!; + + const sig = crypto + .createHmac("sha256", keySecret) + .update(razorpayOrderId + "|" + razorpayPaymentId) + .digest("hex"); + return sig; +}; \ No newline at end of file diff --git a/src/lib/razorpay.ts b/src/lib/razorpay.ts new file mode 100644 index 0000000..807098e --- /dev/null +++ b/src/lib/razorpay.ts @@ -0,0 +1,6 @@ +import Razorpay from "razorpay"; + +export const razorpay = new Razorpay({ + key_id: process.env.RAZORPAY_KEY_ID!, + key_secret: process.env.RAZORPAY_KEY_SECRET!, +}); diff --git a/src/lib/resend-mailer.ts b/src/lib/resend-mailer.ts index 201c9e5..1aaa68b 100644 --- a/src/lib/resend-mailer.ts +++ b/src/lib/resend-mailer.ts @@ -1,32 +1,32 @@ -import { EmailTemplate } from "./email-template"; +import { EmailTemplate } from "../../emails/email-template"; import { ResendEmailOptions, sendEmail as SendEmailType } from "@/types"; import { Resend } from "resend"; const resend = new Resend(process.env.RESEND_API_KEY); export async function MailUsingResend({ email, name, OTP }: SendEmailType) { - console.log(process.env.RESEND_API_KEY); - try { - const mailOptions: ResendEmailOptions = { - from: '"Tedx SJEC" ', - to: email, - subject: "Tedx SJEC - Your OTP for Email Verification", - react: EmailTemplate({ - name: name, - OTP: OTP, - email: email, - }), - text: `Hello ${name},\n\nThank you for registering for Tedx 2024.\n\nYour One-Time Password (OTP) for email verification is:\n\n${OTP}\n\nPlease enter this OTP to complete your registration. The OTP is valid for 10 minutes.\n\nThank you!\n\nTedx SJEC Team`, - }; + console.log(process.env.RESEND_API_KEY); + try { + const mailOptions: ResendEmailOptions = { + from: '"Tedx SJEC" ', + to: email, + subject: "Tedx SJEC - Your OTP for Email Verification", + react: EmailTemplate({ + name: name, + OTP: OTP, + email: email, + }), + text: `Hello ${name},\n\nThank you for registering for Tedx 2024.\n\nYour One-Time Password (OTP) for email verification is:\n\n${OTP}\n\nPlease enter this OTP to complete your registration. The OTP is valid for 10 minutes.\n\nThank you!\n\nTedx SJEC Team`, + }; - const { data, error } = await resend.emails.send(mailOptions); - console.log(data, error); - if (error) { - return { error, status: 500 }; - } + const { data, error } = await resend.emails.send(mailOptions); + console.log(data, error); + if (error) { + return { error, status: 500 }; + } - return { data, status: 200 }; - } catch (error) { - return { error, status: 500 }; - } + return { data, status: 200 }; + } catch (error) { + return { error, status: 500 }; + } } diff --git a/src/lib/send-registration-email.ts b/src/lib/send-registration-email.ts new file mode 100644 index 0000000..4d1cc1d --- /dev/null +++ b/src/lib/send-registration-email.ts @@ -0,0 +1,27 @@ +import { TedxRegistrationEmail } from "../../emails/user-registration-email-template"; +import { Resend } from "resend"; +import { ResendEmailOptions } from "@/types"; + +const resend = new Resend(process.env.RESEND_API_KEY); + +export async function sendRegistrationEmail({ + email, + name, + registrationLink, +}: { + email: string; + name: string; + registrationLink: string; +}) { + try { + await resend.emails.send({ + from: '"Tedx SJEC" ', + to: email, + subject: "Tedx SJEC - Email Verification", + react: TedxRegistrationEmail({ name, registrationLink }), + text: `Hello ${name},\n\nThank you for registering for Tedx 2024.\n\nPlease click on the link below to complete your registration.\n\n${registrationLink}\n\nThank you!\n\nTedx SJEC Team`, + }); + } catch (error) { + console.log(error); + } +} diff --git a/src/lib/sendMail.tsx b/src/lib/sendMail.tsx index 9d67326..c667aea 100644 --- a/src/lib/sendMail.tsx +++ b/src/lib/sendMail.tsx @@ -1,38 +1,34 @@ -import { EmailTemplate } from "./email-template"; +import { EmailTemplate } from "../../emails/email-template"; import { renderAsync } from "@react-email/render"; import { EmailOptions, sendEmail as SendEmailType } from "@/types"; import nodemailer from "nodemailer"; export const sendEmail = async (options: SendEmailType) => { - try { - const transporter = nodemailer.createTransport({ - service: "gmail", - auth: { - user: process.env.GMAIL_USER, - pass: process.env.GMAIL_PASS, - }, - }); + try { + const transporter = nodemailer.createTransport({ + service: "gmail", + auth: { + user: process.env.GMAIL_USER, + pass: process.env.GMAIL_PASS, + }, + }); - const emailHtml = await renderAsync( - , - ); + const emailHtml = await renderAsync( + + ); - const mailOptions: EmailOptions = { - from: `"Tedx SJEC" <${process.env.GMAIL_USER}>`, - to: options.email, - subject: "Tedx SJEC - Your OTP for Email Verification", - html: emailHtml, - text: `Hello ${options.name},\n\nThank you for registering for Tedx 2024.\n\nYour One-Time Password (OTP) for email verification is:\n\n${options.OTP}\n\nPlease enter this OTP to complete your registration. The OTP is valid for 10 minutes.\n\nThank you!\n\nTedx SJEC Team`, - }; - const mailResponse = await transporter.sendMail(mailOptions); - return { mailResponse, status: 200 }; - } catch (error) { - return { error, status: 500 }; - } + const mailOptions: EmailOptions = { + from: `"Tedx SJEC" <${process.env.GMAIL_USER}>`, + to: options.email, + subject: "Tedx SJEC - Your OTP for Email Verification", + html: emailHtml, + text: `Hello ${options.name},\n\nThank you for registering for Tedx 2024.\n\nYour One-Time Password (OTP) for email verification is:\n\n${options.OTP}\n\nPlease enter this OTP to complete your registration. The OTP is valid for 10 minutes.\n\nThank you!\n\nTedx SJEC Team`, + }; + const mailResponse = await transporter.sendMail(mailOptions); + return { mailResponse, status: 200 }; + } catch (error) { + return { error, status: 500 }; + } }; export default sendEmail; diff --git a/src/lib/utils.ts b/src/lib/utils.ts index a5ef193..bd2941b 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -2,5 +2,7 @@ import { clsx, type ClassValue } from "clsx"; import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)); + return twMerge(clsx(inputs)); } + +export const tedxsjecAssetsPrefix = "https://tedx-sjec.github.io/website-assets";