import type { Metadata } from "next"; import { notFound, permanentRedirect, redirect } from "next/navigation"; import { PageHeader } from "@/components/PageHeader"; import { Section } from "@/components/Section"; import { ImagePlaceholder } from "@/components/ImagePlaceholder"; import { RichText } from "@/components/RichText"; import { CTA } from "@/components/CTA"; import { BookingWidget } from "@/components/booking/BookingWidget"; import { GroupRegistrationForm } from "@/components/GroupRegistrationForm"; import { getOfferBySlug } from "@/lib/payload/content"; import { moodForOffer } from "@/lib/angebote"; import { mediaAlt, mediaUrl } from "@/lib/payload/media"; import { OFFER_CATEGORIES } from "@/collections/Offers"; import { getCurrentCustomer } from "@/lib/auth/customer"; import { getSEOSettingsGlobal } from "@/lib/payload/globals"; import { resolveSeo } from "@/lib/seo/resolve"; import { buildMetadata } from "@/lib/seo/metadata"; import { getSiteUrl } from "@/lib/seo/config"; import { excerptFromRichText } from "@/lib/seo/textExcerpt"; import { JsonLd, serviceJsonLd } from "@/lib/seo/jsonld"; import { resolveRedirect } from "@/lib/seo/redirects"; import { siteConfig } from "@/lib/site"; export const dynamic = "force-dynamic"; type Args = { params: Promise<{ slug: string }> }; const WEEKDAY_LABELS: Record = { monday: "Montag", tuesday: "Dienstag", wednesday: "Mittwoch", thursday: "Donnerstag", friday: "Freitag", saturday: "Samstag", sunday: "Sonntag" }; async function resolveOfferOrRedirect(slug: string) { const offer = await getOfferBySlug(slug); if (offer) return offer; const match = await resolveRedirect(`/angebote/${slug}`); if (match) { if (match.permanent) permanentRedirect(match.to); redirect(match.to); } return null; } export async function generateMetadata({ params }: Args): Promise { const { slug } = await params; const [offer, seoSettings] = await Promise.all([getOfferBySlug(slug), getSEOSettingsGlobal()]); if (!offer) return {}; const resolved = resolveSeo({ seo: offer.seo, fallbackTitle: `${offer.title} – ${siteConfig.name}`, fallbackDescription: () => offer.shortDescription, fallbackImage: offer.image, defaultOgImage: seoSettings.defaultOgImage, }); return buildMetadata({ title: resolved.title, description: resolved.description, path: `/angebote/${offer.slug}`, ogImageUrl: resolved.ogImageUrl, keywords: resolved.keywords, // Private single-session offers (e.g. "Einzelbegleitung") stay reachable // via their direct link but must never be indexed or listed. noindex: offer.visibility === "private", }); } export default async function OfferDetailPage({ params }: Args) { const { slug } = await params; const offer = await resolveOfferOrRedirect(slug); if (!offer) notFound(); const categoryLabel = OFFER_CATEGORIES.find((c) => c.value === offer.category)?.label; const customer = offer.bookable ? await getCurrentCustomer() : null; const siteUrl = await getSiteUrl(); return ( <> {offer.visibility !== "private" && ( )}
{(offer.price || offer.durationMinutes) && (
{offer.price && (
Preis {offer.price}
)} {offer.durationMinutes && (
Dauer {offer.durationMinutes} Minuten
)}
)}
{offer.bookingMode === "group" ? (

Für die Gruppe anmelden

{offer.groupInfo &&

{offer.groupInfo}

} {offer.groupSchedule && (

Fester Termin

{offer.groupSchedule.recurrence === "monthly" ? "Monatlich" : "Wöchentlich"}{offer.groupSchedule.weekday ? ` · ${WEEKDAY_LABELS[offer.groupSchedule.weekday] ?? offer.groupSchedule.weekday}` : ""}{offer.groupSchedule.startTime ? ` · ${offer.groupSchedule.startTime}` : ""}{offer.groupSchedule.endTime ? `–${offer.groupSchedule.endTime}` : ""}

)} {offer.groupCapacity &&

Plätze: {offer.groupCapacity}

} {offer.registrationDeadline &&

Anmeldung möglich bis {new Date(offer.registrationDeadline).toLocaleDateString("de-DE")}

}
) : offer.bookable ? (

Termin auswählen

) : ( )} ); }