frontend.zweitmeinu.ng/src/app/fachbereiche/[slug]/page.tsx
CCS Admin 0e5c9808a8 fix: replace hardcoded content with CMS data
- Phone number: 10 locations now use CMS site-settings contact.phone
- ContactForm: service dropdown options from CMS services
- FAQ categories: display names derived from CMS services
- Footer: Top Fachbereiche column dynamic from CMS services
- SEO metadata: fachbereiche, faq, kontakt use generateMetadata()
- HomeCTA: converted to async server component, fetches settings
- Added phoneToHref() helper to payload-helpers.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 02:31:27 +00:00

219 lines
8.1 KiB
TypeScript

import type { Metadata } from "next"
import { notFound } from "next/navigation"
import { Container } from "@/components/ui/Container"
import { Button } from "@/components/ui/Button"
import { RichTextRenderer } from "@/components/ui/RichTextRenderer"
import { getLucideIcon } from "@/lib/icon-map"
import { getServices, getServiceBySlug, getSiteSettings } from "@/lib/api"
import { phoneToHref } from "@/lib/payload-helpers"
import { Phone, Mail, ArrowRight, Check } from "lucide-react"
export async function generateStaticParams() {
const services = await getServices()
return services.map((s) => ({ slug: s.slug }))
}
export async function generateMetadata({
params,
}: {
params: Promise<{ slug: string }>
}): Promise<Metadata> {
const { slug } = await params
const service = await getServiceBySlug(slug)
if (!service) return {}
return {
title: service.metaTitle || service.title,
description: service.metaDescription || service.shortDescription,
}
}
export default async function ServiceDetailPage({
params,
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = await params
const [service, settings] = await Promise.all([
getServiceBySlug(slug),
getSiteSettings(),
])
if (!service) notFound()
const Icon = getLucideIcon(service.icon)
const shortTitle = service.title.replace(/^Zweitmeinung\s+/, "")
const phone = settings?.contact?.phone || "0800 80 44 100"
return (
<>
{/* Hero */}
<section className="bg-gradient-to-br from-navy via-navy-dark to-[#001a2e] py-20 sm:py-28">
<Container size="md">
<div className="text-center">
<div className="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-white/10 text-white mb-6">
<Icon className="h-8 w-8" />
</div>
<p className="text-primary-light text-sm font-semibold mb-2">
Fachbereiche / {shortTitle}
</p>
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-bold text-white mb-6">
{service.title}
</h1>
<p className="text-white/60 text-lg max-w-2xl mx-auto mb-10">
{service.shortDescription}
</p>
<div className="flex flex-wrap justify-center gap-4">
<Button href={phoneToHref(phone)} variant="gold" size="lg">
<Phone className="h-4 w-4" />
Jetzt beraten lassen
</Button>
<Button href="#was-wir-tun" variant="outline" size="lg">
Mehr erfahren
<ArrowRight className="h-4 w-4" />
</Button>
</div>
</div>
</Container>
</section>
{/* Benefits grid from features[] */}
{service.features && service.features.length > 0 && (
<section className="py-20 bg-white">
<Container size="md">
<h2 className="text-2xl sm:text-3xl font-bold text-center text-navy mb-4">
Wann ist eine Zweitmeinung sinnvoll?
</h2>
<p className="text-text-muted text-center max-w-2xl mx-auto mb-12">
{service.shortDescription}
</p>
<div className="grid sm:grid-cols-2 gap-6">
{service.features.map((f) => {
const FeatureIcon = getLucideIcon(f.icon)
return (
<div
key={f.id || f.title}
className="bg-bg rounded-xl p-6 border border-border"
>
<FeatureIcon className="h-6 w-6 text-primary mb-3" />
<h3 className="font-bold text-navy mb-2">{f.title}</h3>
<p className="text-sm text-text-muted">{f.description}</p>
</div>
)
})}
</div>
</Container>
</section>
)}
{/* Checklist from detailSections[] */}
{service.detailSections && service.detailSections.length > 0 && (
<section id="was-wir-tun" className="py-20 bg-bg">
<Container size="md">
<h2 className="text-2xl sm:text-3xl font-bold text-center text-navy mb-3">
Was wir für Sie tun
</h2>
<p className="text-text-muted text-center mb-12">
Unser Leistungsumfang im Bereich {shortTitle}
</p>
<div className="space-y-4 max-w-2xl mx-auto">
{service.detailSections.map((item) => (
<div
key={item.id || item.title}
className="flex gap-4 bg-white rounded-xl p-5 border border-border"
>
<div className="shrink-0 w-8 h-8 rounded-full bg-gold/20 flex items-center justify-center">
<Check className="h-4 w-4 text-gold-hover" />
</div>
<div>
<h3 className="font-bold text-navy">{item.title}</h3>
<div className="text-sm text-text-muted mt-1">
<RichTextRenderer content={item.content as any} />
</div>
</div>
</div>
))}
</div>
</Container>
</section>
)}
{/* Full description (richText) */}
{service.description && (
<section className="py-20 bg-white">
<Container size="md">
<div className="prose prose-lg max-w-none text-text-muted">
<RichTextRenderer content={service.description as any} />
</div>
</Container>
</section>
)}
{/* Stats */}
<section className="py-16 bg-white border-y border-border">
<Container size="md">
<h2 className="text-2xl font-bold text-center text-navy mb-3">
Warum complex care solutions?
</h2>
<p className="text-text-muted text-center max-w-2xl mx-auto mb-12">
Unsere Expert:innen arbeiten unabhängig und ausschließlich im
Interesse der Patient:innen.
</p>
<div className="grid grid-cols-3 gap-8 text-center">
<div>
<div className="text-4xl sm:text-5xl font-bold text-gold">
500+
</div>
<p className="text-sm text-text-muted mt-1">
Medizinische Zweitmeinungen
</p>
</div>
<div>
<div className="text-4xl sm:text-5xl font-bold text-gold">
15+
</div>
<p className="text-sm text-text-muted mt-1">Jahre Erfahrung</p>
</div>
<div>
<div className="text-4xl sm:text-5xl font-bold text-gold">
95%
</div>
<p className="text-sm text-text-muted mt-1">
Patientenzufriedenheit
</p>
</div>
</div>
</Container>
</section>
{/* CTA */}
<section className="py-20 bg-bg">
<Container size="sm">
<div className="bg-white rounded-2xl p-8 sm:p-12 text-center border border-border shadow-sm">
<div className="inline-flex items-center justify-center w-14 h-14 rounded-2xl bg-primary/10 text-primary mb-6">
<Icon className="h-7 w-7" />
</div>
<h2 className="text-2xl sm:text-3xl font-bold text-navy mb-4">
Bereit für Ihre Zweitmeinung?
</h2>
<p className="text-text-muted mb-8">
Kontaktieren Sie uns für eine unabhängige, professionelle
Einschätzung im Bereich {shortTitle}.
</p>
<div className="flex flex-wrap justify-center gap-4">
<Button href={phoneToHref(phone)} variant="gold" size="lg">
<Phone className="h-4 w-4" />
{phone}
</Button>
<Button href="/kontakt" variant="secondary" size="lg">
<Mail className="h-4 w-4" />
E-Mail schreiben
</Button>
</div>
<p className="text-xs text-text-muted mt-4">
Kostenlos für gesetzlich und privat Versicherte
</p>
</div>
</Container>
</section>
</>
)
}