diff --git a/apis/api-journeys/src/app/__generated__/graphql.ts b/apis/api-journeys/src/app/__generated__/graphql.ts index fa103e0e189..d81a572e394 100644 --- a/apis/api-journeys/src/app/__generated__/graphql.ts +++ b/apis/api-journeys/src/app/__generated__/graphql.ts @@ -374,14 +374,12 @@ export class IconBlockCreateInput { name?: Nullable; color?: Nullable; size?: Nullable; - customizable?: Nullable; } export class IconBlockUpdateInput { name?: Nullable; color?: Nullable; size?: Nullable; - customizable?: Nullable; } export class ImageBlockCreateInput { @@ -1317,7 +1315,6 @@ export class IconBlock implements Block { name?: Nullable; color?: Nullable; size?: Nullable; - customizable?: Nullable; } export class ImageBlock implements Block { diff --git a/apps/journeys-admin/__generated__/BlockDuplicate.ts b/apps/journeys-admin/__generated__/BlockDuplicate.ts index fcd1f972750..839908263bf 100644 --- a/apps/journeys-admin/__generated__/BlockDuplicate.ts +++ b/apps/journeys-admin/__generated__/BlockDuplicate.ts @@ -153,6 +153,7 @@ export interface BlockDuplicate_blockDuplicate_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface BlockDuplicate_blockDuplicate_MultiselectOptionBlock { @@ -550,6 +551,7 @@ export interface BlockDuplicate_blockDuplicate_VideoBlock { action: BlockDuplicate_blockDuplicate_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface BlockDuplicate_blockDuplicate_VideoTriggerBlock_triggerAction_NavigateToBlockAction { diff --git a/apps/journeys-admin/__generated__/BlockFields.ts b/apps/journeys-admin/__generated__/BlockFields.ts index 8f3a827873a..8151c9d5a4e 100644 --- a/apps/journeys-admin/__generated__/BlockFields.ts +++ b/apps/journeys-admin/__generated__/BlockFields.ts @@ -153,6 +153,7 @@ export interface BlockFields_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface BlockFields_MultiselectOptionBlock { @@ -550,6 +551,7 @@ export interface BlockFields_VideoBlock { action: BlockFields_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface BlockFields_VideoTriggerBlock_triggerAction_NavigateToBlockAction { diff --git a/apps/journeys-admin/__generated__/BlockRestore.ts b/apps/journeys-admin/__generated__/BlockRestore.ts index 2bb7eae8a20..693dd562cb3 100644 --- a/apps/journeys-admin/__generated__/BlockRestore.ts +++ b/apps/journeys-admin/__generated__/BlockRestore.ts @@ -153,6 +153,7 @@ export interface BlockRestore_blockRestore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface BlockRestore_blockRestore_MultiselectOptionBlock { @@ -560,6 +561,7 @@ export interface BlockRestore_blockRestore_VideoBlock { action: BlockRestore_blockRestore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface BlockRestore_blockRestore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { diff --git a/apps/journeys-admin/__generated__/CardCtaCreate.ts b/apps/journeys-admin/__generated__/CardCtaCreate.ts index cb8fb5d374a..3bb4ff2e0ea 100644 --- a/apps/journeys-admin/__generated__/CardCtaCreate.ts +++ b/apps/journeys-admin/__generated__/CardCtaCreate.ts @@ -26,6 +26,7 @@ export interface CardCtaCreate_image { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardCtaCreate_subtitle_settings { diff --git a/apps/journeys-admin/__generated__/CardCtaRestore.ts b/apps/journeys-admin/__generated__/CardCtaRestore.ts index 59716659fba..b6576bd1a0a 100644 --- a/apps/journeys-admin/__generated__/CardCtaRestore.ts +++ b/apps/journeys-admin/__generated__/CardCtaRestore.ts @@ -153,6 +153,7 @@ export interface CardCtaRestore_imageRestore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardCtaRestore_imageRestore_MultiselectOptionBlock { @@ -550,6 +551,7 @@ export interface CardCtaRestore_imageRestore_VideoBlock { action: CardCtaRestore_imageRestore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardCtaRestore_imageRestore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -758,6 +760,7 @@ export interface CardCtaRestore_subtitleRestore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardCtaRestore_subtitleRestore_MultiselectOptionBlock { @@ -1155,6 +1158,7 @@ export interface CardCtaRestore_subtitleRestore_VideoBlock { action: CardCtaRestore_subtitleRestore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardCtaRestore_subtitleRestore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -1363,6 +1367,7 @@ export interface CardCtaRestore_titleRestore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardCtaRestore_titleRestore_MultiselectOptionBlock { @@ -1760,6 +1765,7 @@ export interface CardCtaRestore_titleRestore_VideoBlock { action: CardCtaRestore_titleRestore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardCtaRestore_titleRestore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -1968,6 +1974,7 @@ export interface CardCtaRestore_button1Restore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardCtaRestore_button1Restore_MultiselectOptionBlock { @@ -2365,6 +2372,7 @@ export interface CardCtaRestore_button1Restore_VideoBlock { action: CardCtaRestore_button1Restore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardCtaRestore_button1Restore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -2573,6 +2581,7 @@ export interface CardCtaRestore_startIcon1Restore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardCtaRestore_startIcon1Restore_MultiselectOptionBlock { @@ -2970,6 +2979,7 @@ export interface CardCtaRestore_startIcon1Restore_VideoBlock { action: CardCtaRestore_startIcon1Restore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardCtaRestore_startIcon1Restore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -3178,6 +3188,7 @@ export interface CardCtaRestore_endIcon1Restore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardCtaRestore_endIcon1Restore_MultiselectOptionBlock { @@ -3575,6 +3586,7 @@ export interface CardCtaRestore_endIcon1Restore_VideoBlock { action: CardCtaRestore_endIcon1Restore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardCtaRestore_endIcon1Restore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -3783,6 +3795,7 @@ export interface CardCtaRestore_button2Restore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardCtaRestore_button2Restore_MultiselectOptionBlock { @@ -4180,6 +4193,7 @@ export interface CardCtaRestore_button2Restore_VideoBlock { action: CardCtaRestore_button2Restore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardCtaRestore_button2Restore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -4388,6 +4402,7 @@ export interface CardCtaRestore_startIcon2Restore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardCtaRestore_startIcon2Restore_MultiselectOptionBlock { @@ -4785,6 +4800,7 @@ export interface CardCtaRestore_startIcon2Restore_VideoBlock { action: CardCtaRestore_startIcon2Restore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardCtaRestore_startIcon2Restore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -4993,6 +5009,7 @@ export interface CardCtaRestore_endIcon2Restore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardCtaRestore_endIcon2Restore_MultiselectOptionBlock { @@ -5390,6 +5407,7 @@ export interface CardCtaRestore_endIcon2Restore_VideoBlock { action: CardCtaRestore_endIcon2Restore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardCtaRestore_endIcon2Restore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -5598,6 +5616,7 @@ export interface CardCtaRestore_button3Restore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardCtaRestore_button3Restore_MultiselectOptionBlock { @@ -5995,6 +6014,7 @@ export interface CardCtaRestore_button3Restore_VideoBlock { action: CardCtaRestore_button3Restore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardCtaRestore_button3Restore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -6203,6 +6223,7 @@ export interface CardCtaRestore_startIcon3Restore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardCtaRestore_startIcon3Restore_MultiselectOptionBlock { @@ -6600,6 +6621,7 @@ export interface CardCtaRestore_startIcon3Restore_VideoBlock { action: CardCtaRestore_startIcon3Restore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardCtaRestore_startIcon3Restore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -6808,6 +6830,7 @@ export interface CardCtaRestore_endIcon3Restore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardCtaRestore_endIcon3Restore_MultiselectOptionBlock { @@ -7205,6 +7228,7 @@ export interface CardCtaRestore_endIcon3Restore_VideoBlock { action: CardCtaRestore_endIcon3Restore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardCtaRestore_endIcon3Restore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { diff --git a/apps/journeys-admin/__generated__/CardFormCreate.ts b/apps/journeys-admin/__generated__/CardFormCreate.ts index fae660a2cab..dae6947af7b 100644 --- a/apps/journeys-admin/__generated__/CardFormCreate.ts +++ b/apps/journeys-admin/__generated__/CardFormCreate.ts @@ -26,6 +26,7 @@ export interface CardFormCreate_image { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardFormCreate_subtitle_settings { diff --git a/apps/journeys-admin/__generated__/CardFormRestore.ts b/apps/journeys-admin/__generated__/CardFormRestore.ts index ebdc3aea42f..99f437df27f 100644 --- a/apps/journeys-admin/__generated__/CardFormRestore.ts +++ b/apps/journeys-admin/__generated__/CardFormRestore.ts @@ -153,6 +153,7 @@ export interface CardFormRestore_image_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardFormRestore_image_MultiselectOptionBlock { @@ -550,6 +551,7 @@ export interface CardFormRestore_image_VideoBlock { action: CardFormRestore_image_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardFormRestore_image_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -758,6 +760,7 @@ export interface CardFormRestore_subtitle_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardFormRestore_subtitle_MultiselectOptionBlock { @@ -1155,6 +1158,7 @@ export interface CardFormRestore_subtitle_VideoBlock { action: CardFormRestore_subtitle_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardFormRestore_subtitle_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -1363,6 +1367,7 @@ export interface CardFormRestore_title_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardFormRestore_title_MultiselectOptionBlock { @@ -1760,6 +1765,7 @@ export interface CardFormRestore_title_VideoBlock { action: CardFormRestore_title_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardFormRestore_title_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -1968,6 +1974,7 @@ export interface CardFormRestore_textResponse_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardFormRestore_textResponse_MultiselectOptionBlock { @@ -2365,6 +2372,7 @@ export interface CardFormRestore_textResponse_VideoBlock { action: CardFormRestore_textResponse_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardFormRestore_textResponse_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -2573,6 +2581,7 @@ export interface CardFormRestore_button_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardFormRestore_button_MultiselectOptionBlock { @@ -2970,6 +2979,7 @@ export interface CardFormRestore_button_VideoBlock { action: CardFormRestore_button_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardFormRestore_button_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -3178,6 +3188,7 @@ export interface CardFormRestore_startIcon_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardFormRestore_startIcon_MultiselectOptionBlock { @@ -3575,6 +3586,7 @@ export interface CardFormRestore_startIcon_VideoBlock { action: CardFormRestore_startIcon_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardFormRestore_startIcon_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -3783,6 +3795,7 @@ export interface CardFormRestore_endIcon_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardFormRestore_endIcon_MultiselectOptionBlock { @@ -4180,6 +4193,7 @@ export interface CardFormRestore_endIcon_VideoBlock { action: CardFormRestore_endIcon_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardFormRestore_endIcon_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -4388,6 +4402,7 @@ export interface CardFormRestore_body_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardFormRestore_body_MultiselectOptionBlock { @@ -4785,6 +4800,7 @@ export interface CardFormRestore_body_VideoBlock { action: CardFormRestore_body_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardFormRestore_body_VideoTriggerBlock_triggerAction_NavigateToBlockAction { diff --git a/apps/journeys-admin/__generated__/CardIntroCreate.ts b/apps/journeys-admin/__generated__/CardIntroCreate.ts index 967b70575aa..c4fa9850507 100644 --- a/apps/journeys-admin/__generated__/CardIntroCreate.ts +++ b/apps/journeys-admin/__generated__/CardIntroCreate.ts @@ -414,6 +414,7 @@ export interface CardIntroCreate_video { action: CardIntroCreate_video_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardIntroCreate { diff --git a/apps/journeys-admin/__generated__/CardIntroRestore.ts b/apps/journeys-admin/__generated__/CardIntroRestore.ts index da06c753668..3dcca11dfb3 100644 --- a/apps/journeys-admin/__generated__/CardIntroRestore.ts +++ b/apps/journeys-admin/__generated__/CardIntroRestore.ts @@ -153,6 +153,7 @@ export interface CardIntroRestore_subtitle_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardIntroRestore_subtitle_MultiselectOptionBlock { @@ -550,6 +551,7 @@ export interface CardIntroRestore_subtitle_VideoBlock { action: CardIntroRestore_subtitle_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardIntroRestore_subtitle_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -758,6 +760,7 @@ export interface CardIntroRestore_title_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardIntroRestore_title_MultiselectOptionBlock { @@ -1155,6 +1158,7 @@ export interface CardIntroRestore_title_VideoBlock { action: CardIntroRestore_title_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardIntroRestore_title_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -1363,6 +1367,7 @@ export interface CardIntroRestore_body_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardIntroRestore_body_MultiselectOptionBlock { @@ -1760,6 +1765,7 @@ export interface CardIntroRestore_body_VideoBlock { action: CardIntroRestore_body_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardIntroRestore_body_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -1968,6 +1974,7 @@ export interface CardIntroRestore_button_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardIntroRestore_button_MultiselectOptionBlock { @@ -2365,6 +2372,7 @@ export interface CardIntroRestore_button_VideoBlock { action: CardIntroRestore_button_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardIntroRestore_button_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -2573,6 +2581,7 @@ export interface CardIntroRestore_startIcon_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardIntroRestore_startIcon_MultiselectOptionBlock { @@ -2970,6 +2979,7 @@ export interface CardIntroRestore_startIcon_VideoBlock { action: CardIntroRestore_startIcon_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardIntroRestore_startIcon_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -3178,6 +3188,7 @@ export interface CardIntroRestore_endIcon_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardIntroRestore_endIcon_MultiselectOptionBlock { @@ -3575,6 +3586,7 @@ export interface CardIntroRestore_endIcon_VideoBlock { action: CardIntroRestore_endIcon_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardIntroRestore_endIcon_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -3783,6 +3795,7 @@ export interface CardIntroRestore_video_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardIntroRestore_video_MultiselectOptionBlock { @@ -4180,6 +4193,7 @@ export interface CardIntroRestore_video_VideoBlock { action: CardIntroRestore_video_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardIntroRestore_video_VideoTriggerBlock_triggerAction_NavigateToBlockAction { diff --git a/apps/journeys-admin/__generated__/CardPollCreate.ts b/apps/journeys-admin/__generated__/CardPollCreate.ts index 52e9c117fd5..3a000d681af 100644 --- a/apps/journeys-admin/__generated__/CardPollCreate.ts +++ b/apps/journeys-admin/__generated__/CardPollCreate.ts @@ -26,6 +26,7 @@ export interface CardPollCreate_image { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardPollCreate_subtitle_settings { diff --git a/apps/journeys-admin/__generated__/CardPollRestore.ts b/apps/journeys-admin/__generated__/CardPollRestore.ts index 04afb5af959..1154a03b0f1 100644 --- a/apps/journeys-admin/__generated__/CardPollRestore.ts +++ b/apps/journeys-admin/__generated__/CardPollRestore.ts @@ -153,6 +153,7 @@ export interface CardPollRestore_imageRestore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardPollRestore_imageRestore_MultiselectOptionBlock { @@ -550,6 +551,7 @@ export interface CardPollRestore_imageRestore_VideoBlock { action: CardPollRestore_imageRestore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardPollRestore_imageRestore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -758,6 +760,7 @@ export interface CardPollRestore_subtitleRestore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardPollRestore_subtitleRestore_MultiselectOptionBlock { @@ -1155,6 +1158,7 @@ export interface CardPollRestore_subtitleRestore_VideoBlock { action: CardPollRestore_subtitleRestore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardPollRestore_subtitleRestore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -1363,6 +1367,7 @@ export interface CardPollRestore_titleRestore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardPollRestore_titleRestore_MultiselectOptionBlock { @@ -1760,6 +1765,7 @@ export interface CardPollRestore_titleRestore_VideoBlock { action: CardPollRestore_titleRestore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardPollRestore_titleRestore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -1968,6 +1974,7 @@ export interface CardPollRestore_radioQuestionRestore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardPollRestore_radioQuestionRestore_MultiselectOptionBlock { @@ -2365,6 +2372,7 @@ export interface CardPollRestore_radioQuestionRestore_VideoBlock { action: CardPollRestore_radioQuestionRestore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardPollRestore_radioQuestionRestore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -2573,6 +2581,7 @@ export interface CardPollRestore_radioOption1Restore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardPollRestore_radioOption1Restore_MultiselectOptionBlock { @@ -2970,6 +2979,7 @@ export interface CardPollRestore_radioOption1Restore_VideoBlock { action: CardPollRestore_radioOption1Restore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardPollRestore_radioOption1Restore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -3178,6 +3188,7 @@ export interface CardPollRestore_radioOption2Restore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardPollRestore_radioOption2Restore_MultiselectOptionBlock { @@ -3575,6 +3586,7 @@ export interface CardPollRestore_radioOption2Restore_VideoBlock { action: CardPollRestore_radioOption2Restore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardPollRestore_radioOption2Restore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -3783,6 +3795,7 @@ export interface CardPollRestore_radioOption3Restore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardPollRestore_radioOption3Restore_MultiselectOptionBlock { @@ -4180,6 +4193,7 @@ export interface CardPollRestore_radioOption3Restore_VideoBlock { action: CardPollRestore_radioOption3Restore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardPollRestore_radioOption3Restore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -4388,6 +4402,7 @@ export interface CardPollRestore_radioOption4Restore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardPollRestore_radioOption4Restore_MultiselectOptionBlock { @@ -4785,6 +4800,7 @@ export interface CardPollRestore_radioOption4Restore_VideoBlock { action: CardPollRestore_radioOption4Restore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardPollRestore_radioOption4Restore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -4993,6 +5009,7 @@ export interface CardPollRestore_bodyRestore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardPollRestore_bodyRestore_MultiselectOptionBlock { @@ -5390,6 +5407,7 @@ export interface CardPollRestore_bodyRestore_VideoBlock { action: CardPollRestore_bodyRestore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardPollRestore_bodyRestore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { diff --git a/apps/journeys-admin/__generated__/CardQuoteCreate.ts b/apps/journeys-admin/__generated__/CardQuoteCreate.ts index eddeb248c03..13250dbee6e 100644 --- a/apps/journeys-admin/__generated__/CardQuoteCreate.ts +++ b/apps/journeys-admin/__generated__/CardQuoteCreate.ts @@ -26,6 +26,7 @@ export interface CardQuoteCreate_image { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardQuoteCreate_subtitle_settings { diff --git a/apps/journeys-admin/__generated__/CardQuoteRestore.ts b/apps/journeys-admin/__generated__/CardQuoteRestore.ts index bb88bc38846..18d6ad202fe 100644 --- a/apps/journeys-admin/__generated__/CardQuoteRestore.ts +++ b/apps/journeys-admin/__generated__/CardQuoteRestore.ts @@ -153,6 +153,7 @@ export interface CardQuoteRestore_image_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardQuoteRestore_image_MultiselectOptionBlock { @@ -550,6 +551,7 @@ export interface CardQuoteRestore_image_VideoBlock { action: CardQuoteRestore_image_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardQuoteRestore_image_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -758,6 +760,7 @@ export interface CardQuoteRestore_subtitle_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardQuoteRestore_subtitle_MultiselectOptionBlock { @@ -1155,6 +1158,7 @@ export interface CardQuoteRestore_subtitle_VideoBlock { action: CardQuoteRestore_subtitle_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardQuoteRestore_subtitle_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -1363,6 +1367,7 @@ export interface CardQuoteRestore_title_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardQuoteRestore_title_MultiselectOptionBlock { @@ -1760,6 +1765,7 @@ export interface CardQuoteRestore_title_VideoBlock { action: CardQuoteRestore_title_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardQuoteRestore_title_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -1968,6 +1974,7 @@ export interface CardQuoteRestore_body_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CardQuoteRestore_body_MultiselectOptionBlock { @@ -2365,6 +2372,7 @@ export interface CardQuoteRestore_body_VideoBlock { action: CardQuoteRestore_body_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardQuoteRestore_body_VideoTriggerBlock_triggerAction_NavigateToBlockAction { diff --git a/apps/journeys-admin/__generated__/CardVideoCreate.ts b/apps/journeys-admin/__generated__/CardVideoCreate.ts index 6521ab8fe6f..130f87f877a 100644 --- a/apps/journeys-admin/__generated__/CardVideoCreate.ts +++ b/apps/journeys-admin/__generated__/CardVideoCreate.ts @@ -190,6 +190,7 @@ export interface CardVideoCreate_video { action: CardVideoCreate_video_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CardVideoCreate { diff --git a/apps/journeys-admin/__generated__/CardVideoDelete.ts b/apps/journeys-admin/__generated__/CardVideoDelete.ts index f15ac9e6bcc..d8ee4390f0d 100644 --- a/apps/journeys-admin/__generated__/CardVideoDelete.ts +++ b/apps/journeys-admin/__generated__/CardVideoDelete.ts @@ -194,6 +194,7 @@ export interface CardVideoDelete_video_VideoBlock { action: CardVideoDelete_video_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export type CardVideoDelete_video = CardVideoDelete_video_ImageBlock | CardVideoDelete_video_VideoBlock; diff --git a/apps/journeys-admin/__generated__/CardVideoRestore.ts b/apps/journeys-admin/__generated__/CardVideoRestore.ts index 2cf4970f57f..db3bb3a5deb 100644 --- a/apps/journeys-admin/__generated__/CardVideoRestore.ts +++ b/apps/journeys-admin/__generated__/CardVideoRestore.ts @@ -194,6 +194,7 @@ export interface CardVideoRestore_video_VideoBlock { action: CardVideoRestore_video_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export type CardVideoRestore_video = CardVideoRestore_video_ImageBlock | CardVideoRestore_video_VideoBlock; diff --git a/apps/journeys-admin/__generated__/CoverBlockRestore.ts b/apps/journeys-admin/__generated__/CoverBlockRestore.ts index 18b80eb7017..7050596d38b 100644 --- a/apps/journeys-admin/__generated__/CoverBlockRestore.ts +++ b/apps/journeys-admin/__generated__/CoverBlockRestore.ts @@ -195,6 +195,7 @@ export interface CoverBlockRestore_blockRestore_VideoBlock { action: CoverBlockRestore_blockRestore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CoverBlockRestore_blockRestore_ImageBlock { @@ -214,6 +215,7 @@ export interface CoverBlockRestore_blockRestore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export type CoverBlockRestore_blockRestore = CoverBlockRestore_blockRestore_StepBlock | CoverBlockRestore_blockRestore_VideoBlock | CoverBlockRestore_blockRestore_ImageBlock; diff --git a/apps/journeys-admin/__generated__/CoverImageBlockCreate.ts b/apps/journeys-admin/__generated__/CoverImageBlockCreate.ts index bebe09fbd43..3142dc81559 100644 --- a/apps/journeys-admin/__generated__/CoverImageBlockCreate.ts +++ b/apps/journeys-admin/__generated__/CoverImageBlockCreate.ts @@ -26,6 +26,7 @@ export interface CoverImageBlockCreate_imageBlockCreate { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CoverImageBlockCreate_cardBlockUpdate { diff --git a/apps/journeys-admin/__generated__/CoverImageBlockUpdate.ts b/apps/journeys-admin/__generated__/CoverImageBlockUpdate.ts index 6306d8e0cb3..974bdee69ef 100644 --- a/apps/journeys-admin/__generated__/CoverImageBlockUpdate.ts +++ b/apps/journeys-admin/__generated__/CoverImageBlockUpdate.ts @@ -26,6 +26,7 @@ export interface CoverImageBlockUpdate_imageBlockUpdate { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface CoverImageBlockUpdate { diff --git a/apps/journeys-admin/__generated__/CoverVideoBlockCreate.ts b/apps/journeys-admin/__generated__/CoverVideoBlockCreate.ts index e67d1b2a042..11082e334e4 100644 --- a/apps/journeys-admin/__generated__/CoverVideoBlockCreate.ts +++ b/apps/journeys-admin/__generated__/CoverVideoBlockCreate.ts @@ -190,6 +190,7 @@ export interface CoverVideoBlockCreate_videoBlockCreate { action: CoverVideoBlockCreate_videoBlockCreate_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CoverVideoBlockCreate_cardBlockUpdate { diff --git a/apps/journeys-admin/__generated__/CoverVideoBlockUpdate.ts b/apps/journeys-admin/__generated__/CoverVideoBlockUpdate.ts index b532bf5c0a4..03bb32b691f 100644 --- a/apps/journeys-admin/__generated__/CoverVideoBlockUpdate.ts +++ b/apps/journeys-admin/__generated__/CoverVideoBlockUpdate.ts @@ -190,6 +190,7 @@ export interface CoverVideoBlockUpdate_videoBlockUpdate { action: CoverVideoBlockUpdate_videoBlockUpdate_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface CoverVideoBlockUpdate { diff --git a/apps/journeys-admin/__generated__/GetAdminJourney.ts b/apps/journeys-admin/__generated__/GetAdminJourney.ts index e9f42c6f046..0c46f437642 100644 --- a/apps/journeys-admin/__generated__/GetAdminJourney.ts +++ b/apps/journeys-admin/__generated__/GetAdminJourney.ts @@ -167,6 +167,7 @@ export interface GetAdminJourney_journey_blocks_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetAdminJourney_journey_blocks_MultiselectOptionBlock { @@ -564,6 +565,7 @@ export interface GetAdminJourney_journey_blocks_VideoBlock { action: GetAdminJourney_journey_blocks_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface GetAdminJourney_journey_blocks_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -645,6 +647,7 @@ export interface GetAdminJourney_journey_primaryImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetAdminJourney_journey_creatorImageBlock { @@ -664,6 +667,7 @@ export interface GetAdminJourney_journey_creatorImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetAdminJourney_journey_userJourneys_user { @@ -745,6 +749,7 @@ export interface GetAdminJourney_journey_logoImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetAdminJourney_journey_menuStepBlock { diff --git a/apps/journeys-admin/__generated__/GetAdminJourneyWithPlausibleToken.ts b/apps/journeys-admin/__generated__/GetAdminJourneyWithPlausibleToken.ts index 527951e0503..6ac468a27b6 100644 --- a/apps/journeys-admin/__generated__/GetAdminJourneyWithPlausibleToken.ts +++ b/apps/journeys-admin/__generated__/GetAdminJourneyWithPlausibleToken.ts @@ -167,6 +167,7 @@ export interface GetAdminJourneyWithPlausibleToken_journey_blocks_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetAdminJourneyWithPlausibleToken_journey_blocks_MultiselectOptionBlock { @@ -564,6 +565,7 @@ export interface GetAdminJourneyWithPlausibleToken_journey_blocks_VideoBlock { action: GetAdminJourneyWithPlausibleToken_journey_blocks_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface GetAdminJourneyWithPlausibleToken_journey_blocks_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -645,6 +647,7 @@ export interface GetAdminJourneyWithPlausibleToken_journey_primaryImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetAdminJourneyWithPlausibleToken_journey_creatorImageBlock { @@ -664,6 +667,7 @@ export interface GetAdminJourneyWithPlausibleToken_journey_creatorImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetAdminJourneyWithPlausibleToken_journey_userJourneys_user { @@ -745,6 +749,7 @@ export interface GetAdminJourneyWithPlausibleToken_journey_logoImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetAdminJourneyWithPlausibleToken_journey_menuStepBlock { diff --git a/apps/journeys-admin/__generated__/GetJourney.ts b/apps/journeys-admin/__generated__/GetJourney.ts index b6b660e62b8..34e9cd8128d 100644 --- a/apps/journeys-admin/__generated__/GetJourney.ts +++ b/apps/journeys-admin/__generated__/GetJourney.ts @@ -167,6 +167,7 @@ export interface GetJourney_journey_blocks_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_blocks_MultiselectOptionBlock { @@ -564,6 +565,7 @@ export interface GetJourney_journey_blocks_VideoBlock { action: GetJourney_journey_blocks_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface GetJourney_journey_blocks_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -645,6 +647,7 @@ export interface GetJourney_journey_primaryImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_creatorImageBlock { @@ -664,6 +667,7 @@ export interface GetJourney_journey_creatorImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_userJourneys_user { @@ -745,6 +749,7 @@ export interface GetJourney_journey_logoImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_menuStepBlock { diff --git a/apps/journeys-admin/__generated__/GetPublisherTemplate.ts b/apps/journeys-admin/__generated__/GetPublisherTemplate.ts index fa137c6cf3f..2c189203cb1 100644 --- a/apps/journeys-admin/__generated__/GetPublisherTemplate.ts +++ b/apps/journeys-admin/__generated__/GetPublisherTemplate.ts @@ -167,6 +167,7 @@ export interface GetPublisherTemplate_publisherTemplate_blocks_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetPublisherTemplate_publisherTemplate_blocks_MultiselectOptionBlock { @@ -564,6 +565,7 @@ export interface GetPublisherTemplate_publisherTemplate_blocks_VideoBlock { action: GetPublisherTemplate_publisherTemplate_blocks_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface GetPublisherTemplate_publisherTemplate_blocks_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -645,6 +647,7 @@ export interface GetPublisherTemplate_publisherTemplate_primaryImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetPublisherTemplate_publisherTemplate_creatorImageBlock { @@ -664,6 +667,7 @@ export interface GetPublisherTemplate_publisherTemplate_creatorImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetPublisherTemplate_publisherTemplate_userJourneys_user { @@ -745,6 +749,7 @@ export interface GetPublisherTemplate_publisherTemplate_logoImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetPublisherTemplate_publisherTemplate_menuStepBlock { diff --git a/apps/journeys-admin/__generated__/ImageBlockCreate.ts b/apps/journeys-admin/__generated__/ImageBlockCreate.ts index 2fba8fd6c17..48920533321 100644 --- a/apps/journeys-admin/__generated__/ImageBlockCreate.ts +++ b/apps/journeys-admin/__generated__/ImageBlockCreate.ts @@ -26,6 +26,7 @@ export interface ImageBlockCreate_imageBlockCreate { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface ImageBlockCreate { diff --git a/apps/journeys-admin/__generated__/ImageBlockUpdate.ts b/apps/journeys-admin/__generated__/ImageBlockUpdate.ts index d3671824d4a..e22e9428d19 100644 --- a/apps/journeys-admin/__generated__/ImageBlockUpdate.ts +++ b/apps/journeys-admin/__generated__/ImageBlockUpdate.ts @@ -26,6 +26,7 @@ export interface ImageBlockUpdate_imageBlockUpdate { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface ImageBlockUpdate { diff --git a/apps/journeys-admin/__generated__/ImageFields.ts b/apps/journeys-admin/__generated__/ImageFields.ts index cf522fda056..cccc1e6e187 100644 --- a/apps/journeys-admin/__generated__/ImageFields.ts +++ b/apps/journeys-admin/__generated__/ImageFields.ts @@ -24,4 +24,5 @@ export interface ImageFields { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } diff --git a/apps/journeys-admin/__generated__/JourneyFields.ts b/apps/journeys-admin/__generated__/JourneyFields.ts index e4ab828d645..54c883e57b2 100644 --- a/apps/journeys-admin/__generated__/JourneyFields.ts +++ b/apps/journeys-admin/__generated__/JourneyFields.ts @@ -167,6 +167,7 @@ export interface JourneyFields_blocks_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_blocks_MultiselectOptionBlock { @@ -564,6 +565,7 @@ export interface JourneyFields_blocks_VideoBlock { action: JourneyFields_blocks_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface JourneyFields_blocks_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -645,6 +647,7 @@ export interface JourneyFields_primaryImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_creatorImageBlock { @@ -664,6 +667,7 @@ export interface JourneyFields_creatorImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_userJourneys_user { @@ -745,6 +749,7 @@ export interface JourneyFields_logoImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_menuStepBlock { diff --git a/apps/journeys-admin/__generated__/JourneyImageBlockCreate.ts b/apps/journeys-admin/__generated__/JourneyImageBlockCreate.ts index 599547ebff8..d4068f7b270 100644 --- a/apps/journeys-admin/__generated__/JourneyImageBlockCreate.ts +++ b/apps/journeys-admin/__generated__/JourneyImageBlockCreate.ts @@ -26,6 +26,7 @@ export interface JourneyImageBlockCreate_imageBlockCreate { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyImageBlockCreate { diff --git a/apps/journeys-admin/__generated__/JourneyImageBlockUpdate.ts b/apps/journeys-admin/__generated__/JourneyImageBlockUpdate.ts index 96e46de4ad2..f132fa0b49f 100644 --- a/apps/journeys-admin/__generated__/JourneyImageBlockUpdate.ts +++ b/apps/journeys-admin/__generated__/JourneyImageBlockUpdate.ts @@ -26,6 +26,7 @@ export interface JourneyImageBlockUpdate_imageBlockUpdate { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyImageBlockUpdate { diff --git a/apps/journeys-admin/__generated__/LogoBlockCreate.ts b/apps/journeys-admin/__generated__/LogoBlockCreate.ts index 96c78d50025..b937a732a70 100644 --- a/apps/journeys-admin/__generated__/LogoBlockCreate.ts +++ b/apps/journeys-admin/__generated__/LogoBlockCreate.ts @@ -26,6 +26,7 @@ export interface LogoBlockCreate_imageBlockCreate { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface LogoBlockCreate_journeyUpdate_logoImageBlock { diff --git a/apps/journeys-admin/__generated__/MenuBlockRestore.ts b/apps/journeys-admin/__generated__/MenuBlockRestore.ts index 0b06ee61b51..535659158f7 100644 --- a/apps/journeys-admin/__generated__/MenuBlockRestore.ts +++ b/apps/journeys-admin/__generated__/MenuBlockRestore.ts @@ -153,6 +153,7 @@ export interface MenuBlockRestore_stepRestore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface MenuBlockRestore_stepRestore_MultiselectOptionBlock { @@ -560,6 +561,7 @@ export interface MenuBlockRestore_stepRestore_VideoBlock { action: MenuBlockRestore_stepRestore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface MenuBlockRestore_stepRestore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { diff --git a/apps/journeys-admin/__generated__/PosterImageBlockCreate.ts b/apps/journeys-admin/__generated__/PosterImageBlockCreate.ts index b93746b1007..49215576ac2 100644 --- a/apps/journeys-admin/__generated__/PosterImageBlockCreate.ts +++ b/apps/journeys-admin/__generated__/PosterImageBlockCreate.ts @@ -26,6 +26,7 @@ export interface PosterImageBlockCreate_imageBlockCreate { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface PosterImageBlockCreate_videoBlockUpdate { diff --git a/apps/journeys-admin/__generated__/PosterImageBlockRestore.ts b/apps/journeys-admin/__generated__/PosterImageBlockRestore.ts index 5fd36a5f0f2..d577543bc3b 100644 --- a/apps/journeys-admin/__generated__/PosterImageBlockRestore.ts +++ b/apps/journeys-admin/__generated__/PosterImageBlockRestore.ts @@ -29,6 +29,7 @@ export interface PosterImageBlockRestore_blockRestore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export type PosterImageBlockRestore_blockRestore = PosterImageBlockRestore_blockRestore_StepBlock | PosterImageBlockRestore_blockRestore_ImageBlock; diff --git a/apps/journeys-admin/__generated__/PosterImageBlockUpdate.ts b/apps/journeys-admin/__generated__/PosterImageBlockUpdate.ts index be77fde3873..1313d93b18f 100644 --- a/apps/journeys-admin/__generated__/PosterImageBlockUpdate.ts +++ b/apps/journeys-admin/__generated__/PosterImageBlockUpdate.ts @@ -26,6 +26,7 @@ export interface PosterImageBlockUpdate_imageBlockUpdate { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface PosterImageBlockUpdate { diff --git a/apps/journeys-admin/__generated__/RadioOptionImageCreate.ts b/apps/journeys-admin/__generated__/RadioOptionImageCreate.ts index 797806f053c..60367f156ab 100644 --- a/apps/journeys-admin/__generated__/RadioOptionImageCreate.ts +++ b/apps/journeys-admin/__generated__/RadioOptionImageCreate.ts @@ -26,6 +26,7 @@ export interface RadioOptionImageCreate_imageBlockCreate { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface RadioOptionImageCreate_radioOptionBlockUpdate { diff --git a/apps/journeys-admin/__generated__/RadioOptionImageRestore.ts b/apps/journeys-admin/__generated__/RadioOptionImageRestore.ts index ee327263b7a..cade77b8ef0 100644 --- a/apps/journeys-admin/__generated__/RadioOptionImageRestore.ts +++ b/apps/journeys-admin/__generated__/RadioOptionImageRestore.ts @@ -29,6 +29,7 @@ export interface RadioOptionImageRestore_blockRestore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export type RadioOptionImageRestore_blockRestore = RadioOptionImageRestore_blockRestore_StepBlock | RadioOptionImageRestore_blockRestore_ImageBlock; diff --git a/apps/journeys-admin/__generated__/RadioOptionImageUpdate.ts b/apps/journeys-admin/__generated__/RadioOptionImageUpdate.ts index 1fa8ead979d..fd52e5cea8d 100644 --- a/apps/journeys-admin/__generated__/RadioOptionImageUpdate.ts +++ b/apps/journeys-admin/__generated__/RadioOptionImageUpdate.ts @@ -26,6 +26,7 @@ export interface RadioOptionImageUpdate_imageBlockUpdate { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface RadioOptionImageUpdate { diff --git a/apps/journeys-admin/__generated__/StepBlockRestoreFromAction.ts b/apps/journeys-admin/__generated__/StepBlockRestoreFromAction.ts index ab483ae447c..5cb77cff4a9 100644 --- a/apps/journeys-admin/__generated__/StepBlockRestoreFromAction.ts +++ b/apps/journeys-admin/__generated__/StepBlockRestoreFromAction.ts @@ -153,6 +153,7 @@ export interface StepBlockRestoreFromAction_blockRestore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface StepBlockRestoreFromAction_blockRestore_MultiselectOptionBlock { @@ -560,6 +561,7 @@ export interface StepBlockRestoreFromAction_blockRestore_VideoBlock { action: StepBlockRestoreFromAction_blockRestore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface StepBlockRestoreFromAction_blockRestore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { diff --git a/apps/journeys-admin/__generated__/StepBlockRestoreFromSocialPreview.ts b/apps/journeys-admin/__generated__/StepBlockRestoreFromSocialPreview.ts index 5ad9973b5c8..f33dc62b271 100644 --- a/apps/journeys-admin/__generated__/StepBlockRestoreFromSocialPreview.ts +++ b/apps/journeys-admin/__generated__/StepBlockRestoreFromSocialPreview.ts @@ -153,6 +153,7 @@ export interface StepBlockRestoreFromSocialPreview_blockRestore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface StepBlockRestoreFromSocialPreview_blockRestore_MultiselectOptionBlock { @@ -560,6 +561,7 @@ export interface StepBlockRestoreFromSocialPreview_blockRestore_VideoBlock { action: StepBlockRestoreFromSocialPreview_blockRestore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface StepBlockRestoreFromSocialPreview_blockRestore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { diff --git a/apps/journeys-admin/__generated__/StepBlockRestoreFromStep.ts b/apps/journeys-admin/__generated__/StepBlockRestoreFromStep.ts index a8253eb1c33..f282fd027a7 100644 --- a/apps/journeys-admin/__generated__/StepBlockRestoreFromStep.ts +++ b/apps/journeys-admin/__generated__/StepBlockRestoreFromStep.ts @@ -153,6 +153,7 @@ export interface StepBlockRestoreFromStep_blockRestore_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface StepBlockRestoreFromStep_blockRestore_MultiselectOptionBlock { @@ -560,6 +561,7 @@ export interface StepBlockRestoreFromStep_blockRestore_VideoBlock { action: StepBlockRestoreFromStep_blockRestore_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface StepBlockRestoreFromStep_blockRestore_VideoTriggerBlock_triggerAction_NavigateToBlockAction { diff --git a/apps/journeys-admin/__generated__/StepDuplicate.ts b/apps/journeys-admin/__generated__/StepDuplicate.ts index e61f5af5397..aedca84d445 100644 --- a/apps/journeys-admin/__generated__/StepDuplicate.ts +++ b/apps/journeys-admin/__generated__/StepDuplicate.ts @@ -153,6 +153,7 @@ export interface StepDuplicate_blockDuplicate_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface StepDuplicate_blockDuplicate_MultiselectOptionBlock { @@ -560,6 +561,7 @@ export interface StepDuplicate_blockDuplicate_VideoBlock { action: StepDuplicate_blockDuplicate_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface StepDuplicate_blockDuplicate_VideoTriggerBlock_triggerAction_NavigateToBlockAction { diff --git a/apps/journeys-admin/__generated__/TemplateCustomizeCreateMuxVideoUploadByFileMutation.ts b/apps/journeys-admin/__generated__/TemplateCustomizeCreateMuxVideoUploadByFileMutation.ts new file mode 100644 index 00000000000..879985d8772 --- /dev/null +++ b/apps/journeys-admin/__generated__/TemplateCustomizeCreateMuxVideoUploadByFileMutation.ts @@ -0,0 +1,22 @@ +/* tslint:disable */ +/* eslint-disable */ +// @generated +// This file was automatically generated and should not be edited. + +// ==================================================== +// GraphQL mutation operation: TemplateCustomizeCreateMuxVideoUploadByFileMutation +// ==================================================== + +export interface TemplateCustomizeCreateMuxVideoUploadByFileMutation_createMuxVideoUploadByFile { + __typename: "MuxVideo"; + uploadUrl: string | null; + id: string; +} + +export interface TemplateCustomizeCreateMuxVideoUploadByFileMutation { + createMuxVideoUploadByFile: TemplateCustomizeCreateMuxVideoUploadByFileMutation_createMuxVideoUploadByFile; +} + +export interface TemplateCustomizeCreateMuxVideoUploadByFileMutationVariables { + name: string; +} diff --git a/apps/journeys-admin/__generated__/TemplateCustomizeGetMyMuxVideoQuery.ts b/apps/journeys-admin/__generated__/TemplateCustomizeGetMyMuxVideoQuery.ts new file mode 100644 index 00000000000..0f392894465 --- /dev/null +++ b/apps/journeys-admin/__generated__/TemplateCustomizeGetMyMuxVideoQuery.ts @@ -0,0 +1,24 @@ +/* tslint:disable */ +/* eslint-disable */ +// @generated +// This file was automatically generated and should not be edited. + +// ==================================================== +// GraphQL query operation: TemplateCustomizeGetMyMuxVideoQuery +// ==================================================== + +export interface TemplateCustomizeGetMyMuxVideoQuery_getMyMuxVideo { + __typename: "MuxVideo"; + id: string; + assetId: string | null; + playbackId: string | null; + readyToStream: boolean; +} + +export interface TemplateCustomizeGetMyMuxVideoQuery { + getMyMuxVideo: TemplateCustomizeGetMyMuxVideoQuery_getMyMuxVideo; +} + +export interface TemplateCustomizeGetMyMuxVideoQueryVariables { + id: string; +} diff --git a/apps/journeys-admin/__generated__/TextResponseWithButtonRestore.ts b/apps/journeys-admin/__generated__/TextResponseWithButtonRestore.ts index 205e143cdda..a0dd4d9247a 100644 --- a/apps/journeys-admin/__generated__/TextResponseWithButtonRestore.ts +++ b/apps/journeys-admin/__generated__/TextResponseWithButtonRestore.ts @@ -153,6 +153,7 @@ export interface TextResponseWithButtonRestore_textResponse_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface TextResponseWithButtonRestore_textResponse_MultiselectOptionBlock { @@ -550,6 +551,7 @@ export interface TextResponseWithButtonRestore_textResponse_VideoBlock { action: TextResponseWithButtonRestore_textResponse_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface TextResponseWithButtonRestore_textResponse_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -758,6 +760,7 @@ export interface TextResponseWithButtonRestore_button_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface TextResponseWithButtonRestore_button_MultiselectOptionBlock { @@ -1155,6 +1158,7 @@ export interface TextResponseWithButtonRestore_button_VideoBlock { action: TextResponseWithButtonRestore_button_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface TextResponseWithButtonRestore_button_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -1363,6 +1367,7 @@ export interface TextResponseWithButtonRestore_startIcon_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface TextResponseWithButtonRestore_startIcon_MultiselectOptionBlock { @@ -1760,6 +1765,7 @@ export interface TextResponseWithButtonRestore_startIcon_VideoBlock { action: TextResponseWithButtonRestore_startIcon_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface TextResponseWithButtonRestore_startIcon_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -1968,6 +1974,7 @@ export interface TextResponseWithButtonRestore_endIcon_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface TextResponseWithButtonRestore_endIcon_MultiselectOptionBlock { @@ -2365,6 +2372,7 @@ export interface TextResponseWithButtonRestore_endIcon_VideoBlock { action: TextResponseWithButtonRestore_endIcon_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface TextResponseWithButtonRestore_endIcon_VideoTriggerBlock_triggerAction_NavigateToBlockAction { diff --git a/apps/journeys-admin/__generated__/VideoBlockCreate.ts b/apps/journeys-admin/__generated__/VideoBlockCreate.ts index 3bf16127157..895cf4e5136 100644 --- a/apps/journeys-admin/__generated__/VideoBlockCreate.ts +++ b/apps/journeys-admin/__generated__/VideoBlockCreate.ts @@ -190,6 +190,7 @@ export interface VideoBlockCreate_videoBlockCreate { action: VideoBlockCreate_videoBlockCreate_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface VideoBlockCreate { diff --git a/apps/journeys-admin/__generated__/VideoBlockUpdate.ts b/apps/journeys-admin/__generated__/VideoBlockUpdate.ts index abcae1009aa..fe6b84143be 100644 --- a/apps/journeys-admin/__generated__/VideoBlockUpdate.ts +++ b/apps/journeys-admin/__generated__/VideoBlockUpdate.ts @@ -190,6 +190,7 @@ export interface VideoBlockUpdate_videoBlockUpdate { action: VideoBlockUpdate_videoBlockUpdate_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface VideoBlockUpdate { diff --git a/apps/journeys-admin/__generated__/VideoFields.ts b/apps/journeys-admin/__generated__/VideoFields.ts index c842d21b285..ec706b87c34 100644 --- a/apps/journeys-admin/__generated__/VideoFields.ts +++ b/apps/journeys-admin/__generated__/VideoFields.ts @@ -190,4 +190,5 @@ export interface VideoFields { action: VideoFields_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } diff --git a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/Canvas.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/Canvas.stories.tsx index f217b3088ef..111438ca057 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/Canvas.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/Canvas.stories.tsx @@ -74,7 +74,8 @@ const steps: Array> = [ blurhash: 'L9AS}j^-0dVC4Tq[=~PATeXSV?aL', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'typographyBlockId1', @@ -179,7 +180,8 @@ const steps: Array> = [ blurhash: 'LQEf1v^*XkEe*IyD$RnOyXTJRjjG', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'typographyBlockId1', @@ -283,7 +285,8 @@ const steps: Array> = [ blurhash: 'L;KRQa-Rs-kA}ot4bZj@SMR,WWj@', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'typographyBlockId1', @@ -448,7 +451,8 @@ const steps: Array> = [ blurhash: 'L3CZt$_NyX4n=|?b00Ip8_IV00IA', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'typographyBlockId1', @@ -579,6 +583,7 @@ const steps: Array> = [ posterBlockId: null, fullsize: null, action: null, + customizable: null, children: [] } ] @@ -620,7 +625,8 @@ const steps: Array> = [ children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { __typename: 'SignUpBlock', @@ -671,7 +677,8 @@ const steps: Array> = [ blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'typographyBlockId1', diff --git a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/CardWrapper/CardWrapper.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/CardWrapper/CardWrapper.spec.tsx index 1e4989c44a4..7b61416e8cd 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/CardWrapper/CardWrapper.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/CardWrapper/CardWrapper.spec.tsx @@ -66,6 +66,7 @@ describe('CardWrapper', () => { showGeneratedSubtitles: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [ { id: 'image5.id', @@ -80,7 +81,8 @@ describe('CardWrapper', () => { blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ] } @@ -114,7 +116,8 @@ describe('CardWrapper', () => { width: 1920, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ], endAt: null, @@ -138,7 +141,8 @@ describe('CardWrapper', () => { subtitleLanguage: null, showGeneratedSubtitles: null, videoId: null, - videoVariantLanguageId: '529' + videoVariantLanguageId: '529', + customizable: null } ], coverBlockId: 'video5.id', @@ -194,6 +198,7 @@ describe('CardWrapper', () => { showGeneratedSubtitles: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [ { id: 'image5.id', @@ -208,7 +213,8 @@ describe('CardWrapper', () => { blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ] } @@ -242,7 +248,8 @@ describe('CardWrapper', () => { width: 1920, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ], endAt: null, @@ -266,7 +273,8 @@ describe('CardWrapper', () => { subtitleLanguage: null, showGeneratedSubtitles: null, videoId: null, - videoVariantLanguageId: '529' + videoVariantLanguageId: '529', + customizable: null } ], coverBlockId: 'video5.id', @@ -391,7 +399,8 @@ describe('CardWrapper', () => { blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ] } diff --git a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/ButtonEdit/ButtonEdit.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/ButtonEdit/ButtonEdit.stories.tsx index d7bc94bf983..71747b853e6 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/ButtonEdit/ButtonEdit.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/ButtonEdit/ButtonEdit.stories.tsx @@ -135,7 +135,8 @@ const steps: Array> = [ blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, contained, filled, diff --git a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/MultiselectOptionEdit/MultiselectOptionEdit.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/MultiselectOptionEdit/MultiselectOptionEdit.stories.tsx index dba9fdc902c..5ad64e97a53 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/MultiselectOptionEdit/MultiselectOptionEdit.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/MultiselectOptionEdit/MultiselectOptionEdit.stories.tsx @@ -88,7 +88,8 @@ const steps: Array> = [ blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'typographyBlockId1', diff --git a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/MultiselectQuestionEdit/MultiselectQuestionEdit.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/MultiselectQuestionEdit/MultiselectQuestionEdit.stories.tsx index f68547941a6..aa769c61435 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/MultiselectQuestionEdit/MultiselectQuestionEdit.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/MultiselectQuestionEdit/MultiselectQuestionEdit.stories.tsx @@ -118,7 +118,8 @@ const steps: Array> = [ blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, heading, description, diff --git a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/RadioOptionEdit/RadioOptionEdit.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/RadioOptionEdit/RadioOptionEdit.stories.tsx index 11538a7aa1b..c446f3e5ca1 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/RadioOptionEdit/RadioOptionEdit.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/RadioOptionEdit/RadioOptionEdit.stories.tsx @@ -93,7 +93,8 @@ const steps: Array> = [ blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'typographyBlockId1', diff --git a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/RadioQuestionEdit/RadioQuestionEdit.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/RadioQuestionEdit/RadioQuestionEdit.stories.tsx index 76808127f3f..453e4a46aa2 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/RadioQuestionEdit/RadioQuestionEdit.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/RadioQuestionEdit/RadioQuestionEdit.stories.tsx @@ -123,7 +123,8 @@ const steps: Array> = [ blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, heading, description, diff --git a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/SignUpEdit/SignUpEdit.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/SignUpEdit/SignUpEdit.stories.tsx index e4ce7e2fc4b..2f4a9149ef3 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/SignUpEdit/SignUpEdit.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/SignUpEdit/SignUpEdit.stories.tsx @@ -68,7 +68,8 @@ const steps: Array> = [ blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, selectedBlock ] diff --git a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/TypographyEdit/TypographyEdit.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/TypographyEdit/TypographyEdit.stories.tsx index 26e608f94d3..f4f59c787ea 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/TypographyEdit/TypographyEdit.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/TypographyEdit/TypographyEdit.stories.tsx @@ -109,7 +109,8 @@ const steps: Array> = [ blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, heading, body, diff --git a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/SelectableWrapper/SelectableWrapper.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/SelectableWrapper/SelectableWrapper.spec.tsx index 5f147a000db..49ad47993f0 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/SelectableWrapper/SelectableWrapper.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/SelectableWrapper/SelectableWrapper.spec.tsx @@ -96,7 +96,8 @@ describe('SelectableWrapper', () => { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const radioOption1: TreeBlock = { diff --git a/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/SocialPreviewNode/SocialPreviewNode.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/SocialPreviewNode/SocialPreviewNode.spec.tsx index 1ea6892214d..d688046eae6 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/SocialPreviewNode/SocialPreviewNode.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/SocialPreviewNode/SocialPreviewNode.spec.tsx @@ -43,7 +43,8 @@ describe('SocialPreviewNode', () => { blurhash: '', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const defaultJourney: Journey = { diff --git a/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/SocialPreviewNode/SocialPreviewNode.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/SocialPreviewNode/SocialPreviewNode.stories.tsx index 40cd9620572..b8d8627af45 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/SocialPreviewNode/SocialPreviewNode.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/SocialPreviewNode/SocialPreviewNode.stories.tsx @@ -95,7 +95,8 @@ const image: ImageBlock = { blurhash: '', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const defaultJourney: Journey = { diff --git a/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/StepBlockNode/libs/getBackgroundImage/getBackgroundImage.spec.ts b/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/StepBlockNode/libs/getBackgroundImage/getBackgroundImage.spec.ts index ebba4e171bf..274cc797aab 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/StepBlockNode/libs/getBackgroundImage/getBackgroundImage.spec.ts +++ b/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/StepBlockNode/libs/getBackgroundImage/getBackgroundImage.spec.ts @@ -37,7 +37,8 @@ const image: TreeBlock = { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const video: TreeBlock = { @@ -63,6 +64,7 @@ const video: TreeBlock = { showGeneratedSubtitles: null, eventLabel: null, endEventLabel: null, + customizable: null, mediaVideo: { __typename: 'Video', id: '2_0-FallingPlates', diff --git a/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/StepBlockNode/libs/getCardMetadata/getCardMetadata.spec.ts b/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/StepBlockNode/libs/getCardMetadata/getCardMetadata.spec.ts index 34dff5389a6..4e0bab765c3 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/StepBlockNode/libs/getCardMetadata/getCardMetadata.spec.ts +++ b/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/StepBlockNode/libs/getCardMetadata/getCardMetadata.spec.ts @@ -62,7 +62,8 @@ const image: TreeBlock = { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const video: TreeBlock = { @@ -78,6 +79,7 @@ const video: TreeBlock = { action: null, eventLabel: null, endEventLabel: null, + customizable: null, videoId: '2_0-FallingPlates', videoVariantLanguageId: '529', source: VideoBlockSource.internal, diff --git a/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/StepBlockNode/libs/getPriorityBlock/getPriorityBlock.spec.ts b/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/StepBlockNode/libs/getPriorityBlock/getPriorityBlock.spec.ts index c9019313e9d..81ed369b805 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/StepBlockNode/libs/getPriorityBlock/getPriorityBlock.spec.ts +++ b/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/StepBlockNode/libs/getPriorityBlock/getPriorityBlock.spec.ts @@ -61,7 +61,8 @@ const image: TreeBlock = { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const radioQuestion: TreeBlock = { @@ -129,6 +130,7 @@ const video: TreeBlock = { posterBlockId: 'posterBlockId', fullsize: null, action: null, + customizable: null, videoId: '2_0-FallingPlates', videoVariantLanguageId: '529', source: VideoBlockSource.internal, diff --git a/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/StepBlockNode/libs/getPriorityImage/getPriorityImage.spec.ts b/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/StepBlockNode/libs/getPriorityImage/getPriorityImage.spec.ts index 2e0f748755d..35734f037ae 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/StepBlockNode/libs/getPriorityImage/getPriorityImage.spec.ts +++ b/apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/StepBlockNode/libs/getPriorityImage/getPriorityImage.spec.ts @@ -20,7 +20,8 @@ const image: TreeBlock = { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const card: TreeBlock = { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/AddBlock/NewImageButton/NewImageButton.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/AddBlock/NewImageButton/NewImageButton.tsx index 1138f21b587..c9c4a5d98e4 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/AddBlock/NewImageButton/NewImageButton.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/AddBlock/NewImageButton/NewImageButton.tsx @@ -59,7 +59,8 @@ export function NewImageButton(): ReactElement { __typename: 'ImageBlock', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } addBlock({ block: imageBlock, diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/AddBlock/NewVideoButton/NewVideoButton.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/AddBlock/NewVideoButton/NewVideoButton.tsx index fef2a43d457..f5396431c4e 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/AddBlock/NewVideoButton/NewVideoButton.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/AddBlock/NewVideoButton/NewVideoButton.tsx @@ -75,6 +75,7 @@ export function NewVideoButton({ action: null, eventLabel: null, endEventLabel: null, + customizable: null, __typename: 'VideoBlock', children: [] } diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/JourneyAppearance/Host/HostForm/HostAvatarsButton/HostAvatarsButton.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/JourneyAppearance/Host/HostForm/HostAvatarsButton/HostAvatarsButton.tsx index 9f70ba6fd9d..07a069fac87 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/JourneyAppearance/Host/HostForm/HostAvatarsButton/HostAvatarsButton.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/JourneyAppearance/Host/HostForm/HostAvatarsButton/HostAvatarsButton.tsx @@ -142,7 +142,8 @@ export function HostAvatarsButton(): ReactElement { parentOrder: 0, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } : null } diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/JourneyAppearance/Logo/Logo.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/JourneyAppearance/Logo/Logo.spec.tsx index ab540b11b22..e8b783a43b4 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/JourneyAppearance/Logo/Logo.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/JourneyAppearance/Logo/Logo.spec.tsx @@ -75,7 +75,8 @@ describe('Logo', () => { height: 1, blurhash: '', focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } function getLogoImageBlockCreateMock(): MockedResponse< diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/JourneyAppearance/Logo/Logo.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/JourneyAppearance/Logo/Logo.tsx index 66773a6107a..178967b1c75 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/JourneyAppearance/Logo/Logo.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/JourneyAppearance/Logo/Logo.tsx @@ -96,7 +96,8 @@ export function Logo(): ReactElement { blurhash: imageBlockCreateInput.blurhash ?? '', scale: 100, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } add({ diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/BackgroundMedia.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/BackgroundMedia.spec.tsx index e38470429b0..f5ca4c5ae93 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/BackgroundMedia.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/BackgroundMedia.spec.tsx @@ -111,6 +111,7 @@ const video: TreeBlock = { showGeneratedSubtitles: null, eventLabel: null, endEventLabel: null, + customizable: null, mediaVideo: { __typename: 'Video', id: '2_0-FallingPlates', @@ -151,7 +152,8 @@ const image: TreeBlock = { scale: 100, children: [], focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const coverVideoBlockDeleteMock: MockedResponse< diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/BackgroundMedia.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/BackgroundMedia.stories.tsx index cd5984e2db8..0819fa42842 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/BackgroundMedia.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/BackgroundMedia.stories.tsx @@ -132,6 +132,7 @@ const video: TreeBlock = { showGeneratedSubtitles: null, eventLabel: null, endEventLabel: null, + customizable: null, mediaVideo: { __typename: 'Video', id: '2_0-FallingPlates', @@ -172,7 +173,8 @@ const poster: TreeBlock = { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const image: TreeBlock = { @@ -188,7 +190,8 @@ const image: TreeBlock = { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const videoLanguages: GetVideoVariantLanguages_video = { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Image/BackgroundMediaImage.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Image/BackgroundMediaImage.spec.tsx index e55b8689d97..6e5a1007035 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Image/BackgroundMediaImage.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Image/BackgroundMediaImage.spec.tsx @@ -35,6 +35,7 @@ import { ThemeMode, ThemeName } from '../../../../../../../../../../../__generated__/globalTypes' +import { JourneyFields } from '../../../../../../../../../../../__generated__/JourneyFields' import { COVER_BLOCK_DELETE } from '../../../../../../../../../../libs/useCoverBlockDeleteMutation/useCoverBlockDeleteMutation' import { COVER_BLOCK_RESTORE } from '../../../../../../../../../../libs/useCoverBlockRestoreMutation/useCoverBlockRestoreMutation' import { CommandRedoItem } from '../../../../../../../../Toolbar/Items/CommandRedoItem' @@ -144,7 +145,14 @@ const image: TreeBlock = { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null +} + +const cardWithImageCover: TreeBlock = { + ...card, + coverBlockId: image.id, + children: [image] } describe('BackgroundMediaImage', () => { @@ -196,7 +204,8 @@ describe('BackgroundMediaImage', () => { blurhash: image.blurhash, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, cardBlockUpdate: { id: card.id, @@ -358,7 +367,8 @@ describe('BackgroundMediaImage', () => { blurhash: image.blurhash, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } } const coverImageBlockUpdateMock: MockedResponse< diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Image/BackgroundMediaImage.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Image/BackgroundMediaImage.tsx index 436bafa8bf4..a0d9e9d5be4 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Image/BackgroundMediaImage.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Image/BackgroundMediaImage.tsx @@ -106,7 +106,8 @@ export function BackgroundMediaImage({ parentOrder: null, scale: 100, focalTop: 50, - focalLeft: 50 + focalLeft: 50, + customizable: null } add({ @@ -344,21 +345,22 @@ export function BackgroundMediaImage({ } } + const imageCoverBlock = + coverBlock?.__typename === 'ImageBlock' ? coverBlock : null + return ( deleteImageBlock()} /> diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Image/FocalPoint/FocalPoint.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Image/FocalPoint/FocalPoint.spec.tsx index 7ea84ca3d9a..11e55271324 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Image/FocalPoint/FocalPoint.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Image/FocalPoint/FocalPoint.spec.tsx @@ -26,7 +26,8 @@ describe('FocalPoint', () => { blurhash: 'blurhash', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const imageBlockResult = { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Image/ZoomImage/ZoomImage.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Image/ZoomImage/ZoomImage.spec.tsx index b1d59b6d0f7..62bbd421bb1 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Image/ZoomImage/ZoomImage.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Image/ZoomImage/ZoomImage.spec.tsx @@ -19,7 +19,8 @@ describe('ZoomImage', () => { blurhash: 'blurhash', scale: 100, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const imageBlockResult = { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Video/BackgroundMediaVideo.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Video/BackgroundMediaVideo.spec.tsx index 60b77919e4d..3882d4f2da0 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Video/BackgroundMediaVideo.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Video/BackgroundMediaVideo.spec.tsx @@ -43,6 +43,7 @@ import { GetVideoVariables } from '../../../../../../../../../../../__generated__/GetVideo' import { VideoBlockSource } from '../../../../../../../../../../../__generated__/globalTypes' +import { JourneyFields } from '../../../../../../../../../../../__generated__/JourneyFields' import { COVER_BLOCK_DELETE } from '../../../../../../../../../../libs/useCoverBlockDeleteMutation/useCoverBlockDeleteMutation' import { COVER_BLOCK_RESTORE } from '../../../../../../../../../../libs/useCoverBlockRestoreMutation/useCoverBlockRestoreMutation' import { MuxVideoUploadProvider } from '../../../../../../../../../MuxVideoUploadProvider' @@ -145,6 +146,7 @@ const video: TreeBlock = { showGeneratedSubtitles: null, eventLabel: null, endEventLabel: null, + customizable: null, mediaVideo: { __typename: 'Video', id: '2_0-FallingPlates', @@ -166,6 +168,12 @@ const video: TreeBlock = { children: [] } +const cardWithVideoCover: TreeBlock = { + ...card, + coverBlockId: video.id, + children: [video] +} + const getVideoMock: MockedResponse = { request: { query: GET_VIDEO, diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Video/BackgroundMediaVideo.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Video/BackgroundMediaVideo.tsx index 9fc8a1d7822..e4ae44eff4d 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Video/BackgroundMediaVideo.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/BackgroundMedia/Video/BackgroundMediaVideo.tsx @@ -142,7 +142,8 @@ export function BackgroundMediaVideo({ : null, showGeneratedSubtitles: null, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null } add({ @@ -373,12 +374,10 @@ export function BackgroundMediaVideo({ } } + const videoCoverBlock = + coverBlock?.__typename === 'VideoBlock' ? coverBlock : null + return ( - + ) } diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/Card.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/Card.spec.tsx index 770a6f2a637..b0321543748 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/Card.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/Card.spec.tsx @@ -318,7 +318,8 @@ describe('Card', () => { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ] }) @@ -344,7 +345,8 @@ describe('Card', () => { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ] }) @@ -371,6 +373,7 @@ describe('Card', () => { image: null, subtitleLanguage: null, showGeneratedSubtitles: null, + customizable: null, mediaVideo: { __typename: 'Video', id: '2_0-FallingPlates', diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/Card.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/Card.stories.tsx index 6900296afdf..77536332f7e 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/Card.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Card/Card.stories.tsx @@ -110,7 +110,8 @@ export const Filled: StoryObj = { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ] } diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Image/Image.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Image/Image.spec.tsx index 8e98e2787db..6486bff09c5 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Image/Image.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Image/Image.spec.tsx @@ -24,7 +24,8 @@ describe('Image', () => { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } it('should display Image Options', () => { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Image/Image.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Image/Image.stories.tsx index 90f0a987e31..a5b02f566ff 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Image/Image.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Image/Image.stories.tsx @@ -33,7 +33,8 @@ const image: TreeBlock = { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const Template: StoryObj> = { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Image/Options/ImageOptions.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Image/Options/ImageOptions.spec.tsx index 42f9e920bd0..06d6d867423 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Image/Options/ImageOptions.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Image/Options/ImageOptions.spec.tsx @@ -54,7 +54,8 @@ describe('ImageOptions', () => { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const response: ImageBlockUpdate = { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Image/Options/ImageOptions.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Image/Options/ImageOptions.stories.tsx index e0d4ce7a077..87e0a73aae8 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Image/Options/ImageOptions.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Image/Options/ImageOptions.stories.tsx @@ -34,7 +34,8 @@ const image: TreeBlock = { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const Template: StoryObj<{ block: TreeBlock }> = { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/RadioOption/RadioOptionImage/RadioOptionImage.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/RadioOption/RadioOptionImage/RadioOptionImage.spec.tsx index ab0625d662c..3000e986b0c 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/RadioOption/RadioOptionImage/RadioOptionImage.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/RadioOption/RadioOptionImage/RadioOptionImage.spec.tsx @@ -148,7 +148,8 @@ const image: TreeBlock = { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } describe('RadioOptionImage', () => { @@ -199,7 +200,8 @@ describe('RadioOptionImage', () => { blurhash: image.blurhash, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, radioOptionBlockUpdate: { id: radioOption.id, @@ -484,7 +486,8 @@ describe('RadioOptionImage', () => { blurhash: image.blurhash, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } } const radioOptionImageUpdateMock: MockedResponse< @@ -567,7 +570,8 @@ describe('RadioOptionImage', () => { blurhash: image.blurhash, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } } const radioOptionImageUpdateMock: MockedResponse< @@ -670,7 +674,8 @@ describe('RadioOptionImage', () => { blurhash: image.blurhash, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } } const radioOptionImageUpdateMock: MockedResponse< diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/RadioOption/RadioOptionImage/RadioOptionImage.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/RadioOption/RadioOptionImage/RadioOptionImage.tsx index 4bd09ee556f..c27ae21e522 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/RadioOption/RadioOptionImage/RadioOptionImage.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/RadioOption/RadioOptionImage/RadioOptionImage.tsx @@ -153,7 +153,8 @@ export function RadioOptionImage({ parentOrder: null, scale: 100, focalTop: 50, - focalLeft: 50 + focalLeft: 50, + customizable: null } add({ diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Video/Options/VideoOptions.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Video/Options/VideoOptions.spec.tsx index e393088f12e..0c30d5d83b3 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Video/Options/VideoOptions.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Video/Options/VideoOptions.spec.tsx @@ -62,6 +62,7 @@ const video: TreeBlock = { showGeneratedSubtitles: null, eventLabel: null, endEventLabel: null, + customizable: null, mediaVideo: { __typename: 'Video', id: '2_0-FallingPlates', diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Video/Options/VideoOptions.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Video/Options/VideoOptions.stories.tsx index 172350ec9c6..d662da4b99a 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Video/Options/VideoOptions.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Video/Options/VideoOptions.stories.tsx @@ -47,6 +47,7 @@ const video: TreeBlock = { showGeneratedSubtitles: null, eventLabel: null, endEventLabel: null, + customizable: null, mediaVideo: { __typename: 'Video', id: '2_0-FallingPlates', diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Video/Video.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Video/Video.spec.tsx index a493314f862..165959f8b36 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Video/Video.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Video/Video.spec.tsx @@ -62,6 +62,7 @@ describe('Video', () => { variantLanguages: [] }, posterBlockId: null, + customizable: null, children: [] } diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Video/Video.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Video/Video.stories.tsx index 0b75e264adb..5224dd5afbc 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Video/Video.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/blocks/Video/Video.stories.tsx @@ -58,6 +58,7 @@ const defaultVideo: TreeBlock = { objectFit: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/Action.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/Action.tsx index 3fa551b804c..5fd9557da8a 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/Action.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/Action.tsx @@ -19,8 +19,8 @@ import { import { TextFieldFormRef } from '../../../../../../../TextFieldForm/TextFieldForm' import { useActionCommand } from '../../../../../../utils/useActionCommand' +import { ActionCustomizationToggle } from './ActionCustomizationToggle' import { ChatAction } from './ChatAction' -import { CustomizationToggle } from './CustomizationToggle' import { EmailAction } from './EmailAction' import { LinkAction } from './LinkAction' import { NavigateToBlockAction } from './NavigateToBlockAction' @@ -129,7 +129,7 @@ export function Action(): ReactElement { {isPhone && } {action === 'NavigateToBlockAction' && } {(isLink || isEmail || isChat || isPhone) && journey?.template && ( - + )} diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/CustomizationToggle/CustomizationToggle.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/ActionCustomizationToggle/ActionCustomizationToggle.spec.tsx similarity index 95% rename from apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/CustomizationToggle/CustomizationToggle.spec.tsx rename to apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/ActionCustomizationToggle/ActionCustomizationToggle.spec.tsx index ddd5d4613ad..96328e0660f 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/CustomizationToggle/CustomizationToggle.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/ActionCustomizationToggle/ActionCustomizationToggle.spec.tsx @@ -10,14 +10,14 @@ import { } from '../../../../../../../../../../__generated__/BlockFields' import { ContactActionType } from '../../../../../../../../../../__generated__/globalTypes' -import { CustomizationToggle } from './CustomizationToggle' +import { ActionCustomizationToggle } from './ActionCustomizationToggle' const mockAddAction = jest.fn() jest.mock('../../../../../../../utils/useActionCommand', () => ({ useActionCommand: () => ({ addAction: mockAddAction }) })) -describe('CustomizationToggle', () => { +describe('ActionCustomizationToggle', () => { beforeEach(() => { jest.clearAllMocks() jest.restoreAllMocks() @@ -46,7 +46,7 @@ describe('CustomizationToggle', () => { render( - + ) @@ -73,7 +73,7 @@ describe('CustomizationToggle', () => { render( - + ) expect(screen.getByText('Needs Customization')).toBeInTheDocument() @@ -104,7 +104,7 @@ describe('CustomizationToggle', () => { render( - + ) @@ -144,7 +144,7 @@ describe('CustomizationToggle', () => { render( - + ) @@ -195,7 +195,7 @@ describe('CustomizationToggle', () => { render( - + ) @@ -242,7 +242,7 @@ describe('CustomizationToggle', () => { render( - + ) @@ -272,7 +272,7 @@ describe('CustomizationToggle', () => { render( - + ) @@ -311,7 +311,7 @@ describe('CustomizationToggle', () => { render( - + ) @@ -357,7 +357,7 @@ describe('CustomizationToggle', () => { render( - + ) @@ -398,7 +398,7 @@ describe('CustomizationToggle', () => { render( - + ) diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/CustomizationToggle/CustomizationToggle.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/ActionCustomizationToggle/ActionCustomizationToggle.tsx similarity index 98% rename from apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/CustomizationToggle/CustomizationToggle.tsx rename to apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/ActionCustomizationToggle/ActionCustomizationToggle.tsx index cc34ec2bb48..b997461bdbb 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/CustomizationToggle/CustomizationToggle.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/ActionCustomizationToggle/ActionCustomizationToggle.tsx @@ -9,7 +9,7 @@ import { isActionBlock } from '@core/journeys/ui/isActionBlock' import { useActionCommand } from '../../../../../../../utils/useActionCommand' -export function CustomizationToggle(): ReactElement { +export function ActionCustomizationToggle(): ReactElement { const { t } = useTranslation('apps-journeys-admin') const { addAction } = useActionCommand() const { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/ActionCustomizationToggle/index.ts b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/ActionCustomizationToggle/index.ts new file mode 100644 index 00000000000..d85c6b3477a --- /dev/null +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/ActionCustomizationToggle/index.ts @@ -0,0 +1 @@ +export { ActionCustomizationToggle } from './ActionCustomizationToggle' diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/CustomizationToggle/index.ts b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/CustomizationToggle/index.ts deleted file mode 100644 index 9be99f70f71..00000000000 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/CustomizationToggle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { CustomizationToggle } from './CustomizationToggle' diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/data.ts b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/data.ts index 516d676c117..5befb33e8c0 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/data.ts +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/data.ts @@ -45,7 +45,8 @@ export const steps: Array> = [ blurhash: 'L9AS}j^-0dVC4Tq[=~PATeXSV?aL', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'typographyBlockId1', @@ -139,7 +140,8 @@ export const steps: Array> = [ blurhash: 'LQEf1v^*XkEe*IyD$RnOyXTJRjjG', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'typographyBlockId1', @@ -284,7 +286,8 @@ export const steps: Array> = [ blurhash: 'L;KRQa-Rs-kA}ot4bZj@SMR,WWj@', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'typographyBlockId1', @@ -412,7 +415,8 @@ export const steps: Array> = [ blurhash: 'L3CZt$_NyX4n=|?b00Ip8_IV00IA', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'typographyBlockId1', @@ -546,7 +550,8 @@ export const steps: Array> = [ blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'typographyBlockId1', diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/BlockCustomizationToggle/BlockCustomizationToggle.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/BlockCustomizationToggle/BlockCustomizationToggle.spec.tsx new file mode 100644 index 00000000000..d927ca56233 --- /dev/null +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/BlockCustomizationToggle/BlockCustomizationToggle.spec.tsx @@ -0,0 +1,940 @@ +import { MockedProvider, MockedResponse } from '@apollo/client/testing' +import { fireEvent, render, screen, waitFor } from '@testing-library/react' + +import { TreeBlock } from '@core/journeys/ui/block' +import { CommandProvider } from '@core/journeys/ui/CommandProvider' +import { EditorProvider } from '@core/journeys/ui/EditorProvider' + +import { + BlockFields_ButtonBlock as ButtonBlock, + BlockFields_ImageBlock as ImageBlock, + BlockFields_VideoBlock as VideoBlock +} from '../../../../../../../../../__generated__/BlockFields' +import { VideoBlockSource } from '../../../../../../../../../__generated__/globalTypes' +import { + ImageBlockUpdate, + ImageBlockUpdateVariables +} from '../../../../../../../../../__generated__/ImageBlockUpdate' +import { + VideoBlockUpdate, + VideoBlockUpdateVariables +} from '../../../../../../../../../__generated__/VideoBlockUpdate' +import { CommandRedoItem } from '../../../../../../Toolbar/Items/CommandRedoItem' +import { CommandUndoItem } from '../../../../../../Toolbar/Items/CommandUndoItem' +import { IMAGE_BLOCK_UPDATE } from '../../blocks/Image/Options/ImageOptions' +import { VIDEO_BLOCK_UPDATE } from '../../blocks/Video/Options/VideoOptions' + +import { BlockCustomizationToggle } from './BlockCustomizationToggle' + +const imageBlock: TreeBlock = { + __typename: 'ImageBlock', + id: 'imageBlockId', + parentBlockId: 'parentBlockId', + parentOrder: 0, + src: 'https://example.com/image.jpg', + alt: 'alt text', + width: 1920, + height: 1080, + blurhash: '', + scale: null, + focalTop: null, + focalLeft: null, + customizable: false, + children: [] +} + +const videoBlock: TreeBlock = { + __typename: 'VideoBlock', + id: 'videoBlockId', + parentBlockId: 'parentBlockId', + parentOrder: 0, + muted: null, + autoplay: null, + startAt: null, + endAt: null, + posterBlockId: null, + fullsize: null, + videoId: null, + videoVariantLanguageId: null, + source: VideoBlockSource.internal, + title: null, + description: null, + image: null, + duration: null, + objectFit: null, + showGeneratedSubtitles: null, + subtitleLanguage: null, + mediaVideo: null, + action: null, + eventLabel: null, + endEventLabel: null, + customizable: false, + children: [] +} + +describe('BlockCustomizationToggle', () => { + beforeEach(() => { + jest.clearAllMocks() + }) + + it('renders toggle for ImageBlock and reflects checked state when customizable is true', () => { + const blockWithCustomizableTrue = { + ...imageBlock, + customizable: true + } + render( + + + + + + + + ) + + expect(screen.getByText('Needs Customization')).toBeInTheDocument() + const toggle = screen.getByRole('checkbox', { name: 'Toggle customizable' }) + expect(toggle).toBeChecked() + expect(toggle).not.toBeDisabled() + }) + + it('renders toggle for ImageBlock and reflects unchecked state when customizable is false', () => { + render( + + + + + + + + ) + + const toggle = screen.getByRole('checkbox', { name: 'Toggle customizable' }) + expect(toggle).not.toBeChecked() + }) + + it('renders toggle for ImageBlock when customizable is null', () => { + const blockWithNullCustomizable = { + ...imageBlock, + customizable: null + } + render( + + + + + + + + ) + + const toggle = screen.getByRole('checkbox', { name: 'Toggle customizable' }) + expect(toggle).not.toBeChecked() + }) + + it('renders toggle for VideoBlock and reflects checked state when customizable is true', () => { + const blockWithCustomizableTrue = { + ...videoBlock, + customizable: true + } + render( + + + + + + + + ) + + expect(screen.getByText('Needs Customization')).toBeInTheDocument() + const toggle = screen.getByRole('checkbox', { name: 'Toggle customizable' }) + expect(toggle).toBeChecked() + expect(toggle).not.toBeDisabled() + }) + + it('renders toggle for VideoBlock and reflects unchecked state when customizable is false', () => { + render( + + + + + + + + ) + + const toggle = screen.getByRole('checkbox', { name: 'Toggle customizable' }) + expect(toggle).not.toBeChecked() + }) + + it('renders toggle when selectedBlock is not ImageBlock or VideoBlock - unchecked and disabled', () => { + const buttonBlock = { + id: 'button-1', + __typename: 'ButtonBlock', + label: 'Button', + action: null + } as unknown as TreeBlock + render( + + + + + + + + ) + + expect(screen.getByText('Needs Customization')).toBeInTheDocument() + const toggle = screen.getByRole('checkbox', { name: 'Toggle customizable' }) + expect(toggle).toBeInTheDocument() + expect(toggle).not.toBeChecked() + expect(toggle).toBeDisabled() + }) + + it('renders toggle when selectedBlock is null - unchecked and disabled', () => { + render( + + + + + + + + ) + + expect(screen.getByText('Needs Customization')).toBeInTheDocument() + const toggle = screen.getByRole('checkbox', { name: 'Toggle customizable' }) + expect(toggle).toBeInTheDocument() + expect(toggle).not.toBeChecked() + expect(toggle).toBeDisabled() + }) + + it('ImageBlock: toggling on calls imageBlockUpdate with customizable true', async () => { + const imageBlockUpdateResult = jest.fn(() => ({ + data: { + imageBlockUpdate: { ...imageBlock, customizable: true } + } + })) + const imageBlockUpdateMock: MockedResponse< + ImageBlockUpdate, + ImageBlockUpdateVariables + > = { + request: { + query: IMAGE_BLOCK_UPDATE, + variables: { + id: imageBlock.id, + input: { + customizable: true, + src: imageBlock.src, + width: 1920, + height: 1080, + blurhash: '' + } + } + }, + result: imageBlockUpdateResult + } + + render( + + + + + + + + ) + + const toggle = screen.getByRole('checkbox', { name: 'Toggle customizable' }) + fireEvent.click(toggle) + + await waitFor(() => { + expect(imageBlockUpdateResult).toHaveBeenCalled() + }) + }) + + it('ImageBlock: toggling off calls imageBlockUpdate with customizable false', async () => { + const blockWithCustomizable = { ...imageBlock, customizable: true } + const imageBlockUpdateResult = jest.fn(() => ({ + data: { + imageBlockUpdate: { ...blockWithCustomizable, customizable: false } + } + })) + const imageBlockUpdateMock: MockedResponse< + ImageBlockUpdate, + ImageBlockUpdateVariables + > = { + request: { + query: IMAGE_BLOCK_UPDATE, + variables: { + id: imageBlock.id, + input: { + customizable: false, + src: imageBlock.src, + width: 1920, + height: 1080, + blurhash: '' + } + } + }, + result: imageBlockUpdateResult + } + + render( + + + + + + + + ) + + const toggle = screen.getByRole('checkbox', { name: 'Toggle customizable' }) + fireEvent.click(toggle) + + await waitFor(() => { + expect(imageBlockUpdateResult).toHaveBeenCalled() + }) + }) + + it('VideoBlock: toggling on calls videoBlockUpdate with customizable true', async () => { + const videoBlockUpdateResult = jest.fn(() => ({ + data: { + videoBlockUpdate: { ...videoBlock, customizable: true } + } + })) + const videoBlockUpdateMock: MockedResponse< + VideoBlockUpdate, + VideoBlockUpdateVariables + > = { + request: { + query: VIDEO_BLOCK_UPDATE, + variables: { + id: videoBlock.id, + input: { customizable: true } + } + }, + result: videoBlockUpdateResult + } + + render( + + + + + + + + ) + + const toggle = screen.getByRole('checkbox', { name: 'Toggle customizable' }) + fireEvent.click(toggle) + + await waitFor(() => { + expect(videoBlockUpdateResult).toHaveBeenCalled() + }) + }) + + it('VideoBlock: toggling off calls videoBlockUpdate with customizable false', async () => { + const blockWithCustomizable = { ...videoBlock, customizable: true } + const videoBlockUpdateResult = jest.fn(() => ({ + data: { + videoBlockUpdate: { ...blockWithCustomizable, customizable: false } + } + })) + const videoBlockUpdateMock: MockedResponse< + VideoBlockUpdate, + VideoBlockUpdateVariables + > = { + request: { + query: VIDEO_BLOCK_UPDATE, + variables: { + id: videoBlock.id, + input: { customizable: false } + } + }, + result: videoBlockUpdateResult + } + + render( + + + + + + + + ) + + const toggle = screen.getByRole('checkbox', { name: 'Toggle customizable' }) + fireEvent.click(toggle) + + await waitFor(() => { + expect(videoBlockUpdateResult).toHaveBeenCalled() + }) + }) + + it('clicking toggle when block is undefined does not call mutation', async () => { + const imageBlockUpdateResult = jest.fn() + const imageBlockUpdateMock: MockedResponse< + ImageBlockUpdate, + ImageBlockUpdateVariables + > = { + request: { + query: IMAGE_BLOCK_UPDATE, + variables: { + id: 'imageBlockId', + input: { customizable: true } + } + }, + result: imageBlockUpdateResult + } + const buttonBlock = { + id: 'button-1', + __typename: 'ButtonBlock', + label: 'Button', + action: null + } as unknown as TreeBlock + + render( + + + + + + + + ) + + const toggle = screen.getByRole('checkbox', { name: 'Toggle customizable' }) + fireEvent.click(toggle) + + await waitFor(() => { + expect(imageBlockUpdateResult).not.toHaveBeenCalled() + }) + }) + + it('undo after toggling ImageBlock customizable calls imageBlockUpdate with customizable false', async () => { + const executeResult = jest.fn(() => ({ + data: { imageBlockUpdate: { ...imageBlock, customizable: true } } + })) + const undoResult = jest.fn(() => ({ + data: { imageBlockUpdate: { ...imageBlock, customizable: false } } + })) + const executeMock: MockedResponse< + ImageBlockUpdate, + ImageBlockUpdateVariables + > = { + request: { + query: IMAGE_BLOCK_UPDATE, + variables: { + id: imageBlock.id, + input: { + customizable: true, + src: imageBlock.src, + width: 1920, + height: 1080, + blurhash: '' + } + } + }, + result: executeResult + } + const undoMock: MockedResponse< + ImageBlockUpdate, + ImageBlockUpdateVariables + > = { + request: { + query: IMAGE_BLOCK_UPDATE, + variables: { + id: imageBlock.id, + input: { + customizable: false, + src: imageBlock.src, + width: 1920, + height: 1080, + blurhash: '' + } + } + }, + result: undoResult + } + + render( + + + + + + + + + ) + + fireEvent.click( + screen.getByRole('checkbox', { name: 'Toggle customizable' }) + ) + await waitFor(() => expect(executeResult).toHaveBeenCalled()) + + fireEvent.click(screen.getByRole('button', { name: 'Undo' })) + await waitFor(() => expect(undoResult).toHaveBeenCalled()) + }) + + it('redo after undo for ImageBlock calls imageBlockUpdate with customizable true', async () => { + const executeResult = jest.fn(() => ({ + data: { imageBlockUpdate: { ...imageBlock, customizable: true } } + })) + const undoResult = jest.fn(() => ({ + data: { imageBlockUpdate: { ...imageBlock, customizable: false } } + })) + const redoResult = jest.fn(() => ({ + data: { imageBlockUpdate: { ...imageBlock, customizable: true } } + })) + const executeMock: MockedResponse< + ImageBlockUpdate, + ImageBlockUpdateVariables + > = { + request: { + query: IMAGE_BLOCK_UPDATE, + variables: { + id: imageBlock.id, + input: { + customizable: true, + src: imageBlock.src, + width: 1920, + height: 1080, + blurhash: '' + } + } + }, + result: executeResult + } + const undoMock: MockedResponse< + ImageBlockUpdate, + ImageBlockUpdateVariables + > = { + request: { + query: IMAGE_BLOCK_UPDATE, + variables: { + id: imageBlock.id, + input: { + customizable: false, + src: imageBlock.src, + width: 1920, + height: 1080, + blurhash: '' + } + } + }, + result: undoResult + } + const redoMock: MockedResponse< + ImageBlockUpdate, + ImageBlockUpdateVariables + > = { + request: { + query: IMAGE_BLOCK_UPDATE, + variables: { + id: imageBlock.id, + input: { + customizable: true, + src: imageBlock.src, + width: 1920, + height: 1080, + blurhash: '' + } + } + }, + result: redoResult + } + + render( + + + + + + + + + + ) + + fireEvent.click( + screen.getByRole('checkbox', { name: 'Toggle customizable' }) + ) + await waitFor(() => expect(executeResult).toHaveBeenCalled()) + + fireEvent.click(screen.getByRole('button', { name: 'Undo' })) + await waitFor(() => expect(undoResult).toHaveBeenCalled()) + + fireEvent.click(screen.getByRole('button', { name: 'Redo' })) + await waitFor(() => expect(redoResult).toHaveBeenCalled()) + }) + + it('undo after toggling VideoBlock customizable calls videoBlockUpdate with customizable false', async () => { + const executeResult = jest.fn(() => ({ + data: { videoBlockUpdate: { ...videoBlock, customizable: true } } + })) + const undoResult = jest.fn(() => ({ + data: { videoBlockUpdate: { ...videoBlock, customizable: false } } + })) + const executeMock: MockedResponse< + VideoBlockUpdate, + VideoBlockUpdateVariables + > = { + request: { + query: VIDEO_BLOCK_UPDATE, + variables: { + id: videoBlock.id, + input: { customizable: true } + } + }, + result: executeResult + } + const undoMock: MockedResponse< + VideoBlockUpdate, + VideoBlockUpdateVariables + > = { + request: { + query: VIDEO_BLOCK_UPDATE, + variables: { + id: videoBlock.id, + input: { customizable: false } + } + }, + result: undoResult + } + + render( + + + + + + + + + ) + + fireEvent.click( + screen.getByRole('checkbox', { name: 'Toggle customizable' }) + ) + await waitFor(() => expect(executeResult).toHaveBeenCalled()) + + fireEvent.click(screen.getByRole('button', { name: 'Undo' })) + await waitFor(() => expect(undoResult).toHaveBeenCalled()) + }) + + it('redo after undo for VideoBlock calls videoBlockUpdate with customizable true', async () => { + const executeResult = jest.fn(() => ({ + data: { videoBlockUpdate: { ...videoBlock, customizable: true } } + })) + const undoResult = jest.fn(() => ({ + data: { videoBlockUpdate: { ...videoBlock, customizable: false } } + })) + const redoResult = jest.fn(() => ({ + data: { videoBlockUpdate: { ...videoBlock, customizable: true } } + })) + const executeMock: MockedResponse< + VideoBlockUpdate, + VideoBlockUpdateVariables + > = { + request: { + query: VIDEO_BLOCK_UPDATE, + variables: { + id: videoBlock.id, + input: { customizable: true } + } + }, + result: executeResult + } + const undoMock: MockedResponse< + VideoBlockUpdate, + VideoBlockUpdateVariables + > = { + request: { + query: VIDEO_BLOCK_UPDATE, + variables: { + id: videoBlock.id, + input: { customizable: false } + } + }, + result: undoResult + } + const redoMock: MockedResponse< + VideoBlockUpdate, + VideoBlockUpdateVariables + > = { + request: { + query: VIDEO_BLOCK_UPDATE, + variables: { + id: videoBlock.id, + input: { customizable: true } + } + }, + result: redoResult + } + + render( + + + + + + + + + + ) + + fireEvent.click( + screen.getByRole('checkbox', { name: 'Toggle customizable' }) + ) + await waitFor(() => expect(executeResult).toHaveBeenCalled()) + + fireEvent.click(screen.getByRole('button', { name: 'Undo' })) + await waitFor(() => expect(undoResult).toHaveBeenCalled()) + + fireEvent.click(screen.getByRole('button', { name: 'Redo' })) + await waitFor(() => expect(redoResult).toHaveBeenCalled()) + }) + + describe('BlockCustomizationToggleProps', () => { + it('uses ImageBlock from block prop when selectedBlock is not ImageBlock', async () => { + const buttonBlock = { + id: 'button-1', + __typename: 'ButtonBlock', + label: 'Button', + action: null + } as unknown as TreeBlock + const imageBlockUpdateResult = jest.fn(() => ({ + data: { imageBlockUpdate: { ...imageBlock, customizable: true } } + })) + const imageBlockUpdateMock: MockedResponse< + ImageBlockUpdate, + ImageBlockUpdateVariables + > = { + request: { + query: IMAGE_BLOCK_UPDATE, + variables: { + id: imageBlock.id, + input: { + customizable: true, + src: imageBlock.src, + width: imageBlock.width, + height: imageBlock.height, + blurhash: imageBlock.blurhash + } + } + }, + result: imageBlockUpdateResult + } + + render( + + + + + + + + ) + + expect(screen.getByText('Needs Customization')).toBeInTheDocument() + const toggle = screen.getByRole('checkbox', { + name: 'Toggle customizable' + }) + expect(toggle).not.toBeChecked() + expect(toggle).not.toBeDisabled() + + fireEvent.click(toggle) + await waitFor(() => { + expect(imageBlockUpdateResult).toHaveBeenCalled() + }) + }) + + it('uses VideoBlock from block prop when selectedBlock is not VideoBlock', async () => { + const buttonBlock = { + id: 'button-1', + __typename: 'ButtonBlock', + label: 'Button', + action: null + } as unknown as TreeBlock + const videoBlockUpdateResult = jest.fn(() => ({ + data: { videoBlockUpdate: { ...videoBlock, customizable: true } } + })) + const videoBlockUpdateMock: MockedResponse< + VideoBlockUpdate, + VideoBlockUpdateVariables + > = { + request: { + query: VIDEO_BLOCK_UPDATE, + variables: { + id: videoBlock.id, + input: { customizable: true } + } + }, + result: videoBlockUpdateResult + } + + render( + + + + + + + + ) + + expect(screen.getByText('Needs Customization')).toBeInTheDocument() + const toggle = screen.getByRole('checkbox', { + name: 'Toggle customizable' + }) + expect(toggle).not.toBeChecked() + expect(toggle).not.toBeDisabled() + + fireEvent.click(toggle) + await waitFor(() => { + expect(videoBlockUpdateResult).toHaveBeenCalled() + }) + }) + + it('block prop overrides selectedBlock when both are provided', async () => { + const imageBlockUpdateResult = jest.fn(() => ({ + data: { imageBlockUpdate: { ...imageBlock, customizable: true } } + })) + const imageBlockUpdateMock: MockedResponse< + ImageBlockUpdate, + ImageBlockUpdateVariables + > = { + request: { + query: IMAGE_BLOCK_UPDATE, + variables: { + id: imageBlock.id, + input: { + customizable: true, + src: imageBlock.src, + width: imageBlock.width, + height: imageBlock.height, + blurhash: imageBlock.blurhash + } + } + }, + result: imageBlockUpdateResult + } + const videoBlockUpdateResult = jest.fn() + const videoBlockUpdateMock: MockedResponse< + VideoBlockUpdate, + VideoBlockUpdateVariables + > = { + request: { + query: VIDEO_BLOCK_UPDATE, + variables: { + id: videoBlock.id, + input: { customizable: true } + } + }, + result: videoBlockUpdateResult + } + + render( + + + + + + + + ) + + const toggle = screen.getByRole('checkbox', { + name: 'Toggle customizable' + }) + fireEvent.click(toggle) + + await waitFor(() => { + expect(imageBlockUpdateResult).toHaveBeenCalled() + }) + expect(videoBlockUpdateResult).not.toHaveBeenCalled() + }) + + it('uses selectedBlock when block prop is undefined', async () => { + const imageBlockUpdateResult = jest.fn(() => ({ + data: { imageBlockUpdate: { ...imageBlock, customizable: true } } + })) + const imageBlockUpdateMock: MockedResponse< + ImageBlockUpdate, + ImageBlockUpdateVariables + > = { + request: { + query: IMAGE_BLOCK_UPDATE, + variables: { + id: imageBlock.id, + input: { + customizable: true, + src: imageBlock.src, + width: imageBlock.width, + height: imageBlock.height, + blurhash: imageBlock.blurhash + } + } + }, + result: imageBlockUpdateResult + } + + render( + + + + + + + + ) + + expect(screen.getByText('Needs Customization')).toBeInTheDocument() + const toggle = screen.getByRole('checkbox', { + name: 'Toggle customizable' + }) + expect(toggle).not.toBeChecked() + expect(toggle).not.toBeDisabled() + + fireEvent.click(toggle) + await waitFor(() => { + expect(imageBlockUpdateResult).toHaveBeenCalled() + }) + }) + }) +}) diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/BlockCustomizationToggle/BlockCustomizationToggle.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/BlockCustomizationToggle/BlockCustomizationToggle.tsx new file mode 100644 index 00000000000..347f1263e4b --- /dev/null +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/BlockCustomizationToggle/BlockCustomizationToggle.tsx @@ -0,0 +1,132 @@ +import { useMutation } from '@apollo/client' +import Stack from '@mui/material/Stack' +import Switch from '@mui/material/Switch' +import Typography from '@mui/material/Typography' +import { useTranslation } from 'next-i18next' +import { ReactElement } from 'react' + +import type { TreeBlock } from '@core/journeys/ui/block' +import { useCommand } from '@core/journeys/ui/CommandProvider' +import { useEditor } from '@core/journeys/ui/EditorProvider' + +import { + BlockFields_ImageBlock as ImageBlock, + BlockFields_VideoBlock as VideoBlock +} from '../../../../../../../../../__generated__/BlockFields' +import { + ImageBlockUpdateInput, + VideoBlockUpdateInput +} from '../../../../../../../../../__generated__/globalTypes' +import { + ImageBlockUpdate, + ImageBlockUpdateVariables +} from '../../../../../../../../../__generated__/ImageBlockUpdate' +import { + VideoBlockUpdate, + VideoBlockUpdateVariables +} from '../../../../../../../../../__generated__/VideoBlockUpdate' +import { IMAGE_BLOCK_UPDATE } from '../../blocks/Image/Options/ImageOptions' +import { VIDEO_BLOCK_UPDATE } from '../../blocks/Video/Options/VideoOptions' + +export interface BlockCustomizationToggleProps { + /** + * Optional block to operate on. When not provided, the component uses the editor's selectedBlock + * (for standalone Video/Image properties). When provided, uses this block (e.g. card + * cover block in BackgroundMediaVideo / BackgroundMediaImage). + */ + block?: TreeBlock +} + +/** + * BlockCustomizationToggle - "Needs Customization" toggle for block-level customizable content. + * + * This component is used in the editor properties panel to let users mark a block as + * customizable on template journeys. When enabled, the block's content can be customized + * per journey created from the template (e.g. ImageBlock, VideoBlock, and later LogoImageBlock). + * + * - Renders a Switch with "Needs Customization" label; state is driven by the block's + * `customizable` field (from props or selectedBlock). + * - Template gating is done at the call site: parents (Image/Video/Logo properties) should + * only render this component when `journey?.template` is true, same pattern as Action.tsx. + * - Toggle changes are persisted via block update mutation and are undo/redoable via useCommand. + * + * @returns {ReactElement} The toggle UI (Stack with Switch and label) + */ +export function BlockCustomizationToggle({ + block: blockProp +}: BlockCustomizationToggleProps): ReactElement { + const { t } = useTranslation('apps-journeys-admin') + const { + state: { selectedBlock } + } = useEditor() + const { add } = useCommand() + const [imageBlockUpdate] = useMutation< + ImageBlockUpdate, + ImageBlockUpdateVariables + >(IMAGE_BLOCK_UPDATE) + const [videoBlockUpdate] = useMutation< + VideoBlockUpdate, + VideoBlockUpdateVariables + >(VIDEO_BLOCK_UPDATE) + + const targetBlock: TreeBlock | undefined = + blockProp ?? + (selectedBlock?.__typename === 'ImageBlock' || + selectedBlock?.__typename === 'VideoBlock' + ? (selectedBlock as TreeBlock) + : undefined) + + const customizable = targetBlock?.customizable ?? false + + function handleChange(event: React.ChangeEvent): void { + if (targetBlock == null) return + const newCustomizable = event.target.checked + const undoCustomizable = customizable + + add({ + parameters: { + execute: { customizable: newCustomizable }, + undo: { customizable: undoCustomizable } + }, + execute({ customizable: value }) { + if (targetBlock.__typename === 'ImageBlock') { + const input: ImageBlockUpdateInput = { + customizable: value, + src: targetBlock.src, + width: targetBlock.width, + height: targetBlock.height, + blurhash: targetBlock.blurhash + } + void imageBlockUpdate({ + variables: { id: targetBlock.id, input }, + optimisticResponse: { + imageBlockUpdate: { ...targetBlock, customizable: value } + } + }) + return + } + if (targetBlock.__typename === 'VideoBlock') { + const input: VideoBlockUpdateInput = { customizable: value } + void videoBlockUpdate({ + variables: { id: targetBlock.id, input }, + optimisticResponse: { + videoBlockUpdate: { ...targetBlock, customizable: value } + } + }) + } + } + }) + } + + return ( + + + {t('Needs Customization')} + + ) +} diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/BlockCustomizationToggle/index.ts b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/BlockCustomizationToggle/index.ts new file mode 100644 index 00000000000..48e9a761e26 --- /dev/null +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/BlockCustomizationToggle/index.ts @@ -0,0 +1 @@ +export { BlockCustomizationToggle } from './BlockCustomizationToggle' diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/EventLabel/EventLabel.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/EventLabel/EventLabel.spec.tsx index eadf62657d0..fd066fd985c 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/EventLabel/EventLabel.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/EventLabel/EventLabel.spec.tsx @@ -965,7 +965,8 @@ describe('EventLabel', () => { it('should undo start event label', async () => { const videoBlock = createVideoBlockMock({ eventLabel: BlockEventLabel.specialVideoStart, - endEventLabel: null + endEventLabel: null, + customizable: null }) const executeMock = createVideoStartEventLabelUpdateMock( @@ -1025,7 +1026,8 @@ describe('EventLabel', () => { it('should redo start event label', async () => { const videoBlock = createVideoBlockMock({ eventLabel: BlockEventLabel.specialVideoStart, - endEventLabel: null + endEventLabel: null, + customizable: null }) const executeMock = createVideoStartEventLabelUpdateMock( @@ -1098,7 +1100,8 @@ describe('EventLabel', () => { it('should update end event label', async () => { const videoBlock = createVideoBlockMock({ eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null }) const executeMock = createVideoEndEventLabelUpdateMock( diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/EventLabel/utils/getCurrentEventLabel/getCurrentEventLabel.spec.ts b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/EventLabel/utils/getCurrentEventLabel/getCurrentEventLabel.spec.ts index ec5d30c69b7..d0e44282d3b 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/EventLabel/utils/getCurrentEventLabel/getCurrentEventLabel.spec.ts +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/Properties/controls/EventLabel/utils/getCurrentEventLabel/getCurrentEventLabel.spec.ts @@ -72,6 +72,7 @@ describe('getCurrentEventLabel', () => { subtitleLanguage: null, mediaVideo: null, action: null, + customizable: null, children: [] } diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardCta/CardCta.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardCta/CardCta.spec.tsx index 248f38ed7bd..541cb948a1e 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardCta/CardCta.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardCta/CardCta.spec.tsx @@ -97,7 +97,8 @@ describe('CardCta', () => { isCover: true, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, subtitleInput: { id: 'subtitleId', @@ -219,7 +220,8 @@ describe('CardCta', () => { __typename: 'ImageBlock', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, subtitle: { id: 'subtitleId', diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardCta/CardCta.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardCta/CardCta.tsx index 41607d60ba0..491c8dc184b 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardCta/CardCta.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardCta/CardCta.tsx @@ -307,7 +307,8 @@ export function CardCta(): ReactElement { __typename: 'ImageBlock', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } satisfies ImageBlock const subtitle = { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardForm/CardForm.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardForm/CardForm.spec.tsx index 083b6d4326a..b215a8d7c9a 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardForm/CardForm.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardForm/CardForm.spec.tsx @@ -96,7 +96,8 @@ describe('CardForm', () => { isCover: true, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, subtitleInput: { id: 'subtitleId', @@ -189,7 +190,8 @@ describe('CardForm', () => { __typename: 'ImageBlock', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, subtitle: { id: 'subtitleId', diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardForm/CardForm.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardForm/CardForm.tsx index 81303039623..e39dea2ce2d 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardForm/CardForm.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardForm/CardForm.tsx @@ -259,7 +259,8 @@ export function CardForm(): ReactElement { __typename: 'ImageBlock', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } satisfies ImageBlock const subtitle = { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardIntro/CardIntro.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardIntro/CardIntro.spec.tsx index baad40d53a3..9d652ba1b0b 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardIntro/CardIntro.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardIntro/CardIntro.spec.tsx @@ -273,6 +273,7 @@ describe('CardIntro', () => { showGeneratedSubtitles: null, eventLabel: null, endEventLabel: null, + customizable: null, mediaVideo: { id: '1_jf-0-0', title: [ diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardIntro/CardIntro.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardIntro/CardIntro.tsx index 7b74e8d657b..b8a64c46e63 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardIntro/CardIntro.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardIntro/CardIntro.tsx @@ -331,6 +331,7 @@ export function CardIntro(): ReactElement { variantLanguages: [] }, action: null, + customizable: null, __typename: 'VideoBlock' } satisfies VideoBlock diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardPoll/CardPoll.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardPoll/CardPoll.spec.tsx index 4ab7281bf4f..97cb74e7b29 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardPoll/CardPoll.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardPoll/CardPoll.spec.tsx @@ -91,7 +91,8 @@ describe('CardPoll', () => { isCover: true, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, subtitleInput: { id: 'subtitleId', @@ -183,7 +184,8 @@ describe('CardPoll', () => { __typename: 'ImageBlock', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, subtitle: { id: 'subtitleId', diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardPoll/CardPoll.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardPoll/CardPoll.tsx index d912da00115..4f3c5bb0da4 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardPoll/CardPoll.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardPoll/CardPoll.tsx @@ -225,7 +225,8 @@ export function CardPoll(): ReactElement { width: 5184, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } satisfies ImageBlock const subtitle = { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardQuote/CardQuote.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardQuote/CardQuote.spec.tsx index b96700e91c4..1fa794a98d4 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardQuote/CardQuote.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardQuote/CardQuote.spec.tsx @@ -90,7 +90,8 @@ const cardQuoteCreateMock: MockedResponse< isCover: true, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, subtitleInput: { id: 'subtitleId', @@ -149,7 +150,8 @@ const cardQuoteCreateMock: MockedResponse< __typename: 'ImageBlock', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, subtitle: { id: 'subtitleId', diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardQuote/CardQuote.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardQuote/CardQuote.tsx index b3f024c1376..f00e63f4da6 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardQuote/CardQuote.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardQuote/CardQuote.tsx @@ -170,7 +170,8 @@ export function CardQuote(): ReactElement { __typename: 'ImageBlock', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } satisfies ImageBlock const subtitle = { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardVideo/CardVideo.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardVideo/CardVideo.spec.tsx index c5ab036ece1..dccca74d9df 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardVideo/CardVideo.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardVideo/CardVideo.spec.tsx @@ -107,7 +107,8 @@ describe('CardVideo', () => { mediaVideo: null, action: null, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null } ] } @@ -161,7 +162,8 @@ describe('CardVideo', () => { mediaVideo: null, action: null, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null } } } @@ -204,7 +206,8 @@ describe('CardVideo', () => { mediaVideo: null, action: null, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null } ] } diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardVideo/CardVideo.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardVideo/CardVideo.tsx index 6e31f2e9473..9b628b1dd46 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardVideo/CardVideo.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/CardTemplates/Templates/CardVideo/CardVideo.tsx @@ -126,6 +126,7 @@ export function CardVideo(): ReactElement { action: null, eventLabel: null, endEventLabel: null, + customizable: null, __typename: 'VideoBlock' } satisfies VideoBlock diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/AIGallery/AIGallery.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/AIGallery/AIGallery.spec.tsx index 3c3ae53445a..2aba4028816 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/AIGallery/AIGallery.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/AIGallery/AIGallery.spec.tsx @@ -64,7 +64,8 @@ describe('AIGallery', () => { src: 'https://imagedelivery.net/cloudflare-key/imageId/public', scale: 100, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }) }) }) diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/AIGallery/AIGallery.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/AIGallery/AIGallery.tsx index 0d38a712fa2..41812e74044 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/AIGallery/AIGallery.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/AIGallery/AIGallery.tsx @@ -57,7 +57,8 @@ export function AIGallery({ alt: `Prompt: ${prompt}`, scale: 100, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }) } else { enqueueSnackbar(t('Something went wrong, please try again!'), { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/AIGallery/AIPrompt/AIPrompt.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/AIGallery/AIPrompt/AIPrompt.spec.tsx index 802fc76d432..182f7dfc9ee 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/AIGallery/AIPrompt/AIPrompt.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/AIGallery/AIPrompt/AIPrompt.spec.tsx @@ -18,7 +18,8 @@ describe('AIPrompt', () => { parentOrder: 0, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } it('should have prefilled textfield on existing prompt', async () => { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/CustomImage/CustomImage.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/CustomImage/CustomImage.spec.tsx index 514ebd21065..6d0abfc34fd 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/CustomImage/CustomImage.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/CustomImage/CustomImage.spec.tsx @@ -18,7 +18,8 @@ describe('CustomImage', () => { parentOrder: 0, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } it('should render custom url image upload', () => { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/CustomImage/CustomImage.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/CustomImage/CustomImage.stories.tsx index 65e89d6ba72..2fbc163f047 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/CustomImage/CustomImage.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/CustomImage/CustomImage.stories.tsx @@ -31,7 +31,8 @@ const Template: StoryObj = { parentOrder: 0, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }} onChange={noop} /> diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/CustomImage/ImageUpload/ImageUpload.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/CustomImage/ImageUpload/ImageUpload.spec.tsx index 891010fc380..fc92da847fb 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/CustomImage/ImageUpload/ImageUpload.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/CustomImage/ImageUpload/ImageUpload.spec.tsx @@ -45,7 +45,8 @@ describe('ImageUpload', () => { parentOrder: 0, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const cfResponse = { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/ImageBlockEditor.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/ImageBlockEditor.spec.tsx index 4b457b355d9..972d2535166 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/ImageBlockEditor.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/ImageBlockEditor.spec.tsx @@ -32,7 +32,8 @@ describe('ImageBlockEditor', () => { parentOrder: 0, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } it('should render the ImageBlockEditor', () => { @@ -139,7 +140,8 @@ describe('ImageBlockEditor', () => { width: 1080, scale: 100, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }) ) }) diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/UnsplashGallery/UnsplashGallery.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/UnsplashGallery/UnsplashGallery.spec.tsx index 7ca29ca3a6e..0dbe5cd9b35 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/UnsplashGallery/UnsplashGallery.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/UnsplashGallery/UnsplashGallery.spec.tsx @@ -131,7 +131,8 @@ describe('UnsplashGallery', () => { width: 1080, scale: 100, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }) }) diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/UnsplashGallery/UnsplashList/UnsplashList.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/UnsplashGallery/UnsplashList/UnsplashList.spec.tsx index 840075ca6fa..61a4313a133 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/UnsplashGallery/UnsplashList/UnsplashList.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/UnsplashGallery/UnsplashList/UnsplashList.spec.tsx @@ -71,7 +71,8 @@ describe('UnsplashList', () => { width: 1080, scale: 100, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }) }) diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/UnsplashGallery/UnsplashList/UnsplashList.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/UnsplashGallery/UnsplashList/UnsplashList.tsx index 8f8cf89ef0e..cfff9fb7e39 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/UnsplashGallery/UnsplashList/UnsplashList.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockEditor/UnsplashGallery/UnsplashList/UnsplashList.tsx @@ -52,7 +52,8 @@ export function UnsplashList({ alt: item.alt_description, scale: 100, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }) } diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockHeader/ImageBlockHeader.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockHeader/ImageBlockHeader.spec.tsx index 2d6d912eb5c..1b8b7a88972 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockHeader/ImageBlockHeader.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockHeader/ImageBlockHeader.spec.tsx @@ -17,7 +17,8 @@ describe('ImageBlockHeader', () => { blurhash: '', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } it('should render selected image block', () => { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockThumbnail/ImageBlockThumbnail.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockThumbnail/ImageBlockThumbnail.spec.tsx index 5b5ae6e9ff1..5d5344eb30d 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockThumbnail/ImageBlockThumbnail.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockThumbnail/ImageBlockThumbnail.spec.tsx @@ -16,7 +16,8 @@ const image: ImageBlock = { blurhash: '', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } describe('ImageBlockThumbnail', () => { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockThumbnail/ImageBlockThumbnail.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockThumbnail/ImageBlockThumbnail.stories.tsx index 9b04a9b2bcd..df633464b6d 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockThumbnail/ImageBlockThumbnail.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageBlockThumbnail/ImageBlockThumbnail.stories.tsx @@ -49,7 +49,8 @@ const image: ImageBlock = { alt: 'poster', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const Template: StoryObj = { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageEdit/ImageEdit.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageEdit/ImageEdit.spec.tsx index 1f1bb1b6a97..89934545a54 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageEdit/ImageEdit.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageEdit/ImageEdit.spec.tsx @@ -48,7 +48,8 @@ describe('ImageEdit', () => { blurhash: '', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } it('should disaply placeholder icon when no image set', () => { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageLibrary/ImageLibrary.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageLibrary/ImageLibrary.spec.tsx index 33a81fcb5f2..81807ec3289 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageLibrary/ImageLibrary.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageLibrary/ImageLibrary.spec.tsx @@ -25,7 +25,8 @@ describe('ImageLibrary', () => { parentOrder: 0, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } describe('smUp', () => { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageSource/ImageSource.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageSource/ImageSource.spec.tsx index d0e01cd0a62..3f967028218 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageSource/ImageSource.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageSource/ImageSource.spec.tsx @@ -4,6 +4,13 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react' import { NextRouter, useRouter } from 'next/router' import { SnackbarProvider } from 'notistack' +import type { TreeBlock } from '@core/journeys/ui/block' +import { CommandProvider } from '@core/journeys/ui/CommandProvider' +import { EditorProvider } from '@core/journeys/ui/EditorProvider' +import { JourneyProvider } from '@core/journeys/ui/JourneyProvider' + +import { BlockFields_ImageBlock as ImageBlock } from '../../../../../../../__generated__/BlockFields' +import { JourneyFields } from '../../../../../../../__generated__/JourneyFields' import { createCloudflareUploadByUrlMock } from '../ImageBlockEditor/CustomImage/CustomUrl/data' import { ImageSource } from './ImageSource' @@ -163,4 +170,89 @@ describe('ImageSource', () => { }) await waitFor(() => expect(onChange).toHaveBeenCalled()) }) + + describe('BlockCustomizationToggle', () => { + const imageBlock: TreeBlock = { + id: 'image1.id', + __typename: 'ImageBlock', + parentBlockId: 'card.id', + parentOrder: 0, + src: 'https://example.com/image.jpg', + alt: 'image alt', + width: 1920, + height: 1080, + blurhash: '', + children: [], + scale: null, + focalLeft: 50, + focalTop: 50, + customizable: null + } + + it('should not render BlockCustomizationToggle when journey is not a template', () => { + render( + + + + + + ) + + expect(screen.queryByText('Needs Customization')).not.toBeInTheDocument() + }) + + it('should not render BlockCustomizationToggle when selectedBlock is null (even when journey is template)', () => { + render( + + + + + + + + ) + + expect(screen.queryByText('Needs Customization')).not.toBeInTheDocument() + }) + + it('should render BlockCustomizationToggle when journey is a template and selectedBlock is non-null', () => { + render( + + + + + + + + + + + + ) + + expect(screen.getByText('Needs Customization')).toBeInTheDocument() + }) + }) }) diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageSource/ImageSource.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageSource/ImageSource.stories.tsx index 5c59c9f39c1..5a3ff259d69 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageSource/ImageSource.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageSource/ImageSource.stories.tsx @@ -50,7 +50,8 @@ const image: ImageBlock = { alt: 'poster', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const onChange = async (): Promise => await Promise.resolve() diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageSource/ImageSource.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageSource/ImageSource.tsx index c92e40762cf..3f63243d582 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageSource/ImageSource.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/ImageSource/ImageSource.tsx @@ -5,9 +5,12 @@ import { useRouter } from 'next/router' import { ReactElement, useState } from 'react' import { setBeaconPageViewed } from '@core/journeys/ui/beaconHooks' +import type { TreeBlock } from '@core/journeys/ui/block' +import { useJourney } from '@core/journeys/ui/JourneyProvider' import { BlockFields_ImageBlock as ImageBlock } from '../../../../../../../__generated__/BlockFields' import { ImageBlockUpdateInput } from '../../../../../../../__generated__/globalTypes' +import { BlockCustomizationToggle } from '../../CanvasDetails/Properties/controls/BlockCustomizationToggle' import { ImageBlockHeader } from '../ImageBlockHeader' const ImageLibrary = dynamic( @@ -33,6 +36,7 @@ export function ImageSource({ loading, error }: ImageSourceProps): ReactElement { + const { journey } = useJourney() const router = useRouter() const [open, setOpen] = useState() @@ -76,6 +80,11 @@ export function ImageSource({ + {journey?.template && selectedBlock != null && ( + } + /> + )} {open != null && ( = { showGeneratedSubtitles: false, eventLabel: null, endEventLabel: null, + customizable: null, mediaVideo: null } diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Settings/Poster/Library/VideoBlockEditorSettingsPosterLibrary.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Settings/Poster/Library/VideoBlockEditorSettingsPosterLibrary.spec.tsx index 2301c5b7324..6fe03822662 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Settings/Poster/Library/VideoBlockEditorSettingsPosterLibrary.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Settings/Poster/Library/VideoBlockEditorSettingsPosterLibrary.spec.tsx @@ -163,6 +163,7 @@ const video: TreeBlock = { posterBlockId: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } @@ -178,7 +179,8 @@ const image: ImageBlock = { blurhash: '', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const onClose = jest.fn() @@ -219,7 +221,8 @@ describe('VideoBlockEditorSettingsPosterLibrary', () => { blurhash: '', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } } }, @@ -237,7 +240,8 @@ describe('VideoBlockEditorSettingsPosterLibrary', () => { blurhash: image.blurhash, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, videoBlockUpdate: { id: video.id, @@ -395,7 +399,8 @@ describe('VideoBlockEditorSettingsPosterLibrary', () => { blurhash: image.blurhash, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } } const posterImageBlockUpdateMock: MockedResponse< diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Settings/Poster/Library/VideoBlockEditorSettingsPosterLibrary.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Settings/Poster/Library/VideoBlockEditorSettingsPosterLibrary.tsx index 46ca98bcd1e..b58731a271f 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Settings/Poster/Library/VideoBlockEditorSettingsPosterLibrary.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Settings/Poster/Library/VideoBlockEditorSettingsPosterLibrary.tsx @@ -151,7 +151,8 @@ export function VideoBlockEditorSettingsPosterLibrary({ parentOrder: 0, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } add({ diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Settings/Poster/VideoBlockEditorSettingsPoster.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Settings/Poster/VideoBlockEditorSettingsPoster.spec.tsx index cdfa03a95a1..68cc78bd4b4 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Settings/Poster/VideoBlockEditorSettingsPoster.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Settings/Poster/VideoBlockEditorSettingsPoster.spec.tsx @@ -63,6 +63,7 @@ const video: VideoBlock = { }, variantLanguages: [] }, + customizable: null, posterBlockId: null } @@ -78,7 +79,8 @@ const image: ImageBlock = { blurhash: '', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } describe('VideoBlockEditorSettingsPoster', () => { diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Settings/VideoBlockEditorSettings.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Settings/VideoBlockEditorSettings.spec.tsx index 1ba7c00001e..bb1da9fe4fe 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Settings/VideoBlockEditorSettings.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Settings/VideoBlockEditorSettings.spec.tsx @@ -135,6 +135,7 @@ const video: TreeBlock = { variantLanguages: [] }, posterBlockId: null, + customizable: null, children: [], objectFit: null, subtitleLanguage: null, diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Source/Source.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Source/Source.spec.tsx index 21d0426daaf..e46f8dc82a3 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Source/Source.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Source/Source.spec.tsx @@ -230,6 +230,7 @@ describe('Source', () => { eventLabel: null, endEventLabel: null, posterBlockId: 'poster1.id', + customizable: null, children: [] }} onChange={onChange} @@ -294,6 +295,7 @@ describe('Source', () => { eventLabel: null, endEventLabel: null, posterBlockId: 'poster1.id', + customizable: null, children: [] }} onChange={onChange} @@ -373,6 +375,7 @@ describe('Source', () => { eventLabel: null, endEventLabel: null, posterBlockId: null, + customizable: null, children: [] }} onChange={onChange} @@ -426,6 +429,7 @@ describe('Source', () => { eventLabel: null, endEventLabel: null, posterBlockId: null, + customizable: null, children: [] }} onChange={onChange} @@ -501,6 +505,7 @@ describe('Source', () => { eventLabel: null, endEventLabel: null, posterBlockId: null, + customizable: null, children: [] }} onChange={onChange} diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/VideoBlockEditor.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/VideoBlockEditor.spec.tsx index 9ef9d8ff71f..52cf4e64958 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/VideoBlockEditor.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/VideoBlockEditor.spec.tsx @@ -1,12 +1,16 @@ import { MockedProvider } from '@apollo/client/testing' -import { render, waitFor } from '@testing-library/react' +import { render, screen, waitFor } from '@testing-library/react' import { SnackbarProvider } from 'notistack' import type { TreeBlock } from '@core/journeys/ui/block' +import { CommandProvider } from '@core/journeys/ui/CommandProvider' +import { EditorProvider } from '@core/journeys/ui/EditorProvider' +import { JourneyProvider } from '@core/journeys/ui/JourneyProvider' import { BlockFields_VideoBlock as VideoBlock } from '../../../../../../../__generated__/BlockFields' import { GetVideoVariantLanguages_video } from '../../../../../../../__generated__/GetVideoVariantLanguages' import { VideoBlockSource } from '../../../../../../../__generated__/globalTypes' +import { JourneyFields } from '../../../../../../../__generated__/JourneyFields' import { ThemeProvider } from '../../../../../ThemeProvider' import { GET_VIDEO_VARIANT_LANGUAGES } from './Source/SourceFromLocal/SourceFromLocal' @@ -60,6 +64,7 @@ const videoInternal: TreeBlock = { variantLanguages: [] }, posterBlockId: null, + customizable: null, children: [] } @@ -124,6 +129,7 @@ const videoYouTube: TreeBlock = { eventLabel: null, endEventLabel: null, posterBlockId: 'poster1.id', + customizable: null, children: [] } @@ -456,6 +462,7 @@ describe('VideoBlockEditor', () => { scale: null, focalTop: null, focalLeft: null, + customizable: null, children: [] } ] @@ -478,4 +485,72 @@ describe('VideoBlockEditor', () => { expect(getByTestId('VideoBlockEditor')).toBeInTheDocument() }) }) + + describe('BlockCustomizationToggle', () => { + it('should not render BlockCustomizationToggle when journey is not a template', () => { + render( + + + + + + + + ) + + expect(screen.queryByText('Needs Customization')).not.toBeInTheDocument() + }) + + it('should not render BlockCustomizationToggle when selectedBlock is null (even when journey is template)', () => { + render( + + + + + + + + + + ) + + expect(screen.queryByText('Needs Customization')).not.toBeInTheDocument() + }) + + it('should render BlockCustomizationToggle when journey is a template and selectedBlock is non-null', () => { + render( + + + + + + + + + + + + + + ) + + expect(screen.getByText('Needs Customization')).toBeInTheDocument() + }) + }) }) diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/VideoBlockEditor.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/VideoBlockEditor.stories.tsx index 25e0429b0a7..a7484929641 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/VideoBlockEditor.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/VideoBlockEditor.stories.tsx @@ -97,6 +97,7 @@ const videoInternal: TreeBlock = { posterBlockId: 'poster1.id', eventLabel: null, endEventLabel: null, + customizable: null, children: [] } @@ -113,7 +114,8 @@ const posterInternal: TreeBlock = { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const videoYouTube: TreeBlock = { @@ -145,6 +147,7 @@ const videoYouTube: TreeBlock = { eventLabel: null, endEventLabel: null, posterBlockId: 'poster1.id', + customizable: null, children: [] } @@ -161,7 +164,8 @@ const posterYouTube: TreeBlock = { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const onChange = async (): Promise => await Promise.resolve() diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/VideoBlockEditor.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/VideoBlockEditor.tsx index e73829a4d7e..7b3648e5717 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/VideoBlockEditor.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/VideoBlockEditor.tsx @@ -3,12 +3,14 @@ import dynamic from 'next/dynamic' import { ReactElement } from 'react' import type { TreeBlock } from '@core/journeys/ui/block' +import { useJourney } from '@core/journeys/ui/JourneyProvider' import { BlockFields_ImageBlock as ImageBlock, BlockFields_VideoBlock as VideoBlock } from '../../../../../../../__generated__/BlockFields' import { VideoBlockUpdateInput } from '../../../../../../../__generated__/globalTypes' +import { BlockCustomizationToggle } from '../../CanvasDetails/Properties/controls/BlockCustomizationToggle' import { Source } from './Source' @@ -32,6 +34,7 @@ export function VideoBlockEditor({ selectedBlock, onChange }: VideoBlockEditorProps): ReactElement { + const { journey } = useJourney() const posterBlock = selectedBlock?.children.find( (child) => child.id === (selectedBlock as VideoBlock).posterBlockId ) as ImageBlock | null @@ -47,6 +50,9 @@ export function VideoBlockEditor({ onChange={onChange} /> + {journey?.template && selectedBlock != null && ( + + )} {videoBlock?.videoId != null && ( { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const videoBlock: TreeBlock = { id: 'videoBlockId', @@ -64,6 +65,7 @@ describe('VideoDetails', () => { objectFit: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [imageBlock] } diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoDetails/VideoDetails.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoDetails/VideoDetails.stories.tsx index 8eced31eb04..1f0d25a9390 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoDetails/VideoDetails.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoDetails/VideoDetails.stories.tsx @@ -174,7 +174,8 @@ const imageBlock: TreeBlock = { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const videoBlock: TreeBlock = { id: 'videoBlockId', @@ -201,6 +202,7 @@ const videoBlock: TreeBlock = { objectFit: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [imageBlock] } diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoFromMux/AddByFile/AddByFile.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoFromMux/AddByFile/AddByFile.spec.tsx index e1df08244cc..e0eae841e21 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoFromMux/AddByFile/AddByFile.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoFromMux/AddByFile/AddByFile.spec.tsx @@ -138,6 +138,7 @@ const TestWrapper = ({ objectFit: null, subtitleLanguage: null, showGeneratedSubtitles: false, + customizable: null, mediaVideo: null, eventLabel: null, endEventLabel: null, diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoFromMux/MuxDetails/MuxDetails.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoFromMux/MuxDetails/MuxDetails.spec.tsx index 49c5f4e7680..4f01f6009ad 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoFromMux/MuxDetails/MuxDetails.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoFromMux/MuxDetails/MuxDetails.spec.tsx @@ -80,6 +80,7 @@ const mockVideoBlock = { action: null, eventLabel: null, endEventLabel: null, + customizable: null, mediaVideo: { __typename: 'MuxVideo' as const, id: 'videoId', diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoFromMux/VideoFromMux.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoFromMux/VideoFromMux.spec.tsx index 28aa9ac7db6..7ffd70af021 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoFromMux/VideoFromMux.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoFromMux/VideoFromMux.spec.tsx @@ -72,6 +72,7 @@ const selectedVideoBlock: TreeBlock = { mediaVideo: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoFromYouTube/YouTubeDetails/YouTubeDetails.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoFromYouTube/YouTubeDetails/YouTubeDetails.spec.tsx index 40abb2bb1a4..94ad4012d14 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoFromYouTube/YouTubeDetails/YouTubeDetails.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoFromYouTube/YouTubeDetails/YouTubeDetails.spec.tsx @@ -236,6 +236,7 @@ describe('YouTubeDetails', () => { action: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } @@ -387,6 +388,7 @@ describe('YouTubeDetails', () => { action: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } @@ -597,6 +599,7 @@ describe('YouTubeDetails', () => { action: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } @@ -703,6 +706,7 @@ describe('YouTubeDetails', () => { action: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } @@ -764,6 +768,7 @@ describe('YouTubeDetails', () => { action: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } @@ -841,6 +846,7 @@ describe('YouTubeDetails', () => { action: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoLibrary.spec.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoLibrary.spec.tsx index 0b44a1affaf..ea5f9a6e0dc 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoLibrary.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoLibrary.spec.tsx @@ -208,6 +208,7 @@ describe('VideoLibrary', () => { posterBlockId: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] }} /> @@ -267,6 +268,7 @@ describe('VideoLibrary', () => { posterBlockId: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] }} /> @@ -457,6 +459,7 @@ describe('VideoLibrary', () => { posterBlockId: 'poster1.id', eventLabel: null, endEventLabel: null, + customizable: null, children: [] }} onSelect={onSelect} @@ -580,6 +583,7 @@ describe('VideoLibrary', () => { posterBlockId: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } @@ -705,6 +709,7 @@ describe('VideoLibrary', () => { posterBlockId: 'poster1.id', eventLabel: null, endEventLabel: null, + customizable: null, children: [] }} onSelect={onSelect} @@ -818,6 +823,7 @@ describe('VideoLibrary', () => { posterBlockId: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [], source: VideoBlockSource.internal }} @@ -887,6 +893,7 @@ describe('VideoLibrary', () => { posterBlockId: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [], source: VideoBlockSource.mux }} diff --git a/apps/journeys-admin/src/components/Editor/Slider/Settings/SocialDetails/SocialDetails.stories.tsx b/apps/journeys-admin/src/components/Editor/Slider/Settings/SocialDetails/SocialDetails.stories.tsx index ccae89d9ac5..8a5820ee4b0 100644 --- a/apps/journeys-admin/src/components/Editor/Slider/Settings/SocialDetails/SocialDetails.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Slider/Settings/SocialDetails/SocialDetails.stories.tsx @@ -96,7 +96,8 @@ const image: ImageBlock = { blurhash: '', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const Template: StoryObj = { diff --git a/apps/journeys-admin/src/components/Editor/Toolbar/Toolbar.stories.tsx b/apps/journeys-admin/src/components/Editor/Toolbar/Toolbar.stories.tsx index ff7f5d3e562..200f63ea026 100644 --- a/apps/journeys-admin/src/components/Editor/Toolbar/Toolbar.stories.tsx +++ b/apps/journeys-admin/src/components/Editor/Toolbar/Toolbar.stories.tsx @@ -31,7 +31,8 @@ const image: ImageBlock = { blurhash: '', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const Template: StoryObj< diff --git a/apps/journeys-admin/src/components/Editor/utils/blockCreateUpdate/blockCreateUpdate.spec.tsx b/apps/journeys-admin/src/components/Editor/utils/blockCreateUpdate/blockCreateUpdate.spec.tsx index e287c7f2ebe..f5ced43cff0 100644 --- a/apps/journeys-admin/src/components/Editor/utils/blockCreateUpdate/blockCreateUpdate.spec.tsx +++ b/apps/journeys-admin/src/components/Editor/utils/blockCreateUpdate/blockCreateUpdate.spec.tsx @@ -18,7 +18,8 @@ const image: TreeBlock = { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const response = { ...image, parentOrder: 0 } diff --git a/apps/journeys-admin/src/components/ImageThumbnail/ImageThumbnail.spec.tsx b/apps/journeys-admin/src/components/ImageThumbnail/ImageThumbnail.spec.tsx index e89c581e07e..b4c9c6257c5 100644 --- a/apps/journeys-admin/src/components/ImageThumbnail/ImageThumbnail.spec.tsx +++ b/apps/journeys-admin/src/components/ImageThumbnail/ImageThumbnail.spec.tsx @@ -16,7 +16,8 @@ const image: ImageBlock = { blurhash: '', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } describe('ImageThumbnail', () => { diff --git a/apps/journeys-admin/src/components/ImageThumbnail/ImageThumbnail.stories.tsx b/apps/journeys-admin/src/components/ImageThumbnail/ImageThumbnail.stories.tsx index 9494ed4d7ba..0843cae5f5d 100644 --- a/apps/journeys-admin/src/components/ImageThumbnail/ImageThumbnail.stories.tsx +++ b/apps/journeys-admin/src/components/ImageThumbnail/ImageThumbnail.stories.tsx @@ -50,7 +50,8 @@ const image: ImageBlock = { alt: 'poster', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const Template: StoryObj = { diff --git a/apps/journeys-admin/src/components/MuxVideoUploadProvider/utils/cancelUploadForBlock/cancelUploadForBlock.spec.ts b/apps/journeys-admin/src/components/MuxVideoUploadProvider/utils/cancelUploadForBlock/cancelUploadForBlock.spec.ts index 5a0a1da4e1c..70541186c92 100644 --- a/apps/journeys-admin/src/components/MuxVideoUploadProvider/utils/cancelUploadForBlock/cancelUploadForBlock.spec.ts +++ b/apps/journeys-admin/src/components/MuxVideoUploadProvider/utils/cancelUploadForBlock/cancelUploadForBlock.spec.ts @@ -92,6 +92,7 @@ describe('cancelUploadForBlock', () => { posterBlockId: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } @@ -143,6 +144,7 @@ describe('cancelUploadForBlock', () => { posterBlockId: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } @@ -194,6 +196,7 @@ describe('cancelUploadForBlock', () => { posterBlockId: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } @@ -229,6 +232,7 @@ describe('cancelUploadForBlock', () => { posterBlockId: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } @@ -275,6 +279,7 @@ describe('cancelUploadForBlock', () => { posterBlockId: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.spec.tsx index 55625745837..b03f159d2f4 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.spec.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.spec.tsx @@ -3,7 +3,6 @@ import { fireEvent, render, screen } from '@testing-library/react' import { JourneyProvider } from '@core/journeys/ui/JourneyProvider' import { journey } from '@core/journeys/ui/JourneyProvider/JourneyProvider.mock' -import { MessagePlatform } from '../../../../__generated__/globalTypes' import { JourneyFields as Journey } from '../../../../__generated__/JourneyFields' import { MultiStepForm } from './MultiStepForm' @@ -46,6 +45,14 @@ jest.mock('./Screens', () => ({ ), + MediaScreen: ({ handleNext }: { handleNext: () => void }) => ( +
+

Media Screen

+ +
+ ), SocialScreen: ({ handleNext }: { handleNext: () => void }) => (

Social Screen

@@ -93,6 +100,11 @@ describe('MultiStepForm', () => { customizable: true, parentStepId: null } + }, + { + __typename: 'ImageBlock', + id: '1', + customizable: true } ] } as unknown as Journey @@ -119,8 +131,13 @@ describe('MultiStepForm', () => { expect(screen.getByTestId('links-screen')).toBeInTheDocument() fireEvent.click(screen.getByTestId('links-next')) - // SocialScreen + DoneScreen + // MediaScreen expect(screen.getByTestId('progress-stepper-step-3')).toBeInTheDocument() + expect(screen.getByTestId('media-screen')).toBeInTheDocument() + fireEvent.click(screen.getByTestId('media-next')) + + // SocialScreen + DoneScreen + expect(screen.getByTestId('progress-stepper-step-4')).toBeInTheDocument() expect(screen.getByTestId('social-screen')).toBeInTheDocument() fireEvent.click(screen.getByTestId('social-next')) }) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.tsx index 22693860eeb..35feaf4b2bd 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.tsx @@ -19,6 +19,7 @@ import { DoneScreen, LanguageScreen, LinksScreen, + MediaScreen, SocialScreen, TextScreen } from './Screens' @@ -52,6 +53,8 @@ function renderScreen( handleScreenNavigation={handleScreenNavigation} /> ) + case 'media': + return case 'social': return ( { blurhash: 'test-blurhash', scale: 1, focalTop: null, - focalLeft: null + focalLeft: null, + customizable: null } satisfies ImageBlock } diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/ShareDrawer/ShareDrawer.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/ShareDrawer/ShareDrawer.spec.tsx index ef962f600b6..7eb7c38df5a 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/ShareDrawer/ShareDrawer.spec.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/ShareDrawer/ShareDrawer.spec.tsx @@ -109,7 +109,8 @@ describe('ShareDrawer', () => { blurhash: 'test-blurhash', scale: 1, focalTop: null, - focalLeft: null + focalLeft: null, + customizable: null } satisfies ImageBlock, seoTitle: 'Test Journey Title' } diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.spec.tsx index 2a313241293..be2fbfafe0d 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.spec.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.spec.tsx @@ -355,7 +355,8 @@ describe('LanguageScreen', () => { blurhash: 'L9AS}j^-0dVC4Tq[=~PATeXSV?aL', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } } diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.spec.tsx new file mode 100644 index 00000000000..1d55b484cd8 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.spec.tsx @@ -0,0 +1,60 @@ +import { MockedProvider, MockedResponse } from '@apollo/client/testing' +import { fireEvent, render, screen } from '@testing-library/react' + +import { JourneyProvider } from '@core/journeys/ui/JourneyProvider' +import { journey } from '@core/journeys/ui/JourneyProvider/JourneyProvider.mock' + +import { MediaScreen } from './MediaScreen' + +describe('MediaScreen', () => { + const handleNext = jest.fn() + + const baseJourney = { + ...journey, + id: 'test-journey-id', + seoTitle: 'Initial SEO Title', + seoDescription: 'Initial SEO Description' + } + + beforeEach(() => { + jest.clearAllMocks() + }) + + const renderMediaScreen = ( + mocks: MockedResponse[] = [] + ): ReturnType => { + return render( + + + + + + ) + } + + it('should render the MediaScreen', () => { + render() + expect(screen.getByText('Media')).toBeInTheDocument() + expect(screen.getByTestId('CustomizeFlowNextButton')).toHaveTextContent( + 'Next' + ) + }) + + it('should call handleNext when Done button is clicked without any changes', () => { + renderMediaScreen() + + const doneButton = screen.getByTestId('CustomizeFlowNextButton') + fireEvent.click(doneButton) + + expect(handleNext).toHaveBeenCalledTimes(1) + }) + + it('should render section components with visible data-testids when screen is shown', () => { + renderMediaScreen() + + expect(screen.getByTestId('LogoSection')).toBeInTheDocument() + expect(screen.getByTestId('CardsSection')).toBeInTheDocument() + expect(screen.getByTestId('ImagesSection')).toBeInTheDocument() + expect(screen.getByTestId('VideosSection')).toBeInTheDocument() + }) +}) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.tsx new file mode 100644 index 00000000000..99bd6644755 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.tsx @@ -0,0 +1,90 @@ +import Box from '@mui/material/Box' +import Stack from '@mui/material/Stack' +import Typography from '@mui/material/Typography' +import { useTranslation } from 'next-i18next' +import { ReactElement, useEffect, useState } from 'react' + +import { TreeBlock } from '@core/journeys/ui/block' +import { useJourney } from '@core/journeys/ui/JourneyProvider' +import { TemplateCardPreview } from '@core/journeys/ui/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview' +import { transformer } from '@core/journeys/ui/transformer' +import { GetJourney_journey_blocks_StepBlock as StepBlock } from '@core/journeys/ui/useJourneyQuery/__generated__/GetJourney' + +import { getJourneyMedia } from '../../../utils/getJourneyMedia' +import { CustomizeFlowNextButton } from '../../CustomizeFlowNextButton' + +import { + CardsSection, + ImagesSection, + LogoSection, + VideosSection +} from './Sections' +import { showImagesSection, showLogoSection, showVideosSection } from './utils' +import { getCustomizableMediaSteps } from './utils/mediaScreenUtils' + +interface MediaScreenProps { + handleNext: () => void +} + +export function MediaScreen({ handleNext }: MediaScreenProps): ReactElement { + const { t } = useTranslation('apps-journeys-admin') + const [selectedCardBlockId, setSelectedCardBlockId] = useState( + null + ) + const { journey } = useJourney() + const showLogo = showLogoSection() + const showImages = showImagesSection(selectedCardBlockId) + const showVideos = showVideosSection(selectedCardBlockId) + const steps = + journey != null + ? (transformer(journey.blocks ?? []) as Array>) + : undefined + + const customizableMediaIds = getJourneyMedia(journey).map((media) => media.id) + + const customizableSteps = getCustomizableMediaSteps( + steps ?? [], + customizableMediaIds + ) + const [selectedStep, setSelectedStep] = useState>( + customizableSteps[0] + ) + + useEffect(() => { + if (customizableSteps.length > 0 && selectedStep == null) { + setSelectedStep(customizableSteps[0]) + } + }, [customizableSteps, selectedStep]) + + function handleStepClick(step: TreeBlock): void { + setSelectedStep(step) + } + return ( + + + {t('Media')} + + + + + {showLogo && } + {} + {showImages && } + {showVideos && } + + + ) +} diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/CardsSection/CardsSection.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/CardsSection/CardsSection.spec.tsx new file mode 100644 index 00000000000..9559e9c1818 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/CardsSection/CardsSection.spec.tsx @@ -0,0 +1,10 @@ +import { render, screen } from '@testing-library/react' + +import { CardsSection } from './CardsSection' + +describe('CardsSection', () => { + it('renders with CardsSection data-testid visible', () => { + render() + expect(screen.getByTestId('CardsSection')).toBeInTheDocument() + }) +}) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/CardsSection/CardsSection.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/CardsSection/CardsSection.tsx new file mode 100644 index 00000000000..60f6c8145fd --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/CardsSection/CardsSection.tsx @@ -0,0 +1,23 @@ +import Box from '@mui/material/Box' +import Typography from '@mui/material/Typography' +import { useTranslation } from 'next-i18next' +import { ReactElement } from 'react' + +interface CardsSectionProps { + onChange: (cardBlockId: string | null) => void +} + +/** + * TODO: update this jsdoc after you implement this component + */ +export function CardsSection({ + onChange: _onChange +}: CardsSectionProps): ReactElement { + const { t } = useTranslation('apps-journeys-admin') + + return ( + + {t('Cards')} + + ) +} diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/CardsSection/index.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/CardsSection/index.ts new file mode 100644 index 00000000000..a0f49e6ae15 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/CardsSection/index.ts @@ -0,0 +1 @@ +export { CardsSection } from './CardsSection' diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/ImagesSection/ImagesSection.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/ImagesSection/ImagesSection.spec.tsx new file mode 100644 index 00000000000..817fd6002bc --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/ImagesSection/ImagesSection.spec.tsx @@ -0,0 +1,10 @@ +import { render, screen } from '@testing-library/react' + +import { ImagesSection } from './ImagesSection' + +describe('ImagesSection', () => { + it('renders with ImagesSection data-testid visible', () => { + render() + expect(screen.getByTestId('ImagesSection')).toBeInTheDocument() + }) +}) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/ImagesSection/ImagesSection.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/ImagesSection/ImagesSection.tsx new file mode 100644 index 00000000000..3794a69a3fe --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/ImagesSection/ImagesSection.tsx @@ -0,0 +1,23 @@ +import Box from '@mui/material/Box' +import Typography from '@mui/material/Typography' +import { useTranslation } from 'next-i18next' +import { ReactElement } from 'react' + +interface ImagesSectionProps { + cardBlockId: string | null +} + +/** + * TODO: update this jsdoc after you implement this component + */ +export function ImagesSection({ + cardBlockId: _cardBlockId +}: ImagesSectionProps): ReactElement { + const { t } = useTranslation('apps-journeys-admin') + + return ( + + {t('Images')} + + ) +} diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/ImagesSection/index.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/ImagesSection/index.ts new file mode 100644 index 00000000000..c7b7408bf05 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/ImagesSection/index.ts @@ -0,0 +1 @@ +export { ImagesSection } from './ImagesSection' diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/LogoSection/LogoSection.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/LogoSection/LogoSection.spec.tsx new file mode 100644 index 00000000000..65e885ddf2e --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/LogoSection/LogoSection.spec.tsx @@ -0,0 +1,10 @@ +import { render, screen } from '@testing-library/react' + +import { LogoSection } from './LogoSection' + +describe('LogoSection', () => { + it('renders with LogoSection data-testid visible', () => { + render() + expect(screen.getByTestId('LogoSection')).toBeInTheDocument() + }) +}) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/LogoSection/LogoSection.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/LogoSection/LogoSection.tsx new file mode 100644 index 00000000000..a4cd8d7c3b8 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/LogoSection/LogoSection.tsx @@ -0,0 +1,23 @@ +import Box from '@mui/material/Box' +import Typography from '@mui/material/Typography' +import { useTranslation } from 'next-i18next' +import { ReactElement } from 'react' + +interface LogoSectionProps { + cardBlockId: string | null +} + +/** + * TODO: update this jsdoc after you implement this component + */ +export function LogoSection({ + cardBlockId: _cardBlockId +}: LogoSectionProps): ReactElement { + const { t } = useTranslation('apps-journeys-admin') + + return ( + + {t('Logo')} + + ) +} diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/LogoSection/index.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/LogoSection/index.ts new file mode 100644 index 00000000000..86fddd025c6 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/LogoSection/index.ts @@ -0,0 +1 @@ +export { LogoSection } from './LogoSection' diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/VideosSection/VideosSection.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/VideosSection/VideosSection.spec.tsx new file mode 100644 index 00000000000..f259983c3bf --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/VideosSection/VideosSection.spec.tsx @@ -0,0 +1,10 @@ +import { render, screen } from '@testing-library/react' + +import { VideosSection } from './VideosSection' + +describe('VideosSection', () => { + it('renders with VideosSection data-testid visible', () => { + render() + expect(screen.getByTestId('VideosSection')).toBeInTheDocument() + }) +}) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/VideosSection/VideosSection.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/VideosSection/VideosSection.tsx new file mode 100644 index 00000000000..f625e6659ef --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/VideosSection/VideosSection.tsx @@ -0,0 +1,23 @@ +import Box from '@mui/material/Box' +import Typography from '@mui/material/Typography' +import { useTranslation } from 'next-i18next' +import { ReactElement } from 'react' + +interface VideosSectionProps { + cardBlockId: string | null +} + +/** + * TODO: update this jsdoc after you implement this component + */ +export function VideosSection({ + cardBlockId: _cardBlockId +}: VideosSectionProps): ReactElement { + const { t } = useTranslation('apps-journeys-admin') + + return ( + + {t('Video')} + + ) +} diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/VideosSection/index.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/VideosSection/index.ts new file mode 100644 index 00000000000..0e26ffe6679 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/VideosSection/index.ts @@ -0,0 +1 @@ +export { VideosSection } from './VideosSection' diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/index.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/index.ts new file mode 100644 index 00000000000..146916c04d6 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/index.ts @@ -0,0 +1,4 @@ +export { LogoSection } from './LogoSection' +export { CardsSection } from './CardsSection' +export { ImagesSection } from './ImagesSection' +export { VideosSection } from './VideosSection' diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/index.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/index.ts new file mode 100644 index 00000000000..938c60cfebc --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/index.ts @@ -0,0 +1 @@ +export { MediaScreen } from './MediaScreen' diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/index.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/index.ts new file mode 100644 index 00000000000..edf11621a59 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/index.ts @@ -0,0 +1,4 @@ +export { showLogoSection } from './showLogoSection' +export { showImagesSection } from './showImagesSection' +export { showVideosSection } from './showVideosSection' +export { getCustomizableMediaSteps } from './mediaScreenUtils' diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/mediaScreenUtils.spec.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/mediaScreenUtils.spec.ts new file mode 100644 index 00000000000..de424a6a8d6 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/mediaScreenUtils.spec.ts @@ -0,0 +1,128 @@ +import type { TreeBlock } from '@core/journeys/ui/block' +import type { GetJourney_journey_blocks_StepBlock as StepBlock } from '@core/journeys/ui/useJourneyQuery/__generated__/GetJourney' + +import { getCustomizableMediaSteps } from './mediaScreenUtils' + +describe('getCustomizableMediaSteps', () => { + it('returns empty array when steps is empty', () => { + expect(getCustomizableMediaSteps([], ['media1'])).toEqual([]) + }) + + it('returns empty array when customizableMediaIds is empty', () => { + const steps: TreeBlock[] = [ + { + id: 'step1', + __typename: 'StepBlock', + children: [{ id: 'media1', __typename: 'CardBlock', children: [] }] + } as unknown as TreeBlock + ] + expect(getCustomizableMediaSteps(steps, [])).toEqual([]) + }) + + it('returns only steps that contain a direct child with id in customizableMediaIds', () => { + const steps: TreeBlock[] = [ + { + id: 'step1', + __typename: 'StepBlock', + children: [ + { id: 'target-media', __typename: 'CardBlock', children: [] } + ] + } as unknown as TreeBlock, + { + id: 'step2', + __typename: 'StepBlock', + children: [{ id: 'other', __typename: 'CardBlock', children: [] }] + } as unknown as TreeBlock + ] + const result = getCustomizableMediaSteps(steps, ['target-media']) + expect(result).toEqual([steps[0]]) + }) + + it('returns only steps that contain a nested descendant with id in customizableMediaIds', () => { + const steps: TreeBlock[] = [ + { + id: 'step1', + __typename: 'StepBlock', + children: [ + { + id: 'card1', + __typename: 'CardBlock', + children: [ + { id: 'nested-media', __typename: 'CardBlock', children: [] } + ] + } + ] + } as unknown as TreeBlock, + { + id: 'step2', + __typename: 'StepBlock', + children: [{ id: 'card2', __typename: 'CardBlock', children: [] }] + } as unknown as TreeBlock + ] + const result = getCustomizableMediaSteps(steps, ['nested-media']) + expect(result).toEqual([steps[0]]) + }) + + it('should return steps that contain direct children and nested descendants with id in customizableMediaIds', () => { + const steps: TreeBlock[] = [ + { + id: 'step1', + __typename: 'StepBlock', + children: [ + { + id: 'card1', + __typename: 'CardBlock', + children: [ + { id: 'nested-media', __typename: 'CardBlock', children: [] } + ] + } + ] + } as unknown as TreeBlock, + { + id: 'step2', + __typename: 'StepBlock', + children: [{ id: 'card2', __typename: 'CardBlock', children: [] }] + } as unknown as TreeBlock + ] + const result = getCustomizableMediaSteps(steps, ['nested-media', 'card2']) + expect(result).toEqual(steps) + }) + + it('excludes steps that have no matching descendant', () => { + const steps: TreeBlock[] = [ + { + id: 'step1', + __typename: 'StepBlock', + children: [{ id: 'block-a', __typename: 'CardBlock', children: [] }] + } as unknown as TreeBlock, + { + id: 'step2', + __typename: 'StepBlock', + children: [{ id: 'block-b', __typename: 'CardBlock', children: [] }] + } as unknown as TreeBlock + ] + expect(getCustomizableMediaSteps(steps, ['media-x'])).toEqual([]) + }) + + it('preserves step order', () => { + const steps: TreeBlock[] = [ + { + id: 'stepA', + __typename: 'StepBlock', + children: [{ id: 'media-a', __typename: 'CardBlock', children: [] }] + } as unknown as TreeBlock, + { + id: 'stepB', + __typename: 'StepBlock', + children: [{ id: 'media-b', __typename: 'CardBlock', children: [] }] + } as unknown as TreeBlock, + { + id: 'stepC', + __typename: 'StepBlock', + children: [{ id: 'other', __typename: 'CardBlock', children: [] }] + } as unknown as TreeBlock + ] + const result = getCustomizableMediaSteps(steps, ['media-a', 'media-b']) + expect(result.map((s) => s.id)).toEqual(['stepA', 'stepB']) + }) +}) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/mediaScreenUtils.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/mediaScreenUtils.ts new file mode 100644 index 00000000000..d0544566a4e --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/mediaScreenUtils.ts @@ -0,0 +1,33 @@ +import { TreeBlock } from '@core/journeys/ui/block/TreeBlock' +import { GetJourney_journey_blocks_StepBlock as StepBlock } from '@core/journeys/ui/useJourneyQuery/__generated__/GetJourney' + +/** + * Returns whether the given block or any of its descendants has an id in the provided list. + * + * @param block - The tree block to check (and its children recursively). + * @param ids - List of block ids to match against. + * @returns True if block.id or any descendant id is in ids, otherwise false. + */ +function hasMatchingDescendant(block: TreeBlock, ids: string[]): boolean { + if (ids.includes(block.id)) return true + return block.children.some((child) => hasMatchingDescendant(child, ids)) +} + +/** + * Filters step blocks to only those that contain at least one block whose id is in customizableMediaIds + * (the block may be the step's direct child or a descendant). + * + * @param steps - Array of step blocks from the journey. + * @param customizableMediaIds - Block ids that represent customizable media. + * @returns Steps that have at least one matching customizable media block in their subtree. + */ +export function getCustomizableMediaSteps( + steps: TreeBlock[], + customizableMediaIds: string[] +): TreeBlock[] { + return steps.filter((step) => + step.children.some((child) => + hasMatchingDescendant(child, customizableMediaIds) + ) + ) +} diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showImagesSection/index.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showImagesSection/index.ts new file mode 100644 index 00000000000..7d88103892a --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showImagesSection/index.ts @@ -0,0 +1 @@ +export { showImagesSection } from './showImagesSection' diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showImagesSection/showImagesSection.spec.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showImagesSection/showImagesSection.spec.ts new file mode 100644 index 00000000000..2e1d6ca6914 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showImagesSection/showImagesSection.spec.ts @@ -0,0 +1,14 @@ +/** + * TODO: update these when implementing the component + */ +import { showImagesSection } from './showImagesSection' + +describe('showImagesSection', () => { + it('returns true when cardBlockId is null (skeleton)', () => { + expect(showImagesSection(null)).toBe(true) + }) + + it('returns true when cardBlockId is set (skeleton)', () => { + expect(showImagesSection('card-1')).toBe(true) + }) +}) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showImagesSection/showImagesSection.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showImagesSection/showImagesSection.ts new file mode 100644 index 00000000000..4b99d9be61b --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showImagesSection/showImagesSection.ts @@ -0,0 +1,11 @@ +/** + * Shows the images section on the media screen. + * When implementing, check if the selected card has customizable image blocks. + * + * @param cardBlockId - the id of the selected card block + * @returns true if the images section should be shown, false otherwise + */ +export function showImagesSection(cardBlockId: string | null): boolean { + // TODO: implement when building Images section – pass journey and check blocks for cardBlockId + return true +} diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showLogoSection/index.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showLogoSection/index.ts new file mode 100644 index 00000000000..4cd89a095a1 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showLogoSection/index.ts @@ -0,0 +1 @@ +export { showLogoSection } from './showLogoSection' diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showLogoSection/showLogoSection.spec.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showLogoSection/showLogoSection.spec.ts new file mode 100644 index 00000000000..0324d8c47bd --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showLogoSection/showLogoSection.spec.ts @@ -0,0 +1,10 @@ +/** + * TODO: update these when implementing the component + */ +import { showLogoSection } from './showLogoSection' + +describe('showLogoSection', () => { + it('returns true (skeleton – implement when building Logo section)', () => { + expect(showLogoSection()).toBe(true) + }) +}) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showLogoSection/showLogoSection.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showLogoSection/showLogoSection.ts new file mode 100644 index 00000000000..3b263c79b07 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showLogoSection/showLogoSection.ts @@ -0,0 +1,10 @@ +/** + * Shows the logo section on the media screen. + * Logo is journey-level; when implementing, check journey.logoImageBlock?.customizable. + * + * @returns true if the logo section should be shown, false otherwise + */ +export function showLogoSection(): boolean { + // TODO: implement when building Logo section – pass journey and check journey.logoImageBlock?.customizable + return true +} diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showVideosSection/index.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showVideosSection/index.ts new file mode 100644 index 00000000000..3cb9a082aef --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showVideosSection/index.ts @@ -0,0 +1 @@ +export { showVideosSection } from './showVideosSection' diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showVideosSection/showVideosSection.spec.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showVideosSection/showVideosSection.spec.ts new file mode 100644 index 00000000000..aa39263105a --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showVideosSection/showVideosSection.spec.ts @@ -0,0 +1,14 @@ +/** + * TODO: update these when implementing the component + */ +import { showVideosSection } from './showVideosSection' + +describe('showVideosSection', () => { + it('returns true when cardBlockId is null (skeleton)', () => { + expect(showVideosSection(null)).toBe(true) + }) + + it('returns true when cardBlockId is set (skeleton)', () => { + expect(showVideosSection('card-1')).toBe(true) + }) +}) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showVideosSection/showVideosSection.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showVideosSection/showVideosSection.ts new file mode 100644 index 00000000000..a0a12dd0242 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/utils/showVideosSection/showVideosSection.ts @@ -0,0 +1,11 @@ +/** + * Shows the videos section on the media screen. + * When implementing, check if the selected card has customizable video blocks. + * + * @param cardBlockId - the id of the selected card block + * @returns true if the videos section should be shown, false otherwise + */ +export function showVideosSection(cardBlockId: string | null): boolean { + // TODO: implement when building Videos section – pass journey and check blocks for cardBlockId + return true +} diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.spec.tsx index b21708eea7e..dad7e0c7152 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.spec.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.spec.tsx @@ -55,7 +55,8 @@ describe('SocialScreenSocialImage', () => { blurhash: 'L9AS}j^-0dVC4Tq[=~PATeXSV?aL', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } } @@ -144,7 +145,8 @@ describe('SocialScreenSocialImage', () => { blurhash: 'L9AS}j^-0dVC4Tq[=~PATeXSV?aL', scale: null, focalTop: null, - focalLeft: null + focalLeft: null, + customizable: null } } })) @@ -203,7 +205,8 @@ describe('SocialScreenSocialImage', () => { blurhash: 'L9AS}j^-0dVC4Tq[=~PATeXSV?aL', scale: null, focalTop: null, - focalLeft: null + focalLeft: null, + customizable: null } } })) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/index.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/index.ts index a72a9379cd4..b3477cdb866 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/index.ts +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/index.ts @@ -3,3 +3,4 @@ export { TextScreen } from './TextScreen' export { LinksScreen } from './LinksScreen' export { SocialScreen } from './SocialScreen' export { DoneScreen } from './DoneScreen' +export { MediaScreen } from './MediaScreen' diff --git a/apps/journeys-admin/src/components/TemplateCustomization/utils/getCustomizeFlowConfig/getCustomizeFlowConfig.spec.ts b/apps/journeys-admin/src/components/TemplateCustomization/utils/getCustomizeFlowConfig/getCustomizeFlowConfig.spec.ts index 3af50d366d4..4c248e58f44 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/utils/getCustomizeFlowConfig/getCustomizeFlowConfig.spec.ts +++ b/apps/journeys-admin/src/components/TemplateCustomization/utils/getCustomizeFlowConfig/getCustomizeFlowConfig.spec.ts @@ -84,7 +84,7 @@ describe('getCustomizeFlowConfig', () => { }) }) - it('should include both text and links screens when journey has both capabilities', () => { + it('should include text, links, and media screens when journey has all three capabilities', () => { const journey = { journeyCustomizationDescription: 'Hello {{ firstName: John }}!', journeyCustomizationFields: [ @@ -106,6 +106,11 @@ describe('getCustomizeFlowConfig', () => { customizable: true, parentStepId: null } + }, + { + __typename: 'ImageBlock', + id: '1', + customizable: true } ] } as unknown as Journey @@ -116,10 +121,11 @@ describe('getCustomizeFlowConfig', () => { 'language', 'text', 'links', + 'media', 'social', 'done' ]) - expect(result.totalSteps).toBe(5) + expect(result.totalSteps).toBe(6) expect(result.hasEditableText).toBe(true) expect(result.hasCustomizableLinks).toBe(true) expect(result.links).toHaveLength(1) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/utils/getCustomizeFlowConfig/getCustomizeFlowConfig.ts b/apps/journeys-admin/src/components/TemplateCustomization/utils/getCustomizeFlowConfig/getCustomizeFlowConfig.ts index 5e075e99822..66ab1878fbb 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/utils/getCustomizeFlowConfig/getCustomizeFlowConfig.ts +++ b/apps/journeys-admin/src/components/TemplateCustomization/utils/getCustomizeFlowConfig/getCustomizeFlowConfig.ts @@ -2,11 +2,13 @@ import { TFunction } from 'i18next' import { GetJourney_journey as Journey } from '../../../../../__generated__/GetJourney' import { JourneyLink, getJourneyLinks } from '../getJourneyLinks' +import { getJourneyMedia } from '../getJourneyMedia' export type CustomizationScreen = | 'language' | 'text' | 'links' + | 'media' | 'social' | 'done' @@ -15,6 +17,7 @@ export interface CustomizeFlowConfig { totalSteps: number hasEditableText: boolean hasCustomizableLinks: boolean + hasCustomizableMedia: boolean links: JourneyLink[] } @@ -25,7 +28,7 @@ export interface CustomizeFlowConfig { * - Whether the journey has editable text (journeyCustomizationDescription and journeyCustomizationFields) * - Whether the journey has customizable links (chat buttons or blocks with customizable actions) * - * The screens are always ordered as: language -> text (if applicable) -> links (if applicable) -> social -> done + * The screens are always ordered as: language -> text (if applicable) -> links (if applicable) -> media (if applicable) -> social -> done * * @param journey - The journey object containing customization data * @param t - Translation function (optional, used for link detection) @@ -34,10 +37,11 @@ export interface CustomizeFlowConfig { * @example * ```typescript * const config = getCustomizeFlowConfig(journey, t) - * // config.screens might be ['language', 'text', 'links', 'social', 'done'] - * // config.totalSteps would be 5 + * // config.screens might be ['language', 'text', 'links', 'media', 'social', 'done'] + * // config.totalSteps would be 6 * // config.hasEditableText would be true * // config.hasCustomizableLinks would be true + * // config.hasCustomizableMedia would be true * // config.links would contain the journey's customizable links * ``` */ @@ -62,6 +66,9 @@ export function getCustomizeFlowConfig( // Check for customizable links const hasCustomizableLinks = links.length > 0 + // Check for media + const hasCustomizableMedia = getJourneyMedia(journey).length > 0 + // Build screens array based on capabilities const screens: CustomizationScreen[] = [...baseScreens] @@ -77,11 +84,18 @@ export function getCustomizeFlowConfig( screens.splice(socialIndex, 0, 'links') } + if (hasCustomizableMedia) { + // Insert media screen before social screen + const socialIndex = screens.indexOf('social') + screens.splice(socialIndex, 0, 'media') + } + return { screens, totalSteps: screens.length, hasEditableText, hasCustomizableLinks, + hasCustomizableMedia, links } } diff --git a/apps/journeys-admin/src/components/TemplateCustomization/utils/getJourneyMedia/getJourneyMedia.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/utils/getJourneyMedia/getJourneyMedia.spec.tsx new file mode 100644 index 00000000000..f162068f05a --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/utils/getJourneyMedia/getJourneyMedia.spec.tsx @@ -0,0 +1,119 @@ +import { GetJourney_journey as Journey } from '../../../../../__generated__/GetJourney' + +import { getJourneyMedia } from './getJourneyMedia' + +describe('getJourneyMedia', () => { + it('should return an empty array if no journey is provided', () => { + expect(getJourneyMedia(undefined)).toEqual([]) + }) + + it('should return empty array if journey has no blocks', () => { + const journey = { blocks: [] } as unknown as Journey + expect(getJourneyMedia(journey)).toEqual([]) + }) + + it('should extract customizable logo block', () => { + const journey = { + logoImageBlock: { + __typename: 'ImageBlock', + customizable: true, + id: 'logo-1' + }, + blocks: [ + { + __typename: 'ButtonBlock', + id: 'btn-1', + label: 'Hi {{firstName}}', + action: { + __typename: 'LinkAction', + url: 'https://example.com', + customizable: true, + parentStepId: 'step-1' + } + } + ] + } as unknown as Journey + expect(getJourneyMedia(journey)).toEqual([ + { __typename: 'ImageBlock', id: 'logo-1', customizable: true } + ]) + }) + + it('should extract customizable image blocks', () => { + const journey = { + blocks: [ + { + __typename: 'ButtonBlock', + id: 'btn-1', + label: 'Hi {{firstName}}', + action: { + __typename: 'LinkAction', + url: 'https://example.com', + customizable: true, + parentStepId: 'step-1' + } + }, + { __typename: 'ImageBlock', id: 'img-1', customizable: true } + ] + } as unknown as Journey + expect(getJourneyMedia(journey)).toEqual([ + { __typename: 'ImageBlock', id: 'img-1', customizable: true } + ]) + }) + + it('should extract customizable video blocks', () => { + const journey = { + blocks: [ + { + __typename: 'ButtonBlock', + id: 'btn-1', + label: 'Hi {{firstName}}', + action: { + __typename: 'LinkAction', + url: 'https://example.com', + customizable: true, + parentStepId: 'step-1' + } + }, + { __typename: 'VideoBlock', id: 'vid-1', customizable: true } + ] + } as unknown as Journey + expect(getJourneyMedia(journey)).toEqual([ + { __typename: 'VideoBlock', id: 'vid-1', customizable: true } + ]) + }) + + it('should extract all three combinations of customizable blocks', () => { + const journey = { + logoImageBlock: { + __typename: 'ImageBlock', + customizable: true, + id: 'logo-1' + }, + blocks: [ + { __typename: 'ImageBlock', id: 'img-1', customizable: true }, + { __typename: 'ImageBlock', id: 'img-2', customizable: false }, + { __typename: 'VideoBlock', id: 'vid-1', customizable: true }, + { __typename: 'VideoBlock', id: 'vid-2', customizable: false } + ] + } as unknown as Journey + expect(getJourneyMedia(journey)).toEqual([ + { __typename: 'ImageBlock', id: 'logo-1', customizable: true }, + { __typename: 'ImageBlock', id: 'img-1', customizable: true }, + { __typename: 'VideoBlock', id: 'vid-1', customizable: true } + ]) + }) + + it('should not extract non-customizable logo', () => { + const journey = { + logoImageBlock: { + __typename: 'ImageBlock', + customizable: false, + id: 'logo-1' + }, + blocks: [{ __typename: 'ImageBlock', id: 'img-1', customizable: true }] + } as unknown as Journey + expect(getJourneyMedia(journey)).toEqual([ + { __typename: 'ImageBlock', id: 'img-1', customizable: true } + ]) + }) +}) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/utils/getJourneyMedia/getJourneyMedia.tsx b/apps/journeys-admin/src/components/TemplateCustomization/utils/getJourneyMedia/getJourneyMedia.tsx new file mode 100644 index 00000000000..140db430e91 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/utils/getJourneyMedia/getJourneyMedia.tsx @@ -0,0 +1,28 @@ +import { + GetJourney_journey_blocks_ImageBlock as ImageBlock, + GetJourney_journey as Journey, + GetJourney_journey_blocks_VideoBlock as VideoBlock +} from '../../../../../__generated__/GetJourney' + +export type JourneyMedia = ImageBlock | VideoBlock + +export function getJourneyMedia(journey?: Journey): JourneyMedia[] { + const customizableLogoBlock = journey?.logoImageBlock?.customizable + ? [journey?.logoImageBlock] + : [] + const customizableImageBlocks = + journey?.blocks?.filter( + (block): block is ImageBlock => + block.__typename === 'ImageBlock' && block.customizable === true + ) ?? [] + const customizableVideoBlocks = + journey?.blocks?.filter( + (block): block is VideoBlock => + block.__typename === 'VideoBlock' && block.customizable === true + ) ?? [] + return [ + ...customizableLogoBlock, + ...customizableImageBlocks, + ...customizableVideoBlocks + ] +} diff --git a/apps/journeys-admin/src/components/TemplateCustomization/utils/getJourneyMedia/index.ts b/apps/journeys-admin/src/components/TemplateCustomization/utils/getJourneyMedia/index.ts new file mode 100644 index 00000000000..134873569ee --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/utils/getJourneyMedia/index.ts @@ -0,0 +1 @@ +export { getJourneyMedia, type JourneyMedia } from './getJourneyMedia' diff --git a/apps/journeys-admin/src/components/TemplateCustomization/utils/useVideoUpload/index.ts b/apps/journeys-admin/src/components/TemplateCustomization/utils/useVideoUpload/index.ts new file mode 100644 index 00000000000..c7b781c6ef0 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/utils/useVideoUpload/index.ts @@ -0,0 +1,2 @@ +export { useVideoUpload } from './useVideoUpload' +export type { VideoUploadStatus } from './useVideoUpload' diff --git a/apps/journeys-admin/src/components/TemplateCustomization/utils/useVideoUpload/useVideoUpload.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/utils/useVideoUpload/useVideoUpload.spec.tsx new file mode 100644 index 00000000000..5c87813e0ba --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/utils/useVideoUpload/useVideoUpload.spec.tsx @@ -0,0 +1,417 @@ +import { MockedProvider, MockedResponse } from '@apollo/client/testing' +import { UpChunk } from '@mux/upchunk' +import { act, renderHook, waitFor } from '@testing-library/react' + +import { + CREATE_MUX_VIDEO_UPLOAD_BY_FILE_MUTATION, + GET_MY_MUX_VIDEO_QUERY, + useVideoUpload +} from './useVideoUpload' + +jest.mock('@mux/upchunk', () => ({ + UpChunk: { + createUpload: jest.fn() + } +})) + +jest.mock('react-dropzone', () => ({ + useDropzone: jest.fn(() => ({ + getRootProps: jest.fn(), + getInputProps: jest.fn(), + open: jest.fn() + })) +})) + +const createMuxVideoUploadByFileMock: MockedResponse = { + request: { + query: CREATE_MUX_VIDEO_UPLOAD_BY_FILE_MUTATION, + variables: { name: 'video.mp4' } + }, + result: { + data: { + createMuxVideoUploadByFile: { + __typename: 'MuxVideo', + uploadUrl: 'https://mux.com/upload', + id: 'videoId' + } + } + } +} + +const getMyMuxVideoMock: MockedResponse = { + request: { + query: GET_MY_MUX_VIDEO_QUERY, + variables: { id: 'videoId' } + }, + result: { + data: { + getMyMuxVideo: { + __typename: 'MuxVideo', + id: 'videoId', + assetId: 'assetId', + playbackId: 'playbackId', + readyToStream: true + } + } + } +} + +const getMyMuxVideoProcessingMock: MockedResponse = { + request: { + query: GET_MY_MUX_VIDEO_QUERY, + variables: { id: 'videoId' } + }, + result: { + data: { + getMyMuxVideo: { + __typename: 'MuxVideo', + id: 'videoId', + assetId: 'assetId', + playbackId: 'playbackId', + readyToStream: false + } + } + } +} + +describe('useVideoUpload', () => { + const file = new File([''], 'video.mp4', { type: 'video/mp4' }) + + it('should handle successful upload and polling', async () => { + const onUploadComplete = jest.fn() + const mockUpload = { + on: jest.fn(), + abort: jest.fn() + } + ;(UpChunk.createUpload as jest.Mock).mockReturnValue(mockUpload) + + const { result } = renderHook(() => useVideoUpload({ onUploadComplete }), { + wrapper: ({ children }) => ( + + {children} + + ) + }) + + await act(async () => { + await result.current.handleUpload(file) + }) + + expect(result.current.status).toBe('uploading') + expect(UpChunk.createUpload).toHaveBeenCalledWith({ + endpoint: 'https://mux.com/upload', + file, + chunkSize: 5120 + }) + + // Simulate progress + const progressCallback = mockUpload.on.mock.calls.find( + (call) => call[0] === 'progress' + )[1] + act(() => { + progressCallback({ detail: 50 }) + }) + expect(result.current.progress).toBe(50) + + // Simulate success + const successCallback = mockUpload.on.mock.calls.find( + (call) => call[0] === 'success' + )[1] + await act(async () => { + successCallback() + }) + + await waitFor(() => expect(result.current.status).toBe('completed')) + expect(onUploadComplete).toHaveBeenCalledWith('videoId') + }) + + it('should set videoId when upload starts', async () => { + const mockUpload = { + on: jest.fn(), + abort: jest.fn() + } + ;(UpChunk.createUpload as jest.Mock).mockReturnValue(mockUpload) + + const { result } = renderHook(() => useVideoUpload(), { + wrapper: ({ children }) => ( + + {children} + + ) + }) + + await act(async () => { + await result.current.handleUpload(file) + }) + + expect(result.current.videoId).toBe('videoId') + }) + + it('should handle upload error', async () => { + const onUploadError = jest.fn() + const mockUpload = { + on: jest.fn(), + abort: jest.fn() + } + ;(UpChunk.createUpload as jest.Mock).mockReturnValue(mockUpload) + + const { result } = renderHook(() => useVideoUpload({ onUploadError }), { + wrapper: ({ children }) => ( + + {children} + + ) + }) + + await act(async () => { + await result.current.handleUpload(file) + }) + + const errorCallback = mockUpload.on.mock.calls.find( + (call) => call[0] === 'error' + )[1] + + act(() => { + errorCallback() + }) + + expect(result.current.status).toBe('error') + expect(result.current.error).toBe('Upload failed') + expect(onUploadError).toHaveBeenCalledWith('Upload failed') + }) + + it('should handle GraphQL errors from createMuxVideoUploadByFile', async () => { + const onUploadError = jest.fn() + const graphqlErrorMock: MockedResponse = { + request: { + query: CREATE_MUX_VIDEO_UPLOAD_BY_FILE_MUTATION, + variables: { name: 'video.mp4' } + }, + result: { + errors: [{ message: 'GraphQL Error: Unauthorized' }] + } + } + + const { result } = renderHook(() => useVideoUpload({ onUploadError }), { + wrapper: ({ children }) => ( + + {children} + + ) + }) + + await act(async () => { + await result.current.handleUpload(file) + }) + + expect(result.current.status).toBe('error') + expect(result.current.error).toBe('GraphQL Error: Unauthorized') + expect(onUploadError).toHaveBeenCalledWith('GraphQL Error: Unauthorized') + }) + + it('should handle file too large error', async () => { + const onUploadError = jest.fn() + const largeFile = new File([''], 'large.mp4', { type: 'video/mp4' }) + Object.defineProperty(largeFile, 'size', { value: 2 * 1024 * 1024 * 1024 }) // 2GB + + const { result } = renderHook(() => useVideoUpload({ onUploadError }), { + wrapper: ({ children }) => ( + + {children} + + ) + }) + + await act(async () => { + await result.current.handleUpload(largeFile) + }) + + expect(result.current.status).toBe('error') + expect(result.current.error).toBe('File is too large. Max size is 1GB.') + expect(onUploadError).toHaveBeenCalledWith( + 'File is too large. Max size is 1GB.' + ) + }) + + it('should cancel upload', async () => { + const mockUpload = { + on: jest.fn(), + abort: jest.fn() + } + ;(UpChunk.createUpload as jest.Mock).mockReturnValue(mockUpload) + + const { result } = renderHook(() => useVideoUpload(), { + wrapper: ({ children }) => ( + + {children} + + ) + }) + + await act(async () => { + await result.current.handleUpload(file) + }) + + expect(result.current.status).toBe('uploading') + + act(() => { + result.current.cancelUpload() + }) + + expect(mockUpload.abort).toHaveBeenCalled() + expect(result.current.status).toBe('idle') + expect(result.current.progress).toBe(0) + expect(result.current.error).toBeUndefined() + expect(result.current.videoId).toBeUndefined() + }) + + it('should poll with exponential backoff until ready', async () => { + const onUploadComplete = jest.fn() + const mockUpload = { + on: jest.fn(), + abort: jest.fn() + } + ;(UpChunk.createUpload as jest.Mock).mockReturnValue(mockUpload) + + const { result } = renderHook( + () => useVideoUpload({ onUploadComplete, initialPollInterval: 100 }), + { + wrapper: ({ children }) => ( + + {children} + + ) + } + ) + + await act(async () => { + await result.current.handleUpload(file) + }) + + // Simulate success to start polling + const successCallback = mockUpload.on.mock.calls.find( + (call) => call[0] === 'success' + )[1] + + await act(async () => { + successCallback() + }) + + // Wait for the immediate poll to be called and for status to change to processing + await waitFor(() => expect(result.current.status).toBe('processing')) + + // Wait for the second poll to complete and status to change to completed + // We use a shorter timeout since we reduced the interval to 100ms for faster testing. + // Note: The backoff timing here (100ms, 150ms, etc.) is reduced for test performance + // and does not match the real-world production intervals (2s, 3s, etc.). + await waitFor(() => expect(result.current.status).toBe('completed'), { + timeout: 2000 + }) + expect(onUploadComplete).toHaveBeenCalledWith('videoId') + }) + + it('should handle polling error', async () => { + const onUploadError = jest.fn() + const mockUpload = { + on: jest.fn(), + abort: jest.fn() + } + ;(UpChunk.createUpload as jest.Mock).mockReturnValue(mockUpload) + + const pollingErrorMock: MockedResponse = { + request: { + query: GET_MY_MUX_VIDEO_QUERY, + variables: { id: 'videoId' } + }, + error: new Error('Polling failed') + } + + const { result } = renderHook( + () => useVideoUpload({ onUploadError, initialPollInterval: 100 }), + { + wrapper: ({ children }) => ( + + {children} + + ) + } + ) + + await act(async () => { + await result.current.handleUpload(file) + }) + + // Simulate success to start polling + const successCallback = mockUpload.on.mock.calls.find( + (call) => call[0] === 'success' + )[1] + + await act(async () => { + successCallback() + }) + + // Wait for all 3 retries to exhaust (3 retries * 100ms delay = ~300ms + buffer) + // Note: The backoff timing here is reduced for test performance and does not match + // the real-world production intervals. + await waitFor(() => expect(result.current.status).toBe('error'), { + timeout: 2000 + }) + expect(result.current.error).toBe('Failed to check video status') + expect(onUploadError).toHaveBeenCalledWith('Failed to check video status') + }) + + it('should cleanup on unmount', async () => { + const mockUpload = { + on: jest.fn(), + abort: jest.fn() + } + ;(UpChunk.createUpload as jest.Mock).mockReturnValue(mockUpload) + + const { result, unmount } = renderHook(() => useVideoUpload(), { + wrapper: ({ children }) => ( + + {children} + + ) + }) + + await act(async () => { + await result.current.handleUpload(file) + }) + + unmount() + + expect(mockUpload.abort).toHaveBeenCalled() + }) +}) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/utils/useVideoUpload/useVideoUpload.tsx b/apps/journeys-admin/src/components/TemplateCustomization/utils/useVideoUpload/useVideoUpload.tsx new file mode 100644 index 00000000000..c212dde9347 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/utils/useVideoUpload/useVideoUpload.tsx @@ -0,0 +1,240 @@ +import { gql, useLazyQuery, useMutation } from '@apollo/client' +import { UpChunk } from '@mux/upchunk' +import { useCallback, useEffect, useRef, useState } from 'react' +import { useDropzone } from 'react-dropzone' + +export const CREATE_MUX_VIDEO_UPLOAD_BY_FILE_MUTATION = gql` + mutation TemplateCustomizeCreateMuxVideoUploadByFileMutation($name: String!) { + createMuxVideoUploadByFile(name: $name) { + uploadUrl + id + } + } +` + +export const GET_MY_MUX_VIDEO_QUERY = gql` + query TemplateCustomizeGetMyMuxVideoQuery($id: ID!) { + getMyMuxVideo(id: $id) { + id + assetId + playbackId + readyToStream + } + } +` + +const INITIAL_POLL_INTERVAL = 2000 // 2 seconds +const MAX_POLL_INTERVAL = 30000 // 30 seconds +const MAX_RETRIES = 3 +const MAX_VIDEO_SIZE = 1073741824 // 1GB + +export type VideoUploadStatus = + | 'idle' + | 'uploading' + | 'processing' + | 'completed' + | 'error' + +interface UseVideoUploadOptions { + onUploadComplete?: (videoId: string) => void + onUploadError?: (error: string) => void + /** @default 2000 */ + initialPollInterval?: number + /** @default 3 */ + maxRetries?: number +} + +export function useVideoUpload({ + onUploadComplete, + onUploadError, + initialPollInterval = INITIAL_POLL_INTERVAL, + maxRetries = MAX_RETRIES +}: UseVideoUploadOptions = {}) { + const [status, setStatus] = useState('idle') + const [progress, setProgress] = useState(0) + const [error, setError] = useState() + const [videoId, setVideoId] = useState() + + const uploadInstanceRef = useRef<{ abort: () => void } | null>(null) + const pollingTimeoutRef = useRef(null) + const retryCountRef = useRef(0) + + const [createMuxVideoUploadByFile] = useMutation( + CREATE_MUX_VIDEO_UPLOAD_BY_FILE_MUTATION + ) + + const [getMyMuxVideo] = useLazyQuery(GET_MY_MUX_VIDEO_QUERY, { + fetchPolicy: 'network-only' + }) + + const clearPolling = useCallback(() => { + if (pollingTimeoutRef.current != null) { + clearTimeout(pollingTimeoutRef.current) + pollingTimeoutRef.current = null + } + retryCountRef.current = 0 + }, []) + + const cancelUpload = useCallback(() => { + uploadInstanceRef.current?.abort() + uploadInstanceRef.current = null + clearPolling() + setStatus('idle') + setProgress(0) + setError(undefined) + setVideoId(undefined) + }, [clearPolling]) + + const startPolling = useCallback( + (videoId: string) => { + setStatus('processing') + + const poll = async (delay: number) => { + try { + const result = await getMyMuxVideo({ + variables: { id: videoId } + }) + + if (result.error != null) { + throw result.error + } + + if (result.data?.getMyMuxVideo?.readyToStream === true) { + clearPolling() + setStatus('completed') + onUploadComplete?.(videoId) + return + } + + // Reset retries on successful query (even if not ready) + retryCountRef.current = 0 + + // Schedule next poll with exponential backoff + const nextDelay = Math.min(delay * 1.5, MAX_POLL_INTERVAL) + pollingTimeoutRef.current = setTimeout(() => { + void poll(nextDelay) + }, delay) + } catch (err) { + // Retry on recoverable errors (e.g., network issues or 500s) + if (retryCountRef.current < maxRetries) { + retryCountRef.current++ + pollingTimeoutRef.current = setTimeout(() => { + void poll(delay) + }, delay) + return + } + + clearPolling() + setStatus('error') + setError('Failed to check video status') + onUploadError?.('Failed to check video status') + } + } + + void poll(initialPollInterval) + }, + [ + clearPolling, + getMyMuxVideo, + onUploadComplete, + onUploadError, + initialPollInterval, + maxRetries + ] + ) + + const handleUpload = useCallback( + async (file: File) => { + if (file.size > MAX_VIDEO_SIZE) { + const message = 'File is too large. Max size is 1GB.' + setStatus('error') + setError(message) + onUploadError?.(message) + return + } + + setStatus('uploading') + setProgress(0) + setError(undefined) + + try { + const { data, errors } = await createMuxVideoUploadByFile({ + variables: { name: file.name } + }) + if (errors != null && errors.length > 0) { + const message = errors[0]?.message ?? 'Upload failed' + throw new Error(message) + } + + const uploadUrl = data?.createMuxVideoUploadByFile?.uploadUrl + const videoId = data?.createMuxVideoUploadByFile?.id + setVideoId(videoId) + + if (uploadUrl == null || videoId == null) { + throw new Error('Failed to create upload URL') + } + + const upload = UpChunk.createUpload({ + endpoint: uploadUrl, + file, + chunkSize: 5120 // 5MB + }) + + uploadInstanceRef.current = upload + + upload.on('progress', (progress) => { + setProgress(progress.detail) + }) + + upload.on('success', () => { + uploadInstanceRef.current = null + startPolling(videoId) + }) + + upload.on('error', () => { + setStatus('error') + setError('Upload failed') + onUploadError?.('Upload failed') + }) + } catch (err) { + setStatus('error') + const message = err instanceof Error ? err.message : 'Upload failed' + setError(message) + onUploadError?.(message) + } + }, + [createMuxVideoUploadByFile, startPolling, onUploadError] + ) + + const { getRootProps, getInputProps, open } = useDropzone({ + onDropAccepted: (files) => { + void handleUpload(files[0]) + }, + noDrag: true, + multiple: false, + accept: { 'video/*': [] }, + disabled: status !== 'idle' && status !== 'error' && status !== 'completed' + }) + + // Cleanup on unmount + useEffect(() => { + return () => { + uploadInstanceRef.current?.abort() + if (pollingTimeoutRef.current != null) { + clearTimeout(pollingTimeoutRef.current) + } + } + }, []) + + return { + handleUpload, + cancelUpload, + status, + progress, + error, + videoId, + open, + getInputProps, + getRootProps + } +} diff --git a/apps/journeys-admin/src/components/TemplateList/data.ts b/apps/journeys-admin/src/components/TemplateList/data.ts index a3951b625c4..cc587c85cbf 100644 --- a/apps/journeys-admin/src/components/TemplateList/data.ts +++ b/apps/journeys-admin/src/components/TemplateList/data.ts @@ -22,7 +22,8 @@ const imageBlock: ImageFields = { blurhash: '', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } export const defaultTemplate: Journey = { diff --git a/apps/journeys-admin/src/libs/blockDeleteUpdate/blockDeleteUpdate.spec.ts b/apps/journeys-admin/src/libs/blockDeleteUpdate/blockDeleteUpdate.spec.ts index e2fe889df2b..5b27673ce1e 100644 --- a/apps/journeys-admin/src/libs/blockDeleteUpdate/blockDeleteUpdate.spec.ts +++ b/apps/journeys-admin/src/libs/blockDeleteUpdate/blockDeleteUpdate.spec.ts @@ -39,6 +39,7 @@ const video: TreeBlock = { showGeneratedSubtitles: null, eventLabel: null, endEventLabel: null, + customizable: null, mediaVideo: { __typename: 'Video', id: '2_0-FallingPlates', @@ -79,7 +80,8 @@ const image: TreeBlock = { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const journey: Journey = { diff --git a/apps/journeys-admin/src/libs/findBlocksByTypename/findBlocksByTypename.spec.ts b/apps/journeys-admin/src/libs/findBlocksByTypename/findBlocksByTypename.spec.ts index 26c8f3bc348..2d1bea580e7 100644 --- a/apps/journeys-admin/src/libs/findBlocksByTypename/findBlocksByTypename.spec.ts +++ b/apps/journeys-admin/src/libs/findBlocksByTypename/findBlocksByTypename.spec.ts @@ -57,6 +57,7 @@ const videoBlock: TreeBlock = { posterBlockId: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } @@ -73,7 +74,8 @@ const imageBlock: TreeBlock = { children: [], scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const buttonBlock: TreeBlock = { diff --git a/apps/journeys-admin/src/libs/useJourneyImageBlockCreateMutation/useJourneyImageBlockCreateMutation.mock.tsx b/apps/journeys-admin/src/libs/useJourneyImageBlockCreateMutation/useJourneyImageBlockCreateMutation.mock.tsx index 9a26472b57e..6016060d7bb 100644 --- a/apps/journeys-admin/src/libs/useJourneyImageBlockCreateMutation/useJourneyImageBlockCreateMutation.mock.tsx +++ b/apps/journeys-admin/src/libs/useJourneyImageBlockCreateMutation/useJourneyImageBlockCreateMutation.mock.tsx @@ -30,7 +30,8 @@ export const journeyImageBlockCreateMock: MockedResponse { blurhash: 'LGF5]+Yk^6#M@-5c,1J5@[or[Q6.', scale: 1, focalTop: 0.5, - focalLeft: 0.5 + focalLeft: 0.5, + customizable: null } } })) diff --git a/apps/journeys-admin/src/libs/useJourneyImageBlockUpdateMutation/useJourneyImageBlockUpdateMutation.mock.tsx b/apps/journeys-admin/src/libs/useJourneyImageBlockUpdateMutation/useJourneyImageBlockUpdateMutation.mock.tsx index fc7ddad1819..32b1ea926c9 100644 --- a/apps/journeys-admin/src/libs/useJourneyImageBlockUpdateMutation/useJourneyImageBlockUpdateMutation.mock.tsx +++ b/apps/journeys-admin/src/libs/useJourneyImageBlockUpdateMutation/useJourneyImageBlockUpdateMutation.mock.tsx @@ -31,7 +31,8 @@ export const journeyImageBlockUpdateMock: MockedResponse { blurhash: 'LGF5]+Yk^6#M@-5c,1J5@[or[Q6.', scale: 1.2, focalTop: 0.3, - focalLeft: 0.7 + focalLeft: 0.7, + customizable: null } } })) diff --git a/apps/journeys/__generated__/BlockFields.ts b/apps/journeys/__generated__/BlockFields.ts index 8f3a827873a..8151c9d5a4e 100644 --- a/apps/journeys/__generated__/BlockFields.ts +++ b/apps/journeys/__generated__/BlockFields.ts @@ -153,6 +153,7 @@ export interface BlockFields_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface BlockFields_MultiselectOptionBlock { @@ -550,6 +551,7 @@ export interface BlockFields_VideoBlock { action: BlockFields_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface BlockFields_VideoTriggerBlock_triggerAction_NavigateToBlockAction { diff --git a/apps/journeys/__generated__/GetJourney.ts b/apps/journeys/__generated__/GetJourney.ts index b6b660e62b8..34e9cd8128d 100644 --- a/apps/journeys/__generated__/GetJourney.ts +++ b/apps/journeys/__generated__/GetJourney.ts @@ -167,6 +167,7 @@ export interface GetJourney_journey_blocks_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_blocks_MultiselectOptionBlock { @@ -564,6 +565,7 @@ export interface GetJourney_journey_blocks_VideoBlock { action: GetJourney_journey_blocks_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface GetJourney_journey_blocks_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -645,6 +647,7 @@ export interface GetJourney_journey_primaryImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_creatorImageBlock { @@ -664,6 +667,7 @@ export interface GetJourney_journey_creatorImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_userJourneys_user { @@ -745,6 +749,7 @@ export interface GetJourney_journey_logoImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_menuStepBlock { diff --git a/apps/journeys/__generated__/ImageFields.ts b/apps/journeys/__generated__/ImageFields.ts index cf522fda056..cccc1e6e187 100644 --- a/apps/journeys/__generated__/ImageFields.ts +++ b/apps/journeys/__generated__/ImageFields.ts @@ -24,4 +24,5 @@ export interface ImageFields { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } diff --git a/apps/journeys/__generated__/JourneyFields.ts b/apps/journeys/__generated__/JourneyFields.ts index e4ab828d645..54c883e57b2 100644 --- a/apps/journeys/__generated__/JourneyFields.ts +++ b/apps/journeys/__generated__/JourneyFields.ts @@ -167,6 +167,7 @@ export interface JourneyFields_blocks_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_blocks_MultiselectOptionBlock { @@ -564,6 +565,7 @@ export interface JourneyFields_blocks_VideoBlock { action: JourneyFields_blocks_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface JourneyFields_blocks_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -645,6 +647,7 @@ export interface JourneyFields_primaryImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_creatorImageBlock { @@ -664,6 +667,7 @@ export interface JourneyFields_creatorImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_userJourneys_user { @@ -745,6 +749,7 @@ export interface JourneyFields_logoImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_menuStepBlock { diff --git a/apps/journeys/__generated__/VideoFields.ts b/apps/journeys/__generated__/VideoFields.ts index c842d21b285..ec706b87c34 100644 --- a/apps/journeys/__generated__/VideoFields.ts +++ b/apps/journeys/__generated__/VideoFields.ts @@ -190,4 +190,5 @@ export interface VideoFields { action: VideoFields_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } diff --git a/apps/journeys/pages/404.tsx b/apps/journeys/pages/404.tsx index 3973b3be176..7b95b97e02e 100644 --- a/apps/journeys/pages/404.tsx +++ b/apps/journeys/pages/404.tsx @@ -54,7 +54,8 @@ export function Custom404(): ReactElement { width: 3244, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { __typename: 'TypographyBlock', diff --git a/apps/journeys/pages/500.tsx b/apps/journeys/pages/500.tsx index ba2c9a708b2..f260c754b6b 100644 --- a/apps/journeys/pages/500.tsx +++ b/apps/journeys/pages/500.tsx @@ -55,7 +55,8 @@ export function Custom500(): ReactElement { width: 3244, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { __typename: 'TypographyBlock', diff --git a/apps/journeys/src/components/VideoWrapperPaused/VideoWrapperPaused.spec.tsx b/apps/journeys/src/components/VideoWrapperPaused/VideoWrapperPaused.spec.tsx index ba266f78b34..a58c74ecddd 100644 --- a/apps/journeys/src/components/VideoWrapperPaused/VideoWrapperPaused.spec.tsx +++ b/apps/journeys/src/components/VideoWrapperPaused/VideoWrapperPaused.spec.tsx @@ -43,6 +43,7 @@ describe('VideoWrapper', () => { showGeneratedSubtitles: false, eventLabel: null, endEventLabel: null, + customizable: null, children: [ { id: 'image5.id', @@ -57,7 +58,8 @@ describe('VideoWrapper', () => { blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ] } @@ -84,7 +86,8 @@ describe('VideoWrapper', () => { width: 1920, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ], endAt: null, @@ -108,7 +111,8 @@ describe('VideoWrapper', () => { videoVariantLanguageId: '529', subtitleLanguage: null, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null }, undefined ) @@ -140,6 +144,7 @@ describe('VideoWrapper', () => { showGeneratedSubtitles: false, eventLabel: null, endEventLabel: null, + customizable: null, children: [ { id: 'image5.id', @@ -154,7 +159,8 @@ describe('VideoWrapper', () => { blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ] } @@ -181,7 +187,8 @@ describe('VideoWrapper', () => { width: 1920, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ], endAt: null, @@ -205,7 +212,8 @@ describe('VideoWrapper', () => { videoVariantLanguageId: '529', subtitleLanguage: null, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null }, undefined ) diff --git a/apps/journeys/src/components/WebView/WebView.spec.tsx b/apps/journeys/src/components/WebView/WebView.spec.tsx index bb3a0a00d49..326f8e16603 100644 --- a/apps/journeys/src/components/WebView/WebView.spec.tsx +++ b/apps/journeys/src/components/WebView/WebView.spec.tsx @@ -280,6 +280,7 @@ describe('WebView', () => { subtitleLanguage: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } ] diff --git a/apps/journeys/src/libs/testData/storyData.ts b/apps/journeys/src/libs/testData/storyData.ts index 78874c21bdd..3c3a8d810df 100644 --- a/apps/journeys/src/libs/testData/storyData.ts +++ b/apps/journeys/src/libs/testData/storyData.ts @@ -133,7 +133,8 @@ export const basic: TreeBlock[] = [ blurhash: 'L9AS}j^-0dVC4Tq[=~PATeXSV?aL', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ] } @@ -575,7 +576,8 @@ export const imageBlocks: TreeBlock[] = [ blurhash: 'L9AS}j^-0dVC4Tq[=~PATeXSV?aL', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ] } @@ -674,7 +676,8 @@ export const imageBlocks: TreeBlock[] = [ blurhash: 'LQEf1v^*XkEe*IyD$RnOyXTJRjjG', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ] } @@ -761,7 +764,8 @@ export const imageBlocks: TreeBlock[] = [ blurhash: 'L;KRQa-Rs-kA}ot4bZj@SMR,WWj@', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ] } @@ -863,7 +867,8 @@ export const imageBlocks: TreeBlock[] = [ blurhash: 'L3CZt$_NyX4n=|?b00Ip8_IV00IA', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ] } @@ -904,7 +909,8 @@ export const imageBlocks: TreeBlock[] = [ blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'typographyBlockId1', @@ -1043,6 +1049,7 @@ export const videoBlocks: TreeBlock[] = [ showGeneratedSubtitles: false, eventLabel: null, endEventLabel: null, + customizable: null, children: [ { id: 'trigger.id', @@ -1071,6 +1078,7 @@ export const videoBlocks: TreeBlock[] = [ scale: null, focalLeft: 50, focalTop: 50, + customizable: null, children: [] } ] @@ -1226,6 +1234,7 @@ export const videoBlocks: TreeBlock[] = [ showGeneratedSubtitles: false, eventLabel: null, endEventLabel: null, + customizable: null, children: [ { id: 'posterBlockId', @@ -1240,6 +1249,7 @@ export const videoBlocks: TreeBlock[] = [ scale: null, focalLeft: 50, focalTop: 50, + customizable: null, children: [] } ] @@ -1298,6 +1308,7 @@ export const videoBlocks: TreeBlock[] = [ showGeneratedSubtitles: false, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } ] @@ -1357,6 +1368,7 @@ export const videoBlocksNoPoster: TreeBlock[] = [ showGeneratedSubtitles: false, eventLabel: null, endEventLabel: null, + customizable: null, children: [ { id: 'trigger.id', @@ -1525,6 +1537,7 @@ export const videoBlocksNoPoster: TreeBlock[] = [ showGeneratedSubtitles: false, eventLabel: null, endEventLabel: null, + customizable: null, children: [ { id: 'posterBlockId', @@ -1539,6 +1552,7 @@ export const videoBlocksNoPoster: TreeBlock[] = [ scale: null, focalLeft: 50, focalTop: 50, + customizable: null, children: [] } ] @@ -1597,6 +1611,7 @@ export const videoBlocksNoPoster: TreeBlock[] = [ showGeneratedSubtitles: false, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } ] @@ -1665,6 +1680,7 @@ export const videoBlocksNoVideo: TreeBlock[] = [ showGeneratedSubtitles: false, eventLabel: null, endEventLabel: null, + customizable: null, children: [ { id: 'trigger.id', @@ -1833,6 +1849,7 @@ export const videoBlocksNoVideo: TreeBlock[] = [ showGeneratedSubtitles: false, eventLabel: null, endEventLabel: null, + customizable: null, children: [ { id: 'posterBlockId', @@ -1847,6 +1864,7 @@ export const videoBlocksNoVideo: TreeBlock[] = [ scale: null, focalLeft: 50, focalTop: 50, + customizable: null, children: [] } ] @@ -1905,6 +1923,7 @@ export const videoBlocksNoVideo: TreeBlock[] = [ showGeneratedSubtitles: false, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } ] @@ -2023,6 +2042,7 @@ export const videoLoop: TreeBlock[] = [ showGeneratedSubtitles: false, eventLabel: null, endEventLabel: null, + customizable: null, children: [ { id: 'image1.id', @@ -2037,6 +2057,7 @@ export const videoLoop: TreeBlock[] = [ scale: null, focalLeft: 50, focalTop: 50, + customizable: null, children: [] } ] @@ -2100,6 +2121,7 @@ export const videoLoop: TreeBlock[] = [ showGeneratedSubtitles: false, eventLabel: null, endEventLabel: null, + customizable: null, children: [ { id: 'image1.id', @@ -2114,6 +2136,7 @@ export const videoLoop: TreeBlock[] = [ scale: null, focalLeft: 50, focalTop: 50, + customizable: null, children: [] } ] @@ -2172,6 +2195,7 @@ export const videoLoop: TreeBlock[] = [ showGeneratedSubtitles: false, eventLabel: null, endEventLabel: null, + customizable: null, children: [ { id: 'image1.id', @@ -2186,6 +2210,7 @@ export const videoLoop: TreeBlock[] = [ scale: null, focalLeft: 50, focalTop: 50, + customizable: null, children: [] } ] diff --git a/apps/resources/__generated__/BlockFields.ts b/apps/resources/__generated__/BlockFields.ts index 8f3a827873a..8151c9d5a4e 100644 --- a/apps/resources/__generated__/BlockFields.ts +++ b/apps/resources/__generated__/BlockFields.ts @@ -153,6 +153,7 @@ export interface BlockFields_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface BlockFields_MultiselectOptionBlock { @@ -550,6 +551,7 @@ export interface BlockFields_VideoBlock { action: BlockFields_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface BlockFields_VideoTriggerBlock_triggerAction_NavigateToBlockAction { diff --git a/apps/resources/__generated__/GetJourney.ts b/apps/resources/__generated__/GetJourney.ts index b6b660e62b8..34e9cd8128d 100644 --- a/apps/resources/__generated__/GetJourney.ts +++ b/apps/resources/__generated__/GetJourney.ts @@ -167,6 +167,7 @@ export interface GetJourney_journey_blocks_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_blocks_MultiselectOptionBlock { @@ -564,6 +565,7 @@ export interface GetJourney_journey_blocks_VideoBlock { action: GetJourney_journey_blocks_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface GetJourney_journey_blocks_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -645,6 +647,7 @@ export interface GetJourney_journey_primaryImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_creatorImageBlock { @@ -664,6 +667,7 @@ export interface GetJourney_journey_creatorImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_userJourneys_user { @@ -745,6 +749,7 @@ export interface GetJourney_journey_logoImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_menuStepBlock { diff --git a/apps/resources/__generated__/ImageFields.ts b/apps/resources/__generated__/ImageFields.ts index cf522fda056..cccc1e6e187 100644 --- a/apps/resources/__generated__/ImageFields.ts +++ b/apps/resources/__generated__/ImageFields.ts @@ -24,4 +24,5 @@ export interface ImageFields { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } diff --git a/apps/resources/__generated__/JourneyFields.ts b/apps/resources/__generated__/JourneyFields.ts index e4ab828d645..54c883e57b2 100644 --- a/apps/resources/__generated__/JourneyFields.ts +++ b/apps/resources/__generated__/JourneyFields.ts @@ -167,6 +167,7 @@ export interface JourneyFields_blocks_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_blocks_MultiselectOptionBlock { @@ -564,6 +565,7 @@ export interface JourneyFields_blocks_VideoBlock { action: JourneyFields_blocks_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface JourneyFields_blocks_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -645,6 +647,7 @@ export interface JourneyFields_primaryImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_creatorImageBlock { @@ -664,6 +667,7 @@ export interface JourneyFields_creatorImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_userJourneys_user { @@ -745,6 +749,7 @@ export interface JourneyFields_logoImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_menuStepBlock { diff --git a/apps/resources/__generated__/VideoFields.ts b/apps/resources/__generated__/VideoFields.ts index c842d21b285..ec706b87c34 100644 --- a/apps/resources/__generated__/VideoFields.ts +++ b/apps/resources/__generated__/VideoFields.ts @@ -190,4 +190,5 @@ export interface VideoFields { action: VideoFields_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } diff --git a/apps/watch/__generated__/BlockFields.ts b/apps/watch/__generated__/BlockFields.ts index 8f3a827873a..8151c9d5a4e 100644 --- a/apps/watch/__generated__/BlockFields.ts +++ b/apps/watch/__generated__/BlockFields.ts @@ -153,6 +153,7 @@ export interface BlockFields_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface BlockFields_MultiselectOptionBlock { @@ -550,6 +551,7 @@ export interface BlockFields_VideoBlock { action: BlockFields_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface BlockFields_VideoTriggerBlock_triggerAction_NavigateToBlockAction { diff --git a/apps/watch/__generated__/GetJourney.ts b/apps/watch/__generated__/GetJourney.ts index b6b660e62b8..34e9cd8128d 100644 --- a/apps/watch/__generated__/GetJourney.ts +++ b/apps/watch/__generated__/GetJourney.ts @@ -167,6 +167,7 @@ export interface GetJourney_journey_blocks_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_blocks_MultiselectOptionBlock { @@ -564,6 +565,7 @@ export interface GetJourney_journey_blocks_VideoBlock { action: GetJourney_journey_blocks_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface GetJourney_journey_blocks_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -645,6 +647,7 @@ export interface GetJourney_journey_primaryImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_creatorImageBlock { @@ -664,6 +667,7 @@ export interface GetJourney_journey_creatorImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_userJourneys_user { @@ -745,6 +749,7 @@ export interface GetJourney_journey_logoImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_menuStepBlock { diff --git a/apps/watch/__generated__/ImageFields.ts b/apps/watch/__generated__/ImageFields.ts index cf522fda056..cccc1e6e187 100644 --- a/apps/watch/__generated__/ImageFields.ts +++ b/apps/watch/__generated__/ImageFields.ts @@ -24,4 +24,5 @@ export interface ImageFields { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } diff --git a/apps/watch/__generated__/JourneyFields.ts b/apps/watch/__generated__/JourneyFields.ts index e4ab828d645..54c883e57b2 100644 --- a/apps/watch/__generated__/JourneyFields.ts +++ b/apps/watch/__generated__/JourneyFields.ts @@ -167,6 +167,7 @@ export interface JourneyFields_blocks_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_blocks_MultiselectOptionBlock { @@ -564,6 +565,7 @@ export interface JourneyFields_blocks_VideoBlock { action: JourneyFields_blocks_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface JourneyFields_blocks_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -645,6 +647,7 @@ export interface JourneyFields_primaryImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_creatorImageBlock { @@ -664,6 +667,7 @@ export interface JourneyFields_creatorImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_userJourneys_user { @@ -745,6 +749,7 @@ export interface JourneyFields_logoImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_menuStepBlock { diff --git a/apps/watch/__generated__/VideoFields.ts b/apps/watch/__generated__/VideoFields.ts index c842d21b285..ec706b87c34 100644 --- a/apps/watch/__generated__/VideoFields.ts +++ b/apps/watch/__generated__/VideoFields.ts @@ -190,4 +190,5 @@ export interface VideoFields { action: VideoFields_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } diff --git a/libs/journeys/ui/src/components/BlockRenderer/BlockRenderer.spec.tsx b/libs/journeys/ui/src/components/BlockRenderer/BlockRenderer.spec.tsx index 522561329f0..9e07ff596be 100644 --- a/libs/journeys/ui/src/components/BlockRenderer/BlockRenderer.spec.tsx +++ b/libs/journeys/ui/src/components/BlockRenderer/BlockRenderer.spec.tsx @@ -235,6 +235,7 @@ describe('BlockRenderer', () => { scale: null, focalLeft: 50, focalTop: 50, + customizable: null, children: [] } const { getByRole } = render() @@ -260,6 +261,7 @@ describe('BlockRenderer', () => { scale: null, focalLeft: 50, focalTop: 50, + customizable: null, children: [] } const { getByTestId, getByRole } = render( @@ -824,6 +826,7 @@ describe('BlockRenderer', () => { parentOrder: 0, fullsize: null, action: null, + customizable: null, children: [] } const { getByTestId } = render( @@ -884,6 +887,7 @@ describe('BlockRenderer', () => { fullsize: null, action: null, parentOrder: 0, + customizable: null, children: [] } const { getByTestId } = render( diff --git a/libs/journeys/ui/src/components/Card/Card.mock.ts b/libs/journeys/ui/src/components/Card/Card.mock.ts index 5f524d4d4eb..74228252fb5 100644 --- a/libs/journeys/ui/src/components/Card/Card.mock.ts +++ b/libs/journeys/ui/src/components/Card/Card.mock.ts @@ -188,6 +188,7 @@ export const imageBlock: TreeBlock = { scale: null, focalLeft: 50, focalTop: 50, + customizable: null, children: [] } @@ -233,6 +234,7 @@ export const videoBlock: TreeBlock = { showGeneratedSubtitles: null, eventLabel: null, endEventLabel: null, + customizable: null, mediaVideo: { __typename: 'Video', id: '2_0-FallingPlates', diff --git a/libs/journeys/ui/src/components/Card/Card.stories.tsx b/libs/journeys/ui/src/components/Card/Card.stories.tsx index 05b57b50968..29f747684b0 100644 --- a/libs/journeys/ui/src/components/Card/Card.stories.tsx +++ b/libs/journeys/ui/src/components/Card/Card.stories.tsx @@ -109,7 +109,8 @@ const image: TreeBlock = { blurhash: 'L9AS}j^-0dVC4Tq[=~PATeXSV?aL', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const video: TreeBlock = { @@ -159,6 +160,7 @@ const video: TreeBlock = { }, action: null, fullsize: null, + customizable: null, children: [] } diff --git a/libs/journeys/ui/src/components/Card/ContainedCover/BackgroundVideo/BackgroundVideo.spec.tsx b/libs/journeys/ui/src/components/Card/ContainedCover/BackgroundVideo/BackgroundVideo.spec.tsx index 5bcfa59c801..5d547eaf3cd 100644 --- a/libs/journeys/ui/src/components/Card/ContainedCover/BackgroundVideo/BackgroundVideo.spec.tsx +++ b/libs/journeys/ui/src/components/Card/ContainedCover/BackgroundVideo/BackgroundVideo.spec.tsx @@ -56,6 +56,7 @@ const video: TreeBlock = { variantLanguages: [] }, posterBlockId: null, + customizable: null, children: [] } diff --git a/libs/journeys/ui/src/components/Card/ContainedCover/ContainedCover.spec.tsx b/libs/journeys/ui/src/components/Card/ContainedCover/ContainedCover.spec.tsx index a7c6bd22a58..a4553fd2e79 100644 --- a/libs/journeys/ui/src/components/Card/ContainedCover/ContainedCover.spec.tsx +++ b/libs/journeys/ui/src/components/Card/ContainedCover/ContainedCover.spec.tsx @@ -27,6 +27,7 @@ describe('ContainedCover', () => { scale: null, focalLeft: 50, focalTop: 50, + customizable: null, children: [] } @@ -77,6 +78,7 @@ describe('ContainedCover', () => { }, variantLanguages: [] }, + customizable: null, children: [] } diff --git a/libs/journeys/ui/src/components/Card/ExpandedCover/ExpandedCover.spec.tsx b/libs/journeys/ui/src/components/Card/ExpandedCover/ExpandedCover.spec.tsx index 6f2fdb19ce2..969a40e331b 100644 --- a/libs/journeys/ui/src/components/Card/ExpandedCover/ExpandedCover.spec.tsx +++ b/libs/journeys/ui/src/components/Card/ExpandedCover/ExpandedCover.spec.tsx @@ -24,6 +24,7 @@ describe('ExpandedCover', () => { scale: null, focalLeft: 50, focalTop: 50, + customizable: null, children: [] } diff --git a/libs/journeys/ui/src/components/Card/WebsiteCover/WebsiteCover.spec.tsx b/libs/journeys/ui/src/components/Card/WebsiteCover/WebsiteCover.spec.tsx index e6fda568447..8838f3bf187 100644 --- a/libs/journeys/ui/src/components/Card/WebsiteCover/WebsiteCover.spec.tsx +++ b/libs/journeys/ui/src/components/Card/WebsiteCover/WebsiteCover.spec.tsx @@ -27,6 +27,7 @@ describe('WebsiteCover', () => { scale: null, focalLeft: 50, focalTop: 50, + customizable: null, children: [] } @@ -77,6 +78,7 @@ describe('WebsiteCover', () => { }, variantLanguages: [] }, + customizable: null, children: [] } diff --git a/libs/journeys/ui/src/components/Card/utils/getHeaderElements/getHeaderElements.spec.ts b/libs/journeys/ui/src/components/Card/utils/getHeaderElements/getHeaderElements.spec.ts index 5590ebef278..56fc15b8fa4 100644 --- a/libs/journeys/ui/src/components/Card/utils/getHeaderElements/getHeaderElements.spec.ts +++ b/libs/journeys/ui/src/components/Card/utils/getHeaderElements/getHeaderElements.spec.ts @@ -31,7 +31,8 @@ describe('getHeaderElements', () => { blurhash: 'blurhash', scale: 1, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } } diff --git a/libs/journeys/ui/src/components/CardWrapper/CardWrapper.spec.tsx b/libs/journeys/ui/src/components/CardWrapper/CardWrapper.spec.tsx index 4587aa7fd91..b30b2ded026 100644 --- a/libs/journeys/ui/src/components/CardWrapper/CardWrapper.spec.tsx +++ b/libs/journeys/ui/src/components/CardWrapper/CardWrapper.spec.tsx @@ -55,6 +55,7 @@ describe('CardWrapper', () => { showGeneratedSubtitles: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [ { id: 'image5.id', @@ -69,7 +70,8 @@ describe('CardWrapper', () => { blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ] } @@ -102,7 +104,8 @@ describe('CardWrapper', () => { width: 1920, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ], endAt: null, @@ -126,7 +129,8 @@ describe('CardWrapper', () => { subtitleLanguage: null, showGeneratedSubtitles: null, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null } ], coverBlockId: 'video5.id', @@ -186,6 +190,7 @@ describe('CardWrapper', () => { showGeneratedSubtitles: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [ { id: 'image5.id', @@ -200,7 +205,8 @@ describe('CardWrapper', () => { blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ] } @@ -233,7 +239,8 @@ describe('CardWrapper', () => { width: 1920, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ], endAt: null, @@ -257,7 +264,8 @@ describe('CardWrapper', () => { subtitleLanguage: null, showGeneratedSubtitles: null, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null } ], coverBlockId: 'video5.id', diff --git a/libs/journeys/ui/src/components/FramePortal/FramePortal.stories.tsx b/libs/journeys/ui/src/components/FramePortal/FramePortal.stories.tsx index a5e1cc0229b..daa95be0707 100644 --- a/libs/journeys/ui/src/components/FramePortal/FramePortal.stories.tsx +++ b/libs/journeys/ui/src/components/FramePortal/FramePortal.stories.tsx @@ -63,7 +63,8 @@ const block: TreeBlock = { blurhash: 'L9AS}j^-0dVC4Tq[=~PATeXSV?aL', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'typographyBlockId1', diff --git a/libs/journeys/ui/src/components/Image/Image.spec.tsx b/libs/journeys/ui/src/components/Image/Image.spec.tsx index 9698e5122fc..6015bd8c5e6 100644 --- a/libs/journeys/ui/src/components/Image/Image.spec.tsx +++ b/libs/journeys/ui/src/components/Image/Image.spec.tsx @@ -33,6 +33,7 @@ describe('Image', () => { scale: null, focalLeft: 50, focalTop: 50, + customizable: null, children: [] } diff --git a/libs/journeys/ui/src/components/Image/Image.stories.tsx b/libs/journeys/ui/src/components/Image/Image.stories.tsx index 3f3b50643bc..aa655cfdf0c 100644 --- a/libs/journeys/ui/src/components/Image/Image.stories.tsx +++ b/libs/journeys/ui/src/components/Image/Image.stories.tsx @@ -24,6 +24,7 @@ const emptyImage: Omit, 'src'> = { scale: null, focalLeft: 50, focalTop: 50, + customizable: null, children: [] } diff --git a/libs/journeys/ui/src/components/Image/__generated__/ImageFields.ts b/libs/journeys/ui/src/components/Image/__generated__/ImageFields.ts index cf522fda056..cccc1e6e187 100644 --- a/libs/journeys/ui/src/components/Image/__generated__/ImageFields.ts +++ b/libs/journeys/ui/src/components/Image/__generated__/ImageFields.ts @@ -24,4 +24,5 @@ export interface ImageFields { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } diff --git a/libs/journeys/ui/src/components/Image/imageFields.ts b/libs/journeys/ui/src/components/Image/imageFields.ts index 75b3daed370..e4227049371 100644 --- a/libs/journeys/ui/src/components/Image/imageFields.ts +++ b/libs/journeys/ui/src/components/Image/imageFields.ts @@ -13,5 +13,6 @@ export const IMAGE_FIELDS = gql` scale focalTop focalLeft + customizable } ` diff --git a/libs/journeys/ui/src/components/StepHeader/StepHeader.spec.tsx b/libs/journeys/ui/src/components/StepHeader/StepHeader.spec.tsx index 59068890f83..660c1f4a91b 100644 --- a/libs/journeys/ui/src/components/StepHeader/StepHeader.spec.tsx +++ b/libs/journeys/ui/src/components/StepHeader/StepHeader.spec.tsx @@ -52,7 +52,8 @@ describe('StepHeader', () => { blurhash: 'blurhash', scale: 1, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } } }} diff --git a/libs/journeys/ui/src/components/TemplateView/TemplateFooter/data.ts b/libs/journeys/ui/src/components/TemplateView/TemplateFooter/data.ts index 98576a09207..86f86479e7b 100644 --- a/libs/journeys/ui/src/components/TemplateView/TemplateFooter/data.ts +++ b/libs/journeys/ui/src/components/TemplateView/TemplateFooter/data.ts @@ -49,7 +49,8 @@ export const journey: Journey = { blurhash: 'LXJGyfWCEgs:~VWVofoet,jZ$%oe', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { __typename: 'CardBlock', @@ -109,7 +110,8 @@ export const journey: Journey = { blurhash: 'LXJGyfWCEgs:~VWVofoet,jZ$%oe', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { __typename: 'CardBlock', diff --git a/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview.spec.tsx b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview.spec.tsx index 37c074165a2..9524d635c78 100644 --- a/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview.spec.tsx +++ b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview.spec.tsx @@ -90,4 +90,40 @@ describe('TemplateCardPreview', () => { expect(getAllByTestId('TemplateCardSkeleton')).toHaveLength(7) ) }) + + it('should render navigation buttons when variant is media', async () => { + const steps = [ + { id: '1', children: [{ __typename: 'CardBlock' }] }, + { id: '2', children: [{ __typename: 'CardBlock' }] }, + { id: '3', children: [{ __typename: 'CardBlock' }] } + ] as Array> + + const { getByRole } = render( + + + + ) + expect(getByRole('button', { name: /prev-button/ })).toBeInTheDocument() + expect(getByRole('button', { name: /next-button/ })).toBeInTheDocument() + }) + + it('should not render navigation buttons when variant is preview', async () => { + const steps = [ + { id: '1', children: [{ __typename: 'CardBlock' }] }, + { id: '2', children: [{ __typename: 'CardBlock' }] }, + { id: '3', children: [{ __typename: 'CardBlock' }] } + ] as Array> + + const { queryByRole } = render( + + + + ) + expect( + queryByRole('button', { name: /prev-button/ }) + ).not.toBeInTheDocument() + expect( + queryByRole('button', { name: /next-button/ }) + ).not.toBeInTheDocument() + }) }) diff --git a/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview.tsx b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview.tsx index 6312b6f80b3..864b447b2c1 100644 --- a/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview.tsx +++ b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview.tsx @@ -6,250 +6,263 @@ import Typography from '@mui/material/Typography' import take from 'lodash/take' import { User } from 'next-firebase-auth' import { useTranslation } from 'next-i18next' -import { ReactElement } from 'react' -import { A11y, FreeMode, Mousewheel } from 'swiper/modules' -import { Swiper, SwiperSlide } from 'swiper/react' +import { ReactElement, useEffect, useRef, useState } from 'react' +import { A11y, FreeMode, Mousewheel, Navigation } from 'swiper/modules' +import { Swiper, SwiperClass, SwiperSlide } from 'swiper/react' import { SwiperOptions } from 'swiper/types' +import { NavigationOptions } from 'swiper/types/modules/navigation' -import { ThemeProvider } from '@core/shared/ui/ThemeProvider' - -import { ThemeMode, ThemeName } from '../../../../../__generated__/globalTypes' import { TreeBlock } from '../../../../libs/block' -import { useJourney } from '../../../../libs/JourneyProvider' -import { getJourneyRTL } from '../../../../libs/rtl' -import { - GetJourney_journey_blocks_CardBlock as CardBlock, - GetJourney_journey_blocks_StepBlock as StepBlock -} from '../../../../libs/useJourneyQuery/__generated__/GetJourney' -import { BlockRenderer } from '../../../BlockRenderer' -import { CardWrapper } from '../../../CardWrapper' -import { FramePortal } from '../../../FramePortal' -import { VideoWrapper } from '../../../VideoWrapper' +import { GetJourney_journey_blocks_StepBlock as StepBlock } from '../../../../libs/useJourneyQuery/__generated__/GetJourney' +import { NavButton } from '../../../ContentCarousel/NavButton' import { TemplateActionButton } from '../../TemplateViewHeader/TemplateActionButton/TemplateActionButton' +import { + SELECTED_SCALE, + type TemplateCardPreviewVariant, + VARIANT_CONFIGS +} from './templateCardPreviewConfig' +import { TemplateCardPreviewItem } from './TemplateCardPreviewItem/TemplateCardPreviewItem' + interface TemplateCardPreviewProps { steps?: Array> authUser?: User -} - -interface TemplateCardPreviewItemProps { - step: TreeBlock + variant?: TemplateCardPreviewVariant + onClick?: (step: TreeBlock) => void + selectedStep?: TreeBlock | null } const StyledSwiperSlide = styled(SwiperSlide)(() => ({})) const StyledSwiper = styled(Swiper)(() => ({})) -function TemplateCardPreviewItem({ - step -}: TemplateCardPreviewItemProps): ReactElement { - const { journey } = useJourney() - const { rtl, locale } = getJourneyRTL(journey) - const cardBlock = step.children.find( - (child) => child.__typename === 'CardBlock' - ) as TreeBlock - - return ( - - - - - - - - - - - - - ) -} - +/** + * Horizontal carousel of template step cards with optional navigation and "more cards" slide. + * + * TemplateCardPreview has two variants: + * + * 'preview': Renders the first 7 steps plus a “use this template” call-to-action. Used on the /templates page. + * + * 'media': Renders the full list of customizable media steps with selection state. Used in the template customization flow. + * + * @param props - Component props + * @param props.steps - Journey step blocks to display as cards + * @param props.authUser - Authenticated user for CTA sign-in state + * @param props.variant - 'preview' | 'media'; controls layout and behaviour + * @param props.onClick - Handler when a card is clicked + * @param props.selectedStep - Selected step (media variant) + * @returns Carousel UI or skeleton placeholder when steps are loading + */ export function TemplateCardPreview({ steps, - authUser + authUser, + variant = 'preview', + onClick, + selectedStep }: TemplateCardPreviewProps): ReactElement { const { breakpoints } = useTheme() const { t } = useTranslation('libs-journeys-ui') + const [swiper, setSwiper] = useState() + const [hovered, setHovered] = useState(false) + const nextRef = useRef(null) + const prevRef = useRef(null) + + const config = VARIANT_CONFIGS[variant] + const { + cardWidth, + cardHeight, + swiperHeight, + showMoreCardsSlide, + showNavigation, + swiperProps, + slideSx, + swiperSx, + modules + } = config + const swiperBreakpoints: SwiperOptions['breakpoints'] = { [breakpoints.values.xs]: { spaceBetween: 12 }, [breakpoints.values.sm]: { - spaceBetween: 28 + spaceBetween: variant === 'preview' ? 28 : 12 } } - const slidesToRender: Array> | undefined = take(steps, 7) + const slidesToRender: Array> | undefined = + variant === 'media' ? steps : take(steps, 7) + + useEffect(() => { + if (swiper != null && showNavigation) { + const navigation = swiper.params.navigation as NavigationOptions + navigation.nextEl = nextRef.current + navigation.prevEl = prevRef.current + swiper.navigation.destroy() + swiper.navigation.init() + swiper.navigation.update() + } + }, [swiper, showNavigation]) - return steps != null ? ( + const swiperContent = ( - {slidesToRender.map((step) => { + {slidesToRender?.map((step) => { + const isSelected = selectedStep?.id === step.id + const selectedSlideSx = + variant === 'media' && isSelected + ? { + width: { + xs: cardWidth.xs * SELECTED_SCALE, + sm: cardWidth.sm * SELECTED_SCALE + }, + height: { + xs: cardHeight.xs * SELECTED_SCALE, + sm: cardHeight.sm * SELECTED_SCALE + } + } + : {} return ( - + ) })} - {steps.length > slidesToRender.length && ( - - (slidesToRender?.length ?? 0) && ( + - - {t('{{count}} more cards', { - count: steps.length - slidesToRender.length - })} - - - {t('Use this template to see more!')} - - - - - - - )} + + {t('{{count}} more cards', { + count: steps.length - (slidesToRender?.length ?? 0) + })} + + + {t('Use this template to see more!')} + + + + + + + )} - ) : ( - - {[0, 1, 2, 3, 4, 5, 6].map((value) => { - return ( + ) + + if (steps == null) { + return ( + + {[0, 1, 2, 3, 4, 5, 6].map((value) => ( - ) - })} - - ) + ))} + + ) + } + + if (showNavigation) { + return ( + setHovered(true)} + onMouseLeave={() => setHovered(false)} + > + {swiperContent} + + + + ) + } + + return swiperContent } diff --git a/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreviewItem/TemplateCardPreviewItem.spec.tsx b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreviewItem/TemplateCardPreviewItem.spec.tsx new file mode 100644 index 00000000000..ebb868e1bc6 --- /dev/null +++ b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreviewItem/TemplateCardPreviewItem.spec.tsx @@ -0,0 +1,100 @@ +import { ThemeProvider, createTheme } from '@mui/material/styles' +import { fireEvent, render } from '@testing-library/react' +import { ReactElement } from 'react' + +import { + ThemeMode, + ThemeName +} from '../../../../../../__generated__/globalTypes' +import { TreeBlock } from '../../../../../libs/block' +import { JourneyProvider } from '../../../../../libs/JourneyProvider' +import { journey } from '../../../../../libs/JourneyProvider/JourneyProvider.mock' +import { GetJourney_journey_blocks_StepBlock as StepBlock } from '../../../../../libs/useJourneyQuery/__generated__/GetJourney' + +import { TemplateCardPreviewItem } from './TemplateCardPreviewItem' + +function renderWithProviders(children: ReactElement) { + return render( + + {children} + + ) +} + +describe('TemplateCardPreviewItem', () => { + const step = { + __typename: 'StepBlock', + id: 'step1', + parentBlockId: null, + parentOrder: 0, + locked: false, + nextBlockId: null, + slug: null, + children: [ + { + __typename: 'CardBlock', + id: 'card1', + parentBlockId: 'step1', + parentOrder: 0, + backgroundColor: null, + backdropBlur: null, + coverBlockId: null, + themeMode: ThemeMode.dark, + themeName: ThemeName.base, + fullscreen: false, + eventLabel: null, + children: [] + } + ] + } as TreeBlock + + it('should render preview variant', () => { + const { getByTestId } = renderWithProviders( + + ) + expect(getByTestId('TemplateCardPreviewItem')).toBeInTheDocument() + }) + + it('should render media variant', () => { + const { getByTestId } = renderWithProviders( + + ) + expect(getByTestId('TemplateCardPreviewItem')).toBeInTheDocument() + }) + + it('should call onClick with step when clicked', () => { + const handleClick = jest.fn() + const { getByTestId } = renderWithProviders( + + ) + fireEvent.click(getByTestId('TemplateCardPreviewItem')) + expect(handleClick).toHaveBeenCalledTimes(1) + expect(handleClick).toHaveBeenCalledWith(step) + }) + + it('should render when selectedStep matches step id', () => { + const { getByTestId } = renderWithProviders( + + ) + expect(getByTestId('TemplateCardPreviewItem')).toBeInTheDocument() + }) + + it('should render when selectedStep is null', () => { + const { getByTestId } = renderWithProviders( + + ) + expect(getByTestId('TemplateCardPreviewItem')).toBeInTheDocument() + }) +}) diff --git a/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreviewItem/TemplateCardPreviewItem.tsx b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreviewItem/TemplateCardPreviewItem.tsx new file mode 100644 index 00000000000..fe8ec5f263d --- /dev/null +++ b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreviewItem/TemplateCardPreviewItem.tsx @@ -0,0 +1,137 @@ +import Box from '@mui/material/Box' +import { ReactElement } from 'react' + +import { ThemeProvider } from '@core/shared/ui/ThemeProvider' + +import { + ThemeMode, + ThemeName +} from '../../../../../../__generated__/globalTypes' +import { TreeBlock } from '../../../../../libs/block' +import { useJourney } from '../../../../../libs/JourneyProvider' +import { getJourneyRTL } from '../../../../../libs/rtl' +import { + GetJourney_journey_blocks_CardBlock as CardBlock, + GetJourney_journey_blocks_StepBlock as StepBlock +} from '../../../../../libs/useJourneyQuery/__generated__/GetJourney' +import { BlockRenderer } from '../../../../BlockRenderer' +import { CardWrapper } from '../../../../CardWrapper' +import { FramePortal } from '../../../../FramePortal' +import { VideoWrapper } from '../../../../VideoWrapper' +import { + SELECTED_SCALE, + type TemplateCardPreviewVariant, + VARIANT_CONFIGS +} from '../templateCardPreviewConfig' + +export interface TemplateCardPreviewItemProps { + step: TreeBlock + variant: TemplateCardPreviewVariant + onClick?: (step: TreeBlock) => void + selectedStep?: TreeBlock | null +} + +/** + * Renders a single template step as a preview card inside a FramePortal. + * Applies variant-based sizing, optional selection scale, and theme/RTL from the journey. + * Invokes onClick when the card is clicked. + * + * @returns A clickable card box containing the step content in a scaled frame. + */ +export function TemplateCardPreviewItem({ + step, + variant, + onClick, + selectedStep +}: TemplateCardPreviewItemProps): ReactElement { + const { journey } = useJourney() + const { rtl, locale } = getJourneyRTL(journey) + const cardBlock = step.children.find( + (child) => child.__typename === 'CardBlock' + ) as TreeBlock + + const config = VARIANT_CONFIGS[variant] + const { cardWidth, cardHeight, framePortal, cardSx } = config + const isSelected = selectedStep?.id === step.id + + return ( + onClick?.(step)} + data-testid="TemplateCardPreviewItem" + > + + + + + + + + + + + + ) +} diff --git a/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreviewItem/index.ts b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreviewItem/index.ts new file mode 100644 index 00000000000..bf2b9a6ab15 --- /dev/null +++ b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreviewItem/index.ts @@ -0,0 +1 @@ +export { TemplateCardPreviewItem } from './TemplateCardPreviewItem' diff --git a/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/index.ts b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/index.ts index b646832b366..be44333288c 100644 --- a/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/index.ts +++ b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/index.ts @@ -1 +1,5 @@ export { TemplateCardPreview } from './TemplateCardPreview' +export { + TemplateCardPreviewItem, + type TemplateCardPreviewItemProps +} from './TemplateCardPreviewItem/TemplateCardPreviewItem' diff --git a/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/templateCardPreviewConfig.ts b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/templateCardPreviewConfig.ts new file mode 100644 index 00000000000..299e162e967 --- /dev/null +++ b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/templateCardPreviewConfig.ts @@ -0,0 +1,118 @@ +import type { SxProps, Theme } from '@mui/material/styles' +import { A11y, FreeMode, Mousewheel, Navigation } from 'swiper/modules' +import type { SwiperModule, SwiperOptions } from 'swiper/types' + +export type TemplateCardPreviewVariant = 'preview' | 'media' + +interface FramePortalConfig { + width: { xs: number; sm: number } + height: { xs: number; sm: number } + transform: { xs: string; sm: string } + borderRadius?: number +} + +export interface VariantConfig { + cardWidth: { xs: number; sm: number } + cardHeight: { xs: number; sm: number } + swiperHeight: { xs: number; sm: number } + showMoreCardsSlide: boolean + showNavigation: boolean + framePortal: FramePortalConfig + swiperProps?: Partial + cardSx: SxProps + slideSx: SxProps + swiperSx: SxProps + modules?: SwiperModule[] +} + +export const SELECTED_SCALE = 1.07 + +const PREVIEW_VARIANT_CONFIG: VariantConfig = { + cardWidth: { xs: 194, sm: 267 }, + cardHeight: { xs: 295, sm: 404 }, + swiperHeight: { xs: 295, sm: 404 }, + showMoreCardsSlide: true, + showNavigation: false, + framePortal: { + width: { xs: 485, sm: 445 }, + height: { xs: 738, sm: 673 }, + transform: { xs: 'scale(0.4)', sm: 'scale(0.6)' } + }, + cardSx: { + position: 'relative', + backgroundColor: 'background.default', + borderRadius: 3 + }, + slideSx: { + zIndex: 2, + mr: { xs: 3, sm: 7 }, + width: 'unset !important' + }, + swiperSx: { + overflow: 'visible', + zIndex: 2 + }, + swiperProps: { + mousewheel: { forceToAxis: true }, + freeMode: true, + watchOverflow: true, + slidesPerView: 'auto', + spaceBetween: 12, + observer: true, + observeParents: true + }, + modules: [Mousewheel, FreeMode, A11y] +} + +const MEDIA_VARIANT_CONFIG: VariantConfig = { + cardWidth: { xs: 120, sm: 120 }, + cardHeight: { xs: 209, sm: 209 }, + swiperHeight: { xs: 209 * SELECTED_SCALE, sm: 209 * SELECTED_SCALE }, + showMoreCardsSlide: false, + showNavigation: true, + framePortal: { + width: { xs: 300, sm: 300 }, + height: { xs: 523, sm: 523 }, + transform: { xs: 'scale(0.4)', sm: 'scale(0.4)' }, + borderRadius: 12 + }, + swiperProps: { + mousewheel: { forceToAxis: true }, + freeMode: true, + watchOverflow: true, + slidesPerView: 'auto', + spaceBetween: 12, + observer: true, + observeParents: true, + allowTouchMove: true + }, + cardSx: { + position: 'relative', + backgroundColor: 'background.default', + borderRadius: 3 + }, + slideSx: { + height: 209, + width: 120, + flexShrink: 0, + display: 'flex', + alignItems: 'center', + justifyContent: 'center' + }, + swiperSx: { + overflow: 'hidden', + zIndex: 2, + '& .swiper-wrapper': { + alignItems: 'center' + } + }, + modules: [Mousewheel, FreeMode, A11y, Navigation] +} + +export const VARIANT_CONFIGS: Record< + TemplateCardPreviewVariant, + VariantConfig +> = { + preview: PREVIEW_VARIANT_CONFIG, + media: MEDIA_VARIANT_CONFIG +} diff --git a/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/data.ts b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/data.ts index 52538ddb59c..4131ba22c7c 100644 --- a/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/data.ts +++ b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/data.ts @@ -61,7 +61,8 @@ export const journeyVideoBlocks: Blocks[] = [ }, action: null, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null }, { __typename: 'VideoBlock', @@ -109,7 +110,8 @@ export const journeyVideoBlocks: Blocks[] = [ }, action: null, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null }, { __typename: 'VideoBlock', @@ -157,7 +159,8 @@ export const journeyVideoBlocks: Blocks[] = [ }, action: null, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null }, { __typename: 'VideoBlock', @@ -184,7 +187,8 @@ export const journeyVideoBlocks: Blocks[] = [ mediaVideo: null, action: null, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null }, { __typename: 'CardBlock', @@ -254,7 +258,8 @@ export const journeyVideoBlocks: Blocks[] = [ variantLanguages: [] }, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null }, { __typename: 'CardBlock', @@ -366,7 +371,8 @@ export const videoBlocksFiltered = [ gtmEventName: 'NavigateToBlockAction' }, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null }, { __typename: 'VideoBlock', @@ -415,7 +421,8 @@ export const videoBlocksFiltered = [ gtmEventName: 'NavigateToBlockAction' }, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null }, { __typename: 'VideoBlock', @@ -449,7 +456,8 @@ export const videoBlocksFiltered = [ gtmEventName: 'NavigateToBlockAction' }, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null }, { __typename: 'VideoBlock', @@ -500,7 +508,8 @@ export const videoBlocksFiltered = [ gtmEventName: 'NavigateToBlockAction' }, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null }, { __typename: 'VideoBlock', @@ -551,7 +560,8 @@ export const videoBlocksFiltered = [ gtmEventName: 'NavigateToBlockAction' }, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null }, { __typename: 'VideoBlock', diff --git a/libs/journeys/ui/src/components/TemplateView/TemplateView.spec.tsx b/libs/journeys/ui/src/components/TemplateView/TemplateView.spec.tsx index 470a47efa8d..f5bf0f227af 100644 --- a/libs/journeys/ui/src/components/TemplateView/TemplateView.spec.tsx +++ b/libs/journeys/ui/src/components/TemplateView/TemplateView.spec.tsx @@ -150,7 +150,8 @@ describe('TemplateView', () => { __typename: 'ImageBlock', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } } const { getAllByText, getAllByRole } = render( @@ -197,7 +198,8 @@ describe('TemplateView', () => { __typename: 'ImageBlock', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } } const { queryAllByText, queryAllByRole } = render( diff --git a/libs/journeys/ui/src/components/TemplateView/TemplateView.stories.tsx b/libs/journeys/ui/src/components/TemplateView/TemplateView.stories.tsx index 860cfbb496c..960890c431f 100644 --- a/libs/journeys/ui/src/components/TemplateView/TemplateView.stories.tsx +++ b/libs/journeys/ui/src/components/TemplateView/TemplateView.stories.tsx @@ -83,7 +83,8 @@ const primaryImageBlock: PrimaryImageBlock = { parentOrder: 1, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } const getJourneysMockEmpty: MockedResponse = { diff --git a/libs/journeys/ui/src/components/TemplateView/TemplateViewHeader/SocialImage/SocialImage.spec.tsx b/libs/journeys/ui/src/components/TemplateView/TemplateViewHeader/SocialImage/SocialImage.spec.tsx index 67c26313ed6..4acee1333de 100644 --- a/libs/journeys/ui/src/components/TemplateView/TemplateViewHeader/SocialImage/SocialImage.spec.tsx +++ b/libs/journeys/ui/src/components/TemplateView/TemplateViewHeader/SocialImage/SocialImage.spec.tsx @@ -24,7 +24,8 @@ describe('SocialImage', () => { blurhash: 'L9AS}j^-0dVC4Tq[=~PATeXSV?aL', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } }, variant: 'admin' diff --git a/libs/journeys/ui/src/components/TemplateView/TemplateViewHeader/TemplateViewHeader.spec.tsx b/libs/journeys/ui/src/components/TemplateView/TemplateViewHeader/TemplateViewHeader.spec.tsx index 18c771c2755..07523e29666 100644 --- a/libs/journeys/ui/src/components/TemplateView/TemplateViewHeader/TemplateViewHeader.spec.tsx +++ b/libs/journeys/ui/src/components/TemplateView/TemplateViewHeader/TemplateViewHeader.spec.tsx @@ -98,7 +98,8 @@ describe('TemplateViewHeader', () => { __typename: 'ImageBlock', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } } const { getByText, getByRole } = render( @@ -145,7 +146,8 @@ describe('TemplateViewHeader', () => { __typename: 'ImageBlock', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } } const { queryByText, queryByRole } = render( diff --git a/libs/journeys/ui/src/components/TemplateView/data.ts b/libs/journeys/ui/src/components/TemplateView/data.ts index 0e1b0707988..27f41eeebc3 100644 --- a/libs/journeys/ui/src/components/TemplateView/data.ts +++ b/libs/journeys/ui/src/components/TemplateView/data.ts @@ -164,7 +164,8 @@ export const publishedJourney: Journey = { blurhash: 'L9AS}j^-0dVC4Tq[=~PATeXSV?aL', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'typographyBlockId1', @@ -375,7 +376,8 @@ export const blocks: Block[] = [ action: null, posterBlockId: 'image0.id', eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null }, { id: 'image0.id', @@ -389,7 +391,8 @@ export const blocks: Block[] = [ blurhash: 'L9AS}j^-0dVC4Tq[=~PATeXSV?aL', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'step1.id', @@ -483,7 +486,8 @@ export const blocks: Block[] = [ blurhash: 'LQEf1v^*XkEe*IyD$RnOyXTJRjjG', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { @@ -600,7 +604,8 @@ export const blocks: Block[] = [ blurhash: 'L;KRQa-Rs-kA}ot4bZj@SMR,WWj@', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'step3.id', @@ -701,7 +706,8 @@ export const blocks: Block[] = [ blurhash: 'L3CZt$_NyX4n=|?b00Ip8_IV00IA', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'step4.id', @@ -758,7 +764,8 @@ export const blocks: Block[] = [ action: null, posterBlockId: 'posterBlockId', eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null }, { id: 'posterBlockId', @@ -772,7 +779,8 @@ export const blocks: Block[] = [ parentOrder: 0, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'step5.id', @@ -808,7 +816,8 @@ export const blocks: Block[] = [ blurhash: 'L9AS}j^-0dVC4Tq[=~PATeXSV?aL', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { __typename: 'SignUpBlock', @@ -862,7 +871,8 @@ export const blocks: Block[] = [ blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null }, { id: 'typographyBlockId11', diff --git a/libs/journeys/ui/src/components/Video/Video.spec.tsx b/libs/journeys/ui/src/components/Video/Video.spec.tsx index e945e18b9cd..f29cc5edea7 100644 --- a/libs/journeys/ui/src/components/Video/Video.spec.tsx +++ b/libs/journeys/ui/src/components/Video/Video.spec.tsx @@ -62,6 +62,7 @@ const block: TreeBlock = { }, variantLanguages: [] }, + customizable: null, children: [ { id: 'posterBlockId', @@ -76,6 +77,7 @@ const block: TreeBlock = { scale: null, focalLeft: 50, focalTop: 50, + customizable: null, children: [] } ] diff --git a/libs/journeys/ui/src/components/Video/Video.stories.tsx b/libs/journeys/ui/src/components/Video/Video.stories.tsx index f20bbb0c669..04d89e31cc2 100644 --- a/libs/journeys/ui/src/components/Video/Video.stories.tsx +++ b/libs/journeys/ui/src/components/Video/Video.stories.tsx @@ -45,6 +45,7 @@ const emptyVideo: Omit, 'source'> = { showGeneratedSubtitles: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [] } diff --git a/libs/journeys/ui/src/components/Video/__generated__/VideoFields.ts b/libs/journeys/ui/src/components/Video/__generated__/VideoFields.ts index c086e1064a7..cabf645cfca 100644 --- a/libs/journeys/ui/src/components/Video/__generated__/VideoFields.ts +++ b/libs/journeys/ui/src/components/Video/__generated__/VideoFields.ts @@ -190,4 +190,5 @@ export interface VideoFields { action: VideoFields_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } diff --git a/libs/journeys/ui/src/components/Video/videoFields.ts b/libs/journeys/ui/src/components/Video/videoFields.ts index 1ea867eed41..285e1aa3a49 100644 --- a/libs/journeys/ui/src/components/Video/videoFields.ts +++ b/libs/journeys/ui/src/components/Video/videoFields.ts @@ -62,5 +62,6 @@ export const VIDEO_FIELDS = gql` } eventLabel endEventLabel + customizable } ` diff --git a/libs/journeys/ui/src/components/VideoWrapper/VideoWrapper.spec.tsx b/libs/journeys/ui/src/components/VideoWrapper/VideoWrapper.spec.tsx index c5f70ffccf5..1181808f9f1 100644 --- a/libs/journeys/ui/src/components/VideoWrapper/VideoWrapper.spec.tsx +++ b/libs/journeys/ui/src/components/VideoWrapper/VideoWrapper.spec.tsx @@ -38,6 +38,7 @@ describe('VideoWrapper', () => { showGeneratedSubtitles: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [ { id: 'image5.id', @@ -52,7 +53,8 @@ describe('VideoWrapper', () => { blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ] } @@ -79,7 +81,8 @@ describe('VideoWrapper', () => { width: 1920, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ], endAt: null, @@ -103,7 +106,8 @@ describe('VideoWrapper', () => { subtitleLanguage: null, showGeneratedSubtitles: null, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null }, undefined ) @@ -135,6 +139,7 @@ describe('VideoWrapper', () => { showGeneratedSubtitles: null, eventLabel: null, endEventLabel: null, + customizable: null, children: [ { id: 'image5.id', @@ -149,7 +154,8 @@ describe('VideoWrapper', () => { blurhash: 'LFALX]%g4Tf+?^jEMxo#00Mx%gjZ', scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ] } @@ -176,7 +182,8 @@ describe('VideoWrapper', () => { width: 1920, scale: null, focalLeft: 50, - focalTop: 50 + focalTop: 50, + customizable: null } ], endAt: null, @@ -200,7 +207,8 @@ describe('VideoWrapper', () => { subtitleLanguage: null, showGeneratedSubtitles: null, eventLabel: null, - endEventLabel: null + endEventLabel: null, + customizable: null }, undefined ) diff --git a/libs/journeys/ui/src/libs/JourneyProvider/__generated__/JourneyFields.ts b/libs/journeys/ui/src/libs/JourneyProvider/__generated__/JourneyFields.ts index 6567c2dd2c3..6ebdc79c358 100644 --- a/libs/journeys/ui/src/libs/JourneyProvider/__generated__/JourneyFields.ts +++ b/libs/journeys/ui/src/libs/JourneyProvider/__generated__/JourneyFields.ts @@ -167,6 +167,7 @@ export interface JourneyFields_blocks_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_blocks_MultiselectOptionBlock { @@ -564,6 +565,7 @@ export interface JourneyFields_blocks_VideoBlock { action: JourneyFields_blocks_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface JourneyFields_blocks_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -645,6 +647,7 @@ export interface JourneyFields_primaryImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_creatorImageBlock { @@ -664,6 +667,7 @@ export interface JourneyFields_creatorImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_userJourneys_user { @@ -745,6 +749,7 @@ export interface JourneyFields_logoImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface JourneyFields_menuStepBlock { diff --git a/libs/journeys/ui/src/libs/block/__generated__/BlockFields.ts b/libs/journeys/ui/src/libs/block/__generated__/BlockFields.ts index bc9f7b3273c..cac27c0e8c3 100644 --- a/libs/journeys/ui/src/libs/block/__generated__/BlockFields.ts +++ b/libs/journeys/ui/src/libs/block/__generated__/BlockFields.ts @@ -153,6 +153,7 @@ export interface BlockFields_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface BlockFields_MultiselectOptionBlock { @@ -550,6 +551,7 @@ export interface BlockFields_VideoBlock { action: BlockFields_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface BlockFields_VideoTriggerBlock_triggerAction_NavigateToBlockAction { diff --git a/libs/journeys/ui/src/libs/filterActionBlocks/filterActionBlocks.spec.ts b/libs/journeys/ui/src/libs/filterActionBlocks/filterActionBlocks.spec.ts index 5bc541f9c82..592f702171b 100644 --- a/libs/journeys/ui/src/libs/filterActionBlocks/filterActionBlocks.spec.ts +++ b/libs/journeys/ui/src/libs/filterActionBlocks/filterActionBlocks.spec.ts @@ -84,6 +84,7 @@ const image: TreeBlock = { scale: null, focalLeft: 50, focalTop: 50, + customizable: null, children: [] } diff --git a/libs/journeys/ui/src/libs/useJourneyQuery/__generated__/GetJourney.ts b/libs/journeys/ui/src/libs/useJourneyQuery/__generated__/GetJourney.ts index 7ed6ccdd69b..6197514fcd7 100644 --- a/libs/journeys/ui/src/libs/useJourneyQuery/__generated__/GetJourney.ts +++ b/libs/journeys/ui/src/libs/useJourneyQuery/__generated__/GetJourney.ts @@ -167,6 +167,7 @@ export interface GetJourney_journey_blocks_ImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_blocks_MultiselectOptionBlock { @@ -564,6 +565,7 @@ export interface GetJourney_journey_blocks_VideoBlock { action: GetJourney_journey_blocks_VideoBlock_action | null; eventLabel: BlockEventLabel | null; endEventLabel: BlockEventLabel | null; + customizable: boolean | null; } export interface GetJourney_journey_blocks_VideoTriggerBlock_triggerAction_NavigateToBlockAction { @@ -645,6 +647,7 @@ export interface GetJourney_journey_primaryImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_creatorImageBlock { @@ -664,6 +667,7 @@ export interface GetJourney_journey_creatorImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_userJourneys_user { @@ -745,6 +749,7 @@ export interface GetJourney_journey_logoImageBlock { scale: number | null; focalTop: number | null; focalLeft: number | null; + customizable: boolean | null; } export interface GetJourney_journey_menuStepBlock { diff --git a/libs/locales/en/apps-journeys-admin.json b/libs/locales/en/apps-journeys-admin.json index 6ed31a068ad..94c5e3cb932 100644 --- a/libs/locales/en/apps-journeys-admin.json +++ b/libs/locales/en/apps-journeys-admin.json @@ -336,12 +336,12 @@ "On Video End": "On Video End", "Video Source": "Video Source", "Navigate to:": "Navigate to:", + "Toggle customizable": "Toggle customizable", + "Needs Customization": "Needs Customization", "Invalid URL": "Invalid URL", "Start a chat with the provided URL.": "Start a chat with the provided URL.", "Paste chat URL here...": "Paste chat URL here...", "e.g. WhatsApp, Messenger, Telegram": "e.g. WhatsApp, Messenger, Telegram", - "Toggle customizable": "Toggle customizable", - "Needs Customization": "Needs Customization", "Invalid Email": "Invalid Email", "Email must be a valid email": "Email must be a valid email", "Open client with the provided email in the to field.": "Open client with the provided email in the to field.", @@ -1017,6 +1017,9 @@ "Enter a valid URL": "Enter a valid URL", "Next": "Next", "Replace the links": "Replace the links", + "Media": "Media", + "Cards": "Cards", + "Images": "Images", "Almost There!": "Almost There!", "Here’s how your invitation will appear when shared on social media. You can update it if you’d like.": "Here’s how your invitation will appear when shared on social media. You can update it if you’d like.", "Failed to update social image, please try again later": "Failed to update social image, please try again later",