Some checks failed
CI / Frontend Lint & Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Backend Lint (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
Deploy / Build & Push Images (push) Has been cancelled
Deploy / Deploy to Server (push) Has been cancelled
Deploy / Notify (push) Has been cancelled
88 lines
2.9 KiB
TypeScript
88 lines
2.9 KiB
TypeScript
import type { Metadata } from 'next'
|
|
import { notFound } from 'next/navigation'
|
|
import Script from 'next/script'
|
|
import { SITE_URL } from '@/lib/seo'
|
|
import BuyDomainClient from './BuyDomainClient'
|
|
import type { Listing } from './types'
|
|
|
|
async function fetchListing(slug: string): Promise<Listing | null> {
|
|
const baseUrl = (process.env.BACKEND_URL || process.env.NEXT_PUBLIC_SITE_URL || SITE_URL).replace(/\/$/, '')
|
|
const res = await fetch(`${baseUrl}/api/v1/listings/${encodeURIComponent(slug)}`, {
|
|
next: { revalidate: 60 },
|
|
})
|
|
if (res.status === 404) return null
|
|
if (!res.ok) throw new Error(`Failed to load listing: ${res.status}`)
|
|
return (await res.json()) as Listing
|
|
}
|
|
|
|
export async function generateMetadata({
|
|
params,
|
|
}: {
|
|
params: Promise<{ slug: string }>
|
|
}): Promise<Metadata> {
|
|
const { slug } = await params
|
|
const listing = await fetchListing(slug)
|
|
if (!listing) return { title: 'Listing not found | Pounce', robots: { index: false, follow: false } }
|
|
|
|
const title = listing.title ? `${listing.domain} — ${listing.title}` : `${listing.domain} — Verified Domain Listing`
|
|
const description =
|
|
listing.description ||
|
|
`Buy ${listing.domain} via Pounce Direct. DNS-verified seller, clean workflow, and secure transfer.`
|
|
|
|
return {
|
|
title,
|
|
description,
|
|
alternates: { canonical: `${SITE_URL}/buy/${listing.slug}` },
|
|
openGraph: {
|
|
title,
|
|
description,
|
|
url: `${SITE_URL}/buy/${listing.slug}`,
|
|
type: 'website',
|
|
},
|
|
}
|
|
}
|
|
|
|
export default async function BuyDomainPage({
|
|
params,
|
|
}: {
|
|
params: Promise<{ slug: string }>
|
|
}) {
|
|
const { slug } = await params
|
|
const listing = await fetchListing(slug)
|
|
if (!listing) notFound()
|
|
|
|
const schema = {
|
|
'@context': 'https://schema.org',
|
|
'@type': 'Product',
|
|
name: listing.domain,
|
|
description: listing.description || listing.title || `Domain ${listing.domain} listed on Pounce Direct.`,
|
|
url: `${SITE_URL}/buy/${listing.slug}`,
|
|
category: 'Domain Names',
|
|
offers: listing.asking_price
|
|
? {
|
|
'@type': 'Offer',
|
|
price: String(listing.asking_price),
|
|
priceCurrency: listing.currency || 'USD',
|
|
availability: 'https://schema.org/InStock',
|
|
url: `${SITE_URL}/buy/${listing.slug}`,
|
|
seller: {
|
|
'@type': 'Organization',
|
|
name: 'Pounce Direct',
|
|
},
|
|
}
|
|
: undefined,
|
|
additionalProperty: [
|
|
{ '@type': 'PropertyValue', name: 'dns_verified', value: listing.is_verified ? 'true' : 'false' },
|
|
{ '@type': 'PropertyValue', name: 'price_type', value: listing.price_type },
|
|
{ '@type': 'PropertyValue', name: 'allow_offers', value: listing.allow_offers ? 'true' : 'false' },
|
|
],
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<Script id="pounce-buy-schema" type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }} />
|
|
<BuyDomainClient initialListing={listing} />
|
|
</>
|
|
)
|
|
}
|