2026-04-12 10:11:23 +02:00
|
|
|
import FacilitySearch from "@/app/FacilitySearch";
|
2026-04-26 11:29:35 +02:00
|
|
|
import type { FacilityRecord } from "@/app/facilityData";
|
|
|
|
|
import { fetchPublicFacilities } from "@/app/publicFacilities";
|
2026-04-28 07:42:49 +02:00
|
|
|
import { resolveSitePageSeo } from "@/app/pageSeo";
|
2026-04-12 22:07:51 +02:00
|
|
|
import {
|
|
|
|
|
createBreadcrumbJsonLd,
|
|
|
|
|
createCollectionPageJsonLd,
|
2026-04-18 09:00:16 +02:00
|
|
|
createItemListJsonLd,
|
2026-04-12 22:07:51 +02:00
|
|
|
createPageMetadata,
|
|
|
|
|
} from "@/app/seo";
|
2026-04-12 10:11:23 +02:00
|
|
|
|
2026-04-26 11:29:35 +02:00
|
|
|
export const revalidate = 900;
|
2026-04-12 10:11:23 +02:00
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
|
|
2026-04-28 13:53:00 +02:00
|
|
|
const fallbackPageTitle = "Alle norske golfbaner: Finn din neste runde på gress | TeeOff.no";
|
2026-04-28 07:42:49 +02:00
|
|
|
const fallbackPageDescription =
|
2026-04-28 13:53:00 +02:00
|
|
|
"Planlegg din neste golfrunde. Se komplett oversikt over alle norske golfbaner med oppdatert banestatus, greenfee-priser og kart på TeeOff.no.";
|
2026-04-12 22:07:51 +02:00
|
|
|
|
2026-04-28 07:42:49 +02:00
|
|
|
export async function generateMetadata() {
|
|
|
|
|
const seo = await resolveSitePageSeo("golfbaner", fallbackPageTitle, fallbackPageDescription);
|
2026-04-28 13:53:00 +02:00
|
|
|
const metadata = createPageMetadata({
|
2026-04-28 07:42:49 +02:00
|
|
|
title: seo.title,
|
|
|
|
|
description: seo.description,
|
|
|
|
|
path: "/golfbaner",
|
|
|
|
|
});
|
2026-04-28 13:53:00 +02:00
|
|
|
return {
|
|
|
|
|
...metadata,
|
|
|
|
|
alternates: {
|
|
|
|
|
canonical: "/",
|
|
|
|
|
},
|
|
|
|
|
};
|
2026-04-28 07:42:49 +02:00
|
|
|
}
|
2026-04-12 22:07:51 +02:00
|
|
|
|
2026-04-12 10:11:23 +02:00
|
|
|
export default async function GolfCoursesIndexPage() {
|
2026-04-28 07:42:49 +02:00
|
|
|
const seo = await resolveSitePageSeo("golfbaner", fallbackPageTitle, fallbackPageDescription);
|
2026-04-26 11:29:35 +02:00
|
|
|
const safeData = await fetchPublicFacilities<FacilityRecord>("search", revalidate);
|
2026-04-12 22:07:51 +02:00
|
|
|
const collectionJsonLd = createCollectionPageJsonLd({
|
2026-04-28 07:42:49 +02:00
|
|
|
name: seo.title,
|
|
|
|
|
description: seo.description,
|
2026-04-12 22:07:51 +02:00
|
|
|
path: "/golfbaner",
|
|
|
|
|
});
|
2026-04-18 09:00:16 +02:00
|
|
|
const itemListJsonLd = createItemListJsonLd({
|
2026-04-28 07:42:49 +02:00
|
|
|
name: seo.title,
|
2026-04-18 09:00:16 +02:00
|
|
|
path: "/golfbaner",
|
|
|
|
|
items: safeData
|
|
|
|
|
.filter((facility) => facility?.slug && facility?.name)
|
|
|
|
|
.map((facility) => ({
|
|
|
|
|
name: facility.name,
|
|
|
|
|
path: `/golfbaner/${facility.slug}`,
|
|
|
|
|
description: facility.description,
|
|
|
|
|
})),
|
|
|
|
|
});
|
2026-04-12 22:07:51 +02:00
|
|
|
const breadcrumbJsonLd = createBreadcrumbJsonLd([
|
|
|
|
|
{ name: "Hjem", path: "/" },
|
|
|
|
|
{ name: "Golfbaner", path: "/golfbaner" },
|
|
|
|
|
]);
|
2026-04-12 10:11:23 +02:00
|
|
|
|
|
|
|
|
return (
|
2026-04-12 22:07:51 +02:00
|
|
|
<>
|
|
|
|
|
<script
|
|
|
|
|
type="application/ld+json"
|
|
|
|
|
dangerouslySetInnerHTML={{ __html: JSON.stringify(collectionJsonLd) }}
|
|
|
|
|
/>
|
2026-04-18 09:00:16 +02:00
|
|
|
<script
|
|
|
|
|
type="application/ld+json"
|
|
|
|
|
dangerouslySetInnerHTML={{ __html: JSON.stringify(itemListJsonLd) }}
|
|
|
|
|
/>
|
2026-04-12 22:07:51 +02:00
|
|
|
<script
|
|
|
|
|
type="application/ld+json"
|
|
|
|
|
dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbJsonLd) }}
|
2026-04-12 10:11:23 +02:00
|
|
|
/>
|
2026-04-12 22:07:51 +02:00
|
|
|
<main className="site-shell min-h-screen">
|
2026-04-20 20:07:46 +02:00
|
|
|
<section className="mx-auto max-w-[1400px] px-4 pt-6 sm:px-6 sm:pt-8 lg:px-8 lg:pt-10">
|
|
|
|
|
<div className="mb-2 max-w-4xl">
|
|
|
|
|
<p className="mb-3 text-[11px] font-extrabold uppercase tracking-[0.3em] text-[#6FA786]">Golfbaner</p>
|
|
|
|
|
<h1 className="section-title text-4xl text-[#112015] sm:text-5xl lg:text-6xl">Golfbaner i Norge</h1>
|
|
|
|
|
<p className="mt-4 max-w-3xl text-base leading-8 text-[#617063]">
|
|
|
|
|
Filtrer norske golfbaner etter område, banestatus, antall hull og fasiliteter, og gå videre til hver baneprofil.
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
2026-04-12 22:07:51 +02:00
|
|
|
<FacilitySearch
|
|
|
|
|
initialFacilities={safeData}
|
2026-04-20 20:07:46 +02:00
|
|
|
variant="home"
|
|
|
|
|
hideTitleBlock
|
|
|
|
|
filterHeading="Filtrer golfbaner"
|
2026-04-12 22:07:51 +02:00
|
|
|
/>
|
|
|
|
|
</main>
|
|
|
|
|
</>
|
2026-04-12 10:11:23 +02:00
|
|
|
);
|
|
|
|
|
}
|