SocialBuddyMarketingWebsite/components/ChannelTestimonialSlider.tsx
2026-01-19 17:48:51 +05:30

116 lines
4.8 KiB
TypeScript

"use client";
import { useState, useEffect } from "react";
import styles from "@/app/channels/[slug]/channel-page.module.css";
import SafeImage from "./SafeImage";
import { Star, Quote } from "lucide-react";
interface Testimonial {
quote: string;
author: string;
role: string;
rating: number;
image: string;
}
export default function ChannelTestimonialSlider({ testimonials, staticImage }: { testimonials: Testimonial[], staticImage?: string }) {
const [currentIndex, setCurrentIndex] = useState(0);
const [isAnimating, setIsAnimating] = useState(false);
useEffect(() => {
const interval = setInterval(() => {
handleNext();
}, 5000); // 5 seconds per slide
return () => clearInterval(interval);
}, [testimonials.length]);
const handleNext = () => {
setIsAnimating(true);
setTimeout(() => {
setCurrentIndex((prev) => (prev + 1) % testimonials.length);
setIsAnimating(false);
}, 300);
};
const current = testimonials[currentIndex];
// Determine what image to show on the left
// If staticImage is provided, use it always.
// If not, use the current testimonial's image.
const leftImageSrc = staticImage || current.image;
// Only animate the left image if it is changing (i.e., no staticImage)
const leftImageClass = staticImage
? styles.sliderLeftImage
: `${styles.sliderLeftImage} ${isAnimating ? styles.fadeOut : styles.fadeIn}`;
return (
<div className={styles.channelTestimonialContainer}>
{/* Left Side: Large Image */}
<div className={leftImageClass}>
<div className={styles.sliderImageWrapper}>
<SafeImage
src={leftImageSrc}
alt={staticImage ? "Testimonial" : current.author}
className={styles.sliderMainImage}
fallbackSrc={`https://placehold.co/600x600/png?text=${encodeURIComponent(current.author)}`}
/>
{/* "Trusted Clients" Pill could go here, but user said "bottom img that no need"?
I'll add a simple name tag overlay if needed, but sticking to clean image first.
*/}
</div>
</div>
{/* Right Side: Content Box */}
<div className={styles.sliderRightContent}>
<div className={styles.testimonialCard}>
<div className={styles.testCardHeader}>
<Quote size={40} className={styles.quoteIcon} />
<div className={styles.testStars}>
{[...Array(5)].map((_, i) => (
<Star
key={i}
fill={i < current.rating ? "#fff" : "none"}
stroke={i < current.rating ? "#fff" : "rgba(255,255,255,0.4)"}
size={20}
/>
))}
</div>
</div>
<blockquote className={`${styles.testQuoteText} ${isAnimating ? styles.fadeOutText : styles.fadeInText}`}>
"{current.quote}"
</blockquote>
<div className={`${styles.testAuthorRow} ${isAnimating ? styles.fadeOutText : styles.fadeInText}`}>
<div className={styles.testAuthorAvatarWrapper}>
<SafeImage
key={currentIndex}
src={current.image}
alt={current.author}
className={styles.testSmallAvatar}
fallbackSrc={`https://placehold.co/100x100/png?text=${current.author.charAt(0)}`}
/>
</div>
<div className={styles.testAuthorInfoWhite}>
<h4>{current.author}</h4>
<span>{current.role}</span>
</div>
</div>
<div className={styles.sliderDotsWhite}>
{testimonials.map((_, idx) => (
<button
key={idx}
className={`${styles.dotWhite} ${idx === currentIndex ? styles.activeDotWhite : ""}`}
onClick={() => setCurrentIndex(idx)}
aria-label={`Go to slide ${idx + 1}`}
/>
))}
</div>
</div>
</div>
</div>
);
}