T.ME/BIBIL_0DAY
CasperSecurity


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.ca/private_html/src/components/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/lavocat.ca/private_html/src/components/PublicCaseFeed.tsx
import React, { useState, useEffect } from 'react';
import { useSession } from 'next-auth/react';
import Link from 'next/link';
import { motion, AnimatePresence } from 'framer-motion';
import { 
  Eye, MessageCircle, Users, Clock, DollarSign, Badge, Star, 
  Heart, Share2, BookOpen, Scale, AlertTriangle, TrendingUp,
  Filter, Search, Calendar, MapPin, User, Award, Briefcase,
  ExternalLink, FileText
} from 'lucide-react';
import toast from 'react-hot-toast';
import LawyerRatingStars from './LawyerRatingStars';
import { CompetitionCountdown } from './CompetitionCountdown';

interface PublicCase {
  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';
  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;
  };
}

interface LawyerOffer {
  id: string;
  lawyerId: string;
  message?: string;
  proposedRate?: number;
  estimatedHours?: number;
  createdAt: string;
  lawyer: {
    id: string;
    name: string;
    profilePicture?: string;
    specialization?: string;
    averageRating?: number;
    proBono: boolean;
    isVerified: boolean;
  };
}

const PublicCaseFeed: React.FC = () => {
  const { data: session } = useSession();
  const [cases, setCases] = useState<PublicCase[]>([]);
  const [loading, setLoading] = useState(true);
  const [filter, setFilter] = useState('all');
  const [sortBy, setSortBy] = useState('newest');
  const [searchTerm, setSearchTerm] = useState('');
  const [selectedCase, setSelectedCase] = useState<PublicCase | null>(null);
  const [offers, setOffers] = useState<LawyerOffer[]>([]);
  const [showOfferModal, setShowOfferModal] = useState(false);
  const [showCompetitionModal, setShowCompetitionModal] = useState(false);
  const [competitionData, setCompetitionData] = useState<any>(null);
  const [realTimeUpdates, setRealTimeUpdates] = useState(false);
  const [showBidHistoryModal, setShowBidHistoryModal] = useState(false);
  const [bidHistory, setBidHistory] = useState<any[]>([]);
  const [showParticipantsModal, setShowParticipantsModal] = useState(false);
  const [participants, setParticipants] = useState<any[]>([]);

  useEffect(() => {
    fetchPublicCases();
  }, [filter, sortBy]);

  const fetchPublicCases = async () => {
    try {
      setLoading(true);
      const params = new URLSearchParams({
        filter,
        sortBy,
        search: searchTerm
      });
      
      const response = await fetch(`/api/public/cases?${params}`);
      if (response.ok) {
        const data = await response.json();
        // Ensure cases is an array with defensive programming
        setCases(Array.isArray(data.cases) ? data.cases : []);
      } else {
        console.error('Failed to load cases:', response.status, response.statusText);
        toast.error('Failed to load cases');
        setCases([]); // Set empty array on error
      }
    } catch (error) {
      console.error('Error fetching cases:', error);
      toast.error('Error loading cases');
      setCases([]); // Set empty array on error
    } finally {
      setLoading(false);
    }
  };

  const handleViewCase = async (caseId: string) => {
    // Update view count
    await fetch(`/api/public/cases/${caseId}/view`, { method: 'POST' });
    // Find and update local state
    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/public/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 handleOfferToRepresent = async (caseId: string) => {
    if (!session || session.user.role !== 'LAWYER') {
      toast.error('Only verified lawyers can offer representation');
      return;
    }

    const selectedCaseData = cases.find(c => c.id === caseId);
    setSelectedCase(selectedCaseData || null);
    setShowOfferModal(true);
  };

  const submitOffer = async (offerData: {
    message: string;
    proposedRate?: number;
    estimatedHours?: number;
  }) => {
    if (!selectedCase) return;

    try {
      const response = await fetch(`/api/cases/${selectedCase.id}/offers`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(offerData)
      });

      if (response.ok) {
        toast.success('Offer submitted successfully! ๐ŸŽฏ');
        setShowOfferModal(false);
        // Update offer count
        setCases(prev => prev.map(c => 
          c.id === selectedCase.id 
            ? { ...c, _count: { ...c._count, offers: c._count.offers + 1 } } 
            : c
        ));
      } else {
        toast.error('Failed to submit offer');
      }
    } catch (error) {
      toast.error('Error submitting offer');
    }
  };

  const handleJoinCompetition = async (caseId: string) => {
    if (!session || session.user.role !== 'LAWYER') {
      toast.error('Only verified lawyers can join competitions');
      return;
    }

    try {
      const response = await fetch(`/api/public/cases/${caseId}/competition/join`, {
        method: 'POST'
      });
      
      if (response.ok) {
        toast.success('Successfully joined competition! ๐Ÿ†');
        fetchPublicCases(); // Refresh data
      } else {
        toast.error('Failed to join competition');
      }
    } catch (error) {
      toast.error('Error joining competition');
    }
  };

  const handlePlaceBid = async (caseId: string, bidAmount: number, message: string) => {
    try {
      const response = await fetch(`/api/public/cases/${caseId}/competition/bid`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ bidAmount, message })
      });
      
      if (response.ok) {
        toast.success('Bid placed successfully! ๐Ÿ’ฐ');
        setShowCompetitionModal(false);
        fetchPublicCases(); // Refresh data
      } else {
        toast.error('Failed to place bid');
      }
    } catch (error) {
      toast.error('Error placing bid');
    }
  };

  const openBidHistoryModal = async (caseId: string) => {
    setShowBidHistoryModal(true);
    try {
      const res = await fetch(`/api/public/cases/${caseId}/competition/bids`);
      if (res.ok) {
        const data = await res.json();
        setBidHistory(data.bids);
      } else {
        setBidHistory([]);
      }
    } catch {
      setBidHistory([]);
    }
  };

  const openParticipantsModal = async (caseId: string) => {
    setShowParticipantsModal(true);
    try {
      const res = await fetch(`/api/public/cases/${caseId}/competition/participants`);
      if (res.ok) {
        const data = await res.json();
        setParticipants(data.participants);
      } else {
        setParticipants([]);
      }
    } catch {
      setParticipants([]);
    }
  };

  const getUrgencyColor = (urgency: string) => {
    switch (urgency) {
      case 'URGENT': return 'bg-red-100 text-red-800 border-red-200';
      case 'HIGH': return 'bg-orange-100 text-orange-800 border-orange-200';
      case 'NORMAL': return 'bg-blue-100 text-blue-800 border-blue-200';
      case 'LOW': return 'bg-green-100 text-green-800 border-green-200';
      default: return 'bg-gray-100 text-gray-800 border-gray-200';
    }
  };

  const getRiskColor = (risk: string) => {
    switch (risk) {
      case 'HIGH': return 'text-red-600';
      case 'MEDIUM': return 'text-yellow-600';
      case 'LOW': return 'text-green-600';
      default: return 'text-gray-600';
    }
  };

  const getCompetitionStatus = (case_: PublicCase) => {
    if (!case_.competitionDeadline) return null;
    
    const deadline = new Date(case_.competitionDeadline);
    const now = new Date();
    const timeLeft = deadline.getTime() - now.getTime();
    
    if (timeLeft <= 0) return 'ENDED';
    if (timeLeft <= 24 * 60 * 60 * 1000) return 'ENDING_SOON';
    return 'ACTIVE';
  };

  const getCompetitionBadge = (case_: PublicCase) => {
    const status = getCompetitionStatus(case_);
    if (!status) return null;

    const badges = {
      ACTIVE: { text: '๐Ÿ”ฅ Live Auction', color: 'bg-green-100 text-green-800 border-green-200' },
      ENDING_SOON: { text: 'โฐ Ending Soon', color: 'bg-orange-100 text-orange-800 border-orange-200' },
      ENDED: { text: '๐Ÿ Auction Ended', color: 'bg-gray-100 text-gray-800 border-gray-200' }
    };

    return badges[status];
  };

  if (loading) {
    return (
      <div className="space-y-6">
        {[1, 2, 3].map(i => (
          <div key={i} className="bg-white rounded-lg shadow-sm p-6 animate-pulse">
            <div className="h-6 bg-gray-200 rounded w-3/4 mb-4"></div>
            <div className="h-4 bg-gray-200 rounded w-full mb-2"></div>
            <div className="h-4 bg-gray-200 rounded w-2/3"></div>
          </div>
        ))}
      </div>
    );
  }

  return (
    <div className="max-w-6xl mx-auto">
      {/* Enhanced Header & Stats */}
      <div className="bg-gradient-to-r from-blue-50 to-purple-50 rounded-2xl p-8 mb-8 border border-blue-100">
        <div className="text-center mb-8">
          <div className="inline-flex items-center gap-3 bg-white/80 backdrop-blur-sm rounded-full px-6 py-3 mb-6 shadow-lg">
            <span className="text-2xl">โš–๏ธ</span>
            <span className="font-bold text-gray-800">Live Legal Marketplace</span>
          </div>
          <h1 className="text-4xl md:text-5xl font-bold text-gray-900 mb-4">
            ๐Ÿ›๏ธ Public Case Arena
          </h1>
          <p className="text-xl text-gray-600 max-w-3xl mx-auto mb-8">
            Where justice meets transparency. Real cases seeking real representation.
          </p>
          
          {/* Live Competition Stats */}
          <div className="grid grid-cols-2 md:grid-cols-4 gap-6 max-w-4xl mx-auto">
            <div className="bg-white rounded-xl p-4 shadow-md border border-blue-100">
              <div className="text-2xl font-bold text-blue-600 mb-1">๐Ÿ”ฅ</div>
              <div className="text-sm font-semibold text-gray-800">Live Auctions</div>
              <div className="text-xs text-gray-600">{cases.filter(c => getCompetitionStatus(c) === 'ACTIVE').length} Active</div>
            </div>
            <div className="bg-white rounded-xl p-4 shadow-md border border-green-100">
              <div className="text-2xl font-bold text-green-600 mb-1">โš–๏ธ</div>
              <div className="text-sm font-semibold text-gray-800">Total Bidders</div>
              <div className="text-xs text-gray-600">{cases.reduce((sum, c) => sum + (c.totalBidders || 0), 0)} Lawyers</div>
            </div>
            <div className="bg-white rounded-xl p-4 shadow-md border border-purple-100">
              <div className="text-2xl font-bold text-purple-600 mb-1">๐Ÿ’ฐ</div>
              <div className="text-sm font-semibold text-gray-800">Total Value</div>
              <div className="text-xs text-gray-600">${cases.reduce((sum, c) => sum + (c.currentHighestBid || 0), 0).toLocaleString()}</div>
            </div>
            <div className="bg-white rounded-xl p-4 shadow-md border border-orange-100">
              <div className="text-2xl font-bold text-orange-600 mb-1">๐ŸŽฏ</div>
              <div className="text-sm font-semibold text-gray-800">Success Rate</div>
              <div className="text-xs text-gray-600">95%+</div>
            </div>
          </div>
        </div>

        {/* Enhanced Filters */}
        <div className="bg-white rounded-xl shadow-lg p-6">
          <div className="flex flex-wrap gap-4 items-center">
            <div className="flex-1 min-w-64">
              <div className="relative">
                <Search className="h-4 w-4 absolute left-3 top-3 text-gray-400" />
                <input
                  type="text"
                  placeholder="Search cases by title, area of law, location..."
                  value={searchTerm}
                  onChange={(e) => setSearchTerm(e.target.value)}
                  className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
                  onKeyPress={(e) => e.key === 'Enter' && fetchPublicCases()}
                />
              </div>
            </div>
            
            <select
              value={filter}
              onChange={(e) => setFilter(e.target.value)}
              className="px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 bg-white"
            >
              <option value="all">All Cases</option>
              <option value="urgent">๐Ÿšจ Urgent Cases</option>
              <option value="criminal">โš–๏ธ Criminal Law</option>
              <option value="civil">๐Ÿ“œ Civil Law</option>
              <option value="human_rights">๐Ÿ•Š๏ธ Human Rights</option>
              <option value="immigration">๐ŸŒ Immigration</option>
              <option value="family">๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ Family Law</option>
              <option value="corporate">๐Ÿข Corporate Law</option>
              <option value="auction">๐Ÿ”ฅ Live Auctions</option>
              <option value="ending_soon">โฐ Ending Soon</option>
            </select>
            
            <select
              value={sortBy}
              onChange={(e) => setSortBy(e.target.value)}
              className="px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 bg-white"
            >
              <option value="newest">๐Ÿ• Newest First</option>
              <option value="urgent">๐Ÿšจ Most Urgent</option>
              <option value="popular">๐Ÿ‘๏ธ Most Popular</option>
              <option value="supported">โค๏ธ Most Supported</option>
              <option value="offers">๐Ÿ“ฌ Most Offers</option>
              <option value="highest_bid">๐Ÿ’ฐ Highest Bid</option>
              <option value="deadline">โฐ Deadline Soon</option>
            </select>
          </div>
        </div>
      </div>

      {/* Cases Grid */}
      <div className="space-y-6">
        <AnimatePresence>
          {cases.map((case_) => (
            <motion.div
              key={case_.id}
              initial={{ opacity: 0, y: 20 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: -20 }}
              className={`bg-white rounded-xl shadow-lg border-2 overflow-hidden hover:shadow-xl transition-all duration-300 ${
                case_.competitionType && getCompetitionStatus(case_) === 'ACTIVE' 
                  ? 'border-blue-200 bg-gradient-to-r from-blue-50 to-white' 
                  : 'border-gray-200'
              }`}
            >
              {/* Case Header */}
              <div className="p-6">
                <div className="flex items-start gap-4 mb-4">
                  {/* Case Logo */}
                  <div className="flex-shrink-0">
                    {case_.logoUrl ? (
                      <img
                        src={case_.logoUrl}
                        alt={`${case_.title} Logo`}
                        className="w-16 h-16 rounded-xl object-cover border-2 border-gray-200 shadow-sm"
                      />
                    ) : (
                      <div className="w-16 h-16 rounded-xl 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 className="flex-1">
                    <div className="flex items-center gap-2 mb-2">
                      <h3 className="text-xl font-bold text-gray-900">{case_.title}</h3>
                      <span className={`px-2 py-1 rounded-full text-xs font-medium border ${getUrgencyColor(case_.urgencyLevel)}`}>
                        {case_.urgencyLevel}
                      </span>
                      {/* Competition Badge */}
                      {getCompetitionBadge(case_) && (
                        <span className={`px-2 py-1 rounded-full text-xs font-medium border ${getCompetitionBadge(case_)?.color}`}>
                          {getCompetitionBadge(case_)?.text}
                        </span>
                      )}
                    </div>
                    
                    <p className="text-gray-600 mb-3 line-clamp-2">
                      {case_.publicSummary || case_.description}
                    </p>

                    {/* Enhanced Case Stats */}
                    <div className="flex flex-wrap gap-4 text-sm text-gray-500 mb-4">
                      <div className="flex items-center gap-1">
                        <MapPin className="h-4 w-4" />
                        {case_.jurisdiction}
                      </div>
                      <div className="flex items-center gap-1">
                        <Eye className="h-4 w-4" />
                        {case_.viewCount} views
                      </div>
                      <div className="flex items-center gap-1">
                        <Heart className="h-4 w-4" />
                        {case_.supporterCount} supporters
                      </div>
                      <div className="flex items-center gap-1">
                        <Users className="h-4 w-4" />
                        {case_._count.offers} offers
                      </div>
                      {/* Competition Stats */}
                      {case_.competitionType && (
                        <>
                          <div className="flex items-center gap-1">
                            <DollarSign className="h-4 w-4" />
                            ${case_.currentHighestBid?.toLocaleString() || 0} highest bid
                          </div>
                          <div className="flex items-center gap-1">
                            <Users className="h-4 w-4" />
                            {case_.totalBidders || 0} bidders
                          </div>
                          {case_.competitionDeadline && (
                            <CompetitionCountdown 
                              deadline={case_.competitionDeadline}
                              onEnd={() => {
                                fetchPublicCases();
                                toast.success('Competition has ended! Check the results.');
                              }}
                            />
                          )}
                        </>
                      )}
                    </div>

                    {/* Lead Lawyer Info */}
                    <div className="flex items-center gap-3 p-3 bg-gray-50 rounded-lg">
                      <div className="flex items-center gap-2">
                        {case_.leadLawyer.profilePicture ? (
                          <img
                            src={case_.leadLawyer.profilePicture}
                            alt={case_.leadLawyer.name}
                            className="w-8 h-8 rounded-full"
                          />
                        ) : (
                          <div className="w-8 h-8 bg-blue-500 rounded-full flex items-center justify-center text-white text-sm font-medium">
                            {case_.leadLawyer.name.charAt(0)}
                          </div>
                        )}
                        <div>
                          <div className="font-medium text-gray-900">{case_.leadLawyer.name}</div>
                          <div className="text-sm text-gray-600">
                            {case_.leadLawyer.specialization} โ€ข {case_.leadLawyer.wonCases}/{case_.leadLawyer.totalCases} cases won
                            {case_.leadLawyer.successRate && ` โ€ข ${case_.leadLawyer.successRate}% success rate`}
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>

                {/* Action Buttons */}
                <div className="flex flex-wrap gap-3">
                  <Link
                    href={`/public/cases/${case_.id}`}
                    onClick={() => handleViewCase(case_.id)}
                    className="flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
                  >
                    <Eye className="h-4 w-4" />
                    View Details
                  </Link>
                  
                  <button
                    onClick={() => handleSupportCase(case_.id)}
                    className="flex items-center gap-2 px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
                  >
                    <Heart className="h-4 w-4" />
                    Support Case
                  </button>

                  {/* Enhanced Competition Actions */}
                  {case_.competitionType && getCompetitionStatus(case_) === 'ACTIVE' && (
                    <>
                      <button
                        onClick={() => handleJoinCompetition(case_.id)}
                        className="flex items-center gap-2 px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors"
                      >
                        <Award className="h-4 w-4" />
                        Join Auction
                      </button>
                      
                      <button
                        onClick={() => {
                          setSelectedCase(case_);
                          setShowCompetitionModal(true);
                        }}
                        className="flex items-center gap-2 px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors"
                      >
                        <DollarSign className="h-4 w-4" />
                        Place Bid
                      </button>

                      <button
                        onClick={() => openBidHistoryModal(case_.id)}
                        className="flex items-center gap-2 px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
                      >
                        <Scale className="h-4 w-4" />
                        Bid History
                      </button>
                      <button
                        onClick={() => openParticipantsModal(case_.id)}
                        className="flex items-center gap-2 px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
                      >
                        <Users className="h-4 w-4" />
                        Participants
                      </button>
                    </>
                  )}

                  {session?.user?.role === 'LAWYER' && (
                    <button
                      onClick={() => handleOfferToRepresent(case_.id)}
                      className="flex items-center gap-2 px-4 py-2 bg-orange-600 text-white rounded-lg hover:bg-orange-700 transition-colors"
                    >
                      <Briefcase className="h-4 w-4" />
                      Offer to Represent
                    </button>
                  )}
                </div>
              </div>
            </motion.div>
          ))}
        </AnimatePresence>
      </div>

      {/* Enhanced Competition Modal */}
      {showCompetitionModal && selectedCase && (
        <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
          <div className="bg-white rounded-lg p-6 max-w-md w-full mx-4">
            <h3 className="text-lg font-semibold mb-4">Place Your Bid</h3>
            <form onSubmit={(e) => {
              e.preventDefault();
              const formData = new FormData(e.currentTarget);
              handlePlaceBid(
                selectedCase.id,
                parseFloat(formData.get('bidAmount') as string),
                formData.get('message') as string
              );
            }}>
              <div className="space-y-4">
                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-1">
                    Bid Amount (CAD)
                  </label>
                  <input
                    type="number"
                    name="bidAmount"
                    min={selectedCase.minimumBid || 0}
                    step="0.01"
                    required
                    className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
                    placeholder={`Min: $${selectedCase.minimumBid || 0}`}
                  />
                </div>
                
                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-1">
                    Your Proposal
                  </label>
                  <textarea
                    name="message"
                    rows={4}
                    required
                    className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
                    placeholder="Explain why you're the best lawyer for this case..."
                  />
                </div>
              </div>
              
              <div className="flex gap-3 mt-6">
                <button
                  type="submit"
                  className="flex-1 bg-purple-600 text-white py-2 rounded-lg hover:bg-purple-700"
                >
                  Place Bid
                </button>
                <button
                  type="button"
                  onClick={() => setShowCompetitionModal(false)}
                  className="flex-1 border border-gray-300 text-gray-700 py-2 rounded-lg hover:bg-gray-50"
                >
                  Cancel
                </button>
              </div>
            </form>
          </div>
        </div>
      )}

      {/* Offer Modal */}
      {showOfferModal && selectedCase && (
        <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
          <div className="bg-white rounded-lg p-6 max-w-md w-full mx-4">
            <h3 className="text-xl font-bold mb-4">Offer to Represent</h3>
            <p className="text-gray-600 mb-4">Case: {selectedCase.title}</p>
            
            <form onSubmit={(e) => {
              e.preventDefault();
              const formData = new FormData(e.target as HTMLFormElement);
              submitOffer({
                message: formData.get('message') as string,
                proposedRate: formData.get('rate') ? Number(formData.get('rate')) : undefined,
                estimatedHours: formData.get('hours') ? Number(formData.get('hours')) : undefined
              });
            }}>
              <div className="space-y-4">
                <textarea
                  name="message"
                  placeholder="Why are you the right lawyer for this case?"
                  rows={4}
                  className="w-full border rounded-lg p-3 focus:ring-2 focus:ring-blue-500"
                  required
                />
                
                <div className="grid grid-cols-2 gap-4">
                  <input
                    name="rate"
                    type="number"
                    placeholder="Hourly rate ($)"
                    className="border rounded-lg p-3 focus:ring-2 focus:ring-blue-500"
                  />
                  <input
                    name="hours"
                    type="number"
                    placeholder="Estimated hours"
                    className="border rounded-lg p-3 focus:ring-2 focus:ring-blue-500"
                  />
                </div>
              </div>

              <div className="flex gap-3 mt-6">
                <button
                  type="submit"
                  className="flex-1 bg-blue-600 text-white py-2 rounded-lg hover:bg-blue-700"
                >
                  Submit Offer
                </button>
                <button
                  type="button"
                  onClick={() => setShowOfferModal(false)}
                  className="flex-1 border border-gray-300 text-gray-700 py-2 rounded-lg hover:bg-gray-50"
                >
                  Cancel
                </button>
              </div>
            </form>
          </div>
        </div>
      )}

      {/* Bid History Modal */}
      {showBidHistoryModal && (
        <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
          <div className="bg-white rounded-lg p-6 max-w-2xl w-full mx-4">
            <h3 className="text-lg font-semibold mb-4">Bid History</h3>
            <div className="max-h-96 overflow-y-auto">
              {bidHistory.length === 0 ? (
                <div className="text-gray-500">No bids yet.</div>
              ) : (
                <table className="w-full text-sm">
                  <thead>
                    <tr className="border-b">
                      <th className="text-left py-2">Lawyer</th>
                      <th className="text-left py-2">Bid Amount</th>
                      <th className="text-left py-2">Message</th>
                      <th className="text-left py-2">Time</th>
                    </tr>
                  </thead>
                  <tbody>
                    {bidHistory.map((bid, idx) => (
                      <tr key={bid.id} className={idx % 2 === 0 ? 'bg-gray-50' : ''}>
                        <td className="py-2 flex items-center gap-2">
                          {bid.lawyer.profilePicture ? (
                            <img src={bid.lawyer.profilePicture} alt={bid.lawyer.name} className="w-6 h-6 rounded-full" />
                          ) : (
                            <div className="w-6 h-6 bg-blue-500 rounded-full flex items-center justify-center text-white text-xs font-medium">
                              {bid.lawyer.name.charAt(0)}
                            </div>
                          )}
                          <span>{bid.lawyer.name}</span>
                        </td>
                        <td className="py-2 font-semibold">${bid.bidAmount.toLocaleString()}</td>
                        <td className="py-2">{bid.message}</td>
                        <td className="py-2">{new Date(bid.createdAt).toLocaleString()}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              )}
            </div>
            <div className="flex justify-end mt-6">
              <button
                onClick={() => setShowBidHistoryModal(false)}
                className="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50"
              >
                Close
              </button>
            </div>
          </div>
        </div>
      )}

      {/* Participants Modal */}
      {showParticipantsModal && (
        <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
          <div className="bg-white rounded-lg p-6 max-w-lg w-full mx-4">
            <h3 className="text-lg font-semibold mb-4">Competition Participants</h3>
            <div className="max-h-96 overflow-y-auto">
              {participants.length === 0 ? (
                <div className="text-gray-500">No participants yet.</div>
              ) : (
                <ul className="space-y-3">
                  {participants.map((p) => (
                    <li key={p.id} className="flex items-center gap-3">
                      {p.lawyer.profilePicture ? (
                        <img src={p.lawyer.profilePicture} alt={p.lawyer.name} className="w-8 h-8 rounded-full" />
                      ) : (
                        <div className="w-8 h-8 bg-blue-500 rounded-full flex items-center justify-center text-white text-sm font-medium">
                          {p.lawyer.name.charAt(0)}
                        </div>
                      )}
                      <div>
                        <div className="font-medium text-gray-900">{p.lawyer.name}</div>
                        <div className="text-xs text-gray-500">{p.lawyer.specialization}</div>
                      </div>
                      {p.lawyer.isVerified && (
                        <Badge className="h-4 w-4 text-blue-600 ml-2" />
                      )}
                    </li>
                  ))}
                </ul>
              )}
            </div>
            <div className="flex justify-end mt-6">
              <button
                onClick={() => setShowParticipantsModal(false)}
                className="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50"
              >
                Close
              </button>
            </div>
          </div>
        </div>
      )}

      {/* Empty State */}
      {!loading && cases.length === 0 && (
        <div className="text-center py-12">
          <Scale className="h-16 w-16 text-gray-400 mx-auto mb-4" />
          <h3 className="text-xl font-semibold text-gray-900 mb-2">No cases found</h3>
          <p className="text-gray-600">
            {searchTerm ? 'Try adjusting your search terms' : 'No public cases available at the moment'}
          </p>
        </div>
      )}
    </div>
  );
};

export default PublicCaseFeed; 

CasperSecurity Mini