172 lines
8.8 KiB
TypeScript
172 lines
8.8 KiB
TypeScript
"use client";
|
|
|
|
import { useRef } from "react";
|
|
import { GrowingBuilding } from "./PropertyAnimations";
|
|
|
|
export default function Testimonials() {
|
|
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
|
|
|
const testimonials = [
|
|
{
|
|
quote: "Aurora Springs transformed our idea of a dream home into reality. The attention to detail is unmatched.",
|
|
author: "Rajesh Kumar",
|
|
location: "Owner at Aurora Heights",
|
|
rating: 5,
|
|
date: "2 months ago"
|
|
},
|
|
{
|
|
quote: "The transparency and professionalism shown by the team made the entire buying process seamless.",
|
|
author: "Priya Sharma",
|
|
location: "Owner at Serene Meadows",
|
|
rating: 5,
|
|
date: "3 months ago"
|
|
},
|
|
{
|
|
quote: "Living here feels like a permanent vacation. The amenities and the community are world-class.",
|
|
author: "David Miller",
|
|
location: "Resident at The Grandeur",
|
|
rating: 5,
|
|
date: "1 month ago"
|
|
},
|
|
{
|
|
quote: "Exceptional service from start to finish. The team went above and beyond to ensure we found our perfect home.",
|
|
author: "Anita Desai",
|
|
location: "Owner at Green Valley",
|
|
rating: 5,
|
|
date: "4 months ago"
|
|
},
|
|
{
|
|
quote: "The quality of construction and the beautiful surroundings make this the best investment we've ever made.",
|
|
author: "Michael Chen",
|
|
location: "Resident at Skyline Towers",
|
|
rating: 5,
|
|
date: "5 months ago"
|
|
}
|
|
];
|
|
|
|
const scroll = (direction: "left" | "right") => {
|
|
if (scrollContainerRef.current) {
|
|
const scrollAmount = direction === "left" ? -400 : 400;
|
|
scrollContainerRef.current.scrollBy({ left: scrollAmount, behavior: "smooth" });
|
|
}
|
|
};
|
|
|
|
const renderStars = (rating: number) => {
|
|
return (
|
|
<div className="flex gap-1">
|
|
{[...Array(5)].map((_, i) => (
|
|
<svg
|
|
key={i}
|
|
className={`w-5 h-5 ${i < rating ? 'text-yellow-400' : 'text-gray-300'}`}
|
|
fill="currentColor"
|
|
viewBox="0 0 20 20"
|
|
>
|
|
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
|
|
</svg>
|
|
))}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const getInitials = (name: string) => {
|
|
return name.split(' ').map(n => n[0]).join('').toUpperCase();
|
|
};
|
|
|
|
return (
|
|
<section className="py-24 bg-white dark:bg-black relative overflow-hidden">
|
|
|
|
{/* Decorative Animations */}
|
|
<div className="absolute top-1/2 left-10 -translate-y-1/2 opacity-20 hidden lg:block">
|
|
<GrowingBuilding />
|
|
</div>
|
|
|
|
<div className="max-w-7xl mx-auto px-6 relative z-10">
|
|
<div className="text-center mb-16">
|
|
<h2 className="text-3xl md:text-4xl font-bold tracking-tight text-foreground mb-4">
|
|
Stories of Satisfaction
|
|
</h2>
|
|
<div className="flex items-center justify-center gap-2 mt-4">
|
|
<div className="flex">
|
|
{renderStars(5)}
|
|
</div>
|
|
<span className="text-lg font-semibold text-foreground">5.0</span>
|
|
<span className="text-gray-500">• Based on {testimonials.length} reviews</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Slider Container */}
|
|
<div className="relative group">
|
|
{/* Navigation Buttons */}
|
|
<button
|
|
onClick={() => scroll("left")}
|
|
className="absolute left-0 top-1/2 -translate-y-1/2 -translate-x-4 z-10 bg-white dark:bg-gray-800 p-3 rounded-full shadow-lg opacity-0 group-hover:opacity-100 transition-all duration-300 hover:scale-110 hidden md:block border border-gray-200 dark:border-gray-700"
|
|
aria-label="Previous reviews"
|
|
>
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={2} stroke="currentColor" className="w-5 h-5 text-foreground">
|
|
<path strokeLinecap="round" strokeLinejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
|
|
</svg>
|
|
</button>
|
|
|
|
<button
|
|
onClick={() => scroll("right")}
|
|
className="absolute right-0 top-1/2 -translate-y-1/2 translate-x-4 z-10 bg-white dark:bg-gray-800 p-3 rounded-full shadow-lg opacity-0 group-hover:opacity-100 transition-all duration-300 hover:scale-110 hidden md:block border border-gray-200 dark:border-gray-700"
|
|
aria-label="Next reviews"
|
|
>
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={2} stroke="currentColor" className="w-5 h-5 text-foreground">
|
|
<path strokeLinecap="round" strokeLinejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
|
|
</svg>
|
|
</button>
|
|
|
|
{/* Scrollable Reviews */}
|
|
<div
|
|
ref={scrollContainerRef}
|
|
className="flex gap-6 overflow-x-auto pb-8 snap-x snap-mandatory hide-scrollbar"
|
|
style={{ scrollbarWidth: 'none', msOverflowStyle: 'none' }}
|
|
>
|
|
{testimonials.map((item, index) => (
|
|
<div
|
|
key={index}
|
|
className="flex-shrink-0 snap-center w-full md:w-[calc(50%-12px)] lg:w-[calc(33.333%-16px)]"
|
|
>
|
|
<div className="bg-white dark:bg-gray-900 p-6 rounded-2xl border border-gray-200 dark:border-gray-800 hover:shadow-xl transition-all duration-300 h-full flex flex-col">
|
|
{/* Header with Avatar and Info */}
|
|
<div className="flex items-start gap-4 mb-4">
|
|
<div className="w-12 h-12 rounded-full bg-primary text-white flex items-center justify-center font-bold text-lg flex-shrink-0">
|
|
{getInitials(item.author)}
|
|
</div>
|
|
<div className="flex-1">
|
|
<h4 className="font-semibold text-foreground">{item.author}</h4>
|
|
<p className="text-sm text-gray-500 dark:text-gray-400">{item.date}</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Star Rating */}
|
|
<div className="mb-4">
|
|
{renderStars(item.rating)}
|
|
</div>
|
|
|
|
{/* Review Text */}
|
|
<p className="text-gray-700 dark:text-gray-300 leading-relaxed mb-4 flex-grow">
|
|
"{item.quote}"
|
|
</p>
|
|
|
|
{/* Location Badge */}
|
|
<div className="pt-4 border-t border-gray-100 dark:border-gray-800">
|
|
<p className="text-sm text-gray-500 dark:text-gray-400 flex items-center gap-2">
|
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
|
|
</svg>
|
|
{item.location}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|