2026-01-10 18:47:08 +05:30

509 lines
24 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client'
import Footer from "@/components/Footer/Footer";
import FAQ from "@/components/FAQ/FAQ";
import Image from "next/image";
import Link from "next/link";
import styles from "./about.module.css";
import { featuresData, ctaData, aboutFaqData } from "@/utils/constant";
import Testimonials from "@/components/Testimonials/Testimonials";
import { useState, useEffect } from "react";
import { motion } from "framer-motion";
import { Swiper, SwiperSlide } from 'swiper/react';
import { Autoplay, Navigation } from 'swiper/modules';
import 'swiper/css';
import 'swiper/css/navigation';
import { FaStar, FaChevronLeft, FaChevronRight } from 'react-icons/fa';
interface Review {
text?: string;
description?: string;
snippet?: string;
review_text?: string;
body?: string;
content?: string;
rating: number;
profile_photo_url?: string;
author_profile_photo_url?: string;
user?: {
thumbnail?: string;
name?: string;
};
author_name?: string;
}
export default function AboutContent() {
const [reviews, setReviews] = useState<Review[]>([]);
const [loading, setLoading] = useState(true);
const [expandedReview, setExpandedReview] = useState<number | null>(null);
const [swiperInstance, setSwiperInstance] = useState<any>(null);
// Auto-collapse expanded review after 10 seconds and handle autoplay
useEffect(() => {
if (expandedReview !== null) {
// Stop autoplay when a review is expanded
if (swiperInstance && swiperInstance.autoplay) {
swiperInstance.autoplay.stop();
}
const timer = setTimeout(() => {
setExpandedReview(null);
}, 5000); // 10 seconds
return () => {
clearTimeout(timer);
};
} else {
// Resume autoplay when reviews are collapsed
if (swiperInstance && swiperInstance.autoplay) {
swiperInstance.autoplay.start();
}
}
}, [expandedReview, swiperInstance]);
// Animation variants
const fadeInUp = {
hidden: { opacity: 0, y: 30 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.6
}
}
};
const fadeIn = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: { duration: 0.8 }
}
};
const slideInLeft = {
hidden: { opacity: 0, y: 30 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.7
}
}
};
const slideInRight = {
hidden: { opacity: 0, y: 30 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.7
}
}
};
const staggerContainer = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.2,
delayChildren: 0.1
}
}
};
useEffect(() => {
async function loadReviews() {
try {
const res = await fetch("/api/reviews");
if (!res.ok) throw new Error("Failed to fetch");
const data = await res.json();
const cleaned = (data.reviews || []).filter((r: Review) =>
(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: number) {
return [...Array(5)].map((_, i) => (
<FaStar
key={i}
style={{ color: i < rating ? '#ffc107' : '#e4e5e9', fontSize: '1.2rem', marginRight: '2px' }}
/>
));
}
function getReviewText(r: Review) {
return r.text || r.description || r.snippet || r.review_text || r.body || r.content || "";
}
function truncateText(text: string) {
return text.length > 200 ? text.substring(0, 200) + "..." : text;
}
function getProfileImage(r: Review) {
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: string) {
if (!name) return "U";
return name.split(' ').map(n => n[0]).join('').substring(0, 2).toUpperCase();
}
return (
<main className={styles.main}>
{/* Hero Banner */}
<motion.section
className={styles.hero}
initial="hidden"
animate="visible"
variants={fadeIn}
>
<div className={styles.heroContent}>
<h1 className={styles.heroTitle}>About Us</h1>
<p className={styles.breadcrumb}>
<Link href="/" prefetch={false}>Home</Link> / About
</p>
</div>
</motion.section>
{/* About Section - No boxed structure */}
<section className={styles.section}>
<motion.div
className={styles.container}
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: "-100px" }}
variants={staggerContainer}
>
<motion.div className={styles.textBlock} variants={slideInLeft}>
<div className={styles.smallHeading} style={{ display: 'flex', alignItems: 'center', justifyContent: 'start', gap: '10px' }}>
<Image src="/images/dinner.png" alt="Our Story Decorative Dinner Icon" width={24} height={24} />
<span>ANTALYA</span>
<Image src="/images/eat.png" alt="Our Story Decorative Cutlery Icon" width={24} height={24} />
</div>
<h2 className={styles.sectionTitle}>Our Story</h2>
<p className={styles.text}>
Antalya began with a simple vision - to share the flavours, warmth, and culinary traditions of Turkey with our community. What started as a humble kitchen has grown into a beloved dining destination, celebrated for its hospitality, charcoal-grilled artistry, and authentic taste.
</p>
<p className={styles.text}>
From handcrafted dishes to time-honoured recipes passed through generations, every plate tells a story of heritage and passion. Our chefs blend tradition with refined technique, using the freshest ingredients to create experiences that feel familiar yet unforgettable.
</p>
<p className={styles.text}>
At Antalya, dining is more than a meal - it is a celebration of culture, flavour, and shared moments. We welcome you to discover the essence of Turkish hospitality and the rich culinary legacy we proudly nurture.
</p>
<Link href="/antalya-restaurant-menu" className={styles.menuButton} prefetch={false}>
VIEW OUR MENU
</Link>
</motion.div>
<motion.div className={styles.imageBlock} variants={slideInRight}>
<Image src="/images/about-us/our-story.webp" alt="Our Story" width={500} height={350} className={styles.image} />
</motion.div>
</motion.div>
</section>
{/* Features Section - With real images */}
<section className={`${styles.section} ${styles.featuresSection}`}>
<div className={styles.smallHeading} style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '10px' }}>
<Image src="/images/dinner.png" alt="Features Section Dinner Icon" width={24} height={24} />
<span>ANTALYA</span>
<Image src="/images/eat.png" alt="Features Section Cutlery Icon" width={24} height={24} />
</div>
<motion.h2
className={styles.sectionTitleCenter}
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
variants={fadeInUp}
>
What Sets Antalya Apart
</motion.h2>
<motion.div
className={styles.featuresGrid}
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: "-100px" }}
variants={staggerContainer}
>
{featuresData.map((feature) => (
<motion.div
key={feature.id}
className={styles.featureCard}
variants={fadeInUp}
whileHover={{ y: -5, transition: { duration: 0.3 } }}
>
<div className={styles.featureImageWrapper}>
<Image src={feature.image} alt={feature.title} fill className={styles.featureImage} />
</div>
<h3 className={styles.featureTitle}>{feature.title}</h3>
<p className={styles.featureDesc}>{feature.description}</p>
</motion.div>
))}
</motion.div>
</section>
{/* Why Choose Us Section */}
<section className={styles.section}>
<motion.div
className={styles.container}
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: "-100px" }}
variants={staggerContainer}
>
<motion.div className={styles.imageBlock} variants={slideInLeft}>
<Image src="/images/about-us/why-choose-us.webp" alt="Why Choose Us" width={500} height={350} className={styles.image} />
</motion.div>
<motion.div className={styles.textBlock} variants={slideInRight}>
<div className={styles.smallHeading} style={{ display: 'flex', alignItems: 'center', justifyContent: 'start', gap: '10px' }}>
<Image src="/images/dinner.png" alt="Why Choose Us Dinner Icon" width={24} height={24} />
<span>ANTALYA</span>
<Image src="/images/eat.png" alt="Why Choose Us Cutlery Icon" width={24} height={24} />
</div>
<h2 className={styles.sectionTitle}>Why Choose Us</h2>
<p className={styles.text}>
At Antalya Restaurant, we dont just serve meals - we curate meaningful dining moments. Our commitment to authenticity ensures that every ingredient, seasoning, and cooking method honours true Turkish culinary heritage.
</p>
<p className={styles.text}>
From our charcoal-grilled kebabs to handcrafted baklava, every dish is made with care to transport you to the bustling streets of Istanbul and the coastal charm of Antalya. We take pride in delivering warmth, flavour, and hospitality that make every visit unforgettable.
</p>
</motion.div>
</motion.div>
</section>
{/* Testimonials Section - Auto Slider */}
<section className={`${styles.section} ${styles.testimonialsSection}`}>
<div className={styles.smallHeading} style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '10px' }}>
<Image src="/images/dinner.png" alt="Testimonials Section Dinner Icon" width={24} height={24} />
<span>ANTALYA</span>
<Image src="/images/eat.png" alt="Testimonials Section Cutlery Icon" width={24} height={24} />
</div>
<h2 className={styles.sectionTitleCenter}>What Our Guests Say</h2>
<div className={styles.testimonialSlider}>
<button className={`${styles.sliderBtn} prev-btn`}>
<FaChevronLeft />
</button>
<div style={{ flex: 1, width: '100%' }}>
{loading ? (
<div className="text-center" style={{ color: '#F5E6D3', padding: '40px' , textAlign: 'center'}}>
<p>Loading reviews...</p>
</div>
) : (
<Swiper
spaceBetween={30}
slidesPerView={1}
loop={true}
navigation={{
prevEl: '.prev-btn',
nextEl: '.next-btn',
}}
autoplay={{
delay: 4000,
disableOnInteraction: false,
}}
onSwiper={setSwiperInstance}
modules={[Autoplay, Navigation]}
className="testimonial_list"
style={{ paddingBottom: '30px' }}
>
{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 (
<SwiperSlide key={index} style={{ height: 'auto' }}>
<div className={styles.testimonialCard}>
<div className={styles.testimonialAuthor}>
<div className={styles.authorImageWrapper}>
{profileImg ? (
<img
src={profileImg}
alt={name}
className={styles.authorImage}
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
onError={(e) => ((e.target as HTMLImageElement).src = '/images/placeholder.png')}
/>
) : (
<div style={{ width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#333', fontSize: '24px', fontWeight: 'bold', color: '#fff' }}>
{getInitials(name)}
</div>
)}
</div>
<div className={styles.authorInfo}>
<p className={styles.authorName}>{name}</p>
<div className={styles.stars} style={{ justifyContent: 'start', marginBottom: 0 }}>
{renderStars(r.rating)}
</div>
</div>
</div>
<p className={styles.testimonialText}>
&quot;{isExpanded ? fullText : truncateText(fullText)}&quot;
</p>
{fullText.length > 300 && (
<button
style={{ background: 'none', border: 'none', color: '#a67c52', cursor: 'pointer', fontWeight: 'bold', fontSize: '1rem', marginTop: '10px' }}
onClick={() => setExpandedReview(isExpanded ? null : index)}
>
{isExpanded ? "Read Less" : "Read More"}
</button>
)}
</div>
</SwiperSlide>
);
})}
</Swiper>
)}
</div>
<button className={`${styles.sliderBtn} next-btn`}>
<FaChevronRight />
</button>
</div>
<div className={styles.buttonContainer}>
<a
href="https://www.google.com/search?sca_esv=fb3147f266a54277&sxsrf=AE3TifPK9lVB_UK5Mt9ko4Ht65w63RgqUQ:1764431326889&si=AMgyJEtREmoPL4P1I5IDCfuA8gybfVI2d5Uj7QMwYCZHKDZ-E3A-qenJpQm2J1V3Wa6_UKYzIQhT0idJrAopWIgZ0RiDDHrNP0RtPpfTzWgU2637exPDNkEZu0WuVN4TEdgoYqqtQwcWsOUIFi4JvvmrZPyybRzrcg%3D%3D&q=Antalya+Turkish+Restaurant+Reviews&sa=X&ved=2ahUKEwic4uDz2peRAxUbTmwGHWwWBRoQ0bkNegQIJRAE&biw=1528&bih=786&dpr=1.25&zx=1764431335803&no_sw_cr=1#lrd=0x882bf532910f4e25:0x4aee10507689253d,3,,,,"
target="_blank"
rel="noopener noreferrer"
className={styles.button}
>
Review Us on Google
</a>
</div>
</section>
{/* FAQ Section - Image Left, FAQ Right */}
<section className={styles.faqSection}>
<motion.div
className={styles.faqContainer}
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: "-100px" }}
variants={staggerContainer}
>
<motion.div className={styles.faqImageBlock} variants={slideInLeft}>
<Image
src="/images/about-us/faq.webp"
alt="Frequently Asked Questions"
width={600}
height={700}
className={styles.faqImage}
/>
</motion.div>
<motion.div className={styles.faqContentBlock} variants={slideInRight}>
<div className={styles.smallHeading} style={{ display: 'flex', alignItems: 'center', justifyContent: 'start', gap: '10px' }}>
<Image src="/images/dinner.png" alt="FAQ Section Decorative Dinner Icon" width={24} height={24} />
<span>ANTALYA</span>
<Image src="/images/eat.png" alt="FAQ Section Decorative Cutlery Icon" width={24} height={24} />
</div>
<h2 className={styles.faqTitle}>FAQ Your Questions Answered</h2>
<p className={styles.faqSubtitle}>
Find helpful answers to common questions about dining at Antalya.
</p>
<div className={styles.faqAccordion}>
{aboutFaqData.map((faq, index) => (
<FaqItem key={index} question={faq.q} answer={faq.a} />
))}
</div>
</motion.div>
</motion.div>
</section>
{/* Call to Action */}
<motion.section
className={styles.ctaSection}
style={{ backgroundImage: `url(${ctaData.backgroundImage})` }}
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
variants={fadeIn}
>
<div className={styles.ctaOverlay}>
<div className={styles.smallHeading} style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '10px' }}>
<Image src="/images/dinner.png" alt="About CTA Dinner Icon" width={24} height={24} />
<span>ANTALYA</span>
<Image src="/images/eat.png" alt="About CTA Cutlery Icon" width={24} height={24} />
</div>
<motion.h2
className={styles.ctaTitle}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: 0.2 }}
>
{ctaData.title}
</motion.h2>
<motion.p
className={styles.ctaSubtitle}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: 0.4 }}
>
{ctaData.subtitle}
</motion.p>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: 0.6 }}
>
<Link href={ctaData.buttonLink} className={styles.ctaButton} prefetch={false}>
{ctaData.buttonText}
</Link>
</motion.div>
</div>
</motion.section>
<Footer />
</main>
);
}
// FAQ Item Component
function FaqItem({ question, answer }: { question: string; answer: string }) {
const [isOpen, setIsOpen] = useState(false);
return (
<div className={styles.faqItem}>
<button
className={`${styles.faqQuestion} ${isOpen ? styles.faqQuestionActive : ''}`}
onClick={() => setIsOpen(!isOpen)}
>
<span>{question}</span>
<span className={styles.faqIcon}>{isOpen ? '' : '+'}</span>
</button>
{isOpen && (
<div className={styles.faqAnswer}>
<p>{answer}</p>
</div>
)}
</div>
);
}