feat: update Preistraeger page to include a simple winner grid for 2023 and remove unused components

fix: change featured status for participation content and remove deprecated award card

feat: add migration for new participation phase form fields and backfill existing data

feat: create AwardsGridSection component for displaying awards with improved layout

feat: implement NewsletterInterestForm component for newsletter sign-up with validation
This commit is contained in:
syntaxbullet
2026-07-01 18:02:12 +02:00
parent 2fda7e8122
commit 2842caa936
15 changed files with 1274 additions and 255 deletions

View File

@@ -1,6 +1,7 @@
import React, { useMemo, useState } from 'react'
import { ChevronRight, Star } from 'lucide-react'
import AwardsGridSection, { type AwardsGridContent } from '@/spa/components/AwardsGridSection'
import TestimonialsSection from '@/spa/components/TestimonialsSection'
import MunichSkylineBg from '@/spa/components/ui/munich-skyline-bg'
import Image from '@/spa/components/ui/UnoptimizedImage'
@@ -61,6 +62,12 @@ const paragraphs = (value: unknown, fallback: string[]) =>
? (value as Array<string | TextRow>).map((item) => (typeof item === 'string' ? item : fallbackText(item.text, ''))).filter(Boolean)
: fallback
const isParticipationPage = (page: CmsRouteDoc) => {
const title = String(page.title || '').toLowerCase()
return page.spaPath === '/teilnahme' || page.slug === 'teilnahme' || page.slug === 'participation' || title === 'teilnahme' || title === 'participation'
}
function HighlightedText({ text, highlight }: { text: string; highlight: string }) {
const index = text.indexOf(highlight)
if (!highlight || index < 0) return <>{text}</>
@@ -115,6 +122,7 @@ const About: React.FC = () => {
const isMobile = useIsMobile()
const cms = (useCmsRoute()?.doc?.about || {}) as AboutCms
const cmsWinners = useCmsCollection('preistraeger')
const cmsPages = useCmsCollection('pages')
const hero = { ...aboutContent.hero, ...(cms.hero || {}) }
const prize = { ...aboutContent.prize, ...(cms.prize || {}) }
const mittelstand = { ...aboutContent.mittelstand, ...(cms.mittelstand || {}) }
@@ -124,6 +132,8 @@ const About: React.FC = () => {
const goals = { ...aboutContent.goals, ...(cms.goals || {}) }
const values = { ...aboutContent.values, ...(cms.values || {}) }
const cta = { ...aboutContent.cta, ...(cms.cta || {}) }
const participationPage = cmsPages.find(isParticipationPage)
const participationAwardsGrid = (participationPage?.participation as { awardsGrid?: AwardsGridContent } | undefined)?.awardsGrid
const showSecondaryCta = !HIDE_MEMBERSHIP_ABOUT_CTA || !isMembershipCta(cta.secondaryCta)
const highlightFallbackImage = mediaUrl(
highlights.fallbackImage,
@@ -407,6 +417,8 @@ const About: React.FC = () => {
))}
</section>
<AwardsGridSection content={participationAwardsGrid} />
<section style={{ background: NAVY, padding: isMobile ? '48px 24px' : '100px 80px', position: 'relative', overflow: 'hidden' }}>
<div style={{ position: 'absolute', top: 0, left: '50%', transform: 'translateX(-50%)', width: '60%', height: 1, background: `linear-gradient(to right, transparent, ${GOLD}, transparent)`, opacity: 0.3 }} />
<div style={{ position: 'absolute', bottom: 0, left: '50%', transform: 'translateX(-50%)', width: '40%', height: 1, background: `linear-gradient(to right, transparent, ${GOLD}, transparent)`, opacity: 0.15 }} />