@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.
Files changed (37) hide show
  1. package/HOW_BEE_EDITOR_WORKS.md +375 -0
  2. package/constants/unified.js +1 -0
  3. package/package.json +1 -1
  4. package/services/api.js +5 -0
  5. package/utils/common.js +6 -1
  6. package/v2Components/CapTagList/index.js +2 -1
  7. package/v2Components/CapTagListWithInput/index.js +5 -1
  8. package/v2Components/CapTagListWithInput/messages.js +1 -1
  9. package/v2Components/ErrorInfoNote/style.scss +1 -1
  10. package/v2Components/HtmlEditor/HTMLEditor.js +86 -14
  11. package/v2Components/HtmlEditor/_htmlEditor.scss +4 -4
  12. package/v2Components/HtmlEditor/_index.lazy.scss +1 -1
  13. package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +107 -96
  14. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +68 -92
  15. package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
  16. package/v2Components/HtmlEditor/hooks/useEditorContent.js +5 -2
  17. package/v2Containers/CreativesContainer/SlideBoxContent.js +85 -35
  18. package/v2Containers/CreativesContainer/SlideBoxFooter.js +9 -3
  19. package/v2Containers/CreativesContainer/index.js +107 -35
  20. package/v2Containers/CreativesContainer/messages.js +4 -0
  21. package/v2Containers/Email/actions.js +7 -0
  22. package/v2Containers/Email/constants.js +5 -1
  23. package/v2Containers/Email/index.js +13 -0
  24. package/v2Containers/Email/messages.js +32 -0
  25. package/v2Containers/Email/reducer.js +12 -1
  26. package/v2Containers/Email/sagas.js +17 -0
  27. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +1005 -0
  28. package/v2Containers/EmailWrapper/components/EmailWrapperView.js +193 -7
  29. package/v2Containers/EmailWrapper/constants.js +2 -0
  30. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +470 -71
  31. package/v2Containers/EmailWrapper/index.js +102 -23
  32. package/v2Containers/EmailWrapper/messages.js +61 -1
  33. package/v2Containers/EmailWrapper/tests/EmailHTMLEditor.test.js +177 -0
  34. package/v2Containers/EmailWrapper/tests/EmailHTMLEditorValidation.test.js +90 -0
  35. package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +49 -49
  36. package/v2Containers/TagList/index.js +2 -0
  37. package/v2Containers/Templates/index.js +5 -0
@@ -1,16 +1,19 @@
1
- import { useState, useEffect, useMemo, useCallback } from 'react';
1
+ import React, {
2
+ useState, useEffect, useMemo, useCallback, useRef,
3
+ } from 'react';
2
4
  import isEmpty from 'lodash/isEmpty';
3
- import get from 'lodash/get';
4
5
  import find from 'lodash/find';
6
+ import get from 'lodash/get';
5
7
  import { GA } from '@capillarytech/cap-ui-utils';
6
8
  import CapNotification from '@capillarytech/cap-ui-library/CapNotification';
9
+ import CapIcon from '@capillarytech/cap-ui-library/CapIcon';
7
10
  import { CHANNEL_CREATE_TRACK_MAPPING } from '../../App/constants';
8
11
  import { gtmPush } from '../../../utils/gtmTrackers';
9
12
  import { EMAIL } from '../../CreativesContainer/constants';
10
13
  import messages from '../messages';
11
- import { STEPS } from '../constants';
12
- import { EMAIL_CREATE_MODES } from '../constants';
14
+ import { STEPS, EMAIL_CREATE_MODES } from '../constants';
13
15
  import { containsBase64Images } from '../../../utils/content';
16
+ import { hasSupportCKEditor } from '../../../utils/common';
14
17
 
15
18
  /**
16
19
  * Custom hook to handle EmailWrapper component business logic
@@ -56,12 +59,21 @@ const useEmailWrapper = ({
56
59
  handleTestAndPreview,
57
60
  handleCloseTestAndPreview,
58
61
  isTestAndPreviewMode,
62
+ // Props for BEE enabled check
63
+ location,
64
+ emailActions,
65
+ Email,
66
+ templateData,
67
+ params,
59
68
  }) => {
60
69
  // State management
61
70
  const [templateName, setTemplateName] = useState('');
62
71
  const [isTemplateNameEmpty, setIsTemplateNameEmpty] = useState(true);
63
72
  const [selectedCreateMode, setSelectedCreateMode] = useState('');
64
73
  const [modeContent, setModeContent] = useState({});
74
+ const [isBeeEditorEnabled, setIsBeeEditorEnabled] = useState(null); // null = not checked yet, true/false = checked
75
+ const beeStatusCheckRef = useRef(false); // Track if we've made the API call for current step
76
+ const defaultTemplatesFetchedRef = useRef(false);
65
77
  const [routeParams] = useState({
66
78
  pathname: `/email/create`,
67
79
  query: { module: 'library', type: 'embedded' },
@@ -76,7 +88,7 @@ const useEmailWrapper = ({
76
88
  }, [onResetStep, templatesActions]);
77
89
 
78
90
  // Event handlers
79
- const onTemplateNameChange = useCallback(({target: {value}}) => {
91
+ const onTemplateNameChange = useCallback(({ target: { value } }) => {
80
92
  const isEmptyTemplateName = !value?.trim();
81
93
  setTemplateName(value);
82
94
  setIsTemplateNameEmpty(isEmptyTemplateName);
@@ -88,9 +100,124 @@ const useEmailWrapper = ({
88
100
  }
89
101
  }, [onEnterTemplateName, onRemoveTemplateName]);
90
102
 
103
+ // Check BEE enabled status from API response
104
+ // BEE is enabled if isDragDrop is true in the API response
105
+ // This should work for both full mode and library mode
106
+ const checkBeeEditorEnabled = useCallback(() => {
107
+ // If we have checked the API and got a response, use that
108
+ if (isBeeEditorEnabled !== null) {
109
+ return isBeeEditorEnabled;
110
+ }
111
+ // If we haven't checked yet, return false (disabled) until API responds
112
+ return false;
113
+ }, [isBeeEditorEnabled]);
114
+
115
+ // Helper function to convert numeric templateStep to string step
116
+ const getStepFromTemplateStep = useCallback((templateStepValue) => {
117
+ // templateStep is numeric: 1 = modeSelection, 2 = templateSelection, 3 = createTemplateContent
118
+ if (typeof templateStepValue === 'number') {
119
+ switch (templateStepValue) {
120
+ case 1:
121
+ return STEPS.MODE_SELECTION;
122
+ case 2:
123
+ return STEPS.TEMPLATE_SELECTION;
124
+ case 3:
125
+ return STEPS.CREATE_TEMPLATE_CONTENT;
126
+ default:
127
+ return STEPS.MODE_SELECTION;
128
+ }
129
+ }
130
+ // If it's already a string, return as-is
131
+ return templateStepValue || STEPS.MODE_SELECTION;
132
+ }, []);
133
+
134
+ // Convert step to string format if it's numeric
135
+ const currentStep = useMemo(() => getStepFromTemplateStep(step), [step, getStepFromTemplateStep]);
136
+
137
+ // Effect to check BEE enabled status via new API when entering MODE_SELECTION step
138
+ useEffect(() => {
139
+ const supportCKEditor = hasSupportCKEditor();
140
+ // Only check BEE enabled status for new flow (when supportCKEditor is false)
141
+ // Reset the ref when step changes to MODE_SELECTION to allow API call
142
+ if (currentStep === STEPS.MODE_SELECTION) {
143
+ beeStatusCheckRef.current = false;
144
+ }
145
+
146
+ // Only check BEE enabled status for new flow (when supportCKEditor is false)
147
+ // Check all conditions
148
+ const shouldMakeCall = !supportCKEditor
149
+ && currentStep === STEPS.MODE_SELECTION
150
+ && !beeStatusCheckRef.current
151
+ && emailActions;
152
+
153
+ if (shouldMakeCall) {
154
+ // Mark that we've made the API call
155
+ beeStatusCheckRef.current = true;
156
+
157
+ // Make API call to check BEE enabled status using new endpoint
158
+ emailActions.getCmsAccounts('BEE_PLUGIN');
159
+ }
160
+ }, [currentStep, emailActions]);
161
+
162
+ // Effect to update isBeeEditorEnabled based on new API response
163
+ // This effect watches for isBeeEnabled from the new API response
164
+ useEffect(() => {
165
+ // Only process if we're in MODE_SELECTION step (when we're checking BEE status)
166
+ // Also check if we've made the API call (beeStatusCheckRef.current === true)
167
+ if (currentStep === STEPS.MODE_SELECTION && beeStatusCheckRef.current) {
168
+ // Use isBeeEnabled from the new API response
169
+ if (Email?.isBeeEnabled !== undefined) {
170
+ setIsBeeEditorEnabled(Email.isBeeEnabled);
171
+ }
172
+ }
173
+ // If API call fails, treat as disabled
174
+ if (Email?.fetchingCmsAccountsError && beeStatusCheckRef.current) {
175
+ setIsBeeEditorEnabled(false);
176
+ }
177
+ }, [Email?.isBeeEnabled, Email?.fetchingCmsAccountsError, currentStep]);
178
+
91
179
  const onChange = useCallback((e) => {
92
- onEmailModeChange(e.target.value);
93
- }, [onEmailModeChange]);
180
+ const { target: { value } } = e;
181
+
182
+ // Prevent selection if Drag & Drop is selected but BEE editor is not enabled
183
+ if (value === EMAIL_CREATE_MODES.DRAG_DROP && !checkBeeEditorEnabled()) {
184
+ return; // Ignore selection if BEE editor is disabled
185
+ }
186
+
187
+ // CRITICAL: When DRAG_DROP is selected, set selectedCreateMode to DRAG_DROP
188
+ // This ensures emailProps will have editor: 'BEE' and selectedEditorMode: null
189
+ if (value === EMAIL_CREATE_MODES.DRAG_DROP) {
190
+ setSelectedCreateMode(EMAIL_CREATE_MODES.DRAG_DROP);
191
+ } else {
192
+ setSelectedCreateMode(value);
193
+ }
194
+
195
+ const supportCKEditor = hasSupportCKEditor();
196
+
197
+ // Map new modes to existing modes for backwards compatibility
198
+ let mappedValue = value;
199
+
200
+ if (!supportCKEditor) {
201
+ // New flow: Handle HTML Editor, Drag & Drop, and Upload Zip
202
+ // Don't auto-navigate - wait for Next button click
203
+ if (value === EMAIL_CREATE_MODES.HTML_EDITOR) {
204
+ // HTML Editor: Map to EDITOR but skip template selection
205
+ mappedValue = EMAIL_CREATE_MODES.EDITOR;
206
+ setModeContent({ skipTemplateSelection: true });
207
+ } else if (value === EMAIL_CREATE_MODES.DRAG_DROP) {
208
+ // Drag & Drop: Map to EDITOR and show template selection
209
+ mappedValue = EMAIL_CREATE_MODES.EDITOR;
210
+ } else if (value === EMAIL_CREATE_MODES.UPLOAD) {
211
+ // Upload Zip: Keep as UPLOAD
212
+ mappedValue = EMAIL_CREATE_MODES.UPLOAD;
213
+ }
214
+ } else if (value === EMAIL_CREATE_MODES.EDITOR && showNextStep) {
215
+ // Legacy flow: Auto-navigate immediately (existing behavior)
216
+ showNextStep();
217
+ }
218
+
219
+ onEmailModeChange(mappedValue, value); // Pass both mapped value and original selected mode
220
+ }, [onEmailModeChange, showNextStep, checkBeeEditorEnabled]);
94
221
 
95
222
  const handleZipUploadError = useCallback(() => {
96
223
  const message = {
@@ -168,10 +295,10 @@ const useEmailWrapper = ({
168
295
  handleZipUploadError();
169
296
  return;
170
297
  }
171
-
298
+
172
299
  // Check for base64 images in HTML content
173
- containsBase64Images({content:text, CapNotification});
174
-
300
+ containsBase64Images({ content: text, CapNotification });
301
+
175
302
  setModeContent({ file });
176
303
  templatesActions.handleHtmlUpload(text);
177
304
  };
@@ -194,8 +321,12 @@ const useEmailWrapper = ({
194
321
  const data = find(CmsTemplates, { _id: id });
195
322
  templatesActions.setEdmTemplate(data);
196
323
  templatesActions.setBEETemplate(data);
197
- setSelectedCreateMode(EMAIL_CREATE_MODES.EDITOR);
198
- }, [CmsTemplates, templatesActions]);
324
+ // Don't override selectedCreateMode - preserve DRAG_DROP or EDITOR mode
325
+ // Only set if not already set
326
+ if (!selectedCreateMode) {
327
+ setSelectedCreateMode(EMAIL_CREATE_MODES.EDITOR);
328
+ }
329
+ }, [CmsTemplates, templatesActions, selectedCreateMode]);
199
330
 
200
331
  const useFileUpload = useCallback(({ file }) => {
201
332
  setModeContent({});
@@ -207,43 +338,84 @@ const useEmailWrapper = ({
207
338
  showNextStep();
208
339
  }, [showNextStep]);
209
340
 
341
+ const handleNextClick = useCallback(() => {
342
+ const supportCKEditor = hasSupportCKEditor();
343
+ if (!supportCKEditor && selectedCreateMode) {
344
+ if ([EMAIL_CREATE_MODES.HTML_EDITOR, EMAIL_CREATE_MODES.DRAG_DROP].includes(selectedCreateMode)) {
345
+ showNextStep();
346
+ }
347
+ }
348
+ }, [selectedCreateMode, showNextStep]);
349
+
210
350
  // Main logic effect - MOVED AFTER function declarations
211
351
  useEffect(() => {
212
- // Skip if user has already made a selection
213
- if (selectedCreateMode) return;
352
+ const supportCKEditor = hasSupportCKEditor();
214
353
 
215
354
  // Handle different steps
216
- switch (step) {
355
+ switch (currentStep) {
217
356
  case STEPS.MODE_SELECTION:
218
357
  if (emailCreateMode === EMAIL_CREATE_MODES.UPLOAD && !EmailLayout) {
219
358
  // Commented out: document.getElementById('upload-email-template').click();
220
359
  }
221
360
  break;
222
361
 
223
- case STEPS.TEMPLATE_SELECTION:
224
- const needsTemplates = emailCreateMode === EMAIL_CREATE_MODES.EDITOR
225
- && !CmsTemplates
226
- && !getCmsTemplatesInProgress;
362
+ case STEPS.TEMPLATE_SELECTION: {
363
+ // Template selection is needed for:
364
+ // 1. Legacy EDITOR mode (when supportCKEditor is true)
365
+ // 2. New DRAG_DROP mode (when supportCKEditor is false)
366
+ // NOT needed for HTML_EDITOR (goes directly to editor)
367
+
368
+ let needsTemplates = false;
369
+ if (supportCKEditor) {
370
+ // Legacy flow: only for EDITOR mode
371
+ needsTemplates = emailCreateMode === EMAIL_CREATE_MODES.EDITOR
372
+ && !CmsTemplates
373
+ && !getCmsTemplatesInProgress;
374
+ } else {
375
+ // New flow: for DRAG_DROP only (not HTML_EDITOR)
376
+ needsTemplates = selectedCreateMode === EMAIL_CREATE_MODES.DRAG_DROP
377
+ && !CmsTemplates
378
+ && !getCmsTemplatesInProgress;
379
+ }
227
380
 
228
- if (needsTemplates) {
381
+ if (needsTemplates && !defaultTemplatesFetchedRef.current) {
229
382
  templatesActions.getDefaultBeeTemplates();
383
+ defaultTemplatesFetchedRef.current = true;
230
384
  }
231
385
  break;
386
+ }
232
387
 
233
- case STEPS.CREATE_TEMPLATE_CONTENT:
388
+ case STEPS.CREATE_TEMPLATE_CONTENT: {
234
389
  if (emailCreateMode === EMAIL_CREATE_MODES.UPLOAD && !isEmpty(EmailLayout)) {
235
390
  setSelectedCreateMode(EMAIL_CREATE_MODES.UPLOAD);
236
- } else if (emailCreateMode === EMAIL_CREATE_MODES.EDITOR && isEmpty(SelectedEdmDefaultTemplate)) {
237
- handleEdmDefaultTemplateSelection(modeContent.id);
391
+ } else if (emailCreateMode === EMAIL_CREATE_MODES.EDITOR
392
+ || emailCreateMode === EMAIL_CREATE_MODES.DRAG_DROP
393
+ || selectedCreateMode === EMAIL_CREATE_MODES.EDITOR
394
+ || selectedCreateMode === EMAIL_CREATE_MODES.DRAG_DROP) {
395
+ if (!supportCKEditor && selectedCreateMode === EMAIL_CREATE_MODES.HTML_EDITOR) {
396
+ // HTML Editor mode: Skip template selection, go directly to editor
397
+ setSelectedCreateMode(EMAIL_CREATE_MODES.HTML_EDITOR);
398
+ } else if (isEmpty(SelectedEdmDefaultTemplate) && modeContent.id) {
399
+ // Legacy EDITOR or DRAG_DROP: Need template selection
400
+ handleEdmDefaultTemplateSelection(modeContent.id);
401
+ } else if (!supportCKEditor && selectedCreateMode === EMAIL_CREATE_MODES.DRAG_DROP) {
402
+ // CRITICAL: Template already selected for DRAG_DROP - ensure selectedCreateMode is DRAG_DROP
403
+ // This ensures emailProps will have editor: 'BEE' and selectedEditorMode: null
404
+ setSelectedCreateMode(EMAIL_CREATE_MODES.DRAG_DROP);
405
+ } else {
406
+ // Template already selected for legacy EDITOR
407
+ setSelectedCreateMode(EMAIL_CREATE_MODES.EDITOR);
408
+ }
238
409
  }
239
410
  break;
411
+ }
240
412
 
241
413
  default:
242
414
  // No operation for other steps
243
415
  break;
244
416
  }
245
417
  }, [
246
- step,
418
+ currentStep,
247
419
  selectedCreateMode,
248
420
  emailCreateMode,
249
421
  EmailLayout,
@@ -252,58 +424,154 @@ const useEmailWrapper = ({
252
424
  modeContent.id,
253
425
  SelectedEdmDefaultTemplate,
254
426
  templatesActions,
255
- handleEdmDefaultTemplateSelection
427
+ handleEdmDefaultTemplateSelection,
256
428
  ]);
257
429
 
430
+ // CRITICAL: Reset selectedCreateMode when templateData is cleared (new template creation)
431
+ // This ensures that when user creates a new template after editing, selectedCreateMode is reset
432
+ useEffect(() => {
433
+ // If templateData is cleared/null and we're not in edit mode, reset selectedCreateMode
434
+ const hasParamsId = params?.id
435
+ || location?.query?.id
436
+ || location?.params?.id
437
+ || location?.pathname?.includes('/edit/');
438
+ const hasTemplateData = templateData && !isEmpty(templateData);
439
+ const isEditMode = hasParamsId || hasTemplateData;
440
+
441
+ // If we're creating a new template (no templateData and no params.id), reset selectedCreateMode
442
+ if (!isEditMode && !hasTemplateData && selectedCreateMode) {
443
+ // Only reset if we're actually in create mode (not just initial load)
444
+ // Check if we have templateName or other create-mode indicators
445
+ if (templateName || currentStep === STEPS.MODE_SELECTION) {
446
+ setSelectedCreateMode('');
447
+ }
448
+ }
449
+ }, [templateData, params?.id, location?.query?.id, location?.params?.id, location?.pathname, selectedCreateMode, templateName, currentStep]);
450
+
258
451
  // Derived state
259
- const isShowEmailCreate = !isEmpty(selectedCreateMode) && (!isEmpty(EmailLayout) || SelectedEdmDefaultTemplate);
452
+ const supportCKEditorFlag = hasSupportCKEditor();
260
453
 
261
- // Memoize static data
262
- const modes = useMemo(() => [
263
- {
264
- title: formatMessage(messages.zipUpload),
265
- content: formatMessage(messages.zipUploadDesc),
266
- value: EMAIL_CREATE_MODES.UPLOAD,
267
- },
268
- {
269
- title: formatMessage(messages.useEditor),
270
- content: formatMessage(messages.useEditorDesc),
271
- value: EMAIL_CREATE_MODES.EDITOR,
272
- },
273
- ], [formatMessage]);
274
-
275
- // Prepare props for Email component
276
- const emailProps = useMemo(() => ({
277
- setIsLoadingContent,
278
- key: "email-create-template",
279
- location: routeParams,
280
- route: { name: 'email' },
281
- params: {},
282
- isGetFormData,
283
- getFormdata,
284
- getFormSubscriptionData: getFormdata,
285
- getDefaultTags: type,
286
- isFullMode,
287
- defaultData: { 'template-name': templateName },
288
- cap,
289
- showTemplateName,
290
- showLiquidErrorInFooter,
291
- onValidationFail,
292
- forwardedTags,
293
- selectedOfferDetails,
294
- onPreviewContentClicked,
295
- onTestContentClicked,
296
- editor,
297
- moduleType,
298
- eventContextTags,
299
- isLoyaltyModule,
300
- showTestAndPreviewSlidebox,
301
- handleTestAndPreview,
302
- handleCloseTestAndPreview,
303
- isTestAndPreviewMode,
304
- }), [
454
+ // Prepare props for Email component - MOVED BEFORE isShowEmailCreate to avoid circular dependency
455
+ const emailProps = useMemo(() => {
456
+ // Determine editor type and mode based on selectedCreateMode
457
+ let editorType = editor;
458
+ let selectedEditorMode = null;
459
+
460
+ if (!supportCKEditorFlag) {
461
+ // CRITICAL: Check selectedCreateMode FIRST to prioritize user's explicit selection
462
+ // This ensures DRAG_DROP selection takes precedence over edit mode detection
463
+ // even if templateDetails persists from a previous template
464
+ if (selectedCreateMode === EMAIL_CREATE_MODES.DRAG_DROP) {
465
+ // CRITICAL: DRAG_DROP mode always uses BEE editor
466
+ // This takes precedence over edit mode detection
467
+ editorType = 'BEE';
468
+ selectedEditorMode = null; // BEE uses existing flow (null indicates BEE editor)
469
+ } else if (selectedCreateMode === EMAIL_CREATE_MODES.HTML_EDITOR) {
470
+ // HTML_EDITOR mode: Always use HTML editor
471
+ editorType = 'HTML';
472
+ selectedEditorMode = EMAIL_CREATE_MODES.HTML_EDITOR;
473
+ } else {
474
+ // Check if we're editing an existing template
475
+ // CRITICAL: Only treat as edit mode if we have params.id (actual edit URL)
476
+ // Don't use templateDetails existence alone, as it might persist from previous template
477
+ const hasParamsId = params?.id || location?.query?.id || location?.params?.id || location?.pathname?.includes('/edit/');
478
+ const hasTemplateDetails = Email?.templateDetails && !isEmpty(Email.templateDetails);
479
+ const hasBEETemplate = Email?.BEETemplate && !isEmpty(Email.BEETemplate);
480
+ // CRITICAL: Only consider it edit mode if we have params.id (actual edit URL)
481
+ // This prevents false edit mode detection when templateDetails persists in Redux from previous template
482
+ const isEditMode = hasParamsId && (hasTemplateDetails || hasBEETemplate);
483
+
484
+ if (isEditMode) {
485
+ // Edit mode: Determine editor based on template data
486
+ // Check if template was created in BEE editor
487
+ const editTemplateData = Email?.templateDetails || Email?.BEETemplate || templateData;
488
+ const isDragDrop = get(editTemplateData, 'versions.base.is_drag_drop', false)
489
+ || get(editTemplateData, 'base.is_drag_drop', false)
490
+ || get(editTemplateData, 'is_drag_drop', false)
491
+ || get(editTemplateData, 'versions.base[0].is_drag_drop', false);
492
+
493
+ // Check if BEE is enabled for org (equivalent to checkBeeEditorAllowedForLibrary)
494
+ // For library mode: BEE is enabled if editor prop is "BEE"
495
+ // For full mode: BEE is always enabled
496
+ const isBeeEnabled = isFullMode || (editor === "BEE" && !isFullMode) || checkBeeEditorEnabled();
497
+
498
+ // If template was created in BEE AND BEE is enabled → open in BEE editor
499
+ // Otherwise → open in HTML editor (fallback)
500
+ // IMPORTANT: When supportCKEditor is false, default to HTML editor unless explicitly BEE
501
+ if (isDragDrop && isBeeEnabled) {
502
+ editorType = 'BEE';
503
+ selectedEditorMode = null; // BEE uses existing flow
504
+ } else {
505
+ // Fallback to HTML editor if BEE not enabled or template not created in BEE
506
+ // This ensures HTML editor is used when supportCKEditor is false
507
+ editorType = 'HTML';
508
+ selectedEditorMode = EMAIL_CREATE_MODES.HTML_EDITOR;
509
+ }
510
+ } else if (selectedCreateMode === EMAIL_CREATE_MODES.EDITOR) {
511
+ // EDITOR mode: Check if selected template is a BEE template
512
+ // When a default template is selected, it's stored in Templates.BEETemplate
513
+ const beeTemplate = Email?.BEETemplate || SelectedEdmDefaultTemplate;
514
+ const isBEETemplate = beeTemplate && (
515
+ get(beeTemplate, 'versions.base.is_drag_drop') === true
516
+ || get(beeTemplate, 'base.is_drag_drop') === true
517
+ || beeTemplate.is_drag_drop === true
518
+ );
519
+
520
+ if (isBEETemplate && checkBeeEditorEnabled()) {
521
+ // Template is BEE and BEE is enabled → use BEE editor
522
+ editorType = 'BEE';
523
+ selectedEditorMode = null; // BEE uses existing flow
524
+ } else {
525
+ // Template is not BEE or BEE is disabled → use HTML editor
526
+ editorType = 'HTML';
527
+ selectedEditorMode = EMAIL_CREATE_MODES.HTML_EDITOR;
528
+ }
529
+ } else {
530
+ // Default: When supportCKEditor is false and no mode selected, use HTML editor
531
+ editorType = 'HTML';
532
+ selectedEditorMode = EMAIL_CREATE_MODES.HTML_EDITOR;
533
+ }
534
+ }
535
+ // UPLOAD mode uses existing editor prop
536
+ }
537
+ // Legacy flow (supportCKEditor is true): Use existing editor prop as-is - no changes
538
+
539
+ return {
540
+ setIsLoadingContent,
541
+ key: "email-create-template",
542
+ location: routeParams,
543
+ route: { name: 'email' },
544
+ params: {},
545
+ isGetFormData,
546
+ getFormdata,
547
+ getFormSubscriptionData: getFormdata,
548
+ getDefaultTags: type,
549
+ isFullMode,
550
+ defaultData: { 'template-name': templateName },
551
+ cap,
552
+ showTemplateName,
553
+ showLiquidErrorInFooter,
554
+ onValidationFail,
555
+ forwardedTags,
556
+ selectedOfferDetails,
557
+ onPreviewContentClicked,
558
+ onTestContentClicked,
559
+ editor: editorType,
560
+ selectedEditorMode, // Pass selected mode to Email component (only for HTML_EDITOR)
561
+ moduleType,
562
+ eventContextTags,
563
+ isLoyaltyModule,
564
+ showTestAndPreviewSlidebox,
565
+ handleTestAndPreview,
566
+ handleCloseTestAndPreview,
567
+ isTestAndPreviewMode,
568
+ };
569
+ }, [
305
570
  setIsLoadingContent,
306
571
  routeParams,
572
+ Email?.BEETemplate,
573
+ SelectedEdmDefaultTemplate,
574
+ checkBeeEditorEnabled,
307
575
  isGetFormData,
308
576
  getFormdata,
309
577
  type,
@@ -325,8 +593,118 @@ const useEmailWrapper = ({
325
593
  handleTestAndPreview,
326
594
  handleCloseTestAndPreview,
327
595
  isTestAndPreviewMode,
596
+ selectedCreateMode,
597
+ supportCKEditorFlag,
598
+ checkBeeEditorEnabled,
599
+ Email,
600
+ location,
601
+ params,
602
+ editor,
603
+ isFullMode,
604
+ templateData,
328
605
  ]);
329
606
 
607
+ const isShowEmailCreate = useMemo(() => {
608
+ // Check if we're in edit mode (templateDetails or BEETemplate exists, or params.id exists)
609
+ const hasTemplateDetails = Email?.templateDetails && !isEmpty(Email.templateDetails);
610
+ const hasBEETemplate = Email?.BEETemplate && !isEmpty(Email.BEETemplate);
611
+ const hasParamsId = params?.id || location?.query?.id || location?.params?.id || location?.pathname?.includes('/edit/');
612
+ const isEditMode = hasTemplateDetails || hasBEETemplate || hasParamsId;
613
+
614
+ // In edit mode with HTML editor (when supportCKEditor is false), always show editor
615
+ if (!supportCKEditorFlag && isEditMode) {
616
+ // Check if it's explicitly BEE editor
617
+ const isExplicitlyBEE = emailCreateMode === EMAIL_CREATE_MODES.DRAG_DROP
618
+ || (emailProps?.editor === 'BEE' && emailProps?.selectedEditorMode === null);
619
+ // If not BEE, show HTML editor
620
+ if (!isExplicitlyBEE) {
621
+ return true;
622
+ }
623
+ }
624
+
625
+ if (!selectedCreateMode) return false;
626
+
627
+ // For HTML Editor (new flow): Always show editor directly without template selection
628
+ // This takes precedence over step check to ensure HTML Editor is shown even if step is temporarily TEMPLATE_SELECTION
629
+ if (!supportCKEditorFlag && selectedCreateMode === EMAIL_CREATE_MODES.HTML_EDITOR) {
630
+ return true;
631
+ }
632
+
633
+ // CRITICAL: For DRAG_DROP mode, show template selection first (CmsTemplatesComponent)
634
+ // Only show editor (Email component with BEE) after template is selected
635
+ if (emailCreateMode === EMAIL_CREATE_MODES.DRAG_DROP || selectedCreateMode === EMAIL_CREATE_MODES.DRAG_DROP) {
636
+ // If we're in TEMPLATE_SELECTION step, show template selection (not email editor)
637
+ if (currentStep === STEPS.TEMPLATE_SELECTION) {
638
+ return false;
639
+ }
640
+ // After template selection, show editor when template is selected
641
+ return !isEmpty(SelectedEdmDefaultTemplate);
642
+ }
643
+
644
+ // If we're in TEMPLATE_SELECTION step, show template selection (not email editor)
645
+ // This applies to legacy Editor modes
646
+ if (currentStep === STEPS.TEMPLATE_SELECTION) {
647
+ return false;
648
+ }
649
+
650
+ // For Upload: Show editor when EmailLayout exists
651
+ if (emailCreateMode === EMAIL_CREATE_MODES.UPLOAD) {
652
+ return !isEmpty(EmailLayout);
653
+ }
654
+
655
+ // For Editor: Show editor when template is selected
656
+ return !isEmpty(SelectedEdmDefaultTemplate);
657
+ }, [currentStep, selectedCreateMode, supportCKEditorFlag, emailCreateMode, EmailLayout, SelectedEdmDefaultTemplate, Email?.templateDetails, Email?.BEETemplate, params?.id, location?.query?.id, location?.params?.id, location?.pathname, emailProps?.editor, emailProps?.selectedEditorMode]);
658
+
659
+ // Memoize static data
660
+ const modes = useMemo(() => {
661
+ const supportCKEditor = hasSupportCKEditor();
662
+ const isBeeEditorEnabledValue = checkBeeEditorEnabled();
663
+
664
+ if (supportCKEditor) {
665
+ // Legacy flow: Show only 2 options (Upload Zip, Use Editor)
666
+ return [
667
+ {
668
+ title: formatMessage(messages.zipUpload),
669
+ content: formatMessage(messages.zipUploadDesc),
670
+ value: EMAIL_CREATE_MODES.UPLOAD,
671
+ },
672
+ {
673
+ title: formatMessage(messages.useEditor),
674
+ content: formatMessage(messages.useEditorDesc),
675
+ value: EMAIL_CREATE_MODES.EDITOR,
676
+ },
677
+ ];
678
+ }
679
+
680
+ // New flow: Show 3 options (HTML Editor, Drag & Drop, Upload Zip)
681
+ return [
682
+ {
683
+ title: formatMessage(messages.htmlEditorTitle),
684
+ content: formatMessage(messages.htmlEditorDesc),
685
+ value: EMAIL_CREATE_MODES.HTML_EDITOR,
686
+ icon: <CapIcon type="code" />,
687
+ },
688
+ {
689
+ title: formatMessage(messages.dragDropEditorTitle),
690
+ content: formatMessage(messages.dragDropEditorDesc),
691
+ value: EMAIL_CREATE_MODES.DRAG_DROP,
692
+ icon: <CapIcon type="draggable" svgProps={{ fill: 'currentColor' }} />,
693
+ disabled: !isBeeEditorEnabledValue,
694
+ tooltipProps: !isBeeEditorEnabledValue ? {
695
+ title: formatMessage(messages.beeEditorDisabledTooltip),
696
+ placement: 'top',
697
+ } : undefined,
698
+ },
699
+ {
700
+ title: formatMessage(messages.uploadZipTitle),
701
+ content: formatMessage(messages.uploadZipDesc),
702
+ value: EMAIL_CREATE_MODES.UPLOAD,
703
+ icon: <CapIcon type="file" />,
704
+ },
705
+ ];
706
+ }, [formatMessage, checkBeeEditorEnabled]);
707
+
330
708
  // Prepare props for CmsTemplatesComponent
331
709
  const cmsTemplatesProps = useMemo(() => ({
332
710
  cmsTemplates: CmsTemplates,
@@ -335,6 +713,24 @@ const useEmailWrapper = ({
335
713
  currentOrgDetails: currentOrgDetails || cap?.currentOrgDetails,
336
714
  }), [CmsTemplates, useEditor, cmsTemplatesLoader, currentOrgDetails, cap]);
337
715
 
716
+ // Check if Next button should be shown (only for new flow)
717
+ const showNextButton = useMemo(() => !hasSupportCKEditor(), []);
718
+
719
+ // Check if Next button should be enabled (for new flow only)
720
+ const isNextButtonEnabled = useMemo(() => {
721
+ const supportCKEditor = hasSupportCKEditor();
722
+ if (supportCKEditor) {
723
+ // Legacy flow: No Next button, always enabled for auto-navigation
724
+ return false;
725
+ }
726
+ // New flow: Enable only when both template name and editor type are selected
727
+ // In library mode (isFullMode=false), template name is not required
728
+ // In full mode (isFullMode=true), template name is required
729
+ const hasTemplateName = !isFullMode || !isTemplateNameEmpty;
730
+ const hasEditorSelection = !!selectedCreateMode;
731
+ return hasTemplateName && hasEditorSelection;
732
+ }, [isTemplateNameEmpty, isFullMode, selectedCreateMode]);
733
+
338
734
  // Upload button label
339
735
  const uploadButtonLabel = formatMessage(messages.upload);
340
736
 
@@ -350,12 +746,15 @@ const useEmailWrapper = ({
350
746
  emailProps,
351
747
  cmsTemplatesProps,
352
748
  uploadButtonLabel,
749
+ showNextButton,
750
+ isNextButtonEnabled,
353
751
 
354
752
  // Event handlers
355
753
  onTemplateNameChange,
356
754
  onChange,
357
755
  useFileUpload,
756
+ handleNextClick,
358
757
  };
359
758
  };
360
759
 
361
- export default useEmailWrapper;
760
+ export default useEmailWrapper;