"use client" import { Button } from "./ui/button" import { VendorDisplayButton } from "./vendor-display-button" import { useAuth } from "./auth-stub" import { formatRelativeTime } from "../utils/date-utils" import { UserSummary } from "./user-summary-stub" interface CommentCardProps { comment: { id: string content: string title?: string type?: 'pro' | 'con' importance?: 'Critical' | 'Important' | 'Nice-to-have' createdAt: string vendor?: { id: number title: string slug: string logo: string | null category?: string | null } user?: { id: string name: string profilePicture: string | null msp?: { id: string | number name?: string | null icon_url?: string | null } } canDelete?: boolean } onViewProduct?: (vendorSlug: string) => void onDeleteComment?: (commentId: string) => void showVendorInfo?: boolean compact?: boolean /** * Which HEADER this tile leads with — the only thing that ever varied by * surface. Two states, because there are two headers: the profile page shows * a person's comments, so it leads with the VENDOR each one is about; * everywhere else the vendor is the page and the commenter is the news. * Every BEHAVIOUR is a prop, so a new surface never needs a new member here. */ leadWith?: 'vendor' | 'commenter' /** * Read the body in FULL (thread reading) instead of the fixed-height, * three-line list tile. Defaults to the list tile. */ fullBody?: boolean /** Rendered under the body — badges + per-surface actions (design-doc threads). */ footer?: React.ReactNode /** Rendered after the card — nested replies + reply composer (design-doc threads). */ children?: React.ReactNode } export function CommentCard({ comment, onViewProduct, onDeleteComment, showVendorInfo = true, compact = false, leadWith = 'commenter', fullBody = false, footer, children }: CommentCardProps) { const { user: currentUser } = useAuth() // Use unified date formatting function const formatActivityTime = (timestamp: string) => { return formatRelativeTime(timestamp); } // Check if current user can delete this comment /** * Deletability is the CALLER's rule, never a per-surface branch in here: an * explicit `comment.canDelete` always wins (design docs compute own-or-DRI * with their gate module and hand it in), and the default is the only rule * this component can honestly know by itself — your own comment. */ const canUserDeleteComment = () => { if (!currentUser) return false if (typeof comment.canDelete === 'boolean') return comment.canDelete return !!comment.user && currentUser.id === comment.user.id } const showDeleteButton = canUserDeleteComment() return ( <>
{/* Comment Header */}
{/* Row 1: Info + Timestamp */}
{leadWith === 'vendor' && comment.vendor ? ( <> {/* Vendor Button - Icon + Name */} {})} /> {/* Timestamp */} {formatActivityTime(comment.createdAt)} ) : comment.user ? ( ) : null}
{/* Row 2: Action Buttons */}
{/* Delete Button - shown when user can delete the comment */} {showDeleteButton && onDeleteComment && ( )}
{/* Comment Content */}
{comment.title && (

{comment.title}

)} {fullBody ? ( // Thread bodies are read in full — no fixed height, no clamp.

{comment.content}

) : (

{comment.content}

)} {footer ?
{footer}
: null}
{children} ) }