157 lines
8.1 KiB
TypeScript
157 lines
8.1 KiB
TypeScript
"use client";
|
|
import React, { useState, useEffect } from "react";
|
|
import Slider from "react-slick";
|
|
import GoogleReviewsBranding from "@/components/common/GoogleReviewsBranding";
|
|
|
|
const TestimonialsSection = () => {
|
|
const [reviews, setReviews] = useState<any[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
async function loadReviews() {
|
|
try {
|
|
const res = await fetch("/api/reviews");
|
|
const data = await res.json();
|
|
const cleaned = (data.reviews || []).filter((r: any) =>
|
|
(r.snippet || r.text || r.review_text || r.description || r.body || r.content)
|
|
);
|
|
setReviews(cleaned);
|
|
} catch (error) {
|
|
console.error("Failed to fetch reviews", error);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
loadReviews();
|
|
}, []);
|
|
|
|
const displayedReviews = reviews.length > 0 && reviews.length < 4
|
|
? [...reviews, ...reviews, ...reviews]
|
|
: reviews;
|
|
|
|
const settings = {
|
|
dots: true,
|
|
arrows: false,
|
|
infinite: displayedReviews.length > 2,
|
|
speed: 600,
|
|
slidesToShow: 2,
|
|
slidesToScroll: 1,
|
|
autoplay: true,
|
|
autoplaySpeed: 5000,
|
|
dotsClass: "testimonial-dot-inner",
|
|
responsive: [
|
|
{
|
|
breakpoint: 1200,
|
|
settings: {
|
|
slidesToShow: 2,
|
|
}
|
|
},
|
|
{
|
|
breakpoint: 991,
|
|
settings: {
|
|
slidesToShow: 1,
|
|
}
|
|
}
|
|
]
|
|
};
|
|
|
|
function getReviewText(r: any) {
|
|
return r.text || r.description || r.snippet || r.review_text || r.body || r.content || "";
|
|
}
|
|
|
|
function getProfileImage(r: any, index: number) {
|
|
const url = r.user?.thumbnail || r.profile_photo_url || r.author_profile_photo_url || r.user?.profile_photo_url || r.thumbnail || r.profile_picture || r.avatar || r.author_image;
|
|
if (!url) return `/assets/imgs/resources/testimonials-${(index % 2) + 1}.png`;
|
|
if (typeof url === 'string' && url.startsWith("http")) return url;
|
|
return `https://lh3.googleusercontent.com/${url}`;
|
|
}
|
|
|
|
return (
|
|
<section className="testimonials-two-section fix section-space-bottom">
|
|
<div className="container-fluid g-0">
|
|
<div className="row g-0">
|
|
<div className="col-xxl-4 col-xl-4 col-lg-12">
|
|
<div className="testimonials-video-area p-relative">
|
|
<figure className="image w-img"><img src="/assets/images/about/6/left.webp" alt="" /></figure>
|
|
{/* <div className="play-btn">
|
|
<div className="video_player_btn">
|
|
<a href="https://www.youtube.com/watch?v=eEzD-Y97ges" className="popup-video"><i className="fa-solid fa-play"></i></a>
|
|
</div>
|
|
</div> */}
|
|
</div>
|
|
</div>
|
|
<div className="col-xxl-8 col-xl-8 col-lg-12">
|
|
<div className="testimonials-two-area section-space-medium p-relative parallax-bg" style={{
|
|
backgroundImage: 'url(/assets/images/home/7/right.webp)',
|
|
backgroundSize: 'cover',
|
|
backgroundPosition: 'center'
|
|
}}>
|
|
<div className="section-overlay" style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', zIndex: 0 }}></div>
|
|
{/* <div className="shape-1" style={{ backgroundImage: "url(/assets/imgs/shapes/shape-36.png)", zIndex: 1 }}></div> */}
|
|
|
|
<div className="sec-title-wrapper" style={{ position: 'relative', zIndex: 2 }}>
|
|
<div className="sec-title">
|
|
<div className="sec-title__shape"></div>
|
|
<h6 className="sec-title__tagline">TESTIMONIALS</h6>
|
|
<h3 className="sec-title__title text-white">Our Client Feedback</h3>
|
|
<div className="space20"></div>
|
|
<div className="d-flex justify-content-start">
|
|
<GoogleReviewsBranding />
|
|
</div>
|
|
</div>
|
|
{/* <img src="https://bracketweb.com/pelocishtml/assets/images/shapes/text-shape-2.png" alt="" className="sec-title__text-shape" /> */}
|
|
</div>
|
|
|
|
<div className="testi-slider-wrapper" style={{ position: 'relative', zIndex: 2, marginTop: '70px' }}>
|
|
{loading ? (
|
|
<div className="text-center py-5">
|
|
<p className="text-white">Loading reviews from Google...</p>
|
|
</div>
|
|
) : displayedReviews.length > 0 ? (
|
|
<Slider {...settings}>
|
|
{displayedReviews.map((slide, index) => {
|
|
const profileImg = getProfileImage(slide, index);
|
|
const name = slide.user?.name || slide.author_name || "Valued Client";
|
|
const rating = slide.rating || 5;
|
|
return (
|
|
<div key={index} style={{ outline: 'none', padding: '10px 15px 40px 10px' }}>
|
|
<div className="testimonials-two-box-solid">
|
|
<div className="author-image-solid">
|
|
<img src={profileImg} alt={name} />
|
|
</div>
|
|
<div className="icon-quote-testi">
|
|
<i className="fa-solid fa-quote-right"></i>
|
|
</div>
|
|
<div className="content-solid">
|
|
<h4>{name}</h4>
|
|
<span className="tag">Verified Google Review</span>
|
|
<ul className="ratings-solid">
|
|
{[...Array(rating)].map((_, i) => (
|
|
<li key={i}><i className="fa-solid fa-star"></i></li>
|
|
))}
|
|
</ul>
|
|
<p>
|
|
"{getReviewText(slide)}"
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</Slider>
|
|
) : (
|
|
<div className="text-center py-5">
|
|
<p className="text-white">No reviews found.</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export default TestimonialsSection;
|