import { useState } from 'react'; import { Star } from 'lucide-react'; import { cn } from '@/lib/utils'; interface StarRatingProps { rating: number; onChange?: (rating: number) => void; size?: 'sm' | 'md' | 'lg'; interactive?: boolean; showLabel?: boolean; className?: string; } export function StarRating({ rating, onChange, size = 'md', interactive = false, showLabel = false, className }: StarRatingProps) { const [hoverRating, setHoverRating] = useState(0); const sizes = { sm: 'w-4 h-4', md: 'w-6 h-6', lg: 'w-8 h-8' }; const starSize = sizes[size]; const displayRating = hoverRating || rating; const handleStarClick = (starIndex: number, isHalf: boolean) => { if (!interactive || !onChange) return; const newRating = starIndex + (isHalf ? 0.5 : 1); onChange(newRating); }; const handleStarHover = (starIndex: number, isHalf: boolean) => { if (!interactive) return; const newHoverRating = starIndex + (isHalf ? 0.5 : 1); setHoverRating(newHoverRating); }; const handleMouseLeave = () => { if (!interactive) return; setHoverRating(0); }; const renderStar = (index: number) => { const starValue = index + 1; const isFullStar = displayRating >= starValue; const isHalfStar = displayRating >= starValue - 0.5 && displayRating < starValue; const getStarFill = () => { if (isFullStar) return '100%'; if (isHalfStar) return '50%'; return '0%'; }; return (
{/* Background unfilled star */} {/* Filled star overlay */}
{/* Interactive click areas */} {interactive && ( <> {/* Left half click area */}
handleStarClick(index, true)} onMouseEnter={() => handleStarHover(index, true)} onMouseLeave={handleMouseLeave} /> {/* Right half click area */}
handleStarClick(index, false)} onMouseEnter={() => handleStarHover(index, false)} onMouseLeave={handleMouseLeave} /> )}
); }; return (
{Array.from({ length: 5 }, (_, i) => renderStar(i))}
{showLabel && ( {displayRating} star{displayRating !== 1 ? 's' : ''} )}
); }