@capillarytech/creatives-library 8.0.354 → 8.0.356

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 (28) hide show
  1. package/index.html +0 -1
  2. package/package.json +1 -1
  3. package/utils/cdnTransformation.js +3 -63
  4. package/utils/tests/cdnTransformation.test.js +0 -111
  5. package/v2Components/CommonTestAndPreview/UnifiedPreview/PreviewHeader.js +16 -0
  6. package/v2Components/CommonTestAndPreview/UnifiedPreview/WebPushPreviewContent.js +169 -0
  7. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +54 -0
  8. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +52 -6
  9. package/v2Components/CommonTestAndPreview/constants.js +2 -0
  10. package/v2Components/CommonTestAndPreview/index.js +51 -2
  11. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/PreviewHeader.test.js +163 -0
  12. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/WebPushPreviewContent.test.js +522 -0
  13. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +255 -0
  14. package/v2Components/CommonTestAndPreview/tests/constants.test.js +2 -1
  15. package/v2Components/CommonTestAndPreview/tests/index.test.js +194 -0
  16. package/v2Components/FormBuilder/index.js +162 -52
  17. package/v2Components/TestAndPreviewSlidebox/index.js +2 -2
  18. package/v2Containers/App/constants.js +3 -0
  19. package/v2Containers/App/tests/constants.test.js +61 -0
  20. package/v2Containers/CreativesContainer/index.js +60 -24
  21. package/v2Containers/Templates/index.js +72 -2
  22. package/v2Containers/Templates/sagas.js +1 -6
  23. package/v2Containers/Templates/tests/sagas.test.js +6 -23
  24. package/v2Containers/Templates/tests/webpush.test.js +375 -0
  25. package/v2Containers/WebPush/Create/index.js +91 -8
  26. package/v2Containers/WebPush/Create/index.scss +7 -0
  27. package/v2Containers/WebPush/Create/tests/getTemplateContent.test.js +348 -0
  28. package/v2Containers/WebPush/Create/tests/testAndPreviewIntegration.test.js +325 -0
@@ -81,7 +81,8 @@ import {
81
81
  IMAGE,
82
82
  VIDEO,
83
83
  URL,
84
- CHANNELS_USING_ANDROID_PREVIEW_DEVICE
84
+ CHANNELS_USING_ANDROID_PREVIEW_DEVICE,
85
+ DAYS,
85
86
  } from './constants';
86
87
 
87
88
  // Import utilities
@@ -610,6 +611,12 @@ const CommonTestAndPreview = (props) => {
610
611
  messageBody: contentStr,
611
612
  };
612
613
 
614
+ case CHANNELS.WEBPUSH:
615
+ return {
616
+ ...basePayload,
617
+ messageBody: contentStr,
618
+ };
619
+
613
620
  default:
614
621
  return basePayload;
615
622
  }
@@ -662,6 +669,12 @@ const CommonTestAndPreview = (props) => {
662
669
  templateContent: contentStr,
663
670
  };
664
671
 
672
+ case CHANNELS.WEBPUSH:
673
+ return {
674
+ templateSubject: formDataObj?.content?.title || '',
675
+ templateContent: contentStr,
676
+ };
677
+
665
678
  case CHANNELS.ZALO: {
666
679
  // For Zalo, extract content from templateListParams array
667
680
  // Combine all variable values into a single string for tag extraction
@@ -1801,6 +1814,42 @@ const CommonTestAndPreview = (props) => {
1801
1814
  };
1802
1815
  }
1803
1816
 
1817
+ case CHANNELS.WEBPUSH: {
1818
+ const webpushData = (typeof formDataObj === 'object' && formDataObj !== null)
1819
+ ? formDataObj
1820
+ : {};
1821
+ const innerContent = webpushData?.content || {};
1822
+
1823
+ const resolvedTitle = resolveTagsInText(innerContent?.title || '', customValuesObj);
1824
+ const resolvedMessage = resolveTagsInText(innerContent?.message || '', customValuesObj);
1825
+
1826
+ return {
1827
+ ...basePayload,
1828
+ webPushMessageContent: {
1829
+ channel: CHANNELS.WEBPUSH,
1830
+ accountId: webpushData?.accountId || null,
1831
+ content: {
1832
+ title: resolvedTitle,
1833
+ message: resolvedMessage,
1834
+ ...(innerContent?.iconImageUrl && { iconImageUrl: innerContent.iconImageUrl }),
1835
+ ...(innerContent?.cta && { cta: innerContent.cta }),
1836
+ ...(innerContent?.expandableDetails && { expandableDetails: innerContent.expandableDetails }),
1837
+ },
1838
+ messageSubject: webpushData?.messageSubject || resolvedTitle || '',
1839
+ },
1840
+ webPushDeliverySettings: {
1841
+ channelSettings: {
1842
+ channel: CHANNELS.WEBPUSH,
1843
+ notificationTtl: {
1844
+ duration: 7,
1845
+ timeUnit: DAYS,
1846
+ },
1847
+ },
1848
+ additionalSettings: {},
1849
+ },
1850
+ };
1851
+ }
1852
+
1804
1853
  default:
1805
1854
  return basePayload;
1806
1855
  }
@@ -1832,7 +1881,7 @@ const CommonTestAndPreview = (props) => {
1832
1881
  contentObj = hasPreviewCallBeenMade && previewDataHtml?.resolvedBody
1833
1882
  ? previewDataHtml.resolvedBody
1834
1883
  : getCurrentContent || '';
1835
- } else if (channel === CHANNELS.WHATSAPP) {
1884
+ } else if ([CHANNELS.WHATSAPP, CHANNELS.WEBPUSH].includes(channel)) {
1836
1885
  // For WhatsApp, content is an object with templateMsg, media, CTA, etc.
1837
1886
  // Content comes from WhatsApp component state, passed via content prop
1838
1887
  let resolvedContent = null;
@@ -514,4 +514,167 @@ describe('PreviewHeader', () => {
514
514
  consoleSpy.mockRestore();
515
515
  });
516
516
  });
517
+
518
+ describe('WEBPUSH channel - Fullscreen expander', () => {
519
+ it('should render expander icon for WEBPUSH channel', () => {
520
+ const setIsFullscreenOpen = jest.fn();
521
+ const props = {
522
+ ...defaultProps,
523
+ channel: CHANNELS.WEBPUSH,
524
+ setIsFullscreenOpen,
525
+ };
526
+
527
+ const { container } = render(
528
+ <TestWrapper>
529
+ <PreviewHeader {...props} />
530
+ </TestWrapper>
531
+ );
532
+
533
+ // expander icon should be present for WEBPUSH
534
+ const expanderIcon = container.querySelector('[class*="expander"], [aria-label*="expander"], .anticon');
535
+ expect(expanderIcon).toBeTruthy();
536
+ });
537
+
538
+ it('should NOT render expander icon for non-WEBPUSH channels', () => {
539
+ const setIsFullscreenOpen = jest.fn();
540
+ const props = {
541
+ ...defaultProps,
542
+ channel: CHANNELS.EMAIL,
543
+ setIsFullscreenOpen,
544
+ showDeviceToggle: false,
545
+ };
546
+
547
+ const { container } = render(
548
+ <TestWrapper>
549
+ <PreviewHeader {...props} />
550
+ </TestWrapper>
551
+ );
552
+
553
+ // No expander icon for EMAIL channel (only device toggle icons may appear)
554
+ const expanderIcon = container.querySelector('[class*="expander"]');
555
+ expect(expanderIcon).toBeNull();
556
+ });
557
+
558
+ it('should call setIsFullscreenOpen(true) when expander icon is clicked', () => {
559
+ const setIsFullscreenOpen = jest.fn();
560
+ const props = {
561
+ ...defaultProps,
562
+ channel: CHANNELS.WEBPUSH,
563
+ setIsFullscreenOpen,
564
+ };
565
+
566
+ const { container } = render(
567
+ <TestWrapper>
568
+ <PreviewHeader {...props} />
569
+ </TestWrapper>
570
+ );
571
+
572
+ const expanderIcon = container.querySelector('[class*="expander"]') ||
573
+ container.querySelector('.anticon');
574
+ if (expanderIcon) {
575
+ fireEvent.click(expanderIcon);
576
+ expect(setIsFullscreenOpen).toHaveBeenCalledWith(true);
577
+ }
578
+ });
579
+
580
+ it('should render expander icon without ACTIVE class when device is MOBILE', () => {
581
+ const setIsFullscreenOpen = jest.fn();
582
+ const props = {
583
+ ...defaultProps,
584
+ channel: CHANNELS.WEBPUSH,
585
+ device: MOBILE,
586
+ setIsFullscreenOpen,
587
+ };
588
+
589
+ const { container } = render(
590
+ <TestWrapper>
591
+ <PreviewHeader {...props} />
592
+ </TestWrapper>
593
+ );
594
+
595
+ // Expander icon no longer adds ACTIVE class based on device
596
+ const activeEl = container.querySelector('.active');
597
+ expect(activeEl).toBeNull();
598
+ // But the expander icon itself should still be present
599
+ const expanderIcon = container.querySelector('[class*="expander"]') ||
600
+ container.querySelector('.anticon');
601
+ expect(expanderIcon).toBeTruthy();
602
+ });
603
+
604
+ it('should render expander icon without ACTIVE class when device is DESKTOP', () => {
605
+ const setIsFullscreenOpen = jest.fn();
606
+ const props = {
607
+ ...defaultProps,
608
+ channel: CHANNELS.WEBPUSH,
609
+ device: DESKTOP,
610
+ setIsFullscreenOpen,
611
+ };
612
+
613
+ const { container } = render(
614
+ <TestWrapper>
615
+ <PreviewHeader {...props} />
616
+ </TestWrapper>
617
+ );
618
+
619
+ // Expander icon does not have ACTIVE class for any device
620
+ const activeEl = container.querySelector('.active');
621
+ expect(activeEl).toBeNull();
622
+ });
623
+
624
+ it('should render expander icon alongside device content for WEBPUSH', () => {
625
+ // Note: suppression of showDeviceToggle for WEBPUSH is done in UnifiedPreview (parent),
626
+ // not in PreviewHeader itself. PreviewHeader only adds the expander icon for WEBPUSH.
627
+ const setIsFullscreenOpen = jest.fn();
628
+ const props = {
629
+ ...defaultProps,
630
+ channel: CHANNELS.WEBPUSH,
631
+ setIsFullscreenOpen,
632
+ showDeviceToggle: false,
633
+ };
634
+
635
+ const { container } = render(
636
+ <TestWrapper>
637
+ <PreviewHeader {...props} />
638
+ </TestWrapper>
639
+ );
640
+
641
+ // expander icon should be present for WEBPUSH
642
+ const expanderIcon = container.querySelector('[class*="expander"]') ||
643
+ container.querySelector('.anticon');
644
+ expect(expanderIcon).toBeTruthy();
645
+ });
646
+
647
+ it('should accept isFullscreenOpen and setIsFullscreenOpen as props', () => {
648
+ const setIsFullscreenOpen = jest.fn();
649
+ const props = {
650
+ ...defaultProps,
651
+ channel: CHANNELS.WEBPUSH,
652
+ isFullscreenOpen: false,
653
+ setIsFullscreenOpen,
654
+ };
655
+
656
+ expect(() =>
657
+ render(
658
+ <TestWrapper>
659
+ <PreviewHeader {...props} />
660
+ </TestWrapper>
661
+ )
662
+ ).not.toThrow();
663
+ });
664
+
665
+ it('should use default setIsFullscreenOpen when not provided', () => {
666
+ const props = {
667
+ ...defaultProps,
668
+ channel: CHANNELS.WEBPUSH,
669
+ };
670
+
671
+ expect(() =>
672
+ render(
673
+ <TestWrapper>
674
+ <PreviewHeader {...props} />
675
+ </TestWrapper>
676
+ )
677
+ ).not.toThrow();
678
+ });
679
+ });
517
680
  });