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.

This commit is contained in:
Julien Froidefond
2025-12-16 16:43:53 +01:00
parent 3dd82c2bd4
commit 16e4b63ffd
10 changed files with 387 additions and 16 deletions

127
actions/admin/feedback.ts Normal file
View File

@@ -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",
};
}
}

View File

@@ -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<string | null>(null);
const [addingPoints, setAddingPoints] = useState<Record<string, boolean>>(
{}
);
const [markingRead, setMarkingRead] = useState<Record<string, boolean>>({});
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,21 +247,46 @@ export default function FeedbackManagement() {
{filteredFeedbacks.map((feedback) => (
<div
key={feedback.id}
className="bg-black/40 border border-pixel-gold/20 rounded p-3 sm:p-4"
className={`bg-black/40 border rounded p-3 sm:p-4 ${
feedback.isRead
? "border-pixel-gold/20 opacity-75"
: "border-pixel-gold/50 bg-pixel-gold/5"
}`}
>
<div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3 mb-3">
<div className="flex-1 min-w-0">
<div className="flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-3 mb-2">
{/* En-tête utilisateur avec avatar */}
<div className="flex items-center gap-2 sm:gap-3 mb-3">
<Avatar
src={feedback.user.avatar}
username={feedback.user.username}
size="md"
borderClassName="border-pixel-gold/30"
/>
<div className="flex-1 min-w-0">
<div className="flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-2 mb-1">
<h4 className="text-white font-semibold text-sm sm:text-base break-words">
{feedback.user.username}
</h4>
<span className="text-pixel-gold font-bold text-xs sm:text-sm">
{feedback.user.score.toLocaleString("fr-FR")} pts
</span>
</div>
<span className="text-gray-500 text-[10px] sm:text-xs break-all">
{feedback.user.email}
</span>
</div>
<div className="text-pixel-gold text-xs sm:text-sm font-semibold mb-2 break-words">
</div>
<div className="flex items-center gap-2 mb-2">
<div className="text-pixel-gold text-xs sm:text-sm font-semibold break-words">
{feedback.event.name}
</div>
{!feedback.isRead && (
<span className="bg-pixel-gold/20 text-pixel-gold text-[10px] px-1.5 py-0.5 rounded uppercase font-semibold">
Non lu
</span>
)}
</div>
<div className="text-gray-500 text-[10px] sm:text-xs mb-2">
{new Date(feedback.createdAt).toLocaleDateString(
"fr-FR",
@@ -212,8 +300,23 @@ export default function FeedbackManagement() {
)}
</div>
</div>
<div className="flex-shrink-0">
<div className="flex flex-col items-end gap-2 flex-shrink-0">
{renderStars(feedback.rating)}
<Button
variant={feedback.isRead ? "secondary" : "success"}
size="sm"
onClick={() =>
handleMarkAsRead(feedback.id, !feedback.isRead)
}
disabled={markingRead[feedback.id]}
className="text-xs whitespace-nowrap"
>
{markingRead[feedback.id]
? "..."
: feedback.isRead
? "Marquer non lu"
: "Marquer lu"}
</Button>
</div>
</div>
{feedback.comment && (
@@ -223,6 +326,39 @@ export default function FeedbackManagement() {
</p>
</div>
)}
{/* Boutons pour ajouter des points bonus */}
<div className="mt-3 pt-3 border-t border-pixel-gold/20 flex flex-wrap gap-2">
<span className="text-gray-400 text-xs sm:text-sm mr-2">
Points bonus:
</span>
<Button
variant="primary"
size="sm"
onClick={() => handleAddPoints(feedback.user.id, 10)}
disabled={addingPoints[`${feedback.user.id}-10`]}
className="text-xs"
>
{addingPoints[`${feedback.user.id}-10`] ? "..." : "+10"}
</Button>
<Button
variant="primary"
size="sm"
onClick={() => handleAddPoints(feedback.user.id, 100)}
disabled={addingPoints[`${feedback.user.id}-100`]}
className="text-xs"
>
{addingPoints[`${feedback.user.id}-100`] ? "..." : "+100"}
</Button>
<Button
variant="primary"
size="sm"
onClick={() => handleAddPoints(feedback.user.id, 1000)}
disabled={addingPoints[`${feedback.user.id}-1000`]}
className="text-xs"
>
{addingPoints[`${feedback.user.id}-1000`] ? "..." : "+1000"}
</Button>
</div>
</div>
))}
</div>

View File

@@ -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[]

File diff suppressed because one or more lines are too long

View File

@@ -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'
*/

View File

@@ -141,6 +141,7 @@ export const EventFeedbackScalarFieldEnum = {
eventId: 'eventId',
rating: 'rating',
comment: 'comment',
isRead: 'isRead',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
} as const

View File

@@ -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<Prisma.EventScalarRelationFilter, Prisma.EventWhereInput>
@@ -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<Prisma.EventScalarRelationFilter, Prisma.EventWhereInput>
@@ -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<ExtArgs extends runtime.Types.Extensions.Interna
eventId?: boolean
rating?: boolean
comment?: boolean
isRead?: boolean
createdAt?: boolean
updatedAt?: boolean
event?: boolean | Prisma.EventDefaultArgs<ExtArgs>
@@ -688,6 +728,7 @@ export type EventFeedbackSelectCreateManyAndReturn<ExtArgs extends runtime.Types
eventId?: boolean
rating?: boolean
comment?: boolean
isRead?: boolean
createdAt?: boolean
updatedAt?: boolean
event?: boolean | Prisma.EventDefaultArgs<ExtArgs>
@@ -700,6 +741,7 @@ export type EventFeedbackSelectUpdateManyAndReturn<ExtArgs extends runtime.Types
eventId?: boolean
rating?: boolean
comment?: boolean
isRead?: boolean
createdAt?: boolean
updatedAt?: boolean
event?: boolean | Prisma.EventDefaultArgs<ExtArgs>
@@ -712,11 +754,12 @@ export type EventFeedbackSelectScalar = {
eventId?: boolean
rating?: boolean
comment?: boolean
isRead?: boolean
createdAt?: boolean
updatedAt?: boolean
}
export type EventFeedbackOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "userId" | "eventId" | "rating" | "comment" | "createdAt" | "updatedAt", ExtArgs["result"]["eventFeedback"]>
export type EventFeedbackOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "userId" | "eventId" | "rating" | "comment" | "isRead" | "createdAt" | "updatedAt", ExtArgs["result"]["eventFeedback"]>
export type EventFeedbackInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
event?: boolean | Prisma.EventDefaultArgs<ExtArgs>
user?: boolean | Prisma.UserDefaultArgs<ExtArgs>
@@ -742,6 +785,7 @@ export type $EventFeedbackPayload<ExtArgs extends runtime.Types.Extensions.Inter
eventId: string
rating: number
comment: string | null
isRead: boolean
createdAt: Date
updatedAt: Date
}, ExtArgs["result"]["eventFeedback"]>
@@ -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'>
}

View File

@@ -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;

View File

@@ -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 {

View File

@@ -98,6 +98,8 @@ export class EventFeedbackService {
id: true,
username: true,
email: true,
avatar: true,
score: true,
},
},
},