@capillarytech/creatives-library 9.0.67-beta.test-cap-204791-beta-publish-yogesh.4 → 9.0.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/v2Components/ErrorInfoNote/index.js +3 -2
- package/v2Components/FormBuilder/Classic.js +10 -2
- package/v2Components/HtmlEditor/components/ValidationTabs/index.js +2 -1
- package/v2Components/HtmlEditor/utils/__tests__/renderIssueMessage.test.js +74 -0
- package/v2Components/HtmlEditor/utils/renderIssueMessage.js +56 -0
- package/v2Components/HtmlEditor/utils/validationConstants.js +5 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +5 -1
- package/v2Containers/CreativesContainer/index.js +1 -0
- package/v2Containers/Email/index.js +1 -0
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +7 -3
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +2 -0
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +3 -0
- package/v2Containers/EmailWrapper/index.js +2 -0
package/package.json
CHANGED
|
@@ -18,6 +18,7 @@ import { ANDROID, GENERIC, IOS } from '../../v2Containers/CreativesContainer/con
|
|
|
18
18
|
import { ERROR_TAB_KEYS } from '../HtmlEditor/utils/validationConstants';
|
|
19
19
|
import { SEVERITY } from '../HtmlEditor/components/ValidationPanel/constants';
|
|
20
20
|
import { LIQUID_DOC_URL } from './constants';
|
|
21
|
+
import renderIssueMessage from '../HtmlEditor/utils/renderIssueMessage';
|
|
21
22
|
|
|
22
23
|
const { CapLabelInline } = CapLabel;
|
|
23
24
|
|
|
@@ -120,7 +121,7 @@ const TabContent = ({ issues, onErrorClick, intl }) => {
|
|
|
120
121
|
>
|
|
121
122
|
<CapRow useLegacy className="error-info-note__item-content">
|
|
122
123
|
<CapLabelInline type="label2" className="error-info-note__item-message">
|
|
123
|
-
{displayMessage}
|
|
124
|
+
{renderIssueMessage(displayMessage)}
|
|
124
125
|
</CapLabelInline>
|
|
125
126
|
{line && (
|
|
126
127
|
<CapLabelInline type="label2" className="error-info-note__item-location">
|
|
@@ -426,7 +427,7 @@ const ErrorSection = ({
|
|
|
426
427
|
{(errors || []).map((error) => (
|
|
427
428
|
<CapRow useLegacy key={`${error}`} className="error-list-legacy__item">
|
|
428
429
|
<CapLabel type="label2" className="cap-list-v2-error-item">
|
|
429
|
-
<CapLabel type="label2">{error}</CapLabel>
|
|
430
|
+
<CapLabel type="label2">{renderIssueMessage(error)}</CapLabel>
|
|
430
431
|
</CapLabel>
|
|
431
432
|
</CapRow>
|
|
432
433
|
))}
|
|
@@ -592,6 +592,12 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
|
|
|
592
592
|
}
|
|
593
593
|
}
|
|
594
594
|
|
|
595
|
+
componentDidUpdate(prevProps) {
|
|
596
|
+
if (!_.isEqual(prevProps.isTransactional, this.props.isTransactional)) {
|
|
597
|
+
this.validateForm(this.props.tags, this.props.injectedTags);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
595
601
|
onEdit() {
|
|
596
602
|
|
|
597
603
|
}
|
|
@@ -1581,7 +1587,9 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
|
|
|
1581
1587
|
const contentForValidation = isEmail ? convert(content, GLOBAL_CONVERT_OPTIONS) : content;
|
|
1582
1588
|
const isOutboundModule = (currentModule || '').toUpperCase() === OUTBOUND;
|
|
1583
1589
|
|
|
1584
|
-
const
|
|
1590
|
+
const isTransactional = this.props.isTransactional;
|
|
1591
|
+
|
|
1592
|
+
const initialMissingTags = (tags && tags.length && !isFullMode && isEmail && isOutboundModule && !isEmailUnsubscribeTagOptional() && !isTransactional && !hasUnsubscribeTag(content))
|
|
1585
1593
|
? ['unsubscribe']
|
|
1586
1594
|
: [];
|
|
1587
1595
|
|
|
@@ -1598,7 +1606,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
|
|
|
1598
1606
|
|
|
1599
1607
|
// When unsubscribe tag is optional (isEmailUnsubscribeTagOptional): do not enforce unsubscribe (defensive splice); set isContentEmpty only when content is empty. Do not override response.valid so brace/format errors are preserved.
|
|
1600
1608
|
const validString = /\S/.test(contentForValidation);
|
|
1601
|
-
if (isEmailUnsubscribeTagOptional() && isEmail && isOutboundModule) {
|
|
1609
|
+
if ((isEmailUnsubscribeTagOptional() || isTransactional) && isEmail && isOutboundModule) {
|
|
1602
1610
|
const missingTagIndex = response.missingTags.indexOf('unsubscribe');
|
|
1603
1611
|
if (missingTagIndex !== -1) {
|
|
1604
1612
|
response.missingTags.splice(missingTagIndex, 1);
|
|
@@ -18,6 +18,7 @@ import CapTooltip from '@capillarytech/cap-ui-library/CapTooltip';
|
|
|
18
18
|
// Messages
|
|
19
19
|
import messages from './messages';
|
|
20
20
|
import { BLOCKING_ERROR_RULE_IDS, VALIDATION_SEVERITY } from '../../constants';
|
|
21
|
+
import renderIssueMessage from '../../utils/renderIssueMessage';
|
|
21
22
|
|
|
22
23
|
// Styles
|
|
23
24
|
import './_validationTabs.scss';
|
|
@@ -109,7 +110,7 @@ const ValidationTabContent = ({
|
|
|
109
110
|
>
|
|
110
111
|
<div className="validation-tabs__item-content">
|
|
111
112
|
<span className="validation-tabs__item-message">
|
|
112
|
-
{message}
|
|
113
|
+
{renderIssueMessage(message)}
|
|
113
114
|
</span>
|
|
114
115
|
{line && (
|
|
115
116
|
<span className="validation-tabs__item-location">
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* renderIssueMessage Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for rendering AI-generated liquid validation messages, including tolerance for
|
|
5
|
+
* non-guaranteed LLM formatting quirks (lead-in text before the first label, markdown-wrapped
|
|
6
|
+
* labels).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import React from 'react';
|
|
10
|
+
import { render } from '@testing-library/react';
|
|
11
|
+
import '@testing-library/jest-dom';
|
|
12
|
+
import renderIssueMessage from '../renderIssueMessage';
|
|
13
|
+
|
|
14
|
+
const renderMessage = (message) => render(<div>{renderIssueMessage(message)}</div>);
|
|
15
|
+
|
|
16
|
+
describe('renderIssueMessage', () => {
|
|
17
|
+
it('returns non-string input unchanged', () => {
|
|
18
|
+
const node = <span>already a node</span>;
|
|
19
|
+
expect(renderIssueMessage(node)).toBe(node);
|
|
20
|
+
expect(renderIssueMessage(null)).toBeNull();
|
|
21
|
+
expect(renderIssueMessage(undefined)).toBeUndefined();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('returns a plain message unchanged when no known labels are present', () => {
|
|
25
|
+
expect(renderIssueMessage('Something went wrong')).toBe('Something went wrong');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('renders all three labels in order, bolding only "Issue text:" and stripping it from the body', () => {
|
|
29
|
+
const message = 'Issue text: bad tag Explanation: the tag is malformed Solution: fix the tag';
|
|
30
|
+
const { container } = renderMessage(message);
|
|
31
|
+
|
|
32
|
+
const strong = container.querySelector('strong');
|
|
33
|
+
expect(strong).toHaveTextContent('Issue text:');
|
|
34
|
+
expect(container).toHaveTextContent('Issue text: bad tag');
|
|
35
|
+
expect(container).toHaveTextContent('Explanation: the tag is malformed');
|
|
36
|
+
expect(container).toHaveTextContent('Solution: fix the tag');
|
|
37
|
+
// Only the "Issue text:" label should be wrapped in <strong>.
|
|
38
|
+
expect(container.querySelectorAll('strong')).toHaveLength(1);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('renders correctly when only some labels are present', () => {
|
|
42
|
+
const message = 'Issue text: bad tag Solution: fix the tag';
|
|
43
|
+
const { container } = renderMessage(message);
|
|
44
|
+
|
|
45
|
+
expect(container).toHaveTextContent('Issue text: bad tag');
|
|
46
|
+
expect(container).toHaveTextContent('Solution: fix the tag');
|
|
47
|
+
expect(container).not.toHaveTextContent('Explanation:');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('preserves lead-in text before the first recognized label instead of dropping it', () => {
|
|
51
|
+
const message = "Here's what I found. Issue text: bad tag Explanation: the tag is malformed";
|
|
52
|
+
const { container } = renderMessage(message);
|
|
53
|
+
|
|
54
|
+
expect(container).toHaveTextContent("Here's what I found.");
|
|
55
|
+
expect(container).toHaveTextContent('Issue text: bad tag');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('strips markdown bold wrapping around a label instead of leaking asterisks', () => {
|
|
59
|
+
const message = '**Issue text:** bad tag **Explanation:** the tag is malformed';
|
|
60
|
+
const { container } = renderMessage(message);
|
|
61
|
+
|
|
62
|
+
expect(container.textContent).not.toContain('*');
|
|
63
|
+
expect(container.querySelector('strong')).toHaveTextContent('Issue text:');
|
|
64
|
+
expect(container).toHaveTextContent('Explanation: the tag is malformed');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('strips markdown underscore-bold wrapping around a label', () => {
|
|
68
|
+
const message = '__Issue text:__ bad tag';
|
|
69
|
+
const { container } = renderMessage(message);
|
|
70
|
+
|
|
71
|
+
expect(container.textContent).not.toContain('_');
|
|
72
|
+
expect(container.querySelector('strong')).toHaveTextContent('Issue text:');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React, { Fragment } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
AI_ISSUE_TEXT_LABEL,
|
|
4
|
+
AI_ISSUE_MESSAGE_LABELS,
|
|
5
|
+
AI_ISSUE_MESSAGE_LEADING_SEGMENT_KEY,
|
|
6
|
+
} from './validationConstants';
|
|
7
|
+
|
|
8
|
+
// Renders askAiraForLiquid's LLM-generated messages, splitting on known labels rather than "\n"
|
|
9
|
+
// since the API doesn't guarantee newlines; tolerates lead-in text and markdown-wrapped labels.
|
|
10
|
+
|
|
11
|
+
const stripLabelMarkdown = (text) => AI_ISSUE_MESSAGE_LABELS.reduce(
|
|
12
|
+
(acc, label) => acc.split(`**${label}**`).join(label).split(`__${label}__`).join(label),
|
|
13
|
+
text
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const renderIssueMessage = (message) => {
|
|
17
|
+
if (typeof message !== 'string') {
|
|
18
|
+
return message;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const normalizedMessage = stripLabelMarkdown(message);
|
|
22
|
+
|
|
23
|
+
const labelPositions = AI_ISSUE_MESSAGE_LABELS
|
|
24
|
+
.map((label) => ({ label, index: normalizedMessage.indexOf(label) }))
|
|
25
|
+
.filter(({ index }) => index !== -1)
|
|
26
|
+
.sort((a, b) => a.index - b.index);
|
|
27
|
+
|
|
28
|
+
if (labelPositions.length === 0) {
|
|
29
|
+
return normalizedMessage;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const segments = labelPositions.map(({ label, index }, i) => {
|
|
33
|
+
const end = i + 1 < labelPositions.length ? labelPositions[i + 1].index : normalizedMessage.length;
|
|
34
|
+
return { key: label, label, text: normalizedMessage.slice(index, end).trim() };
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const leadingText = normalizedMessage.slice(0, labelPositions[0].index).trim();
|
|
38
|
+
if (leadingText) {
|
|
39
|
+
segments.unshift({ key: AI_ISSUE_MESSAGE_LEADING_SEGMENT_KEY, label: null, text: leadingText });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return segments.map(({ key, label, text }, index) => (
|
|
43
|
+
<Fragment key={key}>
|
|
44
|
+
{index > 0 && <br />}
|
|
45
|
+
{index > 0 && ' - '}
|
|
46
|
+
{label === AI_ISSUE_TEXT_LABEL ? (
|
|
47
|
+
<>
|
|
48
|
+
<strong>{label}</strong>
|
|
49
|
+
{text.slice(label.length)}
|
|
50
|
+
</>
|
|
51
|
+
) : text}
|
|
52
|
+
</Fragment>
|
|
53
|
+
));
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export default renderIssueMessage;
|
|
@@ -36,3 +36,8 @@ export const ERROR_TAB_KEYS = {
|
|
|
36
36
|
ERRORS: 'errors',
|
|
37
37
|
WARNINGS: 'warnings',
|
|
38
38
|
};
|
|
39
|
+
|
|
40
|
+
// Labels used to segment AI-generated liquid validation messages (see renderIssueMessage.js)
|
|
41
|
+
export const AI_ISSUE_TEXT_LABEL = 'Issue text:';
|
|
42
|
+
export const AI_ISSUE_MESSAGE_LABELS = [AI_ISSUE_TEXT_LABEL, 'Explanation:', 'Solution:'];
|
|
43
|
+
export const AI_ISSUE_MESSAGE_LEADING_SEGMENT_KEY = 'leading-text';
|
|
@@ -143,6 +143,7 @@ export function SlideBoxContent(props) {
|
|
|
143
143
|
supportedTags = [],
|
|
144
144
|
selectedOfferDetails,
|
|
145
145
|
channelsToDisable,
|
|
146
|
+
isTransactional,
|
|
146
147
|
weChatTemplateType,
|
|
147
148
|
onWechatTemplateChange,
|
|
148
149
|
selectedWeChatAccount,
|
|
@@ -734,6 +735,7 @@ export function SlideBoxContent(props) {
|
|
|
734
735
|
onHtmlEditorValidationStateChange={onHtmlEditorValidationStateChange}
|
|
735
736
|
restrictPersonalization={restrictPersonalization}
|
|
736
737
|
isAnonymousType={isAnonymousType}
|
|
738
|
+
isTransactional={isTransactional}
|
|
737
739
|
/>
|
|
738
740
|
)}
|
|
739
741
|
{(isEditEmailWithId || isEmailEditWithContent) && (
|
|
@@ -783,7 +785,8 @@ export function SlideBoxContent(props) {
|
|
|
783
785
|
handleCloseTestAndPreview={handleCloseTestAndPreview}
|
|
784
786
|
isTestAndPreviewMode={isTestAndPreviewMode}
|
|
785
787
|
onHtmlEditorValidationStateChange={onHtmlEditorValidationStateChange}
|
|
786
|
-
|
|
788
|
+
isTransactional={isTransactional}
|
|
789
|
+
/>
|
|
787
790
|
);
|
|
788
791
|
}
|
|
789
792
|
// HTML template: Use EmailWrapper component (which uses EmailWithoutSaga)
|
|
@@ -823,6 +826,7 @@ export function SlideBoxContent(props) {
|
|
|
823
826
|
handleCloseTestAndPreview={handleCloseTestAndPreview}
|
|
824
827
|
isTestAndPreviewMode={isTestAndPreviewMode}
|
|
825
828
|
onHtmlEditorValidationStateChange={onHtmlEditorValidationStateChange}
|
|
829
|
+
isTransactional={isTransactional}
|
|
826
830
|
location={{
|
|
827
831
|
pathname: `/email/edit/${templateData._id || ''}`,
|
|
828
832
|
query: {
|
|
@@ -2398,6 +2398,7 @@ export class Creatives extends React.Component {
|
|
|
2398
2398
|
forwardedTags={forwardedTags}
|
|
2399
2399
|
selectedOfferDetails={selectedOfferDetails}
|
|
2400
2400
|
channelsToDisable={channelsToDisable}
|
|
2401
|
+
isTransactional={this.props.isTransactional}
|
|
2401
2402
|
restrictPersonalization={restrictPersonalization}
|
|
2402
2403
|
isAnonymousType={isAnonymousType}
|
|
2403
2404
|
customerType={customerType}
|
|
@@ -3278,6 +3278,7 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
3278
3278
|
exportHtmlLocked={this.state.exportHtmlContentLocked}
|
|
3279
3279
|
exportHtmlTooltip={getExportHtmlDisabledTooltip(this.state.isEdit, this.state.exportHtmlContentLocked, this.props.intl.formatMessage)}
|
|
3280
3280
|
isTestAndPreviewMode={this.state.isTestAndPreviewMode} // Add flag to prevent validation
|
|
3281
|
+
isTransactional={this.props.isTransactional}
|
|
3281
3282
|
/> : ''}
|
|
3282
3283
|
</CapColumn>
|
|
3283
3284
|
</CapRow>
|
|
@@ -93,10 +93,13 @@ const EmailHTMLEditor = (props) => {
|
|
|
93
93
|
forwardedRef,
|
|
94
94
|
// Module type for unsubscribe tag validation
|
|
95
95
|
moduleType,
|
|
96
|
+
isTransactional,
|
|
96
97
|
// Validation state callback
|
|
97
98
|
onHtmlEditorValidationStateChange,
|
|
98
99
|
} = props;
|
|
99
100
|
|
|
101
|
+
const isUnsubscribeOptional = isEmailUnsubscribeTagOptional() || isTransactional;
|
|
102
|
+
|
|
100
103
|
const { formatMessage } = intl;
|
|
101
104
|
|
|
102
105
|
// State for content and subject
|
|
@@ -127,7 +130,7 @@ const EmailHTMLEditor = (props) => {
|
|
|
127
130
|
// Merge tag validation errors (missing) into apiValidationErrors so they show in ValidationErrorDisplay
|
|
128
131
|
const mergedApiValidationErrors = useMemo(() => {
|
|
129
132
|
const tagMessages = [];
|
|
130
|
-
if (tagValidationError?.missingTags?.length && !
|
|
133
|
+
if (tagValidationError?.missingTags?.length && !isUnsubscribeOptional) {
|
|
131
134
|
tagMessages.push(`Missing tags are: ${tagValidationError.missingTags.join(', ')}`);
|
|
132
135
|
}
|
|
133
136
|
if (tagMessages.length === 0) {
|
|
@@ -137,7 +140,7 @@ const EmailHTMLEditor = (props) => {
|
|
|
137
140
|
liquidErrors: apiValidationErrors?.liquidErrors || [],
|
|
138
141
|
standardErrors: [...(apiValidationErrors?.standardErrors || []), ...tagMessages],
|
|
139
142
|
};
|
|
140
|
-
}, [apiValidationErrors, tagValidationError]);
|
|
143
|
+
}, [apiValidationErrors, tagValidationError, isUnsubscribeOptional]);
|
|
141
144
|
|
|
142
145
|
// Refs for tracking initialization and previous values
|
|
143
146
|
const contentInitializedRef = useRef(false);
|
|
@@ -738,7 +741,7 @@ const EmailHTMLEditor = (props) => {
|
|
|
738
741
|
// When EMAIL_UNSUBSCRIBE_TAG_MANDATORY is false: validate and require unsubscribe tag.
|
|
739
742
|
// Run for both library and full mode so liquid-enabled orgs also get the error (notification + ValidationErrorDisplay).
|
|
740
743
|
const isModuleTypeOutbound = (moduleType || '').toUpperCase() === OUTBOUND;
|
|
741
|
-
if (!
|
|
744
|
+
if (!isUnsubscribeOptional && isModuleTypeOutbound) {
|
|
742
745
|
const unsubscribeRegex = /{{unsubscribe(\(#[a-zA-Z\d]{6}\))?}}/g; // eslint-disable-line no-useless-escape
|
|
743
746
|
const hasUnsubscribeTag = unsubscribeRegex.test(htmlContent);
|
|
744
747
|
|
|
@@ -1009,6 +1012,7 @@ const EmailHTMLEditor = (props) => {
|
|
|
1009
1012
|
globalActions,
|
|
1010
1013
|
intl,
|
|
1011
1014
|
extractedTemplateName,
|
|
1015
|
+
isUnsubscribeOptional,
|
|
1012
1016
|
]);
|
|
1013
1017
|
|
|
1014
1018
|
// Keep handleSave ref up to date - MUST be before isGetFormData effect
|
|
@@ -193,6 +193,7 @@ const EmailWrapperView = ({
|
|
|
193
193
|
showTemplateName,
|
|
194
194
|
onHtmlEditorValidationStateChange,
|
|
195
195
|
moduleType,
|
|
196
|
+
isTransactional,
|
|
196
197
|
}) => {
|
|
197
198
|
const htmlEditorRef = useRef(null);
|
|
198
199
|
const supportCKEditor = hasSupportCKEditor();
|
|
@@ -275,6 +276,7 @@ const EmailWrapperView = ({
|
|
|
275
276
|
onFormDataChange: handleFormDataChange,
|
|
276
277
|
// Module type for unsubscribe tag validation
|
|
277
278
|
moduleType,
|
|
279
|
+
isTransactional,
|
|
278
280
|
// Loading states
|
|
279
281
|
fetchingLiquidTags: fetchingLiquidTags || false,
|
|
280
282
|
createTemplateInProgress: createTemplateInProgress || false,
|
|
@@ -51,6 +51,7 @@ const useEmailWrapper = ({
|
|
|
51
51
|
editor,
|
|
52
52
|
moduleType,
|
|
53
53
|
eventContextTags,
|
|
54
|
+
isTransactional,
|
|
54
55
|
waitEventContextTags,
|
|
55
56
|
isLoyaltyModule,
|
|
56
57
|
// Props for CmsTemplates component
|
|
@@ -746,6 +747,7 @@ const useEmailWrapper = ({
|
|
|
746
747
|
eventContextTags,
|
|
747
748
|
waitEventContextTags,
|
|
748
749
|
isLoyaltyModule,
|
|
750
|
+
isTransactional,
|
|
749
751
|
showTestAndPreviewSlidebox,
|
|
750
752
|
handleTestAndPreview,
|
|
751
753
|
handleCloseTestAndPreview,
|
|
@@ -776,6 +778,7 @@ const useEmailWrapper = ({
|
|
|
776
778
|
eventContextTags,
|
|
777
779
|
waitEventContextTags,
|
|
778
780
|
isLoyaltyModule,
|
|
781
|
+
isTransactional,
|
|
779
782
|
showTestAndPreviewSlidebox,
|
|
780
783
|
handleTestAndPreview,
|
|
781
784
|
handleCloseTestAndPreview,
|
|
@@ -87,6 +87,7 @@ const EmailWrapper = (props) => {
|
|
|
87
87
|
fetchingCmsData,
|
|
88
88
|
onHtmlEditorValidationStateChange,
|
|
89
89
|
isEditEmail = true,
|
|
90
|
+
isTransactional,
|
|
90
91
|
} = props;
|
|
91
92
|
|
|
92
93
|
// Pass destructured props to the custom hook
|
|
@@ -207,6 +208,7 @@ const EmailWrapper = (props) => {
|
|
|
207
208
|
fetchingCmsData={fetchingCmsData}
|
|
208
209
|
onHtmlEditorValidationStateChange={onHtmlEditorValidationStateChange}
|
|
209
210
|
moduleType={moduleType}
|
|
211
|
+
isTransactional={isTransactional}
|
|
210
212
|
/>
|
|
211
213
|
|
|
212
214
|
{/* HTMLEditor Testing Component - Console Controlled */}
|