import React, { useState, useEffect, useRef } from 'react'; import { Textarea } from '@/components/ui/textarea'; import { Card, CardContent, CardHeader } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { MessageSquare, X } from 'lucide-react'; interface Comment { id: string; lineNumber: number | null; lineRange?: string; author: string; authorId?: string; content: string; timestamp: Date; } interface User { id: string; name: string; color: string; lastSeen: Date; isTyping?: boolean; currentLine?: number; } interface CommentsPageProps { isVisible: boolean; onToggle: () => void; selectedLineStart?: number; selectedLineEnd?: number; onCommentSelect?: (lineNumber: number, lineRange?: string) => void; comments?: Comment[]; onAddComment?: (content: string, lineNumber?: number, lineRange?: string) => void; onDeleteComment?: (commentId: string) => void; currentUser?: User | null; } export const CommentsPanel: React.FC = ({ isVisible, selectedLineStart, selectedLineEnd, onCommentSelect, comments = [], onAddComment, onDeleteComment, currentUser }) => { const [newComment, setNewComment] = useState(''); const [selectedLine, setSelectedLine] = useState(null); const [scrollState, setScrollState] = useState({ top: false, bottom: false }); const commentsScrollRef = useRef(null); // Update selected line when editor selection changes useEffect(() => { if (selectedLineStart && selectedLineEnd) { if (selectedLineStart === selectedLineEnd) { setSelectedLine(selectedLineStart); } else { setSelectedLine(selectedLineStart); // Use start line for range selections } } else { setSelectedLine(null); } }, [selectedLineStart, selectedLineEnd]); // Scroll detection function const handleScroll = () => { const element = commentsScrollRef.current; if (!element) return; const { scrollTop, scrollHeight, clientHeight } = element; const isScrolledFromTop = scrollTop > 5; const isScrolledFromBottom = scrollTop < scrollHeight - clientHeight - 5; setScrollState({ top: isScrolledFromTop, bottom: isScrolledFromBottom && scrollHeight > clientHeight }); }; // Add scroll listener useEffect(() => { const element = commentsScrollRef.current; if (element) { element.addEventListener('scroll', handleScroll); // Initial check handleScroll(); return () => { element.removeEventListener('scroll', handleScroll); }; } }, [comments]); const handleAddComment = () => { if (newComment.trim() && onAddComment && currentUser) { const lineRange = selectedLineStart && selectedLineEnd && selectedLineStart !== selectedLineEnd ? `${selectedLineStart}-${selectedLineEnd}` : undefined; onAddComment(newComment.trim(), selectedLine || undefined, lineRange); setNewComment(''); } }; const formatTime = (date: Date) => { return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); }; return (
{/* Comments List */}
{comments.length === 0 ? (

No comments yet

Add a comment to get started

) : ( comments .sort((a, b) => { // Comments with line numbers come first, sorted by line number // Comments without line numbers come last if (a.lineNumber === null && b.lineNumber === null) return 0; if (a.lineNumber === null) return 1; if (b.lineNumber === null) return -1; return a.lineNumber - b.lineNumber; }) .map((comment) => ( { if (comment.lineNumber && onCommentSelect) { onCommentSelect(comment.lineNumber, comment.lineRange); } }} >
{comment.author} {comment.lineNumber !== null && ( {comment.lineRange || `Line ${comment.lineNumber}`} )}
{formatTime(comment.timestamp)} {currentUser && onDeleteComment && ( )}

{comment.content}

)) )}
{/* Add Comment Form */}