'use client'; import Image from 'next/image'; import { useState, useEffect, useRef } from 'react'; import styles from './Testimonials.module.css'; export default function Testimonials() { const [activeIndex, setActiveIndex] = useState(0); const [isResetting, setIsResetting] = useState(false); const timeoutRef = useRef(null); const testimonials = [ { name: 'Rahul Mehta', role: 'Growth Manager', reviewTitle: 'Highly Impressive Results!', text: 'The performance insights are extremely clear. We can now adjust campaigns quickly and make confident marketing decisions.', image: '/images/home/testimonial-1.webp' }, { name: 'Emily Carter', role: 'Content Strategist', reviewTitle: 'Smooth and Reliable Platform!', text: 'Managing posts feels effortless now. Planning content ahead of time has significantly improved our publishing consistency.', image: '/images/home/testimonial-2.webp' }, { name: 'Arjun Nair', role: 'Digital Consultant', reviewTitle: 'Excellent Tool for Teams!', text: 'Collaboration is seamless and approvals are faster. It has simplified how we handle multiple client accounts.', image: '/images/home/testimonial-3.webp' }, { name: 'Sophia Williams', role: 'Brand Manager', reviewTitle: 'Well Designed and Effective!', text: 'The interface is clean and easy to navigate. Tracking engagement across platforms has never been this simple.', image: '/images/home/testimonial-4.webp' }, { name: 'Daniel Rodrigues', role: ' Marketing Lead', reviewTitle: 'Strong Value for Growth!', text: 'The reporting features save us hours every week. Insights are easy to understand and useful for strategy planning.', image: '/images/home/testimonial-5.webp' }, ]; // Clone the first few items to create the infinite illusion // We need enough clones to fill the visible area. 4 is safe. const extendedTestimonials = [...testimonials, ...testimonials.slice(0, 4)]; const totalOriginal = testimonials.length; const [cardWidth, setCardWidth] = useState(352); const [containerMaxWidth, setContainerMaxWidth] = useState('100%'); useEffect(() => { const handleResize = () => { const width = window.innerWidth; if (width <= 480) { // Mobile: Card 260, Gap 16. Container Padding 32 (layout) setCardWidth(276); // Stride const available = width - 32; const stride = 276; const gap = 16; const count = Math.max(1, Math.floor((available + gap) / stride)); setContainerMaxWidth(count * stride - gap); } else if (width <= 1024) { // Tablet: Card 280, Gap 32. Container Padding 32 setCardWidth(312); // Stride const available = width - 32; const stride = 312; const gap = 32; const count = Math.max(1, Math.floor((available + gap) / stride)); setContainerMaxWidth(count * stride - gap); } else { // Desktop: Force 2 cards exactly per user request. // Card 320, Gap 32. // 2 Cards = 320*2 + 32 = 672. // Plus padding-left: 6rem (96px) defined in CSS for desktop layout. setCardWidth(352); // Stride setContainerMaxWidth(768); // 672 + 96 } }; // Initial call handleResize(); window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); useEffect(() => { const interval = setInterval(() => { handleNext(); }, 3000); return () => clearInterval(interval); }, [activeIndex, isResetting]); // Re-create interval if state changes to avoid stale closures, though functional update handles it. const handleNext = () => { if (isResetting) return; setActiveIndex((prev) => { // If already at totalOriginal, wait for reset effect if (prev >= totalOriginal) return prev; return prev + 1; }); }; // Handle seamless reset useEffect(() => { if (activeIndex === totalOriginal) { // We have just slid TO the first cloned item (visually identical to index 0) // Wait for transition to finish, then snap back to real 0 timeoutRef.current = setTimeout(() => { setIsResetting(true); // Disable transition setActiveIndex(0); // Jump to 0 // Re-enable transition after a brief moment to allow DOM update requestAnimationFrame(() => { requestAnimationFrame(() => { setIsResetting(false); }); }); }, 500); // Must match CSS transition duration } return () => { if (timeoutRef.current) clearTimeout(timeoutRef.current); }; }, [activeIndex, totalOriginal]); const slideNext = () => { if (isResetting) return; if (activeIndex >= totalOriginal) return; // Wait for reset setActiveIndex(prev => prev + 1); }; const slidePrev = () => { if (isResetting) return; if (activeIndex === 0) { // Jump to end clone without transition, then slide back setIsResetting(true); setActiveIndex(totalOriginal); requestAnimationFrame(() => { requestAnimationFrame(() => { setIsResetting(false); setActiveIndex(totalOriginal - 1); }); }); } else { setActiveIndex(prev => prev - 1); } }; return (
{/* Left Side Static Card - High Z-Index */}

Unlock Your Growth Opportunities

Connect with a global community of marketers and creators who have elevated their digital presence using Social Buddy. Real progress, real outcomes - getting started takes only a moment.

Unified Message Center
10,000+ Active Members
Unified Message Center
4.9/5 User Satisfaction
{/* Right Side Slider - Lower Z-Index, moves behind Left Card */}
{extendedTestimonials.map((t, i) => (
User

{t.name}

{t.role}
⭐⭐⭐⭐⭐
{t.reviewTitle}

{t.text}

))}
{/* Navigation Arrows */}
); }