@capillarytech/creatives-library 8.0.186 → 8.0.188
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/config/app.js +0 -1
- package/package.json +1 -1
- package/services/api.js +0 -1
- package/v2Components/CapActionButton/index.js +3 -1
- package/v2Containers/CreativesContainer/SlideBoxContent.js +0 -4
- package/v2Containers/CreativesContainer/index.js +10 -33
- package/v2Containers/Rcs/index.js +258 -66
- package/v2Containers/Rcs/index.scss +0 -1
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +1680 -0
- package/v2Containers/Rcs/tests/index.test.js +1 -2
- package/v2Containers/Rcs/utils.js +0 -2
- package/v2Containers/Templates/index.js +0 -2
- package/v2Containers/Whatsapp/constants.js +1 -22
- package/v2Containers/Whatsapp/index.js +1 -14
package/config/app.js
CHANGED
|
@@ -21,7 +21,6 @@ const config = {
|
|
|
21
21
|
},
|
|
22
22
|
development: {
|
|
23
23
|
api_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/arya/api/v1/creatives',
|
|
24
|
-
// api_endpoint: 'http://localhost:2022/arya/api/v1/creatives',
|
|
25
24
|
campaigns_api_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/iris/v2/campaigns',
|
|
26
25
|
campaigns_api_org_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/iris/v2/org/campaign',
|
|
27
26
|
auth_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/arya/api/v1/auth',
|
package/package.json
CHANGED
package/services/api.js
CHANGED
|
@@ -264,7 +264,6 @@ export const getUserData = () => {
|
|
|
264
264
|
|
|
265
265
|
export const createTemplate = ({template}) => {
|
|
266
266
|
const url = `${API_ENDPOINT}/templates/SMS`;
|
|
267
|
-
console.log("creating template",template);
|
|
268
267
|
return request(url, getAPICallObject('POST', template));
|
|
269
268
|
};
|
|
270
269
|
|
|
@@ -83,7 +83,9 @@ export const CapActionButton = (props) => {
|
|
|
83
83
|
const onButtonTextChange = ({target}) => {
|
|
84
84
|
const { value, id } = target;
|
|
85
85
|
let errorMessage = '';
|
|
86
|
-
if (
|
|
86
|
+
if (value.length > BTN_MAX_LENGTH) {
|
|
87
|
+
errorMessage = formatMessage(messages.ctaButtonTextLengthError);
|
|
88
|
+
} if (!isValidText(value)) {
|
|
87
89
|
errorMessage = formatMessage(messages.ctaButtonErrorMessage);
|
|
88
90
|
}
|
|
89
91
|
setButtonError(errorMessage);
|
|
@@ -378,7 +378,6 @@ export function SlideBoxContent(props) {
|
|
|
378
378
|
};
|
|
379
379
|
}
|
|
380
380
|
case constants.RCS: {
|
|
381
|
-
console.log("in slidebox content .js");
|
|
382
381
|
const template = cloneDeep(templateDataObject);
|
|
383
382
|
const { description = "", media: { mediaUrl = "" } = {}, title = "", suggestions = [] } = get(template, 'versions.base.content.RCS.rcsContent.cardContent[0]', {});
|
|
384
383
|
return {
|
|
@@ -393,10 +392,7 @@ export function SlideBoxContent(props) {
|
|
|
393
392
|
};
|
|
394
393
|
}
|
|
395
394
|
default:
|
|
396
|
-
{
|
|
397
|
-
console.log("in default case");
|
|
398
395
|
return get(templateDataObject, `versions.base.content`);
|
|
399
|
-
}
|
|
400
396
|
}
|
|
401
397
|
};
|
|
402
398
|
|
|
@@ -633,34 +633,7 @@ export class Creatives extends React.Component {
|
|
|
633
633
|
channel = constants.RCS,
|
|
634
634
|
} = templateData || {};
|
|
635
635
|
const cardContent = (rcsContent.cardContent && rcsContent.cardContent[0]) || {};
|
|
636
|
-
const
|
|
637
|
-
const reverseMapText = (text, cardVarMapped) => {
|
|
638
|
-
if (!text || !cardVarMapped || Object.keys(cardVarMapped).length === 0) {
|
|
639
|
-
return text;
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
let reversedText = text;
|
|
643
|
-
Object.entries(cardVarMapped).forEach(([key, value]) => {
|
|
644
|
-
const cleanValue = value.replace(/^\{\{|\}\}$/g, '');
|
|
645
|
-
const valuePattern = new RegExp(`\\{\\{${cleanValue}\\}\\}`, 'g');
|
|
646
|
-
reversedText = reversedText.replace(valuePattern, `{{${key}}}`);
|
|
647
|
-
});
|
|
648
|
-
return reversedText;
|
|
649
|
-
};
|
|
650
|
-
|
|
651
|
-
const updatedRcsContent = {
|
|
652
|
-
...rcsContent,
|
|
653
|
-
cardContent: [
|
|
654
|
-
{
|
|
655
|
-
...cardContent,
|
|
656
|
-
Status: RCS_STATUSES.approved,
|
|
657
|
-
title: reverseMapText(cardContent.title, cardVarMapped),
|
|
658
|
-
description: reverseMapText(cardContent.description, cardVarMapped),
|
|
659
|
-
cardVarMapped: {},
|
|
660
|
-
},
|
|
661
|
-
...(rcsContent.cardContent?.slice(1) || []),
|
|
662
|
-
],
|
|
663
|
-
};
|
|
636
|
+
const Status = RCS_STATUSES.approved || '';
|
|
664
637
|
|
|
665
638
|
creativesTemplateData = {
|
|
666
639
|
type: channel,
|
|
@@ -670,7 +643,15 @@ export class Creatives extends React.Component {
|
|
|
670
643
|
base: {
|
|
671
644
|
content: {
|
|
672
645
|
RCS: {
|
|
673
|
-
rcsContent:
|
|
646
|
+
rcsContent: {
|
|
647
|
+
...rcsContent,
|
|
648
|
+
cardContent: [
|
|
649
|
+
{
|
|
650
|
+
...cardContent,
|
|
651
|
+
Status,
|
|
652
|
+
},
|
|
653
|
+
],
|
|
654
|
+
},
|
|
674
655
|
smsFallBackContent,
|
|
675
656
|
},
|
|
676
657
|
},
|
|
@@ -1063,7 +1044,6 @@ export class Creatives extends React.Component {
|
|
|
1063
1044
|
}
|
|
1064
1045
|
break;
|
|
1065
1046
|
case constants.RCS: {
|
|
1066
|
-
console.log("in creatives container .js");
|
|
1067
1047
|
if (template.value) {
|
|
1068
1048
|
const { name = "", versions = {} } = {
|
|
1069
1049
|
} = template.value || {};
|
|
@@ -1074,14 +1054,12 @@ export class Creatives extends React.Component {
|
|
|
1074
1054
|
cardType = "",
|
|
1075
1055
|
cardSettings = {},
|
|
1076
1056
|
} = get(versions, 'base.content.RCS.rcsContent',{});
|
|
1077
|
-
console.log("versions--->", versions);
|
|
1078
1057
|
const rcsContent = {
|
|
1079
1058
|
contentType,
|
|
1080
1059
|
cardType,
|
|
1081
1060
|
cardSettings,
|
|
1082
1061
|
cardContent,
|
|
1083
1062
|
};
|
|
1084
|
-
console.log("rcsContent--->", rcsContent);
|
|
1085
1063
|
templateData = {
|
|
1086
1064
|
channel,
|
|
1087
1065
|
creativeName: name,
|
|
@@ -1104,7 +1082,6 @@ export class Creatives extends React.Component {
|
|
|
1104
1082
|
default:
|
|
1105
1083
|
break;
|
|
1106
1084
|
}
|
|
1107
|
-
console.log("templateData--->", templateData);
|
|
1108
1085
|
return templateData;
|
|
1109
1086
|
};
|
|
1110
1087
|
|
|
@@ -298,7 +298,7 @@ export const Rcs = (props) => {
|
|
|
298
298
|
// );
|
|
299
299
|
// }
|
|
300
300
|
if (type === titletype) {
|
|
301
|
-
const
|
|
301
|
+
const errorMsg =
|
|
302
302
|
(unsupportedTagsLengthCheck &&
|
|
303
303
|
formatMessage(globalMessages.unsupportedTagsValidationError, {
|
|
304
304
|
unsupportedTags: validationResponse.unsupportedTags,
|
|
@@ -306,10 +306,10 @@ export const Rcs = (props) => {
|
|
|
306
306
|
(validationResponse.isBraceError &&
|
|
307
307
|
formatMessage(globalMessages.unbalanacedCurlyBraces)) ||
|
|
308
308
|
false;
|
|
309
|
-
|
|
310
|
-
setTemplateTitleError(
|
|
309
|
+
// Only update if changed to prevent flicker
|
|
310
|
+
setTemplateTitleError((prev) => (prev !== errorMsg ? errorMsg : prev));
|
|
311
311
|
} else if (type === descType) {
|
|
312
|
-
const
|
|
312
|
+
const errorMsg =
|
|
313
313
|
(unsupportedTagsLengthCheck &&
|
|
314
314
|
formatMessage(globalMessages.unsupportedTagsValidationError, {
|
|
315
315
|
unsupportedTags: validationResponse.unsupportedTags,
|
|
@@ -317,18 +317,29 @@ export const Rcs = (props) => {
|
|
|
317
317
|
(validationResponse.isBraceError &&
|
|
318
318
|
formatMessage(globalMessages.unbalanacedCurlyBraces)) ||
|
|
319
319
|
false;
|
|
320
|
-
|
|
321
|
-
setTemplateDescError(error);
|
|
320
|
+
setTemplateDescError((prev) => (prev !== errorMsg ? errorMsg : prev));
|
|
322
321
|
}
|
|
323
322
|
};
|
|
324
323
|
|
|
325
324
|
useEffect(() => {
|
|
326
|
-
|
|
327
|
-
|
|
325
|
+
const hasInteraction = !isEmpty(cardVarMapped) || Object.values(rcsTextVariables || {}).some(group => Object.values(group || {}).some(v => (v || '').trim() !== ''));
|
|
326
|
+
if (!hasInteraction) {
|
|
327
|
+
setTemplateTitleError(false);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const mapped = getMappedDesc(templateTitle, cardVarMapped);
|
|
331
|
+
tagValidation(mapped, titletype);
|
|
332
|
+
}, [templateTitle, tags, injectedTags, cardVarMapped, rcsTextVariables]);
|
|
328
333
|
|
|
329
334
|
useEffect(() => {
|
|
330
|
-
|
|
331
|
-
|
|
335
|
+
const hasInteraction = !isEmpty(cardVarMapped) || Object.values(rcsTextVariables || {}).some(group => Object.values(group || {}).some(v => (v || '').trim() !== ''));
|
|
336
|
+
if (!hasInteraction) {
|
|
337
|
+
setTemplateDescError(false);
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const mapped = getMappedDesc(templateDesc, cardVarMapped);
|
|
341
|
+
tagValidation(mapped, descType);
|
|
342
|
+
}, [templateDesc, tags, injectedTags, cardVarMapped, rcsTextVariables]);
|
|
332
343
|
|
|
333
344
|
|
|
334
345
|
const RcsLabel = styled.div`
|
|
@@ -384,6 +395,33 @@ export const Rcs = (props) => {
|
|
|
384
395
|
return updated;
|
|
385
396
|
});
|
|
386
397
|
}, [templateTitle]);
|
|
398
|
+
|
|
399
|
+
// Prefill variable inputs from existing mapping on load/edit
|
|
400
|
+
useEffect(() => {
|
|
401
|
+
if (!templateTitle && !templateDesc) return;
|
|
402
|
+
const buildPrefill = (targetString) => {
|
|
403
|
+
const arr = splitTemplateVarString(targetString);
|
|
404
|
+
const pre = {};
|
|
405
|
+
arr.forEach((elem, idx) => {
|
|
406
|
+
if (rcsVarTestRegex.test(elem)) {
|
|
407
|
+
const varName = elem.replace(/^\{\{|\}\}$/g, '');
|
|
408
|
+
const mapped = cardVarMapped[varName] ?? cardVarMapped[elem];
|
|
409
|
+
if (mapped) {
|
|
410
|
+
pre[idx] = /^\{\{[\s\S]*\}\}$/.test(mapped) ? mapped : `{{${mapped}}}`;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
return pre;
|
|
415
|
+
};
|
|
416
|
+
const prefilledTitle = buildPrefill(templateTitle);
|
|
417
|
+
const prefilledDesc = buildPrefill(templateDesc);
|
|
418
|
+
if (Object.keys(prefilledTitle).length === 0 && Object.keys(prefilledDesc).length === 0) return;
|
|
419
|
+
setRcsTextVariables(prev => ({
|
|
420
|
+
...prev,
|
|
421
|
+
[TITLE_TEXT]: { ...(prev[TITLE_TEXT] || {}), ...prefilledTitle },
|
|
422
|
+
[MESSAGE_TEXT]: { ...(prev[MESSAGE_TEXT] || {}), ...prefilledDesc },
|
|
423
|
+
}));
|
|
424
|
+
}, [templateTitle, templateDesc, cardVarMapped]);
|
|
387
425
|
|
|
388
426
|
useEffect(() => {
|
|
389
427
|
if(!isEditFlow && isFullMode){
|
|
@@ -477,8 +515,13 @@ export const Rcs = (props) => {
|
|
|
477
515
|
}
|
|
478
516
|
setEditFlow(true);
|
|
479
517
|
setTemplateName(details.name || '');
|
|
480
|
-
|
|
481
|
-
|
|
518
|
+
const loadedTitle = get(details, 'versions.base.content.RCS.rcsContent.cardContent[0].title', '');
|
|
519
|
+
const loadedDesc = get(details, 'versions.base.content.RCS.rcsContent.cardContent[0].description', '');
|
|
520
|
+
const loadedMap = get(details, 'versions.base.content.RCS.rcsContent.cardContent[0].cardVarMapped', {});
|
|
521
|
+
const normalizedTitle = (!isFullMode && !isEmpty(loadedMap)) ? getUnmappedDesc(loadedTitle, loadedMap) : loadedTitle;
|
|
522
|
+
const normalizedDesc = (!isFullMode && !isEmpty(loadedMap)) ? getUnmappedDesc(loadedDesc, loadedMap) : loadedDesc;
|
|
523
|
+
setTemplateTitle(normalizedTitle);
|
|
524
|
+
setTemplateDesc(normalizedDesc);
|
|
482
525
|
setSuggestions(get(details, 'versions.base.content.RCS.rcsContent.cardContent[0].suggestions', []));
|
|
483
526
|
templateStatusHelper(details);
|
|
484
527
|
const mediaData = get(details, 'versions.base.content.RCS.rcsContent.cardContent[0].media', '');
|
|
@@ -556,44 +599,99 @@ export const Rcs = (props) => {
|
|
|
556
599
|
};
|
|
557
600
|
|
|
558
601
|
const onTagSelect = (tag) => {
|
|
602
|
+
// Determine target input (index and type). If nothing focused, pick the first available variable slot.
|
|
603
|
+
let targetType = focusedVarType;
|
|
604
|
+
let targetIndex;
|
|
605
|
+
let tokenAtIndex = '';
|
|
559
606
|
if (!focusedVarId) {
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
607
|
+
// Try description first
|
|
608
|
+
const descArray = splitTemplateVarString(templateDesc);
|
|
609
|
+
let found = false;
|
|
610
|
+
for (let i = 0; i < descArray.length; i += 1) {
|
|
611
|
+
const elem = descArray[i];
|
|
612
|
+
if (rcsVarTestRegex.test(elem)) {
|
|
613
|
+
const currentVal = (rcsTextVariables?.[MESSAGE_TEXT]?.[i]) || '';
|
|
614
|
+
if (!currentVal) {
|
|
615
|
+
targetType = MESSAGE_TEXT;
|
|
616
|
+
targetIndex = i;
|
|
617
|
+
tokenAtIndex = elem;
|
|
618
|
+
found = true;
|
|
619
|
+
break;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
// If no empty slot in description, try title
|
|
624
|
+
if (!found) {
|
|
625
|
+
const titleArray = splitTemplateVarString(templateTitle);
|
|
626
|
+
for (let i = 0; i < titleArray.length; i += 1) {
|
|
627
|
+
const elem = titleArray[i];
|
|
628
|
+
if (rcsVarTestRegex.test(elem)) {
|
|
629
|
+
const currentVal = (rcsTextVariables?.[TITLE_TEXT]?.[i]) || '';
|
|
630
|
+
if (!currentVal) {
|
|
631
|
+
targetType = TITLE_TEXT;
|
|
632
|
+
targetIndex = i;
|
|
633
|
+
tokenAtIndex = elem;
|
|
634
|
+
found = true;
|
|
635
|
+
break;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
if (!targetType || targetIndex === undefined) {
|
|
641
|
+
CapNotification.error({
|
|
642
|
+
message: formatMessage(messages.noVariableFocused) || "Please select a variable to insert the label.",
|
|
643
|
+
});
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
} else {
|
|
647
|
+
targetIndex = parseInt(focusedVarId.split('_').pop(), 10);
|
|
648
|
+
const arr = splitTemplateVarString(targetType === TITLE_TEXT ? templateTitle : templateDesc);
|
|
649
|
+
tokenAtIndex = arr[targetIndex] || '';
|
|
564
650
|
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
[index]: `{{${tag}}}`,
|
|
576
|
-
},
|
|
577
|
-
};
|
|
578
|
-
return newState;
|
|
579
|
-
});
|
|
651
|
+
|
|
652
|
+
// Update the visual input field
|
|
653
|
+
setRcsTextVariables((prev) => ({
|
|
654
|
+
...prev,
|
|
655
|
+
[targetType]: {
|
|
656
|
+
...(prev[targetType] || {}),
|
|
657
|
+
[targetIndex]: `{{${tag}}}`,
|
|
658
|
+
},
|
|
659
|
+
}));
|
|
660
|
+
|
|
580
661
|
// Store the variable-to-tag mapping
|
|
581
|
-
setCardVarMapped(prev => {
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
662
|
+
setCardVarMapped((prev) => {
|
|
663
|
+
// Determine stable variable name
|
|
664
|
+
const defaultVarName = (focusedVarId ? focusedVarId.split('_')[0] : tokenAtIndex).replace(/^\{\{|\}\}$/g, '');
|
|
665
|
+
const tokenName = tokenAtIndex.replace(/^\{\{|\}\}$/g, '');
|
|
666
|
+
|
|
667
|
+
// If this template had been saved with resolved tags, infer original key via inverse lookup
|
|
668
|
+
let variableName = defaultVarName;
|
|
669
|
+
if (prev && Object.keys(prev).length > 0) {
|
|
670
|
+
const entry = Object.entries(prev).find(([, v]) => {
|
|
671
|
+
const val = v || '';
|
|
672
|
+
const braced = /^\{\{[\s\S]*\}\}$/.test(val) ? val : `{{${val}}}`;
|
|
673
|
+
return braced === `{{${tokenName}}}`;
|
|
674
|
+
});
|
|
675
|
+
if (entry) {
|
|
676
|
+
const [keyFromMap] = entry;
|
|
677
|
+
variableName = keyFromMap;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
const mappedValue = isFullMode ? tag : `{{${tag}}}`;
|
|
682
|
+
|
|
683
|
+
// Clean up any accidental keys equal to the tag token name (e.g., 'gt') to avoid duplicates
|
|
684
|
+
const cleaned = { ...prev };
|
|
685
|
+
if (tokenName && Object.prototype.hasOwnProperty.call(cleaned, tokenName)) {
|
|
686
|
+
delete cleaned[tokenName];
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
return {
|
|
690
|
+
...cleaned,
|
|
691
|
+
[variableName]: mappedValue,
|
|
593
692
|
};
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
693
|
+
});
|
|
694
|
+
|
|
597
695
|
};
|
|
598
696
|
|
|
599
697
|
const onTagSelectFallback = (data) => {
|
|
@@ -907,15 +1005,32 @@ const splitTemplateVarString = (str) => {
|
|
|
907
1005
|
});
|
|
908
1006
|
|
|
909
1007
|
if (type === TITLE_TEXT) {
|
|
910
|
-
|
|
911
|
-
|
|
1008
|
+
// Only run tag-based validation to avoid flicker from multiple setters
|
|
1009
|
+
tagValidation(reconstructed, titletype);
|
|
912
1010
|
} else {
|
|
913
|
-
|
|
914
|
-
|
|
1011
|
+
// Only run tag-based validation to avoid flicker from multiple setters
|
|
1012
|
+
tagValidation(reconstructed, descType);
|
|
915
1013
|
}
|
|
916
1014
|
|
|
917
1015
|
return updated;
|
|
918
1016
|
});
|
|
1017
|
+
|
|
1018
|
+
// Keep mapping in sync with what user types in the variable input
|
|
1019
|
+
const targetStringForMap = type === TITLE_TEXT ? templateTitle : templateDesc;
|
|
1020
|
+
const arrForMap = splitTemplateVarString(targetStringForMap);
|
|
1021
|
+
const token = arrForMap[index] || '';
|
|
1022
|
+
if (rcsVarTestRegex.test(token)) {
|
|
1023
|
+
const variableName = token.replace(/^\{\{|\}\}$/g, '');
|
|
1024
|
+
const normalized = value
|
|
1025
|
+
? (/^\{\{[\s\S]*\}\}$/.test(value) ? value : `{{${value}}}`)
|
|
1026
|
+
: '';
|
|
1027
|
+
setCardVarMapped(prev => {
|
|
1028
|
+
const next = { ...prev };
|
|
1029
|
+
// Keep the variable key even when empty; store empty string as value
|
|
1030
|
+
next[variableName] = (normalized && normalized.trim() !== '') ? normalized : '';
|
|
1031
|
+
return next;
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
919
1034
|
};
|
|
920
1035
|
|
|
921
1036
|
const setTextAreaId = (e, type) => {
|
|
@@ -1055,6 +1170,11 @@ const splitTemplateVarString = (str) => {
|
|
|
1055
1170
|
/>
|
|
1056
1171
|
)}
|
|
1057
1172
|
</div>
|
|
1173
|
+
{(isEditFlow || !isFullMode) && templateTitleError && (
|
|
1174
|
+
<CapError className="rcs-template-title-error">
|
|
1175
|
+
{templateTitleError}
|
|
1176
|
+
</CapError>
|
|
1177
|
+
)}
|
|
1058
1178
|
</>
|
|
1059
1179
|
)}
|
|
1060
1180
|
|
|
@@ -1138,6 +1258,11 @@ const splitTemplateVarString = (str) => {
|
|
|
1138
1258
|
)
|
|
1139
1259
|
}
|
|
1140
1260
|
</div>
|
|
1261
|
+
{(isEditFlow || !isFullMode) && templateDescError && (
|
|
1262
|
+
<CapError className="rcs-template-message-error">
|
|
1263
|
+
{templateDescError}
|
|
1264
|
+
</CapError>
|
|
1265
|
+
)}
|
|
1141
1266
|
</CapRow>
|
|
1142
1267
|
{renderButtonComponent()}
|
|
1143
1268
|
</>
|
|
@@ -1674,8 +1799,9 @@ const splitTemplateVarString = (str) => {
|
|
|
1674
1799
|
const getRcsPreview = () => {
|
|
1675
1800
|
|
|
1676
1801
|
const dimensionObj = RCS_IMAGE_DIMENSIONS[selectedDimension];
|
|
1677
|
-
|
|
1678
|
-
const
|
|
1802
|
+
// Always show resolved values in preview
|
|
1803
|
+
const mappedDesc = getMappedDesc(templateDesc, cardVarMapped);
|
|
1804
|
+
const mappedTitle = getMappedDesc(templateTitle, cardVarMapped);
|
|
1679
1805
|
return (
|
|
1680
1806
|
<TemplatePreview
|
|
1681
1807
|
channel={RCS}
|
|
@@ -1712,6 +1838,21 @@ const splitTemplateVarString = (str) => {
|
|
|
1712
1838
|
return elem;
|
|
1713
1839
|
}).join('');
|
|
1714
1840
|
};
|
|
1841
|
+
|
|
1842
|
+
const getUnmappedDesc = (str, mapping) => {
|
|
1843
|
+
if (!str) return '';
|
|
1844
|
+
if (!mapping || Object.keys(mapping).length === 0) return str;
|
|
1845
|
+
let result = str;
|
|
1846
|
+
Object.keys(mapping).forEach((key) => {
|
|
1847
|
+
const value = mapping[key];
|
|
1848
|
+
if (!value) return;
|
|
1849
|
+
const bracedValue = /^\{\{[\s\S]*\}\}$/.test(value) ? value : `{{${value}}}`;
|
|
1850
|
+
const escaped = bracedValue.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
1851
|
+
const regex = new RegExp(escaped, 'g');
|
|
1852
|
+
result = result.replace(regex, `{{${key}}}`);
|
|
1853
|
+
});
|
|
1854
|
+
return result;
|
|
1855
|
+
};
|
|
1715
1856
|
|
|
1716
1857
|
const createPayload = () => {
|
|
1717
1858
|
const base = get(dltEditData, `versions.base`, {});
|
|
@@ -1804,7 +1945,6 @@ const splitTemplateVarString = (str) => {
|
|
|
1804
1945
|
|
|
1805
1946
|
|
|
1806
1947
|
const onEditRcs = () => {
|
|
1807
|
-
console.log("onEditRcs");
|
|
1808
1948
|
const payload = createPayload();
|
|
1809
1949
|
const formDataParams = {
|
|
1810
1950
|
value: payload,
|
|
@@ -1843,21 +1983,47 @@ const splitTemplateVarString = (str) => {
|
|
|
1843
1983
|
}
|
|
1844
1984
|
}
|
|
1845
1985
|
|
|
1986
|
+
if(!isFullMode){
|
|
1987
|
+
const titleVars = splitTemplateVarString(templateTitle).filter(elem => rcsVarTestRegex.test(elem)).map(v => v.replace(/^\{\{|\}\}$/g, ''));
|
|
1988
|
+
const descVars = splitTemplateVarString(templateDesc).filter(elem => rcsVarTestRegex.test(elem)).map(v => v.replace(/^\{\{|\}\}$/g, ''));
|
|
1989
|
+
const allVars = Array.from(new Set([ ...titleVars, ...descVars ]));
|
|
1990
|
+
|
|
1991
|
+
if (allVars.length > 0 && isEmpty(cardVarMapped)) {
|
|
1992
|
+
return true;
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
const hasEmptyMapping =
|
|
1996
|
+
cardVarMapped &&
|
|
1997
|
+
Object.keys(cardVarMapped).length > 0 &&
|
|
1998
|
+
Object.entries(cardVarMapped).some(([_, v]) => {
|
|
1999
|
+
if (typeof v !== 'string') return !v; // null/undefined
|
|
2000
|
+
return v.trim() === ''; // empty string
|
|
2001
|
+
});
|
|
2002
|
+
|
|
2003
|
+
if (hasEmptyMapping) {
|
|
2004
|
+
return true;
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
const anyMissing = allVars.some(name => {
|
|
2008
|
+
const v = cardVarMapped?.[name];
|
|
2009
|
+
if (typeof v !== 'string') return !v;
|
|
2010
|
+
return v.trim() === '';
|
|
2011
|
+
});
|
|
2012
|
+
if (anyMissing) {
|
|
2013
|
+
return true;
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
|
|
1846
2017
|
if (isMediaTypeText && templateDesc.trim() === '') {
|
|
1847
|
-
console.log("isMediaTypeText", isMediaTypeText);
|
|
1848
|
-
console.log("templateDesc", templateDesc);
|
|
1849
|
-
console.log("disabled becuase template desc is empty");
|
|
1850
2018
|
return true;
|
|
1851
2019
|
|
|
1852
2020
|
}
|
|
1853
2021
|
if (isMediaTypeImage && (rcsImageSrc === '' || templateTitle === '' || templateDesc === '' )) {
|
|
1854
|
-
console.log("disabled becuase template desc and title are empty");
|
|
1855
2022
|
return true;
|
|
1856
2023
|
}
|
|
1857
2024
|
|
|
1858
2025
|
if (isMediaTypeVideo && (rcsVideoSrc.videoSrc === '' || rcsThumbnailSrc === '' || templateTitle === '' || templateDesc === '' )) {
|
|
1859
|
-
|
|
1860
|
-
return true;
|
|
2026
|
+
return true;
|
|
1861
2027
|
}
|
|
1862
2028
|
if (buttonType.includes(CTA)) {
|
|
1863
2029
|
|
|
@@ -1865,12 +2031,10 @@ const splitTemplateVarString = (str) => {
|
|
|
1865
2031
|
suggestion.text && suggestion.url && !suggestionError
|
|
1866
2032
|
);
|
|
1867
2033
|
if (!hasValidButtons) {
|
|
1868
|
-
console.log("disabled becuase no valid buttons");
|
|
1869
2034
|
return true;
|
|
1870
2035
|
}
|
|
1871
2036
|
}
|
|
1872
|
-
if (templateDescError || fallbackMessageError) {
|
|
1873
|
-
console.log("disabled becuase template desc or fallback message has error");
|
|
2037
|
+
if (templateDescError || templateTitleError || fallbackMessageError) {
|
|
1874
2038
|
return true;
|
|
1875
2039
|
}
|
|
1876
2040
|
return false;
|
|
@@ -1887,17 +2051,43 @@ const splitTemplateVarString = (str) => {
|
|
|
1887
2051
|
return true;
|
|
1888
2052
|
}
|
|
1889
2053
|
}
|
|
2054
|
+
if(!isFullMode){
|
|
2055
|
+
const titleVars = splitTemplateVarString(templateTitle).filter(elem => rcsVarTestRegex.test(elem)).map(v => v.replace(/^\{\{|\}\}$/g, ''));
|
|
2056
|
+
const descVars = splitTemplateVarString(templateDesc).filter(elem => rcsVarTestRegex.test(elem)).map(v => v.replace(/^\{\{|\}\}$/g, ''));
|
|
2057
|
+
const allVars = Array.from(new Set([ ...titleVars, ...descVars ]));
|
|
2058
|
+
|
|
2059
|
+
if (allVars.length > 0 && isEmpty(cardVarMapped)) {
|
|
2060
|
+
return true;
|
|
2061
|
+
}
|
|
1890
2062
|
|
|
2063
|
+
const hasEmptyMapping =
|
|
2064
|
+
cardVarMapped &&
|
|
2065
|
+
Object.keys(cardVarMapped).length > 0 &&
|
|
2066
|
+
Object.entries(cardVarMapped).some(([_, v]) => {
|
|
2067
|
+
if (typeof v !== 'string') return !v; // null/undefined
|
|
2068
|
+
return v.trim() === ''; // empty string
|
|
2069
|
+
});
|
|
2070
|
+
|
|
2071
|
+
if (hasEmptyMapping) {
|
|
2072
|
+
return true;
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2075
|
+
const anyMissing = allVars.some(name => {
|
|
2076
|
+
const v = cardVarMapped?.[name];
|
|
2077
|
+
if (typeof v !== 'string') return !v;
|
|
2078
|
+
return v.trim() === '';
|
|
2079
|
+
});
|
|
2080
|
+
if (anyMissing) {
|
|
2081
|
+
return true;
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
1891
2084
|
if (isMediaTypeText && templateDesc.trim() === '') {
|
|
1892
|
-
console.log('disabled becuase template desc is empty');
|
|
1893
2085
|
return true;
|
|
1894
2086
|
}
|
|
1895
2087
|
if (isMediaTypeImage && rcsImageSrc === '') {
|
|
1896
|
-
console.log('disabled becuase image src is empty');
|
|
1897
2088
|
return true;
|
|
1898
2089
|
}
|
|
1899
2090
|
if(isMediaTypeVideo && (rcsThumbnailSrc === '' || rcsVideoSrc.videoSrc === '')) {
|
|
1900
|
-
console.log('disabled becuase thumbnail src or video src is empty');
|
|
1901
2091
|
return true;
|
|
1902
2092
|
}
|
|
1903
2093
|
|
|
@@ -1906,10 +2096,12 @@ const splitTemplateVarString = (str) => {
|
|
|
1906
2096
|
suggestion.text && suggestion.url && !suggestionError
|
|
1907
2097
|
);
|
|
1908
2098
|
if (!hasValidButtons) {
|
|
1909
|
-
console.log('disabled becuase no valid buttons');
|
|
1910
2099
|
return true;
|
|
1911
2100
|
}
|
|
1912
2101
|
}
|
|
2102
|
+
if (templateTitleError || templateDescError || fallbackMessageError) {
|
|
2103
|
+
return true;
|
|
2104
|
+
}
|
|
1913
2105
|
return false;
|
|
1914
2106
|
};
|
|
1915
2107
|
|