Files
sell/middlelayer/mappers/pageMapper.ts

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));
}
}