@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.
Files changed (25) hide show
  1. package/package.json +1 -1
  2. package/utils/tests/imageUrlUpload.test.js +298 -0
  3. package/v2Containers/CreativesContainer/SlideBoxContent.js +2 -0
  4. package/v2Containers/CreativesContainer/SlideBoxFooter.js +5 -2
  5. package/v2Containers/CreativesContainer/index.js +10 -6
  6. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +165 -41
  7. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +6 -0
  8. package/v2Containers/Email/index.js +75 -9
  9. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +9 -4
  10. package/v2Containers/EmailWrapper/components/EmailWrapperView.js +6 -2
  11. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +143 -1
  12. package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +137 -0
  13. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +7 -3
  14. package/v2Containers/EmailWrapper/index.js +3 -0
  15. package/v2Containers/Facebook/Advertisement/index.js +1 -1
  16. package/v2Containers/Line/Container/_lineCreate.scss +1 -0
  17. package/v2Containers/Line/Container/style.js +1 -1
  18. package/v2Containers/MobilePush/Edit/index.js +6 -5
  19. package/v2Containers/SmsTrai/Create/index.scss +1 -1
  20. package/v2Containers/SmsTrai/Edit/index.js +9 -3
  21. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +11682 -86
  22. package/v2Containers/SmsTrai/Edit/tests/index.test.js +5 -0
  23. package/v2Containers/Viber/index.js +7 -0
  24. package/v2Containers/Viber/index.scss +4 -1
  25. 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 ,hasLiquidSupportFeature} from '../../utils/common';
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
- this.setState({ content: (this.props.Templates.selectedEmailLayout ? this.props.Templates.selectedEmailLayout : ''), formData});
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
- //only for ck editor
317
- //when create button is clicked in full mode
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.startValidation(true);
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
- if (!_.isEmpty(nextProps.Email.CmsSettings) && !_.isEqual(this.props.Email.CmsSettings, nextProps.Email.CmsSettings) && !_.isEmpty(this.state.schema)) {
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
- this.props.templatesActions.resetUploadData();
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 = templateDataProp?._id || params?.id || location?.query?.id || location?.params?.id
180
- || location?.pathname?.match(/\/edit\/([^/]+)/)?.[1];
181
- const isEditMode = !!currentTemplateId || !!hasParamsId;
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
- // Legacy flow: use HTML editor for UPLOAD so zip/HTML content (EmailLayout) is shown; use Email component for EDITOR
206
- isHTMLEditorMode = emailCreateMode === EMAIL_CREATE_MODES.UPLOAD;
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['is_drag_drop']).toBe(false);
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 if we're in edit mode and don't have template data yet
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}
@@ -73,7 +73,7 @@ export const Advertisement = (props) => {
73
73
  const FbAdFooter = styled.div`
74
74
  background-color: ${CAP_WHITE};
75
75
  position: fixed;
76
- bottom: 20px;
76
+ bottom: 0;
77
77
  width: 100%;
78
78
  margin-left: -32px;
79
79
  padding: ${CAP_SPACE_32} ${CAP_SPACE_24};
@@ -40,6 +40,7 @@
40
40
  .create-msg,
41
41
  .cancel-msg {
42
42
  position: fixed;
43
+ bottom: 20px;
43
44
  }
44
45
  .cancel-msg {
45
46
  margin-left: 100px;
@@ -38,7 +38,7 @@ export default css`
38
38
  .action-section {
39
39
  background-color: ${CAP_WHITE};
40
40
  position: fixed;
41
- bottom: 20px;
41
+ bottom: 0;
42
42
  width: 100%;
43
43
  margin-left: -32px;
44
44
  padding: ${CAP_SPACE_32} ${CAP_SPACE_24};