236 lines
6.9 KiB
TypeScript
236 lines
6.9 KiB
TypeScript
import type { Page as CmsPage } from "../types/cms/Page";
|
|
import type { HTMLSkeleton } from "../types/cms/Html";
|
|
import type { MarkdownSkeleton } from "../types/cms/Markdown";
|
|
import type { ComponentIframeSkeleton } from "../types/cms/Iframe";
|
|
import type { ImageGallerySkeleton } from "../types/cms/ImageGallery";
|
|
import type { ComponentImageSkeleton } from "../types/cms/Image";
|
|
import type { QuoteSkeleton } from "../types/cms/Quote";
|
|
import type { ComponentYoutubeVideoSkeleton } from "../types/cms/YoutubeVideo";
|
|
import type { ComponentHeadlineSkeleton } from "../types/cms/Headline";
|
|
import type { Page, ContentItem, ContentRow } from "../types/page";
|
|
import { ContentType } from "../types/cms/ContentType.enum";
|
|
|
|
type ContentEntry =
|
|
| HTMLSkeleton
|
|
| MarkdownSkeleton
|
|
| ComponentIframeSkeleton
|
|
| ImageGallerySkeleton
|
|
| ComponentImageSkeleton
|
|
| QuoteSkeleton
|
|
| ComponentYoutubeVideoSkeleton
|
|
| ComponentHeadlineSkeleton;
|
|
|
|
/**
|
|
* Mapper für Page-Transformationen
|
|
* Konvertiert CMS-Typen zu unseren Domain-Typen
|
|
*/
|
|
export class PageMapper {
|
|
/**
|
|
* Strategy Pattern: Map mit Mapper-Funktionen für jeden Content-Type
|
|
*/
|
|
private static contentMappers = new Map<
|
|
ContentType,
|
|
(entry: ContentEntry) => ContentItem | null
|
|
>([
|
|
[
|
|
ContentType.html,
|
|
(entry) => {
|
|
const htmlEntry = entry as HTMLSkeleton;
|
|
return {
|
|
type: "html",
|
|
name: htmlEntry.fields.id || "",
|
|
html: htmlEntry.fields.html,
|
|
layout: htmlEntry.fields.layout,
|
|
};
|
|
},
|
|
],
|
|
[
|
|
ContentType.markdown,
|
|
(entry) => {
|
|
const markdownEntry = entry as MarkdownSkeleton;
|
|
return {
|
|
type: "markdown",
|
|
name: markdownEntry.fields.name,
|
|
content: markdownEntry.fields.content,
|
|
layout: markdownEntry.fields.layout,
|
|
alignment: markdownEntry.fields.alignment,
|
|
};
|
|
},
|
|
],
|
|
[
|
|
ContentType.iframe,
|
|
(entry) => {
|
|
const iframeEntry = entry as ComponentIframeSkeleton;
|
|
return {
|
|
type: "iframe",
|
|
name: iframeEntry.fields.name,
|
|
content: iframeEntry.fields.content,
|
|
iframe: iframeEntry.fields.iframe,
|
|
overlayImageUrl: iframeEntry.fields.overlayImage?.fields.file.url,
|
|
layout: iframeEntry.fields.layout,
|
|
};
|
|
},
|
|
],
|
|
[
|
|
ContentType.imgGallery,
|
|
(entry) => {
|
|
const galleryEntry = entry as ImageGallerySkeleton;
|
|
return {
|
|
type: "imageGallery",
|
|
name: galleryEntry.fields.name,
|
|
images: galleryEntry.fields.images.map((img) => ({
|
|
url: img.fields.file.url,
|
|
title: img.fields.title,
|
|
description: img.fields.description,
|
|
})),
|
|
description: galleryEntry.fields.description,
|
|
layout: galleryEntry.fields.layout,
|
|
};
|
|
},
|
|
],
|
|
[
|
|
ContentType.image,
|
|
(entry) => {
|
|
const imageEntry = entry as ComponentImageSkeleton;
|
|
return {
|
|
type: "image",
|
|
name: imageEntry.fields.name,
|
|
imageUrl: imageEntry.fields.image.fields.file.url,
|
|
caption: imageEntry.fields.caption,
|
|
maxWidth: imageEntry.fields.maxWidth,
|
|
aspectRatio: imageEntry.fields.aspectRatio,
|
|
layout: imageEntry.fields.layout,
|
|
};
|
|
},
|
|
],
|
|
[
|
|
ContentType.quote,
|
|
(entry) => {
|
|
const quoteEntry = entry as QuoteSkeleton;
|
|
return {
|
|
type: "quote",
|
|
quote: quoteEntry.fields.quote,
|
|
author: quoteEntry.fields.author,
|
|
variant: quoteEntry.fields.variant,
|
|
layout: quoteEntry.fields.layout,
|
|
};
|
|
},
|
|
],
|
|
[
|
|
ContentType.youtubeVideo,
|
|
(entry) => {
|
|
const videoEntry = entry as ComponentYoutubeVideoSkeleton;
|
|
return {
|
|
type: "youtubeVideo",
|
|
id: videoEntry.fields.id,
|
|
youtubeId: videoEntry.fields.youtubeId,
|
|
params: videoEntry.fields.params,
|
|
title: videoEntry.fields.title,
|
|
description: videoEntry.fields.description,
|
|
layout: videoEntry.fields.layout,
|
|
};
|
|
},
|
|
],
|
|
[
|
|
ContentType.headline,
|
|
(entry) => {
|
|
const headlineEntry = entry as ComponentHeadlineSkeleton;
|
|
return {
|
|
type: "headline",
|
|
internal: headlineEntry.fields.internal,
|
|
text: headlineEntry.fields.text,
|
|
tag: headlineEntry.fields.tag,
|
|
align: headlineEntry.fields.align,
|
|
layout: headlineEntry.fields.layout,
|
|
};
|
|
},
|
|
],
|
|
]);
|
|
|
|
/**
|
|
* Mappt ein Contentful Content-Item zu unserem ContentItem
|
|
* Verwendet Strategy Pattern für wartbaren Code
|
|
*/
|
|
private static mapContentItem(entry: ContentEntry): ContentItem | null {
|
|
if (!entry.contentTypeId || !entry.fields) {
|
|
return null;
|
|
}
|
|
|
|
const mapper = this.contentMappers.get(entry.contentTypeId);
|
|
if (!mapper) {
|
|
return null;
|
|
}
|
|
|
|
return mapper(entry);
|
|
}
|
|
|
|
/**
|
|
* Mappt eine CMS Content-Row zu unserer ContentRow
|
|
*/
|
|
private static mapContentRow(
|
|
content: ContentEntry[],
|
|
justifyContent: string,
|
|
alignItems: string
|
|
): ContentRow | undefined {
|
|
if (!content || content.length === 0) {
|
|
return undefined;
|
|
}
|
|
|
|
const mappedContent = content
|
|
.map((entry) => this.mapContentItem(entry))
|
|
.filter((item): item is ContentItem => item !== null);
|
|
|
|
if (mappedContent.length === 0) {
|
|
return undefined;
|
|
}
|
|
|
|
return {
|
|
justifyContent: justifyContent as ContentRow["justifyContent"],
|
|
alignItems: alignItems as ContentRow["alignItems"],
|
|
content: mappedContent,
|
|
};
|
|
}
|
|
|
|
static fromCms(cmsPage: CmsPage): Page {
|
|
return {
|
|
slug: cmsPage.slug,
|
|
name: cmsPage.name,
|
|
linkName: cmsPage.linkName,
|
|
headline: cmsPage.headline,
|
|
subheadline: cmsPage.subheadline,
|
|
seoTitle: cmsPage.seoTitle,
|
|
seoMetaRobots: cmsPage.seoMetaRobots,
|
|
seoDescription: cmsPage.seoDescription,
|
|
topFullwidthBanner: cmsPage.topFullwidthBanner
|
|
? {
|
|
name: cmsPage.topFullwidthBanner.fields.name,
|
|
variant: cmsPage.topFullwidthBanner.fields.variant,
|
|
headline: cmsPage.topFullwidthBanner.fields.headline,
|
|
subheadline: cmsPage.topFullwidthBanner.fields.subheadline,
|
|
text: cmsPage.topFullwidthBanner.fields.text,
|
|
imageUrl: cmsPage.topFullwidthBanner.fields.img.fields.file.url,
|
|
}
|
|
: undefined,
|
|
row1: this.mapContentRow(
|
|
cmsPage.row1Content,
|
|
cmsPage.row1JustifyContent,
|
|
cmsPage.row1AlignItems
|
|
),
|
|
row2: this.mapContentRow(
|
|
cmsPage.row2Content,
|
|
cmsPage.row2JustifyContent,
|
|
cmsPage.row2AlignItems
|
|
),
|
|
row3: this.mapContentRow(
|
|
cmsPage.row3Content,
|
|
cmsPage.row3JustifyContent,
|
|
cmsPage.row3AlignItems
|
|
),
|
|
};
|
|
}
|
|
|
|
static fromCmsArray(cmsPages: CmsPage[]): Page[] {
|
|
return cmsPages.map((page) => this.fromCms(page));
|
|
}
|
|
}
|