|
| 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 | + }; |
0 commit comments