'use client'; import { memo, type ReactNode, type RefObject } from 'react'; import { ArrowUpRight, CheckCircle2, Circle, Clock, Download, FileText, Image as ImageIcon, Loader2, MessageSquare, Mic, MoreVertical, Pause, Pencil, Play, Reply, Tag, Trash2, X } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { Textarea } from '@/components/ui/textarea'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { cn } from '@/lib/utils'; import { Linkify } from '@/components/linkify'; import type { Comment, CommentTag, Version } from '@/components/video-page/types'; interface CommentsPaneProps { isMobileCommentsOpen: boolean; setIsMobileCommentsOpen: (open: boolean) => void; isFullscreenMode: boolean; showComments: boolean; comments: Comment[]; filteredComments: Comment[]; sortedComments: Comment[]; showResolved: boolean; handleToggleShowResolved: () => void; activeVersion: Version | undefined; isGuest: boolean; isExportingCsv: boolean; isExportingPdf: boolean; handleExportComments: (format: 'csv' | 'pdf') => void; canResolveComments: boolean; handleResolveComment: (commentId: string, currentlyResolved: boolean) => void; handleSeekToTimestamp: (timestamp: number, annotation?: string | null) => void; currentUserId: string | null; projectOwnerId: string; editingCommentId: string | null; setEditingCommentId: (id: string | null) => void; editText: string; setEditText: (value: string) => void; editTagId: string | null; setEditTagId: (value: string | null) => void; setEditAnnotationData: (value: string | null | undefined) => void; setIsEditingAnnotation: (value: boolean) => void; onStartEditAnnotation: () => void; isSubmittingEdit: boolean; availableTags: CommentTag[]; handleEditComment: (commentId: string) => void; handleDeleteComment: (commentId: string) => void; playVoice: (commentId: string, voiceUrl: string, knownDuration?: number) => void; playingVoiceId: string | null; voiceProgress: number; voiceCurrentTime: number; voicePlaybackRate: number; toggleVoiceSpeed: () => void; formatTime: (seconds: number) => string; setPreviewImage: (url: string | null) => void; replyingTo: string | null; setReplyingTo: (id: string | null) => void; replyText: string; setReplyText: (value: string) => void; handleReplyComment: (parentId: string, voiceData?: { url: string; duration: number }, imageData?: { url: string }) => void; startReplyRecording: () => void; isReplyRecording: boolean; replyRecordingTime: number; stopReplyRecording: () => void; cancelReplyRecording: () => void; replyAudioBlob: Blob | null; replyImageBlob: File | null; setReplyImageBlob: (file: File | null) => void; replyImageInputRef: RefObject; handleImageSelect: (e: React.ChangeEvent, isReply?: boolean) => void; handlePaste: (e: React.ClipboardEvent, isReply?: boolean) => void; submitReplyWithMedia: (parentId: string) => void; isSubmittingReply: boolean; isUploadingReplyAudio: boolean; isUploadingReplyImage: boolean; composer: ReactNode; } export const CommentsPane = memo(function CommentsPane({ isMobileCommentsOpen, setIsMobileCommentsOpen, isFullscreenMode, showComments, comments, filteredComments, sortedComments, showResolved, handleToggleShowResolved, activeVersion, isGuest, isExportingCsv, isExportingPdf, handleExportComments, canResolveComments, handleResolveComment, handleSeekToTimestamp, currentUserId, projectOwnerId, editingCommentId, setEditingCommentId, editText, setEditText, editTagId, setEditTagId, setEditAnnotationData, setIsEditingAnnotation, onStartEditAnnotation, isSubmittingEdit, availableTags, handleEditComment, handleDeleteComment, playVoice, playingVoiceId, voiceProgress, voiceCurrentTime, voicePlaybackRate, toggleVoiceSpeed, formatTime, setPreviewImage, replyingTo, setReplyingTo, replyText, setReplyText, handleReplyComment, startReplyRecording, isReplyRecording, replyRecordingTime, stopReplyRecording, cancelReplyRecording, replyAudioBlob, replyImageBlob, setReplyImageBlob, replyImageInputRef, handleImageSelect, handlePaste, submitReplyWithMedia, isSubmittingReply, isUploadingReplyAudio, isUploadingReplyImage, composer, }: CommentsPaneProps) { return ( <>
setIsMobileCommentsOpen(false)} />
Comments {comments.length}
{filteredComments.length === 0 ? (

No comments yet

Be the first to leave feedback!

) : ( sortedComments.map((comment) => { const authorName = comment.author?.name || comment.guestName || 'Anonymous'; const isEditing = editingCommentId === comment.id; const isReplying = replyingTo === comment.id; const canEditComment = comment.canEdit ?? (comment.author?.id === currentUserId); const canDeleteComment = comment.canDelete ?? (comment.author?.id === currentUserId || projectOwnerId === currentUserId); const canManageComment = canEditComment || canDeleteComment; return (
{authorName.charAt(0)} {authorName}
{canResolveComments && ( )} {canManageComment && ( { setReplyingTo(comment.id); setReplyText(''); }}> Reply {canEditComment && ( { setEditingCommentId(comment.id); setEditText(comment.content || ''); setEditTagId(comment.tag?.id || null); }}> Edit )} {canDeleteComment && ( handleDeleteComment(comment.id)} > Delete )} )}
{isEditing ? (