![]() 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/public_html/src/components/ |
import React, { useState } from 'react';
import { useSession } from 'next-auth/react';
import { useRouter } from 'next/router';
import { motion, AnimatePresence } from 'framer-motion';
import {
Scale, MessageSquare, Calendar, DollarSign,
Users, Star, Clock, CheckCircle, XCircle,
ArrowRight, Phone, Mail, MapPin, Award,
Shield, TrendingUp, FileText, Zap
} from 'lucide-react';
import toast from 'react-hot-toast';
interface HireLawyerButtonProps {
lawyer: {
id: string;
name: string;
role: string;
title?: string;
specialization?: string;
yearsOfExperience?: number;
totalCases: number;
wonCases: number;
lostCases: number;
winRate: number;
averageRating: number;
hourlyRate?: number;
totalBadges: number;
level: number;
isVerified: boolean;
profilePicture?: string;
bio?: string;
officeLocation?: string;
availability?: string;
};
businessProfile?: {
id: string;
businessName: string;
isVerified: boolean;
};
availableCases?: Array<{
id: string;
title: string;
caseType: string;
status: string;
priority: string;
budget?: number;
isAcceptingApplications: boolean;
}>;
className?: string;
}
const HireLawyerButton: React.FC<HireLawyerButtonProps> = ({
lawyer,
businessProfile,
availableCases = [],
className = ''
}) => {
const { data: session } = useSession();
const router = useRouter();
const [showModal, setShowModal] = useState(false);
const [selectedOption, setSelectedOption] = useState<string>('');
const [loading, setLoading] = useState(false);
const hiringOptions = [
{
id: 'case-representation',
title: 'Case Representation',
description: 'Hire for a specific legal case',
icon: Scale,
color: 'bg-blue-500',
features: [
'Full case representation',
'Court appearances',
'Document preparation',
'Client communication',
'Case strategy development'
],
price: lawyer.hourlyRate ? `$${lawyer.hourlyRate}/hour` : 'Contact for pricing',
duration: 'Case duration',
popular: true
},
{
id: 'consultation',
title: 'Legal Consultation',
description: 'One-time legal advice session',
icon: MessageSquare,
color: 'bg-green-500',
features: [
'1-hour consultation',
'Legal advice',
'Case evaluation',
'Strategy recommendations',
'Follow-up summary'
],
price: lawyer.hourlyRate ? `$${lawyer.hourlyRate}/hour` : 'Contact for pricing',
duration: '1 hour',
popular: false
},
{
id: 'retainer',
title: 'Monthly Retainer',
description: 'Ongoing legal services',
icon: Calendar,
color: 'bg-purple-500',
features: [
'Monthly legal services',
'Priority access',
'Regular check-ins',
'Document review',
'Legal strategy support'
],
price: lawyer.hourlyRate ? `$${Math.round(lawyer.hourlyRate * 0.8 * 20)}/month` : 'Contact for pricing',
duration: 'Monthly',
popular: false
},
{
id: 'case-offer',
title: 'Make Case Offer',
description: 'Propose collaboration on a case',
icon: Users,
color: 'bg-orange-500',
features: [
'Case collaboration',
'Shared responsibilities',
'Split fees',
'Joint strategy',
'Team approach'
],
price: 'Negotiable',
duration: 'Case duration',
popular: false
}
];
const handleHire = async (optionId: string) => {
if (!session) {
toast.error('Please log in to hire a lawyer');
router.push('/auth/login');
return;
}
setLoading(true);
setSelectedOption(optionId);
try {
switch (optionId) {
case 'case-representation':
// Redirect to case selection or creation
if (availableCases.length > 0) {
router.push(`/hire/case-selection?lawyerId=${lawyer.id}`);
} else {
router.push(`/hire/new-case?lawyerId=${lawyer.id}`);
}
break;
case 'consultation':
// Create consultation booking
router.push(`/hire/consultation?lawyerId=${lawyer.id}`);
break;
case 'retainer':
// Setup retainer agreement
router.push(`/hire/retainer?lawyerId=${lawyer.id}`);
break;
case 'case-offer':
// Make case offer
if (availableCases.length > 0) {
router.push(`/hire/case-offer?lawyerId=${lawyer.id}`);
} else {
toast.error('No cases available for collaboration');
}
break;
default:
toast.error('Invalid hiring option');
}
} catch (error) {
console.error('Error processing hire request:', error);
toast.error('Error processing request');
} finally {
setLoading(false);
}
};
const getLevelBadge = (level: number) => {
if (level >= 50) return { color: 'bg-purple-500', text: 'Legendary' };
if (level >= 30) return { color: 'bg-red-500', text: 'Master' };
if (level >= 20) return { color: 'bg-orange-500', text: 'Expert' };
if (level >= 10) return { color: 'bg-blue-500', text: 'Advanced' };
return { color: 'bg-gray-500', text: 'Beginner' };
};
const levelBadge = getLevelBadge(lawyer.level);
return (
<>
{/* Hire Button */}
<button
onClick={() => setShowModal(true)}
className={`inline-flex items-center px-6 py-3 bg-gradient-to-r from-blue-600 to-purple-600 text-white font-semibold rounded-lg hover:from-blue-700 hover:to-purple-700 transition-all duration-200 shadow-lg hover:shadow-xl transform hover:-translate-y-0.5 ${className}`}
>
<Scale className="h-5 w-5 mr-2" />
Hire {lawyer.name.split(' ')[0]}
<ArrowRight className="h-4 w-4 ml-2" />
</button>
{/* Hiring Modal */}
<AnimatePresence>
{showModal && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4"
onClick={() => setShowModal(false)}
>
<motion.div
initial={{ scale: 0.9, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.9, opacity: 0 }}
className="bg-white dark:bg-gray-800 rounded-xl shadow-2xl max-w-4xl w-full max-h-[90vh] overflow-y-auto"
onClick={(e) => e.stopPropagation()}
>
{/* Header */}
<div className="p-6 border-b border-gray-200 dark:border-gray-700">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-4">
{lawyer.profilePicture ? (
<img
src={lawyer.profilePicture}
alt={lawyer.name}
className="w-16 h-16 rounded-full object-cover"
/>
) : (
<div className="w-16 h-16 bg-gradient-to-br from-blue-400 to-purple-500 rounded-full flex items-center justify-center">
<Users className="h-8 w-8 text-white" />
</div>
)}
<div>
<h2 className="text-2xl font-bold text-gray-900 dark:text-white flex items-center">
{lawyer.name}
{lawyer.isVerified && (
<Shield className="h-6 w-6 ml-2 text-blue-600" />
)}
</h2>
<p className="text-gray-600 dark:text-gray-400">{lawyer.title}</p>
<div className="flex items-center space-x-2 mt-1">
<span className={`px-2 py-1 text-xs text-white rounded-full ${levelBadge.color}`}>
{levelBadge.text} (Lv.{lawyer.level})
</span>
<div className="flex items-center text-yellow-500">
<Star className="h-4 w-4" />
<span className="text-sm ml-1">{lawyer.averageRating ? lawyer.averageRating.toFixed(1) : 'N/A'}</span>
</div>
</div>
</div>
</div>
<button
onClick={() => setShowModal(false)}
className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
>
<XCircle className="h-6 w-6" />
</button>
</div>
{/* Lawyer Stats */}
<div className="grid grid-cols-4 gap-4 mt-6">
<div className="text-center p-3 bg-blue-50 dark:bg-blue-900/20 rounded-lg">
<div className="text-lg font-bold text-blue-600">{lawyer.totalCases}</div>
<div className="text-xs text-gray-600 dark:text-gray-400">Total Cases</div>
</div>
<div className="text-center p-3 bg-green-50 dark:bg-green-900/20 rounded-lg">
<div className="text-lg font-bold text-green-600">
{typeof lawyer.winRate === 'number' ? `${lawyer.winRate.toFixed(1)}%` : 'N/A'}
</div>
<div className="text-xs text-gray-600 dark:text-gray-400">Win Rate</div>
</div>
<div className="text-center p-3 bg-purple-50 dark:bg-purple-900/20 rounded-lg">
<div className="text-lg font-bold text-purple-600">{lawyer.yearsOfExperience || 0}</div>
<div className="text-xs text-gray-600 dark:text-gray-400">Years Exp.</div>
</div>
<div className="text-center p-3 bg-yellow-50 dark:bg-yellow-900/20 rounded-lg">
<div className="text-lg font-bold text-yellow-600">{lawyer.totalBadges}</div>
<div className="text-xs text-gray-600 dark:text-gray-400">Badges</div>
</div>
</div>
</div>
{/* Hiring Options */}
<div className="p-6">
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-6">
Choose Your Hiring Option
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{hiringOptions.map((option) => (
<motion.div
key={option.id}
whileHover={{ scale: 1.02 }}
className={`relative border-2 rounded-xl p-6 cursor-pointer transition-all duration-200 ${
option.popular
? 'border-blue-500 bg-blue-50 dark:bg-blue-900/10'
: 'border-gray-200 dark:border-gray-700 hover:border-blue-300'
}`}
onClick={() => handleHire(option.id)}
>
{option.popular && (
<div className="absolute -top-3 left-1/2 transform -translate-x-1/2">
<span className="bg-blue-500 text-white px-3 py-1 rounded-full text-xs font-semibold">
Most Popular
</span>
</div>
)}
<div className="flex items-start space-x-4">
<div className={`p-3 rounded-lg ${option.color} text-white`}>
<option.icon className="h-6 w-6" />
</div>
<div className="flex-1">
<h4 className="text-lg font-semibold text-gray-900 dark:text-white">
{option.title}
</h4>
<p className="text-gray-600 dark:text-gray-400 text-sm mb-4">
{option.description}
</p>
<div className="space-y-2 mb-4">
{option.features.map((feature, index) => (
<div key={index} className="flex items-center text-sm text-gray-600 dark:text-gray-400">
<CheckCircle className="h-4 w-4 text-green-500 mr-2 flex-shrink-0" />
{feature}
</div>
))}
</div>
<div className="flex items-center justify-between">
<div>
<div className="text-lg font-bold text-gray-900 dark:text-white">
{option.price}
</div>
<div className="text-sm text-gray-600 dark:text-gray-400">
{option.duration}
</div>
</div>
<ArrowRight className="h-5 w-5 text-blue-600" />
</div>
</div>
</div>
</motion.div>
))}
</div>
{/* Available Cases (if any) */}
{availableCases.length > 0 && (
<div className="mt-8 p-4 bg-gray-50 dark:bg-gray-700 rounded-lg">
<h4 className="font-semibold text-gray-900 dark:text-white mb-3 flex items-center">
<FileText className="h-5 w-5 mr-2" />
Available Cases for Collaboration
</h4>
<div className="space-y-2">
{availableCases.slice(0, 3).map((case_) => (
<div key={case_.id} className="flex items-center justify-between p-3 bg-white dark:bg-gray-600 rounded-lg">
<div>
<div className="font-medium text-gray-900 dark:text-white">{case_.title}</div>
<div className="text-sm text-gray-600 dark:text-gray-400">
{case_.caseType} • {case_.priority} priority
</div>
</div>
<div className="text-right">
<div className="text-sm font-medium text-gray-900 dark:text-white">
{case_.budget ? `$${case_.budget.toLocaleString()}` : 'Contact for budget'}
</div>
<div className="text-xs text-gray-600 dark:text-gray-400">
{case_.status}
</div>
</div>
</div>
))}
</div>
</div>
)}
{/* Contact Information */}
<div className="mt-6 p-4 bg-blue-50 dark:bg-blue-900/10 rounded-lg">
<h4 className="font-semibold text-gray-900 dark:text-white mb-3">
Need to discuss first?
</h4>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className="flex items-center text-gray-600 dark:text-gray-400">
<Phone className="h-4 w-4 mr-2" />
<span>Call for consultation</span>
</div>
<div className="flex items-center text-gray-600 dark:text-gray-400">
<Mail className="h-4 w-4 mr-2" />
<span>Send message</span>
</div>
<div className="flex items-center text-gray-600 dark:text-gray-400">
<MapPin className="h-4 w-4 mr-2" />
<span>{lawyer.officeLocation || 'Office location'}</span>
</div>
</div>
</div>
</div>
</motion.div>
</motion.div>
)}
</AnimatePresence>
</>
);
};
export default HireLawyerButton;