"use client" import { useState, useRef } from "react" import { Star } from "lucide-react" import { cn } from "@/lib/utils" interface RatingProps { value: number onChange?: (value: number) => void readonly?: boolean className?: string size?: "sm" | "md" | "lg" precision?: "full" | "half" | "decimal" } export function StarRating({ value, onChange, readonly = false, className, size = "md", precision = "decimal" }: RatingProps) { const [hoverValue, setHoverValue] = useState(null) const containerRef = useRef(null) const stars = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] const starSize = { sm: "h-3 w-3", md: "h-4 w-4", lg: "h-5 w-5" }[size] const handleMouseMove = (e: React.MouseEvent, starIndex: number) => { if (readonly) return const rect = e.currentTarget.getBoundingClientRect() const x = e.clientX - rect.left const width = rect.width const fraction = x / width let newValue: number if (precision === "decimal") { // Allow 0.1 precision (e.g., 9.2) newValue = starIndex + Math.round(fraction * 10) / 10 newValue = Math.max(starIndex, Math.min(starIndex + 1, newValue)) } else if (precision === "half") { // Half-star precision newValue = fraction < 0.5 ? starIndex + 0.5 : starIndex + 1 } else { // Full star only newValue = starIndex + 1 } setHoverValue(newValue) } const handleClick = () => { if (!readonly && hoverValue !== null && onChange) { // Round to 1 decimal place onChange(Math.round(hoverValue * 10) / 10) } } const displayValue = hoverValue !== null ? hoverValue : value // Calculate fill percentage for each star const getStarFill = (starIndex: number): number => { const starStart = starIndex const starEnd = starIndex + 1 if (displayValue >= starEnd) return 100 if (displayValue <= starStart) return 0 return (displayValue - starStart) * 100 } return (
!readonly && setHoverValue(null)} > {stars.map((star, index) => { const fillPercent = getStarFill(index) return ( ) })} {/* Display numeric value */} {!readonly && ( {displayValue > 0 ? displayValue.toFixed(1) : "—"} )}
) }