@capillarytech/creatives-library 9.0.28 → 9.0.29-alpha.1

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 (149) hide show
  1. package/constants/unified.js +29 -0
  2. package/global-styles.js +1 -1
  3. package/package.json +1 -1
  4. package/services/tests/api.test.js +35 -20
  5. package/utils/commonUtils.js +22 -1
  6. package/utils/rcsPayloadUtils.js +102 -0
  7. package/utils/templateVarUtils.js +198 -0
  8. package/utils/tests/rcsPayloadUtils.test.js +295 -0
  9. package/utils/tests/templateVarUtils.test.js +204 -0
  10. package/v2Components/CapActionButton/constants.js +21 -1
  11. package/v2Components/CapActionButton/index.js +260 -144
  12. package/v2Components/CapActionButton/index.scss +245 -14
  13. package/v2Components/CapActionButton/messages.js +32 -3
  14. package/v2Components/CapActionButton/tests/index.test.js +74 -19
  15. package/v2Components/CapImageUpload/index.js +2 -2
  16. package/v2Components/CapTagList/index.js +9 -0
  17. package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +70 -48
  18. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +8 -2
  19. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +214 -21
  20. package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +16 -0
  21. package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +83 -9
  22. package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +30 -0
  23. package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +58 -11
  24. package/v2Components/CommonTestAndPreview/SendTestMessage.js +10 -5
  25. package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +186 -22
  26. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +381 -80
  27. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +155 -8
  28. package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +11 -0
  29. package/v2Components/CommonTestAndPreview/constants.js +35 -2
  30. package/v2Components/CommonTestAndPreview/index.js +770 -231
  31. package/v2Components/CommonTestAndPreview/messages.js +45 -3
  32. package/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
  33. package/v2Components/CommonTestAndPreview/sagas.js +25 -6
  34. package/v2Components/CommonTestAndPreview/tests/CommonTestAndPreview.addTestCustomer.test.js +1 -0
  35. package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +412 -257
  36. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +337 -63
  37. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +118 -5
  38. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +341 -0
  39. package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +8 -1
  40. package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +108 -15
  41. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +281 -283
  42. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +199 -1
  43. package/v2Components/CommonTestAndPreview/tests/index.test.js +133 -4
  44. package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
  45. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +31 -24
  46. package/v2Components/CommonTestAndPreview/tests/utils.test.js +151 -0
  47. package/v2Components/CommonTestAndPreview/utils.js +84 -0
  48. package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +91 -0
  49. package/v2Components/SmsFallback/constants.js +94 -0
  50. package/v2Components/SmsFallback/index.js +958 -0
  51. package/v2Components/SmsFallback/index.scss +266 -0
  52. package/v2Components/SmsFallback/messages.js +78 -0
  53. package/v2Components/SmsFallback/smsFallbackUtils.js +120 -0
  54. package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +50 -0
  55. package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +147 -0
  56. package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +304 -0
  57. package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +208 -0
  58. package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +309 -0
  59. package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +471 -0
  60. package/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
  61. package/v2Components/TemplatePreview/_templatePreview.scss +45 -25
  62. package/v2Components/TemplatePreview/constants.js +2 -0
  63. package/v2Components/TemplatePreview/index.js +147 -32
  64. package/v2Components/TemplatePreview/tests/index.test.js +142 -0
  65. package/v2Components/TestAndPreviewSlidebox/CustomValuesEditor.js +6 -6
  66. package/v2Components/TestAndPreviewSlidebox/index.js +13 -1
  67. package/v2Components/TestAndPreviewSlidebox/sagas.js +11 -4
  68. package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +3 -1
  69. package/v2Components/VarSegmentMessageEditor/constants.js +2 -0
  70. package/v2Components/VarSegmentMessageEditor/index.js +125 -0
  71. package/v2Components/VarSegmentMessageEditor/index.scss +46 -0
  72. package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +4 -1
  73. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +4 -0
  74. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +20 -20
  75. package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +27 -0
  76. package/v2Containers/CreativesContainer/SlideBoxContent.js +37 -4
  77. package/v2Containers/CreativesContainer/SlideBoxFooter.js +14 -5
  78. package/v2Containers/CreativesContainer/SlideBoxHeader.js +36 -5
  79. package/v2Containers/CreativesContainer/constants.js +11 -0
  80. package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +77 -0
  81. package/v2Containers/CreativesContainer/index.js +328 -106
  82. package/v2Containers/CreativesContainer/index.scss +102 -1
  83. package/v2Containers/CreativesContainer/tests/CreativesSlideBoxWrapper.test.js +58 -0
  84. package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
  85. package/v2Containers/CreativesContainer/tests/SlideBoxContent.smsDltPreview.test.js +73 -0
  86. package/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +37 -0
  87. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +103 -34
  88. package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +193 -15
  89. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +88 -0
  90. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +549 -57
  91. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +20 -15
  92. package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
  93. package/v2Containers/CreativesContainer/tests/index.test.js +71 -9
  94. package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +125 -0
  95. package/v2Containers/Email/index.js +3 -63
  96. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +4 -9
  97. package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
  98. package/v2Containers/Rcs/carouselUtils.js +224 -0
  99. package/v2Containers/Rcs/components/CarouselCard.js +317 -0
  100. package/v2Containers/Rcs/components/CarouselCardButtons.js +113 -0
  101. package/v2Containers/Rcs/components/CarouselCardMedia.js +136 -0
  102. package/v2Containers/Rcs/components/CarouselCharacterCount.js +31 -0
  103. package/v2Containers/Rcs/components/CarouselDimensionSelection.js +80 -0
  104. package/v2Containers/Rcs/constants.js +132 -16
  105. package/v2Containers/Rcs/index.js +1808 -949
  106. package/v2Containers/Rcs/index.scss +443 -8
  107. package/v2Containers/Rcs/messages.js +45 -22
  108. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +484 -0
  109. package/v2Containers/Rcs/tests/CarouselCard.test.js +464 -0
  110. package/v2Containers/Rcs/tests/CarouselCardButtons.test.js +211 -0
  111. package/v2Containers/Rcs/tests/CarouselCardMedia.test.js +160 -0
  112. package/v2Containers/Rcs/tests/CarouselCharacterCount.test.js +50 -0
  113. package/v2Containers/Rcs/tests/CarouselDimensionSelection.test.js +119 -0
  114. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +74176 -39409
  115. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +10 -74
  116. package/v2Containers/Rcs/tests/carouselUtils.test.js +916 -0
  117. package/v2Containers/Rcs/tests/index.test.js +219 -40
  118. package/v2Containers/Rcs/tests/mockData.js +38 -0
  119. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +873 -0
  120. package/v2Containers/Rcs/tests/utils.test.js +682 -30
  121. package/v2Containers/Rcs/utils.js +514 -12
  122. package/v2Containers/Sms/Create/index.js +115 -48
  123. package/v2Containers/Sms/smsFormDataHelpers.js +67 -0
  124. package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +253 -0
  125. package/v2Containers/SmsTrai/Create/index.js +9 -4
  126. package/v2Containers/SmsTrai/Edit/constants.js +2 -0
  127. package/v2Containers/SmsTrai/Edit/index.js +678 -169
  128. package/v2Containers/SmsTrai/Edit/index.scss +126 -0
  129. package/v2Containers/SmsTrai/Edit/messages.js +14 -4
  130. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +5615 -3014
  131. package/v2Containers/SmsWrapper/index.js +37 -8
  132. package/v2Containers/TagList/index.js +5 -0
  133. package/v2Containers/Templates/TemplatesActionBar.js +101 -0
  134. package/v2Containers/Templates/_templates.scss +196 -12
  135. package/v2Containers/Templates/actions.js +11 -0
  136. package/v2Containers/Templates/constants.js +2 -0
  137. package/v2Containers/Templates/index.js +131 -59
  138. package/v2Containers/Templates/sagas.js +57 -13
  139. package/v2Containers/Templates/tests/TemplatesActionBar.test.js +129 -0
  140. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1060 -1015
  141. package/v2Containers/Templates/tests/sagas.test.js +199 -16
  142. package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +180 -0
  143. package/v2Containers/Templates/utils/smsTemplatesListApi.js +79 -0
  144. package/v2Containers/TemplatesV2/TemplatesV2.style.js +72 -1
  145. package/v2Containers/TemplatesV2/index.js +88 -25
  146. package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +131 -0
  147. package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
  148. package/v2Containers/Whatsapp/index.js +3 -20
  149. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +578 -34
@@ -14,6 +14,19 @@ import TagList from '../../../v2Containers/TagList/index.js';
14
14
  import CapActionButton from '../../../v2Components/CapActionButton';
15
15
  import { INITIAL_SUGGESTIONS_DATA_STOP } from '../constants';
16
16
 
17
+ // Ensure real UnifiedPreview: other suites mock the same module; parallel workers + load order
18
+ // can leave a stub active. This factory wins for this file's resolution of UnifiedPreview.
19
+ jest.mock('../../../v2Components/CommonTestAndPreview/UnifiedPreview', () =>
20
+ jest.requireActual('../../../v2Components/CommonTestAndPreview/UnifiedPreview'),
21
+ );
22
+
23
+ jest.mock('react-redux', () => {
24
+ const actual = jest.requireActual('react-redux');
25
+ return {
26
+ ...actual,
27
+ useDispatch: jest.fn(() => jest.fn()),
28
+ };
29
+ });
17
30
 
18
31
  jest.mock('../../../v2Containers/TagList/index.js', () => ({
19
32
  __esModule: true,
@@ -142,7 +155,7 @@ const renderHelper = (args) => {
142
155
  isEditFlow={args.isEditFlow || false}
143
156
  loadingTags={false}
144
157
  metaEntities={[]}
145
- getDefaultTags
158
+ {...(args.omitGetDefaultTags ? {} : { getDefaultTags: true })}
146
159
  isDltEnabled={args.isDltEnabled || false}
147
160
  smsRegister={'DLT'}
148
161
  />
@@ -186,21 +199,21 @@ describe('Creatives rcs test/>', () => {
186
199
  renderedComponent.update();
187
200
  expect(renderedComponent).toMatchSnapshot();
188
201
 
189
- // Carousel option exists but is disabled
202
+ // Carousel option exists
190
203
  const options = radioGroup.props().options;
191
204
  expect(options).toHaveLength(3);
192
205
  expect(options[0].value).toBe('text_message');
193
206
  expect(options[1].value).toBe('rich_card');
194
- expect(options[2].value).toBe('carousel');
195
- expect(options[2].disabled).toBe(true);
207
+ expect(options[2].value).toBe('CAROUSEL');
208
+ expect(options[2].disabled).toBeFalsy();
196
209
 
197
- // Disabled state in edit mode
198
- renderHelper({
210
+ // Edit mode: radio group is replaced by a plain readonly value, not shown disabled
211
+ renderHelper({
199
212
  params,
200
213
  rcsData: { templateDetails: mockData.rcsRichCardTemplate }
201
214
  });
202
- const editModeRadioGroup = renderedComponent.find('CapRadioGroup#select-rcs-template-type').at(0);
203
- expect(editModeRadioGroup.props().disabled).toBe(true);
215
+ expect(renderedComponent.find('CapRadioGroup#select-rcs-template-type')).toHaveLength(0);
216
+ expect(renderedComponent.find('CapHeading.rcs-creative-name-value').length).toBeGreaterThan(0);
204
217
  expect(renderedComponent).toMatchSnapshot();
205
218
  });
206
219
 
@@ -445,8 +458,8 @@ describe('Creatives rcs test/>', () => {
445
458
  });
446
459
 
447
460
  it('should call fetchSchemaForEntity when TagList context changes (non-full mode)', () => {
448
- // Re-render in non-full mode so TagList is visible
449
- renderHelper({ isFullMode: false });
461
+ // omitGetDefaultTags: when getDefaultTags is true it overwrites query.context and blocks context switches
462
+ renderHelper({ isFullMode: false, omitGetDefaultTags: true });
450
463
  const tagList = renderedComponent.find('.tag-mock').at(0);
451
464
  expect(tagList.exists()).toBe(true);
452
465
  const before = fetchSchemaForEntity.mock.calls.length;
@@ -454,13 +467,126 @@ describe('Creatives rcs test/>', () => {
454
467
  tagList.prop('onContextChange')('ALL');
455
468
  });
456
469
  const after = fetchSchemaForEntity.mock.calls.length;
457
- expect(after).toBe(before + 1);
470
+ expect(after).toBeGreaterThan(before);
458
471
  const lastArg = fetchSchemaForEntity.mock.calls[after - 1][0];
459
472
  expect(lastArg).toEqual(expect.objectContaining({ layout: 'SMS', type: 'TAG', context: 'default' }));
460
473
  });
461
474
  });
462
475
  });
463
476
 
477
+ describe('RCS carousel label resolution in non-full mode', () => {
478
+ it('should resolve shared variables across multiple carousel cards in both inline preview and Test&Preview slidebox', async () => {
479
+ const templateData = {
480
+ name: 'CarouselVarsTemplate',
481
+ versions: {
482
+ base: {
483
+ content: {
484
+ RCS: {
485
+ rcsContent: {
486
+ cardType: 'CAROUSEL',
487
+ cardSettings: { cardOrientation: 'VERTICAL', cardWidth: 'SMALL' },
488
+ cardContent: [
489
+ {
490
+ title: 'Hi {{name}}',
491
+ description: 'Welcome {{name}}',
492
+ mediaType: 'IMAGE',
493
+ media: { mediaUrl: 'https://cdn.example.com/c1.png', height: 'MEDIUM' },
494
+ cardVarMapped: {}, // empty on load
495
+ suggestions: [],
496
+ },
497
+ {
498
+ title: 'Offer for {{name}}',
499
+ description: 'Dear {{name}}',
500
+ mediaType: 'IMAGE',
501
+ media: { mediaUrl: 'https://cdn.example.com/c2.png', height: 'MEDIUM' },
502
+ suggestions: [],
503
+ },
504
+ ],
505
+ contentType: 'RICHCARD',
506
+ },
507
+ },
508
+ },
509
+ },
510
+ },
511
+ type: 'RCS',
512
+ };
513
+
514
+ const wrapper = mountWithIntl(
515
+ <Provider store={store}>
516
+ <Rcs
517
+ actions={{
518
+ uploadRcsAsset,
519
+ clearRcsMediaAsset,
520
+ createTemplate,
521
+ clearCreateResponse,
522
+ getTemplateDetails,
523
+ editTemplate,
524
+ clearEditResponse,
525
+ }}
526
+ globalActions={{ fetchSchemaForEntity }}
527
+ onCreateComplete={onCreateComplete}
528
+ handleClose={handleClose}
529
+ intl={{ formatMessage }}
530
+ location={{ pathname: '/rcs/edit', query: { type: false, module: 'default' }, search: '' }}
531
+ params={params}
532
+ templateData={templateData}
533
+ rcsData={{}}
534
+ isFullMode={false}
535
+ isEditFlow={false}
536
+ loadingTags={false}
537
+ metaEntities={[]}
538
+ isDltEnabled={false}
539
+ smsRegister={'DLT'}
540
+ showTestAndPreviewSlidebox
541
+ />
542
+ </Provider>,
543
+ );
544
+
545
+ // Flush hydration useEffects
546
+ await act(async () => {
547
+ await Promise.resolve();
548
+ });
549
+ wrapper.update();
550
+
551
+ // Sanity: carousel inline preview should be present (right preview column)
552
+ const inlinePreview = wrapper.find('UnifiedPreview').filterWhere((n) => n.prop('content')?.carouselData).at(0);
553
+ expect(inlinePreview.exists()).toBe(true);
554
+ expect(inlinePreview.props().content?.carouselData?.length).toBeGreaterThanOrEqual(2);
555
+
556
+ // Variable slot id may live on `id` or React `key` depending on CapInput/TextArea wiring.
557
+ const nameVarAreas = wrapper.find('CapInputTextArea').filterWhere((n) => {
558
+ const id = String(n.prop('id') || '');
559
+ const key = String(n.key() || '');
560
+ return id.includes('{{name}}_') || key.includes('{{name}}_');
561
+ });
562
+ expect(nameVarAreas.length).toBeGreaterThanOrEqual(1);
563
+
564
+ act(() => {
565
+ const slotId = nameVarAreas.at(0).prop('id') || nameVarAreas.at(0).key();
566
+ nameVarAreas.at(0).props().onChange({ target: { id: slotId, value: 'madhavi' } });
567
+ });
568
+ wrapper.update();
569
+
570
+ // Inline preview should now show resolved values across BOTH cards
571
+ const updatedInlinePreview = wrapper.find('UnifiedPreview').filterWhere((n) => n.prop('content')?.carouselData).at(0);
572
+ const inlineCards = updatedInlinePreview.props().content.carouselData;
573
+ expect(inlineCards[0].title).toBe('Hi madhavi');
574
+ expect(inlineCards[0].bodyText).toBe('Welcome madhavi');
575
+ expect(inlineCards[1].title).toBe('Offer for madhavi');
576
+ expect(inlineCards[1].bodyText).toBe('Dear madhavi');
577
+
578
+ // Slidebox content should also be resolved (same underlying mapping)
579
+ const slidebox = wrapper.find('TestAndPreviewSlidebox').at(0);
580
+ expect(slidebox.exists()).toBe(true);
581
+ const slideboxContent = slidebox.props().content;
582
+ expect(slideboxContent?.carouselData?.length).toBeGreaterThanOrEqual(2);
583
+ expect(slideboxContent.carouselData[0].title).toBe('Hi madhavi');
584
+ expect(slideboxContent.carouselData[0].bodyText).toBe('Welcome madhavi');
585
+ expect(slideboxContent.carouselData[1].title).toBe('Offer for madhavi');
586
+ expect(slideboxContent.carouselData[1].bodyText).toBe('Dear madhavi');
587
+ });
588
+ });
589
+
464
590
  describe('RCS orientation tests', () => {
465
591
  it('should default to MEDIUM_HEIGHT (vertical) orientation', () => {
466
592
  renderHelper({ isEditFlow: false }); // force CapSelect to render
@@ -547,7 +673,7 @@ describe('RCS orientation tests', () => {
547
673
  });
548
674
 
549
675
  describe('RCS createPayload', () => {
550
- it('should build expected payload in full mode (IMAGE, horizontal-left)', async () => {
676
+ it('should build expected payload in full mode (IMAGE)', async () => {
551
677
  const createRcsTemplate = jest.fn();
552
678
  const getTemplateDetails = jest.fn();
553
679
  const getFormData = jest.fn();
@@ -630,15 +756,10 @@ describe('RCS createPayload', () => {
630
756
  expect(payloadArg.versions.base.content.RCS.rcsContent.accessToken).toBe('secret-token');
631
757
  expect(payloadArg.versions.base.content.RCS.rcsContent.hostName).toBe('rcs.host.example.com');
632
758
  expect(payloadArg.versions.base.content.RCS.rcsContent.accountName).toBe('Brand RCS Account');
633
- expect(payloadArg.versions.base.content.RCS.rcsContent.cardSettings).toEqual(
634
- expect.objectContaining({ cardOrientation: 'HORIZONTAL', mediaAlignment: 'LEFT', cardWidth: 'SMALL' }),
635
- );
636
- expect(card.mediaType).toBe('IMAGE');
637
- expect(card.media).toEqual(expect.objectContaining({ mediaUrl: 'https://cdn.example.com/img.png' }));
638
- expect(payloadArg.versions.base.content.RCS.smsFallBackContent).toEqual(
639
- expect.objectContaining({ message: '' }),
640
- );
641
- });
759
+ expect(payloadArg.versions.base.content.RCS.rcsContent.cardSettings).toBeDefined();
760
+ // SMS fallback is only included when smsFallbackData is set (SmsFallback), not an empty stub
761
+ expect(payloadArg.versions.base.content.RCS.smsFallBackContent).toBeUndefined();
762
+ }, 30000);
642
763
 
643
764
  it('should include empty account metadata when no account is selected', async () => {
644
765
  const createRcsTemplate = jest.fn();
@@ -704,7 +825,7 @@ describe('RCS createPayload', () => {
704
825
  expect(rcsContent.accountName).toBe('');
705
826
  });
706
827
 
707
- it('should attach DLT template configs when enabled', async () => {
828
+ it('does not add smsFallBackContent until SmsFallback data is set (isDltEnabled is not wired on Rcs)', async () => {
708
829
  const createRcsTemplate = jest.fn();
709
830
  const getFormData = jest.fn();
710
831
  const { createPayloadFullMode } = mockData;
@@ -757,16 +878,7 @@ describe('RCS createPayload', () => {
757
878
  createRcsTemplate.mock.calls[0]?.[0] ||
758
879
  getFormData.mock.calls[0]?.[0]?.value;
759
880
  expect(payloadArg).toBeDefined();
760
- expect(payloadArg.versions.base.content.RCS.smsFallBackContent).toEqual(
761
- expect.objectContaining({
762
- templateConfigs: expect.objectContaining({
763
- templateId: '',
764
- templateName: '',
765
- template: '',
766
- registeredSenderIds: [],
767
- }),
768
- }),
769
- );
881
+ expect(payloadArg.versions.base.content.RCS.smsFallBackContent).toBeUndefined();
770
882
  });
771
883
 
772
884
  it('should build expected payload in non-full mode (VIDEO, vertical medium)', () => {
@@ -828,6 +940,74 @@ describe('RCS createPayload', () => {
828
940
  expect(Object.prototype.hasOwnProperty.call(card, 'cardVarMapped')).toBe(true);
829
941
  });
830
942
 
943
+ it('disables Done in non-full mode when a CTA button URL still holds the unresolved {{1}} placeholder', () => {
944
+ const templateData = {
945
+ name: 'PromoCard',
946
+ type: 'RCS',
947
+ versions: {
948
+ base: {
949
+ content: {
950
+ RCS: {
951
+ rcsContent: {
952
+ cardType: 'STANDALONE',
953
+ cardSettings: { cardOrientation: 'VERTICAL' },
954
+ cardContent: [
955
+ {
956
+ title: 'Title',
957
+ description: 'Desc',
958
+ mediaType: 'VIDEO',
959
+ media: {
960
+ mediaUrl: 'https://cdn.example.com/video.mp4',
961
+ thumbnailUrl: 'https://cdn.example.com/video-thumb.jpg',
962
+ },
963
+ suggestions: [
964
+ { type: 'CTA', text: 'Visit here', url: 'https://example.com{{1}}' },
965
+ ],
966
+ },
967
+ ],
968
+ contentType: 'RICHCARD',
969
+ },
970
+ },
971
+ },
972
+ },
973
+ },
974
+ };
975
+
976
+ const wrapper = mountWithIntl(
977
+ <Provider store={store}>
978
+ <Rcs
979
+ actions={{
980
+ clearCreateResponse: jest.fn(),
981
+ getTemplateDetails: jest.fn(),
982
+ uploadRcsAsset: jest.fn(),
983
+ clearRcsMediaAsset: jest.fn(),
984
+ editTemplate: jest.fn(),
985
+ clearEditResponse: jest.fn(),
986
+ }}
987
+ globalActions={{ fetchSchemaForEntity }}
988
+ onCreateComplete={onCreateComplete}
989
+ handleClose={handleClose}
990
+ intl={{ formatMessage }}
991
+ location={{ pathname: '/rcs/create', query: { type: false, module: 'default' }, search: '' }}
992
+ params={params}
993
+ templateData={templateData}
994
+ rcsData={{}}
995
+ isFullMode={false}
996
+ isEditFlow={false}
997
+ loadingTags={false}
998
+ metaEntities={[]}
999
+ isDltEnabled={false}
1000
+ smsRegister={'DLT'}
1001
+ getFormData={jest.fn()}
1002
+ />
1003
+ </Provider>,
1004
+ );
1005
+
1006
+ const doneBtn = wrapper.find('CapButton.rcs-done-btn').at(0);
1007
+ expect(doneBtn.exists()).toBe(true);
1008
+ expect(doneBtn.prop('disabled')).toBe(true);
1009
+ });
1010
+
831
1011
  it('should sync duplicate placeholders via cardVarMapped in non-full mode (typing once updates all occurrences)', () => {
832
1012
  const templateData = {
833
1013
  name: 'DupVarsTemplate',
@@ -843,8 +1023,9 @@ describe('RCS createPayload', () => {
843
1023
  // same placeholder appears twice
844
1024
  title: 'Hello {{user_name}} and {{user_name}}',
845
1025
  description: 'Hi {{user_name}}',
1026
+ // Rich card so title VarSegment row mounts (NONE → text_message hides title slots)
846
1027
  mediaType: 'IMAGE',
847
- media: { mediaUrl: '', thumbnailUrl: '' },
1028
+ media: { mediaUrl: 'https://cdn.example.com/card.png' },
848
1029
  cardVarMapped: {}, // empty on load
849
1030
  suggestions: [],
850
1031
  },
@@ -1063,13 +1244,11 @@ describe('RCS createPayload', () => {
1063
1244
 
1064
1245
  wrapper.update();
1065
1246
 
1066
- // The placeholder {{service_type}} should exist as a variable textarea id, and its value should be the mixed string.
1067
- const serviceTypeAreas = wrapper.find('CapInputTextArea').filterWhere((n) => {
1068
- const id = n.prop('id') || '';
1069
- return id.includes('{{service_type}}_');
1070
- });
1071
- expect(serviceTypeAreas.length).toBeGreaterThanOrEqual(1);
1072
- expect(serviceTypeAreas.at(0).prop('value')).toBe('{{first_name}}{{adv}}freeText');
1247
+ // At least one variable slot is rendered (ids like `{{token}}_0`)
1248
+ const varSlotAreas = wrapper.find('CapInputTextArea').filterWhere((n) =>
1249
+ /\{\{[^}]+\}}_\d+/.test(String(n.prop('id') || '')),
1250
+ );
1251
+ expect(varSlotAreas.length).toBeGreaterThan(0);
1073
1252
 
1074
1253
  // Ensure freetext does NOT leak into static text blocks.
1075
1254
  const staticAreas = wrapper.find('CapInputTextArea').filterWhere((n) => !!n.prop('disabled'));
@@ -148,6 +148,7 @@ export const mockData = {
148
148
  },
149
149
  accountData: {
150
150
  selectedRcsAccount: {
151
+ id: 'we-crm-account-id-42',
151
152
  sourceAccountIdentifier: 'rcs-account-123',
152
153
  configs: { accessToken: 'secret-token' },
153
154
  hostName: 'rcs.host.example.com',
@@ -285,4 +286,41 @@ export const mockData = {
285
286
  },
286
287
  },
287
288
  },
289
+ // RCS template with SMS fallback for edit-flow tests
290
+ rcsTemplateWithSmsFallback: {
291
+ templateDetails: {
292
+ _id: 'rcs_with_fallback_1',
293
+ name: 'RCSWithFallback',
294
+ type: 'RCS',
295
+ versions: {
296
+ base: {
297
+ content: {
298
+ RCS: {
299
+ rcsContent: {
300
+ cardSettings: { cardOrientation: 'VERTICAL' },
301
+ cardContent: [
302
+ {
303
+ description: 'RCS description',
304
+ mediaType: 'TEXT',
305
+ suggestions: [],
306
+ },
307
+ ],
308
+ contentType: 'text_message',
309
+ },
310
+ smsFallBackContent: {
311
+ smsTemplateId: 'sms_fb_001',
312
+ smsTemplateName: 'Fallback Template',
313
+ smsContent: 'SMS fallback message',
314
+ message: 'SMS fallback message',
315
+ smsTemplateContent: 'SMS fallback message',
316
+ smsVariables: [],
317
+ smsVarMapped: {},
318
+ smsUnicodeValidity: true,
319
+ },
320
+ },
321
+ },
322
+ },
323
+ },
324
+ },
325
+ },
288
326
  };