![]() 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/ |
import React from 'react';
import { Star, StarHalf } from 'lucide-react';
interface LawyerRatingStarsProps {
rating?: number | null;
totalRatings?: number;
size?: 'sm' | 'md' | 'lg';
showBreakdown?: boolean;
breakdown?: {
boldness?: number;
transparency?: number;
communication?: number;
results?: number;
};
}
const LawyerRatingStars: React.FC<LawyerRatingStarsProps> = ({
rating,
totalRatings = 0,
size = 'sm',
showBreakdown = false,
breakdown
}) => {
// Ensure rating is always a number, defaulting to 0 if null or undefined
const safeRating = rating ?? 0;
const sizeConfig = {
sm: { star: 'h-3 w-3', text: 'text-xs' },
md: { star: 'h-4 w-4', text: 'text-sm' },
lg: { star: 'h-5 w-5', text: 'text-base' }
};
const renderStars = (rating: number, starClass: string) => {
const stars = [];
const fullStars = Math.floor(rating);
const hasHalfStar = rating % 1 >= 0.5;
for (let i = 0; i < fullStars; i++) {
stars.push(
<Star key={i} className={`${starClass} fill-yellow-400 text-yellow-400`} />
);
}
if (hasHalfStar) {
stars.push(
<StarHalf key="half" className={`${starClass} fill-yellow-400 text-yellow-400`} />
);
}
const emptyStars = 5 - Math.ceil(rating);
for (let i = 0; i < emptyStars; i++) {
stars.push(
<Star key={`empty-${i}`} className={`${starClass} text-gray-300`} />
);
}
return stars;
};
return (
<div className="space-y-2">
{/* Main Rating */}
<div className="flex items-center gap-2">
<div className="flex items-center gap-1">
{renderStars(safeRating, sizeConfig[size].star)}
</div>
<span className={`${sizeConfig[size].text} font-medium text-gray-700`}>
{safeRating.toFixed(1)}
</span>
{totalRatings > 0 && (
<span className={`${sizeConfig[size].text} text-gray-500`}>
({totalRatings} review{totalRatings !== 1 ? 's' : ''})
</span>
)}
</div>
{/* Detailed Breakdown */}
{showBreakdown && breakdown && (
<div className="space-y-1">
<div className="grid grid-cols-2 gap-2 text-xs">
<div className="flex items-center justify-between">
<span className="text-gray-600">Boldness:</span>
<div className="flex items-center gap-1">
{renderStars(breakdown.boldness || 0, 'h-3 w-3')}
<span className="text-gray-700 ml-1">{(breakdown.boldness || 0).toFixed(1)}</span>
</div>
</div>
<div className="flex items-center justify-between">
<span className="text-gray-600">Transparency:</span>
<div className="flex items-center gap-1">
{renderStars(breakdown.transparency || 0, 'h-3 w-3')}
<span className="text-gray-700 ml-1">{(breakdown.transparency || 0).toFixed(1)}</span>
</div>
</div>
<div className="flex items-center justify-between">
<span className="text-gray-600">Communication:</span>
<div className="flex items-center gap-1">
{renderStars(breakdown.communication || 0, 'h-3 w-3')}
<span className="text-gray-700 ml-1">{(breakdown.communication || 0).toFixed(1)}</span>
</div>
</div>
<div className="flex items-center justify-between">
<span className="text-gray-600">Results:</span>
<div className="flex items-center gap-1">
{renderStars(breakdown.results || 0, 'h-3 w-3')}
<span className="text-gray-700 ml-1">{(breakdown.results || 0).toFixed(1)}</span>
</div>
</div>
</div>
</div>
)}
</div>
);
};
export default LawyerRatingStars;