diff --git a/packages/drupal/gutenberg_blocks/src/blocks/conditional.tsx b/packages/drupal/gutenberg_blocks/src/blocks/conditional.tsx new file mode 100644 index 000000000..131c59b2f --- /dev/null +++ b/packages/drupal/gutenberg_blocks/src/blocks/conditional.tsx @@ -0,0 +1,171 @@ +import clsx from 'clsx'; +import { InnerBlocks, InspectorControls } from 'wordpress__block-editor'; +import { registerBlockType } from 'wordpress__blocks'; +import { BaseControl, PanelBody } from 'wordpress__components'; + +// @ts-ignore +const { t: __ } = Drupal; + +registerBlockType(`custom/conditional`, { + title: __('Conditional content'), + category: 'layout', + icon: 'category', + // Allow the block only at the root level to avoid GraphQL fragment recursion. + parent: ['custom/content'], + attributes: { + displayFrom: { + type: 'string', + default: '', + }, + displayTo: { + type: 'string', + default: '', + }, + purpose: { + type: 'string', + default: '', + }, + }, + edit(props) { + const { attributes, setAttributes } = props; + + const displayFrom = attributes.displayFrom as string | undefined; + const displayTo = attributes.displayTo as string | undefined; + const purpose = ((attributes.purpose as string) || '').trim(); + + // Same logic as in BlockConditional.tsx + const active = { + scheduledDisplay: [ + displayFrom + ? new Date(displayFrom).getTime() <= new Date().getTime() + : true, + displayTo ? new Date(displayTo).getTime() > new Date().getTime() : true, + ].every(Boolean), + }; + const isActive = Object.values(active).every(Boolean); + + const conditions = { + scheduledDisplay: + displayFrom || displayTo + ? 'đ ' + + __('Scheduled display') + + ': ' + + [ + displayFrom + ? __('From') + ' ' + new Date(displayFrom).toLocaleString() + : '', + displayTo + ? __('To') + ' ' + new Date(displayTo).toLocaleString() + : '', + ] + .filter(Boolean) + .join(' ') + : '', + }; + const hasConditions = Object.values(conditions).some(Boolean); + const summary = hasConditions ? ( + Object.entries(conditions) + .filter(([, value]) => !!value) + .map(([key, value]) =>
Complete
+ + + + + +No conditions
+ + + + format: gutenberg + summary: '' diff --git a/packages/schema/src/fragments/Page.gql b/packages/schema/src/fragments/Page.gql index 28f7127f2..33a67a4d5 100644 --- a/packages/schema/src/fragments/Page.gql +++ b/packages/schema/src/fragments/Page.gql @@ -38,6 +38,7 @@ fragment Page on Page { ...BlockHorizontalSeparator ...BlockAccordion ...BlockInfoGrid + ...BlockConditional } metaTags { tag diff --git a/packages/schema/src/fragments/PageContent/BlockConditional.gql b/packages/schema/src/fragments/PageContent/BlockConditional.gql new file mode 100644 index 000000000..5016b930f --- /dev/null +++ b/packages/schema/src/fragments/PageContent/BlockConditional.gql @@ -0,0 +1,17 @@ +fragment BlockConditional on BlockConditional { + displayFrom + displayTo + content { + __typename + ...BlockMarkup + ...BlockMedia + ...BlockForm + ...BlockImageTeasers + ...BlockCta + ...BlockImageWithText + ...BlockQuote + ...BlockHorizontalSeparator + ...BlockAccordion + ...BlockInfoGrid + } +} diff --git a/packages/schema/src/schema.graphql b/packages/schema/src/schema.graphql index 0ee5dc8b1..6f758c9c2 100644 --- a/packages/schema/src/schema.graphql +++ b/packages/schema/src/schema.graphql @@ -203,6 +203,18 @@ type Hero { @webformIdToUrl(id: "$") } +union CommonContent @resolveEditorBlockType = + | BlockMarkup + | BlockMedia + | BlockForm + | BlockImageTeasers + | BlockCta + | BlockImageWithText + | BlockQuote + | BlockHorizontalSeparator + | BlockAccordion + | BlockInfoGrid + union PageContent @resolveEditorBlockType = | BlockMarkup | BlockMedia @@ -214,6 +226,7 @@ union PageContent @resolveEditorBlockType = | BlockHorizontalSeparator | BlockAccordion | BlockInfoGrid + | BlockConditional type BlockForm @type(id: "custom/form") { url: Url @resolveEditorBlockAttribute(key: "formId") @webformIdToUrl(id: "$") @@ -335,6 +348,12 @@ type BlockHorizontalSeparator @type(id: "custom/horizontal-separator") { markup: Markup! @resolveEditorBlockMarkup } +type BlockConditional @type(id: "custom/conditional") { + displayFrom: String @resolveEditorBlockAttribute(key: "displayFrom") + displayTo: String @resolveEditorBlockAttribute(key: "displayTo") + content: [CommonContent] @resolveEditorBlockChildren +} + input PaginationInput { limit: Int! offset: Int! diff --git a/packages/ui/src/components/Organisms/PageContent/BlockConditional.tsx b/packages/ui/src/components/Organisms/PageContent/BlockConditional.tsx new file mode 100644 index 000000000..b401ead14 --- /dev/null +++ b/packages/ui/src/components/Organisms/PageContent/BlockConditional.tsx @@ -0,0 +1,30 @@ +import { BlockConditionalFragment } from '@custom/schema'; +import React, { useEffect, useState } from 'react'; + +import { isTruthy } from '../../../utils/isTruthy'; +import { CommonContent } from '../PageDisplay'; + +export function BlockConditional(props: BlockConditionalFragment) { + const [isActive, setIsActive] = useState(false); + useEffect(() => { + const active = { + scheduledDisplay: [ + props.displayFrom + ? new Date(props.displayFrom).getTime() <= new Date().getTime() + : true, + props.displayTo + ? new Date(props.displayTo).getTime() > new Date().getTime() + : true, + ].every(Boolean), + }; + setIsActive(Object.values(active).every(Boolean)); + }, []); + + return isActive ? ( + <> + {props.content?.filter(isTruthy).map((block, index) => { + returnComplete
+ ", + }, + ], + "displayFrom": "2024-05-16T11:05:00.000Z", + "displayTo": "2024-05-23T13:03:00.000Z", + }, + { + "__typename": "BlockConditional", + "content": [ + { + "markup": " +No conditions
+ ", + }, + ], + "displayFrom": null, + "displayTo": null, + }, + ], + }, + }, + } + `); +});