@capillarytech/creatives-library 8.0.276 → 8.0.277
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/package.json +1 -1
- package/utils/tests/imageUrlUpload.test.js +298 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +2 -0
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +5 -2
- package/v2Containers/CreativesContainer/index.js +10 -6
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +165 -41
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +6 -0
- package/v2Containers/Email/index.js +75 -9
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +9 -4
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +6 -2
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +143 -1
- package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +137 -0
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +7 -3
- package/v2Containers/EmailWrapper/index.js +3 -0
- package/v2Containers/Facebook/Advertisement/index.js +1 -1
- package/v2Containers/Line/Container/_lineCreate.scss +1 -0
- package/v2Containers/Line/Container/style.js +1 -1
- package/v2Containers/MobilePush/Edit/index.js +6 -5
- package/v2Containers/SmsTrai/Create/index.scss +1 -1
- package/v2Containers/SmsTrai/Edit/index.js +9 -3
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +11682 -86
- package/v2Containers/SmsTrai/Edit/tests/index.test.js +5 -0
- package/v2Containers/Viber/index.js +7 -0
- package/v2Containers/Viber/index.scss +4 -1
- package/v2Containers/Viber/style.js +0 -2
|
@@ -26,7 +26,7 @@ import * as globalActions from '../Cap/actions';
|
|
|
26
26
|
import './_email.scss';
|
|
27
27
|
import {getMessageObject} from '../../utils/messageUtils';
|
|
28
28
|
import EmailPreview from '../../v2Components/EmailPreview';
|
|
29
|
-
import { getDecodedFileName ,
|
|
29
|
+
import { getDecodedFileName, hasLiquidSupportFeature, hasSupportCKEditor } from '../../utils/common';
|
|
30
30
|
import Pagination from '../../v2Components/Pagination';
|
|
31
31
|
import * as creativesContainerActions from '../CreativesContainer/actions';
|
|
32
32
|
import withCreatives from '../../hoc/withCreatives';
|
|
@@ -95,6 +95,8 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
95
95
|
|
|
96
96
|
this.isTagLoaded = false;
|
|
97
97
|
this.edmEvent = undefined;
|
|
98
|
+
// When schema is set after CmsSettings (e.g. library create BEE), allow BEE init to run once
|
|
99
|
+
this.schemaJustFilledForBee = false;
|
|
98
100
|
this.supportedLanguages = this.getSupportedLanguages(props);
|
|
99
101
|
this.map = {
|
|
100
102
|
"template-name": {
|
|
@@ -235,7 +237,12 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
235
237
|
this.props.actions.getCmsSetting(BEE_PLUGIN, dragDropId, 'create', undefined, isBEESupport, isBEEAppEnable);
|
|
236
238
|
}
|
|
237
239
|
}
|
|
238
|
-
|
|
240
|
+
const hasUploadedContent = !this.props.params?.id && this.props.Templates?.selectedEmailLayout && !_.isEmpty(formData);
|
|
241
|
+
this.setState({
|
|
242
|
+
content: (this.props.Templates.selectedEmailLayout ? this.props.Templates.selectedEmailLayout : ''),
|
|
243
|
+
formData,
|
|
244
|
+
...(hasUploadedContent ? { loadingStatus: 2 } : {}),
|
|
245
|
+
});
|
|
239
246
|
|
|
240
247
|
// setTimeout(() => {
|
|
241
248
|
// // this.getFormData();
|
|
@@ -286,6 +293,12 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
286
293
|
}
|
|
287
294
|
}
|
|
288
295
|
}
|
|
296
|
+
|
|
297
|
+
// When SUPPORT_CK_EDITOR: after zip/HTML upload we show with selectedEmailLayout. Ensure spinner stops
|
|
298
|
+
// even if formData was empty on first mount (e.g. currentOrgDetails not yet available).
|
|
299
|
+
if (!this.props.params?.id && this.props.Templates?.selectedEmailLayout) {
|
|
300
|
+
this.setState((prev) => ({ loadingStatus: Math.max(prev.loadingStatus, 2) }));
|
|
301
|
+
}
|
|
289
302
|
}
|
|
290
303
|
|
|
291
304
|
|
|
@@ -313,11 +326,10 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
313
326
|
// }
|
|
314
327
|
const {isFullMode, isGetFormData} = nextProps;
|
|
315
328
|
if (isFullMode && isGetFormData && !_.isEqual(isGetFormData, this.props.isGetFormData) && !this.state.isDragDrop) {
|
|
316
|
-
//
|
|
317
|
-
//
|
|
318
|
-
// Don't start validation if we're in Test & Preview mode
|
|
329
|
+
// Only for CK editor: when Done is clicked in full mode, trigger the same chain as library
|
|
330
|
+
// so that FormBuilder validation and saveFormData run reliably (getFormData -> saveValidationData -> startValidation).
|
|
319
331
|
if (!nextProps.isTestAndPreviewMode) {
|
|
320
|
-
this.
|
|
332
|
+
this.getFormData();
|
|
321
333
|
}
|
|
322
334
|
}
|
|
323
335
|
if (this.state.languageDataSet && nextProps.Templates.selectedEmailLayout && nextProps.Templates.selectedEmailLayout !== '' && !_.isEqual(this.props.Templates.selectedEmailLayout, nextProps.Templates.selectedEmailLayout )) {
|
|
@@ -325,7 +337,9 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
325
337
|
}
|
|
326
338
|
if (nextProps.metaEntities && nextProps.metaEntities.layouts && nextProps.metaEntities.layouts.length > 0 && _.isEmpty(this.state.schema)) {
|
|
327
339
|
const newSchema = this.injectEvents(nextProps.metaEntities.layouts[0].definition);
|
|
328
|
-
|
|
340
|
+
this.applyTabOptionIconVisibility(newSchema);
|
|
341
|
+
// So BEE init can run when CmsSettings already arrived (e.g. library create after default template selected)
|
|
342
|
+
this.schemaJustFilledForBee = true;
|
|
329
343
|
this.setState({schema: newSchema, loadingStatus: this.state.loadingStatus + 1});
|
|
330
344
|
if (this.props.location.query.module !== 'library' || (this.props.location.query.module === 'library' && this.props.getDefaultTags)) {
|
|
331
345
|
const query = {
|
|
@@ -487,7 +501,11 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
487
501
|
}
|
|
488
502
|
}
|
|
489
503
|
|
|
490
|
-
|
|
504
|
+
const cmsSettingsChanged = !_.isEqual(this.props.Email.CmsSettings, nextProps.Email.CmsSettings);
|
|
505
|
+
const hasCmsSettingsAndSchema = !_.isEmpty(nextProps.Email.CmsSettings) && !_.isEmpty(this.state.schema);
|
|
506
|
+
const shouldRunBeeInit = hasCmsSettingsAndSchema && (cmsSettingsChanged || this.schemaJustFilledForBee);
|
|
507
|
+
if (shouldRunBeeInit) {
|
|
508
|
+
this.schemaJustFilledForBee = false;
|
|
491
509
|
const apiLangId = nextProps.Email.CmsSettings.langId;
|
|
492
510
|
const langId = nextProps.Email.CmsSettings.langId !== "undefined" ? nextProps.Email.CmsSettings.langId : nextProps.currentOrgDetails.basic_details.base_language;
|
|
493
511
|
|
|
@@ -1560,7 +1578,12 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
1560
1578
|
newFormData[0] = baseData;
|
|
1561
1579
|
newFormData[0].base = true;
|
|
1562
1580
|
}
|
|
1563
|
-
|
|
1581
|
+
// Don't clear selectedEmailLayout when we're in create mode with uploaded content -
|
|
1582
|
+
// EmailWrapper uses it to keep isShowEmailCreate true. Clearing it would unmount Email and show wrong UI.
|
|
1583
|
+
const isCreateWithUpload = !props.params?.id && props.Templates?.selectedEmailLayout;
|
|
1584
|
+
if (!isCreateWithUpload) {
|
|
1585
|
+
this.props.templatesActions.resetUploadData();
|
|
1586
|
+
}
|
|
1564
1587
|
return newFormData;
|
|
1565
1588
|
}
|
|
1566
1589
|
|
|
@@ -1752,6 +1775,16 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
1752
1775
|
newTabPopoverSection.cols[0].style.display = isDragDrop ? "" : "none";
|
|
1753
1776
|
}
|
|
1754
1777
|
});
|
|
1778
|
+
// Hide tab-option-icon (switch editor trigger) when SUPPORT_CK_EDITOR is disabled
|
|
1779
|
+
if (containerInputFieldCol.value && containerInputFieldCol.value.sections) {
|
|
1780
|
+
_.forEach(containerInputFieldCol.value.sections[0].inputFields, (valueInputField) => {
|
|
1781
|
+
_.forEach(valueInputField.cols, (valueCol) => {
|
|
1782
|
+
if (valueCol.id === 'tab-option-icon') {
|
|
1783
|
+
valueCol.colStyle = { ...valueCol.colStyle, display: hasSupportCKEditor() ? 'flex' : 'none' };
|
|
1784
|
+
}
|
|
1785
|
+
});
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1755
1788
|
}
|
|
1756
1789
|
});
|
|
1757
1790
|
}
|
|
@@ -1760,6 +1793,28 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
1760
1793
|
this.setState({schema, isSchemaChanged: true});
|
|
1761
1794
|
}
|
|
1762
1795
|
|
|
1796
|
+
/**
|
|
1797
|
+
* Hides the tab-option-icon (switch editor trigger) in schema when SUPPORT_CK_EDITOR is disabled,
|
|
1798
|
+
* so users cannot switch editor if the feature is not enabled.
|
|
1799
|
+
*/
|
|
1800
|
+
applyTabOptionIconVisibility = (schema) => {
|
|
1801
|
+
if (!schema || !schema.containers) return;
|
|
1802
|
+
_.forEach(schema.containers, (container) => {
|
|
1803
|
+
if (!container.isActive || !container.tabBarExtraContent?.sections?.[0]?.inputFields?.[0]?.cols) return;
|
|
1804
|
+
_.forEach(container.tabBarExtraContent.sections[0].inputFields[0].cols, (col) => {
|
|
1805
|
+
if (col.id === 'tab-options-popover' && col.value?.sections?.[0]?.inputFields) {
|
|
1806
|
+
_.forEach(col.value.sections[0].inputFields, (inputField) => {
|
|
1807
|
+
_.forEach(inputField.cols, (c) => {
|
|
1808
|
+
if (c.id === 'tab-option-icon') {
|
|
1809
|
+
c.colStyle = { ...(c.colStyle || {}), display: hasSupportCKEditor() ? 'flex' : 'none' };
|
|
1810
|
+
}
|
|
1811
|
+
});
|
|
1812
|
+
});
|
|
1813
|
+
}
|
|
1814
|
+
});
|
|
1815
|
+
});
|
|
1816
|
+
};
|
|
1817
|
+
|
|
1763
1818
|
showInsertImageButton = (passedSchema) => {
|
|
1764
1819
|
const schema = passedSchema || _.cloneDeep(this.state.schema);
|
|
1765
1820
|
_.forEach(schema.containers, (container) => {
|
|
@@ -2869,6 +2924,17 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
2869
2924
|
if (!isLoading) {
|
|
2870
2925
|
isLoading = this.state.loadingStatus < 2;
|
|
2871
2926
|
}
|
|
2927
|
+
|
|
2928
|
+
// When SUPPORT_CK_EDITOR: after zip/HTML upload we show Email component with selectedEmailLayout.
|
|
2929
|
+
// Don't show spinner once we have uploaded content in formData (create mode, no params.id).
|
|
2930
|
+
if (isLoading && !this.props.params?.id && this.props.Templates?.selectedEmailLayout) {
|
|
2931
|
+
const content = this.state.formData?.[0]?.['template-content']
|
|
2932
|
+
|| _.get(this.state.formData, 'base.template-content')
|
|
2933
|
+
|| (this.state.formData?.base && this.state.formData.base[this.state.formData.base?.activeTab]?.['template-content']);
|
|
2934
|
+
if (content) {
|
|
2935
|
+
isLoading = false;
|
|
2936
|
+
}
|
|
2937
|
+
}
|
|
2872
2938
|
// if (isLoading) {
|
|
2873
2939
|
// this.props.creativesContainerActions.hideCreativesContanerLoader();
|
|
2874
2940
|
// }
|
|
@@ -73,6 +73,7 @@ const EmailHTMLEditor = (props) => {
|
|
|
73
73
|
getFormdata,
|
|
74
74
|
// Library mode props
|
|
75
75
|
templateData: templateDataProp,
|
|
76
|
+
isEditEmail = true,
|
|
76
77
|
// Uploaded content from zip file
|
|
77
78
|
EmailLayout,
|
|
78
79
|
// Liquid validation
|
|
@@ -174,11 +175,13 @@ const EmailHTMLEditor = (props) => {
|
|
|
174
175
|
// Check if liquid support is enabled
|
|
175
176
|
const isLiquidEnabled = hasLiquidSupportFeature();
|
|
176
177
|
|
|
177
|
-
// Detect edit mode
|
|
178
|
+
// Detect edit mode: when isEditEmail is false (create flow), never treat as edit or fetch template details
|
|
178
179
|
const hasParamsId = params?.id || location?.query?.id || location?.params?.id || location?.pathname?.includes('/edit/');
|
|
179
|
-
const currentTemplateId =
|
|
180
|
-
|| location?.
|
|
181
|
-
|
|
180
|
+
const currentTemplateId = isEditEmail
|
|
181
|
+
? (templateDataProp?._id || params?.id || location?.query?.id || location?.params?.id
|
|
182
|
+
|| location?.pathname?.match(/\/edit\/([^/]+)/)?.[1])
|
|
183
|
+
: (params?.id || location?.query?.id || location?.params?.id || location?.pathname?.match(/\/edit\/([^/]+)/)?.[1]);
|
|
184
|
+
const isEditMode = isEditEmail && (!!currentTemplateId || !!hasParamsId);
|
|
182
185
|
|
|
183
186
|
// Load tags on component mount
|
|
184
187
|
useEffect(() => {
|
|
@@ -1204,6 +1207,7 @@ EmailHTMLEditor.propTypes = {
|
|
|
1204
1207
|
onValidationFail: PropTypes.func,
|
|
1205
1208
|
moduleType: PropTypes.string,
|
|
1206
1209
|
onHtmlEditorValidationStateChange: PropTypes.func,
|
|
1210
|
+
isEditEmail: PropTypes.bool,
|
|
1207
1211
|
};
|
|
1208
1212
|
|
|
1209
1213
|
EmailHTMLEditor.defaultProps = {
|
|
@@ -1239,6 +1243,7 @@ EmailHTMLEditor.defaultProps = {
|
|
|
1239
1243
|
onValidationFail: null,
|
|
1240
1244
|
moduleType: null,
|
|
1241
1245
|
onHtmlEditorValidationStateChange: null,
|
|
1246
|
+
isEditEmail: true,
|
|
1242
1247
|
};
|
|
1243
1248
|
|
|
1244
1249
|
const EmailHTMLEditorWithIntl = injectIntl(EmailHTMLEditor);
|
|
@@ -182,6 +182,7 @@ const EmailWrapperView = ({
|
|
|
182
182
|
Email,
|
|
183
183
|
templateData: templateDataProp,
|
|
184
184
|
params,
|
|
185
|
+
isEditEmail = true,
|
|
185
186
|
fetchingLiquidTags,
|
|
186
187
|
createTemplateInProgress,
|
|
187
188
|
fetchingCmsData,
|
|
@@ -202,8 +203,9 @@ const EmailWrapperView = ({
|
|
|
202
203
|
let isHTMLEditorMode = false;
|
|
203
204
|
|
|
204
205
|
if (supportCKEditor) {
|
|
205
|
-
//
|
|
206
|
-
|
|
206
|
+
// UPLOAD mode should use Email component (CKEditor), NOT HTML editor
|
|
207
|
+
// This ensures consistency between create and edit flows when SUPPORT_CK_EDITOR is enabled
|
|
208
|
+
isHTMLEditorMode = false; // Always use Email component (CKEditor) in legacy flow
|
|
207
209
|
} else if (isEditModeForEditor) {
|
|
208
210
|
isHTMLEditorMode = !isExplicitlyBEEEditor;
|
|
209
211
|
} else {
|
|
@@ -257,6 +259,7 @@ const EmailWrapperView = ({
|
|
|
257
259
|
getFormdata,
|
|
258
260
|
// Library mode props
|
|
259
261
|
templateData: templateDataProp,
|
|
262
|
+
isEditEmail,
|
|
260
263
|
// Uploaded content from zip file
|
|
261
264
|
EmailLayout,
|
|
262
265
|
// Liquid validation
|
|
@@ -372,6 +375,7 @@ EmailWrapperView.propTypes = {
|
|
|
372
375
|
Email: PropTypes.object,
|
|
373
376
|
templateData: PropTypes.object,
|
|
374
377
|
params: PropTypes.object,
|
|
378
|
+
isEditEmail: PropTypes.bool,
|
|
375
379
|
fetchingLiquidTags: PropTypes.bool,
|
|
376
380
|
createTemplateInProgress: PropTypes.bool,
|
|
377
381
|
fetchingCmsData: PropTypes.bool,
|
|
@@ -1897,6 +1897,117 @@ describe('EmailHTMLEditor', () => {
|
|
|
1897
1897
|
});
|
|
1898
1898
|
});
|
|
1899
1899
|
|
|
1900
|
+
describe('Template content extraction (lines 291-309)', () => {
|
|
1901
|
+
it('extracts content and subject from templateDataProp.base branch', async () => {
|
|
1902
|
+
const ref = React.createRef();
|
|
1903
|
+
const templateData = {
|
|
1904
|
+
base: {
|
|
1905
|
+
'template-content': '<p>Base branch content</p>',
|
|
1906
|
+
"subject": 'Base branch subject',
|
|
1907
|
+
},
|
|
1908
|
+
};
|
|
1909
|
+
render(
|
|
1910
|
+
<IntlProvider locale="en" messages={{}}>
|
|
1911
|
+
<EmailHTMLEditor
|
|
1912
|
+
{...defaultProps}
|
|
1913
|
+
ref={ref}
|
|
1914
|
+
params={{ id: '123' }}
|
|
1915
|
+
templateData={templateData}
|
|
1916
|
+
Email={{
|
|
1917
|
+
templateDetails: { _id: '123' },
|
|
1918
|
+
getTemplateDetailsInProgress: false,
|
|
1919
|
+
fetchingCmsData: false,
|
|
1920
|
+
}}
|
|
1921
|
+
/>
|
|
1922
|
+
</IntlProvider>
|
|
1923
|
+
);
|
|
1924
|
+
await waitFor(() => {
|
|
1925
|
+
expect(ref.current).toBeTruthy();
|
|
1926
|
+
}, { timeout: 3000 });
|
|
1927
|
+
await waitFor(() => {
|
|
1928
|
+
const content = ref.current.getContentForPreview();
|
|
1929
|
+
const formData = ref.current.getFormDataForPreview();
|
|
1930
|
+
expect(content).toBe('<p>Base branch content</p>');
|
|
1931
|
+
expect(formData['template-subject']).toBe('Base branch subject');
|
|
1932
|
+
}, { timeout: 3000 });
|
|
1933
|
+
});
|
|
1934
|
+
|
|
1935
|
+
it('extracts content and subject from templateDataProp.versions.base branch with activeTab', async () => {
|
|
1936
|
+
const ref = React.createRef();
|
|
1937
|
+
const templateData = {
|
|
1938
|
+
versions: {
|
|
1939
|
+
base: {
|
|
1940
|
+
activeTab: 'en',
|
|
1941
|
+
en: {
|
|
1942
|
+
'template-content': '<p>Versions base en content</p>',
|
|
1943
|
+
"html_content": '<p>fallback html_content</p>',
|
|
1944
|
+
},
|
|
1945
|
+
subject: 'Versions base subject',
|
|
1946
|
+
emailSubject: 'Fallback email subject',
|
|
1947
|
+
},
|
|
1948
|
+
},
|
|
1949
|
+
};
|
|
1950
|
+
render(
|
|
1951
|
+
<IntlProvider locale="en" messages={{}}>
|
|
1952
|
+
<EmailHTMLEditor
|
|
1953
|
+
{...defaultProps}
|
|
1954
|
+
ref={ref}
|
|
1955
|
+
params={{ id: '123' }}
|
|
1956
|
+
templateData={templateData}
|
|
1957
|
+
Email={{
|
|
1958
|
+
templateDetails: { _id: '123' },
|
|
1959
|
+
getTemplateDetailsInProgress: false,
|
|
1960
|
+
fetchingCmsData: false,
|
|
1961
|
+
}}
|
|
1962
|
+
/>
|
|
1963
|
+
</IntlProvider>
|
|
1964
|
+
);
|
|
1965
|
+
await waitFor(() => {
|
|
1966
|
+
expect(ref.current).toBeTruthy();
|
|
1967
|
+
}, { timeout: 3000 });
|
|
1968
|
+
await waitFor(() => {
|
|
1969
|
+
const content = ref.current.getContentForPreview();
|
|
1970
|
+
const formData = ref.current.getFormDataForPreview();
|
|
1971
|
+
expect(content).toBe('<p>Versions base en content</p>');
|
|
1972
|
+
expect(formData['template-subject']).toBe('Versions base subject');
|
|
1973
|
+
}, { timeout: 3000 });
|
|
1974
|
+
});
|
|
1975
|
+
|
|
1976
|
+
it('extracts content and subject from flat templateDataProp (else branch)', async () => {
|
|
1977
|
+
const ref = React.createRef();
|
|
1978
|
+
const templateData = {
|
|
1979
|
+
'template-content': '<p>Flat content</p>',
|
|
1980
|
+
"emailSubject": 'Flat email subject',
|
|
1981
|
+
"html_content": '<p>flat html_content</p>',
|
|
1982
|
+
"subject": 'Flat subject',
|
|
1983
|
+
};
|
|
1984
|
+
render(
|
|
1985
|
+
<IntlProvider locale="en" messages={{}}>
|
|
1986
|
+
<EmailHTMLEditor
|
|
1987
|
+
{...defaultProps}
|
|
1988
|
+
ref={ref}
|
|
1989
|
+
params={{ id: '123' }}
|
|
1990
|
+
templateData={templateData}
|
|
1991
|
+
Email={{
|
|
1992
|
+
templateDetails: { _id: '123' },
|
|
1993
|
+
getTemplateDetailsInProgress: false,
|
|
1994
|
+
fetchingCmsData: false,
|
|
1995
|
+
}}
|
|
1996
|
+
/>
|
|
1997
|
+
</IntlProvider>
|
|
1998
|
+
);
|
|
1999
|
+
await waitFor(() => {
|
|
2000
|
+
expect(ref.current).toBeTruthy();
|
|
2001
|
+
}, { timeout: 3000 });
|
|
2002
|
+
await waitFor(() => {
|
|
2003
|
+
const content = ref.current.getContentForPreview();
|
|
2004
|
+
const formData = ref.current.getFormDataForPreview();
|
|
2005
|
+
expect(content).toBe('<p>Flat content</p>');
|
|
2006
|
+
expect(formData['template-subject']).toBe('Flat email subject');
|
|
2007
|
+
}, { timeout: 3000 });
|
|
2008
|
+
});
|
|
2009
|
+
});
|
|
2010
|
+
|
|
1900
2011
|
describe('setIsLoadingContent callback', () => {
|
|
1901
2012
|
it('should call setIsLoadingContent when uploaded content is available', async () => {
|
|
1902
2013
|
const setIsLoadingContent = jest.fn();
|
|
@@ -1933,6 +2044,37 @@ describe('EmailHTMLEditor', () => {
|
|
|
1933
2044
|
});
|
|
1934
2045
|
});
|
|
1935
2046
|
|
|
2047
|
+
describe('location.query and tagList (lines 127, 129, 185)', () => {
|
|
2048
|
+
it('should handle missing location.query (destructure from empty object)', () => {
|
|
2049
|
+
renderWithIntl({
|
|
2050
|
+
location: {},
|
|
2051
|
+
supportedTags: [],
|
|
2052
|
+
metaEntities: { tags: { standard: [{ name: 'standard.tag' }] } },
|
|
2053
|
+
});
|
|
2054
|
+
expect(screen.getByTestId('html-editor')).toBeInTheDocument();
|
|
2055
|
+
});
|
|
2056
|
+
|
|
2057
|
+
it('should handle null location (query defaults to {})', () => {
|
|
2058
|
+
renderWithIntl({
|
|
2059
|
+
location: null,
|
|
2060
|
+
supportedTags: [],
|
|
2061
|
+
metaEntities: { tags: { standard: [] } },
|
|
2062
|
+
});
|
|
2063
|
+
expect(screen.getByTestId('html-editor')).toBeInTheDocument();
|
|
2064
|
+
});
|
|
2065
|
+
|
|
2066
|
+
it('should use tagList from supportedTags when type=embedded, module=library and no getDefaultTags (line 129)', () => {
|
|
2067
|
+
const supportedTags = [{ name: 'custom.a' }, { name: 'custom.b' }];
|
|
2068
|
+
renderWithIntl({
|
|
2069
|
+
location: { query: { type: 'embedded', module: 'library' } },
|
|
2070
|
+
getDefaultTags: null,
|
|
2071
|
+
supportedTags,
|
|
2072
|
+
metaEntities: { tags: { standard: [{ name: 'standard.only' }] } },
|
|
2073
|
+
});
|
|
2074
|
+
expect(screen.getByTestId('html-editor')).toBeInTheDocument();
|
|
2075
|
+
});
|
|
2076
|
+
});
|
|
2077
|
+
|
|
1936
2078
|
describe('tags useMemo (lines 125-132)', () => {
|
|
1937
2079
|
it('should use supportedTags when in EMBEDDED mode with LIBRARY module and no getDefaultTags', () => {
|
|
1938
2080
|
const supportedTags = [{ name: 'custom.tag1' }, { name: 'custom.tag2' }];
|
|
@@ -2050,7 +2192,7 @@ describe('EmailHTMLEditor', () => {
|
|
|
2050
2192
|
expect(formData).toBeDefined();
|
|
2051
2193
|
expect(formData['0']).toBeDefined();
|
|
2052
2194
|
expect(formData['0'].fr).toBeDefined(); // Uses base_language 'fr'
|
|
2053
|
-
expect(formData['0'].fr
|
|
2195
|
+
expect(formData['0'].fr.is_drag_drop).toBe(false);
|
|
2054
2196
|
expect(formData['0'].activeTab).toBe('fr');
|
|
2055
2197
|
expect(formData['0'].selectedLanguages).toEqual(['fr']);
|
|
2056
2198
|
expect(formData['0'].base).toBe(true);
|
|
@@ -517,4 +517,141 @@ describe('EmailWrapperView', () => {
|
|
|
517
517
|
// Should handle gracefully if ref methods don't exist
|
|
518
518
|
});
|
|
519
519
|
});
|
|
520
|
+
|
|
521
|
+
describe('Issue 1: Beefree template should open in Beefree editor in Edit mode', () => {
|
|
522
|
+
beforeEach(() => {
|
|
523
|
+
const { hasSupportCKEditor } = require('../../../../utils/common');
|
|
524
|
+
hasSupportCKEditor.mockReturnValue(false); // New flow
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
it('should render Email component (not HTML editor) when editing Beefree template', () => {
|
|
528
|
+
const emailPropsWithBEE = {
|
|
529
|
+
...defaultProps.emailProps,
|
|
530
|
+
editor: 'BEE',
|
|
531
|
+
selectedEditorMode: null,
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
renderWithIntl({
|
|
535
|
+
step: STEPS.CREATE_TEMPLATE_CONTENT,
|
|
536
|
+
isShowEmailCreate: true,
|
|
537
|
+
emailProps: emailPropsWithBEE,
|
|
538
|
+
emailCreateMode: EMAIL_CREATE_MODES.DRAG_DROP,
|
|
539
|
+
params: { id: 'beefree-template-1' },
|
|
540
|
+
location: { query: {}, pathname: '/email/edit/beefree-template-1' },
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
// Should render Email component (BEE editor), not HTML editor
|
|
544
|
+
expect(screen.queryByTestId('email-html-editor')).not.toBeInTheDocument();
|
|
545
|
+
// Email component would be rendered (we're using EmailWithoutSaga which doesn't have a testid)
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
it('should render HTML editor when editing non-Beefree template', () => {
|
|
549
|
+
const emailPropsWithHTML = {
|
|
550
|
+
...defaultProps.emailProps,
|
|
551
|
+
editor: 'HTML',
|
|
552
|
+
selectedEditorMode: EMAIL_CREATE_MODES.HTML_EDITOR,
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
renderWithIntl({
|
|
556
|
+
step: STEPS.CREATE_TEMPLATE_CONTENT,
|
|
557
|
+
isShowEmailCreate: true,
|
|
558
|
+
emailProps: emailPropsWithHTML,
|
|
559
|
+
emailCreateMode: EMAIL_CREATE_MODES.HTML_EDITOR,
|
|
560
|
+
params: { id: 'html-template-1' },
|
|
561
|
+
location: { query: {}, pathname: '/email/edit/html-template-1' },
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
// Should render HTML editor for non-Beefree template
|
|
565
|
+
expect(screen.getByTestId('email-html-editor')).toBeInTheDocument();
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
it('should render Email component when emailCreateMode is DRAG_DROP in create mode', () => {
|
|
569
|
+
const emailPropsWithBEE = {
|
|
570
|
+
...defaultProps.emailProps,
|
|
571
|
+
editor: 'BEE',
|
|
572
|
+
selectedEditorMode: null,
|
|
573
|
+
};
|
|
574
|
+
|
|
575
|
+
renderWithIntl({
|
|
576
|
+
step: STEPS.CREATE_TEMPLATE_CONTENT,
|
|
577
|
+
isShowEmailCreate: true,
|
|
578
|
+
emailProps: emailPropsWithBEE,
|
|
579
|
+
emailCreateMode: EMAIL_CREATE_MODES.DRAG_DROP,
|
|
580
|
+
params: {},
|
|
581
|
+
location: { query: {}, pathname: '/email/create' },
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
// Should render Email component (BEE editor), not HTML editor
|
|
585
|
+
expect(screen.queryByTestId('email-html-editor')).not.toBeInTheDocument();
|
|
586
|
+
});
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
describe('Issue 2: Upload Zip should open in CKEditor when SUPPORT_CK_EDITOR is enabled', () => {
|
|
590
|
+
beforeEach(() => {
|
|
591
|
+
const { hasSupportCKEditor } = require('../../../../utils/common');
|
|
592
|
+
hasSupportCKEditor.mockReturnValue(true); // Legacy flow
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
it('should render Email component (CKEditor) for UPLOAD mode in create flow', () => {
|
|
596
|
+
const emailPropsForCKEditor = {
|
|
597
|
+
...defaultProps.emailProps,
|
|
598
|
+
editor: undefined, // Default CKEditor
|
|
599
|
+
selectedEditorMode: null,
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
renderWithIntl({
|
|
603
|
+
step: STEPS.CREATE_TEMPLATE_CONTENT,
|
|
604
|
+
isShowEmailCreate: true,
|
|
605
|
+
emailProps: emailPropsForCKEditor,
|
|
606
|
+
emailCreateMode: EMAIL_CREATE_MODES.UPLOAD,
|
|
607
|
+
EmailLayout: { html: '<p>Uploaded content</p>' },
|
|
608
|
+
params: {},
|
|
609
|
+
location: { query: {}, pathname: '/email/create' },
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
// Should render Email component (CKEditor), NOT HTML editor
|
|
613
|
+
expect(screen.queryByTestId('email-html-editor')).not.toBeInTheDocument();
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
it('should render Email component (CKEditor) for UPLOAD mode in edit flow', () => {
|
|
617
|
+
const emailPropsForCKEditor = {
|
|
618
|
+
...defaultProps.emailProps,
|
|
619
|
+
editor: undefined,
|
|
620
|
+
selectedEditorMode: null,
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
renderWithIntl({
|
|
624
|
+
step: STEPS.CREATE_TEMPLATE_CONTENT,
|
|
625
|
+
isShowEmailCreate: true,
|
|
626
|
+
emailProps: emailPropsForCKEditor,
|
|
627
|
+
emailCreateMode: EMAIL_CREATE_MODES.UPLOAD,
|
|
628
|
+
EmailLayout: { html: '<p>Edited uploaded content</p>' },
|
|
629
|
+
params: { id: 'uploaded-template-1' },
|
|
630
|
+
location: { query: {}, pathname: '/email/edit/uploaded-template-1' },
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
// Should render Email component (CKEditor), NOT HTML editor
|
|
634
|
+
expect(screen.queryByTestId('email-html-editor')).not.toBeInTheDocument();
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
it('should NOT render HTML editor for EDITOR mode when SUPPORT_CK_EDITOR is enabled', () => {
|
|
638
|
+
const emailPropsForCKEditor = {
|
|
639
|
+
...defaultProps.emailProps,
|
|
640
|
+
editor: undefined,
|
|
641
|
+
selectedEditorMode: null,
|
|
642
|
+
};
|
|
643
|
+
|
|
644
|
+
renderWithIntl({
|
|
645
|
+
step: STEPS.CREATE_TEMPLATE_CONTENT,
|
|
646
|
+
isShowEmailCreate: true,
|
|
647
|
+
emailProps: emailPropsForCKEditor,
|
|
648
|
+
emailCreateMode: EMAIL_CREATE_MODES.EDITOR,
|
|
649
|
+
params: {},
|
|
650
|
+
location: { query: {}, pathname: '/email/create' },
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
// Should render Email component (CKEditor), NOT HTML editor
|
|
654
|
+
expect(screen.queryByTestId('email-html-editor')).not.toBeInTheDocument();
|
|
655
|
+
});
|
|
656
|
+
});
|
|
520
657
|
});
|
|
@@ -66,6 +66,7 @@ const useEmailWrapper = ({
|
|
|
66
66
|
Email,
|
|
67
67
|
templateData,
|
|
68
68
|
params,
|
|
69
|
+
isEditEmail = true,
|
|
69
70
|
}) => {
|
|
70
71
|
// State management
|
|
71
72
|
const [templateName, setTemplateName] = useState('');
|
|
@@ -194,7 +195,10 @@ const useEmailWrapper = ({
|
|
|
194
195
|
return;
|
|
195
196
|
}
|
|
196
197
|
|
|
197
|
-
// New flow: Fetch template details
|
|
198
|
+
// New flow: Fetch template details only when editing (not when creating)
|
|
199
|
+
if (!isEditEmail) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
198
202
|
const hasParamsId = params?.id || location?.query?.id || location?.params?.id || location?.pathname?.includes('/edit/');
|
|
199
203
|
const hasTemplateDetails = Email?.templateDetails && !isEmpty(Email.templateDetails);
|
|
200
204
|
const hasTemplateDataProp = templateData && !isEmpty(templateData);
|
|
@@ -207,7 +211,7 @@ const useEmailWrapper = ({
|
|
|
207
211
|
emailActions.getTemplateDetails(templateId, 'email');
|
|
208
212
|
}
|
|
209
213
|
}
|
|
210
|
-
}, [params?.id, location?.query?.id, location?.params?.id, location?.pathname, Email?.templateDetails, Email?.getTemplateDetailsInProgress, templateData, emailActions]);
|
|
214
|
+
}, [isEditEmail, params?.id, location?.query?.id, location?.params?.id, location?.pathname, Email?.templateDetails, Email?.getTemplateDetailsInProgress, templateData, emailActions]);
|
|
211
215
|
|
|
212
216
|
// Effect to set BEETemplate when template details are loaded for BEE templates
|
|
213
217
|
// This ensures Email component can properly initialize BEE editor
|
|
@@ -643,7 +647,7 @@ const useEmailWrapper = ({
|
|
|
643
647
|
// If template was created in BEE AND BEE is enabled → open in BEE editor
|
|
644
648
|
// Otherwise → open in HTML editor (fallback)
|
|
645
649
|
// IMPORTANT: When supportCKEditor is false, default to HTML editor unless explicitly BEE
|
|
646
|
-
if (isDragDrop && isBeeEnabled) {
|
|
650
|
+
if ((isDragDrop && isBeeEnabled)) {
|
|
647
651
|
editorType = 'BEE';
|
|
648
652
|
selectedEditorMode = null; // BEE uses existing flow
|
|
649
653
|
} else {
|
|
@@ -85,6 +85,7 @@ const EmailWrapper = (props) => {
|
|
|
85
85
|
createTemplateInProgress,
|
|
86
86
|
fetchingCmsData,
|
|
87
87
|
onHtmlEditorValidationStateChange,
|
|
88
|
+
isEditEmail = true,
|
|
88
89
|
} = props;
|
|
89
90
|
|
|
90
91
|
// Pass destructured props to the custom hook
|
|
@@ -143,6 +144,7 @@ const EmailWrapper = (props) => {
|
|
|
143
144
|
Email,
|
|
144
145
|
templateData,
|
|
145
146
|
params,
|
|
147
|
+
isEditEmail,
|
|
146
148
|
});
|
|
147
149
|
|
|
148
150
|
// Render using the presentation component with data from the hook
|
|
@@ -195,6 +197,7 @@ const EmailWrapper = (props) => {
|
|
|
195
197
|
setIsLoadingContent={setIsLoadingContent}
|
|
196
198
|
templateData={templateData}
|
|
197
199
|
params={params}
|
|
200
|
+
isEditEmail={isEditEmail}
|
|
198
201
|
showTemplateName={showTemplateName}
|
|
199
202
|
fetchingLiquidTags={fetchingLiquidTags}
|
|
200
203
|
createTemplateInProgress={createTemplateInProgress}
|