Files
Hotel-Booking/Frontend/src/features/rooms/components/RatingStars.tsx
Iliyan Angelov 39fcfff811 update
2025-11-30 22:43:09 +02:00

91 lines
2.1 KiB
TypeScript

import React from 'react';
import { Star } from 'lucide-react';
interface RatingStarsProps {
rating: number;
maxRating?: number;
size?: 'sm' | 'md' | 'lg';
showNumber?: boolean;
interactive?: boolean;
onRatingChange?: (rating: number) => void;
}
const RatingStars: React.FC<RatingStarsProps> = ({
rating,
maxRating = 5,
size = 'md',
showNumber = false,
interactive = false,
onRatingChange,
}) => {
const [hoveredRating, setHoveredRating] =
React.useState<number | null>(null);
const sizeClasses = {
sm: 'w-4 h-4',
md: 'w-5 h-5',
lg: 'w-6 h-6',
};
const handleClick = (value: number) => {
if (interactive && onRatingChange) {
onRatingChange(value);
}
};
const handleMouseEnter = (value: number) => {
if (interactive) {
setHoveredRating(value);
}
};
const handleMouseLeave = () => {
if (interactive) {
setHoveredRating(null);
}
};
const displayRating = hoveredRating ?? rating;
return (
<div className="flex items-center gap-1">
{Array.from({ length: maxRating }, (_, index) => {
const starValue = index + 1;
const isFilled = starValue <= displayRating;
return (
<button
key={index}
type="button"
onClick={() => handleClick(starValue)}
onMouseEnter={() => handleMouseEnter(starValue)}
onMouseLeave={handleMouseLeave}
disabled={!interactive}
className={`${
interactive
? 'cursor-pointer hover:scale-110 transition-transform'
: 'cursor-default'
}`}
aria-label={`${starValue} star${starValue > 1 ? 's' : ''}`}
>
<Star
className={`${sizeClasses[size]} ${
isFilled
? 'text-[#d4af37] fill-[#d4af37]'
: 'text-gray-500'
}`}
/>
</button>
);
})}
{showNumber && (
<span className="ml-2 text-xs sm:text-sm font-semibold text-white">
{rating.toFixed(1)}
</span>
)}
</div>
);
};
export default RatingStars;