Files
Landing/src/app/(landing)/home/sections/Testimonial.tsx
T
2026-10-06 02:00:11 -05:00

122 lines
4.4 KiB
TypeScript

"use client";
import { useState, useEffect } from "react";
import { motion, AnimatePresence } from "framer-motion";
import Loader from '@/app/(landing)/components/Loader';
import { useTestimonials } from '@/app/(landing)/home/services/testimonials';
import type { ThemeProps } from '@/app/(landing)/types/ui';
export const Testimonial = ({ isNavyBg }: ThemeProps) => {
const { data, isLoading } = useTestimonials();
const [current, setCurrent] = useState(0);
const testimonials = data ?? [];
useEffect(() => {
if (testimonials.length < 2) return;
const t = setInterval(
() => setCurrent((i) => (i + 1) % testimonials.length),
6000,
);
return () => clearInterval(t);
}, [testimonials.length]);
const item = testimonials[current];
const bg = isNavyBg ? "var(--background)" : "#f9f9f7";
const border = isNavyBg ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.08)";
const sub = isNavyBg ? "rgba(255,255,255,0.45)" : "#6a6866";
const text = isNavyBg ? "var(--foreground)" : "#0a0a0a";
if (!isLoading && testimonials.length === 0) return null; // sección se oculta si no hay testimonios
return (
<section
aria-label="Testimonios de clientes"
style={{ background: bg }}
className="px-8 py-24 md:px-14 transition-colors duration-500"
>
<div className="mx-auto max-w-4xl">
<div
aria-hidden="true"
className="mx-auto mb-8 flex h-12 w-12 items-center justify-center rounded-full"
style={{ background: "rgba(59,130,246,0.1)" }}
>
<svg width="20" height="20" viewBox="0 0 24 24" fill="#3b82f6">
<path d="M3 21c3 0 7-1 7-8V5c0-1.25-.756-2.017-2-2H4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2 1 0 1 0 1 1v1c0 1-1 2-2 2s-1 .008-1 1.031V20c0 1 0 1 1 1z" />
<path d="M15 21c3 0 7-1 7-8V5c0-1.25-.757-2.017-2-2h-4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2h.75c0 2.25.25 4-2.75 4v3c0 1 0 1 1 1z" />
</svg>
</div>
{isLoading ? (
<Loader className="py-12" />
) : (
<>
<AnimatePresence mode="wait">
<motion.div
key={current}
initial={{ opacity: 0, y: 16 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -16 }}
transition={{ duration: 0.5, ease: [0.22, 1, 0.36, 1] }}
className="text-center"
>
<blockquote>
<p
className="font-display font-bold leading-snug"
style={{
fontSize: "clamp(1.25rem, 2.5vw, 1.75rem)",
color: text,
letterSpacing: "-0.02em",
maxWidth: "36ch",
margin: "0 auto 2.5rem",
}}
>
"{item.quote}"
</p>
</blockquote>
<div className="flex flex-col items-center gap-1">
{item.author && (
<p
className="font-display font-bold"
style={{ color: text, fontSize: "0.95rem" }}
>
{item.author}
</p>
)}
<p
className="text-sm font-semibold"
style={{ color: "#3b82f6" }}
>
{item.company}
</p>
</div>
</motion.div>
</AnimatePresence>
{testimonials.length > 1 && (
<div className="flex justify-center gap-2 mt-10">
{testimonials.map((_, i) => (
<button
key={i}
onClick={() => setCurrent(i)}
style={{
width: i === current ? 24 : 8,
height: 8,
borderRadius: 20,
background: i === current ? "#3b82f6" : sub,
border: "none",
cursor: "pointer",
padding: 0,
transition: "width 300ms, background 300ms",
}}
aria-label={`Testimonio ${i + 1}`}
/>
))}
</div>
)}
</>
)}
</div>
</section>
);
};