feat: implement home winners selection logic with fallback handling and add integration tests

This commit is contained in:
syntaxbullet
2026-07-13 15:19:37 +02:00
parent b7c499dd35
commit ee7e891a7d
3 changed files with 61 additions and 16 deletions

View File

@@ -0,0 +1,26 @@
import { resolveCmsRelationship, type CmsRouteDoc } from '@/spa/cmsRoute'
const FALLBACK_YEAR = 2025
const FALLBACK_LIMIT = 8
type FallbackWinner = {
id: string | number
year?: string | number
}
export function resolveHomeWinners(
featured: unknown,
cmsWinners: CmsRouteDoc[],
fallbackWinners: FallbackWinner[],
) {
const selectedWinners = Array.isArray(featured) ? featured : []
const selectedWinnerDocs = selectedWinners
.map((selected) => resolveCmsRelationship(selected, cmsWinners))
.filter((winner): winner is CmsRouteDoc => Boolean(winner))
if (selectedWinnerDocs.length) return selectedWinnerDocs
return (cmsWinners.length ? cmsWinners : fallbackWinners)
.filter((winner) => Number(winner.year) === FALLBACK_YEAR)
.slice(0, FALLBACK_LIMIT)
}

View File

@@ -11,9 +11,10 @@ import MunichSkylineBg from '@/spa/components/ui/munich-skyline-bg';
import { useIsMobile } from '@/spa/hooks/useIsMobile';
import Image from '@/spa/components/ui/UnoptimizedImage'
import type { SpaApplicationPhaseData, SpaApplicationPhaseItem } from '@/spa/applicationPhase'
import { resolveCmsRelationship, useApplicationPhase, useCmsCollection, useCmsRoute, useNewsletterForm } from '@/spa/cmsRoute'
import { useApplicationPhase, useCmsCollection, useCmsRoute, useNewsletterForm } from '@/spa/cmsRoute'
import { mediaAlt, mediaUrl } from '@/spa/cmsMediaField'
import { homeContent } from '@/spa/homeContent'
import { resolveHomeWinners } from '@/spa/homeWinnerSelection'
import { netzwerkContent } from '@/spa/netzwerkContent'
import { usePreistraegerPlaceholderImage } from '@/spa/preistraegerPlaceholder'
import { PartnerLogoMark, type PartnerLogoData } from '@/spa/components/ui/partner-logo'
@@ -251,26 +252,12 @@ const Home: React.FC = () => {
const newsletterCopy = newsletterFormCopyForPhase(newsletterForm, activeApplicationPhase);
const newsletterPhase = newsletterPhaseForApplicationPhase(activeApplicationPhase);
const cmsPreistraeger = useCmsCollection('preistraeger');
const selectedWinners = fallbackArray(winnersSection.featured, []);
const heroSecondaryCta = {
label: fallbackText(hero.secondaryCta?.label, homeContent.hero.secondaryCta.label),
url: fallbackText(hero.secondaryCta?.url, homeContent.hero.secondaryCta.url),
};
const showHeroSecondaryCta = !HIDE_MEMBERSHIP_HOME_HERO_CTA || !isMembershipCta(heroSecondaryCta);
const selectedWinnerDocs = selectedWinners
.map((selected) => resolveCmsRelationship(selected, cmsPreistraeger))
.filter(Boolean)
const eligibleWinners = (cmsPreistraeger.length ? cmsPreistraeger : WINNERS)
.filter((winner) => Number((winner as { year?: string | number }).year) === 2025)
const selectedWinnerIDs = new Set(
selectedWinnerDocs.map((winner) => String((winner as WinnerCardData).id || (winner as WinnerCardData).slug)),
)
const remainingWinners = selectedWinnerDocs.length >= 8
? eligibleWinners.filter((winner) => !selectedWinnerIDs.has(String((winner as WinnerCardData).id || (winner as WinnerCardData).slug)))
: []
const homeWinners = selectedWinnerDocs.length
? [...selectedWinnerDocs, ...remainingWinners]
: eligibleWinners;
const homeWinners = resolveHomeWinners(winnersSection.featured, cmsPreistraeger, WINNERS);
const scrollDesktopWinners = !isMobile && homeWinners.length > 8;
const scrollWinnerGrid = isMobile || scrollDesktopWinners;
const quickCriteria = fallbackArray(quickCheck.criteria, homeContent.quickCheck.criteria);