Skip to content

Commit 4cec2b0

Browse files
VIA-603 AS/EO/DB/SB Refactor WarningCallout to accept markdown, html and string
1 parent d6adf50 commit 4cec2b0

File tree

13 files changed

+140
-64
lines changed

13 files changed

+140
-64
lines changed

src/app/_components/content/Callout.tsx

Lines changed: 0 additions & 18 deletions
This file was deleted.

src/app/_components/content/Callout.test.tsx renamed to src/app/_components/content/WarningCallout.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Callout from "@src/app/_components/content/Callout";
1+
import Callout from "@src/app/_components/content/WarningCallout";
22
import { VaccineType } from "@src/models/vaccine";
33
import { mockStyledContent } from "@test-data/content-api/data";
44
import { render, screen } from "@testing-library/react";
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { VaccineInfo, VaccineType } from "@src/models/vaccine";
2+
import { StyledVaccineContent } from "@src/services/content-api/types";
3+
import { JSX } from "react";
4+
5+
const WarningCallout = (props: {
6+
styledVaccineContent: StyledVaccineContent;
7+
vaccineType: VaccineType;
8+
}): JSX.Element => {
9+
const element =
10+
props.styledVaccineContent.callout && !VaccineInfo[props.vaccineType].supressWarningCallout ? (
11+
<div data-testid="callout" className="nhsuk-warning-callout">
12+
<h3 className="nhsuk-warning-callout__label">
13+
<span role="text">
14+
<span className="nhsuk-u-visually-hidden">Important: </span>
15+
{props.styledVaccineContent.callout.heading}
16+
</span>
17+
</h3>
18+
<div data-testid="callout-text">{props.styledVaccineContent.callout.component}</div>
19+
</div>
20+
) : (
21+
<></>
22+
);
23+
return element;
24+
};
25+
export default WarningCallout;

src/app/_components/nhs-frontend/WarningCallout.tsx

Lines changed: 0 additions & 22 deletions
This file was deleted.

src/app/_components/vaccine/Vaccine.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
"use server";
22

33
import { auth } from "@project/auth";
4-
import Callout from "@src/app/_components/content/Callout";
54
import { FindOutMoreLink } from "@src/app/_components/content/FindOutMore";
65
import { HowToGetVaccineFallback } from "@src/app/_components/content/HowToGetVaccineFallback";
76
import { MoreInformation } from "@src/app/_components/content/MoreInformation";
87
import { Overview } from "@src/app/_components/content/Overview";
98
import Recommendation from "@src/app/_components/content/Recommendation";
9+
import WarningCallout from "@src/app/_components/content/WarningCallout";
1010
import { EligibilityVaccinePageContent } from "@src/app/_components/eligibility/EligibilityVaccinePageContent";
1111
import { RSVPregnancyInfo } from "@src/app/_components/vaccine-custom/RSVPregnancyInfo";
1212
import { NhsNumber, VaccineDetails, VaccineInfo, VaccineType } from "@src/models/vaccine";
@@ -70,7 +70,7 @@ const VaccineComponent = async ({ vaccineType }: VaccineProps): Promise<JSX.Elem
7070
<>
7171
<Overview styledVaccineContent={styledVaccineContent} vaccineType={vaccineType} />
7272
<Recommendation styledVaccineContent={styledVaccineContent} />
73-
<Callout styledVaccineContent={styledVaccineContent} vaccineType={vaccineType} />
73+
<WarningCallout styledVaccineContent={styledVaccineContent} vaccineType={vaccineType} />
7474
</>
7575
)}
7676

src/services/content-api/parsers/content-filter-service.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
} from "@src/services/content-api/parsers/content-filter-service";
1212
import {
1313
ContentApiVaccineResponse,
14-
HeadingWithContent,
14+
HeadingWithTypedContent,
1515
MainEntityOfPage,
1616
VaccinePageContent,
1717
VaccinePageSection,
@@ -696,9 +696,10 @@ describe("Content Filter", () => {
696696
});
697697

698698
it("should return all parts for callout section", () => {
699-
const expectedCallout: HeadingWithContent = {
699+
const expectedCallout: HeadingWithTypedContent = {
700700
heading: "Callout heading",
701701
content: "<p>Callout content</p>",
702+
contentType: "html",
702703
};
703704

704705
const pageCopyForRsv: VaccinePageContent = getFilteredContentForVaccine(

src/services/content-api/parsers/content-filter-service.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { getFilteredContentForWhoopingCoughVaccine } from "@src/services/content
44
import {
55
ContentApiVaccineResponse,
66
HasPartSubsection,
7-
HeadingWithContent,
7+
HeadingWithTypedContent,
88
MainEntityOfPage,
99
Overview,
1010
VaccinePageContent,
@@ -247,9 +247,13 @@ const getFilteredContentForStandardVaccine = (apiContent: string): VaccinePageCo
247247
subsections: _extractPartsForAspect(content, "SideEffectsHealthAspect"),
248248
};
249249

250-
let callout: HeadingWithContent | undefined;
250+
let callout: HeadingWithTypedContent | undefined;
251251
if (_hasCallout(content)) {
252-
callout = { heading: _extractCalloutHeading(content), content: _extractCalloutContent(content) };
252+
callout = {
253+
heading: _extractCalloutHeading(content),
254+
content: _extractCalloutContent(content),
255+
contentType: "html",
256+
};
253257
}
254258

255259
const webpageLink: URL = new URL(content.webpage);
@@ -267,6 +271,7 @@ const getFilteredContentForStandardVaccine = (apiContent: string): VaccinePageCo
267271

268272
export {
269273
getFilteredContentForVaccine,
274+
getFilteredContentForStandardVaccine,
270275
_findAspect,
271276
_hasHealthAspect,
272277
_extractPartsForAspect,

src/services/content-api/parsers/content-styling-service.test.tsx

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ import { VaccineType } from "@src/models/vaccine";
22
import {
33
extractHeadingAndContent,
44
getStyledContentForVaccine,
5+
styleCallout,
56
styleSection,
67
styleSubsection,
78
} from "@src/services/content-api/parsers/content-styling-service";
89
import {
910
HeadingWithContent,
11+
HeadingWithTypedContent,
1012
StyledPageSection,
1113
StyledVaccineContent,
1214
VaccinePageContent,
@@ -20,10 +22,11 @@ const mockNBSBookingActionHTML = "NBS Booking Link Test";
2022
jest.mock("@src/app/_components/nbs/NBSBookingAction", () => ({
2123
NBSBookingAction: () => mockNBSBookingActionHTML,
2224
}));
23-
const mockMarkdownWithStylingHtml = "<ul><li>sausage</li><li>egg</li><li>chips</li></ul>";
25+
2426
jest.mock("@project/src/app/_components/markdown/MarkdownWithStyling", () => ({
25-
MarkdownWithStyling: () => mockMarkdownWithStylingHtml,
27+
MarkdownWithStyling: jest.fn(),
2628
}));
29+
2730
jest.mock("sanitize-data", () => ({ sanitize: jest.fn() }));
2831

2932
describe("ContentStylingService", () => {
@@ -258,7 +261,11 @@ describe("ContentStylingService", () => {
258261
headline: "Side effects of the generic vaccine",
259262
subsections: [mockMarkdownSubsection, mockUrgentSubsection],
260263
};
261-
const mockCallout: HeadingWithContent = { heading: "Callout Heading", content: "Callout content" };
264+
const mockCallout: HeadingWithTypedContent = {
265+
heading: "Callout Heading",
266+
content: "Callout content",
267+
contentType: "string",
268+
};
262269
const mockRecommendation: HeadingWithContent = {
263270
heading: "Recommendation Heading",
264271
content: "Recommendation content",
@@ -423,4 +430,53 @@ describe("ContentStylingService", () => {
423430
expect(headingAndContent.content).toEqual("<p>Some content<h3>Heading</h3></p>");
424431
});
425432
});
433+
434+
describe("styleCallout", () => {
435+
it("should return styled callout component for markdown input", async () => {
436+
const mockCallout: HeadingWithTypedContent = {
437+
heading: "Heading for callout",
438+
content: "This is a styled paragraph callout subsection\n\nwith markdown",
439+
contentType: "markdown",
440+
};
441+
442+
const styledCallout = styleCallout(mockCallout);
443+
444+
expect(styledCallout?.heading).toEqual(mockCallout.heading);
445+
expect(styledCallout?.component.props.content).toEqual(mockCallout.content);
446+
});
447+
448+
it("should return styled callout component for html input", async () => {
449+
const mockCallout: HeadingWithTypedContent = {
450+
heading: "Heading for callout",
451+
content: "<h1>This is heading</h1><p>This is paragraph</p>",
452+
contentType: "html",
453+
};
454+
455+
const styledCallout = styleCallout(mockCallout);
456+
457+
expect(styledCallout?.heading).toEqual(mockCallout.heading);
458+
459+
render(styledCallout?.component);
460+
461+
const htmlCallout = screen.getByTestId("callout-html");
462+
expect(htmlCallout).toBeVisible();
463+
});
464+
465+
it("should return styled callout component for string input", async () => {
466+
const mockCallout: HeadingWithTypedContent = {
467+
heading: "Heading for callout",
468+
content: "This is a string",
469+
contentType: "string",
470+
};
471+
472+
const styledCallout = styleCallout(mockCallout);
473+
474+
expect(styledCallout?.heading).toEqual(mockCallout.heading);
475+
476+
render(styledCallout?.component);
477+
478+
const stringCallout = screen.getByTestId("callout-string");
479+
expect(stringCallout).toBeVisible();
480+
});
481+
});
426482
});

src/services/content-api/parsers/content-styling-service.tsx

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { styleHowToGetSectionForRsvPregnancy } from "@src/services/content-api/p
77
import {
88
HeadingLevel,
99
HeadingWithContent,
10+
HeadingWithTypedContent,
1011
Overview,
1112
StyledPageSection,
1213
StyledVaccineContent,
@@ -153,9 +154,25 @@ const styleHowToGetSection = (
153154
}
154155
};
155156

156-
function styleCallout(callout: HeadingWithContent | undefined): HeadingWithContent | undefined {
157+
function styleCallout(callout: HeadingWithTypedContent | undefined): StyledPageSection | undefined {
157158
if (callout) {
158-
return { heading: callout.heading, content: callout.content };
159+
switch (callout?.contentType) {
160+
case "markdown":
161+
return {
162+
heading: callout.heading,
163+
component: <MarkdownWithStyling content={callout.content} delineator={false} />,
164+
};
165+
case "html":
166+
return {
167+
heading: callout.heading,
168+
component: <div data-testid="callout-html" dangerouslySetInnerHTML={{ __html: callout.content || "" }} />,
169+
};
170+
case "string":
171+
return {
172+
heading: callout.heading,
173+
component: <div data-testid="callout-string">{callout.content}</div>,
174+
};
175+
}
159176
}
160177
return undefined;
161178
}
@@ -183,7 +200,7 @@ const getStyledContentForVaccine = async (
183200
const whoVaccineIsFor: StyledPageSection = styleSection(filteredContent.whoVaccineIsFor);
184201
const howToGetVaccine: StyledPageSection = styleHowToGetSection(vaccine, filteredContent.howToGetVaccine, fragile);
185202
const vaccineSideEffects: StyledPageSection = styleSection(filteredContent.vaccineSideEffects);
186-
const callout: HeadingWithContent | undefined = styleCallout(filteredContent.callout);
203+
const callout: StyledPageSection | undefined = styleCallout(filteredContent.callout);
187204
const recommendation: StyledPageSection | undefined = styleRecommendation(filteredContent.recommendation);
188205
const webpageLink: URL = filteredContent.webpageLink;
189206

@@ -199,4 +216,4 @@ const getStyledContentForVaccine = async (
199216
};
200217
};
201218

202-
export { styleSubsection, styleSection, getStyledContentForVaccine, extractHeadingAndContent };
219+
export { styleSubsection, styleSection, getStyledContentForVaccine, extractHeadingAndContent, styleCallout };

src/services/content-api/parsers/custom/flu-in-pregnancy.test.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,11 @@ describe("getFilteredContentForFluInPregnancyVaccine", () => {
105105

106106
it("should return warning callout", () => {
107107
const expected = {
108-
callout: { heading: "Booking service closed", content: "Flu vaccine bookings will reopen in autumn 2026" },
108+
callout: {
109+
heading: "Booking service closed",
110+
content: "Flu vaccine bookings will reopen in autumn 2026",
111+
contentType: "string",
112+
},
109113
};
110114

111115
const pageCopy = getFilteredContentForFluInPregnancyVaccine(apiResponse);

0 commit comments

Comments
 (0)