Skip to content

Commit 2598180

Browse files
committed
Replace the contents of At a glance with a carousel placeholder on the best air fryers article
1 parent e1cee7f commit 2598180

File tree

11 files changed

+109
-2
lines changed

11 files changed

+109
-2
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const ProductCarousel = () => (
2+
<aside>
3+
<p>Carousel!</p>
4+
</aside>
5+
);
6+
7+
export { ProductCarousel };

dotcom-rendering/src/lib/renderElement.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import { MultiBylines } from '../components/MultiBylines';
3636
import { MultiImageBlockComponent } from '../components/MultiImageBlockComponent';
3737
import { NumberedTitleBlockComponent } from '../components/NumberedTitleBlockComponent';
3838
import { PersonalityQuizAtom } from '../components/PersonalityQuizAtom.importable';
39+
import { ProductCarousel } from '../components/ProductCarousel';
3940
import { ProductElement } from '../components/ProductElement';
4041
import { ProductLinkButton } from '../components/ProductLinkButton';
4142
import { ProfileAtomWrapper } from '../components/ProfileAtomWrapper.importable';
@@ -938,6 +939,8 @@ export const renderElement = ({
938939
/>
939940
</Island>
940941
);
942+
case 'model.dotcomrendering.pageElements.ProductCarouselElement':
943+
return <ProductCarousel />;
941944
case 'model.dotcomrendering.pageElements.AudioBlockElement':
942945
case 'model.dotcomrendering.pageElements.ContentAtomBlockElement':
943946
case 'model.dotcomrendering.pageElements.GenericAtomBlockElement':

dotcom-rendering/src/model/enhance-H2s.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@ export const slugify = (text: string): string => {
4747
/**
4848
* This function attempts to create a slugified string to use as the id. It fails over to elementId.
4949
*/
50-
const generateId = (elementId: string, html: string, existingIds: string[]) => {
50+
export const generateId = (
51+
elementId: string,
52+
html: string,
53+
existingIds: string[],
54+
): string => {
5155
const text = extractText(html);
5256
if (!text) return elementId;
5357
const slug = slugify(text);
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import type { FEElement, ProductCarouselElement } from '../types/content';
2+
import { generateId } from './enhance-H2s';
3+
4+
// We only want to insert the carousel in this one specific spot
5+
const isAtAGlance = (element: FEElement) =>
6+
element._type ===
7+
'model.dotcomrendering.pageElements.SubheadingBlockElement' &&
8+
generateId(element.elementId, element.html, []) === 'at-a-glance';
9+
10+
const isSubheadingOrDivider = (element: FEElement) =>
11+
// if an element is one of these then we're likely leaving the 'At a glance' section
12+
element._type ===
13+
'model.dotcomrendering.pageElements.SubheadingBlockElement' ||
14+
element._type === 'model.dotcomrendering.pageElements.DividerBlockElement';
15+
16+
const allowedPageIds = ['thefilter/2025/mar/02/best-air-fryers'];
17+
18+
const isEligibleForCarousel = (pageId: string) =>
19+
allowedPageIds.includes(pageId);
20+
21+
const placeholderCarousel: ProductCarouselElement = {
22+
_type: 'model.dotcomrendering.pageElements.ProductCarouselElement',
23+
};
24+
25+
type ReducerAccumulator = {
26+
elements: FEElement[];
27+
inAtAGlanceSection: boolean;
28+
};
29+
30+
const insertCarouselPlaceholder = (elements: FEElement[]): FEElement[] => {
31+
const elementsWithReducerContext = elements.reduce(
32+
(
33+
prev: ReducerAccumulator,
34+
currentElement: FEElement,
35+
): ReducerAccumulator => {
36+
let inAtAGlance = prev.inAtAGlanceSection;
37+
const elementsToReturn = prev.elements;
38+
39+
if (!inAtAGlance) {
40+
if (isAtAGlance(currentElement)) {
41+
inAtAGlance = true;
42+
}
43+
elementsToReturn.push(currentElement);
44+
} else {
45+
if (isSubheadingOrDivider(currentElement)) {
46+
inAtAGlance = false;
47+
elementsToReturn.push(placeholderCarousel, currentElement);
48+
}
49+
50+
// TODO - here we could maybe build a list of the products mentioned in the at a glance section
51+
// by appending the current element to a different list which then gets passed into the carousel
52+
}
53+
54+
return {
55+
elements: elementsToReturn,
56+
inAtAGlanceSection: inAtAGlance,
57+
};
58+
},
59+
// Initial value for reducer function
60+
{
61+
elements: [],
62+
inAtAGlanceSection: false,
63+
},
64+
);
65+
66+
return elementsWithReducerContext.elements;
67+
};
68+
69+
export const enhanceProductCarousel =
70+
(pageId: string) =>
71+
(elements: FEElement[]): FEElement[] => {
72+
// do nothing if article is not on allow list
73+
if (isEligibleForCarousel(pageId)) {
74+
return insertCarouselPlaceholder(elements);
75+
}
76+
77+
return elements;
78+
};

dotcom-rendering/src/model/enhanceBlocks.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { enhanceH2s } from './enhance-H2s';
1919
import { enhanceElementsImages, enhanceImages } from './enhance-images';
2020
import { enhanceInteractiveContentsElements } from './enhance-interactive-contents-elements';
2121
import { enhanceNumberedLists } from './enhance-numbered-lists';
22+
import { enhanceProductCarousel } from './enhance-product-carousel';
2223
import { enhanceTweets } from './enhance-tweets';
2324
import { enhanceGuVideos } from './enhance-videos';
2425
import { enhanceLists } from './enhanceLists';
@@ -34,6 +35,7 @@ type Options = {
3435
audioArticleImage?: ImageBlockElement;
3536
tags?: TagType[];
3637
shouldHideAds: boolean;
38+
pageId: string;
3739
};
3840

3941
const enhanceNewsletterSignup =
@@ -94,6 +96,7 @@ export const enhanceElements =
9496
options.shouldHideAds,
9597
),
9698
enhanceDisclaimer(options.hasAffiliateLinksDisclaimer, isNested),
99+
enhanceProductCarousel(options.pageId),
97100
].reduce(
98101
(enhancedBlocks, enhancer) => enhancer(enhancedBlocks),
99102
elements,

dotcom-rendering/src/model/enhanceProductElement.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ const elementsEnhancer = enhanceElements(
8282
imagesForLightbox: [],
8383
hasAffiliateLinksDisclaimer: false,
8484
shouldHideAds: false,
85+
pageId: '',
8586
},
8687
true,
8788
);

dotcom-rendering/src/model/pinnedPost.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export const enhancePinnedPost = (
77
format: ArticleFormat,
88
renderingTarget: RenderingTarget,
99
pinnedPost: Block | undefined,
10+
pageId: string,
1011
): Block | undefined => {
1112
if (pinnedPost === undefined) {
1213
return undefined;
@@ -18,5 +19,6 @@ export const enhancePinnedPost = (
1819
promotedNewsletter: undefined,
1920
hasAffiliateLinksDisclaimer: false,
2021
shouldHideAds: false,
22+
pageId,
2123
})[0];
2224
};

dotcom-rendering/src/server/handler.article.apps.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export const handleAppsBlocks: RequestHandler = ({ body }, res) => {
6060
imagesForLightbox: [],
6161
hasAffiliateLinksDisclaimer: false,
6262
shouldHideAds,
63+
pageId,
6364
});
6465
const html = renderAppsBlocks({
6566
blocks: enhancedBlocks,

dotcom-rendering/src/server/handler.article.web.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export const handleBlocks: RequestHandler = ({ body }, res) => {
6363
imagesForLightbox: [],
6464
hasAffiliateLinksDisclaimer: false,
6565
shouldHideAds,
66+
pageId,
6667
});
6768
const html = renderBlocks({
6869
blocks: enhancedBlocks,

dotcom-rendering/src/types/article.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ export const enhanceArticleType = (
103103
audioArticleImage: data.audioArticleImage,
104104
tags: data.tags,
105105
shouldHideAds: data.shouldHideAds,
106+
pageId: data.pageId,
106107
});
107108

108109
const crosswordBlock = buildCrosswordBlock(data);
@@ -176,6 +177,7 @@ export const enhanceArticleType = (
176177
format,
177178
renderingTarget,
178179
data.pinnedPost,
180+
data.pageId,
179181
),
180182
standfirst: enhanceStandfirst(data.standfirst),
181183
commercialProperties: enhanceCommercialProperties(

0 commit comments

Comments
 (0)