review integration updated
This commit is contained in:
parent
b0583a2c25
commit
1cf4f66833
43
app/api/reviews/route.js
Normal file
43
app/api/reviews/route.js
Normal file
@ -0,0 +1,43 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
export async function GET() {
|
||||
const apiKey = "37eb7f83988cfd76ffb5c5af9adc25652efe5607e39997fc7d0e054d690ef25e";
|
||||
const placeId = "ChIJO7FdBHn1K4gR1EklzzybjiU";
|
||||
|
||||
let allReviews = [];
|
||||
let nextPageToken = null;
|
||||
|
||||
try {
|
||||
let pageCount = 0;
|
||||
while (pageCount < 3) {
|
||||
pageCount++;
|
||||
const url = `https://serpapi.com/search.json?engine=google_maps_reviews&hl=en&api_key=${apiKey}&place_id=${placeId}${nextPageToken ? `&next_page_token=${nextPageToken}` : ""}`;
|
||||
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.error) {
|
||||
console.error("Reviews API Error:", data.error);
|
||||
break;
|
||||
}
|
||||
|
||||
if (data.reviews && data.reviews.length > 0) {
|
||||
allReviews = [...allReviews, ...data.reviews];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!data.serpapi_pagination || !data.serpapi_pagination.next_page_token) {
|
||||
break;
|
||||
}
|
||||
|
||||
nextPageToken = data.serpapi_pagination.next_page_token;
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
}
|
||||
|
||||
return NextResponse.json({ reviews: allReviews, total: allReviews.length });
|
||||
} catch (error) {
|
||||
console.error("Reviews API Unexpected Error:", error);
|
||||
return NextResponse.json({ error: "Failed to fetch reviews", details: error.message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
119
app/globals.css
119
app/globals.css
@ -131,3 +131,122 @@
|
||||
|
||||
|
||||
|
||||
|
||||
.google-review-card {
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 25px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05);
|
||||
border: 1px solid #f0f0f0;
|
||||
height: 100%;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.google-review-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.google-avatar {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
background: #546e7a;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
font-size: 24px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.google-avatar img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.google-user-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.google-name {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
margin: 0 !important;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.google-stars {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.google-stars span,
|
||||
.google-stars i {
|
||||
font-size: 16px;
|
||||
color: #ffc107;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.google-text {
|
||||
font-size: 15px;
|
||||
color: #eee;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.google-review-card-home {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.google-review-card-home .google-name {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.google-review-card-home .google-user-info h4 {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.google-review-card-home .testimonial-text {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
/* Ensure stars are visible on white background for About page */
|
||||
.testimonial-five-item .google-stars i {
|
||||
color: #ffc107 !important;
|
||||
}
|
||||
|
||||
.google-review-header .google-name {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.read-more-btn {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #ffb936;
|
||||
padding: 15px 0 0 0;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
display: block;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.read-more-btn:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.equal-height {
|
||||
min-height: 380px;
|
||||
}
|
||||
293
app/page.js
293
app/page.js
@ -10,7 +10,59 @@ import HeroBanner from "@/components/home/HeroBanner";
|
||||
import PopularMenu from "@/components/home/PopularMenu";
|
||||
import MenuCategory from "@/components/home/MenuCategory";
|
||||
import BlogSection from "@/components/home/BlogSection";
|
||||
import { useEffect, useState } from "react";
|
||||
const page = () => {
|
||||
const [reviews, setReviews] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [expandedReview, setExpandedReview] = useState(null);
|
||||
|
||||
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("Home: 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();
|
||||
}
|
||||
return (
|
||||
<WellFoodLayout>
|
||||
{/* Hero Area Start */}
|
||||
@ -346,168 +398,97 @@ const page = () => {
|
||||
data-aos-duration={1500}
|
||||
data-aos-offset={50}
|
||||
>
|
||||
<div className="testimonial-two-item style-two">
|
||||
<div className="content">
|
||||
<div className="icon">
|
||||
{/* <img
|
||||
src="/assets/images/about/fourth-section.testi-2.webp"
|
||||
alt=""
|
||||
/> */}
|
||||
<div className="d-flex gap-2">
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
</div>
|
||||
{loading ? (
|
||||
<div className="testimonial-two-item style-two">
|
||||
<div className="content">
|
||||
<div className="customer-review">Loading reviews...</div>
|
||||
</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";
|
||||
|
||||
</div>
|
||||
<div className="customer-review">
|
||||
The food was exceptional, with the dosas being a particular highlight and deserving of strong recommendation. Their taste was remarkable, representing the best dosas in the entire KWC region. The staff provided polite and attentive service. While the quantity of chutneys and sauces could be improved, the overall dining experience was highly satisfactory.
|
||||
</div>
|
||||
<span className="author">Mohit</span>
|
||||
{/* <span className="designation">web designer</span> */}
|
||||
</div>
|
||||
</div>
|
||||
<div className="testimonial-two-item style-two">
|
||||
<div className="content">
|
||||
<div className="icon">
|
||||
{/* <img
|
||||
src="/assets/images/about/fourth-section.testi-2.webp"
|
||||
alt=""
|
||||
/> */}
|
||||
<div className="d-flex gap-2">
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
return (
|
||||
<div key={index} className="testimonial-two-item style-two">
|
||||
<div className="content">
|
||||
<div className="google-review-card-home" style={{ background: 'transparent', padding: '10px 0' }}>
|
||||
<div className="google-review-header d-flex align-items-center" style={{ marginBottom: '15px' }}>
|
||||
<div className="google-avatar" style={{
|
||||
width: '55px',
|
||||
height: '55px',
|
||||
minWidth: '55px',
|
||||
borderRadius: '50%',
|
||||
overflow: 'hidden',
|
||||
background: '#eee',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
border: '1px solid #ddd'
|
||||
}}>
|
||||
{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' }}>
|
||||
<h4 className="google-name" style={{ fontSize: '18px', fontWeight: '700', margin: 0, color: '#fff', lineHeight: '1.2' }}>
|
||||
{name}
|
||||
</h4>
|
||||
<div className="google-stars" style={{ fontSize: '14px', marginTop: '4px', color: '#ffc107' }}>
|
||||
{renderStars(r.rating)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="testimonial-content">
|
||||
<div className="testimonial-text">
|
||||
<p style={{ color: '#fff' }}>
|
||||
{isExpanded ? fullText : truncateText(fullText)}
|
||||
</p>
|
||||
</div>
|
||||
{fullText.length > 200 && (
|
||||
<button
|
||||
className="read-more-btn mt-3"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setExpandedReview(isExpanded ? null : index);
|
||||
}}
|
||||
style={{ color: '#ffc107', textAlign: 'left', width: 'auto' }}
|
||||
>
|
||||
{isExpanded ? "Read Less" : "Read More"}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<div className="testimonial-two-item style-two">
|
||||
<div className="content">
|
||||
<div className="customer-review">No reviews available.</div>
|
||||
</div>
|
||||
<div className="customer-review">
|
||||
We had a delightful experience at Shivas Dosa. The service was exceptional, and the food was amazing.The Mysore Bonda and Chicken 65 reminded me of Bangalore, and the Mutton Chukka and Biryani were top-notch.A special mention for Rajatha's humble and attentive service. I truly appreciate their wonderful service and incredible food. Highly recommended!
|
||||
</div>
|
||||
<span className="author">Anoop V</span>
|
||||
{/* <span className="designation">web designer</span> */}
|
||||
</div>
|
||||
</div>
|
||||
<div className="testimonial-two-item style-two">
|
||||
<div className="content">
|
||||
<div className="icon">
|
||||
{/* <img
|
||||
src="/assets/images/about/fourth-section.testi-2.webp"
|
||||
alt=""
|
||||
/> */}
|
||||
<div className="d-flex gap-2">
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="customer-review">
|
||||
I ordered two party trays of Ambur chicken biryani and one tray of chicken 65. The price was very reasonable compared to other restaurants in Kitchener and Cambridge. The taste was absolutely delicious, and the Ambur-style biryani was flavorful and authentic. The chicken 65 was crispy and well-seasoned. The service provided by Pungulali was excellent. Highly recommend this place for great food at a great price!
|
||||
</div>
|
||||
<span className="author">Ramesh Babu Gnana Kandan</span>
|
||||
{/* <span className="designation">web designer</span> */}
|
||||
</div>
|
||||
</div>
|
||||
<div className="testimonial-two-item style-two">
|
||||
<div className="content">
|
||||
<div className="icon">
|
||||
{/* <img
|
||||
src="/assets/images/about/fourth-section.testi-2.webp"
|
||||
alt=""
|
||||
/> */}
|
||||
<div className="d-flex gap-2">
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="customer-review">
|
||||
I had a great experience at Shiva Dosa Point today! I ordered Sambhar Idli, Chicken Kothu Parotta, and Coffee, and everything was delicious. The flavors were authentic, and the food was served fresh and hot. A special mention to Poonguzhali and Swetha for their excellent service—they were friendly, attentive, and made the dining experience even better. Definitely recommend this place for anyone craving good South Indian food!
|
||||
</div>
|
||||
<span className="author">Murali Krishna</span>
|
||||
{/* <span className="designation">web designer</span> */}
|
||||
</div>
|
||||
</div>
|
||||
<div className="testimonial-two-item style-two">
|
||||
<div className="content">
|
||||
<div className="icon">
|
||||
{/* <img
|
||||
src="assets/images/about/fourth-section.testi-3.webp"
|
||||
alt=""
|
||||
/> */}
|
||||
<div className="d-flex gap-2">
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
<div className="pr-3">
|
||||
<i className="fa fa-star"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="customer-review">
|
||||
I had a wonderful experience at Shiva Dosa Restaurant! The food was absolutely delicious — authentic South Indian flavors served hot and fresh. We truly didn’t feel far from India. But what truly made our visit special was the outstanding service. A big thank you to Poonguzhali and Smriti, who were both incredibly attentive, kind, and professional throughout our meal. Their warm hospitality made us feel right at home. Highly recommend this place and their food.
|
||||
</div>
|
||||
<span className="author">Serah Benjamin</span>
|
||||
{/* <span className="designation">web designer</span> */}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Slider>
|
||||
<div className="new-button pt-30">
|
||||
<Link
|
||||
href="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"
|
||||
className="theme-btn"
|
||||
target="_blank"
|
||||
>
|
||||
Review us on Google <i className="far fa-arrow-alt-right" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-lg-4">
|
||||
|
||||
@ -8,10 +8,64 @@ function TestimonialAbout() {
|
||||
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,
|
||||
@ -92,43 +146,81 @@ function TestimonialAbout() {
|
||||
data-aos-duration={1500}
|
||||
data-aos-offset={50}
|
||||
>
|
||||
<div className="testimonial-five-item">
|
||||
<div className="text">
|
||||
The food was exceptional, with the dosas being a particular highlight and deserving of strong recommendation. Their taste was remarkable, representing the best dosas in the entire KWC region. The staff provided polite and attentive service. While the quantity of chutneys and sauces could be improved, the overall dining experience was highly satisfactory.
|
||||
{loading ? (
|
||||
<div className="testimonial-five-item">
|
||||
<div className="text text-center">Loading reviews...</div>
|
||||
</div>
|
||||
<span className="author">Mohit</span>
|
||||
{/* <span className="designation">Manager</span> */}
|
||||
</div>
|
||||
<div className="testimonial-five-item">
|
||||
<div className="text">
|
||||
We had a delightful experience at Shivas Dosa. The service was exceptional, and the food was amazing.The Mysore Bonda and Chicken 65 reminded me of Bangalore, and the Mutton Chukka and Biryani were top-notch.A special mention for Rajatha's humble and attentive service. I truly appreciate their wonderful service and incredible food. Highly recommended!
|
||||
</div>
|
||||
<span className="author">Anoop V</span>
|
||||
{/* <span className="designation">Manager</span> */}
|
||||
</div>
|
||||
<div className="testimonial-five-item">
|
||||
<div className="text">
|
||||
I ordered two party trays of Ambur chicken biryani and one tray of chicken 65. The price was very reasonable compared to other restaurants in Kitchener and Cambridge. The taste was absolutely delicious, and the Ambur-style biryani was flavorful and authentic. The chicken 65 was crispy and well-seasoned. The service provided by Pungulali was excellent. Highly recommend this place for great food at a great price!
|
||||
</div>
|
||||
<span className="author">Ramesh Babu Gnana Kandan</span>
|
||||
{/* <span className="designation">Manager</span> */}
|
||||
</div>
|
||||
<div className="testimonial-five-item">
|
||||
<div className="text">
|
||||
I had a great experience at Shiva Dosa Point today! I ordered Sambhar Idli, Chicken Kothu Parotta, and Coffee, and everything was delicious. The flavors were authentic, and the food was served fresh and hot. A special mention to Poonguzhali and Swetha for their excellent service—they were friendly, attentive, and made the dining experience even better. Definitely recommend this place for anyone craving good South Indian food!
|
||||
</div>
|
||||
<span className="author">Murali Krishna</span>
|
||||
{/* <span className="designation">Manager</span> */}
|
||||
</div>
|
||||
<div className="testimonial-five-item">
|
||||
<div className="text">
|
||||
I had a wonderful experience at Shiva Dosa Restaurant! The food was absolutely delicious — authentic South Indian flavors served hot and fresh. We truly didn’t feel far from India. But what truly made our visit special was the outstanding service. A big thank you to Poonguzhali and Smriti, who were both incredibly attentive, kind, and professional throughout our meal. Their warm hospitality made us feel right at home. Highly recommend this place and their food.
|
||||
</div>
|
||||
<span className="author">Serah Benjamin</span>
|
||||
{/* <span className="designation">Manager</span> */}
|
||||
</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">
|
||||
|
||||
@ -110,13 +110,13 @@ export const sliderProps = {
|
||||
testimonialsTwoCarousel: {
|
||||
slidesToShow: 1,
|
||||
slidesToScroll: 1,
|
||||
infinite: false,
|
||||
infinite: true,
|
||||
speed: 400,
|
||||
arrows: false,
|
||||
dots: true,
|
||||
fade: true,
|
||||
focusOnSelect: true,
|
||||
autoplay: false,
|
||||
autoplay: true,
|
||||
autoplaySpeed: 5000,
|
||||
},
|
||||
clientActive: {
|
||||
@ -232,13 +232,13 @@ export const sliderProps = {
|
||||
testimonialsFiveContent: {
|
||||
slidesToShow: 1,
|
||||
slidesToScroll: 1,
|
||||
infinite: false,
|
||||
infinite: true,
|
||||
speed: 400,
|
||||
arrows: false,
|
||||
dots: true,
|
||||
fade: true,
|
||||
focusOnSelect: true,
|
||||
autoplay: false,
|
||||
autoplay: true,
|
||||
autoplaySpeed: 5000,
|
||||
},
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user