--- import { Icon } from 'astro-icon/components' import { Schema } from 'astro-seo-schema' import { z } from 'zod' import CommentItem from '../components/CommentItem.astro' import CommentReply from '../components/CommentReply.astro' import { getCommentStatusInfo } from '../constants/commentStatus' import { cn } from '../lib/cn' import { commentSortSchema, makeCommentsNestedQuery, MAX_COMMENT_DEPTH, type CommentSortOption, type CommentWithReplies, type CommentWithRepliesPopulated, } from '../lib/commentsWithReplies' import { getOrCreateNotificationPreferences } from '../lib/notificationPreferences' import { zodParseQueryParamsStoringErrors } from '../lib/parseUrlFilters' import { prisma } from '../lib/prisma' import { KYCNOTME_SCHEMA_MINI } from '../lib/schema' import { makeOgImageUrl } from './OgImage' import type { Prisma } from '@prisma/client' import type { Comment, DiscussionForumPosting, WithContext } from 'schema-dts' type Props = { itemReviewedId: string service: Prisma.ServiceGetPayload<{ select: { id: true slug: true listedAt: true name: true description: true createdAt: true } }> } const { service, itemReviewedId } = Astro.props const { data: params } = zodParseQueryParamsStoringErrors( { showPending: z.coerce.boolean().default(false), comment: z.coerce.number().int().positive().nullable().default(null), sort: commentSortSchema, }, Astro ) const toggleUrl = new URL(Astro.request.url) toggleUrl.hash = '#comments' if (params.showPending) { toggleUrl.searchParams.delete('showPending') } else { toggleUrl.searchParams.set('showPending', 'true') } const getSortUrl = (sortOption: CommentSortOption) => { const url = new URL(Astro.request.url) url.searchParams.set('sort', sortOption) return url.toString() + '#comments' } const user = Astro.locals.user const [dbComments, pendingCommentsCount, activeRatingComment] = await Astro.locals.banners.tryMany([ [ 'Failed to fetch comments', async () => await prisma.comment.findMany( makeCommentsNestedQuery({ depth: MAX_COMMENT_DEPTH, user, showPending: params.showPending, serviceId: service.id, sort: params.sort, }) ), [], ], [ 'Failed to count unmoderated comments', async () => prisma.comment.count({ where: { serviceId: service.id, status: { in: ['PENDING', 'HUMAN_PENDING'] }, }, }), 0, ], [ "Failed to fetch user's service rating", async () => user ? await prisma.comment.findFirst({ where: { serviceId: service.id, authorId: user.id, ratingActive: true }, orderBy: { createdAt: 'desc' }, select: { id: true, rating: true, }, }) : null, null, ], ]) const notiPref = user ? await getOrCreateNotificationPreferences(user.id, { watchedComments: { select: { id: true } }, }) : null const populateComment = (comment: CommentWithReplies): CommentWithRepliesPopulated => ({ ...comment, isWatchingReplies: notiPref?.watchedComments.some((c) => c.id === comment.id) ?? false, replies: comment.replies?.map(populateComment), }) const comments = dbComments.map(populateComment) function makeReplySchema(comment: CommentWithRepliesPopulated): Comment { const statusInfo = getCommentStatusInfo(comment.status) return { '@type': 'Comment', text: comment.content, datePublished: comment.createdAt.toISOString(), dateCreated: comment.createdAt.toISOString(), creativeWorkStatus: statusInfo.creativeWorkStatus, author: { '@type': 'Person', name: comment.author.displayName ?? comment.author.name, url: new URL(`/u/${comment.author.name}`, Astro.url).href, image: comment.author.picture ?? undefined, }, interactionStatistic: [ { '@type': 'InteractionCounter', interactionType: { '@type': 'LikeAction' }, userInteractionCount: comment.upvotes, }, { '@type': 'InteractionCounter', interactionType: { '@type': 'ReplyAction' }, userInteractionCount: comment.replies?.length ?? 0, }, ], commentCount: comment.replies?.length ?? 0, comment: comment.replies?.map(makeReplySchema), } satisfies Comment } ---
} />
Newest Most Upvotes { user && (user.admin || user.moderator) && ( Status ) }
{ comments.length > 0 ? ( comments.map((comment) => ( )) ) : (
{pendingCommentsCount > 0 ? ( No approved comments, but there are {pendingCommentsCount.toLocaleString()} unmoderated comments ) : ( 'No comments yet' )}
) }