![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/lavocat.quebec/private_html/src/components/ |
import React, { useState, useEffect, useRef } from 'react';
import { useSession } from 'next-auth/react';
import Link from 'next/link';
import { motion, AnimatePresence, useInView } from 'framer-motion';
import { useRouter } from 'next/router';
import {
Eye, MessageCircle, Users, Clock, DollarSign, Badge, Star,
Heart, Share2, BookOpen, Scale, AlertTriangle, TrendingUp,
Filter, Search, Calendar, MapPin, User, Award, Briefcase,
ExternalLink, Send, ThumbsUp, MessageSquare, UserPlus, CheckCircle,
Zap, Sparkles, Diamond, Crown, Brain,
ArrowRight, ArrowUpRight, Target, Globe, Shield, X as XIcon,
FileText
} from 'lucide-react';
import toast from 'react-hot-toast';
import LawyerRatingStars from './LawyerRatingStars';
import { CompetitionCountdown } from './CompetitionCountdown';
import EnhancedShareButton from './EnhancedShareButton';
import OpenGraphMeta from './OpenGraphMeta';
interface LiveCase {
id: string;
title: string;
description: string;
publicSummary?: string;
category: string;
legalArea: string;
urgencyLevel: 'URGENT' | 'HIGH' | 'NORMAL' | 'LOW';
status: string;
jurisdiction: string;
court?: string;
viewCount: number;
supporterCount: number;
estimatedValue?: number;
riskLevel: 'HIGH' | 'MEDIUM' | 'LOW';
tags?: string[];
createdAt: string;
updatedAt: string;
competitionDeadline?: string;
minimumBid?: number;
currentHighestBid?: number;
totalBidders?: number;
averageBidAmount?: number;
competitionType?: 'AUCTION' | 'TENDER' | 'NEGOTIATION';
isPublic: boolean;
logoUrl?: string;
leadLawyer: {
id: string;
name: string;
username?: string;
profilePicture?: string;
specialization?: string;
averageRating?: number;
totalCases: number;
wonCases: number;
proBono: boolean;
hourlyRate?: number;
isVerified: boolean;
successRate?: number;
totalEarnings?: number;
responseTime?: number;
clientSatisfaction?: number;
};
creator: {
id: string;
name: string;
username?: string;
};
_count: {
offers: number;
registrations: number;
supporters: number;
views: number;
comments: number;
lawyerRequests: number;
};
comments?: CaseComment[];
lawyerRequests?: LawyerRequest[];
}
interface CaseComment {
id: string;
content: string;
createdAt: string;
user: {
id: string;
name: string;
profilePicture?: string;
role: string;
};
likes: number;
replies?: CaseComment[];
}
interface LawyerRequest {
id: string;
lawyerId: string;
message: string;
proposedRate?: number;
estimatedHours?: number;
reasoning: string;
status: 'PENDING' | 'APPROVED' | 'REJECTED';
createdAt: string;
lawyer: {
id: string;
name: string;
profilePicture?: string;
specialization?: string;
averageRating?: number;
proBono: boolean;
isVerified: boolean;
successRate?: number;
totalCases: number;
wonCases: number;
};
}
const LiveCaseFeed: React.FC = () => {
const { data: session } = useSession();
const router = useRouter();
const [cases, setCases] = useState<LiveCase[]>([]);
const [loading, setLoading] = useState(true);
const [filter, setFilter] = useState('all');
const [sortBy, setSortBy] = useState('newest');
const [searchTerm, setSearchTerm] = useState('');
const [selectedCase, setSelectedCase] = useState<LiveCase | null>(null);
const [showRequestModal, setShowRequestModal] = useState(false);
const [showCommentsModal, setShowCommentsModal] = useState(false);
const [newComment, setNewComment] = useState('');
const [requestData, setRequestData] = useState({
message: '',
proposedRate: '',
estimatedHours: '',
reasoning: ''
});
useEffect(() => {
fetchLiveCases();
}, [filter, sortBy, searchTerm]);
const fetchLiveCases = async () => {
try {
setLoading(true);
const params = new URLSearchParams({
filter,
sortBy,
search: searchTerm
});
const response = await fetch(
if (response.ok) {
const data = await response.json();
setCases(Array.isArray(data.cases) ? data.cases : []);
} else {
toast.error('Failed to load cases');
setCases([]);
}
} catch (error) {
toast.error('Error loading cases');
setCases([]);
} finally {
setLoading(false);
}
};
const handleViewCase = async (caseId: string) => {
await fetch(`/api/live-cases/${caseId}/view
setCases(prev => prev.map(c =>
c.id === caseId ? { ...c, viewCount: c.viewCount + 1 } : c
));
};
const handleSupportCase = async (caseId: string) => {
if (!session) {
toast.error('Please login to support cases');
return;
}
try {
const response = await fetch(`/api/live-cases/${caseId}/support
method: 'POST'
});
if (response.ok) {
setCases(prev => prev.map(c =>
c.id === caseId ? { ...c, supporterCount: c.supporterCount + 1 } : c
));
toast.success('Case supported! 💪');
}
} catch (error) {
toast.error('Failed to support case');
}
};
const handleRequestCase = async (caseId: string) => {
if (!session || session.user.role !== 'LAWYER') {
toast.error('Only verified lawyers can request cases');
return;
}
const selectedCaseData = cases.find(c => c.id === caseId);
setSelectedCase(selectedCaseData || null);
setShowRequestModal(true);
};
const submitRequest = async () => {
if (!selectedCase || !requestData.message || !requestData.reasoning) {
toast.error('Please fill in all required fields');
return;
}
try {
const response = await fetch(`/api/live-cases/${selectedCase.id}/request
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
message: requestData.message,
proposedRate: requestData.proposedRate ? parseFloat(requestData.proposedRate) : undefined,
estimatedHours: requestData.estimatedHours ? parseInt(requestData.estimatedHours) : undefined,
reasoning: requestData.reasoning
}),
});
if (response.ok) {
toast.success('Request sent successfully! 🎉');
setShowRequestModal(false);
setRequestData({ message: '', proposedRate: '', estimatedHours: '', reasoning: '' });
} else {
toast.error('Failed to send request');
}
} catch (error) {
toast.error('Error sending request');
}
};
const handleAddComment = async (caseId: string) => {
if (!newComment.trim()) {
toast.error('Please enter a comment');
return;
}
try {
const response = await fetch(`/api/live-cases/${caseId}/comments
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ content: newComment }),
});
if (response.ok) {
setNewComment('');
toast.success('Comment added! 💬');
// Refresh comments
fetchLiveCases();
} else {
toast.error('Failed to add comment');
}
} catch (error) {
toast.error('Error adding comment');
}
};
const handleLikeComment = async (caseId: string, commentId: string) => {
try {
const response = await fetch(`/api/live-cases/${caseId}/comments/${commentId}/like
method: 'POST',
});
if (response.ok) {
toast.success('Comment liked! 👍');
// Refresh comments
fetchLiveCases();
}
} catch (error) {
toast.error('Error liking comment');
}
};
const getUrgencyColor = (urgency: string) => {
switch (urgency) {
case 'URGENT':
return 'bg-red-500/20 text-red-300 border-red-500/30';
case 'HIGH':
return 'bg-orange-500/20 text-orange-300 border-orange-500/30';
case 'NORMAL':
return 'bg-blue-500/20 text-blue-300 border-blue-500/30';
case 'LOW':
return 'bg-green-500/20 text-green-300 border-green-500/30';
default:
return 'bg-gray-500/20 text-gray-300 border-gray-500/30';
}
};
const getRiskColor = (risk: string) => {
switch (risk) {
case 'HIGH':
return 'bg-red-500/20 text-red-300 border-red-500/30';
case 'MEDIUM':
return 'bg-yellow-500/20 text-yellow-300 border-yellow-500/30';
case 'LOW':
return 'bg-green-500/20 text-green-300 border-green-500/30';
default:
return 'bg-gray-500/20 text-gray-300 border-gray-500/30';
}
};
const getCompetitionStatus = (case_: LiveCase) => {
if (!case_.competitionDeadline) return null;
const deadline = new Date(case_.competitionDeadline);
const now = new Date();
const diff = deadline.getTime() - now.getTime();
const hoursLeft = diff / (1000 * 60 * 60);
if (hoursLeft < 0) return 'ENDED';
if (hoursLeft < 24) return 'ENDING_SOON';
return 'LIVE';
};
const getCompetitionBadge = (case_: LiveCase) => {
const status = getCompetitionStatus(case_);
if (!status) return null;
const badges = {
LIVE: { text: '🔥 Live', color: 'bg-green-500/20 text-green-300 border-green-500/30' },
ENDING_SOON: { text: '⏰ Ending Soon', color: 'bg-orange-500/20 text-orange-300 border-orange-500/30' },
ENDED: { text: '🏁 Ended', color: 'bg-gray-500/20 text-gray-300 border-gray-500/30' }
};
return badges[status];
};
// Enhanced Case Card Component
const CaseCard = ({ case_: caseData, index }: { case_: LiveCase; index: number }) => {
const cardRef = useRef<HTMLDivElement>(null);
const isInView = useInView(cardRef, { once: true, margin: "-50px" });
const competitionBadge = getCompetitionBadge(caseData);
return (
<motion.div
ref={cardRef}
key={caseData.id}
className="relative group overflow-hidden"
initial={{ opacity: 0, y: 50, scale: 0.9 }}
animate={isInView ? { opacity: 1, y: 0, scale: 1 } : {}}
transition={{ duration: 0.6, delay: index * 0.1 }}
whileHover={{
scale: 1.02,
y: -5,
transition: { duration: 0.3 }
}}
>
{/* Glassmorphism Card Background */}
<div className="bg-white rounded-3xl border border-gray-200 shadow-md overflow-hidden">
{/* Animated gradient overlay */}
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-white/5 to-transparent -translate-x-full group-hover:translate-x-full transition-transform duration-1000 ease-out"></div>
{/* Floating particles */}
<div className="absolute top-4 right-4 opacity-20 group-hover:opacity-40 transition-opacity">
<Sparkles className="h-5 w-5 text-gray-400 animate-pulse" />
</div>
<div className="relative p-8">
<div className="flex items-start gap-6">
{/* Case Logo */}
<div className="flex-shrink-0">
<div className="relative">
{caseData.logoUrl ? (
<img
src={caseData.logoUrl}
alt={`${caseData.title} Logo
className="w-16 h-16 rounded-2xl object-cover border-2 border-gray-200 shadow-sm"
/>
) : (
<div className="w-16 h-16 rounded-2xl bg-gradient-to-br from-blue-500/20 to-indigo-500/20 border-2 border-gray-200 flex items-center justify-center">
<FileText className="w-8 h-8 text-gray-600" />
</div>
)}
</div>
</div>
{/* Enhanced Avatar */}
<div className="flex-shrink-0">
<div className="relative">
{caseData.leadLawyer.profilePicture ? (
<img
src={caseData.leadLawyer.profilePicture}
alt={caseData.leadLawyer.name}
className="w-16 h-16 rounded-2xl object-cover border-2 border-gray-200"
/>
) : (
<div className="w-16 h-16 rounded-2xl bg-gradient-to-br from-purple-500/20 to-pink-500/20 border-2 border-gray-200 flex items-center justify-center">
<User className="w-8 h-8 text-gray-600" />
</div>
)}
{caseData.leadLawyer.isVerified && (
<div className="absolute -top-1 -right-1 p-1 bg-blue-500 rounded-full">
<CheckCircle className="w-4 h-4 text-white" />
</div>
)}
</div>
</div>
{/* Content */}
<div className="flex-1 min-w-0">
<div className="flex items-start justify-between mb-4">
<div className="flex-1">
<div className="flex items-center gap-3 mb-3">
<h3 className="text-xl font-bold text-gray-900 group-hover:text-blue-600 transition-colors">
{caseData.title}
</h3>
{competitionBadge && (
<span className={`px-3 py-1 text-xs rounded-full border ${competitionBadge.color}
{competitionBadge.text}
</span>
)}
</div>
<div className="flex items-center gap-3 mb-4 flex-wrap">
<span className="text-sm text-gray-700 bg-blue-100 px-3 py-1 rounded-full">
{caseData.legalArea}
</span>
<span className={`px-3 py-1 text-xs rounded-full border ${getUrgencyColor(caseData.urgencyLevel)}
{caseData.urgencyLevel}
</span>
<span className={`px-3 py-1 text-xs rounded-full border ${getRiskColor(caseData.riskLevel)}
{caseData.riskLevel} Risk
</span>
{caseData.estimatedValue && (
<span className="text-sm text-green-300 bg-green-100 px-3 py-1 rounded-full">
${caseData.estimatedValue.toLocaleString()}
</span>
)}
</div>
</div>
<div className="text-right text-sm text-gray-600">
<div className="flex items-center gap-1 mb-1">
<Calendar className="w-4 h-4" />
{new Date(caseData.createdAt).toLocaleDateString()}
</div>
<div className="text-xs bg-gray-100 px-2 py-1 rounded-full">
{caseData.status}
</div>
</div>
</div>
<p className="text-gray-800 mb-6 leading-relaxed">
{(caseData.publicSummary || caseData.description).length > 200
? (caseData.publicSummary || caseData.description).substring(0, 200) + '...'
: (caseData.publicSummary || caseData.description)
}
</p>
{/* Enhanced Stats */}
<div className="flex items-center gap-6 text-sm text-gray-600 mb-6">
<div className="flex items-center gap-2 bg-gray-100 px-3 py-2 rounded-full">
<Eye className="w-4 h-4" />
<span className="font-medium">{caseData.viewCount}</span>
</div>
<div className="flex items-center gap-2 bg-gray-100 px-3 py-2 rounded-full">
<Users className="w-4 h-4" />
<span className="font-medium">{caseData.supporterCount}</span>
</div>
<div className="flex items-center gap-2 bg-gray-100 px-3 py-2 rounded-full">
<MessageCircle className="w-4 h-4" />
<span className="font-medium">{caseData._count.comments || 0}</span>
</div>
<div className="flex items-center gap-2 bg-gray-100 px-3 py-2 rounded-full">
<UserPlus className="w-4 h-4" />
<span className="font-medium">{caseData._count.registrations || 0}</span>
</div>
</div>
{/* Enhanced Actions */}
<div className="flex gap-3 flex-wrap">
<button
onClick={() => router.push(`/public/cases/${caseData.id}
className="px-5 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors font-medium flex items-center gap-2"
>
<Eye className="w-4 h-4 group-hover/btn:scale-110 transition-transform" />
View Details
</button>
{session?.user?.role === 'LAWYER' ? (
<button
onClick={() => handleRequestCase(caseData.id)}
className="px-5 py-2 bg-blue-100 text-blue-700 rounded-md hover:bg-blue-200 transition-colors font-medium flex items-center gap-2"
>
<Target className="w-4 h-4" />
Request
</button>
) : session?.user && (
<button
onClick={() => router.push(`/user/registrations/new?caseId=${caseData.id}
className="px-5 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors font-medium flex items-center gap-2"
>
<ArrowRight className="w-4 h-4" />
Apply
</button>
)}
<button
onClick={() => handleSupportCase(caseData.id)}
className="px-5 py-2 border border-gray-300 text-blue-700 rounded-md hover:bg-gray-50 transition-colors font-medium flex items-center gap-2"
>
<Heart className="w-4 h-4" />
Support
</button>
<EnhancedShareButton
url={`${typeof window !== 'undefined' ? window.location.origin : ''}/public/cases/${caseData.id}
title={caseData.title}
description={caseData.publicSummary || caseData.description}
hashtags={caseData.tags || ['legal', 'case', caseData.legalArea.toLowerCase()]}
variant="minimal"
className="px-5 py-2 border border-gray-300 text-gray-700 rounded-md hover:bg-gray-50 transition-colors font-medium flex items-center gap-2 z-50"
/>
</div>
</div>
</div>
</div>
</div>
</motion.div>
);
};
if (loading) {
return (
<div className="flex justify-center items-center py-12">
<div className="relative">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
</div>
</div>
);
}
return (
<div className="space-y-6">
{/* Filter/Search Bar - dashboard style */}
<div className="bg-white rounded-lg shadow-sm border p-4 flex flex-col md:flex-row md:items-center gap-4 mb-2">
<div className="flex-1">
<div className="relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-5 w-5" />
<input
type="text"
placeholder="Search cases by title, description, or legal area..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent text-gray-900 placeholder-gray-400 bg-white"
/>
</div>
</div>
<div className="flex gap-2">
<select
value={filter}
onChange={(e) => setFilter(e.target.value)}
className="px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent text-gray-900 bg-white"
>
<option value="all">All Cases</option>
<option value="urgent">Urgent</option>
<option value="criminal">Criminal</option>
<option value="civil">Civil</option>
<option value="human_rights">Human Rights</option>
<option value="immigration">Immigration</option>
<option value="family">Family</option>
<option value="corporate">Corporate</option>
</select>
<select
value={sortBy}
onChange={(e) => setSortBy(e.target.value)}
className="px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent text-gray-900 bg-white"
>
<option value="newest">Newest</option>
<option value="urgent">Most Urgent</option>
<option value="popular">Most Popular</option>
<option value="deadline">Deadline</option>
</select>
</div>
</div>
{/* Cases List */}
<div className="space-y-4">
{cases.length === 0 ? (
<div className="text-center py-16">
<div className="bg-white rounded-lg border shadow-sm p-12">
<BookOpen className="w-16 h-16 text-gray-200 mx-auto mb-6" />
<h3 className="text-2xl font-bold text-gray-900 mb-4">No Cases Found</h3>
<p className="text-gray-500 text-lg mb-8">
Try adjusting your filters or search terms to find more cases.
</p>
<button
onClick={() => {
setFilter('all');
setSearchTerm('');
setSortBy('newest');
}}
className="px-8 py-4 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-all duration-300 font-medium"
>
Reset Filters
</button>
</div>
</div>
) : (
cases.map((case_, index) => (
<CaseCard key={case_.id} case_={case_} index={index} />
))
)}
</div>
{/* Enhanced Lawyer Request Modal */}
<AnimatePresence>
{showRequestModal && selectedCase && (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm">
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
className="bg-white/10 backdrop-blur-xl rounded-3xl border border-white/20 shadow-2xl max-w-2xl w-full mx-4 max-h-[90vh] overflow-y-auto"
>
<div className="p-8">
<div className="flex items-center justify-between mb-6">
<h3 className="text-2xl font-bold text-white">Request to Represent</h3>
<button
onClick={() => setShowRequestModal(false)}
className="text-white/50 hover:text-white transition-colors p-2 hover:bg-white/10 rounded-full"
>
<XIcon className="w-6 h-6" />
</button>
</div>
<div className="mb-6 p-4 bg-white/10 rounded-2xl border border-white/20">
<h4 className="font-bold text-lg text-white mb-2">{selectedCase.title}</h4>
<p className="text-white/70">{selectedCase.legalArea}</p>
</div>
<div className="space-y-6">
<div>
<label className="block text-sm font-medium text-white/80 mb-2">
Message to Client *
</label>
<textarea
value={requestData.message}
onChange={(e) => setRequestData({...requestData, message: e.target.value})}
placeholder="Introduce yourself and explain your interest in this case..."
className="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-2xl focus:ring-2 focus:ring-purple-500 focus:border-transparent text-white placeholder-white/50 backdrop-blur-sm"
rows={3}
/>
</div>
<div>
<label className="block text-sm font-medium text-white/80 mb-2">
Why You're the Best Fit *
</label>
<textarea
value={requestData.reasoning}
onChange={(e) => setRequestData({...requestData, reasoning: e.target.value})}
placeholder="Explain your experience, expertise, and why you're uniquely qualified..."
className="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-2xl focus:ring-2 focus:ring-purple-500 focus:border-transparent text-white placeholder-white/50 backdrop-blur-sm"
rows={3}
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-white/80 mb-2">
Proposed Rate (CAD/hr)
</label>
<input
type="number"
value={requestData.proposedRate}
onChange={(e) => setRequestData({...requestData, proposedRate: e.target.value})}
placeholder="200"
className="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-2xl focus:ring-2 focus:ring-purple-500 focus:border-transparent text-white placeholder-white/50 backdrop-blur-sm"
/>
</div>
<div>
<label className="block text-sm font-medium text-white/80 mb-2">
Est. Hours
</label>
<input
type="number"
value={requestData.estimatedHours}
onChange={(e) => setRequestData({...requestData, estimatedHours: e.target.value})}
placeholder="40"
className="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-2xl focus:ring-2 focus:ring-purple-500 focus:border-transparent text-white placeholder-white/50 backdrop-blur-sm"
/>
</div>
</div>
</div>
<div className="flex gap-4 mt-8">
<button
onClick={() => setShowRequestModal(false)}
className="flex-1 px-6 py-4 border border-white/20 text-white/80 rounded-2xl hover:bg-white/10 transition-all duration-300 font-medium"
>
Cancel
</button>
<button
onClick={submitRequest}
className="flex-1 bg-gradient-to-r from-purple-500 to-pink-600 text-white px-6 py-4 rounded-2xl hover:from-purple-600 hover:to-pink-700 transition-all duration-300 font-medium"
>
Send Request
</button>
</div>
</div>
</motion.div>
</div>
)}
</AnimatePresence>
{/* Enhanced Comments Modal */}
<AnimatePresence>
{showCommentsModal && selectedCase && (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm">
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
className="bg-white/10 backdrop-blur-xl rounded-3xl border border-white/20 shadow-2xl max-w-4xl w-full mx-4 max-h-[90vh] overflow-y-auto"
>
<div className="p-8">
<div className="flex items-center justify-between mb-6">
<h3 className="text-2xl font-bold text-white">Comments & Discussion</h3>
<button
onClick={() => setShowCommentsModal(false)}
className="text-white/50 hover:text-white transition-colors p-2 hover:bg-white/10 rounded-full"
>
<XIcon className="w-6 h-6" />
</button>
</div>
<div className="mb-6 p-4 bg-white/10 rounded-2xl border border-white/20">
<h4 className="font-bold text-lg text-white mb-2">{selectedCase.title}</h4>
<p className="text-white/70">{selectedCase.legalArea}</p>
</div>
{/* Comments List */}
<div className="space-y-6 mb-8">
{selectedCase.comments?.map((comment) => (
<div key={comment.id} className="border-b border-white/10 pb-6">
<div className="flex items-start gap-4">
<div className="w-10 h-10 rounded-full bg-gradient-to-br from-purple-500/20 to-pink-500/20 border border-white/20 flex items-center justify-center">
<User className="w-5 h-5 text-white/70" />
</div>
<div className="flex-1">
<div className="flex items-center gap-3 mb-2">
<span className="font-medium text-white">{comment.user.name}</span>
<span className="text-xs text-white/50 bg-white/10 px-2 py-1 rounded-full">{comment.user.role}</span>
<span className="text-xs text-white/40">
{new Date(comment.createdAt).toLocaleDateString()}
</span>
</div>
<p className="text-white/80 mb-3 leading-relaxed">{comment.content}</p>
<div className="flex items-center gap-4">
<button
onClick={() => handleLikeComment(selectedCase.id, comment.id)}
className="flex items-center gap-2 text-xs text-white/50 hover:text-purple-300 transition-colors"
>
<ThumbsUp className="w-3 h-3" />
{comment.likes}
</button>
<button className="text-xs text-white/50 hover:text-purple-300 transition-colors">
Reply
</button>
</div>
</div>
</div>
</div>
))}
</div>
{/* Add Comment */}
<div className="space-y-4">
<textarea
value={newComment}
onChange={(e) => setNewComment(e.target.value)}
placeholder="Add a comment..."
className="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-2xl focus:ring-2 focus:ring-purple-500 focus:border-transparent text-white placeholder-white/50 backdrop-blur-sm"
rows={3}
/>
<div className="flex justify-end">
<button
onClick={() => handleAddComment(selectedCase.id)}
className="px-6 py-3 bg-gradient-to-r from-purple-500 to-pink-600 text-white rounded-2xl hover:from-purple-600 hover:to-pink-700 transition-all duration-300 font-medium"
>
Add Comment
</button>
</div>
</div>
</div>
</motion.div>
</div>
)}
</AnimatePresence>
</div>
);
};
export default LiveCaseFeed;