279 lines
9.9 KiB
JavaScript
279 lines
9.9 KiB
JavaScript
"use client";
|
||
import { sliderProps } from "@/utility/sliderProps";
|
||
import { useEffect, useState } from "react";
|
||
import Slider from "react-slick";
|
||
|
||
function TestimonialAbout() {
|
||
const [nav1, setNav1] = useState(null);
|
||
const [nav2, setNav2] = useState(null);
|
||
const [slider1, setSlider1] = useState(null);
|
||
const [slider2, setSlider2] = useState(null);
|
||
const [reviews, setReviews] = useState([]);
|
||
const [loading, setLoading] = useState(true);
|
||
const [expandedReview, setExpandedReview] = useState(null);
|
||
|
||
useEffect(() => {
|
||
setNav1(slider1);
|
||
setNav2(slider2);
|
||
}, [slider1, slider2]);
|
||
|
||
useEffect(() => {
|
||
async function loadReviews() {
|
||
try {
|
||
const res = await fetch("/api/reviews");
|
||
const data = await res.json();
|
||
const cleaned = (data.reviews || []).filter(r =>
|
||
(r.text || r.description || r.snippet || r.review_text || r.body || r.content) &&
|
||
r.rating >= 4
|
||
);
|
||
setReviews(cleaned);
|
||
} catch (error) {
|
||
console.error("About: Failed to fetch reviews", error);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
}
|
||
loadReviews();
|
||
}, []);
|
||
|
||
const displayedReviews = reviews.length > 0 && reviews.length < 3
|
||
? [...reviews, ...reviews, ...reviews]
|
||
: reviews;
|
||
|
||
function renderStars(rating) {
|
||
return [...Array(5)].map((_, i) => (
|
||
<i key={i} className={`fa fa-star ${i < rating ? "text-warning" : ""}`} style={{ marginRight: '5px' }}></i>
|
||
));
|
||
}
|
||
|
||
function getReviewText(r) {
|
||
return r.text || r.description || r.snippet || r.review_text || r.body || r.content || "";
|
||
}
|
||
|
||
function truncateText(text) {
|
||
return text.length > 150 ? text.substring(0, 150) + "..." : text;
|
||
}
|
||
|
||
function getProfileImage(r) {
|
||
const url = r.profile_photo_url || r.author_profile_photo_url || r.user?.thumbnail;
|
||
if (!url) return null;
|
||
return url.startsWith("http") ? url : `https://lh3.googleusercontent.com/${url}`;
|
||
}
|
||
|
||
function getInitials(name) {
|
||
if (!name) return "U";
|
||
return name.split(' ').map(n => n[0]).join('').substring(0, 2).toUpperCase();
|
||
}
|
||
|
||
const link = "https://www.google.com/maps/place/Shivas+Dosa+Restaurant/@43.4056825,-80.5035997,17z/data=!4m8!3m7!1s0x882bf579045db13b:0x258e9b3ccf2549d4!8m2!3d43.4056825!4d-80.5010248!9m1!1b1!16s%2Fg%2F11tj6q0n1j?entry=ttu&g_ep=EgoyMDI1MTIwOS4wIKXMDSoASAFQAw%3D%3D";
|
||
|
||
const thumbs = {
|
||
dots: false,
|
||
arrows: false,
|
||
speed: 800,
|
||
autoplay: true,
|
||
focusOnSelect: true,
|
||
slidesToShow: 3,
|
||
slidesToScroll: 1,
|
||
};
|
||
const slider = {
|
||
arrows: false,
|
||
dots: false,
|
||
infinite: false,
|
||
autoplay: true,
|
||
speed: 500,
|
||
fade: true,
|
||
slidesToShow: 1,
|
||
slidesToScroll: 1,
|
||
};
|
||
|
||
return (
|
||
<section className="testimonials-five rel z-1 py-130 rpy-100">
|
||
<div className="container rel">
|
||
<div className="row text-center justify-content-center">
|
||
<div className="col-xl-6 col-lg-7 col-md-8">
|
||
<div
|
||
className="section-title mb-50"
|
||
data-aos="fade-up"
|
||
data-aos-duration={1500}
|
||
data-aos-offset={50}
|
||
>
|
||
<span className="sub-title mb-5">Customer Feedback</span>
|
||
<h2>what our customer’s say us</h2>
|
||
</div>
|
||
{/* <Slider
|
||
asNavFor={nav1}
|
||
ref={(slider) => setSlider2(slider)}
|
||
{...sliderProps.testimonialsFiveAuthors}
|
||
className="testimonials-five-authors mb-20"
|
||
data-aos="fade-up"
|
||
data-aos-delay={50}
|
||
data-aos-duration={1500}
|
||
data-aos-offset={50}
|
||
>
|
||
<div className="testimonial-five-author-item">
|
||
<img
|
||
src="assets/images/testimonials/testi-author-five1.jpg"
|
||
alt="Author"
|
||
/>
|
||
</div>
|
||
<div className="testimonial-five-author-item">
|
||
<img
|
||
src="assets/images/testimonials/testi-author-five2.jpg"
|
||
alt="Author"
|
||
/>
|
||
</div>
|
||
<div className="testimonial-five-author-item">
|
||
<img
|
||
src="assets/images/testimonials/testi-author-five3.jpg"
|
||
alt="Author"
|
||
/>
|
||
</div>
|
||
<div className="testimonial-five-author-item">
|
||
<img
|
||
src="assets/images/testimonials/testi-author-five2.jpg"
|
||
alt="Author"
|
||
/>
|
||
</div>
|
||
</Slider> */}
|
||
<Slider
|
||
className="testimonials-five-content"
|
||
asNavFor={nav2}
|
||
ref={(slider) => setSlider1(slider)}
|
||
{...sliderProps.testimonialsFiveContent}
|
||
data-aos="fade-up"
|
||
data-aos-delay={100}
|
||
data-aos-duration={1500}
|
||
data-aos-offset={50}
|
||
>
|
||
{loading ? (
|
||
<div className="testimonial-five-item">
|
||
<div className="text text-center">Loading reviews...</div>
|
||
</div>
|
||
) : displayedReviews.length > 0 ? (
|
||
displayedReviews.map((r, index) => {
|
||
const fullText = getReviewText(r);
|
||
const isExpanded = expandedReview === index;
|
||
const profileImg = getProfileImage(r);
|
||
const name = r.user?.name || r.author_name || "Customer";
|
||
|
||
return (
|
||
<div key={index} className="testimonial-five-item">
|
||
<div className="google-review-header d-flex align-items-center mb-15">
|
||
<div className="google-avatar" style={{
|
||
width: '55px',
|
||
height: '55px',
|
||
minWidth: '55px',
|
||
borderRadius: '50%',
|
||
overflow: 'hidden',
|
||
background: '#f8f9fa',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
border: '1px solid #eee'
|
||
}}>
|
||
{profileImg ? (
|
||
<img
|
||
src={profileImg}
|
||
alt={name}
|
||
onError={(e) => (e.target.style.display = 'none')}
|
||
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
||
/>
|
||
) : (
|
||
<span style={{ fontSize: '18px', fontWeight: 'bold', color: '#555' }}>{getInitials(name)}</span>
|
||
)}
|
||
</div>
|
||
<div className="google-user-info" style={{ marginLeft: '15px', textAlign: 'left' }}>
|
||
<h4 className="google-name" style={{ fontSize: '18px', fontWeight: '700', margin: 0, color: '#333' }}>
|
||
{name}
|
||
</h4>
|
||
<div className="google-stars" style={{ fontSize: '14px', marginTop: '4px' }}>
|
||
{renderStars(r.rating)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div className="text" style={{ textAlign: 'left' }}>
|
||
{isExpanded ? fullText : truncateText(fullText)}
|
||
</div>
|
||
{fullText.length > 200 && (
|
||
<button
|
||
className="read-more-btn"
|
||
onClick={(e) => {
|
||
e.stopPropagation();
|
||
setExpandedReview(isExpanded ? null : index);
|
||
}}
|
||
style={{ textAlign: 'left', width: 'auto', padding: '10px 0 0 0' }}
|
||
>
|
||
{isExpanded ? "Read Less" : "Read More"}
|
||
</button>
|
||
)}
|
||
</div>
|
||
);
|
||
})
|
||
) : (
|
||
<div className="testimonial-five-item">
|
||
<div className="text text-center">No reviews available.</div>
|
||
</div>
|
||
)}
|
||
</Slider>
|
||
<div className="new-button pt-30">
|
||
<a href={link} className="theme-btn" target="_blank" rel="noopener noreferrer">
|
||
Review us on Google <i className="far fa-arrow-alt-right" />
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div className="testimonials-five-shapes">
|
||
<div
|
||
className="shape left"
|
||
data-aos="fade-left"
|
||
data-aos-delay={150}
|
||
data-aos-duration={1500}
|
||
data-aos-offset={50}
|
||
>
|
||
<img
|
||
src="/assets/images/about/fourth-section/left.webp"
|
||
alt="Left" loading="lazy"
|
||
/>
|
||
</div>
|
||
<div
|
||
className="shape right"
|
||
data-aos="fade-right"
|
||
data-aos-delay={150}
|
||
data-aos-duration={1500}
|
||
data-aos-offset={50}
|
||
>
|
||
<img
|
||
src="/assets/images/about/fourth-section/right.webp"
|
||
alt="right" loading="lazy"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div className="testimonials-shapes">
|
||
<div className="shape one-1">
|
||
<img
|
||
src="/assets/images/about/fourth-section/bottom.webp"
|
||
alt="Shape" loading="lazy"
|
||
/>
|
||
</div>
|
||
{/* <div className="shape three">
|
||
<img
|
||
src="/assets/images/about/fourth-section/testi-1.webp"
|
||
alt="Shape"
|
||
/>
|
||
</div> */}
|
||
<div className="shape four">
|
||
<img
|
||
src="/assets/images/about/fourth-section/chicken-right.webp"
|
||
alt="Shape" loading="lazy"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|
||
|
||
export default TestimonialAbout;
|
||
|