@capillarytech/creatives-library 8.0.284 → 8.0.285-alpha.1
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/constants/unified.js +0 -1
- package/initialState.js +0 -2
- package/package.json +1 -1
- package/utils/common.js +5 -8
- package/utils/commonUtils.js +2 -83
- package/utils/tagValidations.js +84 -222
- package/utils/tests/commonUtil.test.js +147 -118
- package/utils/tests/tagValidations.test.js +280 -358
- package/v2Components/ErrorInfoNote/index.js +2 -5
- package/v2Components/FormBuilder/index.js +64 -158
- package/v2Components/FormBuilder/messages.js +0 -8
- package/v2Components/HtmlEditor/HTMLEditor.js +0 -5
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +0 -1
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +0 -15
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +1 -2
- package/v2Containers/Cap/mockData.js +0 -14
- package/v2Containers/Cap/reducer.js +3 -55
- package/v2Containers/Cap/tests/reducer.test.js +0 -102
- package/v2Containers/CreativesContainer/index.js +0 -1
- package/v2Containers/Email/index.js +1 -5
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +10 -62
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +12 -115
- package/v2Containers/FTP/index.js +2 -51
- package/v2Containers/FTP/messages.js +0 -4
- package/v2Containers/InApp/index.js +1 -96
- package/v2Containers/InApp/tests/index.test.js +17 -6
- package/v2Containers/InappAdvance/index.js +2 -103
- package/v2Containers/Line/Container/Text/index.js +0 -1
- package/v2Containers/MobilePushNew/index.js +2 -33
- package/v2Containers/Rcs/index.js +12 -37
- package/v2Containers/SmsTrai/Edit/index.js +6 -47
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +6 -6
- package/v2Containers/Viber/index.js +0 -1
- package/v2Containers/WebPush/Create/hooks/useTagManagement.js +1 -3
- package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +0 -7
- package/v2Containers/WebPush/Create/index.js +2 -2
- package/v2Containers/WebPush/Create/utils/validation.js +18 -9
- package/v2Containers/WebPush/Create/utils/validation.test.js +0 -24
- package/v2Containers/Whatsapp/index.js +9 -17
- package/v2Containers/Zalo/index.js +3 -11
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Created by vivek on 22/5/17.
|
|
3
3
|
*/
|
|
4
|
-
import { fromJS
|
|
4
|
+
import { fromJS } from 'immutable';
|
|
5
5
|
import _ from 'lodash';
|
|
6
6
|
import * as types from './constants';
|
|
7
7
|
import initialState from '../../initialState';
|
|
8
8
|
import { FAILURE } from '../App/constants';
|
|
9
|
-
import { TAG } from '../Whatsapp/constants';
|
|
10
|
-
import { getTagMapValue, getForwardedMapValues, getLoyaltyTagsMapValue } from '../../utils/tagValidations';
|
|
11
9
|
|
|
12
10
|
function capReducer(state = fromJS(initialState.cap), action) {
|
|
13
11
|
switch (action.type) {
|
|
@@ -98,39 +96,6 @@ function capReducer(state = fromJS(initialState.cap), action) {
|
|
|
98
96
|
return state
|
|
99
97
|
.set('fetchingLiquidTags', false);
|
|
100
98
|
case types.GET_SCHEMA_FOR_ENTITY_SUCCESS: {
|
|
101
|
-
//Process standard tags
|
|
102
|
-
const standardTagMapInitial = _.keyBy(
|
|
103
|
-
action?.data?.metaEntities?.standard,
|
|
104
|
-
item => item?.definition?.value
|
|
105
|
-
);
|
|
106
|
-
// Mapping only the `definition` object instead of the entire item, to reduce space used
|
|
107
|
-
const standardTagMap = _.mapValues(standardTagMapInitial, item => ({
|
|
108
|
-
definition: item?.definition ?? {},
|
|
109
|
-
}));
|
|
110
|
-
|
|
111
|
-
// Process custom tags
|
|
112
|
-
const customSubtags = getTagMapValue(action?.data?.metaEntities?.custom)
|
|
113
|
-
// Process extended tags
|
|
114
|
-
const extendedSubtags = getTagMapValue(action?.data?.metaEntities?.extended);
|
|
115
|
-
|
|
116
|
-
const loyaltySubTagsData = getLoyaltyTagsMapValue(action?.data?.metaEntities?.loyaltyTags);
|
|
117
|
-
|
|
118
|
-
const getExistingTagLookupMap = (state) => {
|
|
119
|
-
if (!state || !state.get) return {};
|
|
120
|
-
const tagLookupMap = state.getIn(['metaEntities', 'tagLookupMap']);
|
|
121
|
-
return state.get('metaEntities') && ImmutableMap.isMap(tagLookupMap)
|
|
122
|
-
? tagLookupMap.toJS()
|
|
123
|
-
: {};
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
// Combine all maps
|
|
127
|
-
const combinedTagMap = {
|
|
128
|
-
...standardTagMap,
|
|
129
|
-
...customSubtags,
|
|
130
|
-
...extendedSubtags,
|
|
131
|
-
...loyaltySubTagsData,
|
|
132
|
-
...getExistingTagLookupMap(state),
|
|
133
|
-
};
|
|
134
99
|
const stateMeta = state.get("metaEntities");
|
|
135
100
|
return state
|
|
136
101
|
.set('fetchingSchema', false)
|
|
@@ -138,7 +103,6 @@ function capReducer(state = fromJS(initialState.cap), action) {
|
|
|
138
103
|
.set('metaEntities', {
|
|
139
104
|
layouts: action.data && action.entityType === 'LAYOUT' ? action.data.metaEntities : stateMeta?.layouts,
|
|
140
105
|
tags: action.data && action.entityType === 'TAG' ? action.data.metaEntities : stateMeta?.tags,
|
|
141
|
-
tagLookupMap: action?.data && action?.entityType === TAG ? combinedTagMap : stateMeta?.tagLookupMap,
|
|
142
106
|
})
|
|
143
107
|
.set('fetchingSchemaError', false);
|
|
144
108
|
}
|
|
@@ -146,7 +110,6 @@ function capReducer(state = fromJS(initialState.cap), action) {
|
|
|
146
110
|
return state.set('metaEntities', {
|
|
147
111
|
layouts: [],
|
|
148
112
|
tags: [],
|
|
149
|
-
tagLookupMap: {},
|
|
150
113
|
});
|
|
151
114
|
// eslint-disable-next-line no-case-declarations
|
|
152
115
|
case types.HIDE_TAGS:
|
|
@@ -154,23 +117,8 @@ function capReducer(state = fromJS(initialState.cap), action) {
|
|
|
154
117
|
metaEntities.tags.standard = _.filter(state.get('metaEntities').tags.standard, (tag) => action.tagList.indexOf(tag.definition.value) === -1);
|
|
155
118
|
metaEntities.tags.custom = _.filter(state.get('metaEntities').tags.custom, (tag) => action.tagList.indexOf(tag.name) === -1);
|
|
156
119
|
return state.setIn(['metaEntities'], metaEntities);
|
|
157
|
-
case types.SET_INJECTED_TAGS:
|
|
158
|
-
|
|
159
|
-
// Deep clone the tagLookupMap to avoid direct mutations
|
|
160
|
-
let updatedMetaEntitiesTagLookUp = _.cloneDeep(state.getIn(['metaEntities', 'tagLookupMap']));
|
|
161
|
-
const formattedInjectedTags = getForwardedMapValues(action?.injectedTags);
|
|
162
|
-
// Merge the injectedTags with the existing tagLookupMap
|
|
163
|
-
updatedMetaEntitiesTagLookUp = {
|
|
164
|
-
...formattedInjectedTags || {},
|
|
165
|
-
...updatedMetaEntitiesTagLookUp || {},
|
|
166
|
-
};
|
|
167
|
-
return state.set("injectedTags", action.injectedTags).setIn(
|
|
168
|
-
["metaEntities"],
|
|
169
|
-
fromJS({
|
|
170
|
-
...state.get("metaEntities"),
|
|
171
|
-
tagLookupMap: updatedMetaEntitiesTagLookUp
|
|
172
|
-
})
|
|
173
|
-
);
|
|
120
|
+
case types.SET_INJECTED_TAGS:
|
|
121
|
+
return state.set("injectedTags", action.injectedTags);
|
|
174
122
|
case types.GET_TOPBAR_MENU_DATA_REQUEST:
|
|
175
123
|
return state.set('topbarMenuData', fromJS({ status: 'request' }));
|
|
176
124
|
case types.GET_TOPBAR_MENU_DATA_SUCCESS:
|
|
@@ -21,7 +21,6 @@ import {
|
|
|
21
21
|
expectedStateGetSchemaForEntitySuccessTAG,
|
|
22
22
|
expectedStateGetSchemaForEntitySuccess,
|
|
23
23
|
} from '../mockData';
|
|
24
|
-
import { TAG } from '../../Whatsapp/constants';
|
|
25
24
|
import { loadItem } from '../../../services/localStorageApi';
|
|
26
25
|
|
|
27
26
|
|
|
@@ -118,104 +117,3 @@ describe('should handle GET_SUPPORT_VIDEOS_CONFIG', () => {
|
|
|
118
117
|
expect(reducer(mockedInitialState, action).toJS())?.fetchingSchema?.toEqual(true);
|
|
119
118
|
});
|
|
120
119
|
});
|
|
121
|
-
|
|
122
|
-
describe('GET_SCHEMA_FOR_ENTITY_SUCCESS handler', () => {
|
|
123
|
-
it.concurrent('should handle existing tagLookupMap correctly when metaEntities and tagLookupMap exist', () => {
|
|
124
|
-
const initialStateTest = fromJS({
|
|
125
|
-
token: loadItem('token') || '',
|
|
126
|
-
orgID: loadItem('orgID') || '',
|
|
127
|
-
messages: [],
|
|
128
|
-
metaEntities: {
|
|
129
|
-
tags: [{ id: 1, name: 'tag1' }],
|
|
130
|
-
layouts: ['layout1', 'layout2'],
|
|
131
|
-
tagLookupMap: {
|
|
132
|
-
existingTag: { definition: { value: 'existing' } },
|
|
133
|
-
anotherTag: { definition: { value: 'another' } },
|
|
134
|
-
},
|
|
135
|
-
standard: [],
|
|
136
|
-
},
|
|
137
|
-
liquidTags: [],
|
|
138
|
-
fetchingLiquidTags: false,
|
|
139
|
-
fetchingSchema: false,
|
|
140
|
-
fetchingSchemaError: '',
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
let action = {
|
|
144
|
-
type: GET_SCHEMA_FOR_ENTITY_SUCCESS,
|
|
145
|
-
entityType: TAG,
|
|
146
|
-
data: {
|
|
147
|
-
metaEntities: {
|
|
148
|
-
standard: [],
|
|
149
|
-
custom: [],
|
|
150
|
-
extended: [],
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
let newState = reducer(initialStateTest, action);
|
|
156
|
-
let metaEntities = newState.get('metaEntities');
|
|
157
|
-
|
|
158
|
-
expect(metaEntities).toEqual(expect.objectContaining({
|
|
159
|
-
tagLookupMap: expect.objectContaining({
|
|
160
|
-
existingTag: expect.objectContaining({
|
|
161
|
-
definition: expect.objectContaining({
|
|
162
|
-
value: 'existing',
|
|
163
|
-
}),
|
|
164
|
-
}),
|
|
165
|
-
}),
|
|
166
|
-
}));
|
|
167
|
-
|
|
168
|
-
action = {
|
|
169
|
-
type: GET_SCHEMA_FOR_ENTITY_SUCCESS,
|
|
170
|
-
entityType: 'LAYOUT',
|
|
171
|
-
data: {
|
|
172
|
-
metaEntities: {
|
|
173
|
-
layouts: ['layout1', 'layout2'],
|
|
174
|
-
standard: [],
|
|
175
|
-
},
|
|
176
|
-
},
|
|
177
|
-
};
|
|
178
|
-
newState = reducer(initialStateTest, action);
|
|
179
|
-
metaEntities = newState.get('metaEntities');
|
|
180
|
-
expect(metaEntities).toEqual(expect.objectContaining({
|
|
181
|
-
layouts: expect.objectContaining({
|
|
182
|
-
layouts: expect.arrayContaining(['layout1', 'layout2']),
|
|
183
|
-
}),
|
|
184
|
-
}));
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it.concurrent('should handle non-existent tagLookupMap by returning empty object', () => {
|
|
188
|
-
const initialStateTest = fromJS({
|
|
189
|
-
token: loadItem('token') || '',
|
|
190
|
-
orgID: loadItem('orgID') || '',
|
|
191
|
-
messages: [],
|
|
192
|
-
metaEntities: {
|
|
193
|
-
tagLookupMap: {},
|
|
194
|
-
},
|
|
195
|
-
liquidTags: [],
|
|
196
|
-
fetchingLiquidTags: false,
|
|
197
|
-
fetchingSchema: false,
|
|
198
|
-
fetchingSchemaError: '',
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
const action = {
|
|
202
|
-
type: GET_SCHEMA_FOR_ENTITY_SUCCESS,
|
|
203
|
-
entityType: TAG,
|
|
204
|
-
data: {
|
|
205
|
-
metaEntities: {
|
|
206
|
-
standard: [],
|
|
207
|
-
custom: [],
|
|
208
|
-
extended: [],
|
|
209
|
-
},
|
|
210
|
-
},
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
const newState = reducer(initialStateTest, action);
|
|
214
|
-
const metaEntities = newState.get('metaEntities');
|
|
215
|
-
|
|
216
|
-
// Updated assertions to handle plain object
|
|
217
|
-
expect(metaEntities).toBeDefined();
|
|
218
|
-
expect(metaEntities.tagLookupMap).toBeDefined();
|
|
219
|
-
expect(metaEntities.tagLookupMap).toEqual({});
|
|
220
|
-
});
|
|
221
|
-
});
|
|
@@ -131,7 +131,6 @@ export class Creatives extends React.Component {
|
|
|
131
131
|
errorsAcknowledged: false, // Flag to track if user has acknowledged errors by clicking redirection icon
|
|
132
132
|
},
|
|
133
133
|
};
|
|
134
|
-
this.liquidFlow = Boolean(commonUtil.hasLiquidSupportFeature());
|
|
135
134
|
this.creativesTemplateSteps = {
|
|
136
135
|
1: 'modeSelection',
|
|
137
136
|
2: 'templateSelection', // only for email in current flows wil be used for mpush, line and wechat as well.
|
|
@@ -26,7 +26,7 @@ import * as globalActions from '../Cap/actions';
|
|
|
26
26
|
import './_email.scss';
|
|
27
27
|
import {getMessageObject} from '../../utils/messageUtils';
|
|
28
28
|
import EmailPreview from '../../v2Components/EmailPreview';
|
|
29
|
-
import { getDecodedFileName,
|
|
29
|
+
import { getDecodedFileName, hasSupportCKEditor } from '../../utils/common';
|
|
30
30
|
import Pagination from '../../v2Components/Pagination';
|
|
31
31
|
import * as creativesContainerActions from '../CreativesContainer/actions';
|
|
32
32
|
import withCreatives from '../../hoc/withCreatives';
|
|
@@ -170,7 +170,6 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
170
170
|
deleteLanguage: this.deleteLanguage,
|
|
171
171
|
},
|
|
172
172
|
};
|
|
173
|
-
this.liquidFlow = hasLiquidSupportFeature();
|
|
174
173
|
}
|
|
175
174
|
componentWillMount() {
|
|
176
175
|
const formData = this.initFormData(this.props, true); //_.cloneDeep(this.state.formData);
|
|
@@ -255,7 +254,6 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
255
254
|
layout: 'EMAIL',
|
|
256
255
|
type: 'LAYOUT',
|
|
257
256
|
version: 'v2',
|
|
258
|
-
liquidFlow:this.liquidFlow,
|
|
259
257
|
};
|
|
260
258
|
this.props.globalActions.fetchSchemaForEntity(query);
|
|
261
259
|
window.addEventListener("message", this.handleFrameTasks);
|
|
@@ -347,7 +345,6 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
347
345
|
type: 'TAG',
|
|
348
346
|
context: this.props.location.query.type === 'embedded' ? this.props.location.query.module : 'default',
|
|
349
347
|
embedded: this.props.location.query.type === 'embedded' ? this.props.location.query.type : 'full',
|
|
350
|
-
liquidFlow:this.liquidFlow
|
|
351
348
|
};
|
|
352
349
|
if (this.props.getDefaultTags) {
|
|
353
350
|
query.context = this.props.getDefaultTags;
|
|
@@ -2373,7 +2370,6 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
2373
2370
|
type: 'TAG',
|
|
2374
2371
|
context: (data || '').toLowerCase() === 'all' ? 'default' : (data || '').toLowerCase(),
|
|
2375
2372
|
embedded: 'full',
|
|
2376
|
-
liquidFlow:this.liquidFlow
|
|
2377
2373
|
};
|
|
2378
2374
|
this.props.globalActions.fetchSchemaForEntity(query);
|
|
2379
2375
|
}
|
|
@@ -15,7 +15,7 @@ import HTMLEditor from '../../../v2Components/HtmlEditor';
|
|
|
15
15
|
import CapTagListWithInput from '../../../v2Components/CapTagListWithInput';
|
|
16
16
|
import formBuilderMessages from '../../../v2Components/FormBuilder/messages';
|
|
17
17
|
import { validateLiquidTemplateContent } from '../../../utils/commonUtils';
|
|
18
|
-
import {
|
|
18
|
+
import { isEmailUnsubscribeTagOptional } from '../../../utils/common';
|
|
19
19
|
import history from '../../../utils/history';
|
|
20
20
|
import messages from '../messages';
|
|
21
21
|
import emailMessages from '../../Email/messages';
|
|
@@ -108,13 +108,10 @@ const EmailHTMLEditor = (props) => {
|
|
|
108
108
|
standardErrors: [],
|
|
109
109
|
});
|
|
110
110
|
|
|
111
|
-
// Merge tag validation errors (
|
|
111
|
+
// Merge tag validation errors (missing) into apiValidationErrors so they show in ValidationErrorDisplay
|
|
112
112
|
const mergedApiValidationErrors = useMemo(() => {
|
|
113
113
|
const tagMessages = [];
|
|
114
|
-
if (tagValidationError?.
|
|
115
|
-
tagMessages.push(`Unsupported tags are: ${tagValidationError.unsupportedTags.join(', ')}`);
|
|
116
|
-
}
|
|
117
|
-
if (tagValidationError?.missingTags?.length && !isEmailUnsubscribeTagMandatory()) {
|
|
114
|
+
if (tagValidationError?.missingTags?.length && !isEmailUnsubscribeTagOptional()) {
|
|
118
115
|
tagMessages.push(`Missing tags are: ${tagValidationError.missingTags.join(', ')}`);
|
|
119
116
|
}
|
|
120
117
|
if (tagMessages.length === 0) {
|
|
@@ -190,9 +187,6 @@ const EmailHTMLEditor = (props) => {
|
|
|
190
187
|
},
|
|
191
188
|
}), [htmlContent, subject, currentOrgDetails]);
|
|
192
189
|
|
|
193
|
-
// Check if liquid support is enabled
|
|
194
|
-
const isLiquidEnabled = hasLiquidSupportFeature();
|
|
195
|
-
|
|
196
190
|
// Detect edit mode: when isEditEmail is false (create flow), never treat as edit or fetch template details
|
|
197
191
|
const hasParamsId = params?.id || location?.query?.id || location?.params?.id || location?.pathname?.includes('/edit/');
|
|
198
192
|
const currentTemplateId = isEditEmail
|
|
@@ -493,10 +487,8 @@ const EmailHTMLEditor = (props) => {
|
|
|
493
487
|
const validationResult = validateTags({
|
|
494
488
|
content,
|
|
495
489
|
tagsParam: tags,
|
|
496
|
-
injectedTagsParams: injectedTags,
|
|
497
490
|
location,
|
|
498
491
|
tagModule: getDefaultTags,
|
|
499
|
-
eventContextTags,
|
|
500
492
|
isFullMode,
|
|
501
493
|
});
|
|
502
494
|
|
|
@@ -650,7 +642,7 @@ const EmailHTMLEditor = (props) => {
|
|
|
650
642
|
// IMPORTANT: Clear API validation errors FIRST before checking for validation errors
|
|
651
643
|
// This ensures that old API errors don't block the save when user fixes content and clicks Update again
|
|
652
644
|
// We'll re-validate with fresh API call anyway
|
|
653
|
-
if (
|
|
645
|
+
if (getLiquidTags) {
|
|
654
646
|
setApiValidationErrors({
|
|
655
647
|
liquidErrors: [],
|
|
656
648
|
standardErrors: [],
|
|
@@ -712,7 +704,7 @@ const EmailHTMLEditor = (props) => {
|
|
|
712
704
|
// When EMAIL_UNSUBSCRIBE_TAG_MANDATORY is false: validate and require unsubscribe tag.
|
|
713
705
|
// Run for both library and full mode so liquid-enabled orgs also get the error (notification + ValidationErrorDisplay).
|
|
714
706
|
const isModuleTypeOutbound = (moduleType || '').toUpperCase() === OUTBOUND;
|
|
715
|
-
if (!
|
|
707
|
+
if (!isEmailUnsubscribeTagOptional() && isModuleTypeOutbound) {
|
|
716
708
|
const unsubscribeRegex = /{{unsubscribe(\(#[a-zA-Z\d]{6}\))?}}/g; // eslint-disable-line no-useless-escape
|
|
717
709
|
const hasUnsubscribeTag = unsubscribeRegex.test(htmlContent);
|
|
718
710
|
|
|
@@ -744,52 +736,17 @@ const EmailHTMLEditor = (props) => {
|
|
|
744
736
|
const validationResult = validateTags({
|
|
745
737
|
content: htmlContent,
|
|
746
738
|
tagsParam: tags,
|
|
747
|
-
injectedTagsParams: injectedTags,
|
|
748
739
|
location,
|
|
749
740
|
tagModule: getDefaultTags,
|
|
750
|
-
eventContextTags,
|
|
751
741
|
isFullMode,
|
|
752
742
|
});
|
|
753
743
|
|
|
754
|
-
|
|
755
|
-
if (!validationResult?.valid || (hasUnsupportedTags && !isFullMode)) {
|
|
744
|
+
if (!validationResult?.valid) {
|
|
756
745
|
setTagValidationError(validationResult);
|
|
757
|
-
//
|
|
758
|
-
// For liquid orgs, continue (extractTags API will validate)
|
|
759
|
-
if (!isLiquidEnabled) {
|
|
760
|
-
// Show notification popup like CK/BEE editor
|
|
761
|
-
const baseLanguage = get(currentOrgDetails, 'basic_details.base_language', 'en');
|
|
762
|
-
|
|
763
|
-
const contentNotValidMsg = intl.formatMessage(formBuilderMessages.contentNotValidLanguage);
|
|
764
|
-
let errorMessage = `${contentNotValidMsg} ${baseLanguage}`;
|
|
765
|
-
|
|
766
|
-
if (hasUnsupportedTags) {
|
|
767
|
-
const unsupportedTagsMsg = intl.formatMessage(formBuilderMessages.unsupportedTags);
|
|
768
|
-
errorMessage += `\n${unsupportedTagsMsg} ${validationResult?.unsupportedTags?.join(', ')}`;
|
|
769
|
-
}
|
|
770
|
-
if (validationResult?.missingTags?.length > 0) {
|
|
771
|
-
const missingTagsMsg = intl.formatMessage(formBuilderMessages.missingTags);
|
|
772
|
-
errorMessage += `\n${missingTagsMsg} ${validationResult?.missingTags?.join(', ')}`;
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
const type = 'error';
|
|
776
|
-
CapNotification[type]({
|
|
777
|
-
message: `${type.toUpperCase()} ! ! ! `,
|
|
778
|
-
description: errorMessage,
|
|
779
|
-
duration: 5,
|
|
780
|
-
});
|
|
781
|
-
|
|
782
|
-
// Reset parent state so next click is detected as a change
|
|
783
|
-
if (onValidationFail) {
|
|
784
|
-
onValidationFail();
|
|
785
|
-
}
|
|
786
|
-
// Block save for non-liquid orgs
|
|
787
|
-
return;
|
|
788
|
-
}
|
|
789
|
-
// For liquid orgs, just show warning and continue
|
|
746
|
+
// For liquid orgs, show warning and continue (extractTags API will validate)
|
|
790
747
|
}
|
|
791
748
|
// Clear tag errors if valid
|
|
792
|
-
if (tagValidationError && validationResult?.valid
|
|
749
|
+
if (tagValidationError && validationResult?.valid) {
|
|
793
750
|
setTagValidationError(null);
|
|
794
751
|
}
|
|
795
752
|
}
|
|
@@ -956,8 +913,8 @@ const EmailHTMLEditor = (props) => {
|
|
|
956
913
|
}
|
|
957
914
|
};
|
|
958
915
|
|
|
959
|
-
//
|
|
960
|
-
if (
|
|
916
|
+
// Validate first using extractTags API
|
|
917
|
+
if (getLiquidTags) {
|
|
961
918
|
// Note: API validation errors are already cleared at the start of handleSave
|
|
962
919
|
// This ensures fresh validation on every save attempt
|
|
963
920
|
|
|
@@ -998,10 +955,6 @@ const EmailHTMLEditor = (props) => {
|
|
|
998
955
|
messages: formBuilderMessages,
|
|
999
956
|
onError,
|
|
1000
957
|
onSuccess,
|
|
1001
|
-
tagLookupMap: metaEntities?.tagLookupMap,
|
|
1002
|
-
eventContextTags,
|
|
1003
|
-
isLiquidFlow: true,
|
|
1004
|
-
forwardedTags: forwardedTags || {},
|
|
1005
958
|
});
|
|
1006
959
|
} else {
|
|
1007
960
|
performSave();
|
|
@@ -1013,7 +966,6 @@ const EmailHTMLEditor = (props) => {
|
|
|
1013
966
|
injectedTags,
|
|
1014
967
|
location,
|
|
1015
968
|
getDefaultTags,
|
|
1016
|
-
eventContextTags,
|
|
1017
969
|
formatMessage,
|
|
1018
970
|
subjectError,
|
|
1019
971
|
isFullMode,
|
|
@@ -1025,11 +977,8 @@ const EmailHTMLEditor = (props) => {
|
|
|
1025
977
|
emailActions,
|
|
1026
978
|
getFormdata,
|
|
1027
979
|
isGetFormData,
|
|
1028
|
-
isLiquidEnabled,
|
|
1029
980
|
getLiquidTags,
|
|
1030
981
|
showLiquidErrorInFooter,
|
|
1031
|
-
metaEntities,
|
|
1032
|
-
forwardedTags,
|
|
1033
982
|
globalActions,
|
|
1034
983
|
intl,
|
|
1035
984
|
extractedTemplateName,
|
|
@@ -1175,7 +1124,6 @@ const EmailHTMLEditor = (props) => {
|
|
|
1175
1124
|
userLocale={intl.locale || 'en'}
|
|
1176
1125
|
moduleFilterEnabled={location?.query?.type !== EMBEDDED}
|
|
1177
1126
|
onTagContextChange={handleOnTagsContextChange}
|
|
1178
|
-
isLiquidEnabled={isLiquidEnabled}
|
|
1179
1127
|
isFullMode={isFullMode}
|
|
1180
1128
|
onErrorAcknowledged={handleErrorAcknowledged}
|
|
1181
1129
|
onValidationChange={handleValidationChange}
|