@capillarytech/creatives-library 9.0.47 → 9.0.49-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 (30) hide show
  1. package/constants/unified.js +1 -0
  2. package/package.json +1 -1
  3. package/v2Components/CommonTestAndPreview/UnifiedPreview/SmsPreviewContent.js +21 -1
  4. package/v2Components/CommonTestAndPreview/UnifiedPreview/ViberCarouselPreviewCards.js +127 -0
  5. package/v2Components/CommonTestAndPreview/UnifiedPreview/ViberPreviewContent.js +106 -15
  6. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +144 -1
  7. package/v2Components/CommonTestAndPreview/UnifiedPreview/_viberCarouselPreviewCards.scss +133 -0
  8. package/v2Components/CommonTestAndPreview/constants.js +2 -0
  9. package/v2Components/CommonTestAndPreview/index.js +240 -26
  10. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/SmsPreviewContent.test.js +32 -0
  11. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/ViberPreviewContent.test.js +364 -0
  12. package/v2Components/CommonTestAndPreview/tests/utils.test.js +49 -0
  13. package/v2Components/CommonTestAndPreview/utils.js +20 -0
  14. package/v2Components/SmsFallback/constants.js +19 -0
  15. package/v2Components/SmsFallback/index.js +0 -3
  16. package/v2Containers/SmsTrai/Edit/constants.js +2 -0
  17. package/v2Containers/SmsTrai/Edit/dltVarTypes.js +88 -0
  18. package/v2Containers/SmsTrai/Edit/index.js +198 -92
  19. package/v2Containers/SmsTrai/Edit/index.scss +117 -1
  20. package/v2Containers/SmsTrai/Edit/messages.js +40 -0
  21. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +21164 -4559
  22. package/v2Containers/SmsTrai/Edit/tests/dltVarTypes.test.js +100 -0
  23. package/v2Containers/Templates/_templates.scss +202 -1
  24. package/v2Containers/Templates/index.js +210 -42
  25. package/v2Containers/Templates/messages.js +12 -0
  26. package/v2Containers/Viber/constants.js +21 -0
  27. package/v2Containers/Viber/index.js +711 -43
  28. package/v2Containers/Viber/index.scss +175 -0
  29. package/v2Containers/Viber/messages.js +121 -0
  30. package/v2Containers/Viber/tests/index.test.js +80 -0
@@ -73,6 +73,7 @@ import * as ebillActions from '../Ebill/actions';
73
73
  import * as emailActions from '../Email/actions';
74
74
  import * as lineActions from '../Line/Container/actions';
75
75
  import * as viberActions from '../Viber/actions';
76
+ import { VIBER_MEDIA_TYPES } from '../Viber/constants';
76
77
  import * as facebookActions from '../Facebook/actions';
77
78
  import * as whatsappActions from '../Whatsapp/actions';
78
79
  import * as rcsActions from '../Rcs/actions';
@@ -142,7 +143,10 @@ import {CREATIVE} from '../Facebook/constants';
142
143
  import videoPlay from '../../assets/videoPlay.svg';
143
144
  import whatsappImageEmptyPreview from '../../v2Components/TemplatePreview/assets/images/empty_image_preview.svg';
144
145
  import whatsappVideoEmptyPreview from '../../v2Components/TemplatePreview/assets/images/empty_video_preview.svg';
145
- import { CAP_SPACE_16, CAP_G08, CAP_G05, CAP_SPACE_08, CAP_SPACE_12 } from '@capillarytech/cap-ui-library/styled/variables';
146
+ import {
147
+ CAP_SPACE_16, CAP_G08, CAP_G05, CAP_SPACE_08, CAP_SPACE_12, CAP_YELLOW01,
148
+ } from '@capillarytech/cap-ui-library/styled/variables';
149
+ import { SMS_CATEGORY_TAG_STYLES, SMS_CATEGORY_LABELS } from '../../v2Components/SmsFallback/constants';
146
150
  import { GA } from '@capillarytech/cap-ui-utils';
147
151
  import { MAPP_SDK } from '../InApp/constants';
148
152
  import injectReducer from '../../utils/injectReducer';
@@ -158,6 +162,7 @@ import { v2MobilePushSagas } from '../MobilePushNew/sagas';
158
162
  import { AUTO_CAROUSEL, BIG_PICTURE, FILMSTRIP_CAROUSEL, MANUAL_CAROUSEL } from '../MobilePushNew/constants';
159
163
  import CapPageSpinner from '../../v2Components/CapPageSpinner';
160
164
  import webPushSagas from '../WebPush/sagas';
165
+ import { DLT_LEGACY_VAR_REGEX } from '../SmsTrai/Edit/dltVarTypes';
161
166
  const withMobilePushNewSaga = injectSaga({ key: 'mobilePushNew', saga: v2MobilePushSagas, mode: DAEMON });
162
167
  const withWebPushSaga = injectSaga({ key: 'webPush', saga: webPushSagas, mode: DAEMON });
163
168
 
@@ -454,9 +459,11 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
454
459
  }
455
460
 
456
461
  checkDLTfeatureEnable() {
457
- const {smsRegister, isFullMode} = this.props;
458
- const isTraiDlt = commonUtil.isTraiDLTEnable(isFullMode, smsRegister);
459
- return isTraiDlt;
462
+ const { smsRegister, isFullMode, localTemplatesConfig } = this.props;
463
+ if (commonUtil.isTraiDLTEnable(isFullMode, smsRegister)) return true;
464
+ // Local-templates picker (RCS SMS fallback, campaigns): apply DLT UI whenever the org has
465
+ // the feature, even if the parent context wasn't marked `smsRegister === 'DLT'`.
466
+ return !!localTemplatesConfig?.useLocalTemplates && commonUtil.hasTraiDltFeature();
460
467
  }
461
468
 
462
469
  componentDidMount() {
@@ -1399,6 +1406,11 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
1399
1406
  const image = viberContent.image || {};
1400
1407
  const video = viberContent.video || {};
1401
1408
  const button = viberContent.button || {};
1409
+ const messageType = viberContent.type || '';
1410
+ const cardsRaw = viberContent.cards;
1411
+ const cards = Array.isArray(cardsRaw) ? cardsRaw : [];
1412
+ const isCarousel =
1413
+ messageType === VIBER_MEDIA_TYPES.CAROUSEL || cards.length > 0;
1402
1414
 
1403
1415
  const viberPreview = {
1404
1416
  messageContent: text,
@@ -1416,14 +1428,39 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
1416
1428
  };
1417
1429
  }
1418
1430
 
1431
+ if (isCarousel) {
1432
+ viberPreview.type = VIBER_MEDIA_TYPES.CAROUSEL;
1433
+ viberPreview.cards = cards.map((card) => ({
1434
+ text: card?.text || '',
1435
+ mediaUrl: card?.mediaUrl || '',
1436
+ buttons: (card?.buttons || []).map((btn) => ({
1437
+ title: btn?.title || '',
1438
+ action: btn?.action || '',
1439
+ })),
1440
+ }));
1441
+ viberPreview.showCarouselEditorPreview = true;
1442
+ }
1443
+
1419
1444
  // Extract account name
1420
1445
  const accountName = get(template, 'definition.accountName', '');
1421
1446
 
1422
1447
  // Return Viber content object (same as Viber/index.js getTemplateContent)
1423
1448
  return {
1424
1449
  viberPreviewContent: viberPreview,
1425
- accountName: accountName ? [accountName] : [],
1426
- brandName: accountName ? [accountName] : [],
1450
+ accountName: accountName || '',
1451
+ brandName: accountName || '',
1452
+ messageContent: text,
1453
+ ...(isCarousel && {
1454
+ type: VIBER_MEDIA_TYPES.CAROUSEL,
1455
+ cards: viberPreview.cards,
1456
+ }),
1457
+ ...(!isCarousel && !isEmpty(button) && button.text && (button.url || viberContent.buttonURL) && {
1458
+ button: {
1459
+ text: button.text,
1460
+ url: button.url || viberContent.buttonURL || '',
1461
+ },
1462
+ }),
1463
+ buttonURL: button.url || viberContent.buttonURL || '',
1427
1464
  };
1428
1465
  }
1429
1466
 
@@ -2045,11 +2082,21 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
2045
2082
  const isCardArchiveEligible = isArchivalEnabled && this.isChannelArchiveEligible(currentChannel, cardWhatsappStatus, cardRcsStatus);
2046
2083
  const isArchivedMode = isArchivalEnabled && get(this.props, 'Templates.isArchivedMode', false);
2047
2084
  const isAnyArchiveInProgress = isArchivalEnabled && !!(get(this.props, 'Templates.archiveInProgress') || get(this.props, 'Templates.unarchiveInProgress') || get(this.props, 'Templates.bulkArchiveInProgress') || get(this.props, 'Templates.bulkUnarchiveInProgress'));
2085
+ const smsBaseForLegacyCheck = template?.versions?.base || {};
2086
+ const updatedSmsEditorForLegacy = smsBaseForLegacyCheck['updated-sms-editor'];
2087
+ const updatedSmsEditorForLegacyJoined = Array.isArray(updatedSmsEditorForLegacy)
2088
+ ? updatedSmsEditorForLegacy.join('')
2089
+ : updatedSmsEditorForLegacy;
2090
+ const smsBodyForLegacyCheck = `${updatedSmsEditorForLegacyJoined || ''}${smsBaseForLegacyCheck['sms-editor'] || ''}`;
2091
+ const isDltLegacyTemplate = currentChannel === SMS
2092
+ && isTraiDltFeature
2093
+ && !this.props.isFullMode
2094
+ && DLT_LEGACY_VAR_REGEX.test(smsBodyForLegacyCheck);
2048
2095
  const templateData = {
2049
2096
  key: `${currentChannel}-card-${template?.name}`,
2050
2097
  title: (
2051
2098
  <span className="template-card-title" title={template?.name}>
2052
- {isCardArchiveEligible && this.renderCardSelectionCheckbox({ templateId: template._id, selectedIds: selectedIdsArrayForCard, isDisabled: isAnyArchiveInProgress })}
2099
+ {isCardArchiveEligible && this.renderCardSelectionCheckbox({ templateId: template._id, selectedIds: selectedIdsArrayForCard, isDisabled: isAnyArchiveInProgress || isDltLegacyTemplate })}
2053
2100
  <CapLabel.CapLabelInline type="label1" title={template?.name} className="template-card-name">
2054
2101
  {template?.name}
2055
2102
  {currentChannel === INAPP && (
@@ -2109,20 +2156,39 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
2109
2156
  })()
2110
2157
  ],
2111
2158
  hoverOption: isArchivedMode || !this.canPerform(PERMISSIONS.CREATIVE_EDIT) ? null : (
2112
- <CapButton
2113
- className={
2114
- this.props.isFullMode
2115
- ? `edit-${channelLowerCase}`
2116
- : `select-${channelLowerCase}`
2117
- }
2118
- onClick={e =>
2119
- handlers.handleEditClick(e, template, undefined, undefined, {
2120
- account: this.state.selectedAccount
2121
- })
2122
- }
2123
- >
2124
- {hoverButtonText}
2125
- </CapButton>
2159
+ isDltLegacyTemplate ? (
2160
+ <CapTooltip
2161
+ title={this.props.intl.formatMessage(messages.smsLegacyBlockedTooltip)}
2162
+ >
2163
+ <CapLabel.CapLabelInline>
2164
+ <CapButton
2165
+ className={
2166
+ this.props.isFullMode
2167
+ ? `edit-${channelLowerCase}`
2168
+ : `select-${channelLowerCase}`
2169
+ }
2170
+ disabled
2171
+ >
2172
+ {hoverButtonText}
2173
+ </CapButton>
2174
+ </CapLabel.CapLabelInline>
2175
+ </CapTooltip>
2176
+ ) : (
2177
+ <CapButton
2178
+ className={
2179
+ this.props.isFullMode
2180
+ ? `edit-${channelLowerCase}`
2181
+ : `select-${channelLowerCase}`
2182
+ }
2183
+ onClick={e =>
2184
+ handlers.handleEditClick(e, template, undefined, undefined, {
2185
+ account: this.state.selectedAccount
2186
+ })
2187
+ }
2188
+ >
2189
+ {hoverButtonText}
2190
+ </CapButton>
2191
+ )
2126
2192
  )
2127
2193
  };
2128
2194
  const {
@@ -2222,22 +2288,49 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
2222
2288
  );
2223
2289
  }
2224
2290
  switch (currentChannel) {
2225
- case SMS:
2291
+ case SMS: {
2292
+ const smsBaseForCard = template.versions.base || {};
2293
+ const updatedSmsEditor = smsBaseForCard['updated-sms-editor'];
2294
+ const normalizedUpdatedSmsEditor = Array.isArray(updatedSmsEditor)
2295
+ ? updatedSmsEditor.join('')
2296
+ : updatedSmsEditor;
2297
+ const smsBodyForCard = normalizedUpdatedSmsEditor || smsBaseForCard['sms-editor'] || '';
2298
+ const hasLegacyVarToken = DLT_LEGACY_VAR_REGEX.test(smsBodyForCard);
2299
+ const rawCategoryLabel = smsBaseForCard.type || '';
2300
+ const categoryLabel = rawCategoryLabel.toLowerCase() === SMS_CATEGORY_LABELS.SERVICE_EXPLICIT
2301
+ ? this.props.intl.formatMessage(messages.promotional)
2302
+ : rawCategoryLabel;
2303
+ const categoryTagStyle = SMS_CATEGORY_TAG_STYLES[categoryLabel.toLowerCase()] || {};
2226
2304
  templateData.content = isTraiDltFeature ? (
2227
2305
  <>
2228
- <CapLabel type="label3" style={{ marginBottom: CAP_SPACE_16 }}>
2229
- {template.versions.base.type}
2230
- </CapLabel>
2231
- <CapLabel type="label1">
2232
- {template.versions.base['updated-sms-editor'] === ''
2233
- ? template.versions.base['sms-editor']
2234
- : template.versions.base['updated-sms-editor']?.join('')}
2235
- </CapLabel>
2306
+ {hasLegacyVarToken ? (
2307
+ <CapColoredTag
2308
+ tagColor="rgba(254, 197, 46, 0.15)"
2309
+ tagTextColor={CAP_YELLOW01}
2310
+ tagHeight="1.25rem"
2311
+ tagFontSize="0.75rem"
2312
+ className="sms-template-category-tag"
2313
+ >
2314
+ {this.props.intl.formatMessage(messages.smsLegacyFormatBadge)}
2315
+ </CapColoredTag>
2316
+ ) : categoryLabel ? (
2317
+ <CapColoredTag
2318
+ tagColor={categoryTagStyle.tagColor}
2319
+ tagTextColor={categoryTagStyle.tagTextColor}
2320
+ tagHeight="1.25rem"
2321
+ tagFontSize="0.75rem"
2322
+ className="sms-template-category-tag"
2323
+ >
2324
+ {categoryLabel}
2325
+ </CapColoredTag>
2326
+ ) : null}
2327
+ <CapLabel type="label1">{smsBodyForCard}</CapLabel>
2236
2328
  </>
2237
2329
  ) : (
2238
2330
  template.versions.base['sms-editor']
2239
2331
  );
2240
2332
  break;
2333
+ }
2241
2334
  case EMAIL: {
2242
2335
  const url = template.versions.base.preview_http_url;
2243
2336
  if (url) {
@@ -2436,10 +2529,59 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
2436
2529
  image = {},
2437
2530
  button = {},
2438
2531
  video = {},
2532
+ type = '',
2533
+ cards = [],
2439
2534
  } = {},
2440
2535
  } = {},
2441
2536
  } = template.versions.base;
2537
+ const isViberCarousel = type === VIBER_MEDIA_TYPES.CAROUSEL;
2442
2538
  templateData.content = text;
2539
+ if (isViberCarousel) {
2540
+ const previewCards = Array.isArray(cards) ? cards.slice(0, 1) : [];
2541
+ // Bypass CapCustomCard Viber Meta + line-clamp (clips title/buttons for tall images).
2542
+ // Parent class `viber-carousel-static` scopes listing styles in _templates.scss.
2543
+ // cardType hits the default content path; keep VIBER for channel card styles.
2544
+ templateData.cardType = 'VIBER_CAROUSEL_PREVIEW';
2545
+ templateData.className = 'viber-carousel-static VIBER';
2546
+ templateData.content = (
2547
+ <CapRow vertical className="content">
2548
+ <CapRow className="message-box">
2549
+ <CapLabel type="label1" className="message">
2550
+ {text}
2551
+ </CapLabel>
2552
+ </CapRow>
2553
+ <CapRow className="cards">
2554
+ {previewCards?.map((card, cardIdx) => (
2555
+ <CapRow vertical className="card" key={`viber-carousel-static-card-${cardIdx}`}>
2556
+ {card?.mediaUrl ? (
2557
+ <CapImage src={card.mediaUrl} className="image" />
2558
+ ) : (
2559
+ <CapRow className="image-placeholder" />
2560
+ )}
2561
+ <CapLabel type="label1" className="text">
2562
+ {card?.text}
2563
+ </CapLabel>
2564
+ <CapRow vertical className="buttons">
2565
+ {(Array.isArray(card?.buttons) && card.buttons.length
2566
+ ? card.buttons
2567
+ : [{}, {}]
2568
+ ).slice(0, 2).map((carouselButton, btnIdx) => (
2569
+ <CapLabel
2570
+ key={`viber-carousel-static-btn-${cardIdx}-${btnIdx}`}
2571
+ type="label1"
2572
+ className={`button${btnIdx === 1 ? ' button-secondary' : ''}`}
2573
+ >
2574
+ {(carouselButton?.title || '').trim()}
2575
+ </CapLabel>
2576
+ ))}
2577
+ </CapRow>
2578
+ </CapRow>
2579
+ ))}
2580
+ </CapRow>
2581
+ </CapRow>
2582
+ );
2583
+ break;
2584
+ }
2443
2585
  if (!isEmpty(image)) {
2444
2586
  const { url = '' } = image;
2445
2587
  templateData.url = url;
@@ -2761,6 +2903,12 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
2761
2903
  )}
2762
2904
  </CapRow>
2763
2905
  {[WHATSAPP, ZALO, INAPP,RCS].includes(currentChannel) && this.selectedFilters()}
2906
+ {currentChannel === SMS && this.checkDLTfeatureEnable() && (
2907
+ <CapInfoNote
2908
+ className="sms-service-explicit-retired-banner"
2909
+ message={this.props.intl.formatMessage(messages.smsServiceExplicitRetiredBanner)}
2910
+ />
2911
+ )}
2764
2912
  {<div>
2765
2913
  {!isEmpty(filteredTemplates) || !isEmpty(this.state.searchText) || !isEmpty(this.props.Templates.templateError) ? (
2766
2914
  <div className={!isEmpty(this.state.searchText) && isEmpty(cardDataList) ? '' : this.isFullMode() ? "v2-pagination-container" : "v2-pagination-container-half"}>
@@ -3535,6 +3683,22 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
3535
3683
  CapNotification.error({ message: this.props.intl.formatMessage(messages.cannotEditArchivedTemplate) });
3536
3684
  return;
3537
3685
  }
3686
+ if (!this.props.isFullMode
3687
+ && this.checkDLTfeatureEnable()
3688
+ && (this.state.channel || '').toLowerCase() === SMS_LOWERCASE) {
3689
+ const smsBase = template?.versions?.base || {};
3690
+ const updatedSms = smsBase['updated-sms-editor'];
3691
+ const updatedSmsJoined = Array.isArray(updatedSms) ? updatedSms.join('') : updatedSms;
3692
+ // Check BOTH candidate fields — some legacy templates keep the body only in `sms-editor`
3693
+ // while others have it in `updated-sms-editor`. Concatenating catches either.
3694
+ const smsBody = `${updatedSmsJoined || ''}${smsBase['sms-editor'] || ''}`;
3695
+ if (DLT_LEGACY_VAR_REGEX.test(smsBody)) {
3696
+ CapNotification.error({
3697
+ message: this.props.intl.formatMessage(messages.smsLegacyBlockedTooltip),
3698
+ });
3699
+ return;
3700
+ }
3701
+ }
3538
3702
  if (modeType && modeType !== undefined) {
3539
3703
  this.setState({modeType});
3540
3704
  }
@@ -4788,7 +4952,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
4788
4952
  <CapRadio.CapRadioGroup className="line-filters" defaultValue={smsFilter} onChange={this.setSMSFilter}>
4789
4953
  {
4790
4954
  (() => {
4791
- const { ALL, SERVICE_IMPLICIT, SERVICE_EXPLICIT, PROMOTIONAL } = SMS_FILTERS;
4955
+ const { ALL, SERVICE_IMPLICIT, PROMOTIONAL } = SMS_FILTERS;
4792
4956
  return (
4793
4957
  <>
4794
4958
  <CapRadio.Button value={ALL}><CapLabel type="label2">
@@ -4797,9 +4961,6 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
4797
4961
  <CapRadio.Button value={PROMOTIONAL}><CapLabel type="label2">
4798
4962
  <FormattedMessage {...messages.promotional} />
4799
4963
  </CapLabel></CapRadio.Button>
4800
- <CapRadio.Button value={SERVICE_EXPLICIT}><CapLabel type="label2">
4801
- <FormattedMessage {...messages.serviceExplicit} />
4802
- </CapLabel></CapRadio.Button>
4803
4964
  <CapRadio.Button value={SERVICE_IMPLICIT}><CapLabel type="label2">
4804
4965
  <FormattedMessage {...messages.serviceImplicit} />
4805
4966
  </CapLabel></CapRadio.Button>
@@ -5107,15 +5268,22 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
5107
5268
  ? this.props.Templates.selectedWhatsappAccount.name
5108
5269
  : null
5109
5270
  }
5110
- // Pass formData for EMAIL and SMS channels for tag extraction
5271
+ // Pass formData for tag extraction (EMAIL/SMS use nested formData; VIBER uses content object)
5111
5272
  formData={
5112
- this.state.testAndPreviewContent &&
5113
- (this.state.channel?.toUpperCase() === EMAIL ||
5114
- this.state.channel?.toUpperCase() === SMS) &&
5115
- typeof this.state.testAndPreviewContent === 'object' &&
5116
- this.state.testAndPreviewContent?.formData
5117
- ? this.state.testAndPreviewContent.formData
5118
- : null
5273
+ (() => {
5274
+ const previewContent = this.state.testAndPreviewContent;
5275
+ const channelUpper = this.state.channel?.toUpperCase();
5276
+ if (!previewContent || typeof previewContent !== 'object') {
5277
+ return null;
5278
+ }
5279
+ if ([EMAIL, SMS].includes(channelUpper)) {
5280
+ return previewContent.formData || null;
5281
+ }
5282
+ if (channelUpper === VIBER) {
5283
+ return previewContent;
5284
+ }
5285
+ return null;
5286
+ })()
5119
5287
  }
5120
5288
  />
5121
5289
  )}
@@ -538,6 +538,18 @@ export default defineMessages({
538
538
  id: `${scope}.serviceImplicit`,
539
539
  defaultMessage: 'Service implicit',
540
540
  },
541
+ "smsServiceExplicitRetiredBanner": {
542
+ id: `${scope}.smsServiceExplicitRetiredBanner`,
543
+ defaultMessage: 'Service Explicit is retired. Existing Service Explicit templates have been moved under the Promotional category.',
544
+ },
545
+ "smsLegacyFormatBadge": {
546
+ id: `${scope}.smsLegacyFormatBadge`,
547
+ defaultMessage: 'Legacy format',
548
+ },
549
+ "smsLegacyBlockedTooltip": {
550
+ id: `${scope}.smsLegacyBlockedTooltip`,
551
+ defaultMessage: "This template can't be used until re-registered with typed variables on the DLT portal.",
552
+ },
541
553
  "uploadTemplate": {
542
554
  id: `${scope}.uploadTemplate`,
543
555
  defaultMessage: 'Upload template',
@@ -47,7 +47,24 @@ export const VIBER_MEDIA_TYPES = {
47
47
  TEXT: 'TEXT',
48
48
  IMAGE: 'IMAGE',
49
49
  VIDEO: 'VIDEO',
50
+ CAROUSEL: 'CAROUSEL',
50
51
  };
52
+ export const VIBER_CAROUSEL_MIN_CARDS = 2;
53
+ export const VIBER_CAROUSEL_MAX_CARDS = 5;
54
+ export const VIBER_CAROUSEL_MAX_BUTTONS = 2;
55
+ export const VIBER_CAROUSEL_CARD_TITLE_MIN_LENGTH = 2;
56
+ export const VIBER_CAROUSEL_CARD_TITLE_MAX_LENGTH = 38;
57
+ export const VIBER_CAROUSEL_FIRST_BUTTON_TITLE_MAX_LENGTH = 10;
58
+ export const VIBER_CAROUSEL_SECOND_BUTTON_TITLE_MAX_LENGTH = 12;
59
+ export const VIBER_CAROUSEL_BUTTON_URL_MAX_LENGTH = 1000;
60
+ export const STATIC_URL = 'STATIC_URL';
61
+ export const DYNAMIC_URL = 'DYNAMIC_URL';
62
+ /** Recommended / validated carousel image height in pixels (passed to image upload). */
63
+ export const VIBER_CAROUSEL_IMG_HEIGHT = 600;
64
+ /** Recommended / validated carousel image width in pixels (passed to image upload). */
65
+ export const VIBER_CAROUSEL_IMG_WIDTH = 696;
66
+ /** Maximum carousel image file size (bytes). 10_000_000 ≈ 10 MB (decimal). */
67
+ export const VIBER_CAROUSEL_IMG_SIZE = 10000000;
51
68
  export const ALLOWED_IMAGE_EXTENSIONS_REGEX_VIBER = /\.(jpe?g|png)$/i;
52
69
  export const ALLOWED_EXTENSIONS_VIDEO_REGEX_VIBER = /\.(mp4|3gp|m4v|mov)$/i;
53
70
  export const NONE = 'NONE';
@@ -69,6 +86,10 @@ export const mediaRadioOptions = [
69
86
  value: VIBER_MEDIA_TYPES.VIDEO,
70
87
  label: <FormattedMessage {...messages.mediaVideo} />,
71
88
  },
89
+ {
90
+ value: VIBER_MEDIA_TYPES.CAROUSEL,
91
+ label: <FormattedMessage {...messages.mediaCarousel} />,
92
+ },
72
93
  ];
73
94
 
74
95
  export const buttonRadioOptions = [