feat: integrate Instagram feed, handle Prisma gracefully, and adjust UI
This commit is contained in:
+85
-4
@@ -65,6 +65,33 @@ const testimonials = [
|
|||||||
import { getDictionary, Locale } from "./dictionaries";
|
import { getDictionary, Locale } from "./dictionaries";
|
||||||
import prisma from "@/lib/prisma";
|
import prisma from "@/lib/prisma";
|
||||||
|
|
||||||
|
async function getInstagramData() {
|
||||||
|
const url = 'https://instagram120.p.rapidapi.com/api/instagram/posts';
|
||||||
|
const options = {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'x-rapidapi-key': process.env.RAPIDAPI_KEY || '',
|
||||||
|
'x-rapidapi-host': 'instagram120.p.rapidapi.com',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
username: 'kitebeachakyaka',
|
||||||
|
maxId: ''
|
||||||
|
}),
|
||||||
|
next: { revalidate: 86400 }
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(url, options);
|
||||||
|
if (!res.ok) throw new Error('Instagram fetch failed');
|
||||||
|
const data = await res.json();
|
||||||
|
return data.result?.edges?.slice(0, 4).map((edge: any) => edge.node) || [];
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Instagram fetch error:", err);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default async function Home({ params }: { params: Promise<{ lang: string }> }) {
|
export default async function Home({ params }: { params: Promise<{ lang: string }> }) {
|
||||||
const { lang } = await params;
|
const { lang } = await params;
|
||||||
const dict = await getDictionary(lang as Locale);
|
const dict = await getDictionary(lang as Locale);
|
||||||
@@ -83,14 +110,14 @@ export default async function Home({ params }: { params: Promise<{ lang: string
|
|||||||
const activities = await prisma.activity.findMany({ where: { lang }, orderBy: { order: "asc" } });
|
const activities = await prisma.activity.findMany({ where: { lang }, orderBy: { order: "asc" } });
|
||||||
const events = await prisma.event.findMany({ where: { lang }, orderBy: { date: "asc" } });
|
const events = await prisma.event.findMany({ where: { lang }, orderBy: { date: "asc" } });
|
||||||
const dbFeatures = await prisma.feature.findMany({ where: { lang }, orderBy: { order: "asc" } });
|
const dbFeatures = await prisma.feature.findMany({ where: { lang }, orderBy: { order: "asc" } });
|
||||||
|
|
||||||
const aboutDb = await prisma.aboutSection.findUnique({ where: { lang } });
|
const aboutDb = await prisma.aboutSection.findUnique({ where: { lang } });
|
||||||
const aboutData = aboutDb || {
|
const aboutData = aboutDb || {
|
||||||
badge: lang === "en" ? "Our Story" : "Hikayemiz",
|
badge: lang === "en" ? "Our Story" : "Hikayemiz",
|
||||||
titleLine1: lang === "en" ? "In the" : "Doğanın",
|
titleLine1: lang === "en" ? "In the" : "Doğanın",
|
||||||
titleLine2: lang === "en" ? "Heart of Nature" : "Kalbinde",
|
titleLine2: lang === "en" ? "Heart of Nature" : "Kalbinde",
|
||||||
titleHighlight: lang === "en" ? "A Special Escape" : "Özel Bir Kaçış",
|
titleHighlight: lang === "en" ? "A Special Escape" : "Özel Bir Kaçış",
|
||||||
description1: lang === "en"
|
description1: lang === "en"
|
||||||
? "Located right on the banks of the Azmak River flowing into the crystal waters of the Gulf of Gokova, we are in a unique location where the wind never ceases."
|
? "Located right on the banks of the Azmak River flowing into the crystal waters of the Gulf of Gokova, we are in a unique location where the wind never ceases."
|
||||||
: "Gökova Körfezi'nin kristal sularına dökülen Azmak Nehri'nin hemen kıyısında, rüzgarın hiç eksik olmadığı eşsiz bir konumda yer alıyoruz.",
|
: "Gökova Körfezi'nin kristal sularına dökülen Azmak Nehri'nin hemen kıyısında, rüzgarın hiç eksik olmadığı eşsiz bir konumda yer alıyoruz.",
|
||||||
description2: lang === "en"
|
description2: lang === "en"
|
||||||
@@ -106,6 +133,7 @@ export default async function Home({ params }: { params: Promise<{ lang: string
|
|||||||
};
|
};
|
||||||
|
|
||||||
const displayFeatures = dbFeatures.length > 0 ? dbFeatures : defaultFeatures;
|
const displayFeatures = dbFeatures.length > 0 ? dbFeatures : defaultFeatures;
|
||||||
|
const instagramPosts = await getInstagramData();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col min-h-screen">
|
<div className="flex flex-col min-h-screen">
|
||||||
@@ -353,8 +381,8 @@ export default async function Home({ params }: { params: Promise<{ lang: string
|
|||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||||
{activities.length > 0 ? (
|
{activities.length > 0 ? (
|
||||||
activities.map((act, i) => (
|
activities.map((act, i) => (
|
||||||
<ScrollReveal
|
<ScrollReveal
|
||||||
key={act.id}
|
key={act.id}
|
||||||
className={i === 0 || i === 3 ? "md:col-span-2" : ""}
|
className={i === 0 || i === 3 ? "md:col-span-2" : ""}
|
||||||
delay={i * 50}
|
delay={i * 50}
|
||||||
>
|
>
|
||||||
@@ -468,6 +496,59 @@ export default async function Home({ params }: { params: Promise<{ lang: string
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{/* ──────────────────────────────────────────
|
||||||
|
INSTAGRAM FEED
|
||||||
|
────────────────────────────────────────── */}
|
||||||
|
{instagramPosts.length > 0 && (
|
||||||
|
<section className="py-28 bg-background">
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<ScrollReveal className="text-center mb-16">
|
||||||
|
<span className="inline-block text-accent text-xs tracking-[0.25em] uppercase font-semibold mb-4">
|
||||||
|
@kitebeachakyaka
|
||||||
|
</span>
|
||||||
|
<h2 className="font-serif text-5xl font-bold text-dark">Instagram</h2>
|
||||||
|
</ScrollReveal>
|
||||||
|
|
||||||
|
<ScrollReveal stagger className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-6">
|
||||||
|
{instagramPosts.map((post: any) => (
|
||||||
|
<a
|
||||||
|
key={post.id}
|
||||||
|
href={`https://instagram.com/p/${post.code}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="group block relative rounded-2xl overflow-hidden aspect-[4/5] border border-sand"
|
||||||
|
>
|
||||||
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
|
<img
|
||||||
|
src={post.image_versions2?.candidates[0]?.url}
|
||||||
|
alt={post.caption?.text?.substring(0, 100) || "Instagram post"}
|
||||||
|
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-700"
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-0 bg-dark/60 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex flex-col items-center justify-center text-white p-6 text-center">
|
||||||
|
<Icons.Camera className="w-8 h-8 mb-3" />
|
||||||
|
<p className="text-xs line-clamp-3">
|
||||||
|
{post.caption?.text}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</ScrollReveal>
|
||||||
|
|
||||||
|
<div className="text-center mt-12">
|
||||||
|
<a
|
||||||
|
href="https://instagram.com/kitebeachakyaka"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="inline-flex items-center gap-2 border-2 border-dark text-dark text-xs px-8 py-3.5 rounded-full font-bold uppercase tracking-widest hover:bg-dark hover:text-white transition-colors"
|
||||||
|
>
|
||||||
|
Bizi Takip Edin
|
||||||
|
<ArrowRight className="w-3.5 h-3.5" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* ──────────────────────────────────────────
|
{/* ──────────────────────────────────────────
|
||||||
TESTIMONIALS
|
TESTIMONIALS
|
||||||
────────────────────────────────────────── */}
|
────────────────────────────────────────── */}
|
||||||
|
|||||||
Reference in New Issue
Block a user