import React, { useRef } from 'react';
import Image from 'next/image';
import { motion } from 'framer-motion';
import { FaStar, FaStarHalfAlt, FaRegStar } from 'react-icons/fa';
import { FaChevronLeft, FaChevronRight } from 'react-icons/fa';
// Define the interface for a single review
export interface Review {
personName: string;
stars: number;
content: string;
date: string;
googleMapsUrl: string;
avatarUrl?: string; // Optional avatar image
}
// Interface for the component props
interface ReviewsProps {
reviews: Review[];
}
// Helper function to render stars
const renderStars = (rating: number) => {
const stars = [];
const fullStars = Math.floor(rating);
const hasHalfStar = rating % 1 !== 0;
// Add full stars
for (let i = 0; i < fullStars; i++) {
stars.push(<FaStar key={`full-${i}`} className="text-yellow-400" />);
}
// Add half star if needed
if (hasHalfStar) {
stars.push(<FaStarHalfAlt key="half" className="text-yellow-400" />);
}
// Add empty stars
const emptyStars = 5 - fullStars - (hasHalfStar ? 1 : 0);
for (let i = 0; i < emptyStars; i++) {
stars.push(<FaRegStar key={`empty-${i}`} className="text-yellow-400" />);
}
return stars;
};
// Animation variants
const fadeIn = {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 }
};
const Reviews: React.FC<ReviewsProps> = ({ reviews }) => {
const carouselRef = useRef<HTMLDivElement>(null);
// Function to scroll left
const scrollLeft = () => {
if (carouselRef.current) {
carouselRef.current.scrollBy({ left: -300, behavior: 'smooth' });
}
};
// Function to scroll right
const scrollRight = () => {
if (carouselRef.current) {
carouselRef.current.scrollBy({ left: 300, behavior: 'smooth' });
}
};
return (
<div className="w-full relative">
{/* Left Navigation Button */}
<button
onClick={scrollLeft}
className="absolute left-0 top-1/2 transform -translate-y-1/2 z-10 bg-white/80 hover:bg-white text-gray-700 rounded-full p-2 shadow-md focus:outline-none"
aria-label="Scroll left"
>
<FaChevronLeft className="h-5 w-5" />
</button>
<div className="relative overflow-hidden">
<div
ref={carouselRef}
className="carousel carousel-center space-x-4 p-4 w-full"
style={{ scrollBehavior: 'smooth' }}
>
{reviews.map((review, index) => (
<motion.div
key={index}
className="carousel-item"
whileHover={{ scale: 1.03 }}
transition={{ duration: 0.3 }}
>
<a
href={review.googleMapsUrl}
target="_blank"
rel="noopener noreferrer"
className="block w-72 bg-white rounded-xl shadow-lg p-5 cursor-pointer hover:shadow-xl transition-shadow duration-300"
>
<div className="flex items-center mb-3">
{review.avatarUrl ? (
<div className="mr-3">
<Image
src={review.avatarUrl}
alt={review.personName}
width={40}
height={40}
className="rounded-full"
unoptimized
onError={(e) => {
// Replace with a fallback avatar
const target = e.target as HTMLImageElement;
target.style.display = 'none';
target.parentElement!.innerHTML = `
<div class="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center">
<span class="text-gray-600 font-bold text-lg">
${review.personName.charAt(0)}
</span>
</div>
`;
}}
/>
</div>
) : (
<div className="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center mr-3">
<span className="text-gray-600 font-bold text-lg">
{review.personName.charAt(0)}
</span>
</div>
)}
<div>
<h4 className="font-bold">{review.personName}</h4>
<div className="flex">
{renderStars(review.stars)}
</div>
</div>
</div>
<p className="text-gray-600 mb-3 line-clamp-5">{review.content}</p>
<p className="text-gray-400 text-sm">{review.date}</p>
</a>
</motion.div>
))}
</div>
{/* Show navigation indicators for mobile */}
<div className="flex justify-center mt-4 md:hidden">
<div className="flex space-x-2">
{reviews.map((_, index) => (
<div
key={index}
className="w-2 h-2 rounded-full bg-gray-300"
/>
))}
</div>
</div>
</div>
{/* Right Navigation Button */}
<button
onClick={scrollRight}
className="absolute right-0 top-1/2 transform -translate-y-1/2 z-10 bg-white/80 hover:bg-white text-gray-700 rounded-full p-2 shadow-md focus:outline-none"
aria-label="Scroll right"
>
<FaChevronRight className="h-5 w-5" />
</button>
</div>
);
};
export default Reviews;