@capillarytech/creatives-library 8.0.213 → 8.0.214-beta.0
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/HOW_BEE_EDITOR_WORKS.md +375 -0
- package/constants/unified.js +1 -0
- package/package.json +1 -1
- package/services/api.js +5 -0
- package/utils/common.js +6 -1
- package/v2Components/CapTagList/index.js +2 -1
- package/v2Components/CapTagListWithInput/index.js +5 -1
- package/v2Components/CapTagListWithInput/messages.js +1 -1
- package/v2Components/ErrorInfoNote/style.scss +1 -1
- package/v2Components/HtmlEditor/HTMLEditor.js +86 -14
- package/v2Components/HtmlEditor/_htmlEditor.scss +4 -4
- package/v2Components/HtmlEditor/_index.lazy.scss +1 -1
- package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +107 -96
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +68 -92
- package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
- package/v2Components/HtmlEditor/hooks/useEditorContent.js +5 -2
- package/v2Containers/CreativesContainer/SlideBoxContent.js +85 -35
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +9 -3
- package/v2Containers/CreativesContainer/index.js +107 -35
- package/v2Containers/CreativesContainer/messages.js +4 -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 +17 -0
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +1005 -0
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +193 -7
- package/v2Containers/EmailWrapper/constants.js +2 -0
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +470 -71
- package/v2Containers/EmailWrapper/index.js +102 -23
- package/v2Containers/EmailWrapper/messages.js +61 -1
- package/v2Containers/EmailWrapper/tests/EmailHTMLEditor.test.js +177 -0
- package/v2Containers/EmailWrapper/tests/EmailHTMLEditorValidation.test.js +90 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +49 -49
- package/v2Containers/TagList/index.js +2 -0
- package/v2Containers/Templates/index.js +5 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useRef, useCallback } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import { FormattedMessage } from 'react-intl';
|
|
4
4
|
import styled from 'styled-components';
|
|
@@ -11,10 +11,15 @@ import CapSpin from '@capillarytech/cap-ui-library/CapSpin';
|
|
|
11
11
|
import CapButton from '@capillarytech/cap-ui-library/CapButton';
|
|
12
12
|
import CapError from '@capillarytech/cap-ui-library/CapError';
|
|
13
13
|
import ComponentWithLabelHOC from '@capillarytech/cap-ui-library/assets/HOCs/ComponentWithLabelHOC';
|
|
14
|
-
import
|
|
14
|
+
import { CAP_COLOR_06, CAP_WHITE } from '@capillarytech/cap-ui-library/styled/variables';
|
|
15
|
+
import { EmailWithoutSaga } from '../../Email';
|
|
15
16
|
import CmsTemplatesComponent from '../../../v2Components/CmsTemplatesComponent';
|
|
17
|
+
import EmailHTMLEditor from './EmailHTMLEditor';
|
|
18
|
+
import TestAndPreviewSlidebox from '../../../v2Components/TestAndPreviewSlidebox';
|
|
19
|
+
import { EMAIL } from '../../CreativesContainer/constants';
|
|
16
20
|
import messages from '../messages';
|
|
17
21
|
import { EMAIL_CREATE_MODES, STEPS } from '../constants';
|
|
22
|
+
import { hasSupportCKEditor } from '../../../utils/common';
|
|
18
23
|
|
|
19
24
|
const CapRadioCardWithLabel = ComponentWithLabelHOC(CapRadioCard);
|
|
20
25
|
|
|
@@ -27,9 +32,23 @@ const CardContainer = styled.div`
|
|
|
27
32
|
}
|
|
28
33
|
}
|
|
29
34
|
}
|
|
35
|
+
|
|
36
|
+
.ant-radio-group.cap-radioCard-v2 {
|
|
37
|
+
.ant-radio-button-wrapper {
|
|
38
|
+
&.ant-radio-button-wrapper-checked {
|
|
39
|
+
.icon-container {
|
|
40
|
+
background-color: ${CAP_COLOR_06};
|
|
41
|
+
.anticon,
|
|
42
|
+
.cap-icon {
|
|
43
|
+
color: ${CAP_WHITE};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
30
49
|
`;
|
|
31
50
|
|
|
32
|
-
// Mode selection component
|
|
51
|
+
// Mode selection component
|
|
33
52
|
const ModeSelectionUI = ({
|
|
34
53
|
isFullMode,
|
|
35
54
|
templateName,
|
|
@@ -51,7 +70,7 @@ const ModeSelectionUI = ({
|
|
|
51
70
|
value={templateName}
|
|
52
71
|
labelPosition="top"
|
|
53
72
|
size="default"
|
|
54
|
-
style={{ width: '68%'}}
|
|
73
|
+
style={{ width: '68%' }}
|
|
55
74
|
/>
|
|
56
75
|
)}
|
|
57
76
|
<CardContainer>
|
|
@@ -98,15 +117,21 @@ ModeSelectionUI.propTypes = {
|
|
|
98
117
|
uploadButtonLabel: PropTypes.node.isRequired,
|
|
99
118
|
};
|
|
100
119
|
|
|
101
|
-
// Content creation component
|
|
120
|
+
// Content creation component
|
|
102
121
|
const ContentCreationUI = ({
|
|
103
122
|
isShowEmailCreate,
|
|
104
123
|
emailProps,
|
|
105
124
|
cmsTemplatesProps,
|
|
125
|
+
isHTMLEditorMode,
|
|
126
|
+
htmlEditorProps,
|
|
106
127
|
}) => (
|
|
107
128
|
<>
|
|
108
129
|
{isShowEmailCreate ? (
|
|
109
|
-
|
|
130
|
+
isHTMLEditorMode ? (
|
|
131
|
+
<EmailHTMLEditor {...htmlEditorProps} />
|
|
132
|
+
) : (
|
|
133
|
+
<EmailWithoutSaga {...emailProps} />
|
|
134
|
+
)
|
|
110
135
|
) : (
|
|
111
136
|
<CmsTemplatesComponent {...cmsTemplatesProps} />
|
|
112
137
|
)}
|
|
@@ -117,6 +142,8 @@ ContentCreationUI.propTypes = {
|
|
|
117
142
|
isShowEmailCreate: PropTypes.bool.isRequired,
|
|
118
143
|
emailProps: PropTypes.object.isRequired,
|
|
119
144
|
cmsTemplatesProps: PropTypes.object.isRequired,
|
|
145
|
+
isHTMLEditorMode: PropTypes.bool,
|
|
146
|
+
htmlEditorProps: PropTypes.object,
|
|
120
147
|
};
|
|
121
148
|
|
|
122
149
|
// Main EmailWrapper presentational component
|
|
@@ -137,9 +164,130 @@ const EmailWrapperView = ({
|
|
|
137
164
|
isShowEmailCreate,
|
|
138
165
|
emailProps,
|
|
139
166
|
cmsTemplatesProps,
|
|
167
|
+
metaEntities,
|
|
168
|
+
loadingTags,
|
|
169
|
+
injectedTags,
|
|
170
|
+
globalActions,
|
|
171
|
+
supportedTags,
|
|
172
|
+
getDefaultTags,
|
|
173
|
+
location,
|
|
174
|
+
currentOrgDetails,
|
|
175
|
+
forwardedTags,
|
|
176
|
+
selectedOfferDetails,
|
|
177
|
+
eventContextTags,
|
|
178
|
+
getFormdata,
|
|
179
|
+
isGetFormData,
|
|
180
|
+
getLiquidTags,
|
|
181
|
+
showLiquidErrorInFooter,
|
|
182
|
+
onValidationFail,
|
|
183
|
+
emailActions,
|
|
184
|
+
Email,
|
|
185
|
+
templateData: templateDataProp,
|
|
186
|
+
params,
|
|
187
|
+
fetchingLiquidTags,
|
|
188
|
+
createTemplateInProgress,
|
|
189
|
+
fetchingCmsData,
|
|
190
|
+
setIsLoadingContent,
|
|
191
|
+
showTestAndPreviewSlidebox,
|
|
192
|
+
handleCloseTestAndPreview,
|
|
193
|
+
showTemplateName,
|
|
140
194
|
}) => {
|
|
195
|
+
const htmlEditorRef = useRef(null);
|
|
196
|
+
const supportCKEditor = hasSupportCKEditor();
|
|
197
|
+
const hasParamsIdForEditor = params?.id || location?.query?.id || location?.params?.id || location?.pathname?.includes('/edit/');
|
|
198
|
+
const isEditModeForEditor = hasParamsIdForEditor;
|
|
199
|
+
const isBEEFromProps = emailProps?.editor === 'BEE' && emailProps?.selectedEditorMode === null;
|
|
200
|
+
const isDragDropFromCreateMode = emailCreateMode === EMAIL_CREATE_MODES.DRAG_DROP;
|
|
201
|
+
const isExplicitlyBEEEditor = isBEEFromProps || isDragDropFromCreateMode;
|
|
202
|
+
let isHTMLEditorMode = false;
|
|
141
203
|
|
|
142
|
-
|
|
204
|
+
if (supportCKEditor) {
|
|
205
|
+
isHTMLEditorMode = false; // Legacy flow: use Email component
|
|
206
|
+
} else if (isEditModeForEditor) {
|
|
207
|
+
isHTMLEditorMode = !isExplicitlyBEEEditor;
|
|
208
|
+
} else {
|
|
209
|
+
if (isExplicitlyBEEEditor || isBEEFromProps || isDragDropFromCreateMode) {
|
|
210
|
+
isHTMLEditorMode = false;
|
|
211
|
+
} else {
|
|
212
|
+
isHTMLEditorMode = emailProps?.selectedEditorMode === EMAIL_CREATE_MODES.HTML_EDITOR ||
|
|
213
|
+
emailCreateMode === EMAIL_CREATE_MODES.HTML_EDITOR;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const isShowTemplateSelection = step === STEPS.MODE_SELECTION;
|
|
218
|
+
|
|
219
|
+
// Create onFormDataChange callback for template name updates (similar to Email component)
|
|
220
|
+
// This allows CreativesContainer to update the template name when user clicks "Edit name"
|
|
221
|
+
// When user edits the name in CreativesContainer header, it calls this callback
|
|
222
|
+
// which updates the template name in EmailWrapper, and then CreativesContainer
|
|
223
|
+
// will call showTemplateName again with the updated formData
|
|
224
|
+
const handleFormDataChange = useCallback((updatedFormData) => {
|
|
225
|
+
const newTemplateName = updatedFormData?.['template-name'] || templateName;
|
|
226
|
+
if (newTemplateName !== templateName && onTemplateNameChange) {
|
|
227
|
+
// Update template name in parent (useEmailWrapper hook)
|
|
228
|
+
onTemplateNameChange({ target: { value: newTemplateName } });
|
|
229
|
+
}
|
|
230
|
+
// Note: CreativesContainer will call showTemplateName again after this callback
|
|
231
|
+
// (it stores the callback in templateContainerDetails and calls it after state updates)
|
|
232
|
+
}, [templateName, onTemplateNameChange]);
|
|
233
|
+
|
|
234
|
+
const htmlEditorProps = isHTMLEditorMode ? {
|
|
235
|
+
// Location and params
|
|
236
|
+
location,
|
|
237
|
+
params,
|
|
238
|
+
// Tag-related props
|
|
239
|
+
getDefaultTags,
|
|
240
|
+
supportedTags,
|
|
241
|
+
metaEntities,
|
|
242
|
+
injectedTags,
|
|
243
|
+
globalActions,
|
|
244
|
+
loadingTags,
|
|
245
|
+
eventContextTags,
|
|
246
|
+
forwardedTags,
|
|
247
|
+
selectedOfferDetails,
|
|
248
|
+
currentOrgDetails,
|
|
249
|
+
// Email Redux state and actions
|
|
250
|
+
Email,
|
|
251
|
+
emailActions,
|
|
252
|
+
// Full mode props
|
|
253
|
+
isFullMode,
|
|
254
|
+
templateName,
|
|
255
|
+
isGetFormData,
|
|
256
|
+
getFormdata,
|
|
257
|
+
// Library mode props
|
|
258
|
+
templateData: templateDataProp,
|
|
259
|
+
// Uploaded content from zip file
|
|
260
|
+
EmailLayout,
|
|
261
|
+
// Liquid validation
|
|
262
|
+
getLiquidTags,
|
|
263
|
+
showLiquidErrorInFooter,
|
|
264
|
+
onValidationFail,
|
|
265
|
+
// Template name
|
|
266
|
+
showTemplateName,
|
|
267
|
+
onFormDataChange: handleFormDataChange,
|
|
268
|
+
// Loading states
|
|
269
|
+
fetchingLiquidTags: fetchingLiquidTags || false,
|
|
270
|
+
createTemplateInProgress: createTemplateInProgress || false,
|
|
271
|
+
fetchingCmsData: fetchingCmsData || false,
|
|
272
|
+
// Parent loading control
|
|
273
|
+
setIsLoadingContent,
|
|
274
|
+
ref: htmlEditorRef,
|
|
275
|
+
} : {};
|
|
276
|
+
|
|
277
|
+
// Get formData for TestAndPreviewSlidebox when needed
|
|
278
|
+
const getFormDataForPreview = () => {
|
|
279
|
+
if (htmlEditorRef.current && htmlEditorRef.current.getFormDataForPreview) {
|
|
280
|
+
return htmlEditorRef.current.getFormDataForPreview();
|
|
281
|
+
}
|
|
282
|
+
return {};
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const getContentForPreview = () => {
|
|
286
|
+
if (htmlEditorRef.current && htmlEditorRef.current.getContentForPreview) {
|
|
287
|
+
return htmlEditorRef.current.getContentForPreview();
|
|
288
|
+
}
|
|
289
|
+
return '';
|
|
290
|
+
};
|
|
143
291
|
|
|
144
292
|
return (
|
|
145
293
|
<>
|
|
@@ -163,9 +311,22 @@ const EmailWrapperView = ({
|
|
|
163
311
|
isShowEmailCreate={isShowEmailCreate}
|
|
164
312
|
emailProps={emailProps}
|
|
165
313
|
cmsTemplatesProps={cmsTemplatesProps}
|
|
314
|
+
isHTMLEditorMode={isHTMLEditorMode}
|
|
315
|
+
htmlEditorProps={htmlEditorProps}
|
|
166
316
|
/>
|
|
167
317
|
)}
|
|
168
318
|
</CapSpin>
|
|
319
|
+
{/* Render TestAndPreviewSlidebox for HTML Editor (similar to legacy Email component) */}
|
|
320
|
+
{isHTMLEditorMode && showTestAndPreviewSlidebox && (
|
|
321
|
+
<TestAndPreviewSlidebox
|
|
322
|
+
show={showTestAndPreviewSlidebox}
|
|
323
|
+
onClose={handleCloseTestAndPreview}
|
|
324
|
+
formData={getFormDataForPreview()}
|
|
325
|
+
content={getContentForPreview()}
|
|
326
|
+
currentChannel={EMAIL}
|
|
327
|
+
currentTab={1}
|
|
328
|
+
/>
|
|
329
|
+
)}
|
|
169
330
|
</>
|
|
170
331
|
);
|
|
171
332
|
};
|
|
@@ -175,6 +336,10 @@ EmailWrapperView.propTypes = {
|
|
|
175
336
|
emailCreateMode: PropTypes.string,
|
|
176
337
|
step: PropTypes.string,
|
|
177
338
|
isFullMode: PropTypes.bool,
|
|
339
|
+
getFormdata: PropTypes.func,
|
|
340
|
+
isGetFormData: PropTypes.bool,
|
|
341
|
+
getLiquidTags: PropTypes.func,
|
|
342
|
+
showLiquidErrorInFooter: PropTypes.func,
|
|
178
343
|
templateName: PropTypes.string,
|
|
179
344
|
onTemplateNameChange: PropTypes.func.isRequired,
|
|
180
345
|
isTemplateNameEmpty: PropTypes.bool,
|
|
@@ -187,6 +352,27 @@ EmailWrapperView.propTypes = {
|
|
|
187
352
|
isShowEmailCreate: PropTypes.bool.isRequired,
|
|
188
353
|
emailProps: PropTypes.object.isRequired,
|
|
189
354
|
cmsTemplatesProps: PropTypes.object.isRequired,
|
|
355
|
+
metaEntities: PropTypes.object,
|
|
356
|
+
loadingTags: PropTypes.bool,
|
|
357
|
+
injectedTags: PropTypes.object,
|
|
358
|
+
globalActions: PropTypes.object,
|
|
359
|
+
supportedTags: PropTypes.array,
|
|
360
|
+
getDefaultTags: PropTypes.string,
|
|
361
|
+
location: PropTypes.object,
|
|
362
|
+
currentOrgDetails: PropTypes.object,
|
|
363
|
+
forwardedTags: PropTypes.object,
|
|
364
|
+
selectedOfferDetails: PropTypes.array,
|
|
365
|
+
eventContextTags: PropTypes.array,
|
|
366
|
+
emailActions: PropTypes.object,
|
|
367
|
+
Email: PropTypes.object,
|
|
368
|
+
templateData: PropTypes.object,
|
|
369
|
+
params: PropTypes.object,
|
|
370
|
+
fetchingLiquidTags: PropTypes.bool,
|
|
371
|
+
createTemplateInProgress: PropTypes.bool,
|
|
372
|
+
fetchingCmsData: PropTypes.bool,
|
|
373
|
+
setIsLoadingContent: PropTypes.func,
|
|
374
|
+
showTestAndPreviewSlidebox: PropTypes.bool,
|
|
375
|
+
handleCloseTestAndPreview: PropTypes.func,
|
|
190
376
|
};
|
|
191
377
|
|
|
192
378
|
export default EmailWrapperView;
|