@capillarytech/creatives-library 8.0.242-alpha.10 → 8.0.242-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/Android.png +0 -0
- package/assets/iOS.png +0 -0
- package/config/app.js +1 -1
- package/constants/unified.js +2 -2
- package/initialReducer.js +0 -2
- package/package.json +1 -1
- package/services/api.js +5 -10
- package/services/tests/api.test.js +0 -18
- package/translations/en.json +4 -3
- package/utils/common.js +6 -5
- package/utils/commonUtils.js +1 -14
- package/utils/imageUrlUpload.js +141 -0
- package/utils/tests/commonUtil.test.js +0 -224
- package/utils/transformTemplateConfig.js +10 -0
- package/v2Components/CapDeviceContent/index.js +56 -61
- package/v2Components/CapImageUpload/constants.js +2 -0
- package/v2Components/CapImageUpload/index.js +65 -16
- package/v2Components/CapImageUpload/index.scss +4 -1
- package/v2Components/CapImageUpload/messages.js +5 -1
- package/v2Components/CapImageUrlUpload/constants.js +26 -0
- package/v2Components/CapImageUrlUpload/index.js +365 -0
- package/v2Components/CapImageUrlUpload/index.scss +35 -0
- package/v2Components/CapImageUrlUpload/messages.js +47 -0
- package/v2Components/CapTagList/index.js +1 -6
- package/v2Components/CapTagListWithInput/index.js +1 -5
- package/v2Components/CapTagListWithInput/messages.js +1 -1
- package/v2Components/CapWhatsappCTA/tests/index.test.js +0 -5
- package/v2Components/ErrorInfoNote/index.js +72 -412
- package/v2Components/ErrorInfoNote/messages.js +0 -22
- package/v2Components/ErrorInfoNote/style.scss +2 -279
- package/v2Components/HtmlEditor/HTMLEditor.js +91 -220
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +133 -1132
- package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +12 -17
- package/v2Components/HtmlEditor/_htmlEditor.scss +45 -107
- package/v2Components/HtmlEditor/_index.lazy.scss +1 -1
- package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +101 -13
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +139 -148
- package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +1 -2
- package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
- package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +0 -9
- package/v2Components/HtmlEditor/components/EditorToolbar/index.js +1 -1
- package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +0 -22
- package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +7 -4
- package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +45 -35
- package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +3 -1
- package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
- package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +6 -7
- package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +6 -3
- package/v2Components/HtmlEditor/components/PreviewPane/index.js +11 -10
- package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +72 -70
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +31 -49
- package/v2Components/HtmlEditor/constants.js +20 -29
- package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +16 -373
- package/v2Components/HtmlEditor/hooks/useEditorContent.js +2 -5
- package/v2Components/HtmlEditor/hooks/useInAppContent.js +146 -88
- package/v2Components/HtmlEditor/index.js +1 -1
- package/v2Components/HtmlEditor/messages.js +85 -95
- package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +101 -99
- package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +25 -23
- package/v2Components/HtmlEditor/utils/validationAdapter.js +41 -34
- package/v2Components/MobilePushPreviewV2/index.js +7 -32
- package/v2Components/TemplatePreview/_templatePreview.scss +24 -44
- package/v2Components/TemplatePreview/index.js +32 -47
- package/v2Components/TemplatePreview/messages.js +0 -4
- package/v2Components/TestAndPreviewSlidebox/index.js +25 -31
- package/v2Containers/App/constants.js +5 -0
- package/v2Containers/BeeEditor/index.js +80 -82
- package/v2Containers/Cap/tests/__snapshots__/index.test.js.snap +4 -3
- package/v2Containers/CreativesContainer/SlideBoxContent.js +118 -148
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +3 -9
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +2 -2
- package/v2Containers/CreativesContainer/constants.js +2 -1
- package/v2Containers/CreativesContainer/index.js +41 -173
- package/v2Containers/CreativesContainer/messages.js +4 -4
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +210 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +354 -38
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +0 -36
- package/v2Containers/Email/actions.js +0 -7
- package/v2Containers/Email/constants.js +1 -5
- package/v2Containers/Email/index.js +0 -13
- package/v2Containers/Email/messages.js +0 -32
- package/v2Containers/Email/reducer.js +1 -12
- package/v2Containers/Email/sagas.js +6 -41
- package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +0 -2
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +7 -193
- package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +74 -40
- package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +67 -2
- package/v2Containers/EmailWrapper/constants.js +0 -2
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +67 -436
- package/v2Containers/EmailWrapper/index.js +23 -99
- package/v2Containers/EmailWrapper/messages.js +1 -61
- package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +214 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +77 -111
- package/v2Containers/InApp/actions.js +0 -7
- package/v2Containers/InApp/constants.js +4 -20
- package/v2Containers/InApp/index.js +357 -801
- package/v2Containers/InApp/index.scss +3 -4
- package/v2Containers/InApp/messages.js +3 -7
- package/v2Containers/InApp/reducer.js +3 -21
- package/v2Containers/InApp/sagas.js +9 -29
- package/v2Containers/InApp/selectors.js +5 -25
- package/v2Containers/InApp/tests/index.test.js +50 -154
- package/v2Containers/InApp/tests/reducer.test.js +0 -34
- package/v2Containers/InApp/tests/sagas.test.js +9 -61
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +12 -12
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +8 -8
- package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +100 -77
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +72 -63
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +184 -150
- package/v2Containers/SmsTrai/Create/tests/__snapshots__/index.test.js.snap +16 -12
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +32 -28
- package/v2Containers/TagList/index.js +1 -67
- package/v2Containers/Templates/ChannelTypeIllustration.js +13 -1
- package/v2Containers/Templates/_templates.scss +202 -56
- package/v2Containers/Templates/actions.js +2 -1
- package/v2Containers/Templates/constants.js +1 -0
- package/v2Containers/Templates/index.js +278 -128
- package/v2Containers/Templates/messages.js +24 -4
- package/v2Containers/Templates/reducer.js +2 -0
- package/v2Containers/Templates/tests/index.test.js +10 -0
- package/v2Containers/TemplatesV2/index.js +8 -1
- package/v2Containers/TemplatesV2/messages.js +4 -0
- package/v2Containers/WebPush/Create/components/BrandIconSection.js +108 -0
- package/v2Containers/WebPush/Create/components/ButtonForm.js +172 -0
- package/v2Containers/WebPush/Create/components/ButtonItem.js +101 -0
- package/v2Containers/WebPush/Create/components/ButtonList.js +145 -0
- package/v2Containers/WebPush/Create/components/ButtonsLinksSection.js +164 -0
- package/v2Containers/WebPush/Create/components/ButtonsLinksSection.test.js +463 -0
- package/v2Containers/WebPush/Create/components/FormActions.js +54 -0
- package/v2Containers/WebPush/Create/components/FormActions.test.js +163 -0
- package/v2Containers/WebPush/Create/components/MediaSection.js +142 -0
- package/v2Containers/WebPush/Create/components/MediaSection.test.js +341 -0
- package/v2Containers/WebPush/Create/components/MessageSection.js +103 -0
- package/v2Containers/WebPush/Create/components/MessageSection.test.js +268 -0
- package/v2Containers/WebPush/Create/components/NotificationTitleSection.js +87 -0
- package/v2Containers/WebPush/Create/components/NotificationTitleSection.test.js +210 -0
- package/v2Containers/WebPush/Create/components/TemplateNameSection.js +54 -0
- package/v2Containers/WebPush/Create/components/TemplateNameSection.test.js +143 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/ButtonsLinksSection.test.js.snap +86 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/FormActions.test.js.snap +16 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/MediaSection.test.js.snap +41 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/MessageSection.test.js.snap +54 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/NotificationTitleSection.test.js.snap +37 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/TemplateNameSection.test.js.snap +21 -0
- package/v2Containers/WebPush/Create/components/_buttons.scss +246 -0
- package/v2Containers/WebPush/Create/components/tests/ButtonForm.test.js +554 -0
- package/v2Containers/WebPush/Create/components/tests/ButtonItem.test.js +607 -0
- package/v2Containers/WebPush/Create/components/tests/ButtonList.test.js +633 -0
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonForm.test.js.snap +666 -0
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonItem.test.js.snap +74 -0
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonList.test.js.snap +78 -0
- package/v2Containers/WebPush/Create/hooks/useButtonManagement.js +138 -0
- package/v2Containers/WebPush/Create/hooks/useButtonManagement.test.js +406 -0
- package/v2Containers/WebPush/Create/hooks/useCharacterCount.js +30 -0
- package/v2Containers/WebPush/Create/hooks/useCharacterCount.test.js +151 -0
- package/v2Containers/WebPush/Create/hooks/useImageUpload.js +104 -0
- package/v2Containers/WebPush/Create/hooks/useImageUpload.test.js +538 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.js +122 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +633 -0
- package/v2Containers/WebPush/Create/index.js +1056 -0
- package/v2Containers/WebPush/Create/index.scss +134 -0
- package/v2Containers/WebPush/Create/messages.js +203 -0
- package/v2Containers/WebPush/Create/preview/DevicePreviewContent.js +228 -0
- package/v2Containers/WebPush/Create/preview/NotificationContainer.js +294 -0
- package/v2Containers/WebPush/Create/preview/PreviewContent.js +90 -0
- package/v2Containers/WebPush/Create/preview/PreviewControls.js +305 -0
- package/v2Containers/WebPush/Create/preview/PreviewDisclaimer.js +23 -0
- package/v2Containers/WebPush/Create/preview/WebPushPreview.js +150 -0
- package/v2Containers/WebPush/Create/preview/assets/Light.svg +53 -0
- package/v2Containers/WebPush/Create/preview/assets/Top.svg +5 -0
- package/v2Containers/WebPush/Create/preview/assets/android-arrow-down.svg +9 -0
- package/v2Containers/WebPush/Create/preview/assets/android-arrow-up.svg +9 -0
- package/v2Containers/WebPush/Create/preview/assets/chrome-icon.png +0 -0
- package/v2Containers/WebPush/Create/preview/assets/edge-icon.png +0 -0
- package/v2Containers/WebPush/Create/preview/assets/firefox-icon.svg +106 -0
- package/v2Containers/WebPush/Create/preview/assets/iOS.svg +26 -0
- package/v2Containers/WebPush/Create/preview/assets/macos-arrow-down-icon.svg +9 -0
- package/v2Containers/WebPush/Create/preview/assets/macos-triple-dot-icon.svg +9 -0
- package/v2Containers/WebPush/Create/preview/assets/opera-icon.svg +18 -0
- package/v2Containers/WebPush/Create/preview/assets/safari-icon.svg +29 -0
- package/v2Containers/WebPush/Create/preview/assets/windows-close-icon.svg +9 -0
- package/v2Containers/WebPush/Create/preview/assets/windows-triple-dot-icon.svg +9 -0
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileChromeHeader.js +47 -0
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +141 -0
- package/v2Containers/WebPush/Create/preview/components/IOSHeader.js +45 -0
- package/v2Containers/WebPush/Create/preview/components/NotificationExpandedContent.js +68 -0
- package/v2Containers/WebPush/Create/preview/components/NotificationHeader.js +61 -0
- package/v2Containers/WebPush/Create/preview/components/WindowsChromeExpanded.js +99 -0
- package/v2Containers/WebPush/Create/preview/components/tests/AndroidMobileExpanded.test.js +733 -0
- package/v2Containers/WebPush/Create/preview/components/tests/WindowsChromeExpanded.test.js +571 -0
- package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/AndroidMobileExpanded.test.js.snap +81 -0
- package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/WindowsChromeExpanded.test.js.snap +81 -0
- package/v2Containers/WebPush/Create/preview/config/notificationMappings.js +50 -0
- package/v2Containers/WebPush/Create/preview/constants.js +637 -0
- package/v2Containers/WebPush/Create/preview/notification-container.scss +79 -0
- package/v2Containers/WebPush/Create/preview/preview.scss +351 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-chrome.scss +370 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-edge.scss +12 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-firefox.scss +12 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-opera.scss +12 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-chrome.scss +47 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-edge.scss +11 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-firefox.scss +11 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-opera.scss +11 -0
- package/v2Containers/WebPush/Create/preview/styles/_base.scss +207 -0
- package/v2Containers/WebPush/Create/preview/styles/_ios.scss +153 -0
- package/v2Containers/WebPush/Create/preview/styles/_ipados.scss +107 -0
- package/v2Containers/WebPush/Create/preview/styles/_macos-chrome.scss +101 -0
- package/v2Containers/WebPush/Create/preview/styles/_windows-chrome.scss +229 -0
- package/v2Containers/WebPush/Create/preview/tests/DevicePreviewContent.test.js +909 -0
- package/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +1081 -0
- package/v2Containers/WebPush/Create/preview/tests/PreviewControls.test.js +723 -0
- package/v2Containers/WebPush/Create/preview/tests/WebPushPreview.test.js +943 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/DevicePreviewContent.test.js.snap +131 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/NotificationContainer.test.js.snap +112 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/PreviewControls.test.js.snap +144 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/WebPushPreview.test.js.snap +129 -0
- package/v2Containers/WebPush/Create/utils/payloadBuilder.js +94 -0
- package/v2Containers/WebPush/Create/utils/payloadBuilder.test.js +390 -0
- package/v2Containers/WebPush/Create/utils/previewUtils.js +89 -0
- package/v2Containers/WebPush/Create/utils/urlValidation.js +115 -0
- package/v2Containers/WebPush/Create/utils/urlValidation.test.js +449 -0
- package/v2Containers/WebPush/Create/utils/validation.js +75 -0
- package/v2Containers/WebPush/Create/utils/validation.test.js +283 -0
- package/v2Containers/WebPush/actions.js +60 -0
- package/v2Containers/WebPush/constants.js +128 -0
- package/v2Containers/WebPush/index.js +2 -0
- package/v2Containers/WebPush/reducer.js +104 -0
- package/v2Containers/WebPush/sagas.js +119 -0
- package/v2Containers/WebPush/selectors.js +65 -0
- package/v2Containers/WebPush/tests/reducer.test.js +863 -0
- package/v2Containers/WebPush/tests/sagas.test.js +566 -0
- package/v2Containers/WebPush/tests/selectors.test.js +843 -0
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +528 -431
- package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +0 -254
- package/v2Components/HtmlEditor/components/ValidationTabs/index.js +0 -362
- package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +0 -51
- package/v2Containers/BeePopupEditor/constants.js +0 -10
- package/v2Containers/BeePopupEditor/index.js +0 -193
- package/v2Containers/BeePopupEditor/tests/index.test.js +0 -627
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +0 -1046
- package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +0 -376
- package/v2Containers/InApp/__tests__/sagas.test.js +0 -363
- package/v2Containers/InApp/tests/selectors.test.js +0 -612
- package/v2Containers/InAppWrapper/components/InAppWrapperView.js +0 -162
- package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +0 -267
- package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +0 -9
- package/v2Containers/InAppWrapper/constants.js +0 -16
- package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +0 -473
- package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +0 -198
- package/v2Containers/InAppWrapper/index.js +0 -148
- package/v2Containers/InAppWrapper/messages.js +0 -49
- package/v2Containers/InappAdvance/index.js +0 -1099
- package/v2Containers/InappAdvance/index.scss +0 -10
- package/v2Containers/InappAdvance/tests/index.test.js +0 -448
|
@@ -1,1046 +0,0 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
useState, useEffect, useMemo, useCallback, useRef, useImperativeHandle, forwardRef,
|
|
3
|
-
} from 'react';
|
|
4
|
-
import PropTypes from 'prop-types';
|
|
5
|
-
import { injectIntl, FormattedMessage } from 'react-intl';
|
|
6
|
-
import isEmpty from 'lodash/isEmpty';
|
|
7
|
-
import get from 'lodash/get';
|
|
8
|
-
import _ from 'lodash';
|
|
9
|
-
import { CAP_SPACE_16 } from '@capillarytech/cap-ui-library/styled/variables';
|
|
10
|
-
import CapSpin from '@capillarytech/cap-ui-library/CapSpin';
|
|
11
|
-
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
12
|
-
import CapColumn from '@capillarytech/cap-ui-library/CapColumn';
|
|
13
|
-
import CapNotification from '@capillarytech/cap-ui-library/CapNotification';
|
|
14
|
-
import HTMLEditor from '../../../v2Components/HtmlEditor';
|
|
15
|
-
import CapTagListWithInput from '../../../v2Components/CapTagListWithInput';
|
|
16
|
-
import formBuilderMessages from '../../../v2Components/FormBuilder/messages';
|
|
17
|
-
import { validateLiquidTemplateContent } from '../../../utils/commonUtils';
|
|
18
|
-
import { hasLiquidSupportFeature } from '../../../utils/common';
|
|
19
|
-
import history from '../../../utils/history';
|
|
20
|
-
import messages from '../messages';
|
|
21
|
-
import emailMessages from '../../Email/messages';
|
|
22
|
-
import { validateTags } from '../../../utils/tagValidations';
|
|
23
|
-
import {
|
|
24
|
-
TAG, EMBEDDED, DEFAULT, FULL, LIBRARY,
|
|
25
|
-
} from '../../Whatsapp/constants';
|
|
26
|
-
import { EMAIL } from '../../CreativesContainer/constants';
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* EmailHTMLEditor Component
|
|
30
|
-
*
|
|
31
|
-
* IMPORTANT: This component is ONLY used when supportCKEditor flag is FALSE (new flow).
|
|
32
|
-
* When supportCKEditor is TRUE, the existing Email component with FormBuilder is used (legacy flow).
|
|
33
|
-
*
|
|
34
|
-
* A completely self-contained component for Email HTML Editor that handles:
|
|
35
|
-
* - Tag loading and management
|
|
36
|
-
* - Tag validation
|
|
37
|
-
* - Content editing with HTMLEditor
|
|
38
|
-
* - Template data extraction for edit mode
|
|
39
|
-
* - Save logic (full mode & library mode) with liquid validation
|
|
40
|
-
* - API calls via Email actions/sagas
|
|
41
|
-
*
|
|
42
|
-
* This component is independent and reusable, similar to Whatsapp and InApp channels.
|
|
43
|
-
*/
|
|
44
|
-
const EmailHTMLEditor = (props) => {
|
|
45
|
-
const {
|
|
46
|
-
intl,
|
|
47
|
-
location,
|
|
48
|
-
params,
|
|
49
|
-
getDefaultTags,
|
|
50
|
-
supportedTags,
|
|
51
|
-
metaEntities,
|
|
52
|
-
injectedTags,
|
|
53
|
-
globalActions,
|
|
54
|
-
loadingTags,
|
|
55
|
-
eventContextTags,
|
|
56
|
-
forwardedTags,
|
|
57
|
-
selectedOfferDetails,
|
|
58
|
-
currentOrgDetails,
|
|
59
|
-
isReadOnly = false,
|
|
60
|
-
fetchingLiquidTags = false,
|
|
61
|
-
createTemplateInProgress = false,
|
|
62
|
-
fetchingCmsData = false,
|
|
63
|
-
// Email Redux state
|
|
64
|
-
Email,
|
|
65
|
-
// Email actions for API calls
|
|
66
|
-
emailActions,
|
|
67
|
-
// Full mode props
|
|
68
|
-
isFullMode,
|
|
69
|
-
templateName,
|
|
70
|
-
showTemplateName,
|
|
71
|
-
isGetFormData,
|
|
72
|
-
getFormdata,
|
|
73
|
-
// Library mode props
|
|
74
|
-
templateData: templateDataProp,
|
|
75
|
-
// Uploaded content from zip file
|
|
76
|
-
EmailLayout,
|
|
77
|
-
// Liquid validation
|
|
78
|
-
getLiquidTags,
|
|
79
|
-
showLiquidErrorInFooter,
|
|
80
|
-
onValidationFail,
|
|
81
|
-
// Preview/Test
|
|
82
|
-
// Parent loading control
|
|
83
|
-
setIsLoadingContent,
|
|
84
|
-
forwardedRef,
|
|
85
|
-
} = props;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const { formatMessage } = intl;
|
|
89
|
-
|
|
90
|
-
// State for content and subject
|
|
91
|
-
const [htmlContent, setHtmlContent] = useState('');
|
|
92
|
-
const [loadedHtmlContent, setLoadedHtmlContent] = useState(''); // Stable content for HTMLEditor initialization
|
|
93
|
-
const [subject, setSubject] = useState('');
|
|
94
|
-
const [subjectError, setSubjectError] = useState('');
|
|
95
|
-
// State for template name (extracted from template data in Edit mode)
|
|
96
|
-
const [extractedTemplateName, setExtractedTemplateName] = useState('');
|
|
97
|
-
const [tagValidationError, setTagValidationError] = useState(null);
|
|
98
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
99
|
-
|
|
100
|
-
// Refs for tracking initialization and previous values
|
|
101
|
-
const contentInitializedRef = useRef(false);
|
|
102
|
-
const subjectInitializedRef = useRef(false);
|
|
103
|
-
const lastTemplateIdRef = useRef(null);
|
|
104
|
-
const fetchingTemplateIdRef = useRef(null); // Track which template we're currently fetching
|
|
105
|
-
const prevIsGetFormDataRef = useRef(false);
|
|
106
|
-
|
|
107
|
-
// Compute tags directly from metaEntities (same approach as Email component)
|
|
108
|
-
// Use deep equality check to prevent TagList from re-processing when tags haven't actually changed
|
|
109
|
-
// This fixes the slow expansion and React Intl errors when clicking nested tags
|
|
110
|
-
const tags = useMemo(() => {
|
|
111
|
-
let tagList = get(metaEntities, 'tags.standard', []);
|
|
112
|
-
const { type, module } = location?.query || {};
|
|
113
|
-
if (type === EMBEDDED && module === LIBRARY && !getDefaultTags) {
|
|
114
|
-
tagList = supportedTags || [];
|
|
115
|
-
}
|
|
116
|
-
return tagList;
|
|
117
|
-
}, [metaEntities, supportedTags, location, getDefaultTags]);
|
|
118
|
-
|
|
119
|
-
// Expose method to get formData for TestAndPreviewSlidebox
|
|
120
|
-
useImperativeHandle(forwardedRef, () => ({
|
|
121
|
-
getFormDataForPreview: () => {
|
|
122
|
-
const baseLanguage = get(currentOrgDetails, 'basic_details.base_language', 'en');
|
|
123
|
-
return {
|
|
124
|
-
"0": {
|
|
125
|
-
[baseLanguage]: {
|
|
126
|
-
'template-content': htmlContent || '',
|
|
127
|
-
'is_drag_drop': false,
|
|
128
|
-
},
|
|
129
|
-
activeTab: baseLanguage,
|
|
130
|
-
selectedLanguages: [baseLanguage],
|
|
131
|
-
base: true,
|
|
132
|
-
},
|
|
133
|
-
'template-subject': subject || '',
|
|
134
|
-
};
|
|
135
|
-
},
|
|
136
|
-
getContentForPreview: () => htmlContent || '',
|
|
137
|
-
}), [htmlContent, subject, currentOrgDetails]);
|
|
138
|
-
|
|
139
|
-
// Check if liquid support is enabled
|
|
140
|
-
const isLiquidEnabled = hasLiquidSupportFeature();
|
|
141
|
-
|
|
142
|
-
// Detect edit mode
|
|
143
|
-
const hasParamsId = params?.id || location?.query?.id || location?.params?.id || location?.pathname?.includes('/edit/');
|
|
144
|
-
const currentTemplateId = templateDataProp?._id || params?.id || location?.query?.id || location?.params?.id
|
|
145
|
-
|| location?.pathname?.match(/\/edit\/([^/]+)/)?.[1];
|
|
146
|
-
const isEditMode = !!currentTemplateId || !!hasParamsId;
|
|
147
|
-
|
|
148
|
-
// Load tags on component mount
|
|
149
|
-
useEffect(() => {
|
|
150
|
-
const { type, module } = location?.query || {};
|
|
151
|
-
const isEmbedded = type === EMBEDDED;
|
|
152
|
-
const query = {
|
|
153
|
-
layout: EMAIL,
|
|
154
|
-
type: TAG,
|
|
155
|
-
context: isEmbedded ? module : DEFAULT,
|
|
156
|
-
embedded: isEmbedded ? type : FULL,
|
|
157
|
-
};
|
|
158
|
-
if (getDefaultTags) {
|
|
159
|
-
query.context = getDefaultTags;
|
|
160
|
-
}
|
|
161
|
-
if (globalActions && globalActions.fetchSchemaForEntity) {
|
|
162
|
-
globalActions.fetchSchemaForEntity(query);
|
|
163
|
-
}
|
|
164
|
-
}, []);
|
|
165
|
-
|
|
166
|
-
// Initialize content from EmailLayout (uploaded zip) in create mode
|
|
167
|
-
useEffect(() => {
|
|
168
|
-
// Only check EmailLayout in create mode (not edit mode)
|
|
169
|
-
if (isEditMode) {
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Check if EmailLayout has content from zip upload
|
|
174
|
-
if (EmailLayout) {
|
|
175
|
-
// EmailLayout can be a string (HTML content) or an object with html property
|
|
176
|
-
const uploadedContent = typeof EmailLayout === 'string'
|
|
177
|
-
? EmailLayout
|
|
178
|
-
: (EmailLayout.html || EmailLayout.content || '');
|
|
179
|
-
|
|
180
|
-
if (uploadedContent) {
|
|
181
|
-
// IMPORTANT: Set both htmlContent and loadedHtmlContent for ZIP upload
|
|
182
|
-
// loadedHtmlContent is used by HTMLEditor's initialContent prop
|
|
183
|
-
setHtmlContent(uploadedContent);
|
|
184
|
-
setLoadedHtmlContent(uploadedContent);
|
|
185
|
-
setIsLoading(false);
|
|
186
|
-
if (setIsLoadingContent) {
|
|
187
|
-
setIsLoadingContent(false);
|
|
188
|
-
}
|
|
189
|
-
} else {
|
|
190
|
-
// No uploaded content, stop loading
|
|
191
|
-
setIsLoading(false);
|
|
192
|
-
if (setIsLoadingContent) {
|
|
193
|
-
setIsLoadingContent(false);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
} else {
|
|
197
|
-
// No EmailLayout, stop loading
|
|
198
|
-
setIsLoading(false);
|
|
199
|
-
if (setIsLoadingContent) {
|
|
200
|
-
setIsLoadingContent(false);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}, [EmailLayout, isEditMode, setIsLoadingContent]);
|
|
204
|
-
|
|
205
|
-
// Edit mode: Extract template data and load content/subject
|
|
206
|
-
useEffect(() => {
|
|
207
|
-
if (!isEditMode) {
|
|
208
|
-
// Create mode: stop loading immediately
|
|
209
|
-
setIsLoading(false);
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const templateDataFromRedux = Email?.templateDetails || Email?.BEETemplate;
|
|
214
|
-
const isTemplateLoading = Email?.getTemplateDetailsInProgress || Email?.fetchingCmsData;
|
|
215
|
-
|
|
216
|
-
// Check if template ID changed (switching templates)
|
|
217
|
-
const templateIdChanged = currentTemplateId
|
|
218
|
-
&& lastTemplateIdRef.current
|
|
219
|
-
&& currentTemplateId !== lastTemplateIdRef.current;
|
|
220
|
-
|
|
221
|
-
// Reset refs when switching templates
|
|
222
|
-
if (templateIdChanged) {
|
|
223
|
-
contentInitializedRef.current = false;
|
|
224
|
-
subjectInitializedRef.current = false;
|
|
225
|
-
lastTemplateIdRef.current = currentTemplateId;
|
|
226
|
-
setHtmlContent('');
|
|
227
|
-
setSubject('');
|
|
228
|
-
setExtractedTemplateName('');
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Set last template ID on first load
|
|
232
|
-
if (currentTemplateId && !lastTemplateIdRef.current) {
|
|
233
|
-
lastTemplateIdRef.current = currentTemplateId;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Check if templateDataProp has complete data
|
|
237
|
-
// Check if templateDataProp has complete data (must have actual content string)
|
|
238
|
-
const hasCompleteTemplateData = templateDataProp && (
|
|
239
|
-
(templateDataProp.emailBody || templateDataProp.html_content || templateDataProp['template-content'])
|
|
240
|
-
|| (templateDataProp.base && (templateDataProp.base.html_content || templateDataProp.base.emailBody || templateDataProp.base['template-content']))
|
|
241
|
-
|| (templateDataProp.versions?.base && (
|
|
242
|
-
// Check active tab content in versions
|
|
243
|
-
(() => {
|
|
244
|
-
const { base } = templateDataProp.versions;
|
|
245
|
-
const activeTab = base.activeTab || 'en';
|
|
246
|
-
const langData = base[activeTab] || {};
|
|
247
|
-
return langData['template-content'] || langData.html_content || base.html_content || base.emailBody;
|
|
248
|
-
})()
|
|
249
|
-
))
|
|
250
|
-
);
|
|
251
|
-
if (hasCompleteTemplateData && !contentInitializedRef.current) {
|
|
252
|
-
let extractedContent = '';
|
|
253
|
-
let extractedSubject = '';
|
|
254
|
-
let extractedName = '';
|
|
255
|
-
|
|
256
|
-
if (templateDataProp.base) {
|
|
257
|
-
extractedContent = templateDataProp.base['template-content'] || templateDataProp.base.html_content || templateDataProp.base.emailBody || '';
|
|
258
|
-
extractedSubject = templateDataProp.base.subject || templateDataProp.base.emailSubject || '';
|
|
259
|
-
} else if (templateDataProp.versions && templateDataProp.versions.base) {
|
|
260
|
-
const { base } = templateDataProp.versions;
|
|
261
|
-
const activeTab = base.activeTab || 'en';
|
|
262
|
-
const languageData = base[activeTab] || {};
|
|
263
|
-
|
|
264
|
-
extractedContent = languageData['template-content']
|
|
265
|
-
|| languageData.html_content
|
|
266
|
-
|| base.html_content
|
|
267
|
-
|| base.emailBody
|
|
268
|
-
|| '';
|
|
269
|
-
|
|
270
|
-
extractedSubject = base.subject || base.emailSubject || '';
|
|
271
|
-
} else {
|
|
272
|
-
extractedContent = templateDataProp['template-content'] || templateDataProp.emailBody || templateDataProp.html_content || '';
|
|
273
|
-
extractedSubject = templateDataProp.emailSubject || templateDataProp.subject || '';
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// Extract template name from templateDataProp
|
|
277
|
-
extractedName = templateDataProp.name || get(templateDataProp, 'versions.base.name') || '';
|
|
278
|
-
|
|
279
|
-
// IMPORTANT: Set both htmlContent and loadedHtmlContent
|
|
280
|
-
// loadedHtmlContent is used by HTMLEditor's initialContent prop
|
|
281
|
-
setHtmlContent(extractedContent);
|
|
282
|
-
setLoadedHtmlContent(extractedContent);
|
|
283
|
-
setSubject(extractedSubject);
|
|
284
|
-
setExtractedTemplateName(extractedName);
|
|
285
|
-
contentInitializedRef.current = true;
|
|
286
|
-
subjectInitializedRef.current = true;
|
|
287
|
-
setIsLoading(false);
|
|
288
|
-
if (setIsLoadingContent) {
|
|
289
|
-
setIsLoadingContent(false);
|
|
290
|
-
}
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
if (currentTemplateId && emailActions?.getTemplateDetails && !isTemplateLoading) {
|
|
295
|
-
const isTemplateIdChanged = lastTemplateIdRef.current !== currentTemplateId;
|
|
296
|
-
const needsContent = !contentInitializedRef.current;
|
|
297
|
-
const alreadyFetching = fetchingTemplateIdRef.current === currentTemplateId;
|
|
298
|
-
const shouldFetch = (isTemplateIdChanged || needsContent) && !alreadyFetching;
|
|
299
|
-
|
|
300
|
-
// Fetch fresh data when template ID changes OR when we don't have content loaded yet
|
|
301
|
-
// BUT only if we're not already fetching this template
|
|
302
|
-
if (shouldFetch) {
|
|
303
|
-
fetchingTemplateIdRef.current = currentTemplateId; // Mark as fetching
|
|
304
|
-
emailActions.getTemplateDetails(currentTemplateId, 'email');
|
|
305
|
-
lastTemplateIdRef.current = currentTemplateId;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// **IMPORTANT: Clear stale Redux data in create mode**
|
|
310
|
-
// When not in edit mode (create mode), clear any existing template data from Redux
|
|
311
|
-
// This prevents previous template data from persisting when switching from Edit to Create
|
|
312
|
-
if (!currentTemplateId && !isEditMode && (templateDataFromRedux?._id || templateDataFromRedux?.name)) {
|
|
313
|
-
// Clear stale template data - component will handle via resetTemplateData or clearAllValues
|
|
314
|
-
if (emailActions?.clearAllValues) {
|
|
315
|
-
emailActions.clearAllValues();
|
|
316
|
-
}
|
|
317
|
-
// Reset component state to ensure clean slate for create mode
|
|
318
|
-
setExtractedTemplateName('');
|
|
319
|
-
contentInitializedRef.current = false;
|
|
320
|
-
subjectInitializedRef.current = false;
|
|
321
|
-
lastTemplateIdRef.current = null;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// Stop loading if template is loading
|
|
325
|
-
if (isTemplateLoading) {
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
// Extract from Redux data
|
|
330
|
-
const hasTemplateDataFromRedux = templateDataFromRedux
|
|
331
|
-
&& (templateDataFromRedux._id || templateDataFromRedux.name || templateDataFromRedux.versions);
|
|
332
|
-
|
|
333
|
-
if (hasTemplateDataFromRedux && currentTemplateId) {
|
|
334
|
-
const reduxTemplateId = templateDataFromRedux?._id;
|
|
335
|
-
|
|
336
|
-
if (reduxTemplateId === currentTemplateId) {
|
|
337
|
-
const baseData = get(templateDataFromRedux, 'versions.base') || get(templateDataFromRedux, 'base') || {};
|
|
338
|
-
const activeTab = baseData.activeTab
|
|
339
|
-
|| get(currentOrgDetails, 'basic_details.base_language', 'en');
|
|
340
|
-
const languageData = baseData[activeTab] || {};
|
|
341
|
-
|
|
342
|
-
const extractedContent = languageData['template-content']
|
|
343
|
-
|| languageData.html_content
|
|
344
|
-
|| baseData.html_content
|
|
345
|
-
|| baseData['template-content']
|
|
346
|
-
|| get(templateDataFromRedux, 'html_content')
|
|
347
|
-
|| get(templateDataFromRedux, 'template-content')
|
|
348
|
-
|| '';
|
|
349
|
-
|
|
350
|
-
const extractedSubject = baseData.subject
|
|
351
|
-
|| get(templateDataFromRedux, 'subject')
|
|
352
|
-
|| get(templateDataFromRedux, 'versions.base.subject')
|
|
353
|
-
|| '';
|
|
354
|
-
|
|
355
|
-
// Extract template name from Redux data
|
|
356
|
-
const extractedName = templateDataFromRedux.name || '';
|
|
357
|
-
|
|
358
|
-
// Smart update logic:
|
|
359
|
-
// 1. Always update loadedHtmlContent if Redux data is different (keep sync with backend)
|
|
360
|
-
// 2. Update htmlContent ONLY if it matches the OLD loadedHtmlContent (user hasn't edited)
|
|
361
|
-
// OR if it's the first initialization
|
|
362
|
-
if (extractedContent !== loadedHtmlContent) {
|
|
363
|
-
setLoadedHtmlContent(extractedContent);
|
|
364
|
-
|
|
365
|
-
if (!contentInitializedRef.current || htmlContent === loadedHtmlContent) {
|
|
366
|
-
setHtmlContent(extractedContent);
|
|
367
|
-
setSubject(extractedSubject);
|
|
368
|
-
setExtractedTemplateName(extractedName);
|
|
369
|
-
}
|
|
370
|
-
} else if (!contentInitializedRef.current) {
|
|
371
|
-
// First load, even if content matches (e.g. empty), ensure we set state
|
|
372
|
-
setHtmlContent(extractedContent);
|
|
373
|
-
setLoadedHtmlContent(extractedContent);
|
|
374
|
-
setSubject(extractedSubject);
|
|
375
|
-
setExtractedTemplateName(extractedName);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
contentInitializedRef.current = true;
|
|
379
|
-
subjectInitializedRef.current = true;
|
|
380
|
-
|
|
381
|
-
// Only clear fetching ref if we are not loading anymore
|
|
382
|
-
// This prevents race conditions where we load stale data while real fetch is pending
|
|
383
|
-
if (!isTemplateLoading) {
|
|
384
|
-
fetchingTemplateIdRef.current = null;
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
setIsLoading(false);
|
|
389
|
-
if (setIsLoadingContent) {
|
|
390
|
-
setIsLoadingContent(false);
|
|
391
|
-
}
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
// Fallback: stop loading anyway
|
|
396
|
-
if (!isTemplateLoading && !hasTemplateDataFromRedux && !hasCompleteTemplateData) {
|
|
397
|
-
setHtmlContent('');
|
|
398
|
-
setLoadedHtmlContent(''); // Set stable loaded content
|
|
399
|
-
setSubject('');
|
|
400
|
-
setExtractedTemplateName('');
|
|
401
|
-
setIsLoading(false);
|
|
402
|
-
if (setIsLoadingContent) {
|
|
403
|
-
setIsLoadingContent(false);
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
}, [
|
|
407
|
-
Email?.templateDetails,
|
|
408
|
-
Email?.BEETemplate,
|
|
409
|
-
Email?.getTemplateDetailsInProgress,
|
|
410
|
-
Email?.fetchingCmsData,
|
|
411
|
-
templateDataProp,
|
|
412
|
-
currentTemplateId,
|
|
413
|
-
isEditMode,
|
|
414
|
-
emailActions,
|
|
415
|
-
currentOrgDetails,
|
|
416
|
-
]);
|
|
417
|
-
|
|
418
|
-
// Handle loading state
|
|
419
|
-
useEffect(() => {
|
|
420
|
-
const isAnyApiInProgress = loadingTags || fetchingLiquidTags || createTemplateInProgress || fetchingCmsData;
|
|
421
|
-
|
|
422
|
-
// Stop loading when no API is in progress and tags are loaded
|
|
423
|
-
// Use optional chaining to safely access tags
|
|
424
|
-
if (!isAnyApiInProgress && Array.isArray(tags) && tags?.length >= 0) {
|
|
425
|
-
setIsLoading(false);
|
|
426
|
-
} else if (isAnyApiInProgress) {
|
|
427
|
-
setIsLoading(true);
|
|
428
|
-
}
|
|
429
|
-
}, [loadingTags, tags, fetchingLiquidTags, createTemplateInProgress, fetchingCmsData]);
|
|
430
|
-
|
|
431
|
-
// Handle content change from HTMLEditor
|
|
432
|
-
const handleContentChange = useCallback((content) => {
|
|
433
|
-
setHtmlContent(content);
|
|
434
|
-
|
|
435
|
-
// Validate tags
|
|
436
|
-
if (tags.length > 0 || !isEmpty(injectedTags)) {
|
|
437
|
-
const validationResult = validateTags({
|
|
438
|
-
content,
|
|
439
|
-
tagsParam: tags,
|
|
440
|
-
injectedTagsParams: injectedTags,
|
|
441
|
-
location,
|
|
442
|
-
tagModule: getDefaultTags,
|
|
443
|
-
eventContextTags,
|
|
444
|
-
});
|
|
445
|
-
|
|
446
|
-
if (!validationResult.valid) {
|
|
447
|
-
setTagValidationError(validationResult);
|
|
448
|
-
} else {
|
|
449
|
-
setTagValidationError(null);
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
}, [tags, injectedTags, location, getDefaultTags, eventContextTags]);
|
|
453
|
-
|
|
454
|
-
// Handle tag insertion into Subject field
|
|
455
|
-
const handleSubjectTagSelect = useCallback((data) => {
|
|
456
|
-
if (data) {
|
|
457
|
-
const tagToInsert = `{{${data}}}`;
|
|
458
|
-
const input = document.getElementById('template-subject') || document.querySelector('#template-subject input');
|
|
459
|
-
let subjectValue = subject || '';
|
|
460
|
-
try {
|
|
461
|
-
if (input && (typeof input.selectionStart === 'number')) {
|
|
462
|
-
const startPos = input.selectionStart;
|
|
463
|
-
const endPos = input.selectionEnd;
|
|
464
|
-
subjectValue = `${subjectValue.substring(0, startPos)}${tagToInsert}${subjectValue.substring(endPos)}`;
|
|
465
|
-
setSubject(subjectValue);
|
|
466
|
-
try {
|
|
467
|
-
input.focus();
|
|
468
|
-
const newPos = startPos + tagToInsert.length;
|
|
469
|
-
input.selectionStart = newPos;
|
|
470
|
-
input.selectionEnd = newPos;
|
|
471
|
-
} catch (e) {
|
|
472
|
-
// Ignore focus errors
|
|
473
|
-
}
|
|
474
|
-
} else {
|
|
475
|
-
subjectValue = `${subjectValue}${tagToInsert}`;
|
|
476
|
-
setSubject(subjectValue);
|
|
477
|
-
if (input) {
|
|
478
|
-
try {
|
|
479
|
-
input.value = subjectValue;
|
|
480
|
-
} catch (e) {
|
|
481
|
-
// Ignore value setting errors
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
} catch (e) {
|
|
486
|
-
// Fallback: safe append
|
|
487
|
-
subjectValue = `${subjectValue}${tagToInsert}`;
|
|
488
|
-
setSubject(subjectValue);
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
}, [subject]);
|
|
492
|
-
|
|
493
|
-
// Handle subject change
|
|
494
|
-
const handleSubjectChange = useCallback((e) => {
|
|
495
|
-
const newSubject = e.target.value;
|
|
496
|
-
setSubject(newSubject);
|
|
497
|
-
if (newSubject && subjectError) {
|
|
498
|
-
setSubjectError('');
|
|
499
|
-
}
|
|
500
|
-
}, [subjectError]);
|
|
501
|
-
|
|
502
|
-
// Handle Save/Update with liquid validation
|
|
503
|
-
const handleSave = useCallback(() => {
|
|
504
|
-
// 1. Validate Subject - BLOCKING (matches CK/BEE behavior)
|
|
505
|
-
if (!subject || !subject.trim()) {
|
|
506
|
-
const errorMessage = formatMessage(emailMessages["Email Subject cannot be empty."]);
|
|
507
|
-
setSubjectError(errorMessage);
|
|
508
|
-
// Reset parent state so next click is detected as a change
|
|
509
|
-
if (onValidationFail) {
|
|
510
|
-
onValidationFail();
|
|
511
|
-
}
|
|
512
|
-
// IMPORTANT: Return here to block save - matches CK/BEE editor behavior
|
|
513
|
-
return;
|
|
514
|
-
}
|
|
515
|
-
// Clear error if subject is valid
|
|
516
|
-
if (subjectError) {
|
|
517
|
-
setSubjectError('');
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
// 2. Validate Content Tags
|
|
522
|
-
// For NON-liquid orgs: BLOCKING validation (matches CK/BEE behavior)
|
|
523
|
-
// For liquid orgs: Non-blocking (extractTags API will validate)
|
|
524
|
-
if (tags.length > 0 || !isEmpty(injectedTags)) {
|
|
525
|
-
const validationResult = validateTags({
|
|
526
|
-
content: htmlContent,
|
|
527
|
-
tagsParam: tags,
|
|
528
|
-
injectedTagsParams: injectedTags,
|
|
529
|
-
location,
|
|
530
|
-
tagModule: getDefaultTags,
|
|
531
|
-
eventContextTags,
|
|
532
|
-
});
|
|
533
|
-
|
|
534
|
-
const hasUnsupportedTags = validationResult?.unsupportedTags?.length > 0;
|
|
535
|
-
if (!validationResult?.valid || hasUnsupportedTags) {
|
|
536
|
-
setTagValidationError(validationResult);
|
|
537
|
-
|
|
538
|
-
// IMPORTANT: For non-liquid orgs, block save (like CK/BEE editor)
|
|
539
|
-
// For liquid orgs, continue (extractTags API will validate)
|
|
540
|
-
if (!isLiquidEnabled) {
|
|
541
|
-
// Show notification popup like CK/BEE editor
|
|
542
|
-
const baseLanguage = get(currentOrgDetails, 'basic_details.base_language', 'en');
|
|
543
|
-
|
|
544
|
-
const contentNotValidMsg = intl.formatMessage(formBuilderMessages.contentNotValidLanguage);
|
|
545
|
-
let errorMessage = `${contentNotValidMsg} ${baseLanguage}`;
|
|
546
|
-
|
|
547
|
-
if (hasUnsupportedTags) {
|
|
548
|
-
const unsupportedTagsMsg = intl.formatMessage(formBuilderMessages.unsupportedTags);
|
|
549
|
-
errorMessage += `\n${unsupportedTagsMsg} ${validationResult?.unsupportedTags?.join(', ')}`;
|
|
550
|
-
}
|
|
551
|
-
if (validationResult?.missingTags?.length > 0) {
|
|
552
|
-
const missingTagsMsg = intl.formatMessage(formBuilderMessages.missingTags);
|
|
553
|
-
errorMessage += `\n${missingTagsMsg} ${validationResult?.missingTags?.join(', ')}`;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
const type = 'error';
|
|
557
|
-
CapNotification[type]({
|
|
558
|
-
message: `${type.toUpperCase()} ! ! ! `,
|
|
559
|
-
description: errorMessage,
|
|
560
|
-
duration: 5,
|
|
561
|
-
});
|
|
562
|
-
|
|
563
|
-
// Reset parent state so next click is detected as a change
|
|
564
|
-
if (onValidationFail) {
|
|
565
|
-
onValidationFail();
|
|
566
|
-
}
|
|
567
|
-
// Block save for non-liquid orgs
|
|
568
|
-
return;
|
|
569
|
-
}
|
|
570
|
-
// For liquid orgs, just show warning and continue
|
|
571
|
-
} else {
|
|
572
|
-
// Clear tag errors if valid
|
|
573
|
-
if (tagValidationError) {
|
|
574
|
-
setTagValidationError(null);
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
const baseLanguage = get(currentOrgDetails, 'basic_details.base_language', 'en');
|
|
581
|
-
|
|
582
|
-
// Actual save function - called after liquid validation (if enabled) or directly
|
|
583
|
-
const performSave = () => {
|
|
584
|
-
if (isFullMode) {
|
|
585
|
-
// Full mode: Call email actions directly
|
|
586
|
-
const templateDataFromRedux = Email?.templateDetails || Email?.BEETemplate;
|
|
587
|
-
// IMPORTANT: Only use currentTemplateId from URL/params - don't fallback to Redux data
|
|
588
|
-
// which might be stale from previous template in create mode
|
|
589
|
-
const templateId = currentTemplateId;
|
|
590
|
-
const isEditModeForSave = !!templateId;
|
|
591
|
-
|
|
592
|
-
const langId = get(currentOrgDetails, `basic_details.languages.${baseLanguage}.lang_id`, '');
|
|
593
|
-
const language = get(currentOrgDetails, `basic_details.languages.${baseLanguage}.language`, baseLanguage);
|
|
594
|
-
|
|
595
|
-
// Generate or reuse tabKey
|
|
596
|
-
let tabKey = _.uniqueId();
|
|
597
|
-
if (isEditMode && templateDataFromRedux) {
|
|
598
|
-
const existingTabKey = get(templateDataFromRedux, 'versions.base.tabKey')
|
|
599
|
-
|| get(templateDataFromRedux, 'base.tabKey');
|
|
600
|
-
if (existingTabKey) {
|
|
601
|
-
tabKey = existingTabKey;
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
const languageData = {
|
|
606
|
-
'template-content': htmlContent || '',
|
|
607
|
-
"is_drag_drop": false,
|
|
608
|
-
"drag_drop_id": '',
|
|
609
|
-
"lang_id": langId,
|
|
610
|
-
"iso_code": baseLanguage,
|
|
611
|
-
"language": language,
|
|
612
|
-
"tabKey": tabKey,
|
|
613
|
-
};
|
|
614
|
-
|
|
615
|
-
const baseStructure = {
|
|
616
|
-
[baseLanguage]: languageData,
|
|
617
|
-
activeTab: baseLanguage,
|
|
618
|
-
selectedLanguages: [baseLanguage],
|
|
619
|
-
base: true,
|
|
620
|
-
tabKey,
|
|
621
|
-
subject: subject || '',
|
|
622
|
-
};
|
|
623
|
-
|
|
624
|
-
const historyEntry = {
|
|
625
|
-
[baseLanguage]: { ...languageData },
|
|
626
|
-
activeTab: baseLanguage,
|
|
627
|
-
selectedLanguages: [baseLanguage],
|
|
628
|
-
base: true,
|
|
629
|
-
tabKey,
|
|
630
|
-
subject: subject || '',
|
|
631
|
-
};
|
|
632
|
-
|
|
633
|
-
const finalTemplateName = isEditModeForSave ? (extractedTemplateName || '') : (templateName || '');
|
|
634
|
-
|
|
635
|
-
const obj = {
|
|
636
|
-
type: EMAIL,
|
|
637
|
-
// In Edit mode, use extractedTemplateName; in Create mode, use templateName prop
|
|
638
|
-
name: finalTemplateName,
|
|
639
|
-
versions: {
|
|
640
|
-
base: baseStructure,
|
|
641
|
-
history: [historyEntry],
|
|
642
|
-
},
|
|
643
|
-
};
|
|
644
|
-
|
|
645
|
-
if (isEditModeForSave && templateId) {
|
|
646
|
-
obj._id = templateId;
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
if (emailActions?.transformEmailTemplate && emailActions?.createTemplate) {
|
|
650
|
-
emailActions.transformEmailTemplate(obj, (newEmail) => {
|
|
651
|
-
emailActions.createTemplate(newEmail, (createResponse) => {
|
|
652
|
-
// Handle error response (from 409 or other failures)
|
|
653
|
-
if (createResponse?.error) {
|
|
654
|
-
// Error already shown by Email component via stopValidation
|
|
655
|
-
// Just reset parent state so next click is detected
|
|
656
|
-
if (onValidationFail) {
|
|
657
|
-
onValidationFail();
|
|
658
|
-
}
|
|
659
|
-
return;
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
// Handle success response
|
|
663
|
-
if (createResponse && createResponse.templateId) {
|
|
664
|
-
const successMessage = formatMessage(emailMessages.emailCreateSuccess);
|
|
665
|
-
CapNotification.success({ message: successMessage, key: 'create-template-success' });
|
|
666
|
-
|
|
667
|
-
const module = location?.query?.module || 'default';
|
|
668
|
-
const type = location?.query?.type;
|
|
669
|
-
const isLanguageSupport = location?.query?.isLanguageSupport || false;
|
|
670
|
-
const isBEESupport = (location?.query?.isBEESupport !== "false") || false;
|
|
671
|
-
|
|
672
|
-
if (getFormdata) {
|
|
673
|
-
const { versions, ...rest } = createResponse.templateId;
|
|
674
|
-
getFormdata({ value: versions, ...rest, validity: true });
|
|
675
|
-
} else {
|
|
676
|
-
const queryParams = type === 'embedded'
|
|
677
|
-
? {
|
|
678
|
-
type: 'embedded', module, isLanguageSupport, isBEESupport,
|
|
679
|
-
}
|
|
680
|
-
: { module, isLanguageSupport, isBEESupport };
|
|
681
|
-
|
|
682
|
-
const searchParams = new URLSearchParams();
|
|
683
|
-
Object.keys(queryParams).forEach((key) => {
|
|
684
|
-
if (queryParams[key] !== undefined && queryParams[key] !== null) {
|
|
685
|
-
searchParams.append(key, queryParams[key]);
|
|
686
|
-
}
|
|
687
|
-
});
|
|
688
|
-
|
|
689
|
-
history.push({
|
|
690
|
-
pathname: '/email',
|
|
691
|
-
search: searchParams.toString() ? `?${searchParams.toString()}` : '',
|
|
692
|
-
});
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
});
|
|
696
|
-
});
|
|
697
|
-
}
|
|
698
|
-
} else {
|
|
699
|
-
// Library mode: Use getFormdata flow
|
|
700
|
-
const tmpData = {
|
|
701
|
-
html_content: htmlContent || '',
|
|
702
|
-
is_drag_drop: false,
|
|
703
|
-
lang_id: get(currentOrgDetails, `basic_details.languages.${baseLanguage}.lang_id`, ''),
|
|
704
|
-
iso_code: baseLanguage,
|
|
705
|
-
language: get(currentOrgDetails, `basic_details.languages.${baseLanguage}.language`, baseLanguage),
|
|
706
|
-
};
|
|
707
|
-
|
|
708
|
-
const libraryPayload = {
|
|
709
|
-
base: tmpData,
|
|
710
|
-
secondary_templates: [{ template_data: tmpData }],
|
|
711
|
-
};
|
|
712
|
-
libraryPayload.base.subject = subject || '';
|
|
713
|
-
|
|
714
|
-
if (location?.query?.module === 'library' && isGetFormData && getFormdata) {
|
|
715
|
-
const response = {
|
|
716
|
-
action: "getFormData",
|
|
717
|
-
postAction: 'next',
|
|
718
|
-
id: get(Email, 'templateDetails._id', ''),
|
|
719
|
-
value: libraryPayload,
|
|
720
|
-
validity: true,
|
|
721
|
-
type: EMAIL,
|
|
722
|
-
};
|
|
723
|
-
getFormdata(response);
|
|
724
|
-
} else if (getFormdata) {
|
|
725
|
-
getFormdata({
|
|
726
|
-
value: libraryPayload,
|
|
727
|
-
validity: true,
|
|
728
|
-
type: EMAIL,
|
|
729
|
-
});
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
};
|
|
733
|
-
|
|
734
|
-
// If liquid enabled, validate first using extractTags API
|
|
735
|
-
if (isLiquidEnabled && getLiquidTags) {
|
|
736
|
-
const onError = ({ standardErrors, liquidErrors }) => {
|
|
737
|
-
if (showLiquidErrorInFooter) {
|
|
738
|
-
showLiquidErrorInFooter({
|
|
739
|
-
STANDARD_ERROR_MSG: standardErrors || [],
|
|
740
|
-
LIQUID_ERROR_MSG: liquidErrors || [],
|
|
741
|
-
});
|
|
742
|
-
}
|
|
743
|
-
// Don't reset ref here - liquid validation is async and resetting causes infinite loop
|
|
744
|
-
// The parent's isGetFormData will be reset by onValidationFail, and the next click will be detected
|
|
745
|
-
if (onValidationFail) {
|
|
746
|
-
onValidationFail();
|
|
747
|
-
}
|
|
748
|
-
};
|
|
749
|
-
|
|
750
|
-
const onSuccess = () => {
|
|
751
|
-
performSave();
|
|
752
|
-
};
|
|
753
|
-
|
|
754
|
-
validateLiquidTemplateContent(htmlContent || '', {
|
|
755
|
-
getLiquidTags: getLiquidTags
|
|
756
|
-
? (inputContent, callback) => getLiquidTags(inputContent, callback)
|
|
757
|
-
: (inputContent, callback) => globalActions?.getLiquidTags?.(inputContent, callback),
|
|
758
|
-
formatMessage: intl.formatMessage,
|
|
759
|
-
messages: formBuilderMessages,
|
|
760
|
-
onError,
|
|
761
|
-
onSuccess,
|
|
762
|
-
tagLookupMap: metaEntities?.tagLookupMap,
|
|
763
|
-
eventContextTags,
|
|
764
|
-
isLiquidFlow: true,
|
|
765
|
-
forwardedTags: forwardedTags || {},
|
|
766
|
-
});
|
|
767
|
-
} else {
|
|
768
|
-
performSave();
|
|
769
|
-
}
|
|
770
|
-
}, [
|
|
771
|
-
subject,
|
|
772
|
-
htmlContent,
|
|
773
|
-
tags,
|
|
774
|
-
injectedTags,
|
|
775
|
-
location,
|
|
776
|
-
getDefaultTags,
|
|
777
|
-
eventContextTags,
|
|
778
|
-
formatMessage,
|
|
779
|
-
subjectError,
|
|
780
|
-
isFullMode,
|
|
781
|
-
currentOrgDetails,
|
|
782
|
-
Email,
|
|
783
|
-
currentTemplateId,
|
|
784
|
-
templateDataProp,
|
|
785
|
-
templateName,
|
|
786
|
-
emailActions,
|
|
787
|
-
getFormdata,
|
|
788
|
-
isGetFormData,
|
|
789
|
-
isLiquidEnabled,
|
|
790
|
-
getLiquidTags,
|
|
791
|
-
showLiquidErrorInFooter,
|
|
792
|
-
metaEntities,
|
|
793
|
-
forwardedTags,
|
|
794
|
-
globalActions,
|
|
795
|
-
intl,
|
|
796
|
-
extractedTemplateName,
|
|
797
|
-
]);
|
|
798
|
-
|
|
799
|
-
// Trigger save when isGetFormData becomes true (Create/Done button clicked)
|
|
800
|
-
useEffect(() => {
|
|
801
|
-
const isGetFormDataChanged = isGetFormData && !prevIsGetFormDataRef.current;
|
|
802
|
-
const wasReset = !isGetFormData && prevIsGetFormDataRef.current;
|
|
803
|
-
|
|
804
|
-
if (isGetFormDataChanged) {
|
|
805
|
-
handleSave();
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
// Reset ref when parent resets isGetFormData (e.g., after validation failure)
|
|
809
|
-
if (wasReset) {
|
|
810
|
-
prevIsGetFormDataRef.current = false;
|
|
811
|
-
return;
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
prevIsGetFormDataRef.current = isGetFormData;
|
|
815
|
-
}, [isGetFormData, handleSave]);
|
|
816
|
-
|
|
817
|
-
// Handle tag context change
|
|
818
|
-
const handleOnTagsContextChange = useCallback((data) => {
|
|
819
|
-
const { type, module } = location?.query || {};
|
|
820
|
-
const isEmbedded = type === EMBEDDED;
|
|
821
|
-
const contextValue = data || (isEmbedded ? module : DEFAULT);
|
|
822
|
-
const query = {
|
|
823
|
-
layout: EMAIL,
|
|
824
|
-
type: TAG,
|
|
825
|
-
context: contextValue ? contextValue.toLowerCase() : contextValue,
|
|
826
|
-
embedded: isEmbedded ? type : FULL,
|
|
827
|
-
};
|
|
828
|
-
if (globalActions && globalActions.fetchSchemaForEntity) {
|
|
829
|
-
globalActions.fetchSchemaForEntity(query);
|
|
830
|
-
}
|
|
831
|
-
}, [location, globalActions]);
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
const spinTip = fetchingLiquidTags ? <FormattedMessage {...formBuilderMessages.liquidSpinText} /> : '';
|
|
835
|
-
|
|
836
|
-
// Handle template name change
|
|
837
|
-
// Call showTemplateName when templateName is available (for CreativesContainer header)
|
|
838
|
-
// This matches the behavior of Email component which calls showTemplateName in onFormDataChange
|
|
839
|
-
// In Edit mode, use extractedTemplateName from template data; in Create mode, use templateName prop
|
|
840
|
-
const { onFormDataChange: onFormDataChangeProp } = props;
|
|
841
|
-
|
|
842
|
-
// Create onFormDataChange callback that updates extractedTemplateName in Edit mode
|
|
843
|
-
// This matches the Email component's onFormDataChange which updates its state
|
|
844
|
-
const handleFormDataChange = useCallback((updatedFormData) => {
|
|
845
|
-
const newTemplateName = updatedFormData?.['template-name'] || '';
|
|
846
|
-
|
|
847
|
-
// In Edit mode, update extractedTemplateName state (similar to Email component updating its formData state)
|
|
848
|
-
if (isEditMode && newTemplateName !== extractedTemplateName) {
|
|
849
|
-
setExtractedTemplateName(newTemplateName);
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
// Call the parent's onFormDataChange if provided
|
|
853
|
-
if (onFormDataChangeProp) {
|
|
854
|
-
onFormDataChangeProp(updatedFormData);
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
// Call showTemplateName again with updated formData (same pattern as Email component)
|
|
858
|
-
if (showTemplateName && isFullMode) {
|
|
859
|
-
showTemplateName({ formData: updatedFormData, onFormDataChange: handleFormDataChange });
|
|
860
|
-
}
|
|
861
|
-
}, [isEditMode, extractedTemplateName, onFormDataChangeProp, showTemplateName, isFullMode]);
|
|
862
|
-
|
|
863
|
-
useEffect(() => {
|
|
864
|
-
if (showTemplateName && isFullMode) {
|
|
865
|
-
// In Edit mode, use extractedTemplateName; in Create mode, use templateName prop
|
|
866
|
-
const nameToUse = isEditMode ? extractedTemplateName : templateName;
|
|
867
|
-
const formData = {
|
|
868
|
-
'template-name': nameToUse || '',
|
|
869
|
-
};
|
|
870
|
-
// Pass handleFormDataChange callback so CreativesContainer can update template name
|
|
871
|
-
// This is the same pattern used in Email component
|
|
872
|
-
showTemplateName({ formData, onFormDataChange: handleFormDataChange });
|
|
873
|
-
}
|
|
874
|
-
}, [showTemplateName, isFullMode, templateName, extractedTemplateName, isEditMode, handleFormDataChange]);
|
|
875
|
-
|
|
876
|
-
return (
|
|
877
|
-
<CapSpin spinning={isLoading} tip={spinTip}>
|
|
878
|
-
<CapRow>
|
|
879
|
-
<CapColumn span={24}>
|
|
880
|
-
{/* Subject Field */}
|
|
881
|
-
<CapColumn span={24} style={{ marginBottom: CAP_SPACE_16 }}>
|
|
882
|
-
<CapTagListWithInput
|
|
883
|
-
inputId="template-subject"
|
|
884
|
-
inputValue={subject}
|
|
885
|
-
inputOnChange={handleSubjectChange}
|
|
886
|
-
inputPlaceholder={formatMessage(messages.enterEmailSubject)}
|
|
887
|
-
inputRequired
|
|
888
|
-
inputErrorMessage={subjectError}
|
|
889
|
-
headingText={formatMessage(messages.subject)}
|
|
890
|
-
headingType="h4"
|
|
891
|
-
headingStyle={{ marginRight: '85%' }}
|
|
892
|
-
onTagSelect={handleSubjectTagSelect}
|
|
893
|
-
onContextChange={handleOnTagsContextChange}
|
|
894
|
-
location={location}
|
|
895
|
-
tags={tags}
|
|
896
|
-
injectedTags={injectedTags || {}}
|
|
897
|
-
selectedOfferDetails={selectedOfferDetails}
|
|
898
|
-
eventContextTags={eventContextTags}
|
|
899
|
-
showHeading
|
|
900
|
-
showTagList
|
|
901
|
-
showInput
|
|
902
|
-
containerStyle={{
|
|
903
|
-
display: 'flex',
|
|
904
|
-
flexDirection: 'column',
|
|
905
|
-
}}
|
|
906
|
-
popoverPlacement="bottomRight"
|
|
907
|
-
/>
|
|
908
|
-
</CapColumn>
|
|
909
|
-
|
|
910
|
-
{/* Tag Validation Error Display */}
|
|
911
|
-
{/* {tagValidationError && !tagValidationError.valid && (
|
|
912
|
-
<CapColumn span={24} style={{ marginBottom: CAP_SPACE_16 }}>
|
|
913
|
-
<CapNotification
|
|
914
|
-
type="error"
|
|
915
|
-
message={formatMessage({
|
|
916
|
-
id: 'creatives.containersV2.Email.tagValidationError',
|
|
917
|
-
defaultMessage: 'Tag validation error',
|
|
918
|
-
})}
|
|
919
|
-
description={(
|
|
920
|
-
<CapRow>
|
|
921
|
-
{tagValidationError?.missingTags?.length > 0 && (
|
|
922
|
-
<CapColumn span={24}>
|
|
923
|
-
Missing tags:
|
|
924
|
-
{' '}
|
|
925
|
-
{tagValidationError.missingTags.join(', ')}
|
|
926
|
-
</CapColumn>
|
|
927
|
-
)}
|
|
928
|
-
{tagValidationError?.unsupportedTags?.length > 0 && (
|
|
929
|
-
<CapColumn span={24}>
|
|
930
|
-
Unsupported tags:
|
|
931
|
-
{' '}
|
|
932
|
-
{tagValidationError.unsupportedTags.join(', ')}
|
|
933
|
-
</CapColumn>
|
|
934
|
-
)}
|
|
935
|
-
{tagValidationError?.isBraceError && (
|
|
936
|
-
<CapColumn span={24}>
|
|
937
|
-
Unbalanced brackets detected
|
|
938
|
-
</CapColumn>
|
|
939
|
-
)}
|
|
940
|
-
</CapRow>
|
|
941
|
-
)}
|
|
942
|
-
/>
|
|
943
|
-
</CapColumn>
|
|
944
|
-
)} */}
|
|
945
|
-
|
|
946
|
-
<HTMLEditor
|
|
947
|
-
variant="email"
|
|
948
|
-
initialContent={loadedHtmlContent || ''}
|
|
949
|
-
onContentChange={handleContentChange}
|
|
950
|
-
onSave={handleSave}
|
|
951
|
-
readOnly={isReadOnly}
|
|
952
|
-
showFullscreenButton
|
|
953
|
-
autoSave={false}
|
|
954
|
-
tags={tags}
|
|
955
|
-
injectedTags={injectedTags}
|
|
956
|
-
location={location}
|
|
957
|
-
eventContextTags={eventContextTags}
|
|
958
|
-
selectedOfferDetails={selectedOfferDetails}
|
|
959
|
-
channel={EMAIL}
|
|
960
|
-
userLocale={intl.locale || 'en'}
|
|
961
|
-
moduleFilterEnabled={location?.query?.type !== EMBEDDED}
|
|
962
|
-
onTagContextChange={handleOnTagsContextChange}
|
|
963
|
-
isLiquidEnabled={isLiquidEnabled}
|
|
964
|
-
isFullMode={isFullMode}
|
|
965
|
-
/>
|
|
966
|
-
</CapColumn>
|
|
967
|
-
</CapRow>
|
|
968
|
-
</CapSpin>
|
|
969
|
-
);
|
|
970
|
-
};
|
|
971
|
-
|
|
972
|
-
EmailHTMLEditor.propTypes = {
|
|
973
|
-
intl: PropTypes.object.isRequired,
|
|
974
|
-
location: PropTypes.object,
|
|
975
|
-
params: PropTypes.object,
|
|
976
|
-
getDefaultTags: PropTypes.string,
|
|
977
|
-
supportedTags: PropTypes.array,
|
|
978
|
-
metaEntities: PropTypes.object,
|
|
979
|
-
injectedTags: PropTypes.object,
|
|
980
|
-
globalActions: PropTypes.object,
|
|
981
|
-
loadingTags: PropTypes.bool,
|
|
982
|
-
eventContextTags: PropTypes.array,
|
|
983
|
-
forwardedTags: PropTypes.object,
|
|
984
|
-
selectedOfferDetails: PropTypes.array,
|
|
985
|
-
currentOrgDetails: PropTypes.object,
|
|
986
|
-
isReadOnly: PropTypes.bool,
|
|
987
|
-
fetchingLiquidTags: PropTypes.bool,
|
|
988
|
-
createTemplateInProgress: PropTypes.bool,
|
|
989
|
-
fetchingCmsData: PropTypes.bool,
|
|
990
|
-
// Email Redux state
|
|
991
|
-
Email: PropTypes.object,
|
|
992
|
-
// Email actions
|
|
993
|
-
emailActions: PropTypes.object,
|
|
994
|
-
// Full mode props
|
|
995
|
-
isFullMode: PropTypes.bool,
|
|
996
|
-
templateName: PropTypes.string,
|
|
997
|
-
showTemplateName: PropTypes.func,
|
|
998
|
-
onFormDataChange: PropTypes.func,
|
|
999
|
-
isGetFormData: PropTypes.bool,
|
|
1000
|
-
getFormdata: PropTypes.func,
|
|
1001
|
-
// Library mode props
|
|
1002
|
-
templateData: PropTypes.object,
|
|
1003
|
-
// Uploaded content from zip file
|
|
1004
|
-
EmailLayout: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), // eslint-disable-line react/require-default-props
|
|
1005
|
-
// Liquid validation
|
|
1006
|
-
getLiquidTags: PropTypes.func,
|
|
1007
|
-
showLiquidErrorInFooter: PropTypes.func,
|
|
1008
|
-
// Preview/Test
|
|
1009
|
-
// Parent loading control
|
|
1010
|
-
setIsLoadingContent: PropTypes.func,
|
|
1011
|
-
};
|
|
1012
|
-
|
|
1013
|
-
EmailHTMLEditor.defaultProps = {
|
|
1014
|
-
location: {},
|
|
1015
|
-
params: {},
|
|
1016
|
-
getDefaultTags: null,
|
|
1017
|
-
supportedTags: [],
|
|
1018
|
-
showTemplateName: null,
|
|
1019
|
-
metaEntities: {},
|
|
1020
|
-
injectedTags: {},
|
|
1021
|
-
globalActions: {},
|
|
1022
|
-
loadingTags: false,
|
|
1023
|
-
eventContextTags: [],
|
|
1024
|
-
forwardedTags: {},
|
|
1025
|
-
selectedOfferDetails: [],
|
|
1026
|
-
currentOrgDetails: {},
|
|
1027
|
-
isReadOnly: false,
|
|
1028
|
-
fetchingLiquidTags: false,
|
|
1029
|
-
createTemplateInProgress: false,
|
|
1030
|
-
fetchingCmsData: false,
|
|
1031
|
-
Email: {},
|
|
1032
|
-
emailActions: {},
|
|
1033
|
-
isFullMode: false,
|
|
1034
|
-
templateName: '',
|
|
1035
|
-
onFormDataChange: null,
|
|
1036
|
-
isGetFormData: false,
|
|
1037
|
-
getFormdata: null,
|
|
1038
|
-
templateData: null,
|
|
1039
|
-
getLiquidTags: null,
|
|
1040
|
-
showLiquidErrorInFooter: null,
|
|
1041
|
-
setIsLoadingContent: null,
|
|
1042
|
-
};
|
|
1043
|
-
|
|
1044
|
-
const EmailHTMLEditorWithIntl = injectIntl(EmailHTMLEditor);
|
|
1045
|
-
|
|
1046
|
-
export default forwardRef((props, ref) => <EmailHTMLEditorWithIntl {...props} forwardedRef={ref} />);
|