@capillarytech/creatives-library 8.0.235 → 8.0.236-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.
- package/assets/Android.png +0 -0
- package/assets/iOS.png +0 -0
- package/config/app.js +0 -1
- package/constants/unified.js +1 -1
- package/initialReducer.js +2 -0
- package/package.json +1 -1
- package/services/api.js +5 -2
- package/services/tests/api.test.js +18 -0
- package/utils/common.js +1 -2
- package/utils/commonUtils.js +14 -1
- package/utils/transformTemplateConfig.js +0 -10
- package/v2Components/CapDeviceContent/index.js +61 -56
- package/v2Components/CapTagList/index.js +4 -0
- package/v2Components/CapWhatsappCTA/tests/index.test.js +5 -0
- package/v2Components/HtmlEditor/HTMLEditor.js +165 -80
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +532 -0
- package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +17 -12
- package/v2Components/HtmlEditor/_htmlEditor.scss +0 -4
- package/v2Components/HtmlEditor/_index.lazy.scss +0 -1
- package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +0 -98
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +125 -148
- package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +1 -0
- package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
- 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/constants.js +29 -20
- package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +158 -17
- package/v2Components/HtmlEditor/hooks/useInAppContent.js +53 -143
- package/v2Components/HtmlEditor/index.js +1 -1
- package/v2Components/HtmlEditor/messages.js +85 -85
- package/v2Components/MobilePushPreviewV2/index.js +32 -7
- package/v2Components/TemplatePreview/_templatePreview.scss +31 -21
- package/v2Components/TemplatePreview/index.js +47 -32
- package/v2Components/TemplatePreview/messages.js +4 -0
- package/v2Containers/BeeEditor/index.js +82 -80
- package/v2Containers/BeePopupEditor/constants.js +10 -0
- package/v2Containers/BeePopupEditor/index.js +180 -0
- package/v2Containers/BeePopupEditor/tests/index.test.js +627 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +69 -34
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +2 -1
- package/v2Containers/CreativesContainer/constants.js +1 -0
- package/v2Containers/CreativesContainer/index.js +65 -13
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +4 -12
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +15 -0
- 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 +18 -4
- package/v2Containers/InApp/index.js +642 -355
- 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 +1006 -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 -0
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +2 -0
- package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +2 -0
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +9 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +12 -0
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4 -0
- package/v2Containers/TagList/index.js +65 -1
- package/v2Containers/Templates/_templates.scss +49 -1
- package/v2Containers/Templates/index.js +93 -5
- package/v2Containers/Templates/messages.js +4 -0
- package/v2Containers/Templates/reducer.js +20 -7
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +8 -88
- package/v2Containers/Templates/tests/reducer.test.js +125 -0
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +35 -0
|
@@ -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,
|
|
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,14 @@ const HTMLEditor = ({
|
|
|
61
63
|
showFullscreenButton = true,
|
|
62
64
|
autoSave = true,
|
|
63
65
|
autoSaveInterval = 30000, // 30 seconds
|
|
66
|
+
// Tags-related props for Add Label functionality
|
|
67
|
+
tags = [],
|
|
68
|
+
injectedTags = {},
|
|
69
|
+
location = {},
|
|
70
|
+
selectedOfferDetails = null,
|
|
71
|
+
onTagSelect = null,
|
|
72
|
+
onContextChange = null,
|
|
73
|
+
globalActions = null, // Redux actions for API calls
|
|
64
74
|
...props
|
|
65
75
|
}) => {
|
|
66
76
|
// Separate refs for main and modal editors to avoid conflicts
|
|
@@ -69,9 +79,7 @@ const HTMLEditor = ({
|
|
|
69
79
|
const [isFullscreenModalOpen, setIsFullscreenModalOpen] = useState(false);
|
|
70
80
|
|
|
71
81
|
// Get the currently active editor ref based on fullscreen state
|
|
72
|
-
const getActiveEditorRef = useCallback(() =>
|
|
73
|
-
return isFullscreenModalOpen ? modalEditorRef : mainEditorRef;
|
|
74
|
-
}, [isFullscreenModalOpen]);
|
|
82
|
+
const getActiveEditorRef = useCallback(() => isFullscreenModalOpen ? modalEditorRef : mainEditorRef, [isFullscreenModalOpen]);
|
|
75
83
|
|
|
76
84
|
// Initialize custom hooks for state management - always call both hooks to follow Rules of Hooks
|
|
77
85
|
const isEmailVariant = variant === HTML_EDITOR_VARIANTS.EMAIL;
|
|
@@ -80,7 +88,7 @@ const HTMLEditor = ({
|
|
|
80
88
|
autoSave: isEmailVariant ? autoSave : false,
|
|
81
89
|
autoSaveInterval,
|
|
82
90
|
onSave: isEmailVariant ? onSave : null,
|
|
83
|
-
onChange: isEmailVariant ? onContentChange : null
|
|
91
|
+
onChange: isEmailVariant ? onContentChange : null,
|
|
84
92
|
};
|
|
85
93
|
|
|
86
94
|
const emailContent = useEditorContent(
|
|
@@ -97,7 +105,7 @@ const HTMLEditor = ({
|
|
|
97
105
|
// Convert string content to device-specific format
|
|
98
106
|
inAppInitialContent = {
|
|
99
107
|
[DEVICE_TYPES.ANDROID]: initialContent,
|
|
100
|
-
[DEVICE_TYPES.IOS]: initialContent
|
|
108
|
+
[DEVICE_TYPES.IOS]: initialContent,
|
|
101
109
|
};
|
|
102
110
|
} else {
|
|
103
111
|
// Use provided device-specific content
|
|
@@ -109,7 +117,7 @@ const HTMLEditor = ({
|
|
|
109
117
|
autoSave: isInAppVariant ? autoSave : false,
|
|
110
118
|
autoSaveInterval,
|
|
111
119
|
onSave: isInAppVariant ? onSave : null,
|
|
112
|
-
onChange: isInAppVariant ? onContentChange : null
|
|
120
|
+
onChange: isInAppVariant ? onContentChange : null,
|
|
113
121
|
};
|
|
114
122
|
|
|
115
123
|
const inAppContent = useInAppContent(inAppInitialContent, inAppOptions);
|
|
@@ -117,6 +125,42 @@ const HTMLEditor = ({
|
|
|
117
125
|
// Use appropriate content hook based on variant
|
|
118
126
|
const content = variant === HTML_EDITOR_VARIANTS.EMAIL ? emailContent : inAppContent;
|
|
119
127
|
|
|
128
|
+
// Handle context change for tag API calls
|
|
129
|
+
// If variant is INAPP, use SMS layout; otherwise use the channel (EMAIL)
|
|
130
|
+
const handleContextChange = useCallback((contextData) => {
|
|
131
|
+
// If onContextChange is provided, use it instead of making our own API call
|
|
132
|
+
// This prevents duplicate API calls when parent component handles tag fetching
|
|
133
|
+
if (onContextChange) {
|
|
134
|
+
onContextChange(contextData);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Only make API call if onContextChange is not provided and globalActions is available
|
|
139
|
+
if (!globalActions || !location) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const { type } = location.query || {};
|
|
144
|
+
const tempData = (contextData || '').toLowerCase();
|
|
145
|
+
const isEmbedded = type === EMBEDDED;
|
|
146
|
+
const embedded = isEmbedded ? type : FULL;
|
|
147
|
+
const context = tempData === ALL ? DEFAULT : tempData;
|
|
148
|
+
|
|
149
|
+
// Determine layout: INAPP variant uses SMS, EMAIL variant uses EMAIL
|
|
150
|
+
const layout = variant === HTML_EDITOR_VARIANTS.INAPP ? SMS : EMAIL;
|
|
151
|
+
|
|
152
|
+
const query = {
|
|
153
|
+
layout,
|
|
154
|
+
type: TAG,
|
|
155
|
+
context,
|
|
156
|
+
embedded,
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// Call the API via Redux action - this will trigger the saga which calls Api.fetchSchemaForEntity
|
|
160
|
+
// The API endpoint will be: /meta/TAG?query={...}
|
|
161
|
+
globalActions.fetchSchemaForEntity(query);
|
|
162
|
+
}, [variant, globalActions, location, onContextChange]);
|
|
163
|
+
|
|
120
164
|
// Destructure content properties for cleaner access throughout component
|
|
121
165
|
const {
|
|
122
166
|
activeDevice,
|
|
@@ -124,14 +168,14 @@ const HTMLEditor = ({
|
|
|
124
168
|
switchDevice,
|
|
125
169
|
toggleContentSync,
|
|
126
170
|
getDeviceContent,
|
|
127
|
-
markAsSaved
|
|
171
|
+
markAsSaved,
|
|
128
172
|
} = content || {};
|
|
129
173
|
|
|
130
174
|
const layout = useLayoutState({
|
|
131
175
|
splitSizes: [50, 50],
|
|
132
176
|
viewMode: 'desktop',
|
|
133
177
|
mobileWidth: 375,
|
|
134
|
-
isFullscreen: false
|
|
178
|
+
isFullscreen: false,
|
|
135
179
|
});
|
|
136
180
|
|
|
137
181
|
// Get current content for validation based on variant
|
|
@@ -158,7 +202,7 @@ const HTMLEditor = ({
|
|
|
158
202
|
'sanitizer.productionValidHtml': messages.sanitizer.productionValidHtml,
|
|
159
203
|
'sanitizer.productionSanitized': messages.sanitizer.productionSanitized,
|
|
160
204
|
'sanitizer.productionInlineCss': messages.sanitizer.productionInlineCss,
|
|
161
|
-
'sanitizer.productionLargeContent': messages.sanitizer.productionLargeContent
|
|
205
|
+
'sanitizer.productionLargeContent': messages.sanitizer.productionLargeContent,
|
|
162
206
|
};
|
|
163
207
|
|
|
164
208
|
const messageObj = messageMap[messageKey];
|
|
@@ -179,7 +223,7 @@ const HTMLEditor = ({
|
|
|
179
223
|
'validator.largeImageDetected': messages.validator.largeImageDetected,
|
|
180
224
|
'validator.unclosedCssRule': messages.validator.unclosedCssRule,
|
|
181
225
|
'validator.emptyCssRule': messages.validator.emptyCssRule,
|
|
182
|
-
'validator.cssValidationFailed': messages.validator.cssValidationFailed
|
|
226
|
+
'validator.cssValidationFailed': messages.validator.cssValidationFailed,
|
|
183
227
|
};
|
|
184
228
|
|
|
185
229
|
const messageObj = messageMap[messageKey];
|
|
@@ -190,57 +234,69 @@ const HTMLEditor = ({
|
|
|
190
234
|
enableRealTime: true,
|
|
191
235
|
debounceMs: 500,
|
|
192
236
|
enableSanitization: true,
|
|
193
|
-
securityLevel: 'standard'
|
|
237
|
+
securityLevel: 'standard',
|
|
194
238
|
}, formatSanitizerMessage, formatValidatorMessage);
|
|
195
239
|
|
|
196
240
|
// Handle label insertion at cursor position
|
|
241
|
+
// Note: This is called for notification purposes only when tag is inserted via CodeEditorPane
|
|
242
|
+
// The actual insertion happens in CodeEditorPane.handleTagSelect
|
|
197
243
|
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);
|
|
244
|
+
// If position is explicitly null, it means the editor wasn't ready when tag was selected
|
|
245
|
+
// In this case, CodeEditorPane couldn't insert the tag, so we should try here
|
|
246
|
+
if (position === null) {
|
|
247
|
+
// With injectIntl({ forwardRef: true }), ref points directly to CodeEditorPane
|
|
248
|
+
const activeEditorRef = getActiveEditorRef();
|
|
249
|
+
const editor = activeEditorRef.current;
|
|
250
|
+
|
|
251
|
+
if (!editor) {
|
|
252
|
+
CapNotification.warning({
|
|
253
|
+
message: intl.formatMessage(messages.labelInsertError),
|
|
254
|
+
description: intl.formatMessage(messages.editorNotReady),
|
|
255
|
+
duration: 3,
|
|
256
|
+
});
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
229
259
|
|
|
230
|
-
//
|
|
231
|
-
editor?.
|
|
260
|
+
// Check if the required methods exist
|
|
261
|
+
if (typeof editor?.insertText !== 'function') {
|
|
262
|
+
CapNotification.error({
|
|
263
|
+
message: intl.formatMessage(messages.labelInsertError),
|
|
264
|
+
description: intl.formatMessage(messages.editorMethodNotAvailable),
|
|
265
|
+
duration: 4,
|
|
266
|
+
});
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
232
269
|
|
|
233
|
-
|
|
270
|
+
try {
|
|
271
|
+
// Get current cursor position
|
|
272
|
+
const cursor = typeof editor?.getCursor === 'function' ? editor.getCursor() : 0;
|
|
273
|
+
|
|
274
|
+
// Insert label at cursor position
|
|
275
|
+
editor.insertText(label, cursor);
|
|
276
|
+
|
|
277
|
+
// Focus the editor if focus method is available
|
|
278
|
+
editor?.focus?.();
|
|
279
|
+
|
|
280
|
+
// Show success notification
|
|
281
|
+
CapNotification.success({
|
|
282
|
+
message: intl.formatMessage(messages.labelInserted),
|
|
283
|
+
description: intl.formatMessage(messages.labelInsertedDescription, { label }),
|
|
284
|
+
duration: 2,
|
|
285
|
+
});
|
|
286
|
+
} catch (error) {
|
|
287
|
+
CapNotification.error({
|
|
288
|
+
message: intl.formatMessage(messages.labelInsertError),
|
|
289
|
+
description: error.message,
|
|
290
|
+
duration: 4,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
} else {
|
|
294
|
+
// Tag was already inserted by CodeEditorPane (position is a valid number)
|
|
295
|
+
// Just show success notification - no need to access editor
|
|
234
296
|
CapNotification.success({
|
|
235
297
|
message: intl.formatMessage(messages.labelInserted),
|
|
236
298
|
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
|
|
299
|
+
duration: 2,
|
|
244
300
|
});
|
|
245
301
|
}
|
|
246
302
|
}, [intl, getActiveEditorRef]);
|
|
@@ -259,13 +315,13 @@ const HTMLEditor = ({
|
|
|
259
315
|
|
|
260
316
|
CapNotification.success({
|
|
261
317
|
message: intl.formatMessage(messages.contentSaved),
|
|
262
|
-
duration: 2
|
|
318
|
+
duration: 2,
|
|
263
319
|
});
|
|
264
320
|
} catch (error) {
|
|
265
321
|
CapNotification.error({
|
|
266
322
|
message: intl.formatMessage(messages.saveError),
|
|
267
323
|
description: error.message,
|
|
268
|
-
duration: 4
|
|
324
|
+
duration: 4,
|
|
269
325
|
});
|
|
270
326
|
}
|
|
271
327
|
}, [content, onSave, intl, markAsSaved]);
|
|
@@ -319,8 +375,8 @@ const HTMLEditor = ({
|
|
|
319
375
|
switchDevice,
|
|
320
376
|
toggleContentSync,
|
|
321
377
|
getDeviceContent,
|
|
322
|
-
layoutType
|
|
323
|
-
})
|
|
378
|
+
layoutType,
|
|
379
|
+
}),
|
|
324
380
|
}), [
|
|
325
381
|
variant,
|
|
326
382
|
content,
|
|
@@ -336,7 +392,7 @@ const HTMLEditor = ({
|
|
|
336
392
|
switchDevice,
|
|
337
393
|
toggleContentSync,
|
|
338
394
|
getDeviceContent,
|
|
339
|
-
layoutType
|
|
395
|
+
layoutType,
|
|
340
396
|
]);
|
|
341
397
|
|
|
342
398
|
// Loading state
|
|
@@ -387,6 +443,12 @@ const HTMLEditor = ({
|
|
|
387
443
|
ref={mainEditorRef}
|
|
388
444
|
readOnly={readOnly}
|
|
389
445
|
onLabelInsert={handleLabelInsert}
|
|
446
|
+
tags={tags}
|
|
447
|
+
injectedTags={injectedTags}
|
|
448
|
+
location={location}
|
|
449
|
+
selectedOfferDetails={selectedOfferDetails}
|
|
450
|
+
onTagSelect={onTagSelect}
|
|
451
|
+
onContextChange={handleContextChange}
|
|
390
452
|
/>
|
|
391
453
|
|
|
392
454
|
{/* Preview Pane */}
|
|
@@ -411,17 +473,17 @@ const HTMLEditor = ({
|
|
|
411
473
|
maskClosable={false}
|
|
412
474
|
centered
|
|
413
475
|
closable={false}
|
|
414
|
-
width=
|
|
476
|
+
width="90vw"
|
|
415
477
|
className="html-editor-fullscreen-modal"
|
|
416
478
|
>
|
|
417
479
|
<CapRow className="html-editor-fullscreen">
|
|
418
480
|
{/* Editor Toolbar - Conditional based on variant */}
|
|
419
481
|
{variant === HTML_EDITOR_VARIANTS.EMAIL ? (
|
|
420
482
|
<EditorToolbar
|
|
421
|
-
showFullscreenButton
|
|
483
|
+
showFullscreenButton // Show fullscreen button in modal to allow closing
|
|
422
484
|
onLabelInsert={handleLabelInsert}
|
|
423
485
|
onSave={handleSave}
|
|
424
|
-
isFullscreenMode
|
|
486
|
+
isFullscreenMode
|
|
425
487
|
onToggleFullscreen={handleCloseFullscreen} // Close modal when clicked in fullscreen mode
|
|
426
488
|
/>
|
|
427
489
|
) : (
|
|
@@ -434,10 +496,10 @@ const HTMLEditor = ({
|
|
|
434
496
|
onKeepContentSameChange={toggleContentSync}
|
|
435
497
|
/>
|
|
436
498
|
<EditorToolbar
|
|
437
|
-
showFullscreenButton
|
|
499
|
+
showFullscreenButton // Show fullscreen button in modal to allow closing
|
|
438
500
|
onLabelInsert={handleLabelInsert}
|
|
439
501
|
onSave={handleSave}
|
|
440
|
-
isFullscreenMode
|
|
502
|
+
isFullscreenMode
|
|
441
503
|
onToggleFullscreen={handleCloseFullscreen} // Close modal when clicked in fullscreen mode
|
|
442
504
|
variant={variant}
|
|
443
505
|
showTitle={false} // Hide title in InApp variant
|
|
@@ -452,21 +514,27 @@ const HTMLEditor = ({
|
|
|
452
514
|
<CodeEditorPane
|
|
453
515
|
ref={modalEditorRef}
|
|
454
516
|
readOnly={readOnly}
|
|
455
|
-
isFullscreenMode
|
|
517
|
+
isFullscreenMode
|
|
456
518
|
onLabelInsert={handleLabelInsert}
|
|
519
|
+
tags={tags}
|
|
520
|
+
injectedTags={injectedTags}
|
|
521
|
+
location={location}
|
|
522
|
+
selectedOfferDetails={selectedOfferDetails}
|
|
523
|
+
onTagSelect={onTagSelect}
|
|
524
|
+
onContextChange={handleContextChange}
|
|
457
525
|
/>
|
|
458
526
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
527
|
+
{/* Preview Pane */}
|
|
528
|
+
<PreviewPane isFullscreenMode isModalContext />
|
|
529
|
+
</SplitContainer>
|
|
462
530
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
531
|
+
{/* Validation Display in Modal */}
|
|
532
|
+
<ValidationErrorDisplay
|
|
533
|
+
validation={validation}
|
|
534
|
+
onErrorClick={handleValidationErrorClick}
|
|
535
|
+
variant={variant}
|
|
536
|
+
className="html-editor-validation"
|
|
537
|
+
/>
|
|
470
538
|
</CapRow>
|
|
471
539
|
</CapRow>
|
|
472
540
|
</CapModal>
|
|
@@ -481,7 +549,7 @@ HTMLEditor.propTypes = {
|
|
|
481
549
|
layoutType: PropTypes.string, // Layout type for InApp variant
|
|
482
550
|
initialContent: PropTypes.oneOfType([
|
|
483
551
|
PropTypes.string,
|
|
484
|
-
PropTypes.objectOf(PropTypes.string) // Per-device content for INAPP variant
|
|
552
|
+
PropTypes.objectOf(PropTypes.string), // Per-device content for INAPP variant
|
|
485
553
|
]),
|
|
486
554
|
onSave: PropTypes.func,
|
|
487
555
|
onContentChange: PropTypes.func,
|
|
@@ -489,11 +557,20 @@ HTMLEditor.propTypes = {
|
|
|
489
557
|
readOnly: PropTypes.bool,
|
|
490
558
|
showFullscreenButton: PropTypes.bool,
|
|
491
559
|
autoSave: PropTypes.bool,
|
|
492
|
-
autoSaveInterval: PropTypes.number
|
|
560
|
+
autoSaveInterval: PropTypes.number,
|
|
561
|
+
// Tags-related props
|
|
562
|
+
tags: PropTypes.array,
|
|
563
|
+
injectedTags: PropTypes.object,
|
|
564
|
+
location: PropTypes.object,
|
|
565
|
+
selectedOfferDetails: PropTypes.any,
|
|
566
|
+
onTagSelect: PropTypes.func,
|
|
567
|
+
onContextChange: PropTypes.func, // Deprecated: use globalActions instead
|
|
568
|
+
globalActions: PropTypes.object, // Redux actions for API calls
|
|
493
569
|
};
|
|
494
570
|
|
|
495
571
|
HTMLEditor.defaultProps = {
|
|
496
572
|
variant: HTML_EDITOR_VARIANTS.EMAIL, // Default to email variant
|
|
573
|
+
layoutType: null, // Layout type for InApp variant
|
|
497
574
|
initialContent: null, // Will use default from useEditorContent hook
|
|
498
575
|
onSave: null,
|
|
499
576
|
onContentChange: null,
|
|
@@ -501,7 +578,15 @@ HTMLEditor.defaultProps = {
|
|
|
501
578
|
readOnly: false,
|
|
502
579
|
showFullscreenButton: true,
|
|
503
580
|
autoSave: true,
|
|
504
|
-
autoSaveInterval: 30000
|
|
581
|
+
autoSaveInterval: 30000,
|
|
582
|
+
// Tags-related props defaults
|
|
583
|
+
tags: [],
|
|
584
|
+
injectedTags: {},
|
|
585
|
+
location: {},
|
|
586
|
+
selectedOfferDetails: null,
|
|
587
|
+
onTagSelect: null,
|
|
588
|
+
onContextChange: null,
|
|
589
|
+
globalActions: null,
|
|
505
590
|
};
|
|
506
591
|
|
|
507
592
|
// Export with forwardRef to allow direct access to CodeEditorPane via ref
|