Files
got-gaming/services/events/event-feedback.service.ts

180 lines
4.3 KiB
TypeScript

import { prisma } from "../database";
import type { EventFeedback, Prisma } from "@/prisma/generated/prisma/client";
import { ValidationError, NotFoundError } from "../errors";
import { eventService } from "./event.service";
export interface CreateOrUpdateFeedbackInput {
rating: number;
comment?: string | null;
}
export interface FeedbackStatistics {
eventId: string;
eventName: string;
eventDate: Date | null;
eventType: string | null;
averageRating: number;
feedbackCount: number;
}
/**
* Service de gestion des feedbacks sur les événements
*/
export class EventFeedbackService {
/**
* Crée ou met à jour un feedback
*/
async createOrUpdateFeedback(
userId: string,
eventId: string,
data: CreateOrUpdateFeedbackInput
): Promise<EventFeedback> {
return prisma.eventFeedback.upsert({
where: {
userId_eventId: {
userId,
eventId,
},
},
update: {
rating: data.rating,
comment: data.comment || null,
},
create: {
userId,
eventId,
rating: data.rating,
comment: data.comment || null,
},
});
}
/**
* Récupère le feedback d'un utilisateur pour un événement
*/
async getUserFeedback(
userId: string,
eventId: string
): Promise<EventFeedback | null> {
return prisma.eventFeedback.findUnique({
where: {
userId_eventId: {
userId,
eventId,
},
},
include: {
event: {
select: {
id: true,
name: true,
date: true,
},
},
},
});
}
/**
* Récupère tous les feedbacks (pour admin)
*/
async getAllFeedbacks(options?: {
include?: Prisma.EventFeedbackInclude;
orderBy?: Prisma.EventFeedbackOrderByWithRelationInput;
}): Promise<EventFeedback[]> {
return prisma.eventFeedback.findMany({
include: options?.include || {
event: {
select: {
id: true,
name: true,
date: true,
type: true,
},
},
user: {
select: {
id: true,
username: true,
email: true,
},
},
},
orderBy: options?.orderBy || { createdAt: "desc" },
});
}
/**
* Récupère les statistiques de feedback par événement
*/
async getFeedbackStatistics(): Promise<FeedbackStatistics[]> {
// Calculer les statistiques par événement
const eventStats = await prisma.eventFeedback.groupBy({
by: ["eventId"],
_avg: {
rating: true,
},
_count: {
id: true,
},
});
// Récupérer les détails des événements pour les stats
const eventIds = eventStats.map((stat) => stat.eventId);
const events = await prisma.event.findMany({
where: {
id: {
in: eventIds,
},
},
select: {
id: true,
name: true,
date: true,
type: true,
},
});
// Combiner les stats avec les détails des événements
return eventStats.map((stat) => {
const event = events.find((e) => e.id === stat.eventId);
return {
eventId: stat.eventId,
eventName: event?.name || "Événement supprimé",
eventDate: event?.date || null,
eventType: event?.type || null,
averageRating: stat._avg.rating || 0,
feedbackCount: stat._count.id,
};
});
}
/**
* Valide et crée/met à jour un feedback avec toutes les règles métier
*/
async validateAndCreateFeedback(
userId: string,
eventId: string,
data: { rating: number; comment?: string | null }
): Promise<EventFeedback> {
// Valider la note (1-5)
if (!data.rating || data.rating < 1 || data.rating > 5) {
throw new ValidationError("La note doit être entre 1 et 5", "rating");
}
// Vérifier que l'événement existe
const event = await eventService.getEventById(eventId);
if (!event) {
throw new NotFoundError("Événement");
}
// Créer ou mettre à jour le feedback
return this.createOrUpdateFeedback(userId, eventId, {
rating: data.rating,
comment: data.comment || null,
});
}
}
export const eventFeedbackService = new EventFeedbackService();