@capillarytech/creatives-library 8.0.242-alpha.0 → 8.0.242-alpha.1

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