@capillarytech/creatives-library 8.0.353-alpha.2 → 8.0.353-alpha.3

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "8.0.353-alpha.2",
4
+ "version": "8.0.353-alpha.3",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -14,7 +14,14 @@ import CapSpin from '@capillarytech/cap-ui-library/CapSpin';
14
14
  import CapImage from '@capillarytech/cap-ui-library/CapImage';
15
15
  import CapTooltip from '@capillarytech/cap-ui-library/CapTooltip';
16
16
  import CapRow from '@capillarytech/cap-ui-library/CapRow';
17
- import { ANDROID, IOS, ANDROID_DEVICE_NAME, IOS_DEVICE_NAME, VIBER_ACCOUNT_NAME } from '../constants';
17
+ import {
18
+ ANDROID,
19
+ IOS,
20
+ ANDROID_DEVICE_NAME,
21
+ IOS_DEVICE_NAME,
22
+ VIBER_ACCOUNT_NAME,
23
+ MEDIA_TYPE_CAROUSEL,
24
+ } from '../constants';
18
25
  import messages from '../messages';
19
26
  import videoPlay from '../../../assets/videoPlay.svg';
20
27
 
@@ -22,6 +29,9 @@ import videoPlay from '../../../assets/videoPlay.svg';
22
29
  const smsMobileAndroid = require('../../../assets/Android.png');
23
30
  const smsMobileIos = require('../../../assets/iOS.png');
24
31
 
32
+ const getTrimmedText = (value = '') => (value ?? '').trim();
33
+ const hasTrimmedText = (value = '') => Boolean(getTrimmedText(value));
34
+
25
35
  const ViberPreviewContent = ({
26
36
  content,
27
37
  device,
@@ -43,7 +53,34 @@ const ViberPreviewContent = ({
43
53
  imageURL = '',
44
54
  videoParams = {},
45
55
  buttonText = '',
56
+ type = '',
57
+ cards = [],
58
+ showCarouselEditorPreview = false,
46
59
  } = viberContent;
60
+ const hasCarouselContent = type === MEDIA_TYPE_CAROUSEL;
61
+
62
+ const cardHasMeaningfulContent = (card) => {
63
+ if (!card || typeof card !== 'object') return false;
64
+ if (hasTrimmedText(card?.text)) return true;
65
+ if (hasTrimmedText(card?.mediaUrl)) return true;
66
+ const buttons = card?.buttons ?? [];
67
+ return buttons.some((button) => hasTrimmedText(button?.title));
68
+ };
69
+
70
+ const hasMeaningfulCarousel =
71
+ hasCarouselContent &&
72
+ Array.isArray(cards) &&
73
+ cards.length > 0 &&
74
+ cards.some(cardHasMeaningfulContent);
75
+
76
+ const showCarouselInPreview =
77
+ hasCarouselContent && (Boolean(showCarouselEditorPreview) || hasMeaningfulCarousel);
78
+
79
+ const previewCarouselCards =
80
+ hasCarouselContent && Array.isArray(cards) && cards.length ? cards : hasCarouselContent ? [{}] : [];
81
+
82
+ const trimmedMessageContent = getTrimmedText(messageContent);
83
+ const trimmedButtonText = getTrimmedText(buttonText);
47
84
 
48
85
  // Get account name (first letter for icon)
49
86
  const accountIcon = (accountName || brandName || 'V')[0]?.toUpperCase();
@@ -99,8 +136,15 @@ const ViberPreviewContent = ({
99
136
  );
100
137
  }
101
138
 
102
- // Check if there's any content to display
103
- const hasContent = messageContent || imageURL || videoParams?.viberVideoSrc || buttonText;
139
+ // Check if there's any content to display (whitespace-only strings do not count)
140
+ const hasContent = Boolean(
141
+ trimmedMessageContent
142
+ || hasTrimmedText(imageURL)
143
+ || videoParams?.viberVideoSrc
144
+ || trimmedButtonText
145
+ || hasMeaningfulCarousel
146
+ || (hasCarouselContent && showCarouselEditorPreview)
147
+ );
104
148
 
105
149
  // Render normal Viber preview
106
150
  return (
@@ -127,21 +171,23 @@ const ViberPreviewContent = ({
127
171
  {hasContent && (
128
172
  <CapRow className={`viber-message-container ${device !== ANDROID ? 'viber-message-container-ios' : ''}`}>
129
173
  {/* Brand Name Display (from TemplatePreview line 1136) */}
130
- <CapRow className="msg-container viber-preview">
174
+ <CapRow className={`msg-container viber-preview ${showCarouselInPreview ? 'viber-preview-carousel' : ''}`}>
131
175
  {/* Account Icon (from TemplatePreview line 1146-1160) */}
132
- <CapRow className="viber-account-icon">
133
- {accountIcon}
134
- </CapRow>
176
+ {!hasCarouselContent && (
177
+ <CapRow className="viber-account-icon">
178
+ {accountIcon}
179
+ </CapRow>
180
+ )}
135
181
 
136
182
  {/* Message Bubble (from TemplatePreview line 1161-1223) */}
137
- <CapRow className="message-pop align-left viber-message-pop">
183
+ <CapRow className={`message-pop align-left viber-message-pop ${showCarouselInPreview ? 'viber-message-pop-carousel' : ''}`}>
138
184
  {/* Text Viber preview */}
139
- {messageContent && (
185
+ {trimmedMessageContent && !hasCarouselContent && (
140
186
  <CapLabel type="label15" className="viber-message-text">{messageContent}</CapLabel>
141
187
  )}
142
188
 
143
189
  {/* Image Viber preview */}
144
- {imageURL && (
190
+ {hasTrimmedText(imageURL) && (
145
191
  <CapImage
146
192
  src={imageURL}
147
193
  className="viber-image-preview"
@@ -171,16 +217,78 @@ const ViberPreviewContent = ({
171
217
  )}
172
218
 
173
219
  {/* Button Viber preview */}
174
- {buttonText && (
220
+ {trimmedButtonText && (
175
221
  <CapLabel className="viber-button-base">
176
222
  <p className="viber-button-card-text">
177
223
  {buttonText}
178
224
  </p>
179
225
  </CapLabel>
180
226
  )}
181
- <CapLabel type="label1" className="viber-timestamp">
182
- {timestamp}
183
- </CapLabel>
227
+ {/* Carousel Viber preview */}
228
+ {showCarouselInPreview && (
229
+ <>
230
+ <CapRow className="viber-carousel-message-pop">
231
+ {trimmedMessageContent ? (
232
+ <CapLabel
233
+ type="label15"
234
+ className="message-pop-item align-left viber-message-text viber-carousel-message-box-text"
235
+ >
236
+ {messageContent}
237
+ </CapLabel>
238
+ ) : (
239
+ <CapRow className="viber-carousel-message-box-placeholder" />
240
+ )}
241
+ <CapLabel type="label1" className="viber-carousel-message-timestamp">
242
+ {timestamp}
243
+ </CapLabel>
244
+ </CapRow>
245
+
246
+ <CapRow className="viber-carousel-cards-pop">
247
+ <CapRow className="viber-carousel-preview-scroll">
248
+ {previewCarouselCards?.map((card, index) => (
249
+ <CapRow className="viber-carousel-preview-card" key={`viber-carousel-preview-card-${index}`}>
250
+ {hasTrimmedText(card?.mediaUrl) ? (
251
+ <CapImage
252
+ src={card?.mediaUrl}
253
+ className="viber-carousel-preview-image"
254
+ alt="Viber carousel card"
255
+ />
256
+ ) : (
257
+ <CapRow className="viber-carousel-preview-image-placeholder" />
258
+ )}
259
+ <CapRow className="viber-carousel-preview-card-body">
260
+ {hasTrimmedText(card?.text) ? (
261
+ <CapLabel type="label15" className="viber-carousel-preview-text">
262
+ {card?.text}
263
+ </CapLabel>
264
+ ) : (
265
+ <CapLabel type="label15" className="viber-carousel-preview-text-placeholder" />
266
+ )}
267
+ {(card?.buttons?.filter((cardButton) => hasTrimmedText(cardButton?.title)) ?? [])
268
+ .slice(0, 2)
269
+ .map((cardButton, btnIndex) => {
270
+ const trimmedCardButtonTitle = getTrimmedText(cardButton?.title);
271
+ return (
272
+ <CapLabel
273
+ className={`viber-carousel-preview-button ${btnIndex === 1 ? 'viber-carousel-preview-button-secondary' : ''}`}
274
+ key={`viber-carousel-preview-btn-${index}-${btnIndex}-${trimmedCardButtonTitle}`}
275
+ >
276
+ {trimmedCardButtonTitle}
277
+ </CapLabel>
278
+ );
279
+ })}
280
+ </CapRow>
281
+ </CapRow>
282
+ ))}
283
+ </CapRow>
284
+ </CapRow>
285
+ </>
286
+ )}
287
+ {!showCarouselInPreview && (
288
+ <CapLabel type="label1" className="viber-timestamp">
289
+ {timestamp}
290
+ </CapLabel>
291
+ )}
184
292
  <CapRow className="empty-placeholder" />
185
293
  </CapRow>
186
294
 
@@ -214,6 +322,16 @@ ViberPreviewContent.propTypes = {
214
322
  viberVideoPreviewImg: PropTypes.string,
215
323
  }),
216
324
  buttonText: PropTypes.string,
325
+ type: PropTypes.string,
326
+ cards: PropTypes.arrayOf(PropTypes.shape({
327
+ text: PropTypes.string,
328
+ mediaUrl: PropTypes.string,
329
+ buttons: PropTypes.arrayOf(PropTypes.shape({
330
+ title: PropTypes.string,
331
+ action: PropTypes.string,
332
+ })),
333
+ })),
334
+ showCarouselEditorPreview: PropTypes.bool,
217
335
  }),
218
336
  }),
219
337
  device: PropTypes.oneOf([ANDROID, IOS]),
@@ -2116,6 +2116,8 @@
2116
2116
  flex: 1;
2117
2117
  display: flex;
2118
2118
  flex-direction: column;
2119
+ overflow-y: auto;
2120
+ -webkit-overflow-scrolling: touch;
2119
2121
  padding: 0 $CAP_SPACE_16;
2120
2122
  background-color: #ffffff;
2121
2123
  margin-left: $CAP_SPACE_06;
@@ -2141,6 +2143,12 @@
2141
2143
  margin-top: $CAP_SPACE_16;
2142
2144
  width: 68%;
2143
2145
 
2146
+ &.viber-preview-carousel {
2147
+ width: 100%;
2148
+ margin-left: $CAP_SPACE_12;
2149
+ max-height: none;
2150
+ }
2151
+
2144
2152
  // Account icon (from TemplatePreview line 1146-1160)
2145
2153
  .viber-account-icon {
2146
2154
  width: $CAP_SPACE_20;
@@ -2169,6 +2177,18 @@
2169
2177
  border-radius: $CAP_SPACE_04;
2170
2178
  padding: $CAP_SPACE_04;
2171
2179
 
2180
+ &.viber-message-pop-carousel {
2181
+ width: 100%;
2182
+ left: 0;
2183
+ margin-top: 0;
2184
+ padding: 0;
2185
+ background: transparent;
2186
+ display: flex;
2187
+ flex-direction: column;
2188
+ align-items: flex-start;
2189
+ gap: $CAP_SPACE_06;
2190
+ }
2191
+
2172
2192
  // Text Viber preview (from TemplatePreview line 1166-1174)
2173
2193
  .viber-message-text {
2174
2194
  margin: 0.107rem $CAP_SPACE_06 $CAP_SPACE_01 0.5rem;
@@ -2240,6 +2260,149 @@
2240
2260
  }
2241
2261
  }
2242
2262
 
2263
+ .viber-carousel-message-pop,
2264
+ .viber-carousel-cards-pop {
2265
+ width: 100%;
2266
+ background: $CAP_G08;
2267
+ border-radius: $CAP_SPACE_06;
2268
+ padding: $CAP_SPACE_08;
2269
+ }
2270
+
2271
+ .viber-carousel-message-pop {
2272
+ margin-top: 0;
2273
+ width: 68%;
2274
+ border-radius: 0 $CAP_SPACE_06 $CAP_SPACE_06 $CAP_SPACE_06;
2275
+ }
2276
+
2277
+ .viber-carousel-cards-pop {
2278
+ margin-top: 0;
2279
+ width: 100%;
2280
+ background: transparent;
2281
+ border: none;
2282
+ border-radius: 0;
2283
+ padding: 0;
2284
+ }
2285
+
2286
+ .viber-carousel-message-box {
2287
+ width: 100%;
2288
+ min-height: 2.25rem;
2289
+ height: auto;
2290
+ border-radius: $CAP_SPACE_04;
2291
+ background: transparent;
2292
+ padding: 0 $CAP_SPACE_08;
2293
+ display: flex;
2294
+ align-items: center;
2295
+ }
2296
+
2297
+ .viber-carousel-message-box-text {
2298
+ color: $CAP_G01;
2299
+ margin: 0.107rem $CAP_SPACE_06 $CAP_SPACE_01 0.5rem;
2300
+ white-space: normal;
2301
+ word-break: break-word;
2302
+ overflow: visible;
2303
+ width: 100%;
2304
+ }
2305
+
2306
+ .viber-carousel-message-box-placeholder {
2307
+ width: 100%;
2308
+ height: 0.875rem;
2309
+ border-radius: $CAP_SPACE_04;
2310
+ background: $CAP_G07;
2311
+ }
2312
+
2313
+ .viber-carousel-message-timestamp,
2314
+ .viber-carousel-cards-timestamp {
2315
+ display: block;
2316
+ text-align: right;
2317
+ margin-top: $CAP_SPACE_06;
2318
+ color: $CAP_G04;
2319
+ }
2320
+
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
+
2243
2406
  .empty-placeholder {
2244
2407
  height: $CAP_SPACE_08;
2245
2408
  }
@@ -1554,6 +1554,8 @@ const CommonTestAndPreview = (props) => {
1554
1554
  let imageData = null;
1555
1555
  let videoData = null;
1556
1556
  let buttonData = null;
1557
+ let cardsData = [];
1558
+ let messageType = '';
1557
1559
  let accountId = null;
1558
1560
  let accountDetails = null;
1559
1561
  let scenarioKey = '';
@@ -1568,6 +1570,8 @@ const CommonTestAndPreview = (props) => {
1568
1570
  imageData = formDataObj.image || null;
1569
1571
  videoData = formDataObj.video || null;
1570
1572
  buttonData = formDataObj.button || null;
1573
+ cardsData = formDataObj.cards || [];
1574
+ messageType = formDataObj.type || '';
1571
1575
  accountId = formDataObj.accountId || null;
1572
1576
  accountDetails = formDataObj.accountDetails || null;
1573
1577
  scenarioKey = formDataObj.scenarioKey || VIBER_API_SCENARIO_KEY;
@@ -1594,6 +1598,8 @@ const CommonTestAndPreview = (props) => {
1594
1598
  url: formDataObj?.buttonURL || '',
1595
1599
  };
1596
1600
  }
1601
+ cardsData = viberPreview.cards || formDataObj?.cards || [];
1602
+ messageType = viberPreview.type || formDataObj?.type || '';
1597
1603
  // Extract account info from parent formDataObj if available
1598
1604
  accountId = formDataObj.accountId || null;
1599
1605
  accountDetails = formDataObj.accountDetails || null;
@@ -1636,6 +1642,10 @@ const CommonTestAndPreview = (props) => {
1636
1642
  text: messageText,
1637
1643
  };
1638
1644
 
1645
+ if (messageType === CHANNELS.VIBER) {
1646
+ messageType = '';
1647
+ }
1648
+
1639
1649
  // Add image if present
1640
1650
  if (imageData && imageData.url) {
1641
1651
  viberContent.image = {
@@ -1664,6 +1674,19 @@ const CommonTestAndPreview = (props) => {
1664
1674
  }
1665
1675
  }
1666
1676
 
1677
+ if (messageType === MEDIA_TYPE_CAROUSEL || (Array.isArray(cardsData) && cardsData.length)) {
1678
+ viberContent.type = MEDIA_TYPE_CAROUSEL;
1679
+ viberContent.cards = (cardsData || []).map((card) => ({
1680
+ text: card?.text || '',
1681
+ mediaUrl: card?.mediaUrl || '',
1682
+ buttons: (card?.buttons || []).map((button) => ({
1683
+ title: button?.title || '',
1684
+ action: button?.action || '',
1685
+ })),
1686
+ }));
1687
+ delete viberContent.button;
1688
+ }
1689
+
1667
1690
  // Resolve tags in text if custom values are provided
1668
1691
  if (customValuesObj && Object.keys(customValuesObj).length > 0 && viberContent.text) {
1669
1692
  viberContent.text = resolveTagsInText(viberContent.text, customValuesObj);
@@ -2010,6 +2033,13 @@ const CommonTestAndPreview = (props) => {
2010
2033
  // Only use previewDataHtml if preview call was made
2011
2034
  if (hasPreviewCallBeenMade && previewDataHtml?.resolvedBody) {
2012
2035
  resolvedContent = previewDataHtml.resolvedBody;
2036
+ if (typeof resolvedContent === 'string') {
2037
+ try {
2038
+ resolvedContent = JSON.parse(resolvedContent);
2039
+ } catch (e) {
2040
+ resolvedContent = null;
2041
+ }
2042
+ }
2013
2043
  }
2014
2044
 
2015
2045
  // Parse content if it's a string
@@ -2021,15 +2051,25 @@ const CommonTestAndPreview = (props) => {
2021
2051
  parsedViberContent = {};
2022
2052
  }
2023
2053
  }
2024
- // Use resolvedContent if available (from preview call), otherwise use raw content
2054
+ // Merge template preview state with API resolved body so carousel type/cards survive slim responses
2025
2055
  if (resolvedContent && typeof resolvedContent === 'object') {
2026
- contentObj = { ...resolvedContent };
2027
- // Merge in accountName and brandName from raw content if not in resolvedContent
2028
- if (parsedViberContent?.accountName && !contentObj.accountName) {
2029
- contentObj.accountName = parsedViberContent.accountName;
2056
+ const base = parsedViberContent && typeof parsedViberContent === 'object' ? parsedViberContent : {};
2057
+ contentObj = {
2058
+ ...base,
2059
+ ...resolvedContent,
2060
+ viberPreviewContent: {
2061
+ ...base.viberPreviewContent,
2062
+ ...resolvedContent.viberPreviewContent,
2063
+ ...(resolvedContent.messageContent != null && typeof resolvedContent.messageContent === 'string'
2064
+ ? { messageContent: resolvedContent.messageContent }
2065
+ : {}),
2066
+ },
2067
+ };
2068
+ if (base.accountName && !contentObj.accountName) {
2069
+ contentObj.accountName = base.accountName;
2030
2070
  }
2031
- if (parsedViberContent?.brandName && !contentObj.brandName) {
2032
- contentObj.brandName = parsedViberContent.brandName;
2071
+ if (base.brandName && !contentObj.brandName) {
2072
+ contentObj.brandName = base.brandName;
2033
2073
  }
2034
2074
  } else {
2035
2075
  // Use raw content if no preview call was made or resolvedContent is not available