feat: manage preistraeger fallback copy via payload

This commit is contained in:
syntaxbullet
2026-06-22 12:48:54 +02:00
parent 2eef1d8350
commit 856ab84252
7 changed files with 109 additions and 17 deletions

View File

@@ -100,6 +100,18 @@ export const preistraegerIndexFields: Field[] = [
fields: [ fields: [
uploadField('fallbackImage', 'Fallback card image', `Current frontend fallback image: /images/${preistraegerIndexContent.card.fallbackImageFilename}`), uploadField('fallbackImage', 'Fallback card image', `Current frontend fallback image: /images/${preistraegerIndexContent.card.fallbackImageFilename}`),
text('hoverLabel', 'Hover label', preistraegerIndexContent.card.hoverLabel), text('hoverLabel', 'Hover label', preistraegerIndexContent.card.hoverLabel),
{
name: 'fallbackWinner',
label: 'Missing winner field fallbacks',
type: 'group',
fields: [
text('name', 'Name', preistraegerIndexContent.card.fallbackWinner.name),
text('category', 'Category', preistraegerIndexContent.card.fallbackWinner.category),
text('awardType', 'Award type', preistraegerIndexContent.card.fallbackWinner.awardType),
text('location', 'Location', preistraegerIndexContent.card.fallbackWinner.location),
text('industry', 'Industry', preistraegerIndexContent.card.fallbackWinner.industry),
],
},
], ],
}, },
{ {

View File

@@ -138,6 +138,22 @@ export const Preistraeger: CollectionConfig = {
{ name: 'label', type: 'text', label: 'Label', defaultValue: preistraegerDetailContent.breadcrumb.label }, { name: 'label', type: 'text', label: 'Label', defaultValue: preistraegerDetailContent.breadcrumb.label },
], ],
}, },
{
name: 'fallbackWinner',
label: 'Missing winner field fallbacks',
type: 'group',
fields: [
{ name: 'name', type: 'text', defaultValue: preistraegerDetailContent.fallbackWinner.name },
{ name: 'category', type: 'text', defaultValue: preistraegerDetailContent.fallbackWinner.category },
{ name: 'awardType', type: 'text', defaultValue: preistraegerDetailContent.fallbackWinner.awardType },
{ name: 'longDesc', type: 'textarea', defaultValue: preistraegerDetailContent.fallbackWinner.longDesc },
{ name: 'quote', type: 'textarea', defaultValue: preistraegerDetailContent.fallbackWinner.quote },
{ name: 'quotePerson', type: 'text', defaultValue: preistraegerDetailContent.fallbackWinner.quotePerson },
{ name: 'quoteRole', type: 'text', defaultValue: preistraegerDetailContent.fallbackWinner.quoteRole },
{ name: 'location', type: 'text', defaultValue: preistraegerDetailContent.fallbackWinner.location },
{ name: 'industry', type: 'text', defaultValue: preistraegerDetailContent.fallbackWinner.industry },
],
},
{ {
name: 'sections', name: 'sections',
label: 'Section copy', label: 'Section copy',

View File

@@ -1463,6 +1463,13 @@ export interface Page {
*/ */
fallbackImage?: (number | null) | Media; fallbackImage?: (number | null) | Media;
hoverLabel?: string | null; hoverLabel?: string | null;
fallbackWinner?: {
name?: string | null;
category?: string | null;
awardType?: string | null;
location?: string | null;
industry?: string | null;
};
}; };
/** /**
* Bottom application and membership CTA. * Bottom application and membership CTA.
@@ -2782,6 +2789,17 @@ export interface Preistraeger {
url?: string | null; url?: string | null;
label?: string | null; label?: string | null;
}; };
fallbackWinner?: {
name?: string | null;
category?: string | null;
awardType?: string | null;
longDesc?: string | null;
quote?: string | null;
quotePerson?: string | null;
quoteRole?: string | null;
location?: string | null;
industry?: string | null;
};
sections?: { sections?: {
companyHeading?: string | null; companyHeading?: string | null;
juryHeading?: string | null; juryHeading?: string | null;
@@ -4336,6 +4354,15 @@ export interface PagesSelect<T extends boolean = true> {
| { | {
fallbackImage?: T; fallbackImage?: T;
hoverLabel?: T; hoverLabel?: T;
fallbackWinner?:
| T
| {
name?: T;
category?: T;
awardType?: T;
location?: T;
industry?: T;
};
}; };
cta?: cta?:
| T | T
@@ -5243,6 +5270,19 @@ export interface PreistraegerSelect<T extends boolean = true> {
url?: T; url?: T;
label?: T; label?: T;
}; };
fallbackWinner?:
| T
| {
name?: T;
category?: T;
awardType?: T;
longDesc?: T;
quote?: T;
quotePerson?: T;
quoteRole?: T;
location?: T;
industry?: T;
};
sections?: sections?:
| T | T
| { | {

View File

@@ -22,21 +22,25 @@ type PreistraegerIndexCms = Partial<typeof preistraegerIndexContent> & {
const fallbackText = (value: unknown, fallback: string) => typeof value === 'string' && value.length > 0 ? value : fallback; const fallbackText = (value: unknown, fallback: string) => typeof value === 'string' && value.length > 0 ? value : fallback;
const normalizeWinner = (doc: CmsRouteDoc, fallbackImage: string): Winner => ({ const normalizeWinner = (
doc: CmsRouteDoc,
fallbackImage: string,
fallbackWinner: typeof preistraegerIndexContent.card.fallbackWinner,
): Winner => ({
id: String(doc.id), id: String(doc.id),
slug: String(doc.slug || ''), slug: String(doc.slug || ''),
name: String(doc.title || 'Preisträger'), name: String(doc.title || fallbackWinner.name || preistraegerIndexContent.card.fallbackWinner.name),
category: String(doc.category || 'Preisträger'), category: String(doc.category || fallbackWinner.category || preistraegerIndexContent.card.fallbackWinner.category),
year: Number(doc.year || new Date().getFullYear()), year: Number(doc.year || new Date().getFullYear()),
type: String(doc.awardType || 'Auszeichnung'), type: String(doc.awardType || fallbackWinner.awardType || preistraegerIndexContent.card.fallbackWinner.awardType),
img: docImageUrl(doc, fallbackImage), img: docImageUrl(doc, fallbackImage),
shortDesc: String(doc.shortDesc || doc.description || doc.meta?.description || ''), shortDesc: String(doc.shortDesc || doc.description || doc.meta?.description || ''),
longDesc: String(doc.longDesc || doc.description || doc.meta?.description || ''), longDesc: String(doc.longDesc || doc.description || doc.meta?.description || ''),
quote: String(doc.quote || ''), quote: String(doc.quote || ''),
quotePerson: String(doc.quotePerson || ''), quotePerson: String(doc.quotePerson || ''),
quoteRole: String(doc.quoteRole || ''), quoteRole: String(doc.quoteRole || ''),
location: String(doc.location || 'Bayern'), location: String(doc.location || fallbackWinner.location || preistraegerIndexContent.card.fallbackWinner.location),
industry: String(doc.industry || 'Mittelstand'), industry: String(doc.industry || fallbackWinner.industry || preistraegerIndexContent.card.fallbackWinner.industry),
website: String(doc.website || '#'), website: String(doc.website || '#'),
hasMedia: Boolean(doc.hasMedia), hasMedia: Boolean(doc.hasMedia),
}); });
@@ -60,9 +64,10 @@ export default function Preistraeger() {
[card], [card],
); );
const winners = useMemo(() => { const winners = useMemo(() => {
if (cmsPreistraeger.length) return cmsPreistraeger.map((doc) => normalizeWinner(doc, cardFallbackImage)).filter((winner) => winner.slug); const fallbackWinner = card.fallbackWinner || preistraegerIndexContent.card.fallbackWinner;
if (cmsPreistraeger.length) return cmsPreistraeger.map((doc) => normalizeWinner(doc, cardFallbackImage, fallbackWinner)).filter((winner) => winner.slug);
return WINNERS; return WINNERS;
}, [cardFallbackImage, cmsPreistraeger]); }, [card, cardFallbackImage, cmsPreistraeger]);
const years = useMemo(() => [...new Set(winners.map((winner) => winner.year))].sort((a, b) => b - a), [winners]); const years = useMemo(() => [...new Set(winners.map((winner) => winner.year))].sort((a, b) => b - a), [winners]);
const categories = useMemo(() => [...new Set(winners.map((winner) => winner.category))].sort((a, b) => a.localeCompare(b, 'de')), [winners]); const categories = useMemo(() => [...new Set(winners.map((winner) => winner.category))].sort((a, b) => a.localeCompare(b, 'de')), [winners]);
const [activeYear, setActiveYear] = useState<number | undefined>(undefined); const [activeYear, setActiveYear] = useState<number | undefined>(undefined);

View File

@@ -31,22 +31,23 @@ export default function PreistraegerDetail() {
...preistraegerDetailContent, ...preistraegerDetailContent,
...((cmsWinner?.detailPage || {}) as PreistraegerDetailCms), ...((cmsWinner?.detailPage || {}) as PreistraegerDetailCms),
} as PreistraegerDetailCms; } as PreistraegerDetailCms;
const fallbackWinner = cmsDetail.fallbackWinner || preistraegerDetailContent.fallbackWinner;
const winnerFallbackImage = mediaUrl(cmsDetail.fallbackImage, `/images/${preistraegerDetailContent.fallbackImageFilename}`); const winnerFallbackImage = mediaUrl(cmsDetail.fallbackImage, `/images/${preistraegerDetailContent.fallbackImageFilename}`);
const winner = cmsWinner ? { const winner = cmsWinner ? {
id: String(cmsWinner.id), id: String(cmsWinner.id),
slug: String(cmsWinner.slug || slug), slug: String(cmsWinner.slug || slug),
name: String(cmsWinner.title || 'Preisträger'), name: String(cmsWinner.title || fallbackWinner.name || preistraegerDetailContent.fallbackWinner.name),
category: String(cmsWinner.category || 'Preisträger'), category: String(cmsWinner.category || fallbackWinner.category || preistraegerDetailContent.fallbackWinner.category),
year: Number(cmsWinner.year || new Date().getFullYear()), year: Number(cmsWinner.year || new Date().getFullYear()),
type: String(cmsWinner.awardType || 'Auszeichnung'), type: String(cmsWinner.awardType || fallbackWinner.awardType || preistraegerDetailContent.fallbackWinner.awardType),
img: docImageUrl(cmsWinner, winnerFallbackImage), img: docImageUrl(cmsWinner, winnerFallbackImage),
shortDesc: String(cmsWinner.shortDesc || cmsWinner.description || cmsWinner.meta?.description || ''), shortDesc: String(cmsWinner.shortDesc || cmsWinner.description || cmsWinner.meta?.description || ''),
longDesc: String(cmsWinner.longDesc || cmsWinner.description || cmsWinner.meta?.description || 'Dieser Preisträger wird aus Payload CMS geladen.'), longDesc: String(cmsWinner.longDesc || cmsWinner.description || cmsWinner.meta?.description || fallbackWinner.longDesc || preistraegerDetailContent.fallbackWinner.longDesc),
quote: String(cmsWinner.quote || 'Diese Erfolgsgeschichte wird aktuell in Payload CMS gepflegt.'), quote: String(cmsWinner.quote || fallbackWinner.quote || preistraegerDetailContent.fallbackWinner.quote),
quotePerson: String(cmsWinner.quotePerson || cmsWinner.title || 'BMP'), quotePerson: String(cmsWinner.quotePerson || cmsWinner.title || fallbackWinner.quotePerson || preistraegerDetailContent.fallbackWinner.quotePerson),
quoteRole: String(cmsWinner.quoteRole || 'Preisträger'), quoteRole: String(cmsWinner.quoteRole || fallbackWinner.quoteRole || preistraegerDetailContent.fallbackWinner.quoteRole),
location: String(cmsWinner.location || 'Bayern'), location: String(cmsWinner.location || fallbackWinner.location || preistraegerDetailContent.fallbackWinner.location),
industry: String(cmsWinner.industry || 'Mittelstand'), industry: String(cmsWinner.industry || fallbackWinner.industry || preistraegerDetailContent.fallbackWinner.industry),
website: String(cmsWinner.website || '#'), website: String(cmsWinner.website || '#'),
hasMedia: Boolean(cmsWinner.hasMedia), hasMedia: Boolean(cmsWinner.hasMedia),
detailPage: (cmsWinner.detailPage || {}) as PreistraegerDetailCms, detailPage: (cmsWinner.detailPage || {}) as PreistraegerDetailCms,

View File

@@ -5,6 +5,17 @@ export const preistraegerDetailContent = {
url: '/preistraeger', url: '/preistraeger',
label: 'Preisträger:innen', label: 'Preisträger:innen',
}, },
fallbackWinner: {
name: 'Preisträger',
category: 'Preisträger',
awardType: 'Auszeichnung',
longDesc: 'Dieser Preisträger wird aus Payload CMS geladen.',
quote: 'Diese Erfolgsgeschichte wird aktuell in Payload CMS gepflegt.',
quotePerson: 'BMP',
quoteRole: 'Preisträger',
location: 'Bayern',
industry: 'Mittelstand',
},
sections: { sections: {
companyHeading: 'Über das Unternehmen', companyHeading: 'Über das Unternehmen',
juryHeading: 'Warum ausgezeichnet?', juryHeading: 'Warum ausgezeichnet?',

View File

@@ -23,6 +23,13 @@ export const preistraegerIndexContent = {
card: { card: {
fallbackImageFilename: 'gala-saal-overview.jpg', fallbackImageFilename: 'gala-saal-overview.jpg',
hoverLabel: 'Mehr erfahren', hoverLabel: 'Mehr erfahren',
fallbackWinner: {
name: 'Preisträger',
category: 'Preisträger',
awardType: 'Auszeichnung',
location: 'Bayern',
industry: 'Mittelstand',
},
}, },
cta: { cta: {
text: 'Werden Sie der nächste Preisträger.', text: 'Werden Sie der nächste Preisträger.',