@capillarytech/creatives-library 9.0.15-alpha.1 → 9.0.16

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 (132) hide show
  1. package/constants/unified.js +0 -29
  2. package/global-styles.js +1 -1
  3. package/package.json +1 -1
  4. package/services/tests/api.test.js +20 -35
  5. package/utils/commonUtils.js +1 -19
  6. package/v2Components/CapActionButton/constants.js +0 -7
  7. package/v2Components/CapActionButton/index.js +109 -168
  8. package/v2Components/CapActionButton/index.scss +5 -156
  9. package/v2Components/CapActionButton/messages.js +3 -19
  10. package/v2Components/CapActionButton/tests/index.test.js +18 -42
  11. package/v2Components/CapImageUpload/index.js +2 -2
  12. package/v2Components/CapTagList/index.js +0 -10
  13. package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +48 -70
  14. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +2 -8
  15. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +21 -214
  16. package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +0 -16
  17. package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +9 -83
  18. package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +0 -30
  19. package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +11 -60
  20. package/v2Components/CommonTestAndPreview/SendTestMessage.js +5 -10
  21. package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +23 -201
  22. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +76 -355
  23. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +8 -155
  24. package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +0 -11
  25. package/v2Components/CommonTestAndPreview/constants.js +2 -38
  26. package/v2Components/CommonTestAndPreview/index.js +222 -761
  27. package/v2Components/CommonTestAndPreview/messages.js +3 -45
  28. package/v2Components/CommonTestAndPreview/sagas.js +6 -25
  29. package/v2Components/CommonTestAndPreview/tests/CommonTestAndPreview.addTestCustomer.test.js +0 -1
  30. package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +267 -284
  31. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +65 -231
  32. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +5 -118
  33. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +0 -341
  34. package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +1 -8
  35. package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +13 -34
  36. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +283 -281
  37. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +1 -199
  38. package/v2Components/CommonTestAndPreview/tests/index.test.js +4 -133
  39. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +24 -31
  40. package/v2Components/TemplatePreview/_templatePreview.scss +22 -41
  41. package/v2Components/TemplatePreview/index.js +31 -143
  42. package/v2Components/TemplatePreview/tests/index.test.js +0 -142
  43. package/v2Components/TestAndPreviewSlidebox/CustomValuesEditor.js +6 -6
  44. package/v2Components/TestAndPreviewSlidebox/index.js +1 -13
  45. package/v2Components/TestAndPreviewSlidebox/sagas.js +4 -11
  46. package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +1 -3
  47. package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +1 -4
  48. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +0 -4
  49. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +20 -20
  50. package/v2Containers/CreativesContainer/SlideBoxContent.js +7 -36
  51. package/v2Containers/CreativesContainer/SlideBoxFooter.js +5 -14
  52. package/v2Containers/CreativesContainer/SlideBoxHeader.js +5 -36
  53. package/v2Containers/CreativesContainer/constants.js +0 -11
  54. package/v2Containers/CreativesContainer/index.js +104 -323
  55. package/v2Containers/CreativesContainer/index.scss +1 -83
  56. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +34 -79
  57. package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +16 -79
  58. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -8
  59. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +90 -333
  60. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +15 -20
  61. package/v2Containers/CreativesContainer/tests/index.test.js +9 -71
  62. package/v2Containers/Email/index.js +5 -2
  63. package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
  64. package/v2Containers/Rcs/constants.js +11 -131
  65. package/v2Containers/Rcs/index.js +810 -2605
  66. package/v2Containers/Rcs/index.scss +8 -289
  67. package/v2Containers/Rcs/messages.js +3 -34
  68. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +38537 -73535
  69. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +8 -0
  70. package/v2Containers/Rcs/tests/index.test.js +36 -147
  71. package/v2Containers/Rcs/tests/mockData.js +0 -38
  72. package/v2Containers/Rcs/tests/utils.test.js +30 -646
  73. package/v2Containers/Rcs/utils.js +11 -478
  74. package/v2Containers/Sms/Create/index.js +48 -115
  75. package/v2Containers/SmsTrai/Create/index.js +4 -9
  76. package/v2Containers/SmsTrai/Edit/constants.js +0 -2
  77. package/v2Containers/SmsTrai/Edit/index.js +169 -678
  78. package/v2Containers/SmsTrai/Edit/messages.js +4 -14
  79. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +2854 -5455
  80. package/v2Containers/SmsWrapper/index.js +8 -37
  81. package/v2Containers/TagList/index.js +0 -6
  82. package/v2Containers/Templates/_templates.scss +12 -171
  83. package/v2Containers/Templates/actions.js +0 -11
  84. package/v2Containers/Templates/constants.js +0 -2
  85. package/v2Containers/Templates/index.js +55 -125
  86. package/v2Containers/Templates/sagas.js +13 -57
  87. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1015 -1060
  88. package/v2Containers/Templates/tests/sagas.test.js +16 -199
  89. package/v2Containers/TemplatesV2/TemplatesV2.style.js +1 -72
  90. package/v2Containers/TemplatesV2/index.js +23 -86
  91. package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
  92. package/v2Containers/Whatsapp/index.js +20 -3
  93. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -578
  94. package/utils/rcsPayloadUtils.js +0 -92
  95. package/utils/templateVarUtils.js +0 -201
  96. package/utils/tests/rcsPayloadUtils.test.js +0 -226
  97. package/utils/tests/templateVarUtils.test.js +0 -204
  98. package/v2Components/CommonTestAndPreview/previewApiUtils.js +0 -59
  99. package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +0 -67
  100. package/v2Components/CommonTestAndPreview/utils.js +0 -84
  101. package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +0 -91
  102. package/v2Components/SmsFallback/constants.js +0 -94
  103. package/v2Components/SmsFallback/index.js +0 -958
  104. package/v2Components/SmsFallback/index.scss +0 -266
  105. package/v2Components/SmsFallback/messages.js +0 -78
  106. package/v2Components/SmsFallback/smsFallbackUtils.js +0 -120
  107. package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +0 -50
  108. package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +0 -147
  109. package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +0 -304
  110. package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +0 -208
  111. package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +0 -309
  112. package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +0 -422
  113. package/v2Components/SmsFallback/useLocalTemplateList.js +0 -92
  114. package/v2Components/TemplatePreview/constants.js +0 -2
  115. package/v2Components/VarSegmentMessageEditor/constants.js +0 -2
  116. package/v2Components/VarSegmentMessageEditor/index.js +0 -125
  117. package/v2Components/VarSegmentMessageEditor/index.scss +0 -46
  118. package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +0 -17
  119. package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +0 -79
  120. package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +0 -90
  121. package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +0 -258
  122. package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +0 -125
  123. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +0 -227
  124. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -318
  125. package/v2Containers/Sms/smsFormDataHelpers.js +0 -67
  126. package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +0 -253
  127. package/v2Containers/SmsTrai/Edit/index.scss +0 -126
  128. package/v2Containers/Templates/TemplatesActionBar.js +0 -101
  129. package/v2Containers/Templates/tests/TemplatesActionBar.test.js +0 -120
  130. package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +0 -180
  131. package/v2Containers/Templates/utils/smsTemplatesListApi.js +0 -79
  132. package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +0 -131
@@ -9,16 +9,7 @@ import { render, screen } from '@testing-library/react';
9
9
  import '@testing-library/jest-dom';
10
10
  import { injectIntl, IntlProvider } from 'react-intl';
11
11
  import UnifiedPreview from '../../UnifiedPreview';
12
- import {
13
- CHANNELS,
14
- DESKTOP,
15
- TABLET,
16
- MOBILE,
17
- ANDROID,
18
- IOS,
19
- PREVIEW_TAB_RCS,
20
- PREVIEW_TAB_SMS_FALLBACK,
21
- } from '../../constants';
12
+ import { CHANNELS, DESKTOP, TABLET, MOBILE, ANDROID, IOS } from '../../constants';
22
13
  import messages from '../../messages';
23
14
 
24
15
  // Convert messages object to format expected by IntlProvider
@@ -571,195 +562,6 @@ describe('UnifiedPreview', () => {
571
562
 
572
563
  expect(screen.getByTestId('rcs-sender-id')).toHaveTextContent('RCS_SENDER');
573
564
  });
574
-
575
- describe('RCS SMS fallback — Test & Preview tabs', () => {
576
- it('without SMS fallback selected, shows only RCS preview (no RCS+SMS tab layout)', () => {
577
- const props = {
578
- ...defaultProps,
579
- channel: CHANNELS.RCS,
580
- content: { rcsTitle: 'Hello RCS' },
581
- smsFallbackContent: undefined,
582
- };
583
-
584
- const { container } = render(
585
- <TestWrapper>
586
- <ComponentToRender {...props} />
587
- </TestWrapper>
588
- );
589
-
590
- expect(container.querySelector('.unified-preview-rcs-tabs')).toBeNull();
591
- expect(screen.getByTestId('rcs-preview')).toBeInTheDocument();
592
- expect(screen.queryByTestId('sms-preview')).not.toBeInTheDocument();
593
- });
594
-
595
- it('with SMS fallback template body, shows RCS and Fallback SMS tabs', () => {
596
- const props = {
597
- ...defaultProps,
598
- channel: CHANNELS.RCS,
599
- content: { rcsTitle: 'Hello RCS' },
600
- smsFallbackContent: {
601
- content: 'SMS fallback body',
602
- templateContent: 'SMS fallback body',
603
- },
604
- };
605
-
606
- const { container } = render(
607
- <TestWrapper>
608
- <ComponentToRender {...props} />
609
- </TestWrapper>
610
- );
611
-
612
- expect(container.querySelector('.unified-preview-rcs-tabs')).toBeInTheDocument();
613
- expect(
614
- screen.getByRole('tab', { name: messages.rcsTab.defaultMessage })
615
- ).toBeInTheDocument();
616
- expect(
617
- screen.getByRole('tab', { name: messages.smsFallbackTab.defaultMessage })
618
- ).toBeInTheDocument();
619
- });
620
-
621
- it('on SMS fallback tab, renders SMS preview with resolved fallback text when smsFallbackResolvedText is set', () => {
622
- const props = {
623
- ...defaultProps,
624
- channel: CHANNELS.RCS,
625
- content: { rcsTitle: 'Hello RCS' },
626
- smsFallbackContent: {
627
- content: '{{var}}',
628
- templateContent: '{{var}}',
629
- },
630
- smsFallbackResolvedText: 'Resolved SMS for preview',
631
- activePreviewTab: PREVIEW_TAB_SMS_FALLBACK,
632
- onPreviewTabChange: jest.fn(),
633
- };
634
-
635
- render(
636
- <TestWrapper>
637
- <ComponentToRender {...props} />
638
- </TestWrapper>
639
- );
640
-
641
- expect(screen.getByTestId('sms-content')).toHaveTextContent('Resolved SMS for preview');
642
- });
643
-
644
- it('on RCS tab (default), renders RCS preview when dual tabs are shown', () => {
645
- const props = {
646
- ...defaultProps,
647
- channel: CHANNELS.RCS,
648
- content: { rcsTitle: 'Only RCS pane' },
649
- smsFallbackContent: { content: 'SMS', templateContent: 'SMS' },
650
- activePreviewTab: PREVIEW_TAB_RCS,
651
- onPreviewTabChange: jest.fn(),
652
- };
653
-
654
- render(
655
- <TestWrapper>
656
- <ComponentToRender {...props} />
657
- </TestWrapper>
658
- );
659
-
660
- expect(screen.getByTestId('rcs-preview')).toBeInTheDocument();
661
- expect(screen.getByTestId('rcs-content')).toHaveTextContent(/Only RCS pane/);
662
- });
663
-
664
- it('on SMS fallback tab, shows raw template when no varmap and no resolved text', () => {
665
- const props = {
666
- ...defaultProps,
667
- channel: CHANNELS.RCS,
668
- content: { rcsTitle: 'Hello RCS' },
669
- smsFallbackContent: {
670
- content: 'Hello {{name}}',
671
- templateContent: 'Hello {{name}}',
672
- // no rcsSmsFallbackVarMapped
673
- },
674
- smsFallbackResolvedText: undefined,
675
- activePreviewTab: PREVIEW_TAB_SMS_FALLBACK,
676
- onPreviewTabChange: jest.fn(),
677
- };
678
-
679
- render(
680
- <TestWrapper>
681
- <ComponentToRender {...props} />
682
- </TestWrapper>
683
- );
684
-
685
- // rawFallbackTemplate is shown directly — {{tags}} remain visible
686
- expect(screen.getByTestId('sms-content')).toHaveTextContent('Hello {{name}}');
687
- });
688
-
689
- it('on SMS fallback tab, treats empty resolved text as absent and shows raw template', () => {
690
- const props = {
691
- ...defaultProps,
692
- channel: CHANNELS.RCS,
693
- content: { rcsTitle: 'Hello RCS' },
694
- smsFallbackContent: {
695
- content: 'Raw {{var}} template',
696
- templateContent: 'Raw {{var}} template',
697
- },
698
- smsFallbackResolvedText: '',
699
- activePreviewTab: PREVIEW_TAB_SMS_FALLBACK,
700
- onPreviewTabChange: jest.fn(),
701
- };
702
-
703
- render(
704
- <TestWrapper>
705
- <ComponentToRender {...props} />
706
- </TestWrapper>
707
- );
708
-
709
- expect(screen.getByTestId('sms-content')).toHaveTextContent('Raw {{var}} template');
710
- });
711
-
712
- it('on SMS fallback tab, applies varmap slot substitution when varmap entries exist and no resolved text', () => {
713
- // getFallbackResolvedContent key format: `${fullToken}_${segmentIndex}`
714
- // 'Hello {{name}}' → segments ['Hello ', '{{name}}'], so {{name}} is at index 1 → key '{{name}}_1'
715
- const props = {
716
- ...defaultProps,
717
- channel: CHANNELS.RCS,
718
- content: { rcsTitle: 'Hello RCS' },
719
- smsFallbackContent: {
720
- content: 'Hello {{name}}',
721
- templateContent: 'Hello {{name}}',
722
- rcsSmsFallbackVarMapped: { '{{name}}_1': 'World' },
723
- },
724
- smsFallbackResolvedText: undefined,
725
- activePreviewTab: PREVIEW_TAB_SMS_FALLBACK,
726
- onPreviewTabChange: jest.fn(),
727
- };
728
-
729
- render(
730
- <TestWrapper>
731
- <ComponentToRender {...props} />
732
- </TestWrapper>
733
- );
734
-
735
- expect(screen.getByTestId('sms-content')).toHaveTextContent('Hello World');
736
- });
737
-
738
- it('on SMS fallback tab, resolved text takes priority over varmap entries', () => {
739
- const props = {
740
- ...defaultProps,
741
- channel: CHANNELS.RCS,
742
- content: { rcsTitle: 'Hello RCS' },
743
- smsFallbackContent: {
744
- content: 'Hello {{name}}',
745
- templateContent: 'Hello {{name}}',
746
- rcsSmsFallbackVarMapped: { '{{name}}_1': 'World' },
747
- },
748
- smsFallbackResolvedText: 'Hello John',
749
- activePreviewTab: PREVIEW_TAB_SMS_FALLBACK,
750
- onPreviewTabChange: jest.fn(),
751
- };
752
-
753
- render(
754
- <TestWrapper>
755
- <ComponentToRender {...props} />
756
- </TestWrapper>
757
- );
758
-
759
- // resolvedText wins over varmap substitution
760
- expect(screen.getByTestId('sms-content')).toHaveTextContent('Hello John');
761
- });
762
- });
763
565
  });
764
566
 
765
567
  describe('Channel Routing - INAPP', () => {
@@ -30,28 +30,23 @@ jest.mock('@capillarytech/cap-ui-library/CapNotification', () => ({
30
30
  }));
31
31
 
32
32
  // Mock child components - must use React.createElement to avoid hoisting issues
33
- let lastLeftPanelContentProps = null;
34
33
  jest.mock('../LeftPanelContent', () => {
35
34
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies
36
35
  const ReactLib = require('react');
37
36
  return {
38
37
  __esModule: true,
39
- default: function MockLeftPanelContent(props) {
40
- lastLeftPanelContentProps = props;
41
- const editorEl = props.renderCustomValuesEditor ? props.renderCustomValuesEditor() : null;
42
- return ReactLib.createElement('div', { 'data-testid': 'left-panel' }, 'Left Panel', editorEl);
38
+ default: function MockLeftPanelContent() {
39
+ return ReactLib.createElement('div', { 'data-testid': 'left-panel' }, 'Left Panel');
43
40
  },
44
41
  };
45
42
  });
46
43
 
47
- let lastCustomValuesEditorProps = null;
48
44
  jest.mock('../CustomValuesEditor', () => {
49
45
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies
50
46
  const ReactLib = require('react');
51
47
  return {
52
48
  __esModule: true,
53
- default: function MockCustomValuesEditor(props) {
54
- lastCustomValuesEditorProps = props;
49
+ default: function MockCustomValuesEditor() {
55
50
  return ReactLib.createElement('div', { 'data-testid': 'custom-values-editor' }, 'Custom Values Editor');
56
51
  },
57
52
  };
@@ -196,8 +191,6 @@ describe('CommonTestAndPreview', () => {
196
191
  beforeEach(() => {
197
192
  jest.clearAllMocks();
198
193
  lastSendTestMessageProps = null;
199
- lastLeftPanelContentProps = null;
200
- lastCustomValuesEditorProps = null;
201
194
  // Reset all mock function implementations
202
195
  Object.values(mockActions).forEach((mockFn) => {
203
196
  if (jest.isMockFunction(mockFn)) {
@@ -252,25 +245,6 @@ describe('CommonTestAndPreview', () => {
252
245
  });
253
246
  });
254
247
 
255
- it('should call getSenderDetailsRequested for RCS and SMS when channel is RCS', async () => {
256
- render(
257
- <TestWrapper>
258
- <CommonTestAndPreview {...defaultProps} channel={CHANNELS.RCS} />
259
- </TestWrapper>
260
- );
261
- await waitFor(() => {
262
- expect(mockActions.getSenderDetailsRequested).toHaveBeenCalledTimes(2);
263
- expect(mockActions.getSenderDetailsRequested).toHaveBeenNthCalledWith(1, {
264
- channel: CHANNELS.RCS,
265
- orgUnitId: -1,
266
- });
267
- expect(mockActions.getSenderDetailsRequested).toHaveBeenNthCalledWith(2, {
268
- channel: CHANNELS.SMS,
269
- orgUnitId: -1,
270
- });
271
- });
272
- });
273
-
274
248
  it('should not call getSenderDetailsRequested when channel is INAPP', async () => {
275
249
  render(
276
250
  <TestWrapper>
@@ -329,7 +303,7 @@ describe('CommonTestAndPreview', () => {
329
303
  });
330
304
  expect(lastSendTestMessageProps).toBeDefined();
331
305
  expect(lastSendTestMessageProps.deliverySettings).toBeDefined();
332
- expect(lastSendTestMessageProps.senderDetailsByChannel).toEqual(senderDetailsByChannel);
306
+ expect(lastSendTestMessageProps.senderDetailsOptions).toEqual(senderDetailsByChannel[CHANNELS.SMS]);
333
307
  expect(lastSendTestMessageProps.wecrmAccounts).toEqual([]);
334
308
  expect(typeof lastSendTestMessageProps.onSaveDeliverySettings).toBe('function');
335
309
  expect(lastSendTestMessageProps.isLoadingSenderDetails).toBe(false);
@@ -3501,107 +3475,4 @@ describe('CommonTestAndPreview', () => {
3501
3475
  });
3502
3476
  });
3503
3477
  });
3504
-
3505
- describe('SMS DLT and mustache tag discrimination (smsTemplateHasMustacheTags / buildSyntheticSmsMustacheTags)', () => {
3506
- it('should return no tags for SMS content that contains only DLT {#var#} tokens', async () => {
3507
- render(
3508
- <TestWrapper>
3509
- <CommonTestAndPreview
3510
- {...defaultProps}
3511
- channel={CHANNELS.SMS}
3512
- formData={{ 0: { 'sms-editor': 'Order {#orderId#} is confirmed' } }}
3513
- extractedTags={[]}
3514
- />
3515
- </TestWrapper>
3516
- );
3517
-
3518
- await waitFor(() => expect(lastLeftPanelContentProps).not.toBeNull());
3519
-
3520
- // smsTemplateHasMustacheTags returns false for DLT-only → extractedTags is []
3521
- expect(lastLeftPanelContentProps.extractedTags).toEqual([]);
3522
- });
3523
-
3524
- it('should build synthetic tags from {{mustache}} tokens, excluding DLT {#var#} tokens', async () => {
3525
- render(
3526
- <TestWrapper>
3527
- <CommonTestAndPreview
3528
- {...defaultProps}
3529
- channel={CHANNELS.SMS}
3530
- formData={{ 0: { 'sms-editor': 'Hi {{name}}, order {#orderId#} shipped' } }}
3531
- extractedTags={[]}
3532
- />
3533
- </TestWrapper>
3534
- );
3535
-
3536
- await waitFor(() => expect(lastLeftPanelContentProps).not.toBeNull());
3537
-
3538
- const tags = lastLeftPanelContentProps.extractedTags;
3539
- // Only {{name}} should become a tag — {#orderId#} must be excluded
3540
- expect(tags).toHaveLength(1);
3541
- expect(tags[0].name).toBe('name');
3542
- });
3543
-
3544
- it('should use API-extracted tags when present instead of building synthetic ones', async () => {
3545
- const apiTags = [{ name: 'firstName', metaData: { userDriven: true }, children: [] }];
3546
- render(
3547
- <TestWrapper>
3548
- <CommonTestAndPreview
3549
- {...defaultProps}
3550
- channel={CHANNELS.SMS}
3551
- formData={{ 0: { 'sms-editor': 'Hi {{firstName}}' } }}
3552
- extractedTags={apiTags}
3553
- />
3554
- </TestWrapper>
3555
- );
3556
-
3557
- await waitFor(() => expect(lastLeftPanelContentProps).not.toBeNull());
3558
-
3559
- // API tags take priority over buildSyntheticSmsMustacheTags
3560
- expect(lastLeftPanelContentProps.extractedTags).toEqual(apiTags);
3561
- });
3562
- });
3563
-
3564
- describe('handleDiscardCustomValues — preview reset', () => {
3565
- it('should call updatePreviewRequested when handleDiscardCustomValues is invoked', async () => {
3566
- render(
3567
- <TestWrapper>
3568
- <CommonTestAndPreview
3569
- {...defaultProps}
3570
- channel={CHANNELS.SMS}
3571
- formData={{ 0: { 'sms-editor': 'Hi {{name}}' } }}
3572
- />
3573
- </TestWrapper>
3574
- );
3575
-
3576
- await waitFor(() => expect(lastCustomValuesEditorProps).not.toBeNull());
3577
-
3578
- lastCustomValuesEditorProps.handleDiscardCustomValues();
3579
-
3580
- expect(mockActions.updatePreviewRequested).toHaveBeenCalledTimes(1);
3581
- });
3582
-
3583
- it('should call updatePreviewRequested with RCS channel when handleDiscardCustomValues is invoked for RCS with fallback', async () => {
3584
- render(
3585
- <TestWrapper>
3586
- <CommonTestAndPreview
3587
- {...defaultProps}
3588
- channel={CHANNELS.RCS}
3589
- smsFallbackContent={{
3590
- templateContent: 'Fallback {{name}}',
3591
- content: 'Fallback {{name}}',
3592
- }}
3593
- formData={{}}
3594
- />
3595
- </TestWrapper>
3596
- );
3597
-
3598
- await waitFor(() => expect(lastCustomValuesEditorProps).not.toBeNull());
3599
-
3600
- lastCustomValuesEditorProps.handleDiscardCustomValues();
3601
-
3602
- // updatePreviewRequested is called; syncSmsFallbackPreview (which hits Api directly) is NOT called
3603
- expect(mockActions.updatePreviewRequested).toHaveBeenCalledTimes(1);
3604
- });
3605
- });
3606
3478
  });
3607
-
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import {
8
- call, put, takeLatest, takeEvery, all, take, fork, cancel,
8
+ call, put, takeLatest, all,
9
9
  } from 'redux-saga/effects';
10
10
  import {
11
11
  searchCustomersSaga,
@@ -1333,26 +1333,9 @@ describe('CommonTestAndPreview Sagas', () => {
1333
1333
  it('should watch for GET_SENDER_DETAILS_REQUESTED', () => {
1334
1334
  const generator = watchGetSenderDetails();
1335
1335
  expect(generator.next().value).toEqual(
1336
- take('app/CommonTestAndPreview/GET_SENDER_DETAILS_REQUESTED')
1337
- );
1338
- const firstAction = {
1339
- payload: { channel: 'RCS', orgUnitId: 10 },
1340
- };
1341
- expect(generator.next(firstAction).value).toEqual(
1342
- fork(getSenderDetailsSaga, firstAction)
1343
- );
1344
- expect(generator.next({ '@@redux-saga/TASK': true }).value).toEqual(
1345
- take('app/CommonTestAndPreview/GET_SENDER_DETAILS_REQUESTED')
1346
- );
1347
- const secondAction = {
1348
- payload: { channel: 'RCS', orgUnitId: 20 },
1349
- };
1350
- expect(generator.next(secondAction).value).toEqual(
1351
- cancel({ '@@redux-saga/TASK': true })
1352
- );
1353
- expect(generator.next().value).toEqual(
1354
- fork(getSenderDetailsSaga, secondAction)
1336
+ takeLatest('app/CommonTestAndPreview/GET_SENDER_DETAILS_REQUESTED', getSenderDetailsSaga)
1355
1337
  );
1338
+ expect(generator.next().done).toBe(true);
1356
1339
  });
1357
1340
 
1358
1341
  it('should watch for GET_WECRM_ACCOUNTS_REQUESTED', () => {
@@ -1471,24 +1454,34 @@ describe('CommonTestAndPreview Sagas', () => {
1471
1454
  const action = { payload: {} };
1472
1455
  const generator = getWeCrmAccountsSaga(action);
1473
1456
  generator.next();
1474
- const throwResult = generator.throw(new Error('API failed'));
1475
- expect(throwResult.value).toEqual(
1457
+ const err = generator.throw(new Error('API failed'));
1458
+ expect(err.value).toEqual(
1476
1459
  put({ type: GET_WECRM_ACCOUNTS_FAILURE, payload: { error: 'API failed' } })
1477
1460
  );
1478
1461
  expect(generator.next().done).toBe(true);
1479
1462
  });
1480
1463
  });
1481
1464
 
1482
- it('should initialize all watcher sagas', () => {
1483
- const generator = commonTestAndPreviewSaga();
1465
+ describe('commonTestAndPreviewSaga', () => {
1466
+ it('should fork all watcher sagas', () => {
1467
+ const generator = commonTestAndPreviewSaga();
1484
1468
 
1485
- const effect = generator.next().value;
1469
+ expect(generator.next().value).toEqual(
1470
+ all([
1471
+ watchSearchCustomers(),
1472
+ watchExtractTags(),
1473
+ watchUpdatePreview(),
1474
+ watchSendTestMessage(),
1475
+ watchFetchTestCustomers(),
1476
+ watchFetchTestGroups(),
1477
+ watchCreateMessageMeta(),
1478
+ watchGetPrefilledValues(),
1479
+ watchGetSenderDetails(),
1480
+ watchGetWeCrmAccounts(),
1481
+ ])
1482
+ );
1486
1483
 
1487
- // redux-saga v0.x stores the array under effect[ALL] key; v1.x uses effect.payload
1488
- const effectData = effect?.payload || effect?.ALL;
1489
- const watchers = Array.isArray(effectData) ? effectData : Object.values(effectData || {});
1490
- expect(Array.isArray(watchers)).toBe(true);
1491
- expect(watchers.length).toBeGreaterThan(0);
1492
- expect(generator.next().done).toBe(true);
1484
+ expect(generator.next().done).toBe(true);
1485
+ });
1493
1486
  });
1494
1487
  });
@@ -537,21 +537,20 @@
537
537
  .unicode-disabled{
538
538
  font-size: 16px;
539
539
  }
540
- position: absolute;
541
- overflow: auto;
542
- top: 0;
543
- left: 17%;
544
- white-space: pre-wrap;
545
- word-break: break-word;
546
- max-height: 100%;
547
- line-height: 0.875rem;
548
- font-size: 0.625rem;
549
- font-family: 'open-sans';
550
-
551
540
  &.sms {
541
+ max-height: 100%;
542
+ position: absolute;
552
543
  // width: initial;
544
+ overflow: auto;
545
+ top: 0;
546
+ left: 17%;
547
+ white-space: pre-wrap;
548
+ word-break: break-word;
549
+ line-height: 14px;
553
550
  padding: 0 8px 8px 8px;
551
+ font-size: 10px;
554
552
  width: 100%;
553
+ font-family: 'open-sans';
555
554
  .rcs-image{
556
555
  width: 100%;
557
556
  height: 123px;
@@ -583,12 +582,22 @@
583
582
  &:not(.sms){
584
583
  padding: 4px;
585
584
  background: #3F51B5;
585
+ position: absolute;
586
586
  // width: initial;
587
+ overflow: auto;
588
+ top: 0;
589
+ left: 17%;
590
+ white-space: pre-wrap;
591
+ word-break: break-word;
587
592
  border-radius: 4px;
593
+ max-height: 100%;
588
594
  color: #FFFFFF;
589
595
  width: 70%;
590
596
  min-height: 26px;
597
+ line-height: 14px;
591
598
  padding: 8px;
599
+ font-size: 10px;
600
+ font-family: 'open-sans';
592
601
  }
593
602
  &.message-pop-carousel {
594
603
  position: relative;
@@ -833,13 +842,9 @@
833
842
 
834
843
  .msg-container-carousel {
835
844
  display: flex;
836
- width: 100%;
837
845
  .scroll-container {
838
846
  overflow-x: auto;
839
- overflow-y: hidden;
840
847
  display: flex;
841
- flex-wrap: nowrap;
842
- width: 100%;
843
848
  padding-top: $CAP_SPACE_06;
844
849
  padding-right: $CAP_SPACE_06;
845
850
  white-space: nowrap;
@@ -860,32 +865,6 @@
860
865
  }
861
866
  }
862
867
 
863
- .shell-v2.rcs-preview {
864
- // Collapse the default 8px margin so the divider renders as a clean hairline, not a white gap.
865
- .whatsapp-divider {
866
- margin: 0;
867
- }
868
-
869
- // Override `.message-pop:not(.sms)` (blue background) for RCS carousel cards.
870
- .msg-container.sms {
871
- .message-pop.sms {
872
- .rcs-carousel-card {
873
- background: $CAP_WHITE;
874
- color: $CAP_G01;
875
- width: 10.4rem;
876
- left: 0;
877
- flex-shrink: 0;
878
- padding: $CAP_SPACE_04 0 $CAP_SPACE_08;
879
- border-radius: 0.428rem;
880
-
881
- .carousel-title {
882
- font-weight: 700 !important;
883
- }
884
- }
885
- }
886
- }
887
- }
888
-
889
868
  .align-center {
890
869
  text-align: center;
891
870
  }
@@ -1084,6 +1063,8 @@
1084
1063
  }
1085
1064
  .video-icon {
1086
1065
  position: absolute;
1066
+ right: -17px;
1067
+ bottom: -17px;
1087
1068
  }
1088
1069
 
1089
1070
  .zalo-preview-container {