@capillarytech/creatives-library 8.0.242-alpha.0 → 8.0.242-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/Android.png +0 -0
- package/assets/iOS.png +0 -0
- package/constants/unified.js +2 -1
- package/initialReducer.js +2 -0
- package/package.json +1 -1
- package/sagas/__tests__/assetPolling.test.js +74 -3
- package/sagas/assetPolling.js +8 -1
- package/services/api.js +10 -5
- package/services/tests/api.test.js +18 -0
- package/translations/en.json +0 -1
- package/utils/common.js +5 -0
- package/utils/commonUtils.js +14 -1
- package/utils/tests/commonUtil.test.js +224 -0
- package/utils/transformTemplateConfig.js +0 -10
- package/utils/transformerUtils.js +0 -42
- package/v2Components/CapDeviceContent/index.js +61 -56
- package/v2Components/CapImageUpload/constants.js +0 -2
- package/v2Components/CapImageUpload/index.js +14 -54
- package/v2Components/CapImageUpload/index.scss +1 -4
- package/v2Components/CapImageUpload/messages.js +0 -4
- package/v2Components/CapTagList/index.js +6 -1
- package/v2Components/CapTagListWithInput/index.js +5 -1
- package/v2Components/CapTagListWithInput/messages.js +1 -1
- package/v2Components/CapWhatsappCTA/tests/index.test.js +5 -0
- package/v2Components/ErrorInfoNote/index.js +412 -72
- package/v2Components/ErrorInfoNote/messages.js +22 -0
- package/v2Components/ErrorInfoNote/style.scss +279 -2
- package/v2Components/HtmlEditor/HTMLEditor.js +217 -90
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +1132 -133
- package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +17 -12
- package/v2Components/HtmlEditor/_htmlEditor.scss +15 -23
- package/v2Components/HtmlEditor/_index.lazy.scss +1 -1
- package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +13 -101
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +148 -139
- package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +2 -1
- package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
- package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +1 -0
- package/v2Components/HtmlEditor/components/EditorToolbar/index.js +1 -1
- package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +1 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +4 -7
- package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +35 -45
- package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +1 -3
- package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
- package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +7 -6
- package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +3 -6
- package/v2Components/HtmlEditor/components/PreviewPane/index.js +10 -11
- package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +87 -62
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +49 -31
- package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +254 -0
- package/v2Components/HtmlEditor/components/ValidationTabs/index.js +362 -0
- package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +51 -0
- package/v2Components/HtmlEditor/constants.js +29 -20
- package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +373 -16
- package/v2Components/HtmlEditor/hooks/useEditorContent.js +5 -2
- package/v2Components/HtmlEditor/hooks/useInAppContent.js +88 -146
- package/v2Components/HtmlEditor/index.js +1 -1
- package/v2Components/HtmlEditor/messages.js +95 -85
- package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +99 -101
- package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +23 -25
- package/v2Components/HtmlEditor/utils/validationAdapter.js +34 -41
- package/v2Components/MobilePushPreviewV2/index.js +32 -7
- package/v2Components/TemplatePreview/_templatePreview.scss +44 -24
- package/v2Components/TemplatePreview/index.js +47 -32
- package/v2Components/TemplatePreview/messages.js +4 -0
- package/v2Components/TestAndPreviewSlidebox/index.js +31 -25
- package/v2Containers/App/constants.js +0 -5
- package/v2Containers/BeeEditor/index.js +82 -80
- package/v2Containers/BeePopupEditor/constants.js +10 -0
- package/v2Containers/BeePopupEditor/index.js +193 -0
- package/v2Containers/BeePopupEditor/tests/index.test.js +627 -0
- package/v2Containers/Cap/tests/__snapshots__/index.test.js.snap +0 -1
- package/v2Containers/CreativesContainer/SlideBoxContent.js +148 -120
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +9 -3
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +2 -2
- package/v2Containers/CreativesContainer/constants.js +1 -2
- package/v2Containers/CreativesContainer/index.js +173 -193
- package/v2Containers/CreativesContainer/messages.js +4 -4
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +38 -50
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +36 -0
- package/v2Containers/Email/actions.js +7 -0
- package/v2Containers/Email/constants.js +5 -1
- package/v2Containers/Email/index.js +13 -0
- package/v2Containers/Email/messages.js +32 -0
- package/v2Containers/Email/reducer.js +12 -1
- package/v2Containers/Email/sagas.js +41 -6
- package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +2 -0
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +1046 -0
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +193 -7
- package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +40 -74
- package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +2 -67
- package/v2Containers/EmailWrapper/constants.js +2 -0
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +436 -67
- package/v2Containers/EmailWrapper/index.js +99 -23
- package/v2Containers/EmailWrapper/messages.js +61 -1
- package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +26 -1
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +111 -77
- package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +376 -0
- package/v2Containers/InApp/__tests__/sagas.test.js +363 -0
- package/v2Containers/InApp/actions.js +7 -0
- package/v2Containers/InApp/constants.js +20 -4
- package/v2Containers/InApp/index.js +800 -357
- package/v2Containers/InApp/index.scss +4 -3
- package/v2Containers/InApp/messages.js +7 -3
- package/v2Containers/InApp/reducer.js +21 -3
- package/v2Containers/InApp/sagas.js +29 -9
- package/v2Containers/InApp/selectors.js +25 -5
- package/v2Containers/InApp/tests/index.test.js +154 -50
- package/v2Containers/InApp/tests/reducer.test.js +34 -0
- package/v2Containers/InApp/tests/sagas.test.js +61 -9
- package/v2Containers/InApp/tests/selectors.test.js +612 -0
- package/v2Containers/InAppWrapper/components/InAppWrapperView.js +162 -0
- package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +267 -0
- package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +9 -0
- package/v2Containers/InAppWrapper/constants.js +16 -0
- package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +473 -0
- package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +198 -0
- package/v2Containers/InAppWrapper/index.js +148 -0
- package/v2Containers/InAppWrapper/messages.js +49 -0
- package/v2Containers/InappAdvance/index.js +1099 -0
- package/v2Containers/InappAdvance/index.scss +10 -0
- package/v2Containers/InappAdvance/tests/index.test.js +448 -0
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +3 -3
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +2 -2
- package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +2 -25
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +9 -18
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +12 -46
- package/v2Containers/SmsTrai/Create/tests/__snapshots__/index.test.js.snap +0 -4
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4 -8
- package/v2Containers/TagList/index.js +67 -1
- package/v2Containers/Templates/ChannelTypeIllustration.js +1 -13
- package/v2Containers/Templates/_templates.scss +56 -200
- package/v2Containers/Templates/actions.js +1 -2
- package/v2Containers/Templates/constants.js +0 -1
- package/v2Containers/Templates/index.js +124 -277
- package/v2Containers/Templates/messages.js +4 -24
- package/v2Containers/Templates/reducer.js +0 -2
- package/v2Containers/Templates/tests/index.test.js +0 -10
- package/v2Containers/TemplatesV2/index.js +2 -3
- package/v2Containers/TemplatesV2/messages.js +0 -4
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +35 -132
- package/v2Components/CapImageUrlUpload/constants.js +0 -19
- package/v2Components/CapImageUrlUpload/index.js +0 -455
- package/v2Components/CapImageUrlUpload/index.scss +0 -35
- package/v2Components/CapImageUrlUpload/messages.js +0 -47
- package/v2Containers/WebPush/Create/components/ButtonForm.js +0 -175
- package/v2Containers/WebPush/Create/components/ButtonItem.js +0 -101
- package/v2Containers/WebPush/Create/components/ButtonList.js +0 -144
- package/v2Containers/WebPush/Create/components/_buttons.scss +0 -246
- package/v2Containers/WebPush/Create/components/tests/ButtonForm.test.js +0 -554
- package/v2Containers/WebPush/Create/components/tests/ButtonItem.test.js +0 -607
- package/v2Containers/WebPush/Create/components/tests/ButtonList.test.js +0 -633
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonForm.test.js.snap +0 -666
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonItem.test.js.snap +0 -74
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonList.test.js.snap +0 -80
- package/v2Containers/WebPush/Create/index.js +0 -1755
- package/v2Containers/WebPush/Create/index.scss +0 -123
- package/v2Containers/WebPush/Create/messages.js +0 -199
- package/v2Containers/WebPush/Create/preview/DevicePreviewContent.js +0 -241
- package/v2Containers/WebPush/Create/preview/NotificationContainer.js +0 -290
- package/v2Containers/WebPush/Create/preview/PreviewContent.js +0 -81
- package/v2Containers/WebPush/Create/preview/PreviewControls.js +0 -240
- package/v2Containers/WebPush/Create/preview/PreviewDisclaimer.js +0 -23
- package/v2Containers/WebPush/Create/preview/WebPushPreview.js +0 -144
- package/v2Containers/WebPush/Create/preview/assets/Light.svg +0 -53
- package/v2Containers/WebPush/Create/preview/assets/Top.svg +0 -5
- package/v2Containers/WebPush/Create/preview/assets/chrome-icon.png +0 -0
- package/v2Containers/WebPush/Create/preview/assets/edge-icon.png +0 -0
- package/v2Containers/WebPush/Create/preview/assets/firefox-icon.svg +0 -106
- package/v2Containers/WebPush/Create/preview/assets/iOS.svg +0 -26
- package/v2Containers/WebPush/Create/preview/assets/opera-icon.svg +0 -18
- package/v2Containers/WebPush/Create/preview/assets/safari-icon.svg +0 -29
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileChromeHeader.js +0 -44
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +0 -110
- package/v2Containers/WebPush/Create/preview/components/IOSHeader.js +0 -45
- package/v2Containers/WebPush/Create/preview/components/NotificationExpandedContent.js +0 -72
- package/v2Containers/WebPush/Create/preview/components/NotificationHeader.js +0 -55
- package/v2Containers/WebPush/Create/preview/components/WindowsChromeExpanded.js +0 -70
- package/v2Containers/WebPush/Create/preview/components/tests/AndroidMobileExpanded.test.js +0 -512
- package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/AndroidMobileExpanded.test.js.snap +0 -77
- package/v2Containers/WebPush/Create/preview/config/notificationMappings.js +0 -527
- package/v2Containers/WebPush/Create/preview/constants.js +0 -162
- package/v2Containers/WebPush/Create/preview/notification-container.scss +0 -104
- package/v2Containers/WebPush/Create/preview/preview.scss +0 -409
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-chrome.scss +0 -300
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-edge.scss +0 -12
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-firefox.scss +0 -12
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-opera.scss +0 -12
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-chrome.scss +0 -303
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-edge.scss +0 -11
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-firefox.scss +0 -11
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-opera.scss +0 -11
- package/v2Containers/WebPush/Create/preview/styles/_base.scss +0 -188
- package/v2Containers/WebPush/Create/preview/styles/_ios.scss +0 -106
- package/v2Containers/WebPush/Create/preview/styles/_ipados.scss +0 -107
- package/v2Containers/WebPush/Create/preview/styles/_macos-chrome.scss +0 -75
- package/v2Containers/WebPush/Create/preview/styles/_windows-chrome.scss +0 -174
- package/v2Containers/WebPush/Create/preview/tests/DevicePreviewContent.test.js +0 -909
- package/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +0 -1077
- package/v2Containers/WebPush/Create/preview/tests/PreviewControls.test.js +0 -723
- package/v2Containers/WebPush/Create/preview/tests/WebPushPreview.test.js +0 -943
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/DevicePreviewContent.test.js.snap +0 -128
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/NotificationContainer.test.js.snap +0 -121
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/PreviewControls.test.js.snap +0 -144
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/WebPushPreview.test.js.snap +0 -127
- package/v2Containers/WebPush/Create/utils/urlValidation.js +0 -116
- package/v2Containers/WebPush/Create/utils/urlValidation.test.js +0 -449
- package/v2Containers/WebPush/actions.js +0 -60
- package/v2Containers/WebPush/constants.js +0 -108
- package/v2Containers/WebPush/index.js +0 -2
- package/v2Containers/WebPush/reducer.js +0 -104
- package/v2Containers/WebPush/sagas.js +0 -119
- package/v2Containers/WebPush/selectors.js +0 -65
- package/v2Containers/WebPush/tests/reducer.test.js +0 -863
- package/v2Containers/WebPush/tests/sagas.test.js +0 -566
- package/v2Containers/WebPush/tests/selectors.test.js +0 -960
|
@@ -12,14 +12,14 @@
|
|
|
12
12
|
* Note: Uses injectIntl with forwardRef to provide direct access to CodeEditorPane via ref
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import React, {
|
|
15
|
+
import React, {
|
|
16
|
+
useRef, useCallback, useMemo, useState, useEffect,
|
|
17
|
+
} from 'react';
|
|
16
18
|
import PropTypes from 'prop-types';
|
|
17
|
-
import { Layout } from 'antd'; // Fallback - no Cap UI equivalent
|
|
18
19
|
import { injectIntl, intlShape } from 'react-intl';
|
|
19
20
|
|
|
20
21
|
// Cap UI Components (First Preference)
|
|
21
22
|
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
22
|
-
import CapColumn from '@capillarytech/cap-ui-library/CapColumn';
|
|
23
23
|
import CapSpin from '@capillarytech/cap-ui-library/CapSpin';
|
|
24
24
|
import CapNotification from '@capillarytech/cap-ui-library/CapNotification';
|
|
25
25
|
import CapModal from '@capillarytech/cap-ui-library/CapModal';
|
|
@@ -40,7 +40,9 @@ import { useLayoutState } from './hooks/useLayoutState';
|
|
|
40
40
|
import { useValidation } from './hooks/useValidation';
|
|
41
41
|
|
|
42
42
|
// Constants
|
|
43
|
-
import {
|
|
43
|
+
import {
|
|
44
|
+
HTML_EDITOR_VARIANTS, DEVICE_TYPES, DEFAULT_HTML_CONTENT, TAG, EMBEDDED, DEFAULT, FULL, ALL, SMS, EMAIL,
|
|
45
|
+
} from './constants';
|
|
44
46
|
|
|
45
47
|
// Styles
|
|
46
48
|
import './_htmlEditor.scss';
|
|
@@ -61,6 +63,21 @@ const HTMLEditor = ({
|
|
|
61
63
|
showFullscreenButton = true,
|
|
62
64
|
autoSave = true,
|
|
63
65
|
autoSaveInterval = 30000, // 30 seconds
|
|
66
|
+
// Tag-related props - tags are fetched and managed by parent component (EmailHTMLEditor, INAPP, etc.)
|
|
67
|
+
tags = [],
|
|
68
|
+
injectedTags = {},
|
|
69
|
+
location,
|
|
70
|
+
eventContextTags = [],
|
|
71
|
+
selectedOfferDetails = [],
|
|
72
|
+
channel,
|
|
73
|
+
userLocale = 'en',
|
|
74
|
+
moduleFilterEnabled = true,
|
|
75
|
+
onTagContextChange, // Parent component handles tag fetching
|
|
76
|
+
onTagSelect = null,
|
|
77
|
+
onContextChange = null,
|
|
78
|
+
globalActions = null,
|
|
79
|
+
isLiquidEnabled = false, // Controls Liquid tab visibility in ValidationTabs
|
|
80
|
+
isFullMode = true, // Full mode vs library mode - controls layout and visibility
|
|
64
81
|
...props
|
|
65
82
|
}) => {
|
|
66
83
|
// Separate refs for main and modal editors to avoid conflicts
|
|
@@ -69,9 +86,7 @@ const HTMLEditor = ({
|
|
|
69
86
|
const [isFullscreenModalOpen, setIsFullscreenModalOpen] = useState(false);
|
|
70
87
|
|
|
71
88
|
// Get the currently active editor ref based on fullscreen state
|
|
72
|
-
const getActiveEditorRef = useCallback(() =>
|
|
73
|
-
return isFullscreenModalOpen ? modalEditorRef : mainEditorRef;
|
|
74
|
-
}, [isFullscreenModalOpen]);
|
|
89
|
+
const getActiveEditorRef = useCallback(() => isFullscreenModalOpen ? modalEditorRef : mainEditorRef, [isFullscreenModalOpen]);
|
|
75
90
|
|
|
76
91
|
// Initialize custom hooks for state management - always call both hooks to follow Rules of Hooks
|
|
77
92
|
const isEmailVariant = variant === HTML_EDITOR_VARIANTS.EMAIL;
|
|
@@ -80,7 +95,7 @@ const HTMLEditor = ({
|
|
|
80
95
|
autoSave: isEmailVariant ? autoSave : false,
|
|
81
96
|
autoSaveInterval,
|
|
82
97
|
onSave: isEmailVariant ? onSave : null,
|
|
83
|
-
onChange: isEmailVariant ? onContentChange : null
|
|
98
|
+
onChange: isEmailVariant ? onContentChange : null,
|
|
84
99
|
};
|
|
85
100
|
|
|
86
101
|
const emailContent = useEditorContent(
|
|
@@ -97,7 +112,7 @@ const HTMLEditor = ({
|
|
|
97
112
|
// Convert string content to device-specific format
|
|
98
113
|
inAppInitialContent = {
|
|
99
114
|
[DEVICE_TYPES.ANDROID]: initialContent,
|
|
100
|
-
[DEVICE_TYPES.IOS]: initialContent
|
|
115
|
+
[DEVICE_TYPES.IOS]: initialContent,
|
|
101
116
|
};
|
|
102
117
|
} else {
|
|
103
118
|
// Use provided device-specific content
|
|
@@ -109,7 +124,7 @@ const HTMLEditor = ({
|
|
|
109
124
|
autoSave: isInAppVariant ? autoSave : false,
|
|
110
125
|
autoSaveInterval,
|
|
111
126
|
onSave: isInAppVariant ? onSave : null,
|
|
112
|
-
onChange: isInAppVariant ? onContentChange : null
|
|
127
|
+
onChange: isInAppVariant ? onContentChange : null,
|
|
113
128
|
};
|
|
114
129
|
|
|
115
130
|
const inAppContent = useInAppContent(inAppInitialContent, inAppOptions);
|
|
@@ -117,6 +132,64 @@ const HTMLEditor = ({
|
|
|
117
132
|
// Use appropriate content hook based on variant
|
|
118
133
|
const content = variant === HTML_EDITOR_VARIANTS.EMAIL ? emailContent : inAppContent;
|
|
119
134
|
|
|
135
|
+
// Update content when initialContent prop changes (for edit mode)
|
|
136
|
+
// This ensures the editor updates when template data loads
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
if (isEmailVariant && emailContent && initialContent !== undefined && initialContent !== null) {
|
|
139
|
+
// Only update if content is different to avoid unnecessary updates
|
|
140
|
+
if (emailContent.content !== initialContent) {
|
|
141
|
+
emailContent.updateContent(initialContent, true); // immediate update
|
|
142
|
+
}
|
|
143
|
+
} else if (isInAppVariant && inAppContent && initialContent !== undefined && initialContent !== null) {
|
|
144
|
+
// Handle InApp variant updates
|
|
145
|
+
const contentToUpdate = typeof initialContent === 'string'
|
|
146
|
+
? { [DEVICE_TYPES.ANDROID]: initialContent, [DEVICE_TYPES.IOS]: initialContent }
|
|
147
|
+
: initialContent;
|
|
148
|
+
if (inAppContent.updateContent) {
|
|
149
|
+
const currentContent = inAppContent.getDeviceContent?.(inAppContent.activeDevice);
|
|
150
|
+
const newContent = contentToUpdate[inAppContent.activeDevice] || contentToUpdate[DEVICE_TYPES.ANDROID] || '';
|
|
151
|
+
if (currentContent !== newContent) {
|
|
152
|
+
inAppContent.updateContent(newContent, true);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}, [initialContent, isEmailVariant, isInAppVariant]);
|
|
157
|
+
// Handle context change for tag API calls
|
|
158
|
+
// If variant is INAPP, use SMS layout; otherwise use the channel (EMAIL)
|
|
159
|
+
const handleContextChange = useCallback((contextData) => {
|
|
160
|
+
// If onContextChange is provided, use it instead of making our own API call
|
|
161
|
+
// This prevents duplicate API calls when parent component handles tag fetching
|
|
162
|
+
if (onContextChange) {
|
|
163
|
+
onContextChange(contextData);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Only make API call if onContextChange is not provided and globalActions is available
|
|
168
|
+
if (!globalActions || !location) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const { type } = location.query || {};
|
|
173
|
+
const tempData = (contextData || '').toLowerCase();
|
|
174
|
+
const isEmbedded = type === EMBEDDED;
|
|
175
|
+
const embedded = isEmbedded ? type : FULL;
|
|
176
|
+
const context = tempData === ALL ? DEFAULT : tempData;
|
|
177
|
+
|
|
178
|
+
// Determine layout: INAPP variant uses SMS, EMAIL variant uses EMAIL
|
|
179
|
+
const layout = variant === HTML_EDITOR_VARIANTS.INAPP ? SMS : EMAIL;
|
|
180
|
+
|
|
181
|
+
const query = {
|
|
182
|
+
layout,
|
|
183
|
+
type: TAG,
|
|
184
|
+
context,
|
|
185
|
+
embedded,
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
// Call the API via Redux action - this will trigger the saga which calls Api.fetchSchemaForEntity
|
|
189
|
+
// The API endpoint will be: /meta/TAG?query={...}
|
|
190
|
+
globalActions.fetchSchemaForEntity(query);
|
|
191
|
+
}, [variant, globalActions, location, onContextChange]);
|
|
192
|
+
|
|
120
193
|
// Destructure content properties for cleaner access throughout component
|
|
121
194
|
const {
|
|
122
195
|
activeDevice,
|
|
@@ -124,14 +197,14 @@ const HTMLEditor = ({
|
|
|
124
197
|
switchDevice,
|
|
125
198
|
toggleContentSync,
|
|
126
199
|
getDeviceContent,
|
|
127
|
-
markAsSaved
|
|
200
|
+
markAsSaved,
|
|
128
201
|
} = content || {};
|
|
129
202
|
|
|
130
203
|
const layout = useLayoutState({
|
|
131
204
|
splitSizes: [50, 50],
|
|
132
205
|
viewMode: 'desktop',
|
|
133
206
|
mobileWidth: 375,
|
|
134
|
-
isFullscreen: false
|
|
207
|
+
isFullscreen: false,
|
|
135
208
|
});
|
|
136
209
|
|
|
137
210
|
// Get current content for validation based on variant
|
|
@@ -158,7 +231,7 @@ const HTMLEditor = ({
|
|
|
158
231
|
'sanitizer.productionValidHtml': messages.sanitizer.productionValidHtml,
|
|
159
232
|
'sanitizer.productionSanitized': messages.sanitizer.productionSanitized,
|
|
160
233
|
'sanitizer.productionInlineCss': messages.sanitizer.productionInlineCss,
|
|
161
|
-
'sanitizer.productionLargeContent': messages.sanitizer.productionLargeContent
|
|
234
|
+
'sanitizer.productionLargeContent': messages.sanitizer.productionLargeContent,
|
|
162
235
|
};
|
|
163
236
|
|
|
164
237
|
const messageObj = messageMap[messageKey];
|
|
@@ -179,7 +252,7 @@ const HTMLEditor = ({
|
|
|
179
252
|
'validator.largeImageDetected': messages.validator.largeImageDetected,
|
|
180
253
|
'validator.unclosedCssRule': messages.validator.unclosedCssRule,
|
|
181
254
|
'validator.emptyCssRule': messages.validator.emptyCssRule,
|
|
182
|
-
'validator.cssValidationFailed': messages.validator.cssValidationFailed
|
|
255
|
+
'validator.cssValidationFailed': messages.validator.cssValidationFailed,
|
|
183
256
|
};
|
|
184
257
|
|
|
185
258
|
const messageObj = messageMap[messageKey];
|
|
@@ -190,57 +263,69 @@ const HTMLEditor = ({
|
|
|
190
263
|
enableRealTime: true,
|
|
191
264
|
debounceMs: 500,
|
|
192
265
|
enableSanitization: true,
|
|
193
|
-
securityLevel: 'standard'
|
|
266
|
+
securityLevel: 'standard',
|
|
194
267
|
}, formatSanitizerMessage, formatValidatorMessage);
|
|
195
268
|
|
|
196
269
|
// Handle label insertion at cursor position
|
|
270
|
+
// Note: This is called for notification purposes only when tag is inserted via CodeEditorPane
|
|
271
|
+
// The actual insertion happens in CodeEditorPane.handleTagSelect
|
|
197
272
|
const handleLabelInsert = useCallback((label, position) => {
|
|
198
|
-
//
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
CapNotification.error({
|
|
214
|
-
message: intl.formatMessage(messages.labelInsertError),
|
|
215
|
-
description: intl.formatMessage(messages.editorMethodNotAvailable),
|
|
216
|
-
duration: 4
|
|
217
|
-
});
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
try {
|
|
222
|
-
// Get current cursor position or use provided position
|
|
223
|
-
const cursor = position !== undefined
|
|
224
|
-
? position
|
|
225
|
-
: (typeof editor?.getCursor === 'function' ? editor.getCursor() : 0);
|
|
226
|
-
|
|
227
|
-
// Insert label at cursor position
|
|
228
|
-
editor.insertText(label, cursor);
|
|
273
|
+
// If position is explicitly null, it means the editor wasn't ready when tag was selected
|
|
274
|
+
// In this case, CodeEditorPane couldn't insert the tag, so we should try here
|
|
275
|
+
if (position === null) {
|
|
276
|
+
// With injectIntl({ forwardRef: true }), ref points directly to CodeEditorPane
|
|
277
|
+
const activeEditorRef = getActiveEditorRef();
|
|
278
|
+
const editor = activeEditorRef.current;
|
|
279
|
+
|
|
280
|
+
if (!editor) {
|
|
281
|
+
CapNotification.warning({
|
|
282
|
+
message: intl.formatMessage(messages.labelInsertError),
|
|
283
|
+
description: intl.formatMessage(messages.editorNotReady),
|
|
284
|
+
duration: 3,
|
|
285
|
+
});
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
229
288
|
|
|
230
|
-
//
|
|
231
|
-
editor?.
|
|
289
|
+
// Check if the required methods exist
|
|
290
|
+
if (typeof editor?.insertText !== 'function') {
|
|
291
|
+
CapNotification.error({
|
|
292
|
+
message: intl.formatMessage(messages.labelInsertError),
|
|
293
|
+
description: intl.formatMessage(messages.editorMethodNotAvailable),
|
|
294
|
+
duration: 4,
|
|
295
|
+
});
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
232
298
|
|
|
233
|
-
|
|
299
|
+
try {
|
|
300
|
+
// Get current cursor position
|
|
301
|
+
const cursor = typeof editor?.getCursor === 'function' ? editor.getCursor() : 0;
|
|
302
|
+
|
|
303
|
+
// Insert label at cursor position
|
|
304
|
+
editor.insertText(label, cursor);
|
|
305
|
+
|
|
306
|
+
// Focus the editor if focus method is available
|
|
307
|
+
editor?.focus?.();
|
|
308
|
+
|
|
309
|
+
// Show success notification
|
|
310
|
+
CapNotification.success({
|
|
311
|
+
message: intl.formatMessage(messages.labelInserted),
|
|
312
|
+
description: intl.formatMessage(messages.labelInsertedDescription, { label }),
|
|
313
|
+
duration: 2,
|
|
314
|
+
});
|
|
315
|
+
} catch (error) {
|
|
316
|
+
CapNotification.error({
|
|
317
|
+
message: intl.formatMessage(messages.labelInsertError),
|
|
318
|
+
description: error.message,
|
|
319
|
+
duration: 4,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
} else {
|
|
323
|
+
// Tag was already inserted by CodeEditorPane (position is a valid number)
|
|
324
|
+
// Just show success notification - no need to access editor
|
|
234
325
|
CapNotification.success({
|
|
235
326
|
message: intl.formatMessage(messages.labelInserted),
|
|
236
327
|
description: intl.formatMessage(messages.labelInsertedDescription, { label }),
|
|
237
|
-
duration: 2
|
|
238
|
-
});
|
|
239
|
-
} catch (error) {
|
|
240
|
-
CapNotification.error({
|
|
241
|
-
message: intl.formatMessage(messages.labelInsertError),
|
|
242
|
-
description: error.message,
|
|
243
|
-
duration: 4
|
|
328
|
+
duration: 2,
|
|
244
329
|
});
|
|
245
330
|
}
|
|
246
331
|
}, [intl, getActiveEditorRef]);
|
|
@@ -259,13 +344,13 @@ const HTMLEditor = ({
|
|
|
259
344
|
|
|
260
345
|
CapNotification.success({
|
|
261
346
|
message: intl.formatMessage(messages.contentSaved),
|
|
262
|
-
duration: 2
|
|
347
|
+
duration: 2,
|
|
263
348
|
});
|
|
264
349
|
} catch (error) {
|
|
265
350
|
CapNotification.error({
|
|
266
351
|
message: intl.formatMessage(messages.saveError),
|
|
267
352
|
description: error.message,
|
|
268
|
-
duration: 4
|
|
353
|
+
duration: 4,
|
|
269
354
|
});
|
|
270
355
|
}
|
|
271
356
|
}, [content, onSave, intl, markAsSaved]);
|
|
@@ -307,6 +392,7 @@ const HTMLEditor = ({
|
|
|
307
392
|
content,
|
|
308
393
|
layout,
|
|
309
394
|
validation,
|
|
395
|
+
isLiquidEnabled,
|
|
310
396
|
editorRef: getActiveEditorRef(),
|
|
311
397
|
handleLabelInsert,
|
|
312
398
|
handleSave,
|
|
@@ -319,13 +405,14 @@ const HTMLEditor = ({
|
|
|
319
405
|
switchDevice,
|
|
320
406
|
toggleContentSync,
|
|
321
407
|
getDeviceContent,
|
|
322
|
-
layoutType
|
|
323
|
-
})
|
|
408
|
+
layoutType,
|
|
409
|
+
}),
|
|
324
410
|
}), [
|
|
325
411
|
variant,
|
|
326
412
|
content,
|
|
327
413
|
layout,
|
|
328
414
|
validation,
|
|
415
|
+
isLiquidEnabled,
|
|
329
416
|
getActiveEditorRef,
|
|
330
417
|
handleLabelInsert,
|
|
331
418
|
handleSave,
|
|
@@ -336,7 +423,7 @@ const HTMLEditor = ({
|
|
|
336
423
|
switchDevice,
|
|
337
424
|
toggleContentSync,
|
|
338
425
|
getDeviceContent,
|
|
339
|
-
layoutType
|
|
426
|
+
layoutType,
|
|
340
427
|
]);
|
|
341
428
|
|
|
342
429
|
// Loading state
|
|
@@ -348,9 +435,12 @@ const HTMLEditor = ({
|
|
|
348
435
|
);
|
|
349
436
|
}
|
|
350
437
|
|
|
438
|
+
// Add library-mode class when not in full mode
|
|
439
|
+
const editorClassName = `html-editor html-editor--${variant} ${!isFullMode ? 'html-editor--library-mode' : ''} ${className}`;
|
|
440
|
+
|
|
351
441
|
return (
|
|
352
442
|
<EditorProvider value={contextValue}>
|
|
353
|
-
<div className={
|
|
443
|
+
<div className={editorClassName} {...props}>
|
|
354
444
|
{/* Editor Toolbar - Conditional based on variant */}
|
|
355
445
|
{variant === HTML_EDITOR_VARIANTS.EMAIL ? (
|
|
356
446
|
<EditorToolbar
|
|
@@ -387,19 +477,23 @@ const HTMLEditor = ({
|
|
|
387
477
|
ref={mainEditorRef}
|
|
388
478
|
readOnly={readOnly}
|
|
389
479
|
onLabelInsert={handleLabelInsert}
|
|
480
|
+
onErrorClick={handleValidationErrorClick}
|
|
481
|
+
tags={tags}
|
|
482
|
+
injectedTags={injectedTags}
|
|
483
|
+
location={location}
|
|
484
|
+
eventContextTags={eventContextTags}
|
|
485
|
+
selectedOfferDetails={selectedOfferDetails}
|
|
486
|
+
channel={channel}
|
|
487
|
+
userLocale={userLocale}
|
|
488
|
+
moduleFilterEnabled={moduleFilterEnabled}
|
|
489
|
+
onTagContextChange={onTagContextChange}
|
|
490
|
+
onTagSelect={onTagSelect}
|
|
491
|
+
onContextChange={handleContextChange}
|
|
390
492
|
/>
|
|
391
493
|
|
|
392
494
|
{/* Preview Pane */}
|
|
393
495
|
<PreviewPane />
|
|
394
496
|
</SplitContainer>
|
|
395
|
-
|
|
396
|
-
{/* Validation Display - Full Width Below Split Container */}
|
|
397
|
-
<ValidationErrorDisplay
|
|
398
|
-
validation={validation}
|
|
399
|
-
onErrorClick={handleValidationErrorClick}
|
|
400
|
-
variant={variant}
|
|
401
|
-
className="html-editor-validation"
|
|
402
|
-
/>
|
|
403
497
|
</CapRow>
|
|
404
498
|
|
|
405
499
|
{/* Fullscreen Modal */}
|
|
@@ -411,17 +505,17 @@ const HTMLEditor = ({
|
|
|
411
505
|
maskClosable={false}
|
|
412
506
|
centered
|
|
413
507
|
closable={false}
|
|
414
|
-
width=
|
|
508
|
+
width="90vw"
|
|
415
509
|
className="html-editor-fullscreen-modal"
|
|
416
510
|
>
|
|
417
511
|
<CapRow className="html-editor-fullscreen">
|
|
418
512
|
{/* Editor Toolbar - Conditional based on variant */}
|
|
419
513
|
{variant === HTML_EDITOR_VARIANTS.EMAIL ? (
|
|
420
514
|
<EditorToolbar
|
|
421
|
-
showFullscreenButton
|
|
515
|
+
showFullscreenButton // Show fullscreen button in modal to allow closing
|
|
422
516
|
onLabelInsert={handleLabelInsert}
|
|
423
517
|
onSave={handleSave}
|
|
424
|
-
isFullscreenMode
|
|
518
|
+
isFullscreenMode
|
|
425
519
|
onToggleFullscreen={handleCloseFullscreen} // Close modal when clicked in fullscreen mode
|
|
426
520
|
/>
|
|
427
521
|
) : (
|
|
@@ -434,10 +528,10 @@ const HTMLEditor = ({
|
|
|
434
528
|
onKeepContentSameChange={toggleContentSync}
|
|
435
529
|
/>
|
|
436
530
|
<EditorToolbar
|
|
437
|
-
showFullscreenButton
|
|
531
|
+
showFullscreenButton // Show fullscreen button in modal to allow closing
|
|
438
532
|
onLabelInsert={handleLabelInsert}
|
|
439
533
|
onSave={handleSave}
|
|
440
|
-
isFullscreenMode
|
|
534
|
+
isFullscreenMode
|
|
441
535
|
onToggleFullscreen={handleCloseFullscreen} // Close modal when clicked in fullscreen mode
|
|
442
536
|
variant={variant}
|
|
443
537
|
showTitle={false} // Hide title in InApp variant
|
|
@@ -452,21 +546,23 @@ const HTMLEditor = ({
|
|
|
452
546
|
<CodeEditorPane
|
|
453
547
|
ref={modalEditorRef}
|
|
454
548
|
readOnly={readOnly}
|
|
455
|
-
isFullscreenMode
|
|
549
|
+
isFullscreenMode
|
|
456
550
|
onLabelInsert={handleLabelInsert}
|
|
551
|
+
onErrorClick={handleValidationErrorClick}
|
|
552
|
+
tags={tags}
|
|
553
|
+
injectedTags={injectedTags}
|
|
554
|
+
location={location}
|
|
555
|
+
eventContextTags={eventContextTags}
|
|
556
|
+
selectedOfferDetails={selectedOfferDetails}
|
|
557
|
+
channel={channel}
|
|
558
|
+
userLocale={userLocale}
|
|
559
|
+
moduleFilterEnabled={moduleFilterEnabled}
|
|
560
|
+
onTagContextChange={onTagContextChange}
|
|
457
561
|
/>
|
|
458
562
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
{/* Validation Display in Modal */}
|
|
464
|
-
<ValidationErrorDisplay
|
|
465
|
-
validation={validation}
|
|
466
|
-
onErrorClick={handleValidationErrorClick}
|
|
467
|
-
variant={variant}
|
|
468
|
-
className="html-editor-validation"
|
|
469
|
-
/>
|
|
563
|
+
{/* Preview Pane */}
|
|
564
|
+
<PreviewPane isFullscreenMode isModalContext />
|
|
565
|
+
</SplitContainer>
|
|
470
566
|
</CapRow>
|
|
471
567
|
</CapRow>
|
|
472
568
|
</CapModal>
|
|
@@ -481,7 +577,7 @@ HTMLEditor.propTypes = {
|
|
|
481
577
|
layoutType: PropTypes.string, // Layout type for InApp variant
|
|
482
578
|
initialContent: PropTypes.oneOfType([
|
|
483
579
|
PropTypes.string,
|
|
484
|
-
PropTypes.objectOf(PropTypes.string) // Per-device content for INAPP variant
|
|
580
|
+
PropTypes.objectOf(PropTypes.string), // Per-device content for INAPP variant
|
|
485
581
|
]),
|
|
486
582
|
onSave: PropTypes.func,
|
|
487
583
|
onContentChange: PropTypes.func,
|
|
@@ -489,11 +585,27 @@ HTMLEditor.propTypes = {
|
|
|
489
585
|
readOnly: PropTypes.bool,
|
|
490
586
|
showFullscreenButton: PropTypes.bool,
|
|
491
587
|
autoSave: PropTypes.bool,
|
|
492
|
-
autoSaveInterval: PropTypes.number
|
|
588
|
+
autoSaveInterval: PropTypes.number,
|
|
589
|
+
// Tag-related props - tags are fetched and managed by parent component
|
|
590
|
+
tags: PropTypes.array,
|
|
591
|
+
injectedTags: PropTypes.object,
|
|
592
|
+
location: PropTypes.object,
|
|
593
|
+
eventContextTags: PropTypes.array,
|
|
594
|
+
selectedOfferDetails: PropTypes.array,
|
|
595
|
+
channel: PropTypes.string,
|
|
596
|
+
userLocale: PropTypes.string,
|
|
597
|
+
moduleFilterEnabled: PropTypes.bool,
|
|
598
|
+
onTagContextChange: PropTypes.func, // Required - parent must handle tag fetching
|
|
599
|
+
onTagSelect: PropTypes.func,
|
|
600
|
+
onContextChange: PropTypes.func, // Deprecated: use globalActions instead
|
|
601
|
+
globalActions: PropTypes.object,
|
|
602
|
+
isLiquidEnabled: PropTypes.bool, // Controls Liquid tab visibility in validation
|
|
603
|
+
isFullMode: PropTypes.bool, // Full mode vs library mode
|
|
493
604
|
};
|
|
494
605
|
|
|
495
606
|
HTMLEditor.defaultProps = {
|
|
496
607
|
variant: HTML_EDITOR_VARIANTS.EMAIL, // Default to email variant
|
|
608
|
+
layoutType: null,
|
|
497
609
|
initialContent: null, // Will use default from useEditorContent hook
|
|
498
610
|
onSave: null,
|
|
499
611
|
onContentChange: null,
|
|
@@ -501,7 +613,22 @@ HTMLEditor.defaultProps = {
|
|
|
501
613
|
readOnly: false,
|
|
502
614
|
showFullscreenButton: true,
|
|
503
615
|
autoSave: true,
|
|
504
|
-
autoSaveInterval: 30000
|
|
616
|
+
autoSaveInterval: 30000,
|
|
617
|
+
// Tag-related defaults - tags are fetched and managed by parent component
|
|
618
|
+
tags: [],
|
|
619
|
+
injectedTags: {},
|
|
620
|
+
location: null,
|
|
621
|
+
eventContextTags: [],
|
|
622
|
+
selectedOfferDetails: [],
|
|
623
|
+
channel: null,
|
|
624
|
+
userLocale: 'en',
|
|
625
|
+
moduleFilterEnabled: true,
|
|
626
|
+
onTagContextChange: null, // Parent component should provide this
|
|
627
|
+
onTagSelect: null,
|
|
628
|
+
onContextChange: null,
|
|
629
|
+
globalActions: null, // Redux actions for API calls
|
|
630
|
+
isLiquidEnabled: false,
|
|
631
|
+
isFullMode: true, // Default to full mode
|
|
505
632
|
};
|
|
506
633
|
|
|
507
634
|
// Export with forwardRef to allow direct access to CodeEditorPane via ref
|