import Link from "next/link"; import { prisma } from "@/lib/prisma"; import type { Prisma } from "@/generated/prisma/client"; import { BackLink } from "@/components/back-link"; import { ConfirmForm } from "@/components/confirm-form"; import { formatDate } from "@/lib/format"; import { StarRating } from "@/components/star-rating"; import { AdminActionButton, AdminBadge, AdminEmptyState, AdminPageHeader, AdminRowActions, AdminSearchForm, } from "@/components/admin-list"; import { AdminArchiveTabs } from "@/components/admin-archive"; import { insensitiveContains } from "@/lib/prisma-search"; import { isArchiveView } from "@/lib/archive"; import { approvedReviewWhere, pendingReviewWhere, rejectedReviewWhere } from "@/lib/review-status"; import { approveReviewAction, deleteReviewAction, rejectReviewAction } from "../actions"; import { getLocale } from "@/i18n/locale"; import { getDictionary } from "@/i18n/get-dictionary"; import type { Dictionary } from "@/i18n/dictionary-type"; const MAX_ROWS = 100; const BASE_PATH = "/admin/bewertungen"; const REVIEW_INCLUDE = { product: { select: { name: true, slug: true } }, customer: { select: { firstName: true, lastName: true } }, } satisfies Prisma.ReviewInclude; type AdminReview = Prisma.ReviewGetPayload<{ include: typeof REVIEW_INCLUDE }>; type ReviewTexts = Dictionary["adminReviewsPage"]; function searchWhere(query: string): Prisma.ReviewWhereInput { if (!query) return {}; return { OR: [ { product: { name: insensitiveContains(query) } }, { customer: { firstName: insensitiveContains(query) } }, { customer: { lastName: insensitiveContains(query) } }, ], }; } export default async function AdminBewertungenPage(props: PageProps<"/admin/bewertungen">) { const t = getDictionary(await getLocale()); const s = t.adminReviewsPage; const { q, ansicht } = await props.searchParams; const query = typeof q === "string" ? q.trim() : ""; const isArchive = isArchiveView(ansicht); const filter = searchWhere(query); const findReviews = (where: Prisma.ReviewWhereInput, orderBy: Prisma.ReviewOrderByWithRelationInput) => prisma.review.findMany({ where: { ...filter, ...where }, include: REVIEW_INCLUDE, orderBy, take: MAX_ROWS }); // Offene: aelteste zuerst, sie warten am laengsten. Archiv: zuletzt entschiedene oben. const [pending, approved, rejected, pendingCount, decidedCount] = await Promise.all([ isArchive ? Promise.resolve([]) : findReviews(pendingReviewWhere(), { createdAt: "asc" }), isArchive ? findReviews(approvedReviewWhere(), { updatedAt: "desc" }) : Promise.resolve([]), isArchive ? findReviews(rejectedReviewWhere(), { rejectedAt: "desc" }) : Promise.resolve([]), prisma.review.count({ where: { ...filter, ...pendingReviewWhere() } }), prisma.review.count({ where: { ...filter, NOT: pendingReviewWhere() } }), ]); return (
{t.adminArchive.autoRuleReviews}
: null}| {s.colProduct} | {s.colCustomer} | {s.colRating} | {s.colComment} | {s.colDate} | {s.colStatus} | |
|---|---|---|---|---|---|---|
|
|
{review.customer.firstName} {review.customer.lastName} |
|
{review.comment ?? "—"} | {formatDate(review.createdAt)} |
|
|
{s.emptyColumn}
) : ({review.customer.firstName} {review.customer.lastName} ·{" "} {formatDate(review.createdAt)}
{review.comment ?{review.comment}
: null} {decision === "rejected" && review.rejectedAt ? ({s.rejectedOn(formatDate(review.rejectedAt))}
) : null}