@capillarytech/creatives-library 8.0.202 → 8.0.204
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
CHANGED
|
@@ -139,196 +139,8 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
|
|
|
139
139
|
// Check if the liquid flow feature is supported and the channel is in the supported list.
|
|
140
140
|
this.liquidFlow = this.isLiquidFlowSupported.bind(this);
|
|
141
141
|
this.onSubmitWrapper = this.onSubmitWrapper.bind(this);
|
|
142
|
-
|
|
143
|
-
// Performance optimization: Debounced functions for high-frequency updates
|
|
144
|
-
this.debouncedUpdateFormData = _.debounce((data, val, event, skipStateUpdate) => {
|
|
145
|
-
this.performFormDataUpdate(data, val, event, skipStateUpdate);
|
|
146
|
-
}, 300);
|
|
147
|
-
this.debouncedValidation = _.debounce(this.validateForm.bind(this), 500);
|
|
148
|
-
|
|
149
|
-
// Memoized validation cache
|
|
150
|
-
this.validationCache = new Map();
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Helper function to generate unique tab ID
|
|
155
|
-
generateUniqueTabId(formData, tabIndex) {
|
|
156
|
-
let id = _.uniqueId();
|
|
157
|
-
let validId = false;
|
|
158
|
-
|
|
159
|
-
while (!validId) {
|
|
160
|
-
validId = true;
|
|
161
|
-
for (let idx = 0; idx < formData[tabIndex].selectedLanguages.length; idx += 1) {
|
|
162
|
-
if (!formData[tabIndex]) {
|
|
163
|
-
continue;
|
|
164
|
-
}
|
|
165
|
-
if (id === formData[tabIndex][formData[tabIndex].selectedLanguages[idx]].tabKey) {
|
|
166
|
-
validId = false;
|
|
167
|
-
break;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
if (!validId) {
|
|
171
|
-
id = _.uniqueId();
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return id;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Performance optimized form data update function
|
|
179
|
-
performFormDataUpdate(data, val, event, skipStateUpdate = false) {
|
|
180
|
-
|
|
181
|
-
// Use optimized state update instead of deep cloning
|
|
182
|
-
const formData = this.optimizedFormDataUpdate(data, val, event);
|
|
183
|
-
|
|
184
|
-
const tabIndex = this.state.currentTab - 1;
|
|
185
|
-
let currentTab = this.state.currentTab;
|
|
186
|
-
|
|
187
|
-
if (this.state.usingTabContainer && !val.standalone) {
|
|
188
|
-
const data1 = data;
|
|
189
|
-
if (event === "addLanguage") {
|
|
190
|
-
const addLanguageType = this.props.addLanguageType;
|
|
191
|
-
if (addLanguageType === '') {
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
const currentLang = formData[tabIndex].activeTab;
|
|
195
|
-
let baseTab;
|
|
196
|
-
|
|
197
|
-
switch (addLanguageType) {
|
|
198
|
-
case "upload":
|
|
199
|
-
baseTab = _.cloneDeep(formData[tabIndex][currentLang]);
|
|
200
|
-
|
|
201
|
-
baseTab.iso_code = data.iso_code;
|
|
202
|
-
baseTab.lang_id = data.lang_id;
|
|
203
|
-
baseTab.language = data.language;
|
|
204
|
-
baseTab.tabKey = this.generateUniqueTabId(formData, tabIndex);
|
|
205
|
-
|
|
206
|
-
formData[tabIndex][data.iso_code] = baseTab;
|
|
207
|
-
formData[tabIndex].activeTab = data.iso_code;
|
|
208
|
-
formData[tabIndex].tabKey = baseTab.tabKey;
|
|
209
|
-
break;
|
|
210
|
-
case "copyPrimaryLanguage":
|
|
211
|
-
case "useEditor":
|
|
212
|
-
baseTab = _.cloneDeep(formData[tabIndex][this.props.baseLanguage]);
|
|
213
|
-
|
|
214
|
-
baseTab.iso_code = data.iso_code;
|
|
215
|
-
baseTab.lang_id = data.lang_id;
|
|
216
|
-
baseTab.language = data.language;
|
|
217
|
-
baseTab.tabKey = this.generateUniqueTabId(formData, tabIndex);
|
|
218
|
-
|
|
219
|
-
formData[tabIndex].selectedLanguages.push(data.iso_code);
|
|
220
|
-
formData[tabIndex][data.iso_code] = baseTab;
|
|
221
|
-
formData[tabIndex].activeTab = data.iso_code;
|
|
222
|
-
formData[tabIndex].tabKey = baseTab.tabKey;
|
|
223
|
-
break;
|
|
224
|
-
case '':
|
|
225
|
-
return;
|
|
226
|
-
default:
|
|
227
|
-
break;
|
|
228
|
-
}
|
|
229
|
-
const that = this;
|
|
230
|
-
setTimeout(() => {
|
|
231
|
-
that.setState({tabKey: baseTab.tabKey});
|
|
232
|
-
}, 0);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
if (!this.props.isNewVersionFlow) {
|
|
236
|
-
formData[tabIndex][val.id] = data1;
|
|
237
|
-
} else if (this.props.isNewVersionFlow && event !== "addLanguage" && event !== "onContentChange") {
|
|
238
|
-
formData[tabIndex][this.props.baseLanguage][val.id] = data1;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (formData[tabIndex].base) {
|
|
242
|
-
if (!this.props.isNewVersionFlow) {
|
|
243
|
-
formData.base[val.id] = data1;
|
|
244
|
-
} else {
|
|
245
|
-
formData.base[data1.iso_code] = formData[tabIndex][data1.iso_code];
|
|
246
|
-
formData.base.tabKey = formData[tabIndex].tabKey;
|
|
247
|
-
formData.base.activeTab = formData[tabIndex].activeTab;
|
|
248
|
-
formData.base.selectedLanguages = formData[tabIndex].selectedLanguages;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
} else {
|
|
252
|
-
formData[val.id] = data;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (this.props.isNewVersionFlow) {
|
|
256
|
-
if (event === 'onSelect' && data === 'New Version') {
|
|
257
|
-
this.callChildEvent(data, val, 'addVersion', event);
|
|
258
|
-
} else if (event === 'onSelect' && data !== 'New Version') {
|
|
259
|
-
currentTab = _.findIndex(this.state.formData['template-version-options'], { key: data}) + 1;
|
|
260
|
-
this.setState({currentTab, tabKey: formData[`${currentTab - 1}`].tabKey}, () => {
|
|
261
|
-
val.injectedEvents[event].call(this, this.state.formData['template-version-options'][currentTab - 1].key, formData, val);
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
if (event === 'onContentChange') {
|
|
266
|
-
// Content change handling
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
142
|
|
|
270
|
-
// Only update state if not already updated (for immediate UI feedback)
|
|
271
|
-
if (!skipStateUpdate) {
|
|
272
|
-
this.setState({formData}, () => {
|
|
273
|
-
if (this.props.startValidation) {
|
|
274
|
-
this.debouncedValidation();
|
|
275
|
-
}
|
|
276
|
-
});
|
|
277
|
-
} else {
|
|
278
|
-
// Just trigger validation if state was already updated
|
|
279
|
-
if (this.props.startValidation) {
|
|
280
|
-
this.debouncedValidation();
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if (event && val.injectedEvents[event]) {
|
|
285
|
-
if (event === "onRowClick") {
|
|
286
|
-
val.injectedEvents[event].call(this, data);
|
|
287
|
-
} else if (this.props.isNewVersionFlow && event !== 'onSelect') {
|
|
288
|
-
if (event === 'addLanguage') {
|
|
289
|
-
val.injectedEvents[event].call(this, data, formData, val);
|
|
290
|
-
this.setState({currentEventVal: {}, currentEvent: {}, currentEventData: {}});
|
|
291
|
-
} else {
|
|
292
|
-
val.injectedEvents[event].call(this, true, formData, val);
|
|
293
|
-
}
|
|
294
|
-
} else if (!this.props.isNewVersionFlow) {
|
|
295
|
-
val.injectedEvents[event].call(this, true, formData, val);
|
|
296
|
-
}
|
|
297
|
-
} else if (val.injectedEvents && val.injectedEvents.onChange) {
|
|
298
|
-
val.injectedEvents.onChange.call(this, true, formData, val);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
if (!((event === 'onSelect' && data === 'New Version') || event === 'onContentChange')) {
|
|
302
|
-
this.props.onChange(formData, this.state.tabCount, currentTab, val);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Optimized form data update - only clone what's necessary
|
|
307
|
-
optimizedFormDataUpdate(data, val, event) {
|
|
308
|
-
const currentFormData = this.state.formData;
|
|
309
|
-
|
|
310
|
-
// For simple field updates, use spread operator instead of deep clone
|
|
311
|
-
if (!this.state.usingTabContainer || val.standalone) {
|
|
312
|
-
return {
|
|
313
|
-
...currentFormData,
|
|
314
|
-
[val.id]: data
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// For tab container updates, only clone the affected tab
|
|
319
|
-
const tabIndex = this.state.currentTab - 1;
|
|
320
|
-
const updatedFormData = { ...currentFormData };
|
|
321
|
-
|
|
322
|
-
if (updatedFormData[tabIndex]) {
|
|
323
|
-
updatedFormData[tabIndex] = {
|
|
324
|
-
...updatedFormData[tabIndex],
|
|
325
|
-
[val.id]: data
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
return updatedFormData;
|
|
330
143
|
}
|
|
331
|
-
|
|
332
144
|
isLiquidFlowSupported = () => {
|
|
333
145
|
return Boolean(LIQUID_SUPPORTED_CHANNELS.includes(this.props?.schema?.channel?.toUpperCase()) && hasLiquidSupportFeature());
|
|
334
146
|
}
|
|
@@ -457,7 +269,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
|
|
|
457
269
|
}
|
|
458
270
|
this.setState({formData: nextProps.formData, currentLangTab}, () => {
|
|
459
271
|
if (nextProps?.isNewVersionFlow && !this.state?.formData[this.state?.currentTab - 1][this.state?.formData[this.state?.currentTab - 1]?.activeTab]?.tabKey) {
|
|
460
|
-
|
|
272
|
+
this.resetTabKeys(nextProps.formData, nextProps.tabCount, false, true);
|
|
461
273
|
}
|
|
462
274
|
if (type === 'embedded' || ( this.props.schema.channel && this.props.schema.channel.toUpperCase() === 'EMAIL')) {
|
|
463
275
|
// Don't run validation if we're in Test & Preview mode
|
|
@@ -1104,7 +916,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
|
|
|
1104
916
|
}
|
|
1105
917
|
}
|
|
1106
918
|
if(_.isEmpty(androidData) && this.state.currentTab == 2){
|
|
1107
|
-
this.setState({androidValid, iosValid
|
|
919
|
+
this.setState({androidValid, iosValid}, () => {
|
|
1108
920
|
this.props.setModalContent('ios');
|
|
1109
921
|
});
|
|
1110
922
|
// modal.body = "Android template is not configured. Save without Android template";
|
|
@@ -1119,7 +931,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
|
|
|
1119
931
|
}
|
|
1120
932
|
}
|
|
1121
933
|
if(_.isEmpty(iosData) && this.state.currentTab == 1){
|
|
1122
|
-
this.setState({androidValid, iosValid
|
|
934
|
+
this.setState({androidValid, iosValid}, () => {
|
|
1123
935
|
this.props.setModalContent('android');
|
|
1124
936
|
});
|
|
1125
937
|
// modal.body = "IOS template is not configured, Save without IOS template";
|
|
@@ -2215,62 +2027,6 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
|
|
|
2215
2027
|
}
|
|
2216
2028
|
|
|
2217
2029
|
updateFormData(data, val, event) {
|
|
2218
|
-
|
|
2219
|
-
// Check if this is a high-frequency input field that should be optimized
|
|
2220
|
-
const isHighFrequencyField = val && (
|
|
2221
|
-
val.id === 'template-name' ||
|
|
2222
|
-
val.id === 'template-subject'
|
|
2223
|
-
);
|
|
2224
|
-
|
|
2225
|
-
if (isHighFrequencyField && !event) {
|
|
2226
|
-
// For high-frequency fields: immediate UI update + debounced expensive operations
|
|
2227
|
-
this.updateFormDataOptimized(data, val, event);
|
|
2228
|
-
return;
|
|
2229
|
-
}
|
|
2230
|
-
|
|
2231
|
-
// For non-high-frequency fields or special events, use immediate update
|
|
2232
|
-
this.performFormDataUpdate(data, val, event);
|
|
2233
|
-
}
|
|
2234
|
-
|
|
2235
|
-
// Optimized update for high-frequency fields
|
|
2236
|
-
updateFormDataOptimized(data, val, event) {
|
|
2237
|
-
// 1. Immediate UI update - update the field value instantly
|
|
2238
|
-
this.updateFieldValueImmediately(data, val);
|
|
2239
|
-
|
|
2240
|
-
// 2. Debounce expensive operations (validation, parent updates) - skip state update since we already did it
|
|
2241
|
-
this.debouncedUpdateFormData(data, val, event, true);
|
|
2242
|
-
}
|
|
2243
|
-
|
|
2244
|
-
// Update field value immediately for UI feedback
|
|
2245
|
-
updateFieldValueImmediately(data, val) {
|
|
2246
|
-
const currentFormData = this.state.formData;
|
|
2247
|
-
let updatedFormData;
|
|
2248
|
-
|
|
2249
|
-
if (!this.state.usingTabContainer || val.standalone) {
|
|
2250
|
-
// Simple field update
|
|
2251
|
-
updatedFormData = {
|
|
2252
|
-
...currentFormData,
|
|
2253
|
-
[val.id]: data
|
|
2254
|
-
};
|
|
2255
|
-
} else {
|
|
2256
|
-
// Tab container update
|
|
2257
|
-
const tabIndex = this.state.currentTab - 1;
|
|
2258
|
-
updatedFormData = { ...currentFormData };
|
|
2259
|
-
|
|
2260
|
-
if (updatedFormData[tabIndex]) {
|
|
2261
|
-
updatedFormData[tabIndex] = {
|
|
2262
|
-
...updatedFormData[tabIndex],
|
|
2263
|
-
[val.id]: data
|
|
2264
|
-
};
|
|
2265
|
-
}
|
|
2266
|
-
}
|
|
2267
|
-
|
|
2268
|
-
// Update state immediately for UI feedback
|
|
2269
|
-
this.setState({ formData: updatedFormData });
|
|
2270
|
-
}
|
|
2271
|
-
|
|
2272
|
-
// Legacy updateFormData function - kept for backward compatibility
|
|
2273
|
-
updateFormDataLegacy(data, val, event) {
|
|
2274
2030
|
const formData = _.cloneDeep(this.state.formData);
|
|
2275
2031
|
|
|
2276
2032
|
const tabIndex = this.state.currentTab - 1;
|
|
@@ -2430,57 +2186,6 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
|
|
|
2430
2186
|
hasClass(element, className) {
|
|
2431
2187
|
return (` ${element.className} `).indexOf(` ${className} `) > -1;
|
|
2432
2188
|
}
|
|
2433
|
-
|
|
2434
|
-
// Handle field blur for validation
|
|
2435
|
-
handleFieldBlur = (e, val) => {
|
|
2436
|
-
// Trigger validation on blur for high-frequency fields
|
|
2437
|
-
if (val && (val.id === 'template-name' || val.id === 'template-subject')) {
|
|
2438
|
-
this.debouncedValidation();
|
|
2439
|
-
}
|
|
2440
|
-
}
|
|
2441
|
-
|
|
2442
|
-
// Memoized validation for specific fields
|
|
2443
|
-
getMemoizedValidation = (fieldId, fieldValue) => {
|
|
2444
|
-
const cacheKey = `${fieldId}_${fieldValue}`;
|
|
2445
|
-
|
|
2446
|
-
if (this.validationCache.has(cacheKey)) {
|
|
2447
|
-
return this.validationCache.get(cacheKey);
|
|
2448
|
-
}
|
|
2449
|
-
|
|
2450
|
-
// Perform validation logic here
|
|
2451
|
-
const isValid = this.performFieldValidation(fieldId, fieldValue);
|
|
2452
|
-
this.validationCache.set(cacheKey, isValid);
|
|
2453
|
-
|
|
2454
|
-
// Clear cache if it gets too large
|
|
2455
|
-
if (this.validationCache.size > 100) {
|
|
2456
|
-
this.validationCache.clear();
|
|
2457
|
-
}
|
|
2458
|
-
|
|
2459
|
-
return isValid;
|
|
2460
|
-
}
|
|
2461
|
-
|
|
2462
|
-
// Perform validation for a specific field
|
|
2463
|
-
performFieldValidation = (fieldId, fieldValue) => {
|
|
2464
|
-
// Basic validation logic for template-name and template-subject
|
|
2465
|
-
if (fieldId === 'template-name' || fieldId === 'template-subject') {
|
|
2466
|
-
return fieldValue && fieldValue.trim().length > 0;
|
|
2467
|
-
}
|
|
2468
|
-
return true;
|
|
2469
|
-
}
|
|
2470
|
-
|
|
2471
|
-
// Cleanup debounced functions on component unmount
|
|
2472
|
-
componentWillUnmount() {
|
|
2473
|
-
if (this.debouncedUpdateFormData) {
|
|
2474
|
-
this.debouncedUpdateFormData.cancel();
|
|
2475
|
-
}
|
|
2476
|
-
if (this.debouncedValidation) {
|
|
2477
|
-
this.debouncedValidation.cancel();
|
|
2478
|
-
}
|
|
2479
|
-
// Clear validation cache
|
|
2480
|
-
if (this.validationCache) {
|
|
2481
|
-
this.validationCache.clear();
|
|
2482
|
-
}
|
|
2483
|
-
}
|
|
2484
2189
|
allowAddSecondaryCta = (val) => {
|
|
2485
2190
|
if (val.fieldsCount > 0) {
|
|
2486
2191
|
const errorData = _.cloneDeep(this.state.errorData);
|
|
@@ -2896,7 +2601,6 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
|
|
|
2896
2601
|
label={val.label}
|
|
2897
2602
|
autosize={val.autosize ? val.autosizeParams : false}
|
|
2898
2603
|
onChange={(e) => this.updateFormData(e.target.value, val)}
|
|
2899
|
-
onBlur={(e) => this.handleFieldBlur(e, val)}
|
|
2900
2604
|
style={val.style ? val.style : {}}
|
|
2901
2605
|
defaultValue={messageContent || ''}
|
|
2902
2606
|
value={messageContent || ""}
|
|
@@ -2978,7 +2682,6 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
|
|
|
2978
2682
|
style={val.style ? val.style : {}}
|
|
2979
2683
|
placeholder={val.placeholder}
|
|
2980
2684
|
onChange={(e) => this.updateFormData(e.target.value, val)}
|
|
2981
|
-
onBlur={(e) => this.handleFieldBlur(e, val)}
|
|
2982
2685
|
defaultValue={isVersionEnable ? this.state.formData[`${this.state.currentTab - 1}`][val.id] : this.state.formData[val.id]}
|
|
2983
2686
|
value={value || ""}
|
|
2984
2687
|
disabled={val.disabled}
|
|
@@ -3463,7 +3166,6 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
|
|
|
3463
3166
|
style={val.style ? val.style : {}}
|
|
3464
3167
|
placeholder={val.placeholder}
|
|
3465
3168
|
onChange={(e) => this.updateFormData(e.target.value, val)}
|
|
3466
|
-
onBlur={(e) => this.handleFieldBlur(e, val)}
|
|
3467
3169
|
value={value || ""}
|
|
3468
3170
|
defaultValue={isVersionEnable ? this.state.formData[`${this.state.currentTab - 1}`][val.id] : this.state.formData[val.id]}
|
|
3469
3171
|
disabled={val.disabled}
|
|
@@ -349,4 +349,4 @@ const withConnect = connect(mapStateToProps, mapDispatchToProps);
|
|
|
349
349
|
const withSaga = injectSaga({ key: 'beeEditor', saga: v2BeeEditionSagas });
|
|
350
350
|
const withReducer = injectReducer({ key: 'beeEditor', reducer: v2BeeEditionReducer });
|
|
351
351
|
|
|
352
|
-
export default compose(withReducer, withSaga, withConnect)(injectIntl(
|
|
352
|
+
export default compose(withReducer, withSaga, withConnect)(injectIntl(BeeEditor));
|
|
@@ -11,7 +11,7 @@ import CapNotification from '@capillarytech/cap-ui-library/CapNotification';
|
|
|
11
11
|
import { injectIntl, FormattedMessage } from 'react-intl';
|
|
12
12
|
import classnames from 'classnames';
|
|
13
13
|
import {
|
|
14
|
-
isEmpty, get, forEach, cloneDeep,
|
|
14
|
+
isEmpty, get, forEach, cloneDeep,
|
|
15
15
|
} from 'lodash';
|
|
16
16
|
import { connect } from 'react-redux';
|
|
17
17
|
import { createStructuredSelector } from 'reselect';
|
|
@@ -105,8 +105,6 @@ export class Creatives extends React.Component {
|
|
|
105
105
|
// NEW: Test and Preview feature state
|
|
106
106
|
showTestAndPreviewSlidebox: false,
|
|
107
107
|
isTestAndPreviewMode: false, // Add flag to track Test & Preview mode
|
|
108
|
-
// Performance optimization: Local template name for immediate UI feedback
|
|
109
|
-
localTemplateName: '',
|
|
110
108
|
};
|
|
111
109
|
this.liquidFlow = Boolean(commonUtil.hasLiquidSupportFeature());
|
|
112
110
|
this.creativesTemplateSteps = {
|
|
@@ -114,9 +112,6 @@ export class Creatives extends React.Component {
|
|
|
114
112
|
2: 'templateSelection', // only for email in current flows wil be used for mpush, line and wechat as well.
|
|
115
113
|
3: 'createTemplateContent',
|
|
116
114
|
};
|
|
117
|
-
|
|
118
|
-
// Performance optimization: Debounced template name update
|
|
119
|
-
this.debouncedTemplateNameUpdate = debounce(this.performTemplateNameUpdate.bind(this), 300);
|
|
120
115
|
}
|
|
121
116
|
|
|
122
117
|
componentWillUnmount() {
|
|
@@ -124,11 +119,6 @@ export class Creatives extends React.Component {
|
|
|
124
119
|
this.props.templateActions.resetTemplateStoreData();
|
|
125
120
|
}
|
|
126
121
|
this.props.globalActions.clearMetaEntities();
|
|
127
|
-
|
|
128
|
-
// Cleanup debounced function
|
|
129
|
-
if (this.debouncedTemplateNameUpdate) {
|
|
130
|
-
this.debouncedTemplateNameUpdate.cancel();
|
|
131
|
-
}
|
|
132
122
|
}
|
|
133
123
|
|
|
134
124
|
componentDidMount() {
|
|
@@ -146,29 +136,6 @@ export class Creatives extends React.Component {
|
|
|
146
136
|
|
|
147
137
|
onEnterTemplateName = () => {
|
|
148
138
|
this.setState({ templateNameExists: true });
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Performance optimized template name update
|
|
152
|
-
performTemplateNameUpdate = (value, formData, onFormDataChange) => {
|
|
153
|
-
const isEmptyTemplateName = !value.trim();
|
|
154
|
-
const newFormData = { ...formData, 'template-name': value, 'isTemplateNameEdited': true };
|
|
155
|
-
|
|
156
|
-
this.setState({ isTemplateNameEmpty: isEmptyTemplateName });
|
|
157
|
-
onFormDataChange(newFormData);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Update template name immediately for UI feedback
|
|
161
|
-
updateTemplateNameImmediately = (value, formData, onFormDataChange) => {
|
|
162
|
-
const isEmptyTemplateName = !value.trim();
|
|
163
|
-
|
|
164
|
-
// 1. IMMEDIATE: Update local state for instant UI feedback
|
|
165
|
-
this.setState({
|
|
166
|
-
isTemplateNameEmpty: isEmptyTemplateName,
|
|
167
|
-
localTemplateName: value
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
// 2. DEBOUNCED: Only debounce the expensive onFormDataChange call
|
|
171
|
-
this.debouncedTemplateNameUpdate(value, formData, onFormDataChange);
|
|
172
139
|
};
|
|
173
140
|
|
|
174
141
|
onRemoveTemplateName = () => {
|
|
@@ -1428,30 +1395,21 @@ export class Creatives extends React.Component {
|
|
|
1428
1395
|
} />
|
|
1429
1396
|
)
|
|
1430
1397
|
|
|
1431
|
-
templateNameComponentInput = ({ formData, onFormDataChange, name }) =>
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
value=
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
}}
|
|
1447
|
-
onChange={(ev) => {
|
|
1448
|
-
const { value } = ev.currentTarget;
|
|
1449
|
-
// Use optimized update for better performance
|
|
1450
|
-
this.updateTemplateNameImmediately(value, formData, onFormDataChange);
|
|
1451
|
-
}}
|
|
1452
|
-
/>
|
|
1453
|
-
);
|
|
1454
|
-
}
|
|
1398
|
+
templateNameComponentInput = ({ formData, onFormDataChange, name }) => (
|
|
1399
|
+
<CapInput
|
|
1400
|
+
value={name}
|
|
1401
|
+
suffix={<span />}
|
|
1402
|
+
onBlur={() => { this.setState({ isEditName: false }, () => { this.showTemplateName({ formData, onFormDataChange }); }); }}
|
|
1403
|
+
onChange={(ev) => {
|
|
1404
|
+
const { value } = ev.currentTarget;
|
|
1405
|
+
const isEmptyTemplateName = !value.trim();
|
|
1406
|
+
|
|
1407
|
+
const newFormData = { ...formData, 'template-name': value, 'isTemplateNameEdited': true };
|
|
1408
|
+
this.setState({ isTemplateNameEmpty: isEmptyTemplateName });
|
|
1409
|
+
onFormDataChange(newFormData);
|
|
1410
|
+
}}
|
|
1411
|
+
/>
|
|
1412
|
+
)
|
|
1455
1413
|
|
|
1456
1414
|
showTemplateName = ({ formData, onFormDataChange }) => { //gets called from email/index after template data is fetched
|
|
1457
1415
|
const { slidBoxContent, currentChannel, isEditName } = this.state;
|
|
@@ -1465,10 +1423,7 @@ export class Creatives extends React.Component {
|
|
|
1465
1423
|
if (name && !isEditName) {
|
|
1466
1424
|
this.setState({ showTemplateNameComponentEdit: false });
|
|
1467
1425
|
} else if (isEditName) {
|
|
1468
|
-
this.setState({
|
|
1469
|
-
showTemplateNameComponentEdit: true,
|
|
1470
|
-
localTemplateName: name || '' // Initialize local state with current value
|
|
1471
|
-
});
|
|
1426
|
+
this.setState({ showTemplateNameComponentEdit: true });
|
|
1472
1427
|
}
|
|
1473
1428
|
}
|
|
1474
1429
|
}
|
|
@@ -2516,9 +2516,6 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
|
|
|
2516
2516
|
});
|
|
2517
2517
|
obj.versions.history.push(newdata);
|
|
2518
2518
|
}
|
|
2519
|
-
if (index === "template-subject") {
|
|
2520
|
-
obj.versions.history[0].subject = newdata;
|
|
2521
|
-
}
|
|
2522
2519
|
});
|
|
2523
2520
|
//const data = formData[`${this.state.currentTab - 1}`];
|
|
2524
2521
|
obj.name = formData['template-name'];
|
|
@@ -207,6 +207,9 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
207
207
|
{
|
|
208
208
|
formData: newFormData,
|
|
209
209
|
tabCount,
|
|
210
|
+
isSchemaChanged:
|
|
211
|
+
compareValue?.toLowerCase() === EXTERNAL_LINK_LOWERCASE ||
|
|
212
|
+
!this.state?.isSchemaChanged,
|
|
210
213
|
},
|
|
211
214
|
() => {
|
|
212
215
|
if (isFullMode && showTemplateName) {
|
|
@@ -217,9 +220,6 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
217
220
|
}
|
|
218
221
|
}
|
|
219
222
|
);
|
|
220
|
-
this.setState({isSchemaChanged:
|
|
221
|
-
compareValue?.toLowerCase() === EXTERNAL_LINK_LOWERCASE ||
|
|
222
|
-
!this.state?.isSchemaChanged});
|
|
223
223
|
};
|
|
224
224
|
|
|
225
225
|
onTagSelect = (data, currentTab, srcComp) => {
|