// Server-only: this module pulls in Prisma. Do not import from client // components — `@/lib/reviews` (constants/types) is the safe surface. import { prisma } from "@/lib/prisma"; import type { CarbetReview, CarbetReviewStats } from "@/lib/reviews"; // Aggregate stats used on cards and detail pages. Returns null average when // there are no reviews so the caller can render a neutral "no reviews yet" // state rather than a misleading 0.0. export async function getCarbetReviewStats( carbetId: string, ): Promise { const agg = await prisma.review.aggregate({ where: { carbetId }, _count: { _all: true }, _avg: { rating: true }, }); const count = agg._count._all; const avg = agg._avg.rating; return { count, averageRating: count > 0 && avg !== null ? Number(avg) : null, }; } export async function getCarbetReviewStatsMany( carbetIds: string[], ): Promise> { if (carbetIds.length === 0) { return new Map(); } const rows = await prisma.review.groupBy({ by: ["carbetId"], where: { carbetId: { in: carbetIds } }, _count: { _all: true }, _avg: { rating: true }, }); const map = new Map(); for (const id of carbetIds) { map.set(id, { count: 0, averageRating: null }); } for (const row of rows) { const avg = row._avg.rating; map.set(row.carbetId, { count: row._count._all, averageRating: avg !== null ? Number(avg) : null, }); } return map; } export async function listCarbetReviews( carbetId: string, limit = 20, ): Promise { const reviews = await prisma.review.findMany({ where: { carbetId }, orderBy: { createdAt: "desc" }, take: limit, select: { id: true, rating: true, comment: true, hostResponse: true, hostRespondedAt: true, createdAt: true, author: { select: { firstName: true } }, booking: { select: { startDate: true, endDate: true } }, }, }); return reviews.map((review) => ({ id: review.id, rating: review.rating, comment: review.comment, hostResponse: review.hostResponse, hostRespondedAt: review.hostRespondedAt?.toISOString() ?? null, createdAt: review.createdAt.toISOString(), authorFirstName: review.author.firstName, stayStartDate: review.booking.startDate.toISOString(), stayEndDate: review.booking.endDate.toISOString(), })); }