diff --git a/package-lock.json b/package-lock.json index cecc70bc..0af40621 100644 --- a/package-lock.json +++ b/package-lock.json @@ -110,7 +110,7 @@ "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==", - "dev": true, + "devOptional": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -122,7 +122,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, + "devOptional": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -625,13 +625,13 @@ "version": "5.12.0", "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.12.0.tgz", "integrity": "sha512-wK3fQLxPLMqf5riT5ZIhl8NffPSzFUwtzFX5CH7z/oI9Swmo9UhQlUgZABIVgdXSJ5OAlmRcDZtDKaMApIl8sg==", - "dev": true + "devOptional": true }, "node_modules/@prisma/engines": { "version": "5.12.0", "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.12.0.tgz", "integrity": "sha512-rFNRul9JGu0d3tf8etBgmDQ4NVoDwgGrRguvQOc8i+c6g7xPjRuu4aKzMMvHWUuccvRx5+fs1KMBxQ0x2THt+Q==", - "dev": true, + "devOptional": true, "hasInstallScript": true, "dependencies": { "@prisma/debug": "5.12.0", @@ -644,13 +644,13 @@ "version": "5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab", "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab.tgz", "integrity": "sha512-6yvO8s80Tym61aB4QNtYZfWVmE3pwqe807jEtzm8C5VDe7nw8O1FGX3TXUaXmWV0fQTIAfRbeL2Gwrndabp/0g==", - "dev": true + "devOptional": true }, "node_modules/@prisma/fetch-engine": { "version": "5.12.0", "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.12.0.tgz", "integrity": "sha512-qkHQbZ1hspvOwcImvqY4yj7+FUlw0+uP+6tu3g24V4ULHOXLLkvr5ZZc6vy26OF0hkbD3kcDJCeutFis3poKgg==", - "dev": true, + "devOptional": true, "dependencies": { "@prisma/debug": "5.12.0", "@prisma/engines-version": "5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab", @@ -661,13 +661,13 @@ "version": "5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab", "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab.tgz", "integrity": "sha512-6yvO8s80Tym61aB4QNtYZfWVmE3pwqe807jEtzm8C5VDe7nw8O1FGX3TXUaXmWV0fQTIAfRbeL2Gwrndabp/0g==", - "dev": true + "devOptional": true }, "node_modules/@prisma/get-platform": { "version": "5.12.0", "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.12.0.tgz", "integrity": "sha512-81Ptv9YJnwTArEBPQ2Lvu58sZPxy4OixKxVVgysFan6A3bFP7q8gIg15WTjsRuH4WXh6B667EM9sqoMTNu0fLQ==", - "dev": true, + "devOptional": true, "dependencies": { "@prisma/debug": "5.12.0" } @@ -1791,25 +1791,25 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true + "devOptional": true }, "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==", - "dev": true + "devOptional": true }, "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==", - "dev": true + "devOptional": true }, "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==", - "dev": true + "devOptional": true }, "node_modules/@types/body-parser": { "version": "1.19.2", @@ -1973,7 +1973,7 @@ "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true + "devOptional": true }, "node_modules/@types/qs": { "version": "6.9.7", @@ -1997,7 +1997,7 @@ "version": "18.2.16", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.16.tgz", "integrity": "sha512-LLFWr12ZhBJ4YVw7neWLe6Pk7Ey5R9OCydfuMsz1L8bZxzaawJj2p06Q8/EFEHDeTBQNFLF62X+CG7B2zIyu0Q==", - "dev": true, + "devOptional": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -2008,7 +2008,7 @@ "version": "18.2.6", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.6.tgz", "integrity": "sha512-2et4PDvg6PVCyS7fuTc4gPoksV58bW0RwSxWKcPRcHZf0PRUGq03TKcD/rUHe3azfV6/5/biUBJw+HhCQjaP0A==", - "dev": true, + "devOptional": true, "dependencies": { "@types/react": "*" } @@ -2017,7 +2017,7 @@ "version": "0.16.3", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", - "dev": true + "devOptional": true }, "node_modules/@types/semver": { "version": "7.5.0", @@ -2289,7 +2289,7 @@ "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", - "dev": true, + "devOptional": true, "bin": { "acorn": "bin/acorn" }, @@ -2310,7 +2310,7 @@ "version": "8.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.4.0" } @@ -3628,7 +3628,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "devOptional": true }, "node_modules/cross-env": { "version": "7.0.3", @@ -6945,7 +6945,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "devOptional": true }, "node_modules/map-stream": { "version": "0.1.0", @@ -8094,7 +8094,7 @@ "version": "5.12.0", "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.12.0.tgz", "integrity": "sha512-zxw4WSIvpsyNbpv8r7Fxgm7nwTFVmD6wbN6VuH13lClOceSANDOMl4jO3oxE6VzhjxmnEJqOGZjON2T2UpmLag==", - "dev": true, + "devOptional": true, "hasInstallScript": true, "dependencies": { "@prisma/engines": "5.12.0" @@ -9858,7 +9858,7 @@ "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, + "devOptional": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -9901,13 +9901,13 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "devOptional": true }, "node_modules/ts-node/node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.3.1" } @@ -10077,7 +10077,6 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", - "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -10260,7 +10259,7 @@ "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==", - "dev": true + "devOptional": true }, "node_modules/vary": { "version": "1.1.2", @@ -10519,7 +10518,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" } diff --git a/packages/app/prisma/schema.prisma b/packages/app/prisma/schema.prisma index 711bf35c..143b37fe 100644 --- a/packages/app/prisma/schema.prisma +++ b/packages/app/prisma/schema.prisma @@ -1,195 +1,178 @@ generator client { - provider = "prisma-client-js" - binaryTargets = ["native", "rhel-openssl-1.0.x"] + provider = "prisma-client-js" + binaryTargets = ["native", "rhel-openssl-1.0.x"] } datasource db { - provider = "postgresql" - url = env("DATABASE_URL") -} - -enum UserRole { - ADMIN - USER -} - -enum AchievementType { - FIRST_RACE - FIRST_SNIPPET - FIFTH_RACE + provider = "postgresql" + url = env("DATABASE_URL") } model User { - id String @id @default(cuid()) - createdAt DateTime @default(now()) @map("created_at") - name String? - bio String? - email String? @unique - emailVerified DateTime? @map("email_verified") - image String? - accounts Account[] - sessions Session[] - results Result[] - achievements Achievement[] - // followers String[] - // following String[] - - topLanguages String[] - languagesMap Json? - - averageAccuracy Decimal @default(0) @db.Decimal(5, 2) - averageCpm Decimal @default(0) @db.Decimal(6, 2) - - role UserRole @default(USER) - - snippets Snippet[] - snippetVotes SnippetVote[] - RaceParticipant RaceParticipant[] - notifications Notification[] - - @@map("users") + id String @id @default(cuid()) + createdAt DateTime @default(now()) @map("created_at") + name String? + email String? @unique + emailVerified DateTime? @map("email_verified") + image String? + averageAccuracy Decimal @default(0) @db.Decimal(5, 2) + averageCpm Decimal @default(0) @db.Decimal(6, 2) + role UserRole @default(USER) + bio String? + languagesMap Json? + topLanguages String[] + accounts Account[] + achievements Achievement[] + notifications Notification[] + RaceParticipant RaceParticipant[] + results Result[] + sessions Session[] + snippetVotes SnippetVote[] + snippets Snippet[] + + @@map("users") } -// Necessary for Next auth model Account { - id String @id @default(cuid()) - userId String @map("user_id") - type String - provider String - providerAccountId String @map("provider_account_id") - refresh_token String? @db.Text - access_token String? @db.Text - expires_at Int? - token_type String? - scope String? - id_token String? @db.Text - session_state String? - user User @relation(fields: [userId], references: [id], onDelete: Cascade) - - @@unique([provider, providerAccountId]) - @@map("accounts") + id String @id @default(cuid()) + userId String @map("user_id") + type String + provider String + providerAccountId String @map("provider_account_id") + refresh_token String? + access_token String? + expires_at Int? + token_type String? + scope String? + id_token String? + session_state String? + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@unique([provider, providerAccountId]) + @@map("accounts") } model Session { - id String @id @default(cuid()) - sessionToken String @unique @map("session_token") - userId String @map("user_id") - expires DateTime - user User @relation(fields: [userId], references: [id], onDelete: Cascade) + id String @id @default(cuid()) + sessionToken String @unique @map("session_token") + userId String @map("user_id") + expires DateTime + user User @relation(fields: [userId], references: [id], onDelete: Cascade) - @@map("sessions") + @@map("sessions") } model VerificationToken { - identifier String - token String @unique - expires DateTime + identifier String + token String @unique + expires DateTime - @@unique([identifier, token]) - @@map("verification_tokens") + @@unique([identifier, token]) + @@map("verification_tokens") } model Result { - id String @id @default(cuid()) - snippet Snippet @relation(fields: [snippetId], references: [id], onDelete: Cascade) - userId String @map("user_id") - createdAt DateTime @default(now()) @map("created_at") - accuracy Decimal @db.Decimal(5, 2) - cpm Int - takenTime String @map("taken_time") - errorCount Int? @map("error_count") - user User @relation(fields: [userId], references: [id], onDelete: Cascade) - snippetId String - RaceParticipant RaceParticipant[] + id String @id @default(cuid()) + userId String @map("user_id") + createdAt DateTime @default(now()) @map("created_at") + accuracy Decimal @db.Decimal(5, 2) + cpm Int + takenTime String @map("taken_time") + errorCount Int? @map("error_count") + snippetId String + RaceParticipant RaceParticipant[] + snippet Snippet @relation(fields: [snippetId], references: [id], onDelete: Cascade) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) - @@map("results") + @@map("results") } model Achievement { - userId String @map("user_id") - achievementType AchievementType @map("achievement_type") - unlockedAt DateTime @default(now()) @map("unlocked_at") - user User @relation(fields: [userId], references: [id], onDelete: Cascade) + userId String @map("user_id") + achievementType AchievementType @map("achievement_type") + unlockedAt DateTime @default(now()) @map("unlocked_at") + user User @relation(fields: [userId], references: [id], onDelete: Cascade) - @@id([userId, achievementType]) - @@map("achievements") + @@id([userId, achievementType]) + @@map("achievements") } model Snippet { - id String @id @default(cuid()) - name String? - - code String - language String - User User? @relation(fields: [userId], references: [id], onDelete: Cascade) - userId String? @map("user_id") - onReview Boolean @default(false) @map("on_review") - rating Int @default(0) - Result Result[] + id String @id @default(cuid()) + code String + language String + userId String? @map("user_id") + onReview Boolean @default(false) @map("on_review") + rating Int @default(0) + name String? + Race Race[] + Result Result[] + votes SnippetVote[] + User User? @relation(fields: [userId], references: [id], onDelete: Cascade) - votes SnippetVote[] - Race Race[] - - @@map("snippets") + @@map("snippets") } model Race { - id String @id @default(cuid()) - - snippetId String @map("snippet_id") - snippet Snippet @relation(fields: [snippetId], references: [id], onDelete: Cascade) - participants RaceParticipant[] - - startedAt DateTime? @map("started_at") - endedAt DateTime? @map("ended_at") - createdAt DateTime @default(now()) @map("created_at") + id String @id @default(cuid()) + snippetId String @map("snippet_id") + startedAt DateTime? @map("started_at") + endedAt DateTime? @map("ended_at") + createdAt DateTime @default(now()) @map("created_at") + snippet Snippet @relation(fields: [snippetId], references: [id], onDelete: Cascade) + participants RaceParticipant[] - @@map("race") + @@map("race") } model RaceParticipant { - id String @id @default(cuid()) + id String @id @default(cuid()) + raceId String + userId String? @map("user_id") + resultId String? @map("result_id") + Race Race @relation(fields: [raceId], references: [id], onDelete: Cascade) + result Result? @relation(fields: [resultId], references: [id], onDelete: Cascade) + user User? @relation(fields: [userId], references: [id], onDelete: Cascade) - Race Race @relation(fields: [raceId], references: [id], onDelete: Cascade) - raceId String - - // a race participant could be a guest user - userId String? @map("user_id") - user User? @relation(fields: [userId], references: [id], onDelete: Cascade) - - // a user could exit the race without finishing, or is a guest user - resultId String? @map("result_id") - result Result? @relation(fields: [resultId], references: [id], onDelete: Cascade) - - @@map("race_participants") -} - -enum VoteType { - UP - DOWN + @@map("race_participants") } model SnippetVote { - snippetId String - userId String - User User @relation(fields: [userId], references: [id], onDelete: Cascade) - Snippet Snippet @relation(fields: [snippetId], references: [id], onDelete: Cascade) - type VoteType + snippetId String + userId String + type VoteType + Snippet Snippet @relation(fields: [snippetId], references: [id], onDelete: Cascade) + User User @relation(fields: [userId], references: [id], onDelete: Cascade) - @@id([userId, snippetId]) - @@map("snippet_votes") + @@id([userId, snippetId]) + @@map("snippet_votes") } model Notification { - id String @id @default(cuid()) - title String - description String - ctaUrl String? @map("cta_url") // URL to redirect when user click on notification - read Boolean @default(false) - userId String @map("user_id") - createdAt DateTime @default(now()) @map("created_at") + id String @id @default(cuid()) + title String + description String + ctaUrl String? @map("cta_url") + read Boolean @default(false) + userId String @map("user_id") + createdAt DateTime @default(now()) @map("created_at") + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@map("notification") +} - user User @relation(fields: [userId], references: [id], onDelete: Cascade) +enum UserRole { + ADMIN + USER +} - @@map("notification") +enum AchievementType { + FIRST_RACE + FIRST_SNIPPET + FIFTH_RACE +} + +enum VoteType { + UP + DOWN } diff --git a/packages/app/src/app/dashboard/_components/recentRaces.tsx b/packages/app/src/app/dashboard/_components/recentRaces.tsx index 58e189c4..ebe5acbe 100644 --- a/packages/app/src/app/dashboard/_components/recentRaces.tsx +++ b/packages/app/src/app/dashboard/_components/recentRaces.tsx @@ -1,7 +1,7 @@ "use client"; import * as React from "react"; -import type { Result, Snippet } from "@prisma/client"; +import type { Result } from "@prisma/client"; import { type ColumnDef } from "unstyled-table"; import Link from "next/link"; @@ -43,21 +43,21 @@ export function RecentRacesTable({ }, }, { - accessorKey: "name", + accessorKey: "snippet.name", header: "Name", cell: ({ cell }) => { - const snippet = cell.getValue() as Snippet; + const name = cell.getValue() as string; - return {snippet.name ?? "-"}; + return {name ?? "-"}; }, }, { - accessorKey: "language", + accessorKey: "snippet.language", header: "Language", cell: ({ cell }) => { - const snippet = cell.getValue() as Snippet; + const snippet = cell.getValue() as string; const language = snippetLanguages.find((language) => { - if (language.value === snippet.language) { + if (language.value === snippet) { return language.label; } });