From 40b4434a7b0f1f56b606b1c9c64ef3ce89c98f9a Mon Sep 17 00:00:00 2001 From: ayrisdev Date: Tue, 2 Jun 2026 18:05:30 +0300 Subject: [PATCH] feat: i18n fixes, blog rename, footer cleanup, and contact info update - Rename /news route to /blog across all pages, links, and sitemap - Fix hardcoded English text in Experiences, QuoteSection, and Footer by wiring all content through the TR/EN dictionaries - Clean up Footer: remove non-existent page links, add contact column - Update contact info: new phone numbers, bilgi@ email, No:71 address, Instagram @ayrisapart link - Add suppressHydrationWarning to to silence browser-extension attribute mismatch errors - Add sizes prop to all fill-mode Next.js Image components Co-Authored-By: Claude Sonnet 4.6 --- .gitignore | 2 + app/[lang]/blog/NewsClient.tsx | 88 + app/[lang]/blog/[slug]/NewsDetailClient.tsx | 95 + app/[lang]/{news => blog}/[slug]/page.tsx | 22 +- app/[lang]/{news => blog}/page.tsx | 14 +- app/[lang]/contact/ContactClient.tsx | 11 +- app/[lang]/layout.tsx | 39 +- app/[lang]/news/NewsClient.tsx | 120 -- app/[lang]/news/[slug]/NewsDetailClient.tsx | 157 -- app/[lang]/page.tsx | 4 +- app/[lang]/suites/SuitesClient.tsx | 28 +- app/[lang]/suites/[id]/SuiteDetailClient.tsx | 91 +- app/sitemap.ts | 59 + components/CallToAction.tsx | 12 +- components/Experiences.tsx | 40 +- components/Footer.tsx | 47 +- components/Hero.tsx | 44 +- components/Navbar.tsx | 14 +- components/QuoteSection.tsx | 8 +- components/ShowcaseImage.tsx | 7 +- components/SuitesHighlights.tsx | 7 +- components/Welcome.tsx | 2 +- dictionaries/en.json | 166 +- dictionaries/tr.json | 164 +- lib/prisma.ts | 23 + next.config.ts | 7 + package-lock.json | 1834 +++++++++++++++++- package.json | 9 + prisma.config.ts | 15 + prisma/schema.prisma | 37 + prisma/seed.ts | 82 + public/llms.txt | 34 + public/pricing.md | 65 + public/robots.txt | 26 + 34 files changed, 2864 insertions(+), 509 deletions(-) create mode 100644 app/[lang]/blog/NewsClient.tsx create mode 100644 app/[lang]/blog/[slug]/NewsDetailClient.tsx rename app/[lang]/{news => blog}/[slug]/page.tsx (52%) rename app/[lang]/{news => blog}/page.tsx (64%) delete mode 100644 app/[lang]/news/NewsClient.tsx delete mode 100644 app/[lang]/news/[slug]/NewsDetailClient.tsx create mode 100644 app/sitemap.ts create mode 100644 lib/prisma.ts create mode 100644 prisma.config.ts create mode 100644 prisma/schema.prisma create mode 100644 prisma/seed.ts create mode 100644 public/llms.txt create mode 100644 public/pricing.md create mode 100644 public/robots.txt diff --git a/.gitignore b/.gitignore index 5ef6a52..62fcee8 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,5 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +/lib/generated/prisma diff --git a/app/[lang]/blog/NewsClient.tsx b/app/[lang]/blog/NewsClient.tsx new file mode 100644 index 0000000..5c5619a --- /dev/null +++ b/app/[lang]/blog/NewsClient.tsx @@ -0,0 +1,88 @@ +'use client' + +import { motion } from "framer-motion" +import Image from "next/image" +import Link from "next/link" + +export default function NewsClient({ lang, dict, posts }: { lang: string, dict: any, posts: any[] }) { + return ( +
+ {/* HEADER */} +
+
+ + {dict.news_page.title} + + + {dict.news_page.excerpt} + +
+
+ + {/* POSTS GRID */} +
+ {posts.length > 0 ? ( +
+ {posts.map((post, idx) => ( + + +
+ {post.image && ( + {post.title} + )} +
+ +
+
+ {post.author} + + {new Date(post.createdAt).toLocaleDateString(lang === 'tr' ? 'tr-TR' : 'en-US')} +
+ +

+ {post.title} +

+ +

+ {post.excerpt} +

+ +
+ {dict.news_page.read} + +
+
+ +
+ ))} +
+ ) : ( +
+

{lang === 'tr' ? 'Henüz yazı bulunmuyor.' : 'No stories found yet.'}

+
+ )} +
+
+ ) +} diff --git a/app/[lang]/blog/[slug]/NewsDetailClient.tsx b/app/[lang]/blog/[slug]/NewsDetailClient.tsx new file mode 100644 index 0000000..3d42636 --- /dev/null +++ b/app/[lang]/blog/[slug]/NewsDetailClient.tsx @@ -0,0 +1,95 @@ +'use client' + +import { motion } from "framer-motion" +import Image from "next/image" +import Link from "next/link" +import { ArrowLeft, Clock, User } from 'lucide-react' + +export default function NewsDetailClient({ lang, dict, post }: { lang: string, dict: any, post: any }) { + return ( +
+ {/* HEADER & IMAGE */} +
+
+ {/* Back Button */} + + + {lang === 'tr' ? 'Haberlere Dön' : 'Back to News'} + + +
+ +
+ + {post.author} +
+
+ + {new Date(post.createdAt).toLocaleDateString(lang === 'tr' ? 'tr-TR' : 'en-US')} +
+
+ + + {post.title} + +
+ + {post.image && ( + + {post.title} + + )} +
+
+ + {/* CONTENT */} +
+ +

+ {post.excerpt} +

+ +
+ {post.content} +
+
+ +
+ + {dict.footer.book} + + +
+
+
+ ) +} diff --git a/app/[lang]/news/[slug]/page.tsx b/app/[lang]/blog/[slug]/page.tsx similarity index 52% rename from app/[lang]/news/[slug]/page.tsx rename to app/[lang]/blog/[slug]/page.tsx index 4bb7821..4c3caf7 100644 --- a/app/[lang]/news/[slug]/page.tsx +++ b/app/[lang]/blog/[slug]/page.tsx @@ -1,14 +1,20 @@ import { getDictionary } from "@/dictionaries/get-dictionary" import NewsDetailClient from "./NewsDetailClient" +import { prisma } from "@/lib/prisma" +import { notFound } from "next/navigation" export async function generateMetadata({ params }: { params: Promise<{ lang: string, slug: string }> }) { const { lang, slug } = await params - const dict = await getDictionary(lang as 'en' | 'tr') - // Dynamic title based on slug if possible, or just section title + const post = await prisma.post.findUnique({ + where: { slug } + }) + + if (!post) return { title: 'Post Not Found' } + return { - title: `News - Ayris Apart`, - description: dict.news_page.excerpt, + title: `${post.title} - Ayris Apart`, + description: post.excerpt, } } @@ -16,5 +22,11 @@ export default async function NewsDetailPage({ params }: { params: Promise<{ lan const { lang, slug } = await params const dict = await getDictionary(lang as 'en' | 'tr') - return + const post = await prisma.post.findUnique({ + where: { slug } + }) + + if (!post) notFound() + + return } diff --git a/app/[lang]/news/page.tsx b/app/[lang]/blog/page.tsx similarity index 64% rename from app/[lang]/news/page.tsx rename to app/[lang]/blog/page.tsx index c85c1fa..aba7310 100644 --- a/app/[lang]/news/page.tsx +++ b/app/[lang]/blog/page.tsx @@ -1,5 +1,6 @@ import { getDictionary } from "@/dictionaries/get-dictionary" import NewsClient from "./NewsClient" +import { prisma } from "@/lib/prisma" export async function generateMetadata({ params }: { params: Promise<{ lang: string }> }) { const { lang } = await params @@ -14,5 +15,16 @@ export default async function NewsPage({ params }: { params: Promise<{ lang: str const { lang } = await params const dict = await getDictionary(lang as 'en' | 'tr') - return + // Fetch posts from database based on the selected language + const posts = await prisma.post.findMany({ + where: { + lang: lang, + published: true + }, + orderBy: { + createdAt: 'desc' + } + }) + + return } diff --git a/app/[lang]/contact/ContactClient.tsx b/app/[lang]/contact/ContactClient.tsx index 999dc10..da270da 100644 --- a/app/[lang]/contact/ContactClient.tsx +++ b/app/[lang]/contact/ContactClient.tsx @@ -70,9 +70,10 @@ export default function ContactClient({ lang, dict }: { lang: string, dict: any

{dict.contact.call.t}

+90 543 231 87 13

+

+90 554 376 51 03

{dict.contact.call.d}

- + {dict.contact.btn.call} @@ -91,10 +92,10 @@ export default function ContactClient({ lang, dict }: { lang: string, dict: any

{dict.contact.write.t}

-

hello@ayrisapart.com

+

bilgi@ayrisapart.com

{dict.contact.write.d}

- + {dict.contact.btn.mail} @@ -114,7 +115,7 @@ export default function ContactClient({ lang, dict }: { lang: string, dict: any

{dict.contact.wa.d}

- + {dict.contact.btn.wa} @@ -135,7 +136,7 @@ export default function ContactClient({ lang, dict }: { lang: string, dict: any

{dict.contact.ig.d}

- + {dict.contact.btn.ig} diff --git a/app/[lang]/layout.tsx b/app/[lang]/layout.tsx index cf42a68..07b1593 100644 --- a/app/[lang]/layout.tsx +++ b/app/[lang]/layout.tsx @@ -37,9 +37,46 @@ export default async function RootLayout({ const { lang } = await params; const dict = await getDictionary(lang as 'en' | 'tr'); + const jsonLd = { + "@context": "https://schema.org", + "@type": "Hotel", + "name": "Ayris Apart", + "description": dict.hero.desc, + "address": { + "@type": "PostalAddress", + "streetAddress": "Orta İskele Caddesi No:71", + "addressLocality": "Milas", + "addressRegion": "Muğla", + "postalCode": "48220", + "addressCountry": "TR" + }, + "geo": { + "@type": "GeoCoordinates", + "latitude": 37.037, + "longitude": 27.962 + }, + "url": "https://ayrisapart.com", + "telephone": "+90", + "image": "https://ayrisapart.com/logo.png", + "amenityFeature": [ + { "@type": "LocationFeatureSpecification", "name": "Free Wi-Fi", "value": true }, + { "@type": "LocationFeatureSpecification", "name": "Kitchen", "value": true }, + { "@type": "LocationFeatureSpecification", "name": "Air Conditioning", "value": true }, + { "@type": "LocationFeatureSpecification", "name": "Free Parking", "value": true } + ], + "checkinTime": "14:00", + "checkoutTime": "11:00" + }; + return ( - + +