import React, { useState, useEffect, useCallback } from 'react'; import { Card, CardContent, CardHeader } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Textarea } from '@/components/ui/textarea'; import { Badge } from '@/components/ui/badge'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { ThumbsUp, ThumbsDown, MessageSquare, Shield, Award, TrendingUp, AlertTriangle, MoreVertical, Flag, Edit, Trash2, Loader2 } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'; import { useWebSocket } from '@/contexts/WebSocketContext'; import { useToast } from '@/hooks/use-toast'; interface Comment { id: string; author: string; avatar: string; content: string; timestamp: string; upvotes: number; downvotes: number; isExpert: boolean; badges: string[]; replies: Comment[]; sentiment: 'positive' | 'neutral' | 'negative'; userVote?: 'up' | 'down' | null; isLive?: boolean; } export function DiscussionThread({ proposalId }: { proposalId: string }) { const { t } = useTranslation(); const { toast } = useToast(); const { subscribe, unsubscribe, sendMessage, isConnected } = useWebSocket(); const [isLoading, setIsLoading] = useState(false); const [comments, setComments] = useState([ { id: '1', author: 'Dr. Rojin Ahmed', avatar: '/api/placeholder/40/40', content: '## Strong Support for This Proposal\n\nThis proposal addresses a critical need in our governance system. The implementation timeline is realistic and the budget allocation seems appropriate.\n\n**Key Benefits:**\n- Improved transparency\n- Better community engagement\n- Clear accountability metrics\n\nI particularly appreciate the phased approach outlined in section 3.', timestamp: '2 hours ago', upvotes: 24, downvotes: 2, isExpert: true, badges: ['Governance Expert', 'Top Contributor'], sentiment: 'positive', userVote: null, replies: [ { id: '1-1', author: 'Kawa Mustafa', avatar: '/api/placeholder/40/40', content: 'Agreed! The phased approach reduces risk significantly.', timestamp: '1 hour ago', upvotes: 8, downvotes: 0, isExpert: false, badges: ['Active Member'], sentiment: 'positive', userVote: null, replies: [] } ] }, { id: '2', author: 'Dilan Karim', avatar: '/api/placeholder/40/40', content: '### Concerns About Implementation\n\nWhile I support the overall direction, I have concerns about:\n\n1. The technical complexity might be underestimated\n2. We need more details on the security audit process\n3. Reference to [Proposal #142](/proposals/142) shows similar challenges\n\n> "The devil is in the details" - and we need more of them', timestamp: '3 hours ago', upvotes: 18, downvotes: 5, isExpert: true, badges: ['Security Expert'], sentiment: 'negative', userVote: null, replies: [] } ]); const [newComment, setNewComment] = useState(''); const [replyTo, setReplyTo] = useState(null); const [showMarkdownHelp, setShowMarkdownHelp] = useState(false); // WebSocket subscriptions for real-time updates useEffect(() => { const handleNewComment = (data: any) => { const newComment: Comment = { ...data, isLive: true, }; setComments(prev => [newComment, ...prev]); // Show notification for mentions if (data.content.includes('@currentUser')) { toast({ title: "You were mentioned", description: `${data.author} mentioned you in a comment`, }); } }; const handleVoteUpdate = (data: { commentId: string; upvotes: number; downvotes: number }) => { setComments(prev => updateVoteCounts(prev, data.commentId, data.upvotes, data.downvotes)); }; const handleSentimentUpdate = (data: { proposalId: string; sentiment: any }) => { if (data.proposalId === proposalId) { // Update sentiment visualization in parent component console.log('Sentiment updated:', data.sentiment); } }; subscribe('comment', handleNewComment); subscribe('vote', handleVoteUpdate); subscribe('sentiment', handleSentimentUpdate); return () => { unsubscribe('comment', handleNewComment); unsubscribe('vote', handleVoteUpdate); unsubscribe('sentiment', handleSentimentUpdate); }; }, [subscribe, unsubscribe, proposalId, toast]); const updateVoteCounts = (comments: Comment[], targetId: string, upvotes: number, downvotes: number): Comment[] => { return comments.map(comment => { if (comment.id === targetId) { return { ...comment, upvotes, downvotes }; } if (comment.replies.length > 0) { return { ...comment, replies: updateVoteCounts(comment.replies, targetId, upvotes, downvotes) }; } return comment; }); }; const handleVote = useCallback((commentId: string, voteType: 'up' | 'down') => { const updatedComments = updateCommentVote(comments, commentId, voteType); setComments(updatedComments); // Send vote update via WebSocket const comment = findComment(updatedComments, commentId); if (comment && isConnected) { sendMessage({ type: 'vote', data: { commentId, upvotes: comment.upvotes, downvotes: comment.downvotes, proposalId, }, timestamp: Date.now(), }); } }, [comments, isConnected, sendMessage, proposalId]); const findComment = (comments: Comment[], targetId: string): Comment | null => { for (const comment of comments) { if (comment.id === targetId) return comment; const found = findComment(comment.replies, targetId); if (found) return found; } return null; }; const updateCommentVote = (comments: Comment[], targetId: string, voteType: 'up' | 'down'): Comment[] => { return comments.map(comment => { if (comment.id === targetId) { const wasUpvoted = comment.userVote === 'up'; const wasDownvoted = comment.userVote === 'down'; if (voteType === 'up') { return { ...comment, upvotes: wasUpvoted ? comment.upvotes - 1 : comment.upvotes + 1, downvotes: wasDownvoted ? comment.downvotes - 1 : comment.downvotes, userVote: wasUpvoted ? null : 'up' }; } else { return { ...comment, upvotes: wasUpvoted ? comment.upvotes - 1 : comment.upvotes, downvotes: wasDownvoted ? comment.downvotes - 1 : comment.downvotes + 1, userVote: wasDownvoted ? null : 'down' }; } } if (comment.replies.length > 0) { return { ...comment, replies: updateCommentVote(comment.replies, targetId, voteType) }; } return comment; }); }; const renderComment = (comment: Comment, depth: number = 0) => (
0 ? 'ml-12 mt-4' : 'mb-6'} ${comment.isLive ? 'animate-pulse-once' : ''}`}>
{comment.author[0]} {comment.isLive && (
)}
{comment.author} {comment.isExpert && ( )} {comment.badges.map(badge => ( {badge} ))} {comment.isLive ? 'Just now' : comment.timestamp} {isConnected && (
)}
Report Edit Delete
{replyTo === comment.id && (