import { prisma } from "@/lib/prisma"; import type { Review } from "@/generated/prisma/client"; export type ReviewWithCustomer = Review & { customer: { firstName: string; lastName: string }; }; export interface ReviewSummary { average: number | null; count: number; } export async function getApprovedReviews(productId: string): Promise { return prisma.review.findMany({ where: { productId, isApproved: true }, include: { customer: { select: { firstName: true, lastName: true } } }, orderBy: { createdAt: "desc" }, }); } export async function getReviewSummary(productId: string): Promise { const result = await prisma.review.aggregate({ where: { productId, isApproved: true }, _avg: { rating: true }, _count: true, }); return { average: result._avg.rating, count: result._count }; } /** * Wie getReviewSummary, aber fuer mehrere Produkte in einer Abfrage — vermeidet * N+1-Abfragen beim Rendern von Produktrastern (Shop-Uebersicht u.ae.). */ export async function getReviewSummariesByProductIds( productIds: string[] ): Promise> { if (productIds.length === 0) return new Map(); const results = await prisma.review.groupBy({ by: ["productId"], where: { productId: { in: productIds }, isApproved: true }, _avg: { rating: true }, _count: true, }); return new Map(results.map((r) => [r.productId, { average: r._avg.rating, count: r._count }])); } /** Eigene Bewertung des Kunden fuer dieses Produkt, unabhaengig vom Freischaltungsstatus. */ export async function getCustomerReview(productId: string, customerId: string): Promise { return prisma.review.findUnique({ where: { productId_customerId: { productId, customerId } }, }); } /** * "Verifizierter Kauf": mindestens eine bezahlte, nicht stornierte Bestellung * des Kunden enthaelt dieses Produkt. Gastbestellungen (ohne customerId) * zaehlen bewusst nicht, da eine Bewertung an ein Kundenkonto gebunden ist. */ export async function hasCustomerPurchased(productId: string, customerId: string): Promise { const orderItem = await prisma.orderItem.findFirst({ where: { productId, order: { customerId, status: { notIn: ["NEU", "STORNIERT"] }, }, }, select: { id: true }, }); return orderItem !== null; }