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

206 lines
5.2 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";
import { sitePreferencesService } from "../preferences/site-preferences.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,
avatar: true,
score: 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");
}
// Vérifier si c'est un nouveau feedback ou une mise à jour
const existingFeedback = await this.getUserFeedback(userId, eventId);
const isNewFeedback = !existingFeedback;
// Récupérer les points à attribuer depuis les préférences du site
const sitePreferences = await sitePreferencesService.getOrCreateSitePreferences();
const pointsToAward = sitePreferences.eventFeedbackPoints || 100;
// Créer ou mettre à jour le feedback et attribuer les points (seulement pour nouveau feedback)
const [feedback] = await Promise.all([
this.createOrUpdateFeedback(userId, eventId, {
rating: data.rating,
comment: data.comment || null,
}),
// Attribuer les points seulement si c'est un nouveau feedback
isNewFeedback
? prisma.user.update({
where: { id: userId },
data: {
score: {
increment: pointsToAward,
},
},
})
: Promise.resolve(null),
]);
return feedback;
}
}
export const eventFeedbackService = new EventFeedbackService();