mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-23 11:11:14 -05:00
Refactor code structure and remove redundant changes
This commit is contained in:
110
src-old/components/reviews/StarRating.tsx
Normal file
110
src-old/components/reviews/StarRating.tsx
Normal file
@@ -0,0 +1,110 @@
|
||||
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 (
|
||||
<div key={index} className="relative inline-block">
|
||||
{/* Background unfilled star */}
|
||||
<Star className={cn(starSize, 'text-muted-foreground')} />
|
||||
|
||||
{/* Filled star overlay */}
|
||||
<div
|
||||
className="absolute inset-0 overflow-hidden"
|
||||
style={{ width: getStarFill() }}
|
||||
>
|
||||
<Star className={cn(starSize, 'fill-yellow-400 text-yellow-400')} />
|
||||
</div>
|
||||
|
||||
{/* Interactive click areas */}
|
||||
{interactive && (
|
||||
<>
|
||||
{/* Left half click area */}
|
||||
<div
|
||||
className="absolute top-0 left-0 w-1/2 h-full cursor-pointer z-10"
|
||||
onClick={() => handleStarClick(index, true)}
|
||||
onMouseEnter={() => handleStarHover(index, true)}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
/>
|
||||
|
||||
{/* Right half click area */}
|
||||
<div
|
||||
className="absolute top-0 right-0 w-1/2 h-full cursor-pointer z-10"
|
||||
onClick={() => handleStarClick(index, false)}
|
||||
onMouseEnter={() => handleStarHover(index, false)}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={cn('flex items-center gap-1', className)}>
|
||||
<div className="flex items-center">
|
||||
{Array.from({ length: 5 }, (_, i) => renderStar(i))}
|
||||
</div>
|
||||
{showLabel && (
|
||||
<span className="ml-2 text-sm text-muted-foreground">
|
||||
{displayRating} star{displayRating !== 1 ? 's' : ''}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user