@capillarytech/creatives-library 8.0.353-alpha.0 → 8.0.353-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.
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.0",
4
+ "version": "8.0.353-alpha.1",
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
 
@@ -43,7 +50,34 @@ const ViberPreviewContent = ({
43
50
  imageURL = '',
44
51
  videoParams = {},
45
52
  buttonText = '',
53
+ type = '',
54
+ cards = [],
55
+ showCarouselEditorPreview = false,
46
56
  } = viberContent;
57
+ const hasCarouselContent = type === MEDIA_TYPE_CAROUSEL;
58
+
59
+ const cardHasMeaningfulContent = (card) => {
60
+ if (!card || typeof card !== 'object') return false;
61
+ if ((card.text || '').trim()) return true;
62
+ if ((card.mediaUrl || '').trim()) return true;
63
+ const buttons = card.buttons || [];
64
+ return buttons.some((button) => (button?.title || '').trim());
65
+ };
66
+
67
+ const hasMeaningfulCarousel =
68
+ hasCarouselContent &&
69
+ Array.isArray(cards) &&
70
+ cards.length > 0 &&
71
+ cards.some(cardHasMeaningfulContent);
72
+
73
+ const showCarouselInPreview =
74
+ hasCarouselContent && (Boolean(showCarouselEditorPreview) || hasMeaningfulCarousel);
75
+
76
+ const previewCarouselCards =
77
+ hasCarouselContent && Array.isArray(cards) && cards.length ? cards : hasCarouselContent ? [{}] : [];
78
+
79
+ const trimmedMessageContent = (messageContent || '').trim();
80
+ const trimmedButtonText = (buttonText || '').trim();
47
81
 
48
82
  // Get account name (first letter for icon)
49
83
  const accountIcon = (accountName || brandName || 'V')[0]?.toUpperCase();
@@ -99,8 +133,15 @@ const ViberPreviewContent = ({
99
133
  );
100
134
  }
101
135
 
102
- // Check if there's any content to display
103
- const hasContent = messageContent || imageURL || videoParams?.viberVideoSrc || buttonText;
136
+ // Check if there's any content to display (whitespace-only strings do not count)
137
+ const hasContent = Boolean(
138
+ trimmedMessageContent
139
+ || (imageURL || '').trim()
140
+ || videoParams?.viberVideoSrc
141
+ || trimmedButtonText
142
+ || hasMeaningfulCarousel
143
+ || (hasCarouselContent && showCarouselEditorPreview)
144
+ );
104
145
 
105
146
  // Render normal Viber preview
106
147
  return (
@@ -129,19 +170,21 @@ const ViberPreviewContent = ({
129
170
  {/* Brand Name Display (from TemplatePreview line 1136) */}
130
171
  <CapRow className="msg-container viber-preview">
131
172
  {/* Account Icon (from TemplatePreview line 1146-1160) */}
132
- <CapRow className="viber-account-icon">
133
- {accountIcon}
134
- </CapRow>
173
+ {!hasCarouselContent && (
174
+ <CapRow className="viber-account-icon">
175
+ {accountIcon}
176
+ </CapRow>
177
+ )}
135
178
 
136
179
  {/* Message Bubble (from TemplatePreview line 1161-1223) */}
137
180
  <CapRow className="message-pop align-left viber-message-pop">
138
181
  {/* Text Viber preview */}
139
- {messageContent && (
182
+ {trimmedMessageContent && !hasCarouselContent && (
140
183
  <CapLabel type="label15" className="viber-message-text">{messageContent}</CapLabel>
141
184
  )}
142
185
 
143
186
  {/* Image Viber preview */}
144
- {imageURL && (
187
+ {(imageURL || '').trim() && (
145
188
  <CapImage
146
189
  src={imageURL}
147
190
  className="viber-image-preview"
@@ -171,13 +214,59 @@ const ViberPreviewContent = ({
171
214
  )}
172
215
 
173
216
  {/* Button Viber preview */}
174
- {buttonText && (
217
+ {trimmedButtonText && (
175
218
  <CapLabel className="viber-button-base">
176
219
  <p className="viber-button-card-text">
177
220
  {buttonText}
178
221
  </p>
179
222
  </CapLabel>
180
223
  )}
224
+ {/* Carousel Viber preview */}
225
+ {showCarouselInPreview && (
226
+ <>
227
+ <CapRow className="viber-carousel-message-box">
228
+ {trimmedMessageContent ? (
229
+ <CapLabel type="label15" className="viber-carousel-message-box-text">
230
+ {messageContent}
231
+ </CapLabel>
232
+ ) : (
233
+ <CapRow className="viber-carousel-message-box-placeholder" />
234
+ )}
235
+ </CapRow>
236
+ <CapRow className="viber-carousel-preview-scroll">
237
+ {previewCarouselCards?.map((card, index) => (
238
+ <CapRow className="viber-carousel-preview-card" key={`viber-carousel-preview-card-${index}`}>
239
+ {(card?.mediaUrl || '').trim() ? (
240
+ <CapImage
241
+ src={card?.mediaUrl}
242
+ className="viber-carousel-preview-image"
243
+ alt="Viber carousel card"
244
+ />
245
+ ) : (
246
+ <CapRow className="viber-carousel-preview-image-placeholder" />
247
+ )}
248
+ {(card?.text || '').trim() ? (
249
+ <CapLabel type="label15" className="viber-carousel-preview-text">
250
+ {card?.text}
251
+ </CapLabel>
252
+ ) : (
253
+ <CapLabel type="label15" className="viber-carousel-preview-text-placeholder" />
254
+ )}
255
+ {(card?.buttons?.filter((cardButton) => (cardButton?.title || '').trim()) ?? [])
256
+ .slice(0, 2)
257
+ .map((cardButton, btnIndex) => (
258
+ <CapLabel
259
+ className={`viber-carousel-preview-button ${btnIndex === 1 ? 'viber-carousel-preview-button-secondary' : ''}`}
260
+ key={`viber-carousel-preview-btn-${index}-${btnIndex}-${(cardButton?.title || '').trim()}`}
261
+ >
262
+ {(cardButton?.title || '').trim()}
263
+ </CapLabel>
264
+ ))}
265
+ </CapRow>
266
+ ))}
267
+ </CapRow>
268
+ </>
269
+ )}
181
270
  <CapLabel type="label1" className="viber-timestamp">
182
271
  {timestamp}
183
272
  </CapLabel>
@@ -214,6 +303,16 @@ ViberPreviewContent.propTypes = {
214
303
  viberVideoPreviewImg: PropTypes.string,
215
304
  }),
216
305
  buttonText: PropTypes.string,
306
+ type: PropTypes.string,
307
+ cards: PropTypes.arrayOf(PropTypes.shape({
308
+ text: PropTypes.string,
309
+ mediaUrl: PropTypes.string,
310
+ buttons: PropTypes.arrayOf(PropTypes.shape({
311
+ title: PropTypes.string,
312
+ action: PropTypes.string,
313
+ })),
314
+ })),
315
+ showCarouselEditorPreview: PropTypes.bool,
217
316
  }),
218
317
  }),
219
318
  device: PropTypes.oneOf([ANDROID, IOS]),
@@ -17,7 +17,7 @@ import CapTooltip from '@capillarytech/cap-ui-library/CapTooltip';
17
17
  import CapRow from '@capillarytech/cap-ui-library/CapRow';
18
18
  import { ANDROID, IOS } from '../constants';
19
19
  import messages from '../messages';
20
- import { getWhatsappQuickReply, getWhatsappCarouselButtonView, getWhatsappDocPreview } from '../../../v2Containers/Whatsapp/utils';
20
+ import { getWhatsappQuickReply, getWhatsappCarouselButtonView } from '../../../v2Containers/Whatsapp/utils';
21
21
  import { QUICK_REPLY, PHONE_NUMBER, WHATSAPP_CATEGORIES, TEMPLATE_VARIABLE_REGEX } from '../../../v2Containers/Whatsapp/constants';
22
22
  import videoPlay from '../../../assets/videoPlay.svg';
23
23
  import whatsappImageEmptyPreview from '../../TemplatePreview/assets/images/empty_image_preview.svg';
@@ -256,9 +256,9 @@ const WhatsAppPreviewContent = ({
256
256
  )}
257
257
 
258
258
  {/* Document Preview */}
259
- {content?.whatsappDocSource && content?.whatsappDocParams && (
259
+ {content?.docPreview && (
260
260
  <CapRow className="whatsapp-image">
261
- {getWhatsappDocPreview(content.whatsappDocParams)}
261
+ {content.docPreview}
262
262
  </CapRow>
263
263
  )}
264
264
 
@@ -2240,6 +2240,99 @@
2240
2240
  }
2241
2241
  }
2242
2242
 
2243
+ .viber-carousel-preview-scroll {
2244
+ margin-top: $CAP_SPACE_08;
2245
+ display: flex;
2246
+ overflow-x: auto;
2247
+ gap: $CAP_SPACE_08;
2248
+ white-space: nowrap;
2249
+ scrollbar-width: none;
2250
+
2251
+ &::-webkit-scrollbar {
2252
+ display: none;
2253
+ }
2254
+
2255
+ .viber-carousel-preview-card {
2256
+ min-width: 8.75rem;
2257
+ background: $CAP_WHITE;
2258
+ border-radius: $CAP_SPACE_04;
2259
+ padding: $CAP_SPACE_06;
2260
+ display: flex;
2261
+ flex-direction: column;
2262
+ gap: $CAP_SPACE_04;
2263
+
2264
+ .viber-carousel-preview-image {
2265
+ width: 100%;
2266
+ height: 5.357rem;
2267
+ object-fit: cover;
2268
+ border-radius: $CAP_SPACE_04;
2269
+ }
2270
+
2271
+ .viber-carousel-preview-image-placeholder {
2272
+ width: 100%;
2273
+ height: 5.357rem;
2274
+ border-radius: $CAP_SPACE_04;
2275
+ background: $CAP_G07;
2276
+ }
2277
+
2278
+ .viber-carousel-preview-text {
2279
+ color: $CAP_G01;
2280
+ line-height: 1.3;
2281
+ white-space: normal;
2282
+ }
2283
+
2284
+ .viber-carousel-preview-text-placeholder {
2285
+ width: 100%;
2286
+ height: 0.875rem;
2287
+ border-radius: $CAP_SPACE_04;
2288
+ background: $CAP_G07;
2289
+ min-height: 0.875rem;
2290
+ }
2291
+
2292
+ .viber-carousel-preview-button {
2293
+ color: $CAP_WHITE;
2294
+ background: $CAP_PURPLE01;
2295
+ border-radius: $CAP_SPACE_12;
2296
+ text-align: center;
2297
+ padding: 0.179rem $CAP_SPACE_08;
2298
+ white-space: normal;
2299
+ min-height: 1rem;
2300
+ }
2301
+
2302
+ .viber-carousel-preview-button-secondary {
2303
+ color: $CAP_PURPLE01;
2304
+ background: $CAP_WHITE;
2305
+ border: 1px solid $CAP_PURPLE01;
2306
+ }
2307
+ }
2308
+ }
2309
+
2310
+ .viber-carousel-message-box {
2311
+ width: 100%;
2312
+ height: 2.25rem;
2313
+ border-radius: $CAP_SPACE_04;
2314
+ background: $CAP_WHITE;
2315
+ margin-top: $CAP_SPACE_08;
2316
+ padding: 0 $CAP_SPACE_08;
2317
+ display: flex;
2318
+ align-items: center;
2319
+ }
2320
+
2321
+ .viber-carousel-message-box-text {
2322
+ color: $CAP_G01;
2323
+ white-space: nowrap;
2324
+ overflow: hidden;
2325
+ text-overflow: ellipsis;
2326
+ width: 100%;
2327
+ }
2328
+
2329
+ .viber-carousel-message-box-placeholder {
2330
+ width: 100%;
2331
+ height: 0.875rem;
2332
+ border-radius: $CAP_SPACE_04;
2333
+ background: $CAP_G07;
2334
+ }
2335
+
2243
2336
  .empty-placeholder {
2244
2337
  height: $CAP_SPACE_08;
2245
2338
  }
@@ -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