From 16e4b63ffdc214b56bee7b662e21aef95f548be1 Mon Sep 17 00:00:00 2001 From: Julien Froidefond Date: Tue, 16 Dec 2025 16:43:53 +0100 Subject: [PATCH] Add feedback management features: Implement functions to add bonus points and mark feedback as read in the FeedbackManagement component. Update EventFeedback model to include isRead property, enhancing user interaction and feedback tracking. --- actions/admin/feedback.ts | 127 ++++++++++++++ components/admin/FeedbackManagement.tsx | 162 ++++++++++++++++-- prisma/generated/prisma/commonInputTypes.ts | 26 +++ prisma/generated/prisma/internal/class.ts | 4 +- .../prisma/internal/prismaNamespace.ts | 8 + .../prisma/internal/prismaNamespaceBrowser.ts | 1 + .../generated/prisma/models/EventFeedback.ts | 47 ++++- .../migration.sql | 24 +++ prisma/schema.prisma | 2 + services/events/event-feedback.service.ts | 2 + 10 files changed, 387 insertions(+), 16 deletions(-) create mode 100644 actions/admin/feedback.ts create mode 100644 prisma/migrations/20251216154133_add_feedback_is_read/migration.sql diff --git a/actions/admin/feedback.ts b/actions/admin/feedback.ts new file mode 100644 index 0000000..1cf796f --- /dev/null +++ b/actions/admin/feedback.ts @@ -0,0 +1,127 @@ +"use server"; + +import { revalidatePath } from "next/cache"; +import { auth } from "@/lib/auth"; +import { prisma } from "@/services/database"; +import { Role } from "@/prisma/generated/prisma/client"; +import { NotFoundError } from "@/services/errors"; + +function checkAdminAccess() { + return async () => { + const session = await auth(); + if (!session?.user || session.user.role !== Role.ADMIN) { + throw new Error("Accès refusé"); + } + return session; + }; +} + +export async function addFeedbackBonusPoints( + userId: string, + points: number +) { + try { + await checkAdminAccess()(); + + // Vérifier que l'utilisateur existe + const user = await prisma.user.findUnique({ + where: { id: userId }, + select: { id: true, score: true }, + }); + + if (!user) { + throw new NotFoundError("Utilisateur"); + } + + // Ajouter les points + const updatedUser = await prisma.user.update({ + where: { id: userId }, + data: { + score: { + increment: points, + }, + }, + select: { + id: true, + username: true, + score: true, + }, + }); + + revalidatePath("/admin"); + revalidatePath("/leaderboard"); + + return { + success: true, + message: `${points} points ajoutés avec succès`, + data: updatedUser, + }; + } catch (error) { + console.error("Error adding bonus points:", error); + + if (error instanceof NotFoundError) { + return { success: false, error: error.message }; + } + if (error instanceof Error && error.message === "Accès refusé") { + return { success: false, error: "Accès refusé" }; + } + + return { + success: false, + error: "Erreur lors de l'ajout des points", + }; + } +} + +export async function markFeedbackAsRead(feedbackId: string, isRead: boolean) { + try { + await checkAdminAccess()(); + + // Vérifier que le feedback existe + const feedback = await prisma.eventFeedback.findUnique({ + where: { id: feedbackId }, + select: { id: true }, + }); + + if (!feedback) { + throw new NotFoundError("Feedback"); + } + + // Mettre à jour le statut + const updatedFeedback = await prisma.eventFeedback.update({ + where: { id: feedbackId }, + data: { + isRead, + }, + select: { + id: true, + isRead: true, + }, + }); + + revalidatePath("/admin"); + + return { + success: true, + message: isRead + ? "Feedback marqué comme lu" + : "Feedback marqué comme non lu", + data: updatedFeedback, + }; + } catch (error) { + console.error("Error marking feedback as read:", error); + + if (error instanceof NotFoundError) { + return { success: false, error: error.message }; + } + if (error instanceof Error && error.message === "Accès refusé") { + return { success: false, error: "Accès refusé" }; + } + + return { + success: false, + error: "Erreur lors de la mise à jour du feedback", + }; + } +} + diff --git a/components/admin/FeedbackManagement.tsx b/components/admin/FeedbackManagement.tsx index 0746a6e..1c3728c 100644 --- a/components/admin/FeedbackManagement.tsx +++ b/components/admin/FeedbackManagement.tsx @@ -1,11 +1,18 @@ "use client"; import { useState, useEffect } from "react"; +import { + addFeedbackBonusPoints, + markFeedbackAsRead, +} from "@/actions/admin/feedback"; +import { Button } from "@/components/ui"; +import Avatar from "@/components/ui/Avatar"; interface Feedback { id: string; rating: number; comment: string | null; + isRead: boolean; createdAt: string; event: { id: string; @@ -17,6 +24,8 @@ interface Feedback { id: string; username: string; email: string; + avatar: string | null; + score: number; }; } @@ -35,6 +44,10 @@ export default function FeedbackManagement() { const [loading, setLoading] = useState(true); const [error, setError] = useState(""); const [selectedEvent, setSelectedEvent] = useState(null); + const [addingPoints, setAddingPoints] = useState>( + {} + ); + const [markingRead, setMarkingRead] = useState>({}); useEffect(() => { fetchFeedbacks(); @@ -92,9 +105,59 @@ export default function FeedbackManagement() { ); }; - const filteredFeedbacks = selectedEvent + const handleAddPoints = async (userId: string, points: number) => { + const key = `${userId}-${points}`; + setAddingPoints((prev) => ({ ...prev, [key]: true })); + setError(""); + + try { + const result = await addFeedbackBonusPoints(userId, points); + if (result.success) { + // Rafraîchir les données pour voir les nouveaux scores + await fetchFeedbacks(); + // Rafraîchir le score dans le header si l'utilisateur est connecté + window.dispatchEvent(new Event("refreshUserScore")); + } else { + setError(result.error || "Erreur lors de l'ajout des points"); + } + } catch { + setError("Erreur lors de l'ajout des points"); + } finally { + setAddingPoints((prev) => ({ ...prev, [key]: false })); + } + }; + + const handleMarkAsRead = async (feedbackId: string, isRead: boolean) => { + setMarkingRead((prev) => ({ ...prev, [feedbackId]: true })); + setError(""); + + try { + const result = await markFeedbackAsRead(feedbackId, isRead); + if (result.success) { + // Rafraîchir les données pour voir le nouveau statut + await fetchFeedbacks(); + } else { + setError(result.error || "Erreur lors de la mise à jour"); + } + } catch { + setError("Erreur lors de la mise à jour"); + } finally { + setMarkingRead((prev) => ({ ...prev, [feedbackId]: false })); + } + }; + + const filteredFeedbacks = (selectedEvent ? feedbacks.filter((f) => f.event.id === selectedEvent) - : feedbacks; + : feedbacks + ).sort((a, b) => { + // Trier : non lus en premier, puis par date décroissante + if (a.isRead !== b.isRead) { + return a.isRead ? 1 : -1; + } + return ( + new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() + ); + }); if (loading) { return ( @@ -184,20 +247,45 @@ export default function FeedbackManagement() { {filteredFeedbacks.map((feedback) => (
-
-

- {feedback.user.username} -

- - {feedback.user.email} - + {/* En-tête utilisateur avec avatar */} +
+ +
+
+

+ {feedback.user.username} +

+ + {feedback.user.score.toLocaleString("fr-FR")} pts + +
+ + {feedback.user.email} + +
-
- {feedback.event.name} +
+
+ {feedback.event.name} +
+ {!feedback.isRead && ( + + Non lu + + )}
{new Date(feedback.createdAt).toLocaleDateString( @@ -212,8 +300,23 @@ export default function FeedbackManagement() { )}
-
+
{renderStars(feedback.rating)} +
{feedback.comment && ( @@ -223,6 +326,39 @@ export default function FeedbackManagement() {

)} + {/* Boutons pour ajouter des points bonus */} +
+ + Points bonus: + + + + +
))}
diff --git a/prisma/generated/prisma/commonInputTypes.ts b/prisma/generated/prisma/commonInputTypes.ts index 98b0898..d4b3755 100644 --- a/prisma/generated/prisma/commonInputTypes.ts +++ b/prisma/generated/prisma/commonInputTypes.ts @@ -211,6 +211,19 @@ export type IntNullableWithAggregatesFilter<$PrismaModel = never> = { _max?: Prisma.NestedIntNullableFilter<$PrismaModel> } +export type BoolFilter<$PrismaModel = never> = { + equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> + not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean +} + +export type BoolWithAggregatesFilter<$PrismaModel = never> = { + equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> + not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedBoolFilter<$PrismaModel> + _max?: Prisma.NestedBoolFilter<$PrismaModel> +} + export type EnumChallengeStatusFilter<$PrismaModel = never> = { equals?: $Enums.ChallengeStatus | Prisma.EnumChallengeStatusFieldRefInput<$PrismaModel> in?: $Enums.ChallengeStatus[] @@ -467,6 +480,19 @@ export type NestedFloatNullableFilter<$PrismaModel = never> = { not?: Prisma.NestedFloatNullableFilter<$PrismaModel> | number | null } +export type NestedBoolFilter<$PrismaModel = never> = { + equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> + not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean +} + +export type NestedBoolWithAggregatesFilter<$PrismaModel = never> = { + equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> + not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedBoolFilter<$PrismaModel> + _max?: Prisma.NestedBoolFilter<$PrismaModel> +} + export type NestedEnumChallengeStatusFilter<$PrismaModel = never> = { equals?: $Enums.ChallengeStatus | Prisma.EnumChallengeStatusFieldRefInput<$PrismaModel> in?: $Enums.ChallengeStatus[] diff --git a/prisma/generated/prisma/internal/class.ts b/prisma/generated/prisma/internal/class.ts index c2455be..32e8ae6 100644 --- a/prisma/generated/prisma/internal/class.ts +++ b/prisma/generated/prisma/internal/class.ts @@ -20,7 +20,7 @@ const config: runtime.GetPrismaClientConfig = { "clientVersion": "7.1.0", "engineVersion": "ab635e6b9d606fa5c8fb8b1a7f909c3c3c1c98ba", "activeProvider": "sqlite", - "inlineSchema": "generator client {\n provider = \"prisma-client\"\n output = \"./generated/prisma\"\n}\n\ndatasource db {\n provider = \"sqlite\"\n}\n\nmodel User {\n id String @id @default(cuid())\n email String @unique\n password String\n username String @unique\n role Role @default(USER)\n score Int @default(0)\n level Int @default(1)\n hp Int @default(1000)\n maxHp Int @default(1000)\n xp Int @default(0)\n maxXp Int @default(5000)\n avatar String?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n bio String?\n characterClass CharacterClass?\n eventFeedbacks EventFeedback[]\n eventRegistrations EventRegistration[]\n preferences UserPreferences?\n challengesAsChallenger Challenge[] @relation(\"Challenger\")\n challengesAsChallenged Challenge[] @relation(\"Challenged\")\n challengesAsAdmin Challenge[] @relation(\"AdminValidator\")\n challengesAsWinner Challenge[] @relation(\"ChallengeWinner\")\n\n @@index([score])\n @@index([email])\n}\n\nmodel UserPreferences {\n id String @id @default(cuid())\n userId String @unique\n homeBackground String?\n eventsBackground String?\n leaderboardBackground String?\n theme String? @default(\"default\")\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n}\n\nmodel Event {\n id String @id @default(cuid())\n date DateTime\n name String\n description String\n type EventType\n room String?\n time String?\n maxPlaces Int?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n feedbacks EventFeedback[]\n registrations EventRegistration[]\n\n @@index([date])\n}\n\nmodel EventRegistration {\n id String @id @default(cuid())\n userId String\n eventId String\n createdAt DateTime @default(now())\n event Event @relation(fields: [eventId], references: [id], onDelete: Cascade)\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([userId, eventId])\n @@index([userId])\n @@index([eventId])\n}\n\nmodel EventFeedback {\n id String @id @default(cuid())\n userId String\n eventId String\n rating Int\n comment String?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n event Event @relation(fields: [eventId], references: [id], onDelete: Cascade)\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([userId, eventId])\n @@index([userId])\n @@index([eventId])\n}\n\nmodel SitePreferences {\n id String @id @default(\"global\")\n homeBackground String?\n eventsBackground String?\n leaderboardBackground String?\n challengesBackground String?\n eventRegistrationPoints Int @default(100)\n eventFeedbackPoints Int @default(50)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nenum Role {\n USER\n ADMIN\n}\n\nenum EventType {\n ATELIER\n KATA\n PRESENTATION\n LEARNING_HOUR\n}\n\nenum CharacterClass {\n WARRIOR\n MAGE\n ROGUE\n RANGER\n PALADIN\n ENGINEER\n MERCHANT\n SCHOLAR\n BERSERKER\n NECROMANCER\n}\n\nenum ChallengeStatus {\n PENDING\n ACCEPTED\n COMPLETED\n REJECTED\n CANCELLED\n}\n\nmodel Challenge {\n id String @id @default(cuid())\n challengerId String // Joueur qui lance le défi\n challengedId String // Joueur qui reçoit le défi\n challenger User @relation(\"Challenger\", fields: [challengerId], references: [id], onDelete: Cascade)\n challenged User @relation(\"Challenged\", fields: [challengedId], references: [id], onDelete: Cascade)\n title String // Titre du défi\n description String // Description détaillée du défi\n pointsReward Int @default(100) // Points à gagner pour le gagnant\n status ChallengeStatus @default(PENDING)\n adminId String? // Admin qui valide le défi\n admin User? @relation(\"AdminValidator\", fields: [adminId], references: [id], onDelete: SetNull)\n adminComment String? // Commentaire de l'admin lors de la validation/rejet\n winnerId String? // ID du gagnant (challengerId ou challengedId)\n winner User? @relation(\"ChallengeWinner\", fields: [winnerId], references: [id], onDelete: SetNull)\n createdAt DateTime @default(now())\n acceptedAt DateTime? // Date d'acceptation du défi\n completedAt DateTime? // Date de validation par l'admin\n updatedAt DateTime @updatedAt\n\n @@index([challengerId])\n @@index([challengedId])\n @@index([status])\n @@index([adminId])\n}\n", + "inlineSchema": "generator client {\n provider = \"prisma-client\"\n output = \"./generated/prisma\"\n}\n\ndatasource db {\n provider = \"sqlite\"\n}\n\nmodel User {\n id String @id @default(cuid())\n email String @unique\n password String\n username String @unique\n role Role @default(USER)\n score Int @default(0)\n level Int @default(1)\n hp Int @default(1000)\n maxHp Int @default(1000)\n xp Int @default(0)\n maxXp Int @default(5000)\n avatar String?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n bio String?\n characterClass CharacterClass?\n eventFeedbacks EventFeedback[]\n eventRegistrations EventRegistration[]\n preferences UserPreferences?\n challengesAsChallenger Challenge[] @relation(\"Challenger\")\n challengesAsChallenged Challenge[] @relation(\"Challenged\")\n challengesAsAdmin Challenge[] @relation(\"AdminValidator\")\n challengesAsWinner Challenge[] @relation(\"ChallengeWinner\")\n\n @@index([score])\n @@index([email])\n}\n\nmodel UserPreferences {\n id String @id @default(cuid())\n userId String @unique\n homeBackground String?\n eventsBackground String?\n leaderboardBackground String?\n theme String? @default(\"default\")\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n}\n\nmodel Event {\n id String @id @default(cuid())\n date DateTime\n name String\n description String\n type EventType\n room String?\n time String?\n maxPlaces Int?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n feedbacks EventFeedback[]\n registrations EventRegistration[]\n\n @@index([date])\n}\n\nmodel EventRegistration {\n id String @id @default(cuid())\n userId String\n eventId String\n createdAt DateTime @default(now())\n event Event @relation(fields: [eventId], references: [id], onDelete: Cascade)\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([userId, eventId])\n @@index([userId])\n @@index([eventId])\n}\n\nmodel EventFeedback {\n id String @id @default(cuid())\n userId String\n eventId String\n rating Int\n comment String?\n isRead Boolean @default(false)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n event Event @relation(fields: [eventId], references: [id], onDelete: Cascade)\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([userId, eventId])\n @@index([userId])\n @@index([eventId])\n @@index([isRead])\n}\n\nmodel SitePreferences {\n id String @id @default(\"global\")\n homeBackground String?\n eventsBackground String?\n leaderboardBackground String?\n challengesBackground String?\n eventRegistrationPoints Int @default(100)\n eventFeedbackPoints Int @default(100)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nenum Role {\n USER\n ADMIN\n}\n\nenum EventType {\n ATELIER\n KATA\n PRESENTATION\n LEARNING_HOUR\n}\n\nenum CharacterClass {\n WARRIOR\n MAGE\n ROGUE\n RANGER\n PALADIN\n ENGINEER\n MERCHANT\n SCHOLAR\n BERSERKER\n NECROMANCER\n}\n\nenum ChallengeStatus {\n PENDING\n ACCEPTED\n COMPLETED\n REJECTED\n CANCELLED\n}\n\nmodel Challenge {\n id String @id @default(cuid())\n challengerId String // Joueur qui lance le défi\n challengedId String // Joueur qui reçoit le défi\n challenger User @relation(\"Challenger\", fields: [challengerId], references: [id], onDelete: Cascade)\n challenged User @relation(\"Challenged\", fields: [challengedId], references: [id], onDelete: Cascade)\n title String // Titre du défi\n description String // Description détaillée du défi\n pointsReward Int @default(100) // Points à gagner pour le gagnant\n status ChallengeStatus @default(PENDING)\n adminId String? // Admin qui valide le défi\n admin User? @relation(\"AdminValidator\", fields: [adminId], references: [id], onDelete: SetNull)\n adminComment String? // Commentaire de l'admin lors de la validation/rejet\n winnerId String? // ID du gagnant (challengerId ou challengedId)\n winner User? @relation(\"ChallengeWinner\", fields: [winnerId], references: [id], onDelete: SetNull)\n createdAt DateTime @default(now())\n acceptedAt DateTime? // Date d'acceptation du défi\n completedAt DateTime? // Date de validation par l'admin\n updatedAt DateTime @updatedAt\n\n @@index([challengerId])\n @@index([challengedId])\n @@index([status])\n @@index([adminId])\n}\n", "runtimeDataModel": { "models": {}, "enums": {}, @@ -28,7 +28,7 @@ const config: runtime.GetPrismaClientConfig = { } } -config.runtimeDataModel = JSON.parse("{\"models\":{\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"password\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"username\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"role\",\"kind\":\"enum\",\"type\":\"Role\"},{\"name\":\"score\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"level\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"hp\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"maxHp\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"xp\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"maxXp\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"avatar\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"bio\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"characterClass\",\"kind\":\"enum\",\"type\":\"CharacterClass\"},{\"name\":\"eventFeedbacks\",\"kind\":\"object\",\"type\":\"EventFeedback\",\"relationName\":\"EventFeedbackToUser\"},{\"name\":\"eventRegistrations\",\"kind\":\"object\",\"type\":\"EventRegistration\",\"relationName\":\"EventRegistrationToUser\"},{\"name\":\"preferences\",\"kind\":\"object\",\"type\":\"UserPreferences\",\"relationName\":\"UserToUserPreferences\"},{\"name\":\"challengesAsChallenger\",\"kind\":\"object\",\"type\":\"Challenge\",\"relationName\":\"Challenger\"},{\"name\":\"challengesAsChallenged\",\"kind\":\"object\",\"type\":\"Challenge\",\"relationName\":\"Challenged\"},{\"name\":\"challengesAsAdmin\",\"kind\":\"object\",\"type\":\"Challenge\",\"relationName\":\"AdminValidator\"},{\"name\":\"challengesAsWinner\",\"kind\":\"object\",\"type\":\"Challenge\",\"relationName\":\"ChallengeWinner\"}],\"dbName\":null},\"UserPreferences\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"homeBackground\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"eventsBackground\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"leaderboardBackground\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"theme\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"UserToUserPreferences\"}],\"dbName\":null},\"Event\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"date\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"description\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"type\",\"kind\":\"enum\",\"type\":\"EventType\"},{\"name\":\"room\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"time\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"maxPlaces\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"feedbacks\",\"kind\":\"object\",\"type\":\"EventFeedback\",\"relationName\":\"EventToEventFeedback\"},{\"name\":\"registrations\",\"kind\":\"object\",\"type\":\"EventRegistration\",\"relationName\":\"EventToEventRegistration\"}],\"dbName\":null},\"EventRegistration\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"eventId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"event\",\"kind\":\"object\",\"type\":\"Event\",\"relationName\":\"EventToEventRegistration\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"EventRegistrationToUser\"}],\"dbName\":null},\"EventFeedback\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"eventId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"rating\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"comment\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"event\",\"kind\":\"object\",\"type\":\"Event\",\"relationName\":\"EventToEventFeedback\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"EventFeedbackToUser\"}],\"dbName\":null},\"SitePreferences\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"homeBackground\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"eventsBackground\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"leaderboardBackground\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"challengesBackground\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"eventRegistrationPoints\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"eventFeedbackPoints\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"Challenge\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"challengerId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"challengedId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"challenger\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"Challenger\"},{\"name\":\"challenged\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"Challenged\"},{\"name\":\"title\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"description\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"pointsReward\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"status\",\"kind\":\"enum\",\"type\":\"ChallengeStatus\"},{\"name\":\"adminId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"admin\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"AdminValidator\"},{\"name\":\"adminComment\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"winnerId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"winner\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"ChallengeWinner\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"acceptedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"completedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}") +config.runtimeDataModel = JSON.parse("{\"models\":{\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"password\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"username\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"role\",\"kind\":\"enum\",\"type\":\"Role\"},{\"name\":\"score\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"level\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"hp\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"maxHp\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"xp\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"maxXp\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"avatar\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"bio\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"characterClass\",\"kind\":\"enum\",\"type\":\"CharacterClass\"},{\"name\":\"eventFeedbacks\",\"kind\":\"object\",\"type\":\"EventFeedback\",\"relationName\":\"EventFeedbackToUser\"},{\"name\":\"eventRegistrations\",\"kind\":\"object\",\"type\":\"EventRegistration\",\"relationName\":\"EventRegistrationToUser\"},{\"name\":\"preferences\",\"kind\":\"object\",\"type\":\"UserPreferences\",\"relationName\":\"UserToUserPreferences\"},{\"name\":\"challengesAsChallenger\",\"kind\":\"object\",\"type\":\"Challenge\",\"relationName\":\"Challenger\"},{\"name\":\"challengesAsChallenged\",\"kind\":\"object\",\"type\":\"Challenge\",\"relationName\":\"Challenged\"},{\"name\":\"challengesAsAdmin\",\"kind\":\"object\",\"type\":\"Challenge\",\"relationName\":\"AdminValidator\"},{\"name\":\"challengesAsWinner\",\"kind\":\"object\",\"type\":\"Challenge\",\"relationName\":\"ChallengeWinner\"}],\"dbName\":null},\"UserPreferences\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"homeBackground\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"eventsBackground\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"leaderboardBackground\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"theme\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"UserToUserPreferences\"}],\"dbName\":null},\"Event\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"date\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"description\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"type\",\"kind\":\"enum\",\"type\":\"EventType\"},{\"name\":\"room\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"time\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"maxPlaces\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"feedbacks\",\"kind\":\"object\",\"type\":\"EventFeedback\",\"relationName\":\"EventToEventFeedback\"},{\"name\":\"registrations\",\"kind\":\"object\",\"type\":\"EventRegistration\",\"relationName\":\"EventToEventRegistration\"}],\"dbName\":null},\"EventRegistration\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"eventId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"event\",\"kind\":\"object\",\"type\":\"Event\",\"relationName\":\"EventToEventRegistration\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"EventRegistrationToUser\"}],\"dbName\":null},\"EventFeedback\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"eventId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"rating\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"comment\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"isRead\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"event\",\"kind\":\"object\",\"type\":\"Event\",\"relationName\":\"EventToEventFeedback\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"EventFeedbackToUser\"}],\"dbName\":null},\"SitePreferences\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"homeBackground\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"eventsBackground\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"leaderboardBackground\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"challengesBackground\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"eventRegistrationPoints\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"eventFeedbackPoints\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"Challenge\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"challengerId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"challengedId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"challenger\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"Challenger\"},{\"name\":\"challenged\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"Challenged\"},{\"name\":\"title\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"description\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"pointsReward\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"status\",\"kind\":\"enum\",\"type\":\"ChallengeStatus\"},{\"name\":\"adminId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"admin\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"AdminValidator\"},{\"name\":\"adminComment\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"winnerId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"winner\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"ChallengeWinner\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"acceptedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"completedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}") async function decodeBase64AsWasm(wasmBase64: string): Promise { const { Buffer } = await import('node:buffer') diff --git a/prisma/generated/prisma/internal/prismaNamespace.ts b/prisma/generated/prisma/internal/prismaNamespace.ts index d868283..2507494 100644 --- a/prisma/generated/prisma/internal/prismaNamespace.ts +++ b/prisma/generated/prisma/internal/prismaNamespace.ts @@ -1032,6 +1032,7 @@ export const EventFeedbackScalarFieldEnum = { eventId: 'eventId', rating: 'rating', comment: 'comment', + isRead: 'isRead', createdAt: 'createdAt', updatedAt: 'updatedAt' } as const @@ -1138,6 +1139,13 @@ export type EnumEventTypeFieldRefInput<$PrismaModel> = FieldRefInputType<$Prisma +/** + * Reference to a field of type 'Boolean' + */ +export type BooleanFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Boolean'> + + + /** * Reference to a field of type 'ChallengeStatus' */ diff --git a/prisma/generated/prisma/internal/prismaNamespaceBrowser.ts b/prisma/generated/prisma/internal/prismaNamespaceBrowser.ts index 63d8c82..501d99e 100644 --- a/prisma/generated/prisma/internal/prismaNamespaceBrowser.ts +++ b/prisma/generated/prisma/internal/prismaNamespaceBrowser.ts @@ -141,6 +141,7 @@ export const EventFeedbackScalarFieldEnum = { eventId: 'eventId', rating: 'rating', comment: 'comment', + isRead: 'isRead', createdAt: 'createdAt', updatedAt: 'updatedAt' } as const diff --git a/prisma/generated/prisma/models/EventFeedback.ts b/prisma/generated/prisma/models/EventFeedback.ts index 9b50f8e..3627215 100644 --- a/prisma/generated/prisma/models/EventFeedback.ts +++ b/prisma/generated/prisma/models/EventFeedback.ts @@ -40,6 +40,7 @@ export type EventFeedbackMinAggregateOutputType = { eventId: string | null rating: number | null comment: string | null + isRead: boolean | null createdAt: Date | null updatedAt: Date | null } @@ -50,6 +51,7 @@ export type EventFeedbackMaxAggregateOutputType = { eventId: string | null rating: number | null comment: string | null + isRead: boolean | null createdAt: Date | null updatedAt: Date | null } @@ -60,6 +62,7 @@ export type EventFeedbackCountAggregateOutputType = { eventId: number rating: number comment: number + isRead: number createdAt: number updatedAt: number _all: number @@ -80,6 +83,7 @@ export type EventFeedbackMinAggregateInputType = { eventId?: true rating?: true comment?: true + isRead?: true createdAt?: true updatedAt?: true } @@ -90,6 +94,7 @@ export type EventFeedbackMaxAggregateInputType = { eventId?: true rating?: true comment?: true + isRead?: true createdAt?: true updatedAt?: true } @@ -100,6 +105,7 @@ export type EventFeedbackCountAggregateInputType = { eventId?: true rating?: true comment?: true + isRead?: true createdAt?: true updatedAt?: true _all?: true @@ -197,6 +203,7 @@ export type EventFeedbackGroupByOutputType = { eventId: string rating: number comment: string | null + isRead: boolean createdAt: Date updatedAt: Date _count: EventFeedbackCountAggregateOutputType | null @@ -230,6 +237,7 @@ export type EventFeedbackWhereInput = { eventId?: Prisma.StringFilter<"EventFeedback"> | string rating?: Prisma.IntFilter<"EventFeedback"> | number comment?: Prisma.StringNullableFilter<"EventFeedback"> | string | null + isRead?: Prisma.BoolFilter<"EventFeedback"> | boolean createdAt?: Prisma.DateTimeFilter<"EventFeedback"> | Date | string updatedAt?: Prisma.DateTimeFilter<"EventFeedback"> | Date | string event?: Prisma.XOR @@ -242,6 +250,7 @@ export type EventFeedbackOrderByWithRelationInput = { eventId?: Prisma.SortOrder rating?: Prisma.SortOrder comment?: Prisma.SortOrderInput | Prisma.SortOrder + isRead?: Prisma.SortOrder createdAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder event?: Prisma.EventOrderByWithRelationInput @@ -258,6 +267,7 @@ export type EventFeedbackWhereUniqueInput = Prisma.AtLeast<{ eventId?: Prisma.StringFilter<"EventFeedback"> | string rating?: Prisma.IntFilter<"EventFeedback"> | number comment?: Prisma.StringNullableFilter<"EventFeedback"> | string | null + isRead?: Prisma.BoolFilter<"EventFeedback"> | boolean createdAt?: Prisma.DateTimeFilter<"EventFeedback"> | Date | string updatedAt?: Prisma.DateTimeFilter<"EventFeedback"> | Date | string event?: Prisma.XOR @@ -270,6 +280,7 @@ export type EventFeedbackOrderByWithAggregationInput = { eventId?: Prisma.SortOrder rating?: Prisma.SortOrder comment?: Prisma.SortOrderInput | Prisma.SortOrder + isRead?: Prisma.SortOrder createdAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder _count?: Prisma.EventFeedbackCountOrderByAggregateInput @@ -288,6 +299,7 @@ export type EventFeedbackScalarWhereWithAggregatesInput = { eventId?: Prisma.StringWithAggregatesFilter<"EventFeedback"> | string rating?: Prisma.IntWithAggregatesFilter<"EventFeedback"> | number comment?: Prisma.StringNullableWithAggregatesFilter<"EventFeedback"> | string | null + isRead?: Prisma.BoolWithAggregatesFilter<"EventFeedback"> | boolean createdAt?: Prisma.DateTimeWithAggregatesFilter<"EventFeedback"> | Date | string updatedAt?: Prisma.DateTimeWithAggregatesFilter<"EventFeedback"> | Date | string } @@ -296,6 +308,7 @@ export type EventFeedbackCreateInput = { id?: string rating: number comment?: string | null + isRead?: boolean createdAt?: Date | string updatedAt?: Date | string event: Prisma.EventCreateNestedOneWithoutFeedbacksInput @@ -308,6 +321,7 @@ export type EventFeedbackUncheckedCreateInput = { eventId: string rating: number comment?: string | null + isRead?: boolean createdAt?: Date | string updatedAt?: Date | string } @@ -316,6 +330,7 @@ export type EventFeedbackUpdateInput = { id?: Prisma.StringFieldUpdateOperationsInput | string rating?: Prisma.IntFieldUpdateOperationsInput | number comment?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + isRead?: Prisma.BoolFieldUpdateOperationsInput | boolean createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string event?: Prisma.EventUpdateOneRequiredWithoutFeedbacksNestedInput @@ -328,6 +343,7 @@ export type EventFeedbackUncheckedUpdateInput = { eventId?: Prisma.StringFieldUpdateOperationsInput | string rating?: Prisma.IntFieldUpdateOperationsInput | number comment?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + isRead?: Prisma.BoolFieldUpdateOperationsInput | boolean createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string } @@ -338,6 +354,7 @@ export type EventFeedbackCreateManyInput = { eventId: string rating: number comment?: string | null + isRead?: boolean createdAt?: Date | string updatedAt?: Date | string } @@ -346,6 +363,7 @@ export type EventFeedbackUpdateManyMutationInput = { id?: Prisma.StringFieldUpdateOperationsInput | string rating?: Prisma.IntFieldUpdateOperationsInput | number comment?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + isRead?: Prisma.BoolFieldUpdateOperationsInput | boolean createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string } @@ -356,6 +374,7 @@ export type EventFeedbackUncheckedUpdateManyInput = { eventId?: Prisma.StringFieldUpdateOperationsInput | string rating?: Prisma.IntFieldUpdateOperationsInput | number comment?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + isRead?: Prisma.BoolFieldUpdateOperationsInput | boolean createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string } @@ -381,6 +400,7 @@ export type EventFeedbackCountOrderByAggregateInput = { eventId?: Prisma.SortOrder rating?: Prisma.SortOrder comment?: Prisma.SortOrder + isRead?: Prisma.SortOrder createdAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder } @@ -395,6 +415,7 @@ export type EventFeedbackMaxOrderByAggregateInput = { eventId?: Prisma.SortOrder rating?: Prisma.SortOrder comment?: Prisma.SortOrder + isRead?: Prisma.SortOrder createdAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder } @@ -405,6 +426,7 @@ export type EventFeedbackMinOrderByAggregateInput = { eventId?: Prisma.SortOrder rating?: Prisma.SortOrder comment?: Prisma.SortOrder + isRead?: Prisma.SortOrder createdAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder } @@ -497,10 +519,15 @@ export type EventFeedbackUncheckedUpdateManyWithoutEventNestedInput = { deleteMany?: Prisma.EventFeedbackScalarWhereInput | Prisma.EventFeedbackScalarWhereInput[] } +export type BoolFieldUpdateOperationsInput = { + set?: boolean +} + export type EventFeedbackCreateWithoutUserInput = { id?: string rating: number comment?: string | null + isRead?: boolean createdAt?: Date | string updatedAt?: Date | string event: Prisma.EventCreateNestedOneWithoutFeedbacksInput @@ -511,6 +538,7 @@ export type EventFeedbackUncheckedCreateWithoutUserInput = { eventId: string rating: number comment?: string | null + isRead?: boolean createdAt?: Date | string updatedAt?: Date | string } @@ -549,6 +577,7 @@ export type EventFeedbackScalarWhereInput = { eventId?: Prisma.StringFilter<"EventFeedback"> | string rating?: Prisma.IntFilter<"EventFeedback"> | number comment?: Prisma.StringNullableFilter<"EventFeedback"> | string | null + isRead?: Prisma.BoolFilter<"EventFeedback"> | boolean createdAt?: Prisma.DateTimeFilter<"EventFeedback"> | Date | string updatedAt?: Prisma.DateTimeFilter<"EventFeedback"> | Date | string } @@ -557,6 +586,7 @@ export type EventFeedbackCreateWithoutEventInput = { id?: string rating: number comment?: string | null + isRead?: boolean createdAt?: Date | string updatedAt?: Date | string user: Prisma.UserCreateNestedOneWithoutEventFeedbacksInput @@ -567,6 +597,7 @@ export type EventFeedbackUncheckedCreateWithoutEventInput = { userId: string rating: number comment?: string | null + isRead?: boolean createdAt?: Date | string updatedAt?: Date | string } @@ -601,6 +632,7 @@ export type EventFeedbackCreateManyUserInput = { eventId: string rating: number comment?: string | null + isRead?: boolean createdAt?: Date | string updatedAt?: Date | string } @@ -609,6 +641,7 @@ export type EventFeedbackUpdateWithoutUserInput = { id?: Prisma.StringFieldUpdateOperationsInput | string rating?: Prisma.IntFieldUpdateOperationsInput | number comment?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + isRead?: Prisma.BoolFieldUpdateOperationsInput | boolean createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string event?: Prisma.EventUpdateOneRequiredWithoutFeedbacksNestedInput @@ -619,6 +652,7 @@ export type EventFeedbackUncheckedUpdateWithoutUserInput = { eventId?: Prisma.StringFieldUpdateOperationsInput | string rating?: Prisma.IntFieldUpdateOperationsInput | number comment?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + isRead?: Prisma.BoolFieldUpdateOperationsInput | boolean createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string } @@ -628,6 +662,7 @@ export type EventFeedbackUncheckedUpdateManyWithoutUserInput = { eventId?: Prisma.StringFieldUpdateOperationsInput | string rating?: Prisma.IntFieldUpdateOperationsInput | number comment?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + isRead?: Prisma.BoolFieldUpdateOperationsInput | boolean createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string } @@ -637,6 +672,7 @@ export type EventFeedbackCreateManyEventInput = { userId: string rating: number comment?: string | null + isRead?: boolean createdAt?: Date | string updatedAt?: Date | string } @@ -645,6 +681,7 @@ export type EventFeedbackUpdateWithoutEventInput = { id?: Prisma.StringFieldUpdateOperationsInput | string rating?: Prisma.IntFieldUpdateOperationsInput | number comment?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + isRead?: Prisma.BoolFieldUpdateOperationsInput | boolean createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string user?: Prisma.UserUpdateOneRequiredWithoutEventFeedbacksNestedInput @@ -655,6 +692,7 @@ export type EventFeedbackUncheckedUpdateWithoutEventInput = { userId?: Prisma.StringFieldUpdateOperationsInput | string rating?: Prisma.IntFieldUpdateOperationsInput | number comment?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + isRead?: Prisma.BoolFieldUpdateOperationsInput | boolean createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string } @@ -664,6 +702,7 @@ export type EventFeedbackUncheckedUpdateManyWithoutEventInput = { userId?: Prisma.StringFieldUpdateOperationsInput | string rating?: Prisma.IntFieldUpdateOperationsInput | number comment?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + isRead?: Prisma.BoolFieldUpdateOperationsInput | boolean createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string } @@ -676,6 +715,7 @@ export type EventFeedbackSelect @@ -688,6 +728,7 @@ export type EventFeedbackSelectCreateManyAndReturn @@ -700,6 +741,7 @@ export type EventFeedbackSelectUpdateManyAndReturn @@ -712,11 +754,12 @@ export type EventFeedbackSelectScalar = { eventId?: boolean rating?: boolean comment?: boolean + isRead?: boolean createdAt?: boolean updatedAt?: boolean } -export type EventFeedbackOmit = runtime.Types.Extensions.GetOmit<"id" | "userId" | "eventId" | "rating" | "comment" | "createdAt" | "updatedAt", ExtArgs["result"]["eventFeedback"]> +export type EventFeedbackOmit = runtime.Types.Extensions.GetOmit<"id" | "userId" | "eventId" | "rating" | "comment" | "isRead" | "createdAt" | "updatedAt", ExtArgs["result"]["eventFeedback"]> export type EventFeedbackInclude = { event?: boolean | Prisma.EventDefaultArgs user?: boolean | Prisma.UserDefaultArgs @@ -742,6 +785,7 @@ export type $EventFeedbackPayload @@ -1174,6 +1218,7 @@ export interface EventFeedbackFieldRefs { readonly eventId: Prisma.FieldRef<"EventFeedback", 'String'> readonly rating: Prisma.FieldRef<"EventFeedback", 'Int'> readonly comment: Prisma.FieldRef<"EventFeedback", 'String'> + readonly isRead: Prisma.FieldRef<"EventFeedback", 'Boolean'> readonly createdAt: Prisma.FieldRef<"EventFeedback", 'DateTime'> readonly updatedAt: Prisma.FieldRef<"EventFeedback", 'DateTime'> } diff --git a/prisma/migrations/20251216154133_add_feedback_is_read/migration.sql b/prisma/migrations/20251216154133_add_feedback_is_read/migration.sql new file mode 100644 index 0000000..fa7ee2b --- /dev/null +++ b/prisma/migrations/20251216154133_add_feedback_is_read/migration.sql @@ -0,0 +1,24 @@ +-- RedefineTables +PRAGMA defer_foreign_keys=ON; +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_EventFeedback" ( + "id" TEXT NOT NULL PRIMARY KEY, + "userId" TEXT NOT NULL, + "eventId" TEXT NOT NULL, + "rating" INTEGER NOT NULL, + "comment" TEXT, + "isRead" BOOLEAN NOT NULL DEFAULT false, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + CONSTRAINT "EventFeedback_eventId_fkey" FOREIGN KEY ("eventId") REFERENCES "Event" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT "EventFeedback_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); +INSERT INTO "new_EventFeedback" ("comment", "createdAt", "eventId", "id", "rating", "updatedAt", "userId") SELECT "comment", "createdAt", "eventId", "id", "rating", "updatedAt", "userId" FROM "EventFeedback"; +DROP TABLE "EventFeedback"; +ALTER TABLE "new_EventFeedback" RENAME TO "EventFeedback"; +CREATE INDEX "EventFeedback_userId_idx" ON "EventFeedback"("userId"); +CREATE INDEX "EventFeedback_eventId_idx" ON "EventFeedback"("eventId"); +CREATE INDEX "EventFeedback_isRead_idx" ON "EventFeedback"("isRead"); +CREATE UNIQUE INDEX "EventFeedback_userId_eventId_key" ON "EventFeedback"("userId", "eventId"); +PRAGMA foreign_keys=ON; +PRAGMA defer_foreign_keys=OFF; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 23fa4a1..115f100 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -84,6 +84,7 @@ model EventFeedback { eventId String rating Int comment String? + isRead Boolean @default(false) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt event Event @relation(fields: [eventId], references: [id], onDelete: Cascade) @@ -92,6 +93,7 @@ model EventFeedback { @@unique([userId, eventId]) @@index([userId]) @@index([eventId]) + @@index([isRead]) } model SitePreferences { diff --git a/services/events/event-feedback.service.ts b/services/events/event-feedback.service.ts index 933f88a..f451ba5 100644 --- a/services/events/event-feedback.service.ts +++ b/services/events/event-feedback.service.ts @@ -98,6 +98,8 @@ export class EventFeedbackService { id: true, username: true, email: true, + avatar: true, + score: true, }, }, },