@capillarytech/creatives-library 8.0.359-alpha.0 → 8.0.360-alpha.0

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 (34) hide show
  1. package/index.html +1 -0
  2. package/package.json +1 -1
  3. package/utils/cdnTransformation.js +75 -3
  4. package/utils/tests/cdnTransformation.test.js +127 -0
  5. package/v2Components/CommonTestAndPreview/UnifiedPreview/PreviewHeader.js +16 -0
  6. package/v2Components/CommonTestAndPreview/UnifiedPreview/ViberCarouselPreviewCards.js +132 -0
  7. package/v2Components/CommonTestAndPreview/UnifiedPreview/ViberPreviewContent.js +2 -37
  8. package/v2Components/CommonTestAndPreview/UnifiedPreview/WebPushPreviewContent.js +169 -0
  9. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +55 -85
  10. package/v2Components/CommonTestAndPreview/UnifiedPreview/_viberCarouselPreviewCards.scss +127 -0
  11. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +52 -6
  12. package/v2Components/CommonTestAndPreview/constants.js +2 -0
  13. package/v2Components/CommonTestAndPreview/index.js +67 -3
  14. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/PreviewHeader.test.js +163 -0
  15. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/WebPushPreviewContent.test.js +522 -0
  16. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +255 -0
  17. package/v2Components/CommonTestAndPreview/tests/constants.test.js +2 -1
  18. package/v2Components/CommonTestAndPreview/tests/index.test.js +194 -0
  19. package/v2Components/FormBuilder/index.js +162 -52
  20. package/v2Components/TestAndPreviewSlidebox/index.js +2 -2
  21. package/v2Containers/App/constants.js +3 -0
  22. package/v2Containers/App/tests/constants.test.js +61 -0
  23. package/v2Containers/CreativesContainer/index.js +60 -24
  24. package/v2Containers/Templates/index.js +72 -2
  25. package/v2Containers/Templates/sagas.js +6 -1
  26. package/v2Containers/Templates/tests/sagas.test.js +23 -6
  27. package/v2Containers/Templates/tests/webpush.test.js +375 -0
  28. package/v2Containers/Viber/index.js +24 -18
  29. package/v2Containers/Viber/index.scss +27 -0
  30. package/v2Containers/Viber/messages.js +4 -4
  31. package/v2Containers/WebPush/Create/index.js +91 -8
  32. package/v2Containers/WebPush/Create/index.scss +7 -0
  33. package/v2Containers/WebPush/Create/tests/getTemplateContent.test.js +348 -0
  34. package/v2Containers/WebPush/Create/tests/testAndPreviewIntegration.test.js +325 -0
@@ -1,4 +1,5 @@
1
1
  @import '~@capillarytech/cap-ui-library/styles/_variables';
2
+ @import './_viberCarouselPreviewCards.scss';
2
3
 
3
4
  /**
4
5
  * UnifiedPreview Styles
@@ -2318,91 +2319,6 @@
2318
2319
  color: $CAP_G04;
2319
2320
  }
2320
2321
 
2321
- .viber-carousel-preview-scroll {
2322
- display: flex;
2323
- width: 100%;
2324
- overflow-x: auto;
2325
- overflow-y: visible;
2326
-
2327
- scrollbar-width: none;
2328
- -webkit-overflow-scrolling: touch;
2329
-
2330
- &::-webkit-scrollbar {
2331
- display: none;
2332
- }
2333
-
2334
- .viber-carousel-preview-card {
2335
- flex: 0 0 68%;
2336
- min-width: 68%;
2337
- margin-right: $CAP_SPACE_08;
2338
- background: $CAP_G09;
2339
- border: 1px solid $CAP_G07;
2340
- border-radius: $CAP_SPACE_12;
2341
- overflow: hidden;
2342
- display: flex;
2343
- flex-direction: column;
2344
-
2345
- &:last-child {
2346
- margin-right: 0;
2347
- }
2348
-
2349
- .viber-carousel-preview-card-body {
2350
- padding: $CAP_SPACE_08;
2351
- display: flex;
2352
- flex-direction: column;
2353
- gap: $CAP_SPACE_06;
2354
- }
2355
-
2356
- .viber-carousel-preview-image {
2357
- width: 100%;
2358
- height: 10rem;
2359
- object-fit: cover;
2360
- border-radius: 0;
2361
- }
2362
-
2363
- .viber-carousel-preview-image-placeholder {
2364
- width: 100%;
2365
- height: 10rem;
2366
- border-radius: 0;
2367
- background: $CAP_G07;
2368
- }
2369
-
2370
- .viber-carousel-preview-text {
2371
- color: $CAP_G01;
2372
- line-height: 1.3;
2373
- white-space: normal;
2374
- }
2375
-
2376
- .viber-carousel-preview-text-placeholder {
2377
- width: 100%;
2378
- height: 0.875rem;
2379
- border-radius: $CAP_SPACE_04;
2380
- background: $CAP_G07;
2381
- min-height: 0.875rem;
2382
- }
2383
-
2384
- .viber-carousel-preview-button {
2385
- color: $CAP_WHITE;
2386
- background: $CAP_PURPLE01;
2387
- border-radius: $CAP_SPACE_12;
2388
- text-align: center;
2389
- width: 100%;
2390
- display: flex;
2391
- align-items: center;
2392
- justify-content: center;
2393
- min-height: 1.5rem;
2394
- padding: $CAP_SPACE_06 $CAP_SPACE_08;
2395
- white-space: normal;
2396
- }
2397
-
2398
- .viber-carousel-preview-button-secondary {
2399
- color: $CAP_PURPLE01;
2400
- background: transparent;
2401
- border: none;
2402
- }
2403
- }
2404
- }
2405
-
2406
2322
  .empty-placeholder {
2407
2323
  height: $CAP_SPACE_08;
2408
2324
  }
@@ -2513,6 +2429,60 @@
2513
2429
  }
2514
2430
  }
2515
2431
 
2432
+ // WebPush Test & Preview Styles
2433
+ .webpush-test-preview-container {
2434
+ width: 100%;
2435
+ position: relative;
2436
+ padding-left: $CAP_SPACE_16;
2437
+ padding-right: $CAP_SPACE_16;
2438
+ }
2439
+
2440
+ .webpush-preview-panel {
2441
+ position: relative;
2442
+ width: 100%;
2443
+ }
2444
+
2445
+ .webpush-fullscreen-modal {
2446
+ .webpush-fullscreen-divider {
2447
+ margin-top: 0;
2448
+ margin-bottom: $CAP_SPACE_16;
2449
+ }
2450
+ .ant-modal.cap-modal-v2 {
2451
+ width: 90%;
2452
+ max-width: 100%;
2453
+ margin-top: $CAP_SPACE_40;
2454
+ }
2455
+ // Preview Chrome wrapper (matches old TestAndPreviewSlidebox design)
2456
+ .webpush-preview-header {
2457
+ background: $CAP_WHITE;
2458
+ overflow: hidden;
2459
+
2460
+ .preview-divider {
2461
+ margin: 0;
2462
+ }
2463
+
2464
+ .webpush-heading-container {
2465
+ display: flex;
2466
+ justify-content: space-between;
2467
+ align-items: center;
2468
+ padding: $CAP_SPACE_16 0 $CAP_SPACE_16 0;
2469
+
2470
+ .preview-for {
2471
+ gap: $CAP_SPACE_04;
2472
+ align-items: center;
2473
+ b {
2474
+ margin-left: $CAP_SPACE_08;
2475
+ }
2476
+ }
2477
+
2478
+ .webpush-fullscreen-close-icon {
2479
+ width: $CAP_SPACE_24;
2480
+ height: $CAP_SPACE_24;
2481
+ }
2482
+ }
2483
+ }
2484
+ }
2485
+
2516
2486
  // Responsive adjustments
2517
2487
  @media (max-width: 85.714rem) {
2518
2488
  .unified-preview {
@@ -0,0 +1,127 @@
1
+ // Shared Viber carousel card row (Test & Preview device preview)
2
+ .viber-carousel-preview-scroll {
3
+ display: flex;
4
+ align-items: stretch;
5
+ width: 100%;
6
+ overflow-x: auto;
7
+ overflow-y: visible;
8
+ scrollbar-width: none;
9
+ -webkit-overflow-scrolling: touch;
10
+
11
+ &::-webkit-scrollbar {
12
+ display: none;
13
+ }
14
+
15
+ .viber-carousel-preview-card {
16
+ flex: 0 0 68%;
17
+ min-width: 68%;
18
+ margin-right: $CAP_SPACE_08;
19
+ background: $CAP_G09;
20
+ border: 1px solid $CAP_G07;
21
+ border-radius: $CAP_SPACE_12;
22
+ overflow: hidden;
23
+ display: flex;
24
+ flex-direction: column;
25
+ align-self: stretch;
26
+
27
+ &:last-child {
28
+ margin-right: 0;
29
+ }
30
+
31
+ .viber-carousel-preview-card-body {
32
+ flex: 1;
33
+ padding: $CAP_SPACE_08;
34
+ display: flex;
35
+ flex-direction: column;
36
+ min-height: 0;
37
+ }
38
+
39
+ .viber-carousel-preview-text-wrap {
40
+ flex-shrink: 0;
41
+ width: 100%;
42
+
43
+ &--1-line {
44
+ min-height: 1.3em;
45
+ }
46
+
47
+ &--2-line {
48
+ min-height: 2.6em;
49
+ }
50
+ }
51
+
52
+ .viber-carousel-preview-text-inner {
53
+ width: 100%;
54
+ }
55
+
56
+ .viber-carousel-preview-buttons {
57
+ display: flex;
58
+ flex-direction: column;
59
+ gap: $CAP_SPACE_06;
60
+ margin-top: auto;
61
+ width: 100%;
62
+ flex-shrink: 0;
63
+ }
64
+
65
+ .viber-carousel-preview-image {
66
+ width: 100%;
67
+ height: 10rem;
68
+ object-fit: cover;
69
+ border-radius: 0;
70
+ }
71
+
72
+ .viber-carousel-preview-image-placeholder {
73
+ width: 100%;
74
+ height: 10rem;
75
+ border-radius: 0;
76
+ background: $CAP_G07;
77
+ }
78
+
79
+ .viber-carousel-preview-text {
80
+ color: $CAP_G01;
81
+ line-height: 1.3;
82
+ white-space: normal;
83
+ word-break: break-word;
84
+ display: block;
85
+ width: 100%;
86
+ margin: 0;
87
+ }
88
+
89
+ .viber-carousel-preview-text-placeholder {
90
+ width: 100%;
91
+ height: 0.875rem;
92
+ border-radius: $CAP_SPACE_04;
93
+ background: $CAP_G07;
94
+ min-height: 0.875rem;
95
+ display: block;
96
+ }
97
+
98
+ .viber-carousel-preview-button {
99
+ color: $CAP_WHITE;
100
+ background: $CAP_PURPLE01;
101
+ border-radius: $CAP_SPACE_12;
102
+ text-align: center;
103
+ width: 100%;
104
+ display: flex;
105
+ align-items: center;
106
+ justify-content: center;
107
+ min-height: 1.5rem;
108
+ padding: $CAP_SPACE_06 $CAP_SPACE_08;
109
+ white-space: normal;
110
+ box-sizing: border-box;
111
+ }
112
+
113
+ .viber-carousel-preview-button-placeholder {
114
+ visibility: hidden;
115
+ pointer-events: none;
116
+ padding: 0;
117
+ background: transparent;
118
+ border: none;
119
+ }
120
+
121
+ .viber-carousel-preview-button-secondary {
122
+ color: $CAP_PURPLE01;
123
+ background: transparent;
124
+ border: none;
125
+ }
126
+ }
127
+ }
@@ -6,7 +6,7 @@
6
6
  * Routes to channel-specific preview content components
7
7
  */
8
8
 
9
- import React from 'react';
9
+ import React, { useState } from 'react';
10
10
  import PropTypes from 'prop-types';
11
11
  import CapRow from '@capillarytech/cap-ui-library/CapRow';
12
12
  import CapSpin from '@capillarytech/cap-ui-library/CapSpin';
@@ -21,6 +21,7 @@ import InAppPreviewContent from './InAppPreviewContent';
21
21
  import MobilePushPreviewContent from './MobilePushPreviewContent';
22
22
  import ViberPreviewContent from './ViberPreviewContent';
23
23
  import ZaloPreviewContent from './ZaloPreviewContent';
24
+ import WebPushPreviewContent from './WebPushPreviewContent';
24
25
  import { CHANNELS, DESKTOP, TABLET, MOBILE, ANDROID, IOS } from '../constants';
25
26
  import messages from '../messages';
26
27
  import './_unifiedPreview.scss';
@@ -44,6 +45,7 @@ const UnifiedPreview = ({
44
45
  * For Phase 5, we'll render placeholders
45
46
  * Phase 6+ will implement actual content components
46
47
  */
48
+ const [isFullscreenOpen, setIsFullscreenOpen] = useState(false);
47
49
  const renderChannelContent = () => {
48
50
  // Phase 5: Placeholder content for all channels
49
51
  // Phase 6+: Import and render actual channel-specific components
@@ -197,6 +199,45 @@ const UnifiedPreview = ({
197
199
  );
198
200
  }
199
201
 
202
+ case CHANNELS.WEBPUSH: {
203
+ // WebPush content arrives as a JSON string (from getCurrentContent or preview API response)
204
+ let webPushOuter = {};
205
+ try {
206
+ webPushOuter = typeof content === 'string' ? JSON.parse(content) : (typeof content === 'object' && content !== null ? content : {});
207
+ } catch (e) {
208
+ webPushOuter = {};
209
+ }
210
+ const { content: webPushInner = {} } = webPushOuter;
211
+ const {
212
+ title,
213
+ message,
214
+ iconImageUrl,
215
+ cta,
216
+ expandableDetails = {},
217
+ } = webPushInner;
218
+ const { media: webPushMedia = [], ctas: webPushCtas = [] } = expandableDetails;
219
+ const webPushButtons = webPushCtas.map(({ title: text = '', actionLink: url = '', type = '' }) => ({
220
+ text,
221
+ url,
222
+ type,
223
+ }));
224
+ return (
225
+ <WebPushPreviewContent
226
+ notificationTitle={title || ''}
227
+ notificationBody={message || ''}
228
+ imageSrc={webPushMedia[0]?.url || ''}
229
+ brandIconSrc={iconImageUrl || ''}
230
+ buttons={webPushButtons}
231
+ url={cta?.actionLink || ''}
232
+ isUpdating={isUpdating}
233
+ error={error}
234
+ isFullscreenOpen={isFullscreenOpen}
235
+ setIsFullscreenOpen={setIsFullscreenOpen}
236
+ selectedCustomer={selectedCustomer}
237
+ />
238
+ );
239
+ }
240
+
200
241
  default:
201
242
  return (
202
243
  <div className="channel-preview-placeholder">
@@ -212,6 +253,8 @@ const UnifiedPreview = ({
212
253
  }
213
254
  };
214
255
 
256
+ const showToggle = channel !== CHANNELS.WEBPUSH && showDeviceToggle;
257
+
215
258
  /**
216
259
  * Render loading state for all channels
217
260
  */
@@ -222,9 +265,10 @@ const UnifiedPreview = ({
222
265
  <PreviewHeader
223
266
  selectedCustomer={selectedCustomer}
224
267
  device={device}
225
- showDeviceToggle={showDeviceToggle}
268
+ showDeviceToggle={showToggle}
226
269
  onDeviceChange={onDeviceChange}
227
270
  channel={channel}
271
+ setIsFullscreenOpen={setIsFullscreenOpen}
228
272
  />
229
273
  )}
230
274
  <CapRow className="preview-loading-container">
@@ -247,9 +291,10 @@ const UnifiedPreview = ({
247
291
  <PreviewHeader
248
292
  selectedCustomer={selectedCustomer}
249
293
  device={device}
250
- showDeviceToggle={showDeviceToggle}
294
+ showDeviceToggle={showToggle}
251
295
  onDeviceChange={onDeviceChange}
252
296
  channel={channel}
297
+ setIsFullscreenOpen={setIsFullscreenOpen}
253
298
  />
254
299
  )}
255
300
  <CapRow className="preview-error-container">
@@ -275,15 +320,16 @@ const UnifiedPreview = ({
275
320
  <PreviewHeader
276
321
  selectedCustomer={selectedCustomer}
277
322
  device={device}
278
- showDeviceToggle={showDeviceToggle}
323
+ showDeviceToggle={showToggle}
279
324
  onDeviceChange={onDeviceChange}
280
325
  channel={channel}
326
+ setIsFullscreenOpen={setIsFullscreenOpen}
281
327
  />
282
328
  )}
283
329
 
284
330
  {/* Channel-specific preview content */}
285
331
  <CapRow className={`preview-content-container ${!showHeader ? 'preview-content-container-no-header' : ''}`}>
286
- {[CHANNELS.EMAIL, CHANNELS.SMS, CHANNELS.WHATSAPP, CHANNELS.RCS, CHANNELS.INAPP, CHANNELS.MOBILEPUSH, CHANNELS.VIBER].includes(channel) ? (
332
+ {[CHANNELS.EMAIL, CHANNELS.SMS, CHANNELS.WHATSAPP, CHANNELS.RCS, CHANNELS.INAPP, CHANNELS.MOBILEPUSH, CHANNELS.VIBER, CHANNELS.WEBPUSH].includes(channel) ? (
287
333
  renderChannelContent()
288
334
  ) : (
289
335
  <DeviceFrame device={device || DESKTOP}>
@@ -319,7 +365,7 @@ const UnifiedPreview = ({
319
365
  UnifiedPreview.propTypes = {
320
366
  // Core
321
367
  channel: PropTypes.oneOf(Object.values(CHANNELS)).isRequired,
322
- content: PropTypes.object.isRequired,
368
+ content: PropTypes.oneOfType([PropTypes.object, PropTypes.string]).isRequired,
323
369
 
324
370
  // Display options
325
371
  device: PropTypes.oneOf([DESKTOP, TABLET, MOBILE, ANDROID, IOS]),
@@ -85,6 +85,7 @@ export const CHANNELS = {
85
85
  MOBILEPUSH: 'MOBILEPUSH',
86
86
  VIBER: 'VIBER',
87
87
  ZALO: 'ZALO',
88
+ WEBPUSH: 'WEBPUSH',
88
89
  };
89
90
  export const CHANNELS_USING_ANDROID_PREVIEW_DEVICE = [CHANNELS.SMS, CHANNELS.RCS, CHANNELS.WHATSAPP, CHANNELS.VIBER, CHANNELS.ZALO, CHANNELS.INAPP, CHANNELS.MOBILEPUSH];
90
91
 
@@ -203,6 +204,7 @@ export const DYNAMIC_URL = 'DYNAMIC_URL';
203
204
  export const IMAGE = 'IMAGE';
204
205
  export const VIDEO = 'VIDEO';
205
206
  export const URL = 'URL';
207
+ export const DAYS = 'DAYS';
206
208
 
207
209
  // Initial Payload Template (for reference)
208
210
  export const INITIAL_PAYLOAD = {
@@ -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
@@ -475,15 +476,25 @@ const CommonTestAndPreview = (props) => {
475
476
  ?? formDataObj.cards
476
477
  ?? contentObj.viberPreviewContent?.cards
477
478
  ?? contentObj.cards;
479
+ const isCarousel = Boolean(
480
+ formDataObj.type === MEDIA_TYPE_CAROUSEL
481
+ || contentObj.type === MEDIA_TYPE_CAROUSEL
482
+ || (Array.isArray(previewCards) && previewCards.length > 0),
483
+ );
478
484
  const mergedPreview = {
479
485
  ...(contentObj.viberPreviewContent || {}),
480
486
  ...(formDataObj.viberPreviewContent || {}),
481
487
  ...(Array.isArray(previewCards) && previewCards.length ? { cards: previewCards } : {}),
488
+ ...(isCarousel ? {
489
+ type: MEDIA_TYPE_CAROUSEL,
490
+ showCarouselEditorPreview: true,
491
+ } : {}),
482
492
  };
483
493
  return {
484
494
  ...contentObj,
485
495
  ...formDataObj,
486
496
  ...(Array.isArray(previewCards) && previewCards.length ? { cards: previewCards } : {}),
497
+ ...(isCarousel ? { type: MEDIA_TYPE_CAROUSEL } : {}),
487
498
  ...(Object.keys(mergedPreview).length ? { viberPreviewContent: mergedPreview } : {}),
488
499
  };
489
500
  }, [formData, content]);
@@ -588,8 +599,13 @@ const CommonTestAndPreview = (props) => {
588
599
  viberPreviewContent: {
589
600
  ...basePreview,
590
601
  ...resolvedPreview,
591
- type: resolvedPreview.type || basePreview.type || baseObj.type,
602
+ type: resolvedPreview.type || basePreview.type || baseObj.type || (mergedCards.length ? MEDIA_TYPE_CAROUSEL : ''),
592
603
  cards: mergedCards.length ? mergedCards : (resolvedPreview.cards || basePreview.cards),
604
+ showCarouselEditorPreview: Boolean(
605
+ basePreview.showCarouselEditorPreview
606
+ || resolvedPreview.showCarouselEditorPreview
607
+ || mergedCards.length > 0,
608
+ ),
593
609
  ...(resolvedMessage != null ? { messageContent: resolvedMessage } : {}),
594
610
  },
595
611
  };
@@ -750,6 +766,12 @@ const CommonTestAndPreview = (props) => {
750
766
  messageBody: contentStr,
751
767
  };
752
768
 
769
+ case CHANNELS.WEBPUSH:
770
+ return {
771
+ ...basePayload,
772
+ messageBody: contentStr,
773
+ };
774
+
753
775
  default:
754
776
  return basePayload;
755
777
  }
@@ -804,6 +826,12 @@ const CommonTestAndPreview = (props) => {
804
826
  };
805
827
  }
806
828
 
829
+ case CHANNELS.WEBPUSH:
830
+ return {
831
+ templateSubject: formDataObj?.content?.title || '',
832
+ templateContent: contentStr,
833
+ };
834
+
807
835
  case CHANNELS.ZALO: {
808
836
  // For Zalo, extract content from templateListParams array
809
837
  // Combine all variable values into a single string for tag extraction
@@ -1981,6 +2009,42 @@ const CommonTestAndPreview = (props) => {
1981
2009
  };
1982
2010
  }
1983
2011
 
2012
+ case CHANNELS.WEBPUSH: {
2013
+ const webpushData = (typeof formDataObj === 'object' && formDataObj !== null)
2014
+ ? formDataObj
2015
+ : {};
2016
+ const innerContent = webpushData?.content || {};
2017
+
2018
+ const resolvedTitle = resolveTagsInText(innerContent?.title || '', customValuesObj);
2019
+ const resolvedMessage = resolveTagsInText(innerContent?.message || '', customValuesObj);
2020
+
2021
+ return {
2022
+ ...basePayload,
2023
+ webPushMessageContent: {
2024
+ channel: CHANNELS.WEBPUSH,
2025
+ accountId: webpushData?.accountId || null,
2026
+ content: {
2027
+ title: resolvedTitle,
2028
+ message: resolvedMessage,
2029
+ ...(innerContent?.iconImageUrl && { iconImageUrl: innerContent.iconImageUrl }),
2030
+ ...(innerContent?.cta && { cta: innerContent.cta }),
2031
+ ...(innerContent?.expandableDetails && { expandableDetails: innerContent.expandableDetails }),
2032
+ },
2033
+ messageSubject: webpushData?.messageSubject || resolvedTitle || '',
2034
+ },
2035
+ webPushDeliverySettings: {
2036
+ channelSettings: {
2037
+ channel: CHANNELS.WEBPUSH,
2038
+ notificationTtl: {
2039
+ duration: 7,
2040
+ timeUnit: DAYS,
2041
+ },
2042
+ },
2043
+ additionalSettings: {},
2044
+ },
2045
+ };
2046
+ }
2047
+
1984
2048
  default:
1985
2049
  return basePayload;
1986
2050
  }
@@ -2012,7 +2076,7 @@ const CommonTestAndPreview = (props) => {
2012
2076
  contentObj = hasPreviewCallBeenMade && previewDataHtml?.resolvedBody
2013
2077
  ? previewDataHtml.resolvedBody
2014
2078
  : getCurrentContent || '';
2015
- } else if (channel === CHANNELS.WHATSAPP) {
2079
+ } else if ([CHANNELS.WHATSAPP, CHANNELS.WEBPUSH].includes(channel)) {
2016
2080
  // For WhatsApp, content is an object with templateMsg, media, CTA, etc.
2017
2081
  // Content comes from WhatsApp component state, passed via content prop
2018
2082
  let resolvedContent = null;