Skip to content

Commit 5fe28ba

Browse files
Add primary heading text to product element (#15088)
* add primaryHeadingText which is the primary heading with html removed and trailing `:` removed
1 parent f970caf commit 5fe28ba

File tree

7 files changed

+39
-11
lines changed

7 files changed

+39
-11
lines changed

dotcom-rendering/src/components/ProductCarouselCard.stories.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ import { css } from '@emotion/react';
22
import type { Meta, StoryObj } from '@storybook/react-webpack5';
33
import { productImage } from '../../fixtures/manual/productImage';
44
import { ArticleDesign, ArticleDisplay, Pillar } from '../lib/articleFormat';
5+
import { extractHeadingText } from '../model/enhanceProductElement';
56
import type { ProductBlockElement } from '../types/content';
67
import { ProductCarouselCard } from './ProductCarouselCard';
78

89
const product = {
910
_type: 'model.dotcomrendering.pageElements.ProductBlockElement',
1011
elementId: 'b1f6e8e2-3f3a-4f0c-8d1e-5f3e3e3e3e3e',
11-
primaryHeadingHtml: 'Best Kettle overall',
12+
primaryHeadingHtml: '<em>Best Kettle overall:<em/>',
13+
primaryHeadingText: extractHeadingText('<em>Best Kettle overall:</em>'),
1214
secondaryHeadingHtml: 'Bosch Sky Kettle',
1315
brandName: 'Bosch',
1416
productName: 'Sky Kettle',
@@ -277,7 +279,9 @@ export const WithLongHeadingProductNameAndCTA = {
277279
args: {
278280
product: {
279281
...product,
280-
primaryHeadingHtml: 'Super long product category review name',
282+
primaryHeadingText: extractHeadingText(
283+
'<em>Super long product: category review name:</em>',
284+
),
281285
productName:
282286
'Sky Kettle with a super duper long name that goes on and on',
283287
productCtas: [

dotcom-rendering/src/components/ProductCarouselCard.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,9 @@ export const ProductCarouselCard = ({
8484
<div css={baseCard}>
8585
{hasHeading && (
8686
<>
87-
<div
88-
css={productCarouselCardHeading}
89-
dangerouslySetInnerHTML={{
90-
__html: product.primaryHeadingHtml,
91-
}}
92-
/>
87+
<div css={productCarouselCardHeading}>
88+
{product.primaryHeadingText}
89+
</div>
9390
<div css={brandAndProductNameRow}>
9491
<span css={brandAndProductNameInline}>
9592
{product.brandName}{' '}

dotcom-rendering/src/frontend/schemas/feArticle.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4480,6 +4480,9 @@
44804480
"primaryHeadingHtml": {
44814481
"type": "string"
44824482
},
4483+
"primaryHeadingText": {
4484+
"type": "string"
4485+
},
44834486
"customAttributes": {
44844487
"type": "array",
44854488
"items": {

dotcom-rendering/src/model/block-schema.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3968,6 +3968,9 @@
39683968
"primaryHeadingHtml": {
39693969
"type": "string"
39703970
},
3971+
"primaryHeadingText": {
3972+
"type": "string"
3973+
},
39713974
"customAttributes": {
39723975
"type": "array",
39733976
"items": {

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// typescript
21
import type { ArticleFormat } from '../lib/articleFormat';
32
import { ArticleDesign, ArticleDisplay, Pillar } from '../lib/articleFormat';
43
import type {
@@ -26,8 +25,8 @@ const productBlockElement: ProductBlockElement = {
2625
starRating: '5',
2726
productName: 'Sky Kettle',
2827
image: productImage,
29-
secondaryHeadingHtml: 'Best Kettle Overall',
30-
primaryHeadingHtml: 'Bosch Sky Kettle',
28+
primaryHeadingHtml: '<em>Best Kettle: Overall:</em>',
29+
secondaryHeadingHtml: 'Bosch Sky Kettle',
3130
customAttributes: [
3231
{ name: 'What we love', value: 'It packs away pretty small' },
3332
{
@@ -167,4 +166,11 @@ describe('enhanceProductBlockElements', () => {
167166

168167
expect(enhancedElementWithNaN.lowestPrice).toEqual('£29.99');
169168
});
169+
170+
it('extracts all html from primary heading and removes trailing `:` only', () => {
171+
enhanceProductElement(elementsEnhancer)(inputElements);
172+
expect(enhancedElements.primaryHeadingText).toEqual(
173+
'Best Kettle: Overall',
174+
);
175+
});
170176
});

dotcom-rendering/src/model/enhanceProductElement.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { JSDOM } from 'jsdom';
12
import type {
23
FEElement,
34
ProductBlockElement,
@@ -13,6 +14,7 @@ const enhanceProductBlockElement = (
1314
...element,
1415
content: elementsEnhancer(element.content),
1516
lowestPrice: getLowestPrice(element.productCtas),
17+
primaryHeadingText: extractHeadingText(element.primaryHeadingHtml),
1618
});
1719

1820
/**
@@ -72,3 +74,15 @@ export const enhanceProductElement =
7274
(elementsEnhancer: ElementsEnhancer) =>
7375
(elements: FEElement[]): FEElement[] =>
7476
elements.flatMap(enhance(elementsEnhancer));
77+
78+
export const extractHeadingText = (headingHtml: string): string => {
79+
return removeTrailingColon(extractText(headingHtml));
80+
};
81+
82+
const removeTrailingColon = (text: string): string => {
83+
return text.replace(/\s*:\s*$/, '');
84+
};
85+
86+
const extractText = (html: string): string => {
87+
return JSDOM.fragment(html).textContent?.trim() ?? '';
88+
};

dotcom-rendering/src/types/content.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,7 @@ export interface ProductBlockElement {
480480
image?: ProductImage;
481481
secondaryHeadingHtml: string;
482482
primaryHeadingHtml: string;
483+
primaryHeadingText?: string;
483484
customAttributes: ProductCustomAttribute[];
484485
content: FEElement[];
485486
h2Id?: string;

0 commit comments

Comments
 (0)