import { getTranslations, setRequestLocale } from 'next-intl/server' import { mockDb } from '@/lib/mockDb' import ListingCard from '@/components/ListingCard' import { notFound } from 'next/navigation' import Image from 'next/image' import { Link } from '@/i18n/routing' import { Phone, Globe, MapPin, Clock, Star, MessageSquare, Share2 } from 'lucide-react' import SaveButton from './SaveButton' import DetailTracker from './DetailTracker' import type { Metadata } from 'next' import { SITE_URL } from '@/lib/seo' interface DetailPageProps { params: Promise<{ locale: string; category: string; slug: string }> } export const dynamic = 'force-dynamic' export async function generateMetadata({ params }: DetailPageProps): Promise { const { locale, slug } = await params const listing = await mockDb.getListingBySlug(slug) if (!listing) return {} const name = locale === 'ru' ? listing.nameRu : locale === 'en' ? listing.nameEn : listing.nameTr const description = locale === 'ru' ? listing.descriptionRu : locale === 'en' ? listing.descriptionEn : listing.descriptionTr const title = `${name} — Marmaris Local` const image = listing.images?.[0]?.url return { title, description, openGraph: { title, description, url: `${SITE_URL}/${locale}/${listing.category?.slug || 'isletme'}/${listing.slug}`, siteName: 'Marmaris Local', type: 'website', ...(image ? { images: [{ url: image }] } : {}), }, twitter: { card: 'summary_large_image', title, description, }, } } export default async function ListingDetailPage({ params }: DetailPageProps) { const { locale, category, slug } = await params setRequestLocale(locale) const t = await getTranslations('detail') const listing = await mockDb.getListingBySlug(slug) if (!listing) { notFound() } // Fetch similar listings in same category (limit to 3, excluding current) const allCategoryListings = await mockDb.getListings({ categoryId: listing.categoryId }) const relatedListings = allCategoryListings .filter(l => l.id !== listing.id) .slice(0, 3) // Fetch newest 3 listings (excluding current) const allListings = await mockDb.getListings() const latestListings = allListings .filter(l => l.id !== listing.id) .slice(0, 3) // Fetch Instagram Feed Cache const instagramFeed = await mockDb.getInstagramFeedCacheByListingId(listing.id) const instagramPosts = instagramFeed?.posts ? (instagramFeed.posts as any[]) : [] // Localized values const name = locale === 'ru' ? listing.nameRu : locale === 'en' ? listing.nameEn : listing.nameTr const description = locale === 'ru' ? listing.descriptionRu : locale === 'en' ? listing.descriptionEn : listing.descriptionTr const priceSymbols = '₺'.repeat(listing.priceRange) const categorySlug = listing.category?.slug || 'isletme' const rawId = listing.id; // örn: "gm-ChIJY_2Q8tbJvxQRs7xwaSne0is" const hasGooglePlaceId = rawId.startsWith('gm-'); const placeId = hasGooglePlaceId ? rawId.replace('gm-', '') : null; // Format WhatsApp Link const getWhatsAppLink = (number: string) => { const cleanNum = number.replace(/\D/g, '') return `https://wa.me/${cleanNum}` } // WhatsApp Share deep link text const getShareLink = () => { const text = encodeURIComponent(`Marmaris Local'da harika bir yer keşfettim: ${name}\nDetayları incele: https://marmarislocal.com/${locale}/${categorySlug}/${listing.slug}`) return `https://wa.me/?text=${text}` } // schema.org LocalBusiness structured data const schemaTypeByCategory: Record = { restoran: 'Restaurant', apart: 'LodgingBusiness', isletme: 'LocalBusiness', } const jsonLd = { '@context': 'https://schema.org', '@type': schemaTypeByCategory[categorySlug] || 'LocalBusiness', name, description, image: listing.images?.map(img => img.url) || undefined, url: `https://marmarislocal.com/${locale}/${categorySlug}/${listing.slug}`, address: { '@type': 'PostalAddress', streetAddress: listing.address, addressLocality: 'Marmaris', addressCountry: 'TR', }, ...(listing.latitude && listing.longitude ? { geo: { '@type': 'GeoCoordinates', latitude: listing.latitude, longitude: listing.longitude } } : {}), ...(listing.phone ? { telephone: listing.phone } : {}), ...(listing.website ? { sameAs: [listing.website] } : {}), priceRange: priceSymbols || undefined, ...(listing.openingHours && (listing.openingHours as any).all ? { openingHours: (listing.openingHours as any).all } : {}), } return (