fix: resolve selected winners from populated CMS data
This commit is contained in:
@@ -42,6 +42,14 @@ export function useCmsCollection(collection: CmsRouteCollection) {
|
|||||||
return useCmsRoute()?.lists?.[collection] || []
|
return useCmsRoute()?.lists?.[collection] || []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function resolveCmsRelationship(entry: unknown, docs: CmsRouteDoc[]) {
|
||||||
|
const entryID = entry && typeof entry === 'object' ? (entry as { id?: unknown }).id : entry
|
||||||
|
const populatedDoc = docs.find((doc) => String(doc.id) === String(entryID))
|
||||||
|
|
||||||
|
if (populatedDoc) return populatedDoc
|
||||||
|
return entry && typeof entry === 'object' ? (entry as CmsRouteDoc) : undefined
|
||||||
|
}
|
||||||
|
|
||||||
export function useApplicationPhase() {
|
export function useApplicationPhase() {
|
||||||
return useCmsRoute()?.applicationPhase
|
return useCmsRoute()?.applicationPhase
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import TestimonialsSection from '@/spa/components/TestimonialsSection'
|
|||||||
import MunichSkylineBg from '@/spa/components/ui/munich-skyline-bg'
|
import MunichSkylineBg from '@/spa/components/ui/munich-skyline-bg'
|
||||||
import Image from '@/spa/components/ui/UnoptimizedImage'
|
import Image from '@/spa/components/ui/UnoptimizedImage'
|
||||||
import { mediaAlt, mediaUrl } from '@/spa/cmsMediaField'
|
import { mediaAlt, mediaUrl } from '@/spa/cmsMediaField'
|
||||||
import { useCmsCollection, useCmsRoute, type CmsRouteDoc } from '@/spa/cmsRoute'
|
import { resolveCmsRelationship, useCmsCollection, useCmsRoute, type CmsRouteDoc } from '@/spa/cmsRoute'
|
||||||
import { WINNERS, type Winner } from '@/spa/data/winners'
|
import { WINNERS, type Winner } from '@/spa/data/winners'
|
||||||
import { useIsMobile } from '@/spa/hooks/useIsMobile'
|
import { useIsMobile } from '@/spa/hooks/useIsMobile'
|
||||||
import { Link } from '@/spa/router'
|
import { Link } from '@/spa/router'
|
||||||
@@ -108,17 +108,6 @@ const normalizeWinner = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const winnerFromRelationship = (
|
|
||||||
entry: unknown,
|
|
||||||
allDocs: CmsRouteDoc[],
|
|
||||||
placeholderImage: string,
|
|
||||||
fallbackWinner: typeof aboutContent.highlights.fallbackWinner,
|
|
||||||
) => {
|
|
||||||
if (entry && typeof entry === 'object') return normalizeWinner(entry as CmsRouteDoc, placeholderImage, fallbackWinner)
|
|
||||||
const doc = allDocs.find((item) => String(item.id) === String(entry))
|
|
||||||
return normalizeWinner(doc, placeholderImage, fallbackWinner)
|
|
||||||
}
|
|
||||||
|
|
||||||
const About: React.FC = () => {
|
const About: React.FC = () => {
|
||||||
const isMobile = useIsMobile()
|
const isMobile = useIsMobile()
|
||||||
const placeholderImage = usePreistraegerPlaceholderImage()
|
const placeholderImage = usePreistraegerPlaceholderImage()
|
||||||
@@ -144,7 +133,7 @@ const About: React.FC = () => {
|
|||||||
|
|
||||||
const highlightWinners = useMemo(() => {
|
const highlightWinners = useMemo(() => {
|
||||||
const selected = fallbackArray<unknown>(highlights.selectedWinners, [])
|
const selected = fallbackArray<unknown>(highlights.selectedWinners, [])
|
||||||
.map((entry) => winnerFromRelationship(entry, cmsWinners, placeholderImage, highlightFallbackWinner))
|
.map((entry) => normalizeWinner(resolveCmsRelationship(entry, cmsWinners), placeholderImage, highlightFallbackWinner))
|
||||||
.filter((winner): winner is Winner => Boolean(winner))
|
.filter((winner): winner is Winner => Boolean(winner))
|
||||||
|
|
||||||
if (selected.length) return selected.slice(0, 8)
|
if (selected.length) return selected.slice(0, 8)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import MunichSkylineBg from '@/spa/components/ui/munich-skyline-bg';
|
|||||||
import { useIsMobile } from '@/spa/hooks/useIsMobile';
|
import { useIsMobile } from '@/spa/hooks/useIsMobile';
|
||||||
import Image from '@/spa/components/ui/UnoptimizedImage'
|
import Image from '@/spa/components/ui/UnoptimizedImage'
|
||||||
import type { SpaApplicationPhaseData, SpaApplicationPhaseItem } from '@/spa/applicationPhase'
|
import type { SpaApplicationPhaseData, SpaApplicationPhaseItem } from '@/spa/applicationPhase'
|
||||||
import { useApplicationPhase, useCmsCollection, useCmsRoute } from '@/spa/cmsRoute'
|
import { resolveCmsRelationship, useApplicationPhase, useCmsCollection, useCmsRoute } from '@/spa/cmsRoute'
|
||||||
import { mediaAlt, mediaUrl } from '@/spa/cmsMediaField'
|
import { mediaAlt, mediaUrl } from '@/spa/cmsMediaField'
|
||||||
import { homeContent } from '@/spa/homeContent'
|
import { homeContent } from '@/spa/homeContent'
|
||||||
import { netzwerkContent } from '@/spa/netzwerkContent'
|
import { netzwerkContent } from '@/spa/netzwerkContent'
|
||||||
@@ -276,13 +276,8 @@ const Home: React.FC = () => {
|
|||||||
};
|
};
|
||||||
const showHeroSecondaryCta = !HIDE_MEMBERSHIP_HOME_HERO_CTA || !isMembershipCta(heroSecondaryCta);
|
const showHeroSecondaryCta = !HIDE_MEMBERSHIP_HOME_HERO_CTA || !isMembershipCta(heroSecondaryCta);
|
||||||
const selectedWinnerDocs = selectedWinners
|
const selectedWinnerDocs = selectedWinners
|
||||||
.map((selected) => {
|
.map((selected) => resolveCmsRelationship(selected, cmsPreistraeger))
|
||||||
const selectedRecord = selected as { id?: string | number }
|
.filter(Boolean)
|
||||||
const selectedID = typeof selected === 'object' && selected !== null ? selectedRecord.id : selected
|
|
||||||
const listDoc = cmsPreistraeger.find((doc) => String((doc as { id?: string | number }).id) === String(selectedID))
|
|
||||||
return listDoc || (typeof selected === 'object' ? selected : undefined)
|
|
||||||
})
|
|
||||||
.filter(Boolean)
|
|
||||||
const homeWinners = selectedWinnerDocs.length
|
const homeWinners = selectedWinnerDocs.length
|
||||||
? selectedWinnerDocs
|
? selectedWinnerDocs
|
||||||
: (cmsPreistraeger.length ? cmsPreistraeger : WINNERS).filter((w) => Number((w as { year?: string | number }).year) === 2025).slice(0, 8);
|
: (cmsPreistraeger.length ? cmsPreistraeger : WINNERS).filter((w) => Number((w as { year?: string | number }).year) === 2025).slice(0, 8);
|
||||||
|
|||||||
25
tests/int/cms-route-relationship.int.spec.ts
Normal file
25
tests/int/cms-route-relationship.int.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { describe, expect, it } from 'vitest'
|
||||||
|
|
||||||
|
import { resolveCmsRelationship, type CmsRouteDoc } from '@/spa/cmsRoute'
|
||||||
|
|
||||||
|
const fullWinner: CmsRouteDoc = {
|
||||||
|
id: 20,
|
||||||
|
title: 'Adelholzener Alpenquellen GmbH',
|
||||||
|
image: { id: 55, url: '/api/media/file/image%20(1).png' },
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('CMS relationship resolution', () => {
|
||||||
|
it('prefers the fully populated collection document over a shallow relationship object', () => {
|
||||||
|
expect(resolveCmsRelationship({ id: 20, image: 55 }, [fullWinner])).toBe(fullWinner)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('resolves an ID-only relationship', () => {
|
||||||
|
expect(resolveCmsRelationship(20, [fullWinner])).toBe(fullWinner)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('preserves a populated relationship when no list document is available', () => {
|
||||||
|
const relationship = { id: 20, image: { id: 55, url: '/api/media/file/image%20(1).png' } }
|
||||||
|
|
||||||
|
expect(resolveCmsRelationship(relationship, [])).toBe(relationship)
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user