@capillarytech/creatives-library 9.0.36-alpha.0 → 9.0.36

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.
Files changed (61) hide show
  1. package/app.js +175 -10
  2. package/entry.js +1 -67
  3. package/mfe-exposed-components.js +4 -2
  4. package/package.json +2 -2
  5. package/services/api.js +1 -9
  6. package/styles/containers/layout/_layoutPage.scss +6 -8
  7. package/utils/gtmTrackers/gtmEvents/creativeDetails.js +1 -2
  8. package/utils/rcsPayloadUtils.js +2 -5
  9. package/utils/tests/rcsPayloadUtils.test.js +2 -54
  10. package/v2Components/CapActionButton/constants.js +0 -1
  11. package/v2Components/CapActionButton/index.js +9 -77
  12. package/v2Components/CapActionButton/index.scss +0 -13
  13. package/v2Components/CapActionButton/messages.js +0 -13
  14. package/v2Components/CapActionButton/tests/index.test.js +1 -32
  15. package/v2Components/CommonTestAndPreview/UnifiedPreview/ViberPreviewContent.js +15 -108
  16. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +1 -139
  17. package/v2Components/CommonTestAndPreview/index.js +41 -284
  18. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/ViberPreviewContent.test.js +0 -364
  19. package/v2Components/CommonTestAndPreview/tests/index.test.js +0 -78
  20. package/v2Components/CommonTestAndPreview/utils.js +0 -34
  21. package/v2Components/NavigationBar/index.js +7 -9
  22. package/v2Components/NavigationBar/tests/index.test.js +19 -39
  23. package/v2Components/SmsFallback/index.js +0 -6
  24. package/v2Containers/Cap/constants.js +0 -1
  25. package/v2Containers/Cap/index.js +27 -57
  26. package/v2Containers/CreativesContainer/index.js +8 -11
  27. package/v2Containers/CreativesContainer/tests/index.test.js +0 -53
  28. package/v2Containers/Rcs/carouselUtils.js +73 -46
  29. package/v2Containers/Rcs/components/CarouselCard.js +9 -11
  30. package/v2Containers/Rcs/components/CarouselCardButtons.js +0 -20
  31. package/v2Containers/Rcs/constants.js +7 -2
  32. package/v2Containers/Rcs/index.js +205 -226
  33. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +47 -60
  34. package/v2Containers/Rcs/tests/CarouselCard.test.js +2 -1
  35. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +0 -286
  36. package/v2Containers/Rcs/tests/carouselUtils.test.js +32 -28
  37. package/v2Containers/Rcs/tests/index.test.js +238 -151
  38. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -110
  39. package/v2Containers/Rcs/tests/utils.test.js +17 -36
  40. package/v2Containers/Rcs/utils.js +55 -28
  41. package/v2Containers/SmsTrai/Edit/index.js +24 -35
  42. package/v2Containers/Templates/_templates.scss +1 -115
  43. package/v2Containers/Templates/index.js +10 -91
  44. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +0 -5
  45. package/v2Containers/TemplatesV2/TemplatesV2.style.js +3 -8
  46. package/v2Containers/TemplatesV2/index.js +9 -22
  47. package/v2Containers/Viber/constants.js +0 -21
  48. package/v2Containers/Viber/index.js +49 -719
  49. package/v2Containers/Viber/index.scss +0 -175
  50. package/v2Containers/Viber/messages.js +0 -121
  51. package/v2Containers/Viber/tests/index.test.js +0 -80
  52. package/AppRoot.js +0 -124
  53. package/app-config.js +0 -61
  54. package/bootstrap.js +0 -185
  55. package/utils/getDataLayer.js +0 -15
  56. package/utils/mfeDetect.js +0 -1
  57. package/utils/mfeFirstPaintReady.js +0 -29
  58. package/utils/mfeHistory.js +0 -62
  59. package/v2Components/CommonTestAndPreview/UnifiedPreview/ViberCarouselPreviewCards.js +0 -132
  60. package/v2Components/CommonTestAndPreview/UnifiedPreview/_viberCarouselPreviewCards.scss +0 -131
  61. package/v2Components/NavigationBar/mfeModuleHeader.config.js +0 -16
@@ -37,8 +37,6 @@ import {
37
37
  buildSyntheticSmsMustacheTags,
38
38
  normalizeRcsTestCardMedia,
39
39
  mapRcsSuggestionForTestMeta,
40
- getRcsPrimaryTagExtractionText,
41
- mergeSyntheticMustacheTags,
42
40
  } from './utils';
43
41
  import AddTestCustomerButton from './AddTestCustomer';
44
42
  import ExistingCustomerModal from './ExistingCustomerModal';
@@ -246,8 +244,6 @@ const CommonTestAndPreview = (props) => {
246
244
  const [smsFallbackPreviewText, setSmsFallbackPreviewText] = useState(undefined);
247
245
  // Track if a preview call has been made (to know when to use previewDataHtml vs raw content)
248
246
  const [hasPreviewCallBeenMade, setHasPreviewCallBeenMade] = useState(false);
249
- // Viber: tag values applied to preview only after explicit Update preview / Discard (not while typing)
250
- const [viberPreviewTagValues, setViberPreviewTagValues] = useState(null);
251
247
  const [previewDataHtml, setPreviewDataHtml] = useState(() => {
252
248
  // Initialize preview data based on channel
253
249
  if (channel === CHANNELS.EMAIL && formData) {
@@ -578,7 +574,7 @@ const CommonTestAndPreview = (props) => {
578
574
  }
579
575
  const hasFallbackSmsBody = !!(smsFallbackContent?.templateContent || smsFallbackContent?.content);
580
576
  if (channel === CHANNELS.RCS && hasFallbackSmsBody) {
581
- const rcsPrimaryTags = mergeSyntheticMustacheTags(extractedTags, getRcsPrimaryTagExtractionText(formData));
577
+ const rcsPrimaryTags = extractedTags ?? [];
582
578
  const fallbackSmsTextForTags = smsFallbackTextForTagExtraction ?? '';
583
579
  const fallbackSmsTagRows = smsTemplateHasMustacheTags(fallbackSmsTextForTags)
584
580
  ? (smsFallbackExtractedTags?.length > 0
@@ -589,15 +585,11 @@ const CommonTestAndPreview = (props) => {
589
585
  if (mergedRcsAndFallbackTags.length > 0) return mergedRcsAndFallbackTags;
590
586
  return buildSyntheticSmsMustacheTags(fallbackSmsTextForTags);
591
587
  }
592
- if (channel === CHANNELS.RCS) {
593
- return mergeSyntheticMustacheTags(extractedTags, getRcsPrimaryTagExtractionText(formData));
594
- }
595
588
  return extractedTags ?? [];
596
589
  }, [
597
590
  channel,
598
591
  extractedTags,
599
592
  getCurrentContent,
600
- formData,
601
593
  smsFallbackContent,
602
594
  smsFallbackExtractedTags,
603
595
  smsFallbackTextForTagExtraction,
@@ -673,175 +665,15 @@ const CommonTestAndPreview = (props) => {
673
665
  let resolvedText = text;
674
666
 
675
667
  // Replace each tag with its custom value
676
- Object.keys(tagValues || {}).forEach((tagPath) => {
668
+ Object.keys(tagValues).forEach((tagPath) => {
677
669
  const tagName = tagPath.split('.').pop(); // Get the actual tag name from the path
678
- // Escape regex metacharacters in tagName (arbitrary JSON key) so it can't break the pattern.
679
- const escapedTagName = tagName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
680
- const tagRegex = new RegExp(`{{${escapedTagName}}}`, 'g');
681
- const rawValue = tagValues[tagPath];
682
- // Preserve legitimate falsy values (0, false); only an unset/blank slot keeps the placeholder.
683
- const hasValue = rawValue !== null && rawValue !== undefined && rawValue !== '';
684
- const replacement = hasValue ? String(rawValue) : `{{${tagName}}}`;
685
- // Replacer function (not a string) so `$&`/`$1`-style sequences in the value are inserted literally.
686
- resolvedText = resolvedText.replace(tagRegex, () => replacement);
670
+ const tagRegex = new RegExp(`{{${tagName}}}`, 'g');
671
+ resolvedText = resolvedText.replace(tagRegex, tagValues[tagPath] || `{{${tagName}}}`);
687
672
  });
688
673
 
689
674
  return resolvedText;
690
675
  };
691
676
 
692
- const getViberMergedFormData = useCallback((formDataOverride) => {
693
- const formDataObj = formDataOverride && typeof formDataOverride === 'object'
694
- ? formDataOverride
695
- : (formData && typeof formData === 'object' ? formData : {});
696
- let contentObj = {};
697
- if (content && typeof content === 'object') {
698
- contentObj = content;
699
- } else if (typeof content === 'string' && content.trim()) {
700
- try {
701
- contentObj = JSON.parse(content);
702
- } catch (e) {
703
- contentObj = {};
704
- }
705
- }
706
- const previewCards = formDataObj.viberPreviewContent?.cards
707
- ?? formDataObj.cards
708
- ?? contentObj.viberPreviewContent?.cards
709
- ?? contentObj.cards;
710
- const isCarousel = Boolean(
711
- formDataObj.type === MEDIA_TYPE_CAROUSEL
712
- || contentObj.type === MEDIA_TYPE_CAROUSEL
713
- || (Array.isArray(previewCards) && previewCards.length > 0),
714
- );
715
- const mergedPreview = {
716
- ...(contentObj.viberPreviewContent || {}),
717
- ...(formDataObj.viberPreviewContent || {}),
718
- ...(Array.isArray(previewCards) && previewCards.length ? { cards: previewCards } : {}),
719
- ...(isCarousel ? {
720
- type: MEDIA_TYPE_CAROUSEL,
721
- showCarouselEditorPreview: true,
722
- } : {}),
723
- };
724
- return {
725
- ...contentObj,
726
- ...formDataObj,
727
- ...(Array.isArray(previewCards) && previewCards.length ? { cards: previewCards } : {}),
728
- ...(isCarousel ? { type: MEDIA_TYPE_CAROUSEL } : {}),
729
- ...(Object.keys(mergedPreview).length ? { viberPreviewContent: mergedPreview } : {}),
730
- };
731
- }, [formData, content]);
732
-
733
- const getViberCarouselCardsFromFormData = (formDataObj) => {
734
- const previewCards = formDataObj?.viberPreviewContent?.cards;
735
- if (Array.isArray(previewCards) && previewCards.length) {
736
- return previewCards;
737
- }
738
- const rootCards = formDataObj?.cards;
739
- if (Array.isArray(rootCards) && rootCards.length) {
740
- return rootCards;
741
- }
742
- return [];
743
- };
744
-
745
- const getViberTagExtractionContent = (formDataObj, contentStr = '') => {
746
- const messageText = formDataObj?.messageContent
747
- || formDataObj?.viberPreviewContent?.messageContent
748
- || contentStr
749
- || '';
750
- const cardFieldTexts = getViberCarouselCardsFromFormData(formDataObj).flatMap((card) => {
751
- const fields = [card?.text || ''];
752
- (card?.buttons || []).forEach((button) => {
753
- fields.push(button?.title || '', button?.action || '');
754
- });
755
- return fields;
756
- });
757
- return [messageText, ...cardFieldTexts]
758
- .filter((value) => typeof value === 'string' && value.trim())
759
- .join(' ');
760
- };
761
-
762
- const resolveViberCarouselCards = (cards, tagValues) => {
763
- if (!Array.isArray(cards) || !tagValues || !Object.keys(tagValues).length) {
764
- return cards;
765
- }
766
- return cards.map((card) => ({
767
- ...card,
768
- text: resolveTagsInText(card?.text || '', tagValues),
769
- buttons: (card?.buttons || []).map((button) => ({
770
- ...button,
771
- title: resolveTagsInText(button?.title || '', tagValues),
772
- action: resolveTagsInText(button?.action || '', tagValues),
773
- })),
774
- }));
775
- };
776
-
777
- const applyViberCustomValuesToContent = (contentObj, tagValues) => {
778
- if (!contentObj || typeof contentObj !== 'object' || !tagValues || !Object.keys(tagValues).length) {
779
- return contentObj;
780
- }
781
- const result = { ...contentObj };
782
- if (typeof result.messageContent === 'string') {
783
- result.messageContent = resolveTagsInText(result.messageContent, tagValues);
784
- }
785
- if (Array.isArray(result.cards)) {
786
- result.cards = resolveViberCarouselCards(result.cards, tagValues);
787
- }
788
- if (result.viberPreviewContent && typeof result.viberPreviewContent === 'object') {
789
- const preview = result.viberPreviewContent;
790
- result.viberPreviewContent = {
791
- ...preview,
792
- messageContent: resolveTagsInText(preview.messageContent || '', tagValues),
793
- cards: resolveViberCarouselCards(preview.cards, tagValues),
794
- };
795
- }
796
- return result;
797
- };
798
-
799
- const mergeViberPreviewWithResolved = (base, resolved) => {
800
- if (!resolved || typeof resolved !== 'object') {
801
- return base && typeof base === 'object' ? base : {};
802
- }
803
- const baseObj = base && typeof base === 'object' ? base : {};
804
- const basePreview = baseObj.viberPreviewContent || {};
805
- const resolvedPreview = resolved.viberPreviewContent || {};
806
- const baseCards = basePreview.cards || baseObj.cards || [];
807
- const resolvedCards = resolvedPreview.cards || resolved.cards || [];
808
- const mergedCards = baseCards.length
809
- ? baseCards.map((card, index) => {
810
- const resolvedCard = resolvedCards[index];
811
- if (!resolvedCard) {
812
- return card;
813
- }
814
- return {
815
- ...card,
816
- ...(resolvedCard.text != null ? { text: resolvedCard.text } : {}),
817
- ...(resolvedCard.mediaUrl != null ? { mediaUrl: resolvedCard.mediaUrl } : {}),
818
- buttons: (card.buttons || []).map((button, buttonIndex) => ({
819
- ...button,
820
- ...(resolvedCard.buttons?.[buttonIndex] || {}),
821
- })),
822
- };
823
- })
824
- : resolvedCards;
825
- const resolvedMessage = resolved.messageContent ?? resolvedPreview.messageContent;
826
-
827
- return {
828
- ...baseObj,
829
- ...resolved,
830
- viberPreviewContent: {
831
- ...basePreview,
832
- ...resolvedPreview,
833
- type: resolvedPreview.type || basePreview.type || baseObj.type || (mergedCards.length ? MEDIA_TYPE_CAROUSEL : ''),
834
- cards: mergedCards.length ? mergedCards : (resolvedPreview.cards || basePreview.cards),
835
- showCarouselEditorPreview: Boolean(
836
- basePreview.showCarouselEditorPreview
837
- || resolvedPreview.showCarouselEditorPreview
838
- || mergedCards.length > 0,
839
- ),
840
- ...(resolvedMessage != null ? { messageContent: resolvedMessage } : {}),
841
- },
842
- };
843
- };
844
-
845
677
  /**
846
678
  * Common handler for saving test customers (both new and existing)
847
679
  */
@@ -1120,13 +952,11 @@ const CommonTestAndPreview = (props) => {
1120
952
  templateContent: formDataObj?.bodyText || contentStr,
1121
953
  };
1122
954
 
1123
- case CHANNELS.VIBER: {
1124
- const viberFormData = getViberMergedFormData(formDataObj);
955
+ case CHANNELS.VIBER:
1125
956
  return {
1126
- templateSubject: viberFormData?.messageTitle || '',
1127
- templateContent: getViberTagExtractionContent(viberFormData, contentStr),
957
+ templateSubject: formDataObj?.messageTitle || '',
958
+ templateContent: contentStr,
1128
959
  };
1129
- }
1130
960
 
1131
961
  case CHANNELS.WEBPUSH:
1132
962
  return {
@@ -1226,7 +1056,7 @@ const CommonTestAndPreview = (props) => {
1226
1056
  const buildRcsTestMessagePayload = (
1227
1057
  creativeFormData,
1228
1058
  _unusedEditorContentString,
1229
- customValuesObj,
1059
+ _customValuesObj,
1230
1060
  deliverySettingsOverride,
1231
1061
  basePayload,
1232
1062
  _rcsTestMetaExtras = {},
@@ -1241,9 +1071,7 @@ const CommonTestAndPreview = (props) => {
1241
1071
  } else if (rcsContentFromForm?.cardContent) {
1242
1072
  rcsCardPayloadList = [rcsContentFromForm.cardContent];
1243
1073
  }
1244
- // Title/description/suggestion text carry {{tag}} placeholders; resolve them against the
1245
- // user's test values here, same as every other channel (see resolveTagsInText usage below
1246
- // for SMS/EMAIL/WHATSAPP) — otherwise the test send goes out with literal tags unresolved.
1074
+ // Raw title/description with template tags; SMS fallback uses tagged template fields (pickFirst…).
1247
1075
  const cardContentForTestMetaApi = rcsCardPayloadList.map((singleRcsCardPayload) => {
1248
1076
  const normalizedCardMediaForTestApi = singleRcsCardPayload?.media
1249
1077
  ? normalizeRcsTestCardMedia(singleRcsCardPayload.media)
@@ -1251,25 +1079,11 @@ const CommonTestAndPreview = (props) => {
1251
1079
  const suggestionsFromCard = Array.isArray(singleRcsCardPayload?.suggestions)
1252
1080
  ? singleRcsCardPayload.suggestions
1253
1081
  : [];
1254
- const suggestionsFormattedForTestMeta = suggestionsFromCard.map((suggestionItem, index) => mapRcsSuggestionForTestMeta(
1255
- {
1256
- ...suggestionItem,
1257
- text: resolveTagsInText(
1258
- suggestionItem?.text != null ? String(suggestionItem.text) : '',
1259
- customValuesObj,
1260
- ),
1261
- },
1262
- index,
1263
- ));
1082
+ const suggestionsFormattedForTestMeta = suggestionsFromCard.map((suggestionItem, index) =>
1083
+ mapRcsSuggestionForTestMeta(suggestionItem, index));
1264
1084
  return {
1265
- title: resolveTagsInText(
1266
- singleRcsCardPayload?.title != null ? String(singleRcsCardPayload.title) : '',
1267
- customValuesObj,
1268
- ),
1269
- description: resolveTagsInText(
1270
- singleRcsCardPayload?.description != null ? String(singleRcsCardPayload.description) : '',
1271
- customValuesObj,
1272
- ),
1085
+ title: singleRcsCardPayload?.title ?? '',
1086
+ description: singleRcsCardPayload?.description ?? '',
1273
1087
  mediaType: singleRcsCardPayload?.mediaType ?? MEDIA_TYPE_TEXT,
1274
1088
  ...(normalizedCardMediaForTestApi && { media: normalizedCardMediaForTestApi }),
1275
1089
  ...(suggestionsFormattedForTestMeta.length > 0 && {
@@ -2180,16 +1994,11 @@ const CommonTestAndPreview = (props) => {
2180
1994
  // 1. formDataObj from getTemplateContent (contains both viberPreviewContent and payload fields)
2181
1995
  // 2. formDataObj[0] (array format - legacy)
2182
1996
  // 3. contentStr (direct string - legacy)
2183
- // Merge content prop so listing / preview-only flows include carousel card tags
2184
- const viberFormData = getViberMergedFormData(formDataObj);
2185
- formDataObj = viberFormData;
2186
1997
 
2187
1998
  let messageText = '';
2188
1999
  let imageData = null;
2189
2000
  let videoData = null;
2190
2001
  let buttonData = null;
2191
- let cardsData = [];
2192
- let messageType = '';
2193
2002
  let accountId = null;
2194
2003
  let accountDetails = null;
2195
2004
  let scenarioKey = '';
@@ -2204,8 +2013,6 @@ const CommonTestAndPreview = (props) => {
2204
2013
  imageData = formDataObj.image || null;
2205
2014
  videoData = formDataObj.video || null;
2206
2015
  buttonData = formDataObj.button || null;
2207
- cardsData = formDataObj.cards || [];
2208
- messageType = formDataObj.type || '';
2209
2016
  accountId = formDataObj.accountId || null;
2210
2017
  accountDetails = formDataObj.accountDetails || null;
2211
2018
  scenarioKey = formDataObj.scenarioKey || VIBER_API_SCENARIO_KEY;
@@ -2232,8 +2039,6 @@ const CommonTestAndPreview = (props) => {
2232
2039
  url: formDataObj?.buttonURL || '',
2233
2040
  };
2234
2041
  }
2235
- cardsData = viberPreview.cards || formDataObj?.cards || [];
2236
- messageType = viberPreview.type || formDataObj?.type || '';
2237
2042
  // Extract account info from parent formDataObj if available
2238
2043
  accountId = formDataObj.accountId || null;
2239
2044
  accountDetails = formDataObj.accountDetails || null;
@@ -2276,10 +2081,6 @@ const CommonTestAndPreview = (props) => {
2276
2081
  text: messageText,
2277
2082
  };
2278
2083
 
2279
- if (messageType === CHANNELS.VIBER) {
2280
- messageType = '';
2281
- }
2282
-
2283
2084
  // Add image if present
2284
2085
  if (imageData && imageData.url) {
2285
2086
  viberContent.image = {
@@ -2308,34 +2109,9 @@ const CommonTestAndPreview = (props) => {
2308
2109
  }
2309
2110
  }
2310
2111
 
2311
- if (messageType === MEDIA_TYPE_CAROUSEL || (Array.isArray(cardsData) && cardsData.length)) {
2312
- viberContent.type = MEDIA_TYPE_CAROUSEL;
2313
- viberContent.cards = (cardsData || []).map((card) => ({
2314
- text: card?.text || '',
2315
- mediaUrl: card?.mediaUrl || '',
2316
- buttons: (card?.buttons || []).map((button) => ({
2317
- title: button?.title || '',
2318
- action: button?.action || '',
2319
- })),
2320
- }));
2321
- delete viberContent.button;
2322
- }
2323
-
2324
- // Resolve tags in text/cards if custom values are provided
2325
- if (customValuesObj && Object.keys(customValuesObj).length > 0) {
2326
- if (viberContent.text) {
2327
- viberContent.text = resolveTagsInText(viberContent.text, customValuesObj);
2328
- }
2329
- if (Array.isArray(viberContent.cards)) {
2330
- viberContent.cards = resolveViberCarouselCards(viberContent.cards, customValuesObj);
2331
- }
2332
- if (viberContent.button) {
2333
- viberContent.button = {
2334
- ...viberContent.button,
2335
- text: resolveTagsInText(viberContent.button.text || '', customValuesObj),
2336
- url: resolveTagsInText(viberContent.button.url || '', customValuesObj),
2337
- };
2338
- }
2112
+ // Resolve tags in text if custom values are provided
2113
+ if (customValuesObj && Object.keys(customValuesObj).length > 0 && viberContent.text) {
2114
+ viberContent.text = resolveTagsInText(viberContent.text, customValuesObj);
2339
2115
  }
2340
2116
 
2341
2117
  // Build messageBody JSON string
@@ -2727,39 +2503,33 @@ const CommonTestAndPreview = (props) => {
2727
2503
  // Only use previewDataHtml if preview call was made
2728
2504
  if (hasPreviewCallBeenMade && previewDataHtml?.resolvedBody) {
2729
2505
  resolvedContent = previewDataHtml.resolvedBody;
2730
- if (typeof resolvedContent === 'string') {
2731
- try {
2732
- resolvedContent = JSON.parse(resolvedContent);
2733
- } catch (e) {
2734
- resolvedContent = null;
2735
- }
2736
- }
2737
2506
  }
2738
2507
 
2739
- // Parse content if it's a string, then merge with formData for carousel + tags in all entry flows
2740
- let parsedViberContent = getViberMergedFormData();
2741
- if (!parsedViberContent || typeof parsedViberContent !== 'object') {
2742
- parsedViberContent = {};
2508
+ // Parse content if it's a string
2509
+ let parsedViberContent = content;
2510
+ if (typeof content === 'string') {
2511
+ try {
2512
+ parsedViberContent = JSON.parse(content);
2513
+ } catch (e) {
2514
+ parsedViberContent = {};
2515
+ }
2743
2516
  }
2744
- // Merge template preview state with API resolved body so carousel type/cards survive slim responses
2517
+ // Use resolvedContent if available (from preview call), otherwise use raw content
2745
2518
  if (resolvedContent && typeof resolvedContent === 'object') {
2746
- const base = parsedViberContent && typeof parsedViberContent === 'object' ? parsedViberContent : {};
2747
- contentObj = mergeViberPreviewWithResolved(base, resolvedContent);
2748
- if (base.accountName && !contentObj.accountName) {
2749
- contentObj.accountName = base.accountName;
2519
+ contentObj = { ...resolvedContent };
2520
+ // Merge in accountName and brandName from raw content if not in resolvedContent
2521
+ if (parsedViberContent?.accountName && !contentObj.accountName) {
2522
+ contentObj.accountName = parsedViberContent.accountName;
2750
2523
  }
2751
- if (base.brandName && !contentObj.brandName) {
2752
- contentObj.brandName = base.brandName;
2524
+ if (parsedViberContent?.brandName && !contentObj.brandName) {
2525
+ contentObj.brandName = parsedViberContent.brandName;
2753
2526
  }
2754
2527
  } else {
2755
- contentObj = parsedViberContent && typeof parsedViberContent === 'object' ? parsedViberContent : {};
2756
- }
2757
- if (
2758
- hasPreviewCallBeenMade
2759
- && viberPreviewTagValues
2760
- && Object.keys(viberPreviewTagValues).length > 0
2761
- ) {
2762
- contentObj = applyViberCustomValuesToContent(contentObj, viberPreviewTagValues);
2528
+ // Use raw content if no preview call was made or resolvedContent is not available
2529
+ contentObj = {...parsedViberContent, messageContent: resolvedContent};
2530
+ if (resolvedContent) {
2531
+ contentObj.viberPreviewContent = {...parsedViberContent?.viberPreviewContent, messageContent: resolvedContent};
2532
+ }
2763
2533
  }
2764
2534
  } else if (channel === CHANNELS.ZALO) {
2765
2535
  // For Zalo, content is an object with templatePreviewUrl, templateStatus, etc.
@@ -3143,11 +2913,6 @@ const CommonTestAndPreview = (props) => {
3143
2913
 
3144
2914
  setCustomValues(updatedValues);
3145
2915
 
3146
- // Viber: do not auto-resolve tags in preview; user must click Update preview
3147
- if (channel === CHANNELS.VIBER) {
3148
- return;
3149
- }
3150
-
3151
2916
  // Update preview with prefilled values (this is a valid preview call trigger)
3152
2917
  // For RCS: always dispatch with RCS channel/content so previewDataHtml stays RCS-shaped.
3153
2918
  // SMS fallback preview is kept in sync by syncSmsFallbackPreview via smsFallbackPreviewText.
@@ -3230,7 +2995,6 @@ const CommonTestAndPreview = (props) => {
3230
2995
  setPreviewDevice(DESKTOP);
3231
2996
  setPreviewDataHtml('');
3232
2997
  setHasPreviewCallBeenMade(false); // Reset preview call flag
3233
- setViberPreviewTagValues(null);
3234
2998
  setSelectedTestEntities([]);
3235
2999
  setBeeContent('');
3236
3000
  previousBeeContentRef.current = '';
@@ -3268,7 +3032,6 @@ const CommonTestAndPreview = (props) => {
3268
3032
  const handleClearSelection = () => {
3269
3033
  setSelectedCustomer(null);
3270
3034
  setHasPreviewCallBeenMade(false); // Reset flag when customer is cleared
3271
- setViberPreviewTagValues(null);
3272
3035
 
3273
3036
  // Clear all preview errors when customer is cleared
3274
3037
  actions.clearPreviewErrors();
@@ -3327,9 +3090,6 @@ const CommonTestAndPreview = (props) => {
3327
3090
  emptyValues,
3328
3091
  selectedCustomer
3329
3092
  );
3330
- if (channel === CHANNELS.VIBER) {
3331
- setViberPreviewTagValues({ ...emptyValues });
3332
- }
3333
3093
  actions.updatePreviewRequested(payload);
3334
3094
  setHasPreviewCallBeenMade(true); // Mark that preview call was made
3335
3095
  };
@@ -3355,9 +3115,6 @@ const CommonTestAndPreview = (props) => {
3355
3115
  customValues,
3356
3116
  selectedCustomer
3357
3117
  );
3358
- if (channel === CHANNELS.VIBER) {
3359
- setViberPreviewTagValues({ ...customValues });
3360
- }
3361
3118
  await actions.updatePreviewRequested(payload);
3362
3119
 
3363
3120
  await syncSmsFallbackPreview(customValues, selectedCustomer);
@@ -3404,8 +3161,7 @@ const CommonTestAndPreview = (props) => {
3404
3161
  * Apply tag extraction when content comes from RCS + SMS fallback (no API call).
3405
3162
  */
3406
3163
  const applyRcsSmsFallbackTagExtraction = () => {
3407
- const rcsPrimaryTagTree = mergeSyntheticMustacheTags(extractedTags, getRcsPrimaryTagExtractionText(formData));
3408
- const rcsPrimaryCategorized = categorizeTags(rcsPrimaryTagTree);
3164
+ const rcsPrimaryCategorized = categorizeTags(extractedTags ?? []);
3409
3165
  const fallbackSmsResolvedForTags = smsFallbackTextForTagExtraction ?? '';
3410
3166
  let fallbackSmsTagTree = smsFallbackExtractedTags?.length > 0
3411
3167
  ? smsFallbackExtractedTags
@@ -3431,7 +3187,8 @@ const CommonTestAndPreview = (props) => {
3431
3187
  */
3432
3188
  useEffect(() => {
3433
3189
  if (!show) return;
3434
- if (channel === CHANNELS.RCS) {
3190
+ const hasFallbackSmsTemplate = !!(smsFallbackContent?.templateContent || smsFallbackContent?.content);
3191
+ if (channel === CHANNELS.RCS && hasFallbackSmsTemplate) {
3435
3192
  applyRcsSmsFallbackTagExtraction();
3436
3193
  return;
3437
3194
  }
@@ -3447,8 +3204,8 @@ const CommonTestAndPreview = (props) => {
3447
3204
  setOptionalTags(optional);
3448
3205
  setTagsExtracted(hasPersonalizationTags);
3449
3206
  setCustomValues((prev) => mergeCustomValuesWithTagKeys(prev, { required, optional }, { required: [], optional: [] }));
3450
- // eslint-disable-next-line react-hooks/exhaustive-deps -- applyRcsSmsFallbackTagExtraction closes over latest extractedTags/smsFallbackExtractedTags/formData
3451
- }, [show, extractedTags, channel, formData, smsFallbackContent, smsFallbackExtractedTags, getCurrentContent, smsFallbackTextForTagExtraction]);
3207
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- applyRcsSmsFallbackTagExtraction closes over latest extractedTags/smsFallbackExtractedTags
3208
+ }, [show, extractedTags, channel, smsFallbackContent, smsFallbackExtractedTags, getCurrentContent, smsFallbackTextForTagExtraction]);
3452
3209
 
3453
3210
  /**
3454
3211
  * Get content to run tag extraction on (channel-specific).