From 32fda7b8931e00977171323a47b4df10c213a691 Mon Sep 17 00:00:00 2001 From: tydolla00 <90355178+tydolla00@users.noreply.github.com> Date: Fri, 18 Oct 2024 21:10:42 -0400 Subject: [PATCH 01/15] bug fix, first prod deployment --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index fd3dbb5..ef4cb97 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. +# VSCode +.vscode + # dependencies /node_modules /.pnp @@ -27,6 +30,7 @@ yarn-error.log* # local env files .env*.local +/.env # vercel .vercel From 54d66cf1641e832d6d22e8686300423c15cc15e3 Mon Sep 17 00:00:00 2001 From: tydolla00 <90355178+tydolla00@users.noreply.github.com> Date: Sat, 2 Nov 2024 15:34:50 -0400 Subject: [PATCH 02/15] Create main.yml (#6) * Create main.yml For viewing logs of deployment before going to vercel. * Update main.yml --- .github/workflows/main.yml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..f105500 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,33 @@ +name: Vercel Build + +on: + push: + branches: + - main + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + + - name: Install Vercel CLI + run: npm install -g vercel + + - name: Pull Vercel Environment Variables + env: + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + run: vercel pull --yes --token ${{ secrets.VERCEL_TOKEN }} + + - name: Build with Vercel + env: + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + run: vercel build --token ${{ secrets.VERCEL_TOKEN }} --prod From 7fa67c45930e2222d1ff406c737fb320dee847eb Mon Sep 17 00:00:00 2001 From: Scott Hargrove Date: Sat, 2 Nov 2024 21:33:56 -0400 Subject: [PATCH 03/15] Implement Prisma + Model Structure (#5) db model creation --------- Co-authored-by: shargrove09 Co-authored-by: tydolla00 <90355178+tydolla00@users.noreply.github.com> --- .gitignore | 2 +- package-lock.json | 730 ++++++++++++------ package.json | 14 +- prisma/.env | 7 + prisma/dev.db | Bin 0 -> 53248 bytes prisma/lib/marioKart.ts | 161 ++++ .../20241021174935_init/migration.sql | 19 + .../20241022125255_rdcmodelsv01/migration.sql | 35 + .../20241022134030_rdcmodelsv02/migration.sql | 18 + .../20241023204014_rdcmodelsv03/migration.sql | 75 ++ .../20241024205334_rdcmodelsv04/migration.sql | 41 + .../migrations/20241028114014_/migration.sql | 50 ++ .../migrations/20241028142754_/migration.sql | 19 + .../20241102173000_rdcmodelsv05/migration.sql | 77 ++ prisma/migrations/migration_lock.toml | 3 + prisma/schema.prisma | 105 +++ prisma/script.ts | 38 + prisma/scripts/testbed.ts | 138 ++++ prisma/seed.ts | 359 +++++++++ prisma/types/gameSet.ts | 18 + prisma/types/playerSession.ts | 24 + prisma/types/playerStat.ts | 17 + prisma/types/session.ts | 22 + src/api/marioKartAPI.ts | 0 src/app/(routes)/submission/page.tsx | 5 +- src/app/layout.tsx | 11 +- src/components/navbar.tsx | 36 +- src/lib/config.ts | 26 + src/lib/featureflag.tsx | 35 + src/lib/providers.tsx | 20 + tsconfig.json | 8 +- 31 files changed, 1867 insertions(+), 246 deletions(-) create mode 100644 prisma/.env create mode 100644 prisma/dev.db create mode 100644 prisma/lib/marioKart.ts create mode 100644 prisma/migrations/20241021174935_init/migration.sql create mode 100644 prisma/migrations/20241022125255_rdcmodelsv01/migration.sql create mode 100644 prisma/migrations/20241022134030_rdcmodelsv02/migration.sql create mode 100644 prisma/migrations/20241023204014_rdcmodelsv03/migration.sql create mode 100644 prisma/migrations/20241024205334_rdcmodelsv04/migration.sql create mode 100644 prisma/migrations/20241028114014_/migration.sql create mode 100644 prisma/migrations/20241028142754_/migration.sql create mode 100644 prisma/migrations/20241102173000_rdcmodelsv05/migration.sql create mode 100644 prisma/migrations/migration_lock.toml create mode 100644 prisma/schema.prisma create mode 100644 prisma/script.ts create mode 100644 prisma/scripts/testbed.ts create mode 100644 prisma/seed.ts create mode 100644 prisma/types/gameSet.ts create mode 100644 prisma/types/playerSession.ts create mode 100644 prisma/types/playerStat.ts create mode 100644 prisma/types/session.ts create mode 100644 src/api/marioKartAPI.ts create mode 100644 src/lib/config.ts create mode 100644 src/lib/featureflag.tsx create mode 100644 src/lib/providers.tsx diff --git a/.gitignore b/.gitignore index ef4cb97..78e1d69 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. -# VSCode +# vs .vscode # dependencies diff --git a/package-lock.json b/package-lock.json index 2360ce5..fbbd119 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "dependencies": { "@hookform/resolvers": "^3.9.0", + "@prisma/client": "^5.21.1", "@radix-ui/react-avatar": "^1.1.1", "@radix-ui/react-checkbox": "^1.1.2", "@radix-ui/react-dropdown-menu": "^2.1.2", @@ -26,6 +27,7 @@ "lucide-react": "^0.378.0", "next": "14.2.3", "next-themes": "^0.3.0", + "posthog-js": "^1.180.1", "react": "^18", "react-dom": "^18", "react-hook-form": "^7.53.1", @@ -33,10 +35,11 @@ "sonner": "^1.5.0", "tailwind-merge": "^2.5.4", "tailwindcss-animate": "^1.0.7", + "ts-node": "^10.9.2", "zod": "^3.23.8" }, "devDependencies": { - "@types/node": "^20", + "@types/node": "^20.17.1", "@types/react": "^18", "@types/react-dom": "^18", "eslint": "^8", @@ -44,8 +47,9 @@ "postcss": "^8", "prettier": "^3.3.3", "prettier-plugin-tailwindcss": "^0.6.8", + "prisma": "^5.21.1", "tailwindcss": "^3.4.1", - "typescript": "^5" + "typescript": "^5.6.3" } }, "node_modules/@alloc/quick-lru": { @@ -60,9 +64,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz", - "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -70,25 +74,48 @@ "node": ">=6.9.0" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -118,9 +145,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -135,9 +162,9 @@ } }, "node_modules/@floating-ui/dom": { - "version": "1.6.11", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.11.tgz", - "integrity": "sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==", + "version": "1.6.12", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.12.tgz", + "integrity": "sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==", "dependencies": { "@floating-ui/core": "^1.6.0", "@floating-ui/utils": "^0.2.8" @@ -161,20 +188,21 @@ "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==" }, "node_modules/@hookform/resolvers": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.9.0.tgz", - "integrity": "sha512-bU0Gr4EepJ/EQsH/IwEzYLsT/PEj5C0ynLQ4m+GSHS+xKH4TfSelhluTgOaoc4kA5s7eCsQbM4wvZLzELmWzUg==", + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.9.1.tgz", + "integrity": "sha512-ud2HqmGBM0P0IABqoskKWI6PEf6ZDDBZkFqe2Vnl+mTHCEHzr3ISjjZyCwTjC/qpL25JC9aIDkloQejvMeq0ug==", "peerDependencies": { "react-hook-form": "^7.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", + "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", "minimatch": "^3.0.5" }, @@ -199,6 +227,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", "dev": true }, "node_modules/@isaacs/cliui": { @@ -218,9 +247,9 @@ } }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "engines": { "node": ">=12" }, @@ -272,9 +301,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", @@ -466,6 +495,15 @@ "node": ">= 8" } }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "engines": { + "node": ">=12.4.0" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -475,6 +513,68 @@ "node": ">=14" } }, + "node_modules/@prisma/client": { + "version": "5.21.1", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.21.1.tgz", + "integrity": "sha512-3n+GgbAZYjaS/k0M03yQsQfR1APbr411r74foknnsGpmhNKBG49VuUkxIU6jORgvJPChoD4WC4PqoHImN1FP0w==", + "hasInstallScript": true, + "engines": { + "node": ">=16.13" + }, + "peerDependencies": { + "prisma": "*" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + } + } + }, + "node_modules/@prisma/debug": { + "version": "5.21.1", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.21.1.tgz", + "integrity": "sha512-uY8SAhcnORhvgtOrNdvWS98Aq/nkQ9QDUxrWAgW8XrCZaI3j2X7zb7Xe6GQSh6xSesKffFbFlkw0c2luHQviZA==", + "devOptional": true + }, + "node_modules/@prisma/engines": { + "version": "5.21.1", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.21.1.tgz", + "integrity": "sha512-hGVTldUkIkTwoV8//hmnAAiAchi4oMEKD3aW5H2RrnI50tTdwza7VQbTTAyN3OIHWlK5DVg6xV7X8N/9dtOydA==", + "devOptional": true, + "hasInstallScript": true, + "dependencies": { + "@prisma/debug": "5.21.1", + "@prisma/engines-version": "5.21.1-1.bf0e5e8a04cada8225617067eaa03d041e2bba36", + "@prisma/fetch-engine": "5.21.1", + "@prisma/get-platform": "5.21.1" + } + }, + "node_modules/@prisma/engines-version": { + "version": "5.21.1-1.bf0e5e8a04cada8225617067eaa03d041e2bba36", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.21.1-1.bf0e5e8a04cada8225617067eaa03d041e2bba36.tgz", + "integrity": "sha512-qvnEflL0//lh44S/T9NcvTMxfyowNeUxTunPcDfKPjyJNrCNf2F1zQLcUv5UHAruECpX+zz21CzsC7V2xAeM7Q==", + "devOptional": true + }, + "node_modules/@prisma/fetch-engine": { + "version": "5.21.1", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.21.1.tgz", + "integrity": "sha512-70S31vgpCGcp9J+mh/wHtLCkVezLUqe/fGWk3J3JWZIN7prdYSlr1C0niaWUyNK2VflLXYi8kMjAmSxUVq6WGQ==", + "devOptional": true, + "dependencies": { + "@prisma/debug": "5.21.1", + "@prisma/engines-version": "5.21.1-1.bf0e5e8a04cada8225617067eaa03d041e2bba36", + "@prisma/get-platform": "5.21.1" + } + }, + "node_modules/@prisma/get-platform": { + "version": "5.21.1", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.21.1.tgz", + "integrity": "sha512-sRxjL3Igst3ct+e8ya/x//cDXmpLbZQ5vfps2N4tWl4VGKQAmym77C/IG/psSMsQKszc8uFC/q1dgmKFLUgXZQ==", + "devOptional": true, + "dependencies": { + "@prisma/debug": "5.21.1" + } + }, "node_modules/@radix-ui/number": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.0.tgz", @@ -765,11 +865,11 @@ } }, "node_modules/@radix-ui/react-icons": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.0.tgz", - "integrity": "sha512-jQxj/0LKgp+j9BiTXz3O3sgs26RNet2iLWmsPyRz2SIcR4q/4SbazXfnYwbAr+vLYKSfc7qxzyGQA1HLlYiuNw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.1.tgz", + "integrity": "sha512-QvYompk0X+8Yjlo/Fv4McrzxohDdM5GgLHyQcPpcsPvlOSXCGFjdbuyGL5dzRbg0GpknAjQJJZzdiRK7iWVuFQ==", "peerDependencies": { - "react": "^16.x || ^17.x || ^18.x" + "react": "^16.x || ^17.x || ^18.x || ^19.x" } }, "node_modules/@radix-ui/react-id": { @@ -1357,6 +1457,26 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" + }, "node_modules/@types/d3-array": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", @@ -1418,12 +1538,11 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.12.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", - "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", - "dev": true, + "version": "20.17.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.5.tgz", + "integrity": "sha512-n8FYY/pRxu496441gIcAQFZPKXbhsd6VZygcq+PTSZ75eMh/Ke0hCAROdUa21qiFqKNsPPYic46yXDO1JGiPBQ==", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, "node_modules/@types/prop-types": { @@ -1585,10 +1704,9 @@ "dev": true }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "bin": { "acorn": "bin/acorn" }, @@ -1605,6 +1723,17 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -1872,9 +2001,9 @@ } }, "node_modules/axe-core": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.1.tgz", - "integrity": "sha512-qPC9o+kD8Tir0lzNGLeghbOrWMr3ZJpaRlCIb6Uobt/7N4FiEDvqUMnxzCHRHmg8vOg14kr5gVNyScRmbMaJ9g==", + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.2.tgz", + "integrity": "sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w==", "dev": true, "engines": { "node": ">=4" @@ -1916,11 +2045,11 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1974,9 +2103,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001620", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001620.tgz", - "integrity": "sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew==", + "version": "1.0.30001677", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001677.tgz", + "integrity": "sha512-fmfjsOlJUpMWu+mAAtZZZHz7UEwsUxIIvu1TJfO1HqFQvB/B+ii0xr9B5HpbZY/mC4XZ8SvjHJqtAY6pDPQEog==", "funding": [ { "type": "opencollective", @@ -2104,6 +2233,21 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/core-js": { + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz", + "integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2301,12 +2445,12 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -2372,6 +2516,14 @@ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -2421,9 +2573,9 @@ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/enhanced-resolve": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.1.tgz", - "integrity": "sha512-4U5pNsuDl0EhuZpq46M5xPslstkviJuhrdobaRDBk2Jy2KO37FDAJl4lb2KlNabxT0m4MTK2UHNrsAcphE8nyw==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -2604,16 +2756,17 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -2705,17 +2858,18 @@ } }, "node_modules/eslint-import-resolver-typescript": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", - "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", - "dev": true, - "dependencies": { - "debug": "^4.3.4", - "enhanced-resolve": "^5.12.0", - "eslint-module-utils": "^2.7.4", - "fast-glob": "^3.3.1", - "get-tsconfig": "^4.5.0", - "is-core-module": "^2.11.0", + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.3.tgz", + "integrity": "sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==", + "dev": true, + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.3.5", + "enhanced-resolve": "^5.15.0", + "eslint-module-utils": "^2.8.1", + "fast-glob": "^3.3.2", + "get-tsconfig": "^4.7.5", + "is-bun-module": "^1.0.2", "is-glob": "^4.0.3" }, "engines": { @@ -2726,7 +2880,16 @@ }, "peerDependencies": { "eslint": "*", - "eslint-plugin-import": "*" + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } } }, "node_modules/eslint-module-utils": { @@ -2819,9 +2982,9 @@ } }, "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.1.tgz", - "integrity": "sha512-zHByM9WTUMnfsDTafGXRiqxp6lFtNoSOWBY6FonVRn3A+BUwN1L/tdBXT40BcBJi0cZjOGTXZ0eD/rTG9fEJ0g==", + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", + "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", "dev": true, "dependencies": { "aria-query": "^5.3.2", @@ -2832,7 +2995,6 @@ "axobject-query": "^4.1.0", "damerau-levenshtein": "^1.0.8", "emoji-regex": "^9.2.2", - "es-iterator-helpers": "^1.1.0", "hasown": "^2.0.2", "jsx-ast-utils": "^3.3.5", "language-tags": "^1.0.9", @@ -2849,9 +3011,9 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.37.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.1.tgz", - "integrity": "sha512-xwTnwDqzbDRA8uJ7BMxPs/EXRB3i8ZfnOIp8BsxEQkT0nHPp+WWceqGgo6rKb9ctNi8GJLDT4Go5HAWELa/WMg==", + "version": "7.37.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.2.tgz", + "integrity": "sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==", "dev": true, "dependencies": { "array-includes": "^3.1.8", @@ -2859,7 +3021,7 @@ "array.prototype.flatmap": "^1.3.2", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.19", + "es-iterator-helpers": "^1.1.0", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", @@ -2976,9 +3138,9 @@ } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -3082,6 +3244,11 @@ "reusify": "^1.0.4" } }, + "node_modules/fflate": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", + "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==" + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -3095,9 +3262,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -3151,9 +3318,9 @@ } }, "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -3264,9 +3431,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", - "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", + "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", "dev": true, "dependencies": { "resolve-pkg-maps": "^1.0.0" @@ -3316,9 +3483,9 @@ } }, "node_modules/glob/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -3484,9 +3651,9 @@ } }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "engines": { "node": ">= 4" @@ -3521,6 +3688,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, "dependencies": { "once": "^1.3.0", @@ -3633,6 +3801,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-bun-module": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-1.2.1.tgz", + "integrity": "sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==", + "dev": true, + "dependencies": { + "semver": "^7.6.3" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -3972,9 +4149,9 @@ } }, "node_modules/jiti": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", - "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", "bin": { "jiti": "bin/jiti.js" } @@ -4132,12 +4309,9 @@ } }, "node_modules/lru-cache": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", - "engines": { - "node": "14 || >=16.14" - } + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" }, "node_modules/lucide-react": { "version": "0.378.0", @@ -4147,6 +4321,11 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -4156,11 +4335,11 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -4189,17 +4368,17 @@ } }, "node_modules/minipass": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz", - "integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "node_modules/mz": { @@ -4345,10 +4524,13 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4567,9 +4749,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -4608,9 +4790,9 @@ } }, "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", "funding": [ { "type": "opencollective", @@ -4627,8 +4809,8 @@ ], "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" @@ -4703,9 +4885,9 @@ } }, "node_modules/postcss-load-config/node_modules/lilconfig": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", - "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", "engines": { "node": ">=14" }, @@ -4714,27 +4896,33 @@ } }, "node_modules/postcss-nested": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", - "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "postcss-selector-parser": "^6.0.11" + "postcss-selector-parser": "^6.1.1" }, "engines": { "node": ">=12.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, "peerDependencies": { "postcss": "^8.2.14" } }, "node_modules/postcss-selector-parser": { - "version": "6.0.16", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", - "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -4748,6 +4936,26 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, + "node_modules/posthog-js": { + "version": "1.180.1", + "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.180.1.tgz", + "integrity": "sha512-LV65maVrpqkAh0wu32YvU7FpCSEjg6o+sZFYCs1+6tnEa9VvXuz8J6ReLiyRpJABI4j1qX/PB2jaVY5tDbLalQ==", + "dependencies": { + "core-js": "^3.38.1", + "fflate": "^0.4.8", + "preact": "^10.19.3", + "web-vitals": "^4.2.0" + } + }, + "node_modules/preact": { + "version": "10.24.3", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz", + "integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -4850,6 +5058,25 @@ } } }, + "node_modules/prisma": { + "version": "5.21.1", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.21.1.tgz", + "integrity": "sha512-PB+Iqzld/uQBPaaw2UVIk84kb0ITsLajzsxzsadxxl54eaU5Gyl2/L02ysivHxK89t7YrfQJm+Ggk37uvM70oQ==", + "devOptional": true, + "hasInstallScript": true, + "dependencies": { + "@prisma/engines": "5.21.1" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=16.13" + }, + "optionalDependencies": { + "fsevents": "2.3.3" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -4976,6 +5203,20 @@ } } }, + "node_modules/react-smooth": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.1.tgz", + "integrity": "sha512-OE4hm7XqR0jNOq3Qmk9mFLyd6p2+j6bvbPJ7qlB7+oo0eNcL2l7WQzG6MBnT3EXY6xzkLMUBec3AfewJdA0J8w==", + "dependencies": { + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-style-singleton": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", @@ -4998,6 +5239,21 @@ } } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -5018,9 +5274,9 @@ } }, "node_modules/recharts": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.13.0.tgz", - "integrity": "sha512-sbfxjWQ+oLWSZEWmvbq/DFVdeRLqqA6d0CDjKx2PkxVVdoXo16jvENCE+u/x7HxOO+/fwx//nYRwb8p8X6s/lQ==", + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.13.3.tgz", + "integrity": "sha512-YDZ9dOfK9t3ycwxgKbrnDlRC4BHdjlY73fet3a0C1+qGMjXVZe6+VXmpOIIhzkje5MMEL8AN4hLIe4AMskBzlA==", "dependencies": { "clsx": "^2.0.0", "eventemitter3": "^4.0.1", @@ -5052,35 +5308,6 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" }, - "node_modules/recharts/node_modules/react-smooth": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.1.tgz", - "integrity": "sha512-OE4hm7XqR0jNOq3Qmk9mFLyd6p2+j6bvbPJ7qlB7+oo0eNcL2l7WQzG6MBnT3EXY6xzkLMUBec3AfewJdA0J8w==", - "dependencies": { - "fast-equals": "^5.0.1", - "prop-types": "^15.8.1", - "react-transition-group": "^4.4.5" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/recharts/node_modules/react-smooth/node_modules/react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", - "dependencies": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" - }, - "peerDependencies": { - "react": ">=16.6.0", - "react-dom": ">=16.6.0" - } - }, "node_modules/reflect.getprototypeof": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", @@ -5108,15 +5335,15 @@ "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==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", + "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -5172,6 +5399,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "dependencies": { "glob": "^7.1.3" @@ -5187,6 +5415,7 @@ "version": "7.2.3", "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", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -5370,18 +5599,18 @@ } }, "node_modules/sonner": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/sonner/-/sonner-1.5.0.tgz", - "integrity": "sha512-FBjhG/gnnbN6FY0jaNnqZOMmB73R+5IiyYAw8yBj7L54ER7HB3fOSE5OFiQiE2iXWxeXKvg6fIP4LtVppHEdJA==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-1.6.1.tgz", + "integrity": "sha512-0iD+eDJHyJitl069BC6wVDykQD56FMKk4TD6XkcCcikcDYaGsFKlSU0mZQXYWKPpFof3jlV/u4vGZc2KCqz8OQ==", "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "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==", "engines": { "node": ">=0.10.0" } @@ -5430,9 +5659,9 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "engines": { "node": ">=12" }, @@ -5673,9 +5902,9 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", - "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==", + "version": "3.4.14", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.14.tgz", + "integrity": "sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -5767,9 +5996,9 @@ } }, "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==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.0.tgz", + "integrity": "sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==", "dev": true, "engines": { "node": ">=16" @@ -5783,6 +6012,53 @@ "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -5796,9 +6072,9 @@ } }, "node_modules/tslib": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", - "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, "node_modules/type-check": { "version": "0.4.0", @@ -5898,10 +6174,9 @@ } }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "dev": true, + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -5926,10 +6201,9 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" }, "node_modules/uri-js": { "version": "4.4.1", @@ -5986,6 +6260,11 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" + }, "node_modules/victory-vendor": { "version": "36.9.2", "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", @@ -6007,6 +6286,11 @@ "d3-timer": "^3.0.1" } }, + "node_modules/web-vitals": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz", + "integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -6161,9 +6445,9 @@ } }, "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "engines": { "node": ">=12" }, @@ -6203,9 +6487,9 @@ "dev": true }, "node_modules/yaml": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", - "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", + "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", "bin": { "yaml": "bin.mjs" }, @@ -6213,6 +6497,14 @@ "node": ">= 14" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index fbe3ad1..6b5a2fe 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,14 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "dbcrashout": "npx prisma db push --force-reset && npx prisma db push" + }, + "prisma": { + "seed": "ts-node prisma/seed.ts" }, "dependencies": { + "@prisma/client": "^5.21.1", "@hookform/resolvers": "^3.9.0", "@radix-ui/react-avatar": "^1.1.1", "@radix-ui/react-checkbox": "^1.1.2", @@ -27,6 +32,7 @@ "lucide-react": "^0.378.0", "next": "14.2.3", "next-themes": "^0.3.0", + "posthog-js": "^1.180.1", "react": "^18", "react-dom": "^18", "react-hook-form": "^7.53.1", @@ -34,10 +40,11 @@ "sonner": "^1.5.0", "tailwind-merge": "^2.5.4", "tailwindcss-animate": "^1.0.7", + "ts-node": "^10.9.2", "zod": "^3.23.8" }, "devDependencies": { - "@types/node": "^20", + "@types/node": "^20.17.1", "@types/react": "^18", "@types/react-dom": "^18", "eslint": "^8", @@ -45,7 +52,8 @@ "postcss": "^8", "prettier": "^3.3.3", "prettier-plugin-tailwindcss": "^0.6.8", + "prisma": "^5.21.1", "tailwindcss": "^3.4.1", - "typescript": "^5" + "typescript": "^5.6.3" } } diff --git a/prisma/.env b/prisma/.env new file mode 100644 index 0000000..c498ab5 --- /dev/null +++ b/prisma/.env @@ -0,0 +1,7 @@ +# Environment variables declared in this file are automatically made available to Prisma. +# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema + +# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB. +# See the documentation for all the connection string options: https://pris.ly/d/connection-strings + +DATABASE_URL="file:./dev.db" \ No newline at end of file diff --git a/prisma/dev.db b/prisma/dev.db new file mode 100644 index 0000000000000000000000000000000000000000..bd8471b0100b1ec9e1d2ce7bf131c5d7976d02fd GIT binary patch literal 53248 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 iPl2O)! { + try { + const latestMK8Session: EnrichedSession | null = + await prisma.session.findFirst({ + where: { + gameId: 1, + }, + orderBy: { + sessionId: "desc", + }, + include: { + sets: { + include: { + playerSessions: { + include: { + player: { + select: { + playerName: true, + }, + }, + playerStats: true, + }, + }, + }, + }, + }, + }); + + if (latestMK8Session != null) { + return latestMK8Session; + } + } catch (error) { + console.error("Error Fetching Latest Mario Kart Session"); + } +}; + +// Get detailed information about set by ID +const getMarioKart8SetById = async (setId: number) => { + try { + const mk8Set = await prisma.gameSet.findUnique({ + where: { + setId: setId, + }, + include: { + playerSessions: { + include: { + player: { + select: { + playerName: true, + }, + }, + playerStats: true, + }, + }, + }, + }); + console.log("Mario Kart 8 Set: ", mk8Set); + } catch (error) { + console.error("Error Fetching Mario Kart 8 Set"); + } +}; + +// Find Winner of Set(s) +// By ID +async function findWinnerOfSet(setId: number) { + try { + const mk8Set = await prisma.gameSet.findUnique({ + where: { + setId: setId, + }, + include: { + playerSessions: { + include: { + player: { + select: { + playerName: true, + }, + }, + playerStats: true, + }, + }, + }, + }); + + // Copilot suggested this - logic doesnt seem sound + + if (mk8Set) { + let winner = mk8Set.playerSessions[0]; + for (const playerSession of mk8Set.playerSessions) { + if (playerSession.playerStats[0].value > winner.playerStats[0].value) { + winner = playerSession; + } + } + + console.log(`Winner of Set ${setId}: ${winner.player.playerName}`); + } + } catch (error) { + console.error("Error Fetching Winner of Set"); + } +} + +// Also should do just given a Set object + +// --- Helper Functions --- + +// Print out stats for each player in each set grouped +function printPlayerStatsFromSet( + latestMK8Session: EnrichedSession | undefined, +) { + if (latestMK8Session) { + for (const set of latestMK8Session.sets) { + console.log(`--- Set ${set.setId} ---`); + for (const playerSession of set.playerSessions) { + console.log(`Player: ${playerSession.player.playerName}`); + + for (const playerStat of playerSession.playerStats) { + console.log(`Stat ID: ${playerStat.statId} ${playerStat.value}`); + } + } + } + } +} + +// Return a list of player stats per race in a set +async function getPlayerRankingsByRace(race: PlayerSession[]) {} + +// Get player averages and rank (sorriest racer stat) + +// --- Player Specific --- + +// Get number of (nth) places + +// --- TODO Laters --- + +// Get All MK8 sessions (paginated) + +// --- Main Function Since Vercel won't let me merge --- + +// Testing Purposes Main Function (Comment out when not in use) +async function main() { + const latestMK8Session = await getLatestMarioKart8Session(); + + findWinnerOfSet(1); +} + +main() + .then(async () => { + await prisma.$disconnect(); + }) + .catch(async (e) => { + console.error(e); + await prisma.$disconnect(); + process.exit(1); + }); diff --git a/prisma/migrations/20241021174935_init/migration.sql b/prisma/migrations/20241021174935_init/migration.sql new file mode 100644 index 0000000..16407fb --- /dev/null +++ b/prisma/migrations/20241021174935_init/migration.sql @@ -0,0 +1,19 @@ +-- CreateTable +CREATE TABLE "User" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "email" TEXT NOT NULL, + "name" TEXT +); + +-- CreateTable +CREATE TABLE "Post" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "title" TEXT NOT NULL, + "content" TEXT, + "published" BOOLEAN NOT NULL DEFAULT false, + "authorId" INTEGER NOT NULL, + CONSTRAINT "Post_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE +); + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); diff --git a/prisma/migrations/20241022125255_rdcmodelsv01/migration.sql b/prisma/migrations/20241022125255_rdcmodelsv01/migration.sql new file mode 100644 index 0000000..e065ac7 --- /dev/null +++ b/prisma/migrations/20241022125255_rdcmodelsv01/migration.sql @@ -0,0 +1,35 @@ +-- CreateTable +CREATE TABLE "Player" ( + "player_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "player_name" TEXT NOT NULL +); + +-- CreateTable +CREATE TABLE "Game" ( + "game_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "game_name" TEXT NOT NULL, + "release_date" DATETIME NOT NULL +); + +-- CreateTable +CREATE TABLE "GameStats" ( + "stat_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "game_id" INTEGER NOT NULL, + "stat_name" TEXT NOT NULL, + "stat_value" TEXT NOT NULL, + "recorded_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "GameStats_game_id_fkey" FOREIGN KEY ("game_id") REFERENCES "Game" ("game_id") ON DELETE RESTRICT ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "PlayerGameStats" ( + "player_game_stat_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "player_id" INTEGER NOT NULL, + "game_id" INTEGER NOT NULL, + "stat_id" INTEGER NOT NULL, + "value" TEXT NOT NULL, + "date_played" DATETIME NOT NULL, + CONSTRAINT "PlayerGameStats_player_id_fkey" FOREIGN KEY ("player_id") REFERENCES "Player" ("player_id") ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT "PlayerGameStats_game_id_fkey" FOREIGN KEY ("game_id") REFERENCES "Game" ("game_id") ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT "PlayerGameStats_stat_id_fkey" FOREIGN KEY ("stat_id") REFERENCES "GameStats" ("stat_id") ON DELETE RESTRICT ON UPDATE CASCADE +); diff --git a/prisma/migrations/20241022134030_rdcmodelsv02/migration.sql b/prisma/migrations/20241022134030_rdcmodelsv02/migration.sql new file mode 100644 index 0000000..fee1cf3 --- /dev/null +++ b/prisma/migrations/20241022134030_rdcmodelsv02/migration.sql @@ -0,0 +1,18 @@ +/* + Warnings: + + - You are about to drop the column `release_date` on the `Game` table. All the data in the column will be lost. + +*/ +-- RedefineTables +PRAGMA defer_foreign_keys=ON; +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_Game" ( + "game_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "game_name" TEXT NOT NULL +); +INSERT INTO "new_Game" ("game_id", "game_name") SELECT "game_id", "game_name" FROM "Game"; +DROP TABLE "Game"; +ALTER TABLE "new_Game" RENAME TO "Game"; +PRAGMA foreign_keys=ON; +PRAGMA defer_foreign_keys=OFF; diff --git a/prisma/migrations/20241023204014_rdcmodelsv03/migration.sql b/prisma/migrations/20241023204014_rdcmodelsv03/migration.sql new file mode 100644 index 0000000..c20c960 --- /dev/null +++ b/prisma/migrations/20241023204014_rdcmodelsv03/migration.sql @@ -0,0 +1,75 @@ +/* + Warnings: + + - You are about to drop the `Game` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `GameStats` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `Player` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `PlayerGameStats` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `Post` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `User` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropTable +PRAGMA foreign_keys=off; +DROP TABLE "Game"; +PRAGMA foreign_keys=on; + +-- DropTable +PRAGMA foreign_keys=off; +DROP TABLE "GameStats"; +PRAGMA foreign_keys=on; + +-- DropTable +PRAGMA foreign_keys=off; +DROP TABLE "Player"; +PRAGMA foreign_keys=on; + +-- DropTable +PRAGMA foreign_keys=off; +DROP TABLE "PlayerGameStats"; +PRAGMA foreign_keys=on; + +-- DropTable +PRAGMA foreign_keys=off; +DROP TABLE "Post"; +PRAGMA foreign_keys=on; + +-- DropTable +PRAGMA foreign_keys=off; +DROP TABLE "User"; +PRAGMA foreign_keys=on; + +-- CreateTable +CREATE TABLE "players" ( + "player_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "player_name" TEXT NOT NULL +); + +-- CreateTable +CREATE TABLE "games" ( + "game_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "game_name" TEXT NOT NULL +); + +-- CreateTable +CREATE TABLE "game_stats" ( + "stat_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "game_id" INTEGER NOT NULL, + "stat_name" TEXT NOT NULL, + "stat_value" TEXT NOT NULL, + "date" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "game_stats_game_id_fkey" FOREIGN KEY ("game_id") REFERENCES "games" ("game_id") ON DELETE RESTRICT ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "player_stats" ( + "player_game_stat_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "player_id" INTEGER NOT NULL, + "game_id" INTEGER NOT NULL, + "stat_id" INTEGER NOT NULL, + "value" TEXT NOT NULL, + "date_play" DATETIME NOT NULL, + CONSTRAINT "player_stats_player_id_fkey" FOREIGN KEY ("player_id") REFERENCES "players" ("player_id") ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT "player_stats_game_id_fkey" FOREIGN KEY ("game_id") REFERENCES "games" ("game_id") ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT "player_stats_stat_id_fkey" FOREIGN KEY ("stat_id") REFERENCES "game_stats" ("stat_id") ON DELETE RESTRICT ON UPDATE CASCADE +); diff --git a/prisma/migrations/20241024205334_rdcmodelsv04/migration.sql b/prisma/migrations/20241024205334_rdcmodelsv04/migration.sql new file mode 100644 index 0000000..cf881ec --- /dev/null +++ b/prisma/migrations/20241024205334_rdcmodelsv04/migration.sql @@ -0,0 +1,41 @@ +/* + Warnings: + + - You are about to drop the column `date_play` on the `player_stats` table. All the data in the column will be lost. + - Added the required column `date_played` to the `player_stats` table without a default value. This is not possible if the table is not empty. + +*/ +-- CreateTable +CREATE TABLE "game_sessions" ( + "session_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "gameId" INTEGER NOT NULL +); + +-- CreateTable +CREATE TABLE "game_session_players" ( + "game_session_player_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "session_id" INTEGER NOT NULL, + "player_id" INTEGER NOT NULL, + CONSTRAINT "game_session_players_session_id_fkey" FOREIGN KEY ("session_id") REFERENCES "game_sessions" ("session_id") ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT "game_session_players_player_id_fkey" FOREIGN KEY ("player_id") REFERENCES "players" ("player_id") ON DELETE RESTRICT ON UPDATE CASCADE +); + +-- RedefineTables +PRAGMA defer_foreign_keys=ON; +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_player_stats" ( + "player_game_stat_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "player_id" INTEGER NOT NULL, + "game_id" INTEGER NOT NULL, + "stat_id" INTEGER NOT NULL, + "value" TEXT NOT NULL, + "date_played" DATETIME NOT NULL, + CONSTRAINT "player_stats_player_id_fkey" FOREIGN KEY ("player_id") REFERENCES "players" ("player_id") ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT "player_stats_game_id_fkey" FOREIGN KEY ("game_id") REFERENCES "games" ("game_id") ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT "player_stats_stat_id_fkey" FOREIGN KEY ("stat_id") REFERENCES "game_stats" ("stat_id") ON DELETE RESTRICT ON UPDATE CASCADE +); +INSERT INTO "new_player_stats" ("game_id", "player_game_stat_id", "player_id", "stat_id", "value") SELECT "game_id", "player_game_stat_id", "player_id", "stat_id", "value" FROM "player_stats"; +DROP TABLE "player_stats"; +ALTER TABLE "new_player_stats" RENAME TO "player_stats"; +PRAGMA foreign_keys=ON; +PRAGMA defer_foreign_keys=OFF; diff --git a/prisma/migrations/20241028114014_/migration.sql b/prisma/migrations/20241028114014_/migration.sql new file mode 100644 index 0000000..365569a --- /dev/null +++ b/prisma/migrations/20241028114014_/migration.sql @@ -0,0 +1,50 @@ +/* + Warnings: + + - You are about to drop the `game_sessions` table. If the table is not empty, all the data it contains will be lost. + - Added the required column `session_id` to the `player_stats` table without a default value. This is not possible if the table is not empty. + +*/ +-- DropTable +PRAGMA foreign_keys=off; +DROP TABLE "game_sessions"; +PRAGMA foreign_keys=on; + +-- CreateTable +CREATE TABLE "sessions" ( + "session_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "session_name" TEXT NOT NULL, + "session_url" TEXT NOT NULL, + "gameId" INTEGER NOT NULL +); + +-- RedefineTables +PRAGMA defer_foreign_keys=ON; +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_game_session_players" ( + "game_session_player_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "session_id" INTEGER NOT NULL, + "player_id" INTEGER NOT NULL, + CONSTRAINT "game_session_players_session_id_fkey" FOREIGN KEY ("session_id") REFERENCES "sessions" ("session_id") ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT "game_session_players_player_id_fkey" FOREIGN KEY ("player_id") REFERENCES "players" ("player_id") ON DELETE RESTRICT ON UPDATE CASCADE +); +INSERT INTO "new_game_session_players" ("game_session_player_id", "player_id", "session_id") SELECT "game_session_player_id", "player_id", "session_id" FROM "game_session_players"; +DROP TABLE "game_session_players"; +ALTER TABLE "new_game_session_players" RENAME TO "game_session_players"; +CREATE TABLE "new_player_stats" ( + "player_game_stat_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "player_id" INTEGER NOT NULL, + "game_id" INTEGER NOT NULL, + "stat_id" INTEGER NOT NULL, + "session_id" INTEGER NOT NULL, + "value" TEXT NOT NULL, + "date_played" DATETIME NOT NULL, + CONSTRAINT "player_stats_player_id_fkey" FOREIGN KEY ("player_id") REFERENCES "players" ("player_id") ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT "player_stats_game_id_fkey" FOREIGN KEY ("game_id") REFERENCES "games" ("game_id") ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT "player_stats_stat_id_fkey" FOREIGN KEY ("stat_id") REFERENCES "game_stats" ("stat_id") ON DELETE RESTRICT ON UPDATE CASCADE +); +INSERT INTO "new_player_stats" ("date_played", "game_id", "player_game_stat_id", "player_id", "stat_id", "value") SELECT "date_played", "game_id", "player_game_stat_id", "player_id", "stat_id", "value" FROM "player_stats"; +DROP TABLE "player_stats"; +ALTER TABLE "new_player_stats" RENAME TO "player_stats"; +PRAGMA foreign_keys=ON; +PRAGMA defer_foreign_keys=OFF; diff --git a/prisma/migrations/20241028142754_/migration.sql b/prisma/migrations/20241028142754_/migration.sql new file mode 100644 index 0000000..5563bbd --- /dev/null +++ b/prisma/migrations/20241028142754_/migration.sql @@ -0,0 +1,19 @@ +/* + Warnings: + + - You are about to drop the `game_session_players` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropTable +PRAGMA foreign_keys=off; +DROP TABLE "game_session_players"; +PRAGMA foreign_keys=on; + +-- CreateTable +CREATE TABLE "player_sessions" ( + "game_session_player_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "session_id" INTEGER NOT NULL, + "player_id" INTEGER NOT NULL, + CONSTRAINT "player_sessions_session_id_fkey" FOREIGN KEY ("session_id") REFERENCES "sessions" ("session_id") ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT "player_sessions_player_id_fkey" FOREIGN KEY ("player_id") REFERENCES "players" ("player_id") ON DELETE RESTRICT ON UPDATE CASCADE +); diff --git a/prisma/migrations/20241102173000_rdcmodelsv05/migration.sql b/prisma/migrations/20241102173000_rdcmodelsv05/migration.sql new file mode 100644 index 0000000..cfc6990 --- /dev/null +++ b/prisma/migrations/20241102173000_rdcmodelsv05/migration.sql @@ -0,0 +1,77 @@ +/* + Warnings: + + - You are about to drop the column `stat_value` on the `game_stats` table. All the data in the column will be lost. + - The primary key for the `player_sessions` table will be changed. If it partially fails, the table could be left without primary key constraint. + - You are about to drop the column `game_session_player_id` on the `player_sessions` table. All the data in the column will be lost. + - The primary key for the `player_stats` table will be changed. If it partially fails, the table could be left without primary key constraint. + - You are about to drop the column `date_played` on the `player_stats` table. All the data in the column will be lost. + - You are about to drop the column `player_game_stat_id` on the `player_stats` table. All the data in the column will be lost. + - You are about to drop the column `session_id` on the `player_stats` table. All the data in the column will be lost. + - You are about to drop the column `gameId` on the `sessions` table. All the data in the column will be lost. + - Added the required column `player_session_id` to the `player_sessions` table without a default value. This is not possible if the table is not empty. + - Added the required column `set_id` to the `player_sessions` table without a default value. This is not possible if the table is not empty. + - Added the required column `player_session_id` to the `player_stats` table without a default value. This is not possible if the table is not empty. + - Added the required column `player_stat_id` to the `player_stats` table without a default value. This is not possible if the table is not empty. + - Added the required column `game_id` to the `sessions` table without a default value. This is not possible if the table is not empty. + +*/ +-- CreateTable +CREATE TABLE "GameSet" ( + "set_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "session_id" INTEGER NOT NULL, + CONSTRAINT "GameSet_session_id_fkey" FOREIGN KEY ("session_id") REFERENCES "sessions" ("session_id") ON DELETE RESTRICT ON UPDATE CASCADE +); + +-- RedefineTables +PRAGMA defer_foreign_keys=ON; +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_game_stats" ( + "stat_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "game_id" INTEGER NOT NULL, + "stat_name" TEXT NOT NULL, + "date" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "game_stats_game_id_fkey" FOREIGN KEY ("game_id") REFERENCES "games" ("game_id") ON DELETE RESTRICT ON UPDATE CASCADE +); +INSERT INTO "new_game_stats" ("date", "game_id", "stat_id", "stat_name") SELECT "date", "game_id", "stat_id", "stat_name" FROM "game_stats"; +DROP TABLE "game_stats"; +ALTER TABLE "new_game_stats" RENAME TO "game_stats"; +CREATE TABLE "new_player_sessions" ( + "player_session_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "session_id" INTEGER NOT NULL, + "player_id" INTEGER NOT NULL, + "set_id" INTEGER NOT NULL, + CONSTRAINT "player_sessions_player_id_fkey" FOREIGN KEY ("player_id") REFERENCES "players" ("player_id") ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT "player_sessions_set_id_fkey" FOREIGN KEY ("set_id") REFERENCES "GameSet" ("set_id") ON DELETE RESTRICT ON UPDATE CASCADE +); +INSERT INTO "new_player_sessions" ("player_id", "session_id") SELECT "player_id", "session_id" FROM "player_sessions"; +DROP TABLE "player_sessions"; +ALTER TABLE "new_player_sessions" RENAME TO "player_sessions"; +CREATE TABLE "new_player_stats" ( + "player_stat_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "player_id" INTEGER NOT NULL, + "game_id" INTEGER NOT NULL, + "stat_id" INTEGER NOT NULL, + "player_session_id" INTEGER NOT NULL, + "value" TEXT NOT NULL, + "date" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "player_stats_player_id_fkey" FOREIGN KEY ("player_id") REFERENCES "players" ("player_id") ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT "player_stats_game_id_fkey" FOREIGN KEY ("game_id") REFERENCES "games" ("game_id") ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT "player_stats_stat_id_fkey" FOREIGN KEY ("stat_id") REFERENCES "game_stats" ("stat_id") ON DELETE RESTRICT ON UPDATE CASCADE, + CONSTRAINT "player_stats_player_session_id_fkey" FOREIGN KEY ("player_session_id") REFERENCES "player_sessions" ("player_session_id") ON DELETE RESTRICT ON UPDATE CASCADE +); +INSERT INTO "new_player_stats" ("game_id", "player_id", "stat_id", "value") SELECT "game_id", "player_id", "stat_id", "value" FROM "player_stats"; +DROP TABLE "player_stats"; +ALTER TABLE "new_player_stats" RENAME TO "player_stats"; +CREATE TABLE "new_sessions" ( + "session_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "session_name" TEXT NOT NULL, + "session_url" TEXT NOT NULL, + "game_id" INTEGER NOT NULL, + "date" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP +); +INSERT INTO "new_sessions" ("session_id", "session_name", "session_url") SELECT "session_id", "session_name", "session_url" FROM "sessions"; +DROP TABLE "sessions"; +ALTER TABLE "new_sessions" RENAME TO "sessions"; +PRAGMA foreign_keys=ON; +PRAGMA defer_foreign_keys=OFF; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..e5e5c47 --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "sqlite" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..7ca6cac --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,105 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "sqlite" + url = env("DATABASE_URL") +} + +///////////////////////// +// Project RDC Models +// Player Ids +// 1. Mark +// 2. Aff +// 3. Des +// 4. Ben +// 5. Lee +// 6. Dyl +// 7. John +// 8. Ippi +////////////////////// + +// {player_id: 1, player_name: "Mark", player_game_stats: []} +model Player { + playerId Int @id @default(autoincrement()) @map("player_id") + playerName String @map("player_name") + playerSessions PlayerSession[] + playerStats PlayerStat[] + + @@map("players") +} + +// { game_id: 1, game_name: 'Mario Kart', game_stats: [], player_game_stats: [] } +model Game { + gameId Int @id @default(autoincrement()) @map("game_id") + gameName String @map("game_name") + gameStats GameStat[] + playerStats PlayerStat[] + + @@map("games") +} + +// { stat_id: 1, game_id: 1, stat_name: 'mk_first', stat_value: '0', date: 2024-10-23 12:00:00 } +model GameStat { + statId Int @id @default(autoincrement()) @map("stat_id") // TODO: MAKE ENUM + gameId Int @map("game_id") + statName String @map("stat_name") + date DateTime @default(now()) // Date video posted + game Game @relation(fields: [gameId], references: [gameId]) + playerStats PlayerStat[] + + @@map("game_stats") +} + +// { player_game_stat_id: 1, player_id: 1, game_id: 1, stat_id: 1, value: } +model PlayerStat { + playerStatId Int @id @default(autoincrement()) @map("player_stat_id") + playerId Int @map("player_id") + player Player @relation(fields: [playerId], references: [playerId]) + gameId Int @map("game_id") + game Game @relation(fields: [gameId], references: [gameId]) + gameStat GameStat @relation(fields: [statId], references: [statId]) + statId Int @map("stat_id") + playerSessionId Int @map("player_session_id") + playerSession PlayerSession @relation(fields: [playerSessionId], references: [playerSessionId]) + value String + date DateTime @default(now()) // Date video posted + + @@map("player_stats") +} + +model Session { + sessionId Int @id @default(autoincrement()) @map("session_id") + sessionName String @map("session_name") + sessionUrl String @map("session_url") + gameId Int @map("game_id") + sets GameSet[] + date DateTime @default(now()) // Date video posted + + @@map("sessions") +} + +// Join Table between Session & Player +model PlayerSession { + playerSessionId Int @id @default(autoincrement()) @map("player_session_id") + sessionId Int @map("session_id") + playerId Int @map("player_id") + player Player @relation(fields: [playerId], references: [playerId]) + playerStats PlayerStat[] + setId Int @map("set_id") + set GameSet @relation(fields: [setId], references: [setId]) + + @@map("player_sessions") +} + +// Set Table Concept +model GameSet { + setId Int @id @default(autoincrement()) @map("set_id") + sessionId Int @map("session_id") + session Session @relation(fields: [sessionId], references: [sessionId]) + playerSessions PlayerSession[] +} diff --git a/prisma/script.ts b/prisma/script.ts new file mode 100644 index 0000000..3a93518 --- /dev/null +++ b/prisma/script.ts @@ -0,0 +1,38 @@ +import { PrismaClient } from "@prisma/client"; + +const prisma = new PrismaClient(); + +async function main() { + console.log(await getMarioKartGameSession()); +} + +async function getAllRDCMembers() { + const rdcMembers = await prisma.player.findMany(); + console.log("RDC Members: ", rdcMembers); +} + +async function getMarioKartGameSession() { + const gameSessions = await prisma.playerStat.findMany({ + where: { + game: { + gameId: 1, + }, + }, + include: { + player: true, + game: true, + gameStat: true, + }, + }); + return gameSessions; +} + +main() + .then(async () => { + await prisma.$disconnect(); + }) + .catch(async (e) => { + console.error(e); + await prisma.$disconnect(); + process.exit(1); + }); diff --git a/prisma/scripts/testbed.ts b/prisma/scripts/testbed.ts new file mode 100644 index 0000000..1a32745 --- /dev/null +++ b/prisma/scripts/testbed.ts @@ -0,0 +1,138 @@ +import { PrismaClient } from "@prisma/client"; +import { EnrichedSession } from "../types/session"; +import { EnrichedGameSet } from "../types/gameSet"; + +const prisma = new PrismaClient(); + +async function main() { + console.log(await getLatestMarioKartSession()); +} + +/// Fetched Enriched Mario Kart Session +async function getLatestMarioKartSession() { + try { + const latestMKPlayerSessions = await prisma.session.findFirst({ + where: { + gameId: 1, + }, + orderBy: { + sessionId: "desc", + }, + include: { + sets: { + include: { + playerSessions: { + include: { + player: { + select: { + playerName: true, + }, + }, + playerStats: true, + }, + }, + }, + }, + }, + }); + if (latestMKPlayerSessions != null) { + console.log( + "Latest Mario Kart Session: ", + showSetStatsByPlayerByRace([latestMKPlayerSessions]), + ); + } + } catch (error) { + console.error("Error Fetching Latest Mario Kart Session"); + } +} + +/** + * Takes a mario kart session and prints out the stats for each player in each set grouped. + * Format: + * Player: playerName + * Rankings: []number + * @param mkSession + */ +async function showSetStatsByPlayerByRace(mkSession: EnrichedSession[]) { + // Group Stats For A Set By Player + for (const session of mkSession) { + for (const set of session.sets) { + console.log(`--- Set ${set.setId} ---`); + const playerStatsMap: { [playerName: string]: string[] } = {}; + + for (const playerSession of set.playerSessions) { + const playerName = playerSession.player.playerName; + if (!playerStatsMap[playerName]) { + playerStatsMap[playerName] = []; + } + for (const playerStat of playerSession.playerStats) { + playerStatsMap[playerName].push(playerStat.value); + } + } + + for (const playerName in playerStatsMap) { + console.log(`\nPlayer: ${playerName}`); + console.log(`Placements: ${playerStatsMap[playerName].join(", ")}`); + } + console.log(getMK8RankingsFromSet(set)); + } + } +} + +/** +/* Given a MK8 Set, return the rankings for each player and the number of points they received + * @param set + * @returns + */ +async function getMK8RankingsFromSet(set: EnrichedGameSet) { + const pointsMap = [6, 4, 3, 2, 1]; + const playerPoints: { [playerName: string]: number } = { + Mark: 0, + Dylan: 0, + Ben: 0, + Lee: 0, + Des: 0, + }; + + // Leaving these comments logs in for debugging purposes TODO: Remove when done + for (const playerSession of set.playerSessions) { + // console.log(`Looking at PlayerSession ${playerSession.playerSessionId}`); + + const playerName = playerSession.player.playerName; + + for (const playerStat of playerSession.playerStats) { + // console.log(`\nLooking at statId${playerStat.statId}`); + + const placement = parseInt(playerStat.value); + // console.log( + // `${playerName} placed ${placement} and received ${pointsMap[placement - 1]} points`, + // ); + if (placement >= 1 && placement <= 5) { + const pointsWon = pointsMap[placement - 1]; + // console.log(`Points Won: ${pointsWon}`); + playerPoints[playerName] += pointsWon; + // console.log("Player Points: ", playerPoints); + } + } + } + + const rankings = Object.entries(playerPoints) + .sort(([, pointsA], [, pointsB]) => pointsB - pointsA) + .map(([playerName, points], index) => ({ + rank: index + 1, + playerName, + points, + })); + + return rankings; +} + +main() + .then(async () => { + await prisma.$disconnect(); + }) + .catch(async (e) => { + console.error(e); + await prisma.$disconnect(); + process.exit(1); + }); diff --git a/prisma/seed.ts b/prisma/seed.ts new file mode 100644 index 0000000..b400ff2 --- /dev/null +++ b/prisma/seed.ts @@ -0,0 +1,359 @@ +import { GameSet, Player, PrismaClient } from "@prisma/client"; + +const prisma = new PrismaClient(); + +async function main() { + // TODO: Seed player stats in seedPlayerSessions + await seedRDCMembers(); + await seedGames(); + await seedSession(1); + + // Seed 1st set + await seedSet(1, 1); + await seedPlayerSessions(1); + await seedPlayerStats(); // Seed Player Stats for Race 1 + await seedPlayerStats(5, ["2", "3", "1", "4", "5"]); // Seed Player Stats for Race 2 + await seedPlayerStats(10, ["3", "2", "4", "5", "1"]); // Seed Player Stats for Race 3 + await seedPlayerStats(15); // Seed Player Stats for Race 4 + + // Seed 2nd set + await seedSet(2, 1); + await seedPlayerSessions(2); + await seedPlayerStats(20); // Races 5-8 + await seedPlayerStats(25); + await seedPlayerStats(30, ["5", "3", "2", "4", "1"]); + await seedPlayerStats(35, ["4", "1", "3", "5", "2"]); + + // Seed 3rd set + await seedSet(3, 1); + await seedPlayerSessions(3); + await seedPlayerStats(40); // Races 9-12 + await seedPlayerStats(45, ["5", "2", "1", "4", "3"]); + await seedPlayerStats(50, ["4", "3", "1", "5", "2"]); + await seedPlayerStats(55); + + // Seed 4th set + await seedSet(4, 1); + await seedPlayerSessions(4); + await seedPlayerStats(60, ["5", "4", "2", "3", "1"]); // Races 12-15 + await seedPlayerStats(65); + await seedPlayerStats(50, ["5", "1", "2", "4", "3"]); + await seedPlayerStats(70, ["4", "1", "5", "3", "2"]); + await seedPlayerStats(75, ["1", "5", "2", "3", "4"]); + + console.log("--- <> Seeded Mario Kart Session successfully <> ---"); + console.log("Seeds have been sown. o7"); +} + +main() + .then(async () => { + await prisma.$disconnect(); + }) + .catch(async (e) => { + console.error(e); + await prisma.$disconnect(); + process.exit(1); + }); + +// Seed RDC Members +async function seedRDCMembers() { + console.log("--- Seeding RDC Members ---"); + const mark = await prisma.player.upsert({ + where: { playerId: 1 }, + update: {}, + create: { + playerId: 1, + playerName: "Mark", + }, + }); + + const aff = await prisma.player.upsert({ + where: { playerId: 2 }, + update: {}, + create: { + playerId: 2, + playerName: "Dylan", + }, + }); + + const des = await prisma.player.upsert({ + where: { playerId: 3 }, + update: {}, + create: { + playerId: 3, + playerName: "Ben", + }, + }); + + const ben = await prisma.player.upsert({ + where: { playerId: 4 }, + update: {}, + create: { + playerId: 4, + playerName: "Lee", + }, + }); + const lee = await prisma.player.upsert({ + where: { playerId: 5 }, + update: {}, + create: { + playerId: 5, + playerName: "Des", + }, + }); + + const dylan = await prisma.player.upsert({ + where: { playerId: 6 }, + update: {}, + create: { + playerId: 6, + playerName: "John", + }, + }); + + const john = await prisma.player.upsert({ + where: { playerId: 7 }, + update: {}, + create: { + playerId: 7, + playerName: "Aff", + }, + }); + + const ippi = await prisma.player.upsert({ + where: { playerId: 8 }, + update: {}, + create: { + playerId: 8, + playerName: "Ippi", + }, + }); + + console.log("RDC Members Seeded Successfully.\n"); +} + +async function seedGames() { + console.log("--- Seeding Games ---"); + const marioKart = await prisma.game.upsert({ + where: { gameId: 1 }, + update: {}, + create: { + gameName: "Mario Kart", + gameStats: { + create: [ + { + statId: 1, + statName: "MK8_POS", + date: new Date(), + }, + ], + }, + }, + }); + console.log("Mario Kart Game Seeded."); +} + +// Seed game session with RDC Stream Five +async function seedSession(sessionId: number) { + console.log(`\n--- Seeding Game Session ${sessionId} ---`); + const marioKartSession = await prisma.session.upsert({ + where: { sessionId: sessionId }, + update: {}, + create: { + sessionId: sessionId, + gameId: 1, + sessionName: "TEST MK8 SESSION YOU WON'T BELIEVE WHAT HAPPENS NEXT", + sessionUrl: "https://example.com", + }, + }); + console.log("Seeded MK8 Session Successfully.\n"); +} + +/** + * + * @param setId - setId of the set to seed + * @param sessionId - sessionId of parent session of seeded set + */ +async function seedSet(setId: number, sessionId: number = 1) { + const marioKartSet = await prisma.gameSet.upsert({ + where: { setId: setId }, + update: {}, + create: { + setId: setId, + sessionId: sessionId, + }, + }); + + console.log(`Seeded Set ${setId} Successfully.\n`); +} + +async function seedPlayerSessions(setId: number) { + const mk8Players: Player[] = await prisma.player.findMany({ + where: { + playerId: { + in: [1, 2, 3, 4, 5], + }, + }, + }); + + const mk8Session = await prisma.session.findFirst({ + where: { + gameId: 1, + }, + include: { + sets: { + include: { + playerSessions: { + include: { + player: { + select: { + playerName: true, + }, + }, + playerStats: true, + }, + }, + }, + }, + }, + }); + + if (!mk8Session) { + throw new Error("Session not found"); + } + + await createPlayerSessionsBatch( + 4, + mk8Players, + mk8Session.sets[setId - 1], // TODO: Need to find better way to pass in set here + mk8Session.sessionId, + ); +} + +// Instead of creating playerSessions once per race manually, we should have a function that can create the playerSessions for the four races +/** + * Create a batch of player sessions for a set number of games + * @param numgames - number of games in set + * @param players - array of players who participated in the set + * @param set - GameSet type that will contain batched sessions + * @param sessionId - Id of session that the set belongs too + */ +async function createPlayerSessionsBatch( + numGames: number, + players: Player[], + set: GameSet, + sessionId: number, +) { + console.log("\n--- Creating Batch of Player Sessions for Set ---", set.setId); + for (let game = 0; game < numGames; game++) { + const setModifier = (set.setId - 1) * 20; // Every set assume there are 5 players * 4 races = 20 player sessions + const idOffset = game * 5 + setModifier; + + // Creating Player Sessions per Race + console.log(`\nCreating Sessions for Race ${game}`); + for (let i = 0; i < players.length; i++) { + const player = players[i]; + + await prisma.playerSession.upsert({ + where: { playerSessionId: player.playerId + idOffset }, + update: {}, + create: { + playerSessionId: player.playerId + idOffset, + sessionId: sessionId, + setId: set.setId, + playerId: player.playerId, + }, + }); + console.log( + `Created Player Session ${player.playerId + idOffset} for Player: ${player.playerName}`, + ); + } + } +} + +/** + * Upsert player stat assuming playerStatID and playerSessionId are the same + * @param idOffset - used to offset playerStatId and playerSessionId + * @param positions - optional parameter to dictate positions (1-5) of players in the order of (Mark, Dyl, Ben, Lee, Des) + * @param setId - optional parameter to identify set number player stats should belong too + */ +async function seedPlayerStats( + idOffset: number = 0, + positions: string[] = ["1", "2", "3", "4", "5"], + setId: number = 1, +) { + idOffset = idOffset * setId; + + // Seed PlayerStat for players (assume its the stream five) + const markRace = await prisma.playerStat.upsert({ + where: { playerStatId: 1 + idOffset }, + update: {}, + create: { + playerStatId: 1 + idOffset, + playerId: 1, + statId: 1, // MK_POS + playerSessionId: 1 + idOffset, + gameId: 1, + value: positions[0], + date: new Date(), + }, + }); + + const dylRace = await prisma.playerStat.upsert({ + where: { playerStatId: 2 + idOffset }, + update: {}, + create: { + playerStatId: 2 + idOffset, + playerId: 6, + statId: 1, // MK_POS + playerSessionId: 2 + idOffset, + gameId: 1, + value: positions[1], + date: new Date(), + }, + }); + + const benRace = await prisma.playerStat.upsert({ + where: { playerStatId: 3 + idOffset }, + update: {}, + create: { + playerStatId: 3 + idOffset, + playerId: 4, + statId: 1, // MK_POS + playerSessionId: 3 + idOffset, + gameId: 1, + value: positions[2], + date: new Date(), + }, + }); + + const leeRace = await prisma.playerStat.upsert({ + where: { playerStatId: 4 + idOffset }, + update: {}, + create: { + playerStatId: 4 + idOffset, + playerId: 5, + statId: 1, // MK_POS + playerSessionId: 4 + idOffset, + gameId: 1, + value: positions[3], + date: new Date(), + }, + }); + + const desRace = await prisma.playerStat.upsert({ + where: { playerStatId: 5 + idOffset }, + update: {}, + create: { + playerStatId: 5 + idOffset, + playerId: 3, + statId: 1, // MK_POS + playerSessionId: 5 + idOffset, + gameId: 1, + value: positions[4], + date: new Date(), + }, + }); + + console.log(`Finished creating player stats for set ${setId}`); +} diff --git a/prisma/types/gameSet.ts b/prisma/types/gameSet.ts new file mode 100644 index 0000000..2290566 --- /dev/null +++ b/prisma/types/gameSet.ts @@ -0,0 +1,18 @@ +import { Prisma } from "@prisma/client"; + +const enrichedGameSet = Prisma.validator()({ + include: { + playerSessions: { + include: { + player: { + select: { + playerName: true, + }, + }, + playerStats: true, + }, + }, + }, +}); + +export type EnrichedGameSet = Prisma.GameSetGetPayload; diff --git a/prisma/types/playerSession.ts b/prisma/types/playerSession.ts new file mode 100644 index 0000000..8d7f1ff --- /dev/null +++ b/prisma/types/playerSession.ts @@ -0,0 +1,24 @@ +import { Prisma } from "@prisma/client"; + +// Things we need for each Mario Kart Session +// RDC names, stat names and values +const playerSessionWithPlayerStats = + Prisma.validator()({ + include: { + set: true, + player: { + select: { + playerName: true, + }, + }, + playerStats: { + include: { + gameStat: true, + }, + }, + }, + }); + +export type PlayerSessionWithStats = Prisma.PlayerSessionGetPayload< + typeof playerSessionWithPlayerStats +>; diff --git a/prisma/types/playerStat.ts b/prisma/types/playerStat.ts new file mode 100644 index 0000000..6adbea6 --- /dev/null +++ b/prisma/types/playerStat.ts @@ -0,0 +1,17 @@ +import { Prisma } from "@prisma/client"; + +const playerStatWithStatName = Prisma.validator()( + { + include: { + gameStat: { + select: { + statName: true, + }, + }, + }, + }, +); + +export type PlayerStatWithStatName = Prisma.PlayerStatGetPayload< + typeof playerStatWithStatName +>; diff --git a/prisma/types/session.ts b/prisma/types/session.ts new file mode 100644 index 0000000..e1276cf --- /dev/null +++ b/prisma/types/session.ts @@ -0,0 +1,22 @@ +import { Prisma } from "@prisma/client"; + +const enrichedSession = Prisma.validator()({ + include: { + sets: { + include: { + playerSessions: { + include: { + player: { + select: { + playerName: true, + }, + }, + playerStats: true, + }, + }, + }, + }, + }, +}); + +export type EnrichedSession = Prisma.SessionGetPayload; diff --git a/src/api/marioKartAPI.ts b/src/api/marioKartAPI.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/app/(routes)/submission/page.tsx b/src/app/(routes)/submission/page.tsx index ec26ad7..98a2653 100644 --- a/src/app/(routes)/submission/page.tsx +++ b/src/app/(routes)/submission/page.tsx @@ -1,12 +1,15 @@ import { H1 } from "@/components/headings"; import { SubmissionForm } from "./_components/form"; +import { FeatureFlag } from "@/lib/featureflag"; export default function Page() { return (

Want to help?

- + + +
); diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 3770e44..3e77b52 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -6,6 +6,7 @@ import { ThemeProvider } from "@/components/theme-provider"; import { Navbar } from "@/components/navbar"; import { Footer } from "@/components/footer"; import { Toaster } from "@/components/ui/sonner"; +import { CSPostHogProvider } from "@/lib/providers"; const inter = Inter({ subsets: ["latin"] }); @@ -28,10 +29,12 @@ export default function RootLayout({ enableSystem disableTransitionOnChange > - -
{children}
- -