@capillarytech/creatives-library 9.0.35 → 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 (51) 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/index.js +15 -44
  16. package/v2Components/CommonTestAndPreview/tests/index.test.js +0 -78
  17. package/v2Components/CommonTestAndPreview/utils.js +0 -34
  18. package/v2Components/NavigationBar/index.js +7 -9
  19. package/v2Components/NavigationBar/tests/index.test.js +19 -39
  20. package/v2Components/SmsFallback/index.js +0 -6
  21. package/v2Containers/Cap/constants.js +0 -1
  22. package/v2Containers/Cap/index.js +27 -57
  23. package/v2Containers/CreativesContainer/index.js +8 -11
  24. package/v2Containers/CreativesContainer/tests/index.test.js +0 -53
  25. package/v2Containers/Rcs/carouselUtils.js +73 -46
  26. package/v2Containers/Rcs/components/CarouselCard.js +9 -11
  27. package/v2Containers/Rcs/components/CarouselCardButtons.js +0 -20
  28. package/v2Containers/Rcs/constants.js +7 -2
  29. package/v2Containers/Rcs/index.js +205 -226
  30. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +47 -60
  31. package/v2Containers/Rcs/tests/CarouselCard.test.js +2 -1
  32. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +0 -286
  33. package/v2Containers/Rcs/tests/carouselUtils.test.js +32 -28
  34. package/v2Containers/Rcs/tests/index.test.js +238 -151
  35. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -110
  36. package/v2Containers/Rcs/tests/utils.test.js +17 -36
  37. package/v2Containers/Rcs/utils.js +55 -28
  38. package/v2Containers/SmsTrai/Edit/index.js +24 -35
  39. package/v2Containers/Templates/_templates.scss +1 -1
  40. package/v2Containers/Templates/index.js +0 -1
  41. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +0 -5
  42. package/v2Containers/TemplatesV2/TemplatesV2.style.js +3 -8
  43. package/v2Containers/TemplatesV2/index.js +9 -22
  44. package/AppRoot.js +0 -124
  45. package/app-config.js +0 -61
  46. package/bootstrap.js +0 -185
  47. package/utils/getDataLayer.js +0 -15
  48. package/utils/mfeDetect.js +0 -1
  49. package/utils/mfeFirstPaintReady.js +0 -29
  50. package/utils/mfeHistory.js +0 -62
  51. package/v2Components/NavigationBar/mfeModuleHeader.config.js +0 -16
@@ -217,24 +217,6 @@ export function buildSmsFallBackContentForPayload({
217
217
  ? tcSibling.header
218
218
  : null;
219
219
  const hasRegisteredSenderIds = Array.isArray(registeredSenderIdsForPayload);
220
- // `rcsSmsFallbackVarMapped` (root of smsFallBackContent) is a custom field that
221
- // normalizeRcsMessageContentForApi strips before the real API call (see comment below) — it
222
- // only survives for same-session local re-hydration. templateConfigs.templateVariableMapping is
223
- // the field the backend actually persists (same shape TRAI/DLT registration uses), so mirror the
224
- // var map there too — otherwise slot values saved through campaigns/library mode are lost on reopen.
225
- const varMapForTemplateConfigs =
226
- smsFallbackForPayload?.[RCS_SMS_FALLBACK_VAR_MAPPED_PROP]
227
- || mergedFallback[RCS_SMS_FALLBACK_VAR_MAPPED_PROP];
228
- const templateVariableMappingForPayload =
229
- varMapForTemplateConfigs && typeof varMapForTemplateConfigs === 'object'
230
- ? Object.entries(varMapForTemplateConfigs).reduce((acc, [slotKey, slotValue], index) => {
231
- if (slotValue == null || slotValue === '') return acc;
232
- acc[slotKey] = { data: slotValue, count: index + 1 };
233
- return acc;
234
- }, {})
235
- : null;
236
- const hasTemplateVariableMapping =
237
- templateVariableMappingForPayload && Object.keys(templateVariableMappingForPayload).length > 0;
238
220
  const smsFallbackTemplateConfigs =
239
221
  smsFallbackTemplateId || hasRegisteredSenderIds
240
222
  ? {
@@ -246,9 +228,6 @@ export function buildSmsFallBackContentForPayload({
246
228
  ...(hasRegisteredSenderIds && {
247
229
  registeredSenderIds: registeredSenderIdsForPayload,
248
230
  }),
249
- ...(hasTemplateVariableMapping && {
250
- templateVariableMapping: templateVariableMappingForPayload,
251
- }),
252
231
  }
253
232
  : null;
254
233
  const isDltCampaign = !isFullMode && isTraiDLTEnable(isFullMode, smsRegister);
@@ -316,48 +295,18 @@ export function resolveSmsFallbackHydrationFromDetails(details) {
316
295
  const fromNested = Array.isArray(updatedEditor)
317
296
  ? updatedEditor.join('')
318
297
  : (typeof updatedEditor === 'string' ? updatedEditor : (smsEditor || ''));
319
- const templateConfigsRecord =
320
- smsFallbackContent.templateConfigs && typeof smsFallbackContent.templateConfigs === 'object'
321
- ? smsFallbackContent.templateConfigs
322
- : {};
323
- // For DLT/TRAI fallbacks, smsContent/smsTemplateContent/message are the send-ready text —
324
- // {#var#} slots are already baked into a literal value there (required to match the
325
- // TRAI-approved template). Only templateConfigs.template keeps {#var#} intact, so prefer it
326
- // here — otherwise reopening the editor can never re-render that slot as its own box again.
327
- const rawDltTemplate =
328
- typeof templateConfigsRecord.template === 'string' && templateConfigsRecord.template.trim() !== ''
329
- ? templateConfigsRecord.template
330
- : '';
331
- const fallbackMessage = rawDltTemplate
332
- || smsFallbackContent.smsContent
298
+ const fallbackMessage = smsFallbackContent.smsContent
333
299
  || smsFallbackContent.smsTemplateContent
334
300
  || smsFallbackContent.message
335
301
  || fromNested
336
302
  || '';
337
- const varMapFromTemplateVariableMapping =
338
- templateConfigsRecord.templateVariableMapping && typeof templateConfigsRecord.templateVariableMapping === 'object'
339
- ? Object.entries(templateConfigsRecord.templateVariableMapping).reduce((acc, [slotKey, slotEntry]) => {
340
- const slotValue = slotEntry && typeof slotEntry === 'object' ? slotEntry.data : slotEntry;
341
- if (slotValue != null) acc[slotKey] = slotValue;
342
- return acc;
343
- }, {})
344
- : null;
345
- const varMappedFromPayload = {
346
- ...(varMapFromTemplateVariableMapping || {}),
347
- ...(smsFallbackContent[RCS_SMS_FALLBACK_VAR_MAPPED_PROP] || {}),
348
- };
303
+ const varMappedFromPayload = smsFallbackContent[RCS_SMS_FALLBACK_VAR_MAPPED_PROP] || {};
349
304
  const hasVarMapped = Object.keys(varMappedFromPayload).length > 0;
350
- const smsFallbackTemplateName =
351
- smsFallbackContent.templateName
352
- || smsFallbackContent.smsTemplateName
353
- || templateConfigsRecord.templateName
354
- || templateConfigsRecord.name
355
- || '';
356
305
  const hasFallbackPayload =
357
306
  smsFallbackContent
358
307
  && Object.keys(smsFallbackContent).length > 0
359
308
  && (
360
- !!smsFallbackTemplateName
309
+ !!smsFallbackContent.smsTemplateName
361
310
  || !!fallbackMessage
362
311
  || hasVarMapped
363
312
  );
@@ -376,7 +325,7 @@ export function resolveSmsFallbackHydrationFromDetails(details) {
376
325
  : (typeof base['unicode-validity'] === 'boolean' ? base['unicode-validity'] : true);
377
326
  const registeredSenderIds = extractRegisteredSenderIdsFromSmsFallbackRecord(smsFallbackContent);
378
327
  const nextSmsState = {
379
- templateName: smsFallbackTemplateName,
328
+ templateName: smsFallbackContent.smsTemplateName || '',
380
329
  content: fallbackMessage,
381
330
  templateContent: fallbackMessage,
382
331
  unicodeValidity: unicodeFromApi,
@@ -447,6 +396,7 @@ export function syncCardVarMappedSemanticsFromSlots(
447
396
  templateDesc,
448
397
  rcsVarRegex,
449
398
  ) {
399
+ console.log('syncCardVarMappedSemanticsFromSlots', cardVarMappedInput, templateTitle, templateDesc);
450
400
  const cardVarMappedSynced =
451
401
  cardVarMappedInput != null && typeof cardVarMappedInput === 'object'
452
402
  ? { ...cardVarMappedInput }
@@ -459,11 +409,48 @@ export function syncCardVarMappedSemanticsFromSlots(
459
409
  templateVarTokens.forEach((token, slotIndexZeroBased) => {
460
410
  const semanticVarName = getVarNameFromToken(token);
461
411
  if (!semanticVarName) return;
462
- const numericSlotKey = String(slotIndexZeroBased + 1);
463
- const semanticValueTrimmed = String(cardVarMappedSynced[semanticVarName] ?? '').trim();
464
- const numericSlotValueTrimmed = String(cardVarMappedSynced[numericSlotKey] ?? '').trim();
465
- if (!semanticValueTrimmed && numericSlotValueTrimmed) {
466
- cardVarMappedSynced[semanticVarName] = cardVarMappedSynced[numericSlotKey];
412
+
413
+ if (!RCS_NUMERIC_VAR_NAME_REGEX.test(semanticVarName)) {
414
+ // A numeric slot may already self-reference this exact tag (e.g. "4" -> "{{last_name}}") when
415
+ // the template's own numeric placeholder has since been resolved to this tag in the text —
416
+ // that numeric key is the source of truth, not this token's position.
417
+ const mustacheSelfReference = `{{${semanticVarName}}}`;
418
+ const existingNumericKeyForSemantic = Object.keys(cardVarMappedSynced).find((key) => (
419
+ RCS_NUMERIC_VAR_NAME_REGEX.test(key) && cardVarMappedSynced[key] === mustacheSelfReference
420
+ ));
421
+ if (existingNumericKeyForSemantic) {
422
+ const semanticValueTrimmed = String(cardVarMappedSynced[semanticVarName] ?? '').trim();
423
+ const numericValueTrimmed = String(cardVarMappedSynced[existingNumericKeyForSemantic] ?? '').trim();
424
+ if (!semanticValueTrimmed && numericValueTrimmed) {
425
+ cardVarMappedSynced[semanticVarName] = cardVarMappedSynced[existingNumericKeyForSemantic];
426
+ }
427
+ return;
428
+ }
429
+
430
+ // Legacy: template embeds the semantic token directly ({{user_name}}), but older payloads
431
+ // stored the resolved value under a position-based numeric key ("1", "2", …).
432
+ const numericSlotKey = String(slotIndexZeroBased + 1);
433
+ const semanticValueTrimmed = String(cardVarMappedSynced[semanticVarName] ?? '').trim();
434
+ const numericSlotValueTrimmed = String(cardVarMappedSynced[numericSlotKey] ?? '').trim();
435
+ if (!semanticValueTrimmed && numericSlotValueTrimmed) {
436
+ cardVarMappedSynced[semanticVarName] = cardVarMappedSynced[numericSlotKey];
437
+ }
438
+ return;
439
+ }
440
+
441
+ // Carousel numeric placeholder ({{3}}, {{4}}, …): the slot key IS the token digit itself —
442
+ // numbers are allocated globally across the whole carousel (getNextCarouselVarToken), not
443
+ // re-numbered per card, so a position-based key here would target the wrong slot. Its value
444
+ // may be a mustache-wrapped tag reference (e.g. "3" -> "{{last_name}}") — mirror that onto the
445
+ // bare semantic key too so VarSegment editors keyed by tag name also prepopulate.
446
+ const slotValueTrimmed = String(cardVarMappedSynced[semanticVarName] ?? '').trim();
447
+ if (!slotValueTrimmed) return;
448
+ const mustacheInnerMatch = slotValueTrimmed.match(/^\{\{([^}]+)\}\}$/);
449
+ const innerSemanticName = mustacheInnerMatch?.[1]?.trim();
450
+ if (!innerSemanticName || innerSemanticName === semanticVarName) return;
451
+ const existingSemanticValue = String(cardVarMappedSynced[innerSemanticName] ?? '').trim();
452
+ if (!existingSemanticValue) {
453
+ cardVarMappedSynced[innerSemanticName] = cardVarMappedSynced[semanticVarName];
467
454
  }
468
455
  });
469
456
  return cardVarMappedSynced;
@@ -220,7 +220,8 @@ const baseProps = {
220
220
  onDescriptionChange: jest.fn(),
221
221
  onTitleAddVar: jest.fn(),
222
222
  onDescriptionAddVar: jest.fn(),
223
- onTagSelect: jest.fn(),
223
+ onTitleTagSelect: jest.fn(),
224
+ onDescTagSelect: jest.fn(),
224
225
  onContextChange: jest.fn(),
225
226
  renderEditMessage: (val) => <div data-testid="render-edit-message">{val}</div>,
226
227
  onFieldChange: jest.fn(),