import type { Metadata } from 'next'; import Link from 'next/link'; import { notFound } from 'next/navigation'; import { Section } from '@/components/Section'; import { buildFallbackProperty, getPublishedPropertyBySlug } from '@/lib/properties'; import { site } from '@/lib/site'; export const dynamic = 'force-dynamic'; type PropertyPageProps = { params: Promise<{ slug: string; }>; }; function formatPounds(cents: number) { return new Intl.NumberFormat('en-GB', { style: 'currency', currency: 'GBP', maximumFractionDigits: 0, }).format(cents / 100); } function formatDate(date: Date) { return date.toISOString().slice(0, 10); } function formatReason(reason: string) { return reason .toLowerCase() .split('_') .map((chunk) => chunk.charAt(0).toUpperCase() + chunk.slice(1)) .join(' '); } function fallbackMetadata(slug: string) { const seeded = buildFallbackProperty(slug); if (!seeded) { return { title: site.name, description: site.description, }; } return { title: `${seeded.title} | ${site.name}`, description: seeded.summary, }; } export async function generateMetadata({ params }: PropertyPageProps): Promise { const { slug } = await params; try { const property = await getPublishedPropertyBySlug(slug); if (!property) { return fallbackMetadata(slug); } return { title: `${property.title} | ${site.name}`, description: property.summary, }; } catch { return fallbackMetadata(slug); } } export default async function PropertyDetailPage({ params }: PropertyPageProps) { const { slug } = await params; const property = (await getPublishedPropertyBySlug(slug)) ?? buildFallbackProperty(slug); if (!property) { notFound(); } const primaryImage = property.images[0] ?? null; const standardRate = property.pricingRules.find((rule) => !rule.validFrom && !rule.validTo) ?? property.pricingRules[0]; const seasonalRates = property.pricingRules.filter((rule) => rule.validFrom && rule.validTo); return ( <>

Property detail

{property.title}

{property.summary}

Check availability Ask a question first

Booking context

{standardRate ? `From ${formatPounds(standardRate.basePriceCents)} per night` : 'Price on request'}

{property.locationText}

Sleeps
{property.sleeps}
Bedrooms
{property.bedrooms}
Bathrooms
{property.bathrooms}
{property.images.map((image) => (
{image.altText}
))}

About this stay

{property.longDescription}

Amenities

    {property.amenities.map((item) => (
  • {item.amenity.name}
  • ))}

Stay policies and practical details

{property.minStayNights} Minimum nights
{property.checkInTime ?? '16:00'} Check-in
{property.checkOutTime ?? '10:00'} Check-out
{property.petsAllowed ? 'Allowed' : 'Not allowed'} Pets
); }