Files
marmarislocal/app/[locale]/[category]/page.tsx
T

186 lines
7.3 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.
import { getTranslations, setRequestLocale } from 'next-intl/server'
import { mockDb } from '@/lib/mockDb'
import ListingCard from '@/components/ListingCard'
import { Link } from '@/i18n/routing'
import { notFound } from 'next/navigation'
import { MapPin, SlidersHorizontal, Check } from 'lucide-react'
import LiveFilterForm from '@/components/LiveFilterForm'
import type { Metadata } from 'next'
import { basicMetadata } from '@/lib/seo'
interface PageProps {
params: Promise<{ locale: string, category: string }>
searchParams: Promise<{
search?: string
neighborhood?: string
price?: string
approved?: string
}>
}
export const dynamic = 'force-dynamic'
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
const { locale, category: categorySlug } = await params
const categories = await mockDb.getCategories()
const category = categories.find(c => c.slug === categorySlug)
if (!category) return {}
const name = locale === 'ru' ? category.nameRu : locale === 'en' ? category.nameEn : category.nameTr
const title =
locale === 'en'
? `${name} in Marmaris — Marmaris Local`
: locale === 'ru'
? `${name} в Мармарисе — Marmaris Local`
: `Marmaris ${name} Rehberi — Marmaris Local`
const description =
locale === 'en'
? `Browse the best ${name.toLowerCase()} in Marmaris, filtered by neighborhood and price — curated and locally approved.`
: locale === 'ru'
? `Лучшие места категории «${name}» в Мармарисе — с фильтрами по районам и ценам, проверено местными.`
: `Marmaris'teki en iyi ${name.toLowerCase()} listesi — mahalle ve fiyata göre filtrele, yerel onaylılardan seç.`
return basicMetadata(title, description)
}
export default async function DynamicCategoryPage({ params, searchParams }: PageProps) {
const { locale, category: categorySlug } = await params
setRequestLocale(locale)
const { search, neighborhood, price, approved } = await searchParams
const t = await getTranslations('categories')
const navT = await getTranslations('nav')
// Find Category Restoran
const categories = await mockDb.getCategories()
const currentCategory = categories.find(c => c.slug === categorySlug)
if (!currentCategory) notFound()
const categoryId = currentCategory?.id
// Get active neighborhoods for filter
const neighborhoods = await mockDb.getNeighborhoods()
// Selected filters
const selectedNeighborhoodId = neighborhood || undefined
const selectedPriceRange = price ? parseInt(price) : undefined
const isApprovedOnly = approved === 'true'
const listings = await mockDb.getListings({
categoryId,
neighborhoodId: selectedNeighborhoodId,
priceRange: selectedPriceRange,
isLocalApproved: isApprovedOnly ? true : undefined,
search: search
})
const getLocalizedName = (obj: any) => {
if (!obj) return ''
return locale === 'ru' ? obj.nameRu : locale === 'en' ? obj.nameEn : obj.nameTr
}
return (
<div className="flex-1 flex flex-col min-h-screen bg-stone text-ink">
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-10 flex-1">
{/* Header */}
<div className="mb-8">
<h1 className="text-3xl font-heading font-extrabold text-pine lowercase">
{getLocalizedName(currentCategory)}
</h1>
<p className="text-xs text-shutter font-mono uppercase tracking-wider mt-1">
marmaris local {listings.length} {locale === 'tr' ? 'sonuç' : locale === 'en' ? 'results' : 'результатов'}
</p>
</div>
{/* Filters Panel */}
<div className="bg-paper p-5 rounded-2xl border border-pine/8 shadow-sm mb-10">
<div className="flex items-center gap-2 mb-4 font-heading font-bold text-sm text-pine lowercase border-b border-dashed border-pine/8 pb-3">
<SlidersHorizontal className="w-4 h-4 text-turquoise" />
<span>filtreler</span>
</div>
<LiveFilterForm>
{/* Search Input */}
<div className="space-y-1.5">
<label className="block text-[11px] font-mono uppercase tracking-wider text-shutter">Arama</label>
<input
type="text"
name="search"
defaultValue={search || ''}
placeholder="İsim veya adres..."
className="w-full bg-stone border border-pine/10 rounded-xl px-3 py-2 text-xs focus:ring-1 focus:ring-turquoise outline-none"
/>
</div>
{/* Neighborhood select */}
<div className="space-y-1.5">
<label className="block text-[11px] font-mono uppercase tracking-wider text-shutter">{t('filterNeighborhood')}</label>
<select
name="neighborhood"
defaultValue={neighborhood || ''}
className="w-full bg-stone border border-pine/10 rounded-xl px-3 py-2 text-xs focus:ring-1 focus:ring-turquoise outline-none appearance-none"
>
<option value="">{t('allNeighborhoods')}</option>
{neighborhoods.map((n) => (
<option key={n.id} value={n.id}>
{getLocalizedName(n)}
</option>
))}
</select>
</div>
{/* Price range select */}
<div className="space-y-1.5">
<label className="block text-[11px] font-mono uppercase tracking-wider text-shutter">{t('filterPrice')}</label>
<select
name="price"
defaultValue={price || ''}
className="w-full bg-stone border border-pine/10 rounded-xl px-3 py-2 text-xs focus:ring-1 focus:ring-turquoise outline-none"
>
<option value="">{t('allPrices')}</option>
<option value="1"> (Ekonomik)</option>
<option value="2">₺₺ (Orta)</option>
<option value="3">₺₺₺ (Lüks)</option>
</select>
</div>
{/* Submit / Checkbox area */}
<div className="flex flex-col sm:flex-row items-stretch sm:items-center gap-4">
<label className="flex items-center gap-2 cursor-pointer select-none text-xs font-semibold py-2.5">
<input
type="checkbox"
name="approved"
value="true"
defaultChecked={isApprovedOnly}
className="rounded border-pine/10 text-turquoise focus:ring-turquoise w-4 h-4"
/>
<span className="text-pine">{t('filterApproved')}</span>
</label>
<div className="flex-1" />
</div>
</LiveFilterForm>
</div>
{/* Results */}
{listings.length === 0 ? (
<div className="bg-paper/50 rounded-2xl border border-dashed border-pine/12 p-12 text-center text-shutter">
<p className="text-sm font-medium">{t('noResults')}</p>
</div>
) : (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8">
{listings.map((listing) => (
<ListingCard key={listing.id} listing={listing} />
))}
</div>
)}
</main>
</div>
)
}