diff --git a/dotcom-rendering/src/components/ReporterCalloutBlockComponent.importable.tsx b/dotcom-rendering/src/components/ReporterCalloutBlockComponent.importable.tsx new file mode 100644 index 00000000000..1b872d87057 --- /dev/null +++ b/dotcom-rendering/src/components/ReporterCalloutBlockComponent.importable.tsx @@ -0,0 +1,52 @@ +import { isUndefined } from '@guardian/libs'; +import type { ReporterCalloutBlockElement } from '../types/content'; +import { Body } from './ExpandableAtom/Body'; +import { Container } from './ExpandableAtom/Container'; + +/** + * A callout to readers to share tips with reporters + * + * ## TODO: check if this needs to be an island - possibly not as there's no user interaction beyond expanding the box + * + */ + +export const ReporterCalloutBlockComponent = ({ + callout, +}: { + callout: ReporterCalloutBlockElement; +}) => { + const { + id, + title, + description, + activeUntil, + // contacts, TODO: Render contacts + } = callout; + const isExpired = isUndefined(activeUntil) + ? false + : Math.floor(new Date().getTime() / 1000) > activeUntil; + + return isExpired ? ( + <> + ) : ( +
+ { + // do nothing - I don't think we want to track interactions with this component in ophan + }} + > + + +
+ ); +}; diff --git a/dotcom-rendering/src/frontend/schemas/feArticle.json b/dotcom-rendering/src/frontend/schemas/feArticle.json index 03ee010d1cd..fa6fffd2ef1 100644 --- a/dotcom-rendering/src/frontend/schemas/feArticle.json +++ b/dotcom-rendering/src/frontend/schemas/feArticle.json @@ -611,6 +611,9 @@ { "$ref": "#/definitions/CalloutBlockElementV2" }, + { + "$ref": "#/definitions/ReporterCalloutBlockElement" + }, { "$ref": "#/definitions/CartoonBlockElement" }, @@ -1547,6 +1550,53 @@ "value" ] }, + "ReporterCalloutBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.ReporterCalloutBlockElement" + }, + "elementId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "activeFrom": { + "type": "number" + }, + "activeUntil": { + "type": "number" + }, + "displayOnSensitive": { + "type": "boolean" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "contacts": { + "type": "array", + "items": { + "$ref": "#/definitions/CalloutContactType" + } + } + }, + "required": [ + "_type", + "description", + "displayOnSensitive", + "elementId", + "id", + "title" + ] + }, "CartoonBlockElement": { "type": "object", "properties": { diff --git a/dotcom-rendering/src/lib/renderElement.tsx b/dotcom-rendering/src/lib/renderElement.tsx index 5d28c63b295..0a12cc61fa0 100644 --- a/dotcom-rendering/src/lib/renderElement.tsx +++ b/dotcom-rendering/src/lib/renderElement.tsx @@ -42,6 +42,7 @@ import { ProfileAtomWrapper } from '../components/ProfileAtomWrapper.importable' import { PullQuoteBlockComponent } from '../components/PullQuoteBlockComponent'; import { QandaAtom } from '../components/QandaAtom.importable'; import { QAndAExplainers } from '../components/QAndAExplainers'; +import { ReporterCalloutBlockComponent } from '../components/ReporterCalloutBlockComponent.importable'; import { RichLinkComponent } from '../components/RichLinkComponent.importable'; import { SoundcloudBlockComponent } from '../components/SoundcloudBlockComponent'; import { SpotifyBlockComponent } from '../components/SpotifyBlockComponent.importable'; @@ -220,6 +221,15 @@ export const renderElement = ({ ); } return null; + case 'model.dotcomrendering.pageElements.ReporterCalloutBlockElement': + if (switches.callouts) { + return ( + + + + ); + } + return null; case 'model.dotcomrendering.pageElements.CaptionBlockElement': return ( diff --git a/dotcom-rendering/src/model/block-schema.json b/dotcom-rendering/src/model/block-schema.json index 776b641d0c7..a5d68a872c8 100644 --- a/dotcom-rendering/src/model/block-schema.json +++ b/dotcom-rendering/src/model/block-schema.json @@ -99,6 +99,9 @@ { "$ref": "#/definitions/CalloutBlockElementV2" }, + { + "$ref": "#/definitions/ReporterCalloutBlockElement" + }, { "$ref": "#/definitions/CartoonBlockElement" }, @@ -1035,6 +1038,53 @@ "value" ] }, + "ReporterCalloutBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.ReporterCalloutBlockElement" + }, + "elementId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "activeFrom": { + "type": "number" + }, + "activeUntil": { + "type": "number" + }, + "displayOnSensitive": { + "type": "boolean" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "contacts": { + "type": "array", + "items": { + "$ref": "#/definitions/CalloutContactType" + } + } + }, + "required": [ + "_type", + "description", + "displayOnSensitive", + "elementId", + "id", + "title" + ] + }, "CartoonBlockElement": { "type": "object", "properties": { diff --git a/dotcom-rendering/src/types/content.ts b/dotcom-rendering/src/types/content.ts index 37b0274f15c..057400978c7 100644 --- a/dotcom-rendering/src/types/content.ts +++ b/dotcom-rendering/src/types/content.ts @@ -111,6 +111,19 @@ export interface CalloutBlockElementV2 { contacts?: CalloutContactType[]; } +export interface ReporterCalloutBlockElement { + _type: 'model.dotcomrendering.pageElements.ReporterCalloutBlockElement'; + elementId: string; + id: string; + activeFrom?: number; + activeUntil?: number; + displayOnSensitive: boolean; + title: string; + description: string; + role?: RoleType; + contacts?: CalloutContactType[]; +} + export interface CartoonBlockElement { _type: 'model.dotcomrendering.pageElements.CartoonBlockElement'; elementId: string; @@ -796,6 +809,7 @@ export type FEElement = | CaptionBlockElement | CalloutBlockElement | CalloutBlockElementV2 + | ReporterCalloutBlockElement | CartoonBlockElement | ChartAtomBlockElement | CodeBlockElement