@capillarytech/creatives-library 9.0.33 → 9.0.34-alpha.2
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/CommonTestAndPreview/UnifiedPreview/ViberCarouselPreviewCards.js +132 -0
- package/v2Components/CommonTestAndPreview/UnifiedPreview/ViberPreviewContent.js +108 -15
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +139 -1
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_viberCarouselPreviewCards.scss +131 -0
- package/v2Components/CommonTestAndPreview/index.js +240 -26
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/ViberPreviewContent.test.js +364 -0
- package/v2Containers/Templates/_templates.scss +114 -0
- package/v2Containers/Templates/index.js +90 -10
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +5 -0
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +0 -1
- package/v2Containers/TemplatesV2/index.js +1 -9
- package/v2Containers/Viber/constants.js +21 -0
- package/v2Containers/Viber/index.js +719 -49
- package/v2Containers/Viber/index.scss +175 -0
- package/v2Containers/Viber/messages.js +121 -0
- package/v2Containers/Viber/tests/index.test.js +80 -0
|
@@ -244,6 +244,8 @@ const CommonTestAndPreview = (props) => {
|
|
|
244
244
|
const [smsFallbackPreviewText, setSmsFallbackPreviewText] = useState(undefined);
|
|
245
245
|
// Track if a preview call has been made (to know when to use previewDataHtml vs raw content)
|
|
246
246
|
const [hasPreviewCallBeenMade, setHasPreviewCallBeenMade] = useState(false);
|
|
247
|
+
// Viber: tag values applied to preview only after explicit Update preview / Discard (not while typing)
|
|
248
|
+
const [viberPreviewTagValues, setViberPreviewTagValues] = useState(null);
|
|
247
249
|
const [previewDataHtml, setPreviewDataHtml] = useState(() => {
|
|
248
250
|
// Initialize preview data based on channel
|
|
249
251
|
if (channel === CHANNELS.EMAIL && formData) {
|
|
@@ -681,6 +683,159 @@ const CommonTestAndPreview = (props) => {
|
|
|
681
683
|
return resolvedText;
|
|
682
684
|
};
|
|
683
685
|
|
|
686
|
+
const getViberMergedFormData = useCallback((formDataOverride) => {
|
|
687
|
+
const formDataObj = formDataOverride && typeof formDataOverride === 'object'
|
|
688
|
+
? formDataOverride
|
|
689
|
+
: (formData && typeof formData === 'object' ? formData : {});
|
|
690
|
+
let contentObj = {};
|
|
691
|
+
if (content && typeof content === 'object') {
|
|
692
|
+
contentObj = content;
|
|
693
|
+
} else if (typeof content === 'string' && content.trim()) {
|
|
694
|
+
try {
|
|
695
|
+
contentObj = JSON.parse(content);
|
|
696
|
+
} catch (e) {
|
|
697
|
+
contentObj = {};
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
const previewCards = formDataObj.viberPreviewContent?.cards
|
|
701
|
+
?? formDataObj.cards
|
|
702
|
+
?? contentObj.viberPreviewContent?.cards
|
|
703
|
+
?? contentObj.cards;
|
|
704
|
+
const isCarousel = Boolean(
|
|
705
|
+
formDataObj.type === MEDIA_TYPE_CAROUSEL
|
|
706
|
+
|| contentObj.type === MEDIA_TYPE_CAROUSEL
|
|
707
|
+
|| (Array.isArray(previewCards) && previewCards.length > 0),
|
|
708
|
+
);
|
|
709
|
+
const mergedPreview = {
|
|
710
|
+
...(contentObj.viberPreviewContent || {}),
|
|
711
|
+
...(formDataObj.viberPreviewContent || {}),
|
|
712
|
+
...(Array.isArray(previewCards) && previewCards.length ? { cards: previewCards } : {}),
|
|
713
|
+
...(isCarousel ? {
|
|
714
|
+
type: MEDIA_TYPE_CAROUSEL,
|
|
715
|
+
showCarouselEditorPreview: true,
|
|
716
|
+
} : {}),
|
|
717
|
+
};
|
|
718
|
+
return {
|
|
719
|
+
...contentObj,
|
|
720
|
+
...formDataObj,
|
|
721
|
+
...(Array.isArray(previewCards) && previewCards.length ? { cards: previewCards } : {}),
|
|
722
|
+
...(isCarousel ? { type: MEDIA_TYPE_CAROUSEL } : {}),
|
|
723
|
+
...(Object.keys(mergedPreview).length ? { viberPreviewContent: mergedPreview } : {}),
|
|
724
|
+
};
|
|
725
|
+
}, [formData, content]);
|
|
726
|
+
|
|
727
|
+
const getViberCarouselCardsFromFormData = (formDataObj) => {
|
|
728
|
+
const previewCards = formDataObj?.viberPreviewContent?.cards;
|
|
729
|
+
if (Array.isArray(previewCards) && previewCards.length) {
|
|
730
|
+
return previewCards;
|
|
731
|
+
}
|
|
732
|
+
const rootCards = formDataObj?.cards;
|
|
733
|
+
if (Array.isArray(rootCards) && rootCards.length) {
|
|
734
|
+
return rootCards;
|
|
735
|
+
}
|
|
736
|
+
return [];
|
|
737
|
+
};
|
|
738
|
+
|
|
739
|
+
const getViberTagExtractionContent = (formDataObj, contentStr = '') => {
|
|
740
|
+
const messageText = formDataObj?.messageContent
|
|
741
|
+
|| formDataObj?.viberPreviewContent?.messageContent
|
|
742
|
+
|| contentStr
|
|
743
|
+
|| '';
|
|
744
|
+
const cardFieldTexts = getViberCarouselCardsFromFormData(formDataObj).flatMap((card) => {
|
|
745
|
+
const fields = [card?.text || ''];
|
|
746
|
+
(card?.buttons || []).forEach((button) => {
|
|
747
|
+
fields.push(button?.title || '', button?.action || '');
|
|
748
|
+
});
|
|
749
|
+
return fields;
|
|
750
|
+
});
|
|
751
|
+
return [messageText, ...cardFieldTexts]
|
|
752
|
+
.filter((value) => typeof value === 'string' && value.trim())
|
|
753
|
+
.join(' ');
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
const resolveViberCarouselCards = (cards, tagValues) => {
|
|
757
|
+
if (!Array.isArray(cards) || !tagValues || !Object.keys(tagValues).length) {
|
|
758
|
+
return cards;
|
|
759
|
+
}
|
|
760
|
+
return cards.map((card) => ({
|
|
761
|
+
...card,
|
|
762
|
+
text: resolveTagsInText(card?.text || '', tagValues),
|
|
763
|
+
buttons: (card?.buttons || []).map((button) => ({
|
|
764
|
+
...button,
|
|
765
|
+
title: resolveTagsInText(button?.title || '', tagValues),
|
|
766
|
+
action: resolveTagsInText(button?.action || '', tagValues),
|
|
767
|
+
})),
|
|
768
|
+
}));
|
|
769
|
+
};
|
|
770
|
+
|
|
771
|
+
const applyViberCustomValuesToContent = (contentObj, tagValues) => {
|
|
772
|
+
if (!contentObj || typeof contentObj !== 'object' || !tagValues || !Object.keys(tagValues).length) {
|
|
773
|
+
return contentObj;
|
|
774
|
+
}
|
|
775
|
+
const result = { ...contentObj };
|
|
776
|
+
if (typeof result.messageContent === 'string') {
|
|
777
|
+
result.messageContent = resolveTagsInText(result.messageContent, tagValues);
|
|
778
|
+
}
|
|
779
|
+
if (Array.isArray(result.cards)) {
|
|
780
|
+
result.cards = resolveViberCarouselCards(result.cards, tagValues);
|
|
781
|
+
}
|
|
782
|
+
if (result.viberPreviewContent && typeof result.viberPreviewContent === 'object') {
|
|
783
|
+
const preview = result.viberPreviewContent;
|
|
784
|
+
result.viberPreviewContent = {
|
|
785
|
+
...preview,
|
|
786
|
+
messageContent: resolveTagsInText(preview.messageContent || '', tagValues),
|
|
787
|
+
cards: resolveViberCarouselCards(preview.cards, tagValues),
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
return result;
|
|
791
|
+
};
|
|
792
|
+
|
|
793
|
+
const mergeViberPreviewWithResolved = (base, resolved) => {
|
|
794
|
+
if (!resolved || typeof resolved !== 'object') {
|
|
795
|
+
return base && typeof base === 'object' ? base : {};
|
|
796
|
+
}
|
|
797
|
+
const baseObj = base && typeof base === 'object' ? base : {};
|
|
798
|
+
const basePreview = baseObj.viberPreviewContent || {};
|
|
799
|
+
const resolvedPreview = resolved.viberPreviewContent || {};
|
|
800
|
+
const baseCards = basePreview.cards || baseObj.cards || [];
|
|
801
|
+
const resolvedCards = resolvedPreview.cards || resolved.cards || [];
|
|
802
|
+
const mergedCards = baseCards.length
|
|
803
|
+
? baseCards.map((card, index) => {
|
|
804
|
+
const resolvedCard = resolvedCards[index];
|
|
805
|
+
if (!resolvedCard) {
|
|
806
|
+
return card;
|
|
807
|
+
}
|
|
808
|
+
return {
|
|
809
|
+
...card,
|
|
810
|
+
...(resolvedCard.text != null ? { text: resolvedCard.text } : {}),
|
|
811
|
+
...(resolvedCard.mediaUrl != null ? { mediaUrl: resolvedCard.mediaUrl } : {}),
|
|
812
|
+
buttons: (card.buttons || []).map((button, buttonIndex) => ({
|
|
813
|
+
...button,
|
|
814
|
+
...(resolvedCard.buttons?.[buttonIndex] || {}),
|
|
815
|
+
})),
|
|
816
|
+
};
|
|
817
|
+
})
|
|
818
|
+
: resolvedCards;
|
|
819
|
+
const resolvedMessage = resolved.messageContent ?? resolvedPreview.messageContent;
|
|
820
|
+
|
|
821
|
+
return {
|
|
822
|
+
...baseObj,
|
|
823
|
+
...resolved,
|
|
824
|
+
viberPreviewContent: {
|
|
825
|
+
...basePreview,
|
|
826
|
+
...resolvedPreview,
|
|
827
|
+
type: resolvedPreview.type || basePreview.type || baseObj.type || (mergedCards.length ? MEDIA_TYPE_CAROUSEL : ''),
|
|
828
|
+
cards: mergedCards.length ? mergedCards : (resolvedPreview.cards || basePreview.cards),
|
|
829
|
+
showCarouselEditorPreview: Boolean(
|
|
830
|
+
basePreview.showCarouselEditorPreview
|
|
831
|
+
|| resolvedPreview.showCarouselEditorPreview
|
|
832
|
+
|| mergedCards.length > 0,
|
|
833
|
+
),
|
|
834
|
+
...(resolvedMessage != null ? { messageContent: resolvedMessage } : {}),
|
|
835
|
+
},
|
|
836
|
+
};
|
|
837
|
+
};
|
|
838
|
+
|
|
684
839
|
/**
|
|
685
840
|
* Common handler for saving test customers (both new and existing)
|
|
686
841
|
*/
|
|
@@ -959,11 +1114,13 @@ const CommonTestAndPreview = (props) => {
|
|
|
959
1114
|
templateContent: formDataObj?.bodyText || contentStr,
|
|
960
1115
|
};
|
|
961
1116
|
|
|
962
|
-
case CHANNELS.VIBER:
|
|
1117
|
+
case CHANNELS.VIBER: {
|
|
1118
|
+
const viberFormData = getViberMergedFormData(formDataObj);
|
|
963
1119
|
return {
|
|
964
|
-
templateSubject:
|
|
965
|
-
templateContent: contentStr,
|
|
1120
|
+
templateSubject: viberFormData?.messageTitle || '',
|
|
1121
|
+
templateContent: getViberTagExtractionContent(viberFormData, contentStr),
|
|
966
1122
|
};
|
|
1123
|
+
}
|
|
967
1124
|
|
|
968
1125
|
case CHANNELS.WEBPUSH:
|
|
969
1126
|
return {
|
|
@@ -2017,11 +2174,16 @@ const CommonTestAndPreview = (props) => {
|
|
|
2017
2174
|
// 1. formDataObj from getTemplateContent (contains both viberPreviewContent and payload fields)
|
|
2018
2175
|
// 2. formDataObj[0] (array format - legacy)
|
|
2019
2176
|
// 3. contentStr (direct string - legacy)
|
|
2177
|
+
// Merge content prop so listing / preview-only flows include carousel card tags
|
|
2178
|
+
const viberFormData = getViberMergedFormData(formDataObj);
|
|
2179
|
+
formDataObj = viberFormData;
|
|
2020
2180
|
|
|
2021
2181
|
let messageText = '';
|
|
2022
2182
|
let imageData = null;
|
|
2023
2183
|
let videoData = null;
|
|
2024
2184
|
let buttonData = null;
|
|
2185
|
+
let cardsData = [];
|
|
2186
|
+
let messageType = '';
|
|
2025
2187
|
let accountId = null;
|
|
2026
2188
|
let accountDetails = null;
|
|
2027
2189
|
let scenarioKey = '';
|
|
@@ -2036,6 +2198,8 @@ const CommonTestAndPreview = (props) => {
|
|
|
2036
2198
|
imageData = formDataObj.image || null;
|
|
2037
2199
|
videoData = formDataObj.video || null;
|
|
2038
2200
|
buttonData = formDataObj.button || null;
|
|
2201
|
+
cardsData = formDataObj.cards || [];
|
|
2202
|
+
messageType = formDataObj.type || '';
|
|
2039
2203
|
accountId = formDataObj.accountId || null;
|
|
2040
2204
|
accountDetails = formDataObj.accountDetails || null;
|
|
2041
2205
|
scenarioKey = formDataObj.scenarioKey || VIBER_API_SCENARIO_KEY;
|
|
@@ -2062,6 +2226,8 @@ const CommonTestAndPreview = (props) => {
|
|
|
2062
2226
|
url: formDataObj?.buttonURL || '',
|
|
2063
2227
|
};
|
|
2064
2228
|
}
|
|
2229
|
+
cardsData = viberPreview.cards || formDataObj?.cards || [];
|
|
2230
|
+
messageType = viberPreview.type || formDataObj?.type || '';
|
|
2065
2231
|
// Extract account info from parent formDataObj if available
|
|
2066
2232
|
accountId = formDataObj.accountId || null;
|
|
2067
2233
|
accountDetails = formDataObj.accountDetails || null;
|
|
@@ -2104,6 +2270,10 @@ const CommonTestAndPreview = (props) => {
|
|
|
2104
2270
|
text: messageText,
|
|
2105
2271
|
};
|
|
2106
2272
|
|
|
2273
|
+
if (messageType === CHANNELS.VIBER) {
|
|
2274
|
+
messageType = '';
|
|
2275
|
+
}
|
|
2276
|
+
|
|
2107
2277
|
// Add image if present
|
|
2108
2278
|
if (imageData && imageData.url) {
|
|
2109
2279
|
viberContent.image = {
|
|
@@ -2132,9 +2302,34 @@ const CommonTestAndPreview = (props) => {
|
|
|
2132
2302
|
}
|
|
2133
2303
|
}
|
|
2134
2304
|
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
viberContent.
|
|
2305
|
+
if (messageType === MEDIA_TYPE_CAROUSEL || (Array.isArray(cardsData) && cardsData.length)) {
|
|
2306
|
+
viberContent.type = MEDIA_TYPE_CAROUSEL;
|
|
2307
|
+
viberContent.cards = (cardsData || []).map((card) => ({
|
|
2308
|
+
text: card?.text || '',
|
|
2309
|
+
mediaUrl: card?.mediaUrl || '',
|
|
2310
|
+
buttons: (card?.buttons || []).map((button) => ({
|
|
2311
|
+
title: button?.title || '',
|
|
2312
|
+
action: button?.action || '',
|
|
2313
|
+
})),
|
|
2314
|
+
}));
|
|
2315
|
+
delete viberContent.button;
|
|
2316
|
+
}
|
|
2317
|
+
|
|
2318
|
+
// Resolve tags in text/cards if custom values are provided
|
|
2319
|
+
if (customValuesObj && Object.keys(customValuesObj).length > 0) {
|
|
2320
|
+
if (viberContent.text) {
|
|
2321
|
+
viberContent.text = resolveTagsInText(viberContent.text, customValuesObj);
|
|
2322
|
+
}
|
|
2323
|
+
if (Array.isArray(viberContent.cards)) {
|
|
2324
|
+
viberContent.cards = resolveViberCarouselCards(viberContent.cards, customValuesObj);
|
|
2325
|
+
}
|
|
2326
|
+
if (viberContent.button) {
|
|
2327
|
+
viberContent.button = {
|
|
2328
|
+
...viberContent.button,
|
|
2329
|
+
text: resolveTagsInText(viberContent.button.text || '', customValuesObj),
|
|
2330
|
+
url: resolveTagsInText(viberContent.button.url || '', customValuesObj),
|
|
2331
|
+
};
|
|
2332
|
+
}
|
|
2138
2333
|
}
|
|
2139
2334
|
|
|
2140
2335
|
// Build messageBody JSON string
|
|
@@ -2526,33 +2721,39 @@ const CommonTestAndPreview = (props) => {
|
|
|
2526
2721
|
// Only use previewDataHtml if preview call was made
|
|
2527
2722
|
if (hasPreviewCallBeenMade && previewDataHtml?.resolvedBody) {
|
|
2528
2723
|
resolvedContent = previewDataHtml.resolvedBody;
|
|
2724
|
+
if (typeof resolvedContent === 'string') {
|
|
2725
|
+
try {
|
|
2726
|
+
resolvedContent = JSON.parse(resolvedContent);
|
|
2727
|
+
} catch (e) {
|
|
2728
|
+
resolvedContent = null;
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2529
2731
|
}
|
|
2530
2732
|
|
|
2531
|
-
// Parse content if it's a string
|
|
2532
|
-
let parsedViberContent =
|
|
2533
|
-
if (typeof
|
|
2534
|
-
|
|
2535
|
-
parsedViberContent = JSON.parse(content);
|
|
2536
|
-
} catch (e) {
|
|
2537
|
-
parsedViberContent = {};
|
|
2538
|
-
}
|
|
2733
|
+
// Parse content if it's a string, then merge with formData for carousel + tags in all entry flows
|
|
2734
|
+
let parsedViberContent = getViberMergedFormData();
|
|
2735
|
+
if (!parsedViberContent || typeof parsedViberContent !== 'object') {
|
|
2736
|
+
parsedViberContent = {};
|
|
2539
2737
|
}
|
|
2540
|
-
//
|
|
2738
|
+
// Merge template preview state with API resolved body so carousel type/cards survive slim responses
|
|
2541
2739
|
if (resolvedContent && typeof resolvedContent === 'object') {
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
if (
|
|
2545
|
-
contentObj.accountName =
|
|
2740
|
+
const base = parsedViberContent && typeof parsedViberContent === 'object' ? parsedViberContent : {};
|
|
2741
|
+
contentObj = mergeViberPreviewWithResolved(base, resolvedContent);
|
|
2742
|
+
if (base.accountName && !contentObj.accountName) {
|
|
2743
|
+
contentObj.accountName = base.accountName;
|
|
2546
2744
|
}
|
|
2547
|
-
if (
|
|
2548
|
-
contentObj.brandName =
|
|
2745
|
+
if (base.brandName && !contentObj.brandName) {
|
|
2746
|
+
contentObj.brandName = base.brandName;
|
|
2549
2747
|
}
|
|
2550
2748
|
} else {
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2749
|
+
contentObj = parsedViberContent && typeof parsedViberContent === 'object' ? parsedViberContent : {};
|
|
2750
|
+
}
|
|
2751
|
+
if (
|
|
2752
|
+
hasPreviewCallBeenMade
|
|
2753
|
+
&& viberPreviewTagValues
|
|
2754
|
+
&& Object.keys(viberPreviewTagValues).length > 0
|
|
2755
|
+
) {
|
|
2756
|
+
contentObj = applyViberCustomValuesToContent(contentObj, viberPreviewTagValues);
|
|
2556
2757
|
}
|
|
2557
2758
|
} else if (channel === CHANNELS.ZALO) {
|
|
2558
2759
|
// For Zalo, content is an object with templatePreviewUrl, templateStatus, etc.
|
|
@@ -2936,6 +3137,11 @@ const CommonTestAndPreview = (props) => {
|
|
|
2936
3137
|
|
|
2937
3138
|
setCustomValues(updatedValues);
|
|
2938
3139
|
|
|
3140
|
+
// Viber: do not auto-resolve tags in preview; user must click Update preview
|
|
3141
|
+
if (channel === CHANNELS.VIBER) {
|
|
3142
|
+
return;
|
|
3143
|
+
}
|
|
3144
|
+
|
|
2939
3145
|
// Update preview with prefilled values (this is a valid preview call trigger)
|
|
2940
3146
|
// For RCS: always dispatch with RCS channel/content so previewDataHtml stays RCS-shaped.
|
|
2941
3147
|
// SMS fallback preview is kept in sync by syncSmsFallbackPreview via smsFallbackPreviewText.
|
|
@@ -3018,6 +3224,7 @@ const CommonTestAndPreview = (props) => {
|
|
|
3018
3224
|
setPreviewDevice(DESKTOP);
|
|
3019
3225
|
setPreviewDataHtml('');
|
|
3020
3226
|
setHasPreviewCallBeenMade(false); // Reset preview call flag
|
|
3227
|
+
setViberPreviewTagValues(null);
|
|
3021
3228
|
setSelectedTestEntities([]);
|
|
3022
3229
|
setBeeContent('');
|
|
3023
3230
|
previousBeeContentRef.current = '';
|
|
@@ -3055,6 +3262,7 @@ const CommonTestAndPreview = (props) => {
|
|
|
3055
3262
|
const handleClearSelection = () => {
|
|
3056
3263
|
setSelectedCustomer(null);
|
|
3057
3264
|
setHasPreviewCallBeenMade(false); // Reset flag when customer is cleared
|
|
3265
|
+
setViberPreviewTagValues(null);
|
|
3058
3266
|
|
|
3059
3267
|
// Clear all preview errors when customer is cleared
|
|
3060
3268
|
actions.clearPreviewErrors();
|
|
@@ -3113,6 +3321,9 @@ const CommonTestAndPreview = (props) => {
|
|
|
3113
3321
|
emptyValues,
|
|
3114
3322
|
selectedCustomer
|
|
3115
3323
|
);
|
|
3324
|
+
if (channel === CHANNELS.VIBER) {
|
|
3325
|
+
setViberPreviewTagValues({ ...emptyValues });
|
|
3326
|
+
}
|
|
3116
3327
|
actions.updatePreviewRequested(payload);
|
|
3117
3328
|
setHasPreviewCallBeenMade(true); // Mark that preview call was made
|
|
3118
3329
|
};
|
|
@@ -3138,6 +3349,9 @@ const CommonTestAndPreview = (props) => {
|
|
|
3138
3349
|
customValues,
|
|
3139
3350
|
selectedCustomer
|
|
3140
3351
|
);
|
|
3352
|
+
if (channel === CHANNELS.VIBER) {
|
|
3353
|
+
setViberPreviewTagValues({ ...customValues });
|
|
3354
|
+
}
|
|
3141
3355
|
await actions.updatePreviewRequested(payload);
|
|
3142
3356
|
|
|
3143
3357
|
await syncSmsFallbackPreview(customValues, selectedCustomer);
|