import React from 'react'; import { Link, useParams, Navigate } from '@/spa/router'; import { Trophy, ArrowLeft, MapPin, Building2, Globe, ChevronRight, Download, ChevronLeft, X } from 'lucide-react'; import { WINNERS } from '@/spa/data/winners'; import { useCmsRoute } from '@/spa/cmsRoute'; import { docImageUrl, mediaAlt, mediaUrl } from '@/spa/cmsMediaField'; import { useIsMobile } from '@/spa/hooks/useIsMobile'; import { preistraegerDetailContent } from '@/spa/preistraegerDetailContent'; import { usePreistraegerPlaceholderImage } from '@/spa/preistraegerPlaceholder'; import Image from '@/spa/components/ui/UnoptimizedImage' const FF = '"IBM Plex Sans", sans-serif'; const FB = '"Inter", sans-serif'; const NAVY = '#111D55'; const GOLD = '#EFBF04'; const BORDER = '#D0D5DD'; const GRAY = '#666666'; const BG_ALT = '#E4E2E3'; type PreistraegerDetailCms = Partial & { fallbackImage?: unknown sideImage?: Partial & { image?: unknown } } type GalleryImageCms = { id?: string | null image?: unknown imageAlt?: string | null caption?: string | null } type PreistraegerGalleryCms = { enabled?: boolean | null heading?: string | null description?: string | null images?: GalleryImageCms[] | null } const fallbackText = (value: unknown, fallback: string) => typeof value === 'string' && value.length > 0 ? value : fallback; const mediaFilename = (media: unknown) => { if (!media || typeof media !== 'object') return undefined; const filename = (media as { filename?: unknown }).filename; return typeof filename === 'string' && filename.length > 0 ? filename : undefined; }; export default function PreistraegerDetail() { const { slug } = useParams<{ slug: string }>(); const route = useCmsRoute(); const placeholderImage = usePreistraegerPlaceholderImage(); const cmsWinner = route?.collection === 'preistraeger' ? route.doc : undefined; const cmsDetail = { ...preistraegerDetailContent, ...((cmsWinner?.detailPage || {}) as PreistraegerDetailCms), } as PreistraegerDetailCms; const fallbackWinner = cmsDetail.fallbackWinner || preistraegerDetailContent.fallbackWinner; const cmsWinnerIsGoldeneBavaria = cmsWinner?.awardGroup === 'goldene-bavaria'; const winner = cmsWinner ? { id: String(cmsWinner.id), slug: String(cmsWinner.slug || slug), name: String(cmsWinner.title || fallbackWinner.name || preistraegerDetailContent.fallbackWinner.name), category: String(cmsWinner.category || fallbackWinner.category || preistraegerDetailContent.fallbackWinner.category), year: Number(cmsWinner.year || new Date().getFullYear()), type: String(cmsWinner.awardType || (cmsWinnerIsGoldeneBavaria ? 'Goldene Bavaria' : fallbackWinner.awardType) || preistraegerDetailContent.fallbackWinner.awardType), img: docImageUrl(cmsWinner, placeholderImage), shortDesc: String(cmsWinner.shortDesc || cmsWinner.description || cmsWinner.meta?.description || ''), longDesc: String(cmsWinner.longDesc || cmsWinner.description || cmsWinner.meta?.description || fallbackWinner.longDesc || preistraegerDetailContent.fallbackWinner.longDesc), quote: String(cmsWinner.quote || fallbackWinner.quote || preistraegerDetailContent.fallbackWinner.quote), quotePerson: String(cmsWinner.quotePerson || cmsWinner.title || fallbackWinner.quotePerson || preistraegerDetailContent.fallbackWinner.quotePerson), quoteRole: String(cmsWinner.quoteRole || fallbackWinner.quoteRole || preistraegerDetailContent.fallbackWinner.quoteRole), location: String(cmsWinner.location || fallbackWinner.location || preistraegerDetailContent.fallbackWinner.location), industry: String(cmsWinner.industry || fallbackWinner.industry || preistraegerDetailContent.fallbackWinner.industry), website: String(cmsWinner.website || '#'), hasMedia: Boolean(cmsWinner.hasMedia), detailPage: (cmsWinner.detailPage || {}) as PreistraegerDetailCms, } : WINNERS.find(w => w.slug === slug); const isMobile = useIsMobile(); const detail = (winner && 'detailPage' in winner ? { ...preistraegerDetailContent, ...(winner.detailPage || {}) } : cmsDetail) as PreistraegerDetailCms; const breadcrumb = { ...preistraegerDetailContent.breadcrumb, ...(detail.breadcrumb || {}) }; const sections = { ...preistraegerDetailContent.sections, ...(detail.sections || {}) }; const sideImage = { ...preistraegerDetailContent.sideImage, ...(detail.sideImage || {}) }; const facts = { ...preistraegerDetailContent.facts, ...(detail.facts || {}) }; const websiteCta = { ...preistraegerDetailContent.websiteCta, ...(detail.websiteCta || {}) }; const backLink = { ...preistraegerDetailContent.backLink, ...(detail.backLink || {}) }; const downloadHref = mediaUrl(cmsWinner?.downloadZip, ''); const downloadFilename = mediaFilename(cmsWinner?.downloadZip); const downloadLabel = fallbackText(cmsWinner?.downloadLabel, 'Pressepaket herunterladen'); const gallery = (cmsWinner?.gallery || {}) as PreistraegerGalleryCms; const galleryImages = Array.isArray(gallery.images) ? gallery.images .map((item) => ({ id: item.id || mediaFilename(item.image) || String(mediaUrl(item.image, '')), src: mediaUrl(item.image, ''), alt: mediaAlt(item.image, fallbackText(item.imageAlt, fallbackText(item.caption, winner?.name || 'Galeriebild'))), caption: fallbackText(item.caption, ''), })) .filter((item) => item.src) : []; const [activeGalleryIndex, setActiveGalleryIndex] = React.useState(undefined); const activeGalleryImage = typeof activeGalleryIndex === 'number' ? galleryImages[activeGalleryIndex] : undefined; const showGallery = Boolean(gallery.enabled) && galleryImages.length > 0; if (!winner) return ; return (
{/* Hero */}
{winner.name}
{/* Breadcrumb */}
{fallbackText(breadcrumb.label, preistraegerDetailContent.breadcrumb.label)} {winner.name}
{/* Header block */}
{winner.category} {winner.year} {winner.type}

{winner.name}

{winner.shortDesc}

{/* Content 2-col */}
{/* Left: Text */}

{fallbackText(sections.companyHeading, preistraegerDetailContent.sections.companyHeading)}

{winner.longDesc}

{fallbackText(sections.juryHeading, preistraegerDetailContent.sections.juryHeading)}

{fallbackText(sections.juryTextBeforeName, preistraegerDetailContent.sections.juryTextBeforeName)} {winner.name} {fallbackText(sections.juryTextAfterNameBeforeCategory, preistraegerDetailContent.sections.juryTextAfterNameBeforeCategory)} {winner.category}. {fallbackText(sections.juryTextAfterCategory, preistraegerDetailContent.sections.juryTextAfterCategory)}

{/* Quote */}

“ {winner.quote} ”

– {winner.quotePerson}, {winner.quoteRole}

{/* Right: Photo + Info box */}
{/* Photo */}
{mediaAlt(sideImage.image,
{/* Kenndaten */}

{fallbackText(facts.heading, preistraegerDetailContent.facts.heading)}

{[ { label: fallbackText(facts.categoryLabel, preistraegerDetailContent.facts.categoryLabel), value: winner.category, icon: }, { label: fallbackText(facts.awardLabel, preistraegerDetailContent.facts.awardLabel), value: winner.type, icon: }, { label: fallbackText(facts.yearLabel, preistraegerDetailContent.facts.yearLabel), value: String(winner.year), icon: null }, { label: fallbackText(facts.locationLabel, preistraegerDetailContent.facts.locationLabel), value: winner.location, icon: }, { label: fallbackText(facts.industryLabel, preistraegerDetailContent.facts.industryLabel), value: winner.industry, icon: }, ].map(row => (
{row.label} {row.value}
))}
{/* Website button */} { const el = e.currentTarget as HTMLElement; el.style.background = NAVY; el.style.color = '#fff'; }} onMouseLeave={e => { const el = e.currentTarget as HTMLElement; el.style.background = 'transparent'; el.style.color = NAVY; }} > {fallbackText(websiteCta.label, preistraegerDetailContent.websiteCta.label)} {downloadHref ? ( { const el = e.currentTarget as HTMLElement; el.style.background = GOLD; el.style.color = '#101828'; }} onMouseLeave={e => { const el = e.currentTarget as HTMLElement; el.style.background = 'transparent'; el.style.color = NAVY; }} > {downloadLabel} ) : null}
{showGallery ? (

{fallbackText(gallery.heading, 'Bildergalerie')}

{gallery.description ? (

{gallery.description}

) : null}
{galleryImages.map((image, index) => ( ))}
) : null} {activeGalleryImage ? (
setActiveGalleryIndex(undefined)} style={{ position: 'fixed', inset: 0, zIndex: 1000, background: 'rgba(3,9,58,0.92)', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: isMobile ? 18 : 40, }} > {galleryImages.length > 1 ? ( ) : null}
event.stopPropagation()} style={{ maxWidth: 'min(1120px, 100%)', maxHeight: '86vh', display: 'flex', flexDirection: 'column', gap: 14 }}> {activeGalleryImage.alt} {activeGalleryImage.caption ? (

{activeGalleryImage.caption}

) : null}
{galleryImages.length > 1 ? ( ) : null}
) : null} {/* Back link */}
((e.currentTarget as HTMLElement).style.color = GOLD)} onMouseLeave={e => ((e.currentTarget as HTMLElement).style.color = NAVY)} > {fallbackText(backLink.label, preistraegerDetailContent.backLink.label)}
); }