mirror of
https://github.com/complexcaresolutions/frontend.zweitmeinu.ng.git
synced 2026-03-17 16:13:48 +00:00
- 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>
219 lines
8.1 KiB
TypeScript
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>
|
|
</>
|
|
)
|
|
}
|