@capillarytech/creatives-library 8.0.345-alpha.15 → 8.0.345-alpha.17

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.345-alpha.15",
4
+ "version": "8.0.345-alpha.17",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -82,7 +82,7 @@ export const splitTemplateVarString = (str = '', varRegex = DEFAULT_MUSTACHE_VAR
82
82
  if (!str) return [];
83
83
  const matchedVariableTokens = str.match(varRegex) || [];
84
84
  return splitContentByOrderedVarTokens(matchedVariableTokens, str).filter(
85
- (segment) => segment === 0 || segment
85
+ (segment) => segment !== ''
86
86
  );
87
87
  };
88
88
 
@@ -0,0 +1,226 @@
1
+ import { normalizeRcsMessageContentForApi } from '../rcsPayloadUtils';
2
+
3
+ describe('normalizeRcsMessageContentForApi', () => {
4
+ it('defaults missing rcsContent to empty object and still normalizes root smsFallBackContent', () => {
5
+ const item = {
6
+ smsFallBackContent: { message: 'root-only' },
7
+ };
8
+ normalizeRcsMessageContentForApi(item);
9
+ expect(item.rcsContent).toEqual({});
10
+ expect(item.smsFallBackContent).toEqual({ message: 'root-only' });
11
+ });
12
+
13
+ it('moves nested smsFallBackContent out of rcsContent and merges onto root', () => {
14
+ const item = {
15
+ rcsContent: {
16
+ contentType: 'RICHCARD',
17
+ smsFallBackContent: {
18
+ message: 'nested-msg',
19
+ templateConfigs: { registeredSenderIds: ['H1'] },
20
+ },
21
+ },
22
+ smsFallBackContent: { message: 'root-msg' },
23
+ };
24
+ normalizeRcsMessageContentForApi(item);
25
+ expect(item.rcsContent).toEqual({ contentType: 'RICHCARD' });
26
+ expect(item.smsFallBackContent.message).toBe('root-msg');
27
+ expect(item.smsFallBackContent.templateConfigs).toEqual({
28
+ registeredSenderIds: ['H1'],
29
+ });
30
+ });
31
+
32
+ it('nested message merges when root has no message key', () => {
33
+ const item = {
34
+ rcsContent: {
35
+ smsFallBackContent: { message: 'from-nested' },
36
+ },
37
+ };
38
+ normalizeRcsMessageContentForApi(item);
39
+ expect(item.rcsContent).toEqual({});
40
+ expect(item.smsFallBackContent).toEqual({ message: 'from-nested' });
41
+ });
42
+
43
+ it('removes smsFallBackContent when nothing to serialize', () => {
44
+ const item = {
45
+ rcsContent: { smsFallBackContent: {} },
46
+ smsFallBackContent: {},
47
+ };
48
+ normalizeRcsMessageContentForApi(item);
49
+ expect(item.rcsContent).toEqual({});
50
+ expect(item.smsFallBackContent).toBeUndefined();
51
+ });
52
+
53
+ it('does not add templateConfigs when empty', () => {
54
+ const item = {
55
+ rcsContent: {},
56
+ smsFallBackContent: { message: 'x', templateConfigs: {} },
57
+ };
58
+ normalizeRcsMessageContentForApi(item);
59
+ expect(item.smsFallBackContent).toEqual({ message: 'x' });
60
+ });
61
+
62
+ it('serializes templateConfigs only when message is absent but templateConfigs has data', () => {
63
+ const item = {
64
+ rcsContent: {
65
+ smsFallBackContent: {
66
+ templateConfigs: { registeredSenderIds: ['Z'] },
67
+ },
68
+ },
69
+ };
70
+ normalizeRcsMessageContentForApi(item);
71
+ expect(item.smsFallBackContent).toEqual({
72
+ templateConfigs: { registeredSenderIds: ['Z'] },
73
+ });
74
+ });
75
+
76
+ it('includes message in api payload when key exists with empty string', () => {
77
+ const item = {
78
+ smsFallBackContent: { message: '', templateConfigs: { id: 't1' } },
79
+ };
80
+ normalizeRcsMessageContentForApi(item);
81
+ expect(item.smsFallBackContent).toEqual({
82
+ message: '',
83
+ templateConfigs: { id: 't1' },
84
+ });
85
+ });
86
+
87
+ it('merges when legacy nested is null-coalesced', () => {
88
+ const item = {
89
+ rcsContent: {
90
+ contentType: 'TEXT',
91
+ smsFallBackContent: null,
92
+ },
93
+ smsFallBackContent: { message: 'from-root' },
94
+ };
95
+ normalizeRcsMessageContentForApi(item);
96
+ expect(item.rcsContent).toEqual({ contentType: 'TEXT' });
97
+ expect(item.smsFallBackContent).toEqual({ message: 'from-root' });
98
+ });
99
+
100
+ it('folds rcsSmsFallbackVarMapped into message and omits var map from API shape', () => {
101
+ const msg = '{{optout}} {{fullname}} test SMS';
102
+ const varMapped = {
103
+ '{{optout}}_0': '{{city}}',
104
+ '{{fullname}}_2': '{{fullname}}',
105
+ };
106
+ const item = {
107
+ rcsContent: { contentType: 'RICHCARD' },
108
+ smsFallBackContent: {
109
+ message: msg,
110
+ rcsSmsFallbackVarMapped: varMapped,
111
+ },
112
+ };
113
+ normalizeRcsMessageContentForApi(item);
114
+ expect(item.smsFallBackContent).toEqual({
115
+ message: '{{city}} {{fullname}} test SMS',
116
+ });
117
+ expect(item.smsFallBackContent.rcsSmsFallbackVarMapped).toBeUndefined();
118
+ });
119
+
120
+ it('merges nested rcsSmsFallbackVarMapped with root message; root message wins on key clash', () => {
121
+ const nestedVar = { '{{a}}_0': '{{nested}}' };
122
+ const item = {
123
+ rcsContent: {
124
+ contentType: 'RICHCARD',
125
+ smsFallBackContent: {
126
+ message: '{{a}} tail',
127
+ rcsSmsFallbackVarMapped: nestedVar,
128
+ },
129
+ },
130
+ smsFallBackContent: {
131
+ message: '{{a}} tail',
132
+ rcsSmsFallbackVarMapped: { '{{a}}_0': '{{root}}' },
133
+ },
134
+ };
135
+ normalizeRcsMessageContentForApi(item);
136
+ expect(item.smsFallBackContent.message).toBe('{{root}} tail');
137
+ expect(item.smsFallBackContent.rcsSmsFallbackVarMapped).toBeUndefined();
138
+ });
139
+
140
+ it('non-slot var map keys do not change message but var map is still stripped', () => {
141
+ const varMapped = { 0: { label: 'City', tag: '{{city}}' } };
142
+ const item = {
143
+ rcsContent: { contentType: 'RICHCARD' },
144
+ smsFallBackContent: {
145
+ message: 'Hello',
146
+ rcsSmsFallbackVarMapped: varMapped,
147
+ },
148
+ };
149
+ normalizeRcsMessageContentForApi(item);
150
+ expect(item.smsFallBackContent).toEqual({ message: 'Hello' });
151
+ });
152
+
153
+ it('omits rcsSmsFallbackVarMapped when merged value is empty object', () => {
154
+ const item = {
155
+ rcsContent: {
156
+ smsFallBackContent: { rcsSmsFallbackVarMapped: {} },
157
+ },
158
+ smsFallBackContent: { message: 'only-msg' },
159
+ };
160
+ normalizeRcsMessageContentForApi(item);
161
+ expect(item.smsFallBackContent).toEqual({ message: 'only-msg' });
162
+ expect(item.smsFallBackContent.rcsSmsFallbackVarMapped).toBeUndefined();
163
+ });
164
+
165
+ it('removes root-level templateConfigs from RCS message content item', () => {
166
+ const item = {
167
+ rcsContent: { cardType: 'STANDALONE' },
168
+ templateConfigs: {
169
+ templateId: '69b3d33934a7bd0db5bada8e',
170
+ template: '{{registered_store_name}} Its a test message',
171
+ },
172
+ };
173
+ normalizeRcsMessageContentForApi(item);
174
+ expect(item.templateConfigs).toBeUndefined();
175
+ expect(item.rcsContent).toEqual({ cardType: 'STANDALONE' });
176
+ });
177
+
178
+ it('removes templateConfigs nested inside rcsContent', () => {
179
+ const item = {
180
+ rcsContent: {
181
+ cardType: 'STANDALONE',
182
+ templateConfigs: {
183
+ templateId: '69b3d33934a7bd0db5bada8e',
184
+ template: '{{registered_store_name}} Its a test message',
185
+ },
186
+ cardContent: [{ title: 'Card' }],
187
+ },
188
+ };
189
+ normalizeRcsMessageContentForApi(item);
190
+ expect(item.templateConfigs).toBeUndefined();
191
+ expect(item.rcsContent.templateConfigs).toBeUndefined();
192
+ expect(item.rcsContent.cardContent).toEqual([{ title: 'Card' }]);
193
+ });
194
+
195
+ it('strips isSaved from each suggestion in cardContent', () => {
196
+ const item = {
197
+ rcsContent: {
198
+ cardContent: [
199
+ {
200
+ title: 'Card 1',
201
+ suggestions: [
202
+ { type: 'QUICK_REPLY', text: 'Yes', isSaved: true },
203
+ { type: 'CTA', text: 'Go', url: 'https://example.com', isSaved: false },
204
+ ],
205
+ },
206
+ ],
207
+ },
208
+ };
209
+ normalizeRcsMessageContentForApi(item);
210
+ expect(item.rcsContent.cardContent[0].suggestions).toEqual([
211
+ { type: 'QUICK_REPLY', text: 'Yes' },
212
+ { type: 'CTA', text: 'Go', url: 'https://example.com' },
213
+ ]);
214
+ });
215
+
216
+ it('handles cardContent with no suggestions gracefully', () => {
217
+ const item = {
218
+ rcsContent: {
219
+ cardContent: [{ title: 'Card 1' }, { title: 'Card 2', suggestions: [] }],
220
+ },
221
+ };
222
+ normalizeRcsMessageContentForApi(item);
223
+ expect(item.rcsContent.cardContent[0].suggestions).toBeUndefined();
224
+ expect(item.rcsContent.cardContent[1].suggestions).toEqual([]);
225
+ });
226
+ });
@@ -324,10 +324,6 @@ export default defineMessages({
324
324
  id: `${scope}.senderId`,
325
325
  defaultMessage: 'Sender ID',
326
326
  },
327
- rcsSenderIdLabel: {
328
- id: `${scope}.rcsSenderIdLabel`,
329
- defaultMessage: 'RCS sender ID',
330
- },
331
327
  domainLabel: {
332
328
  id: `${scope}.domainLabel`,
333
329
  defaultMessage: 'Domain',
@@ -23,7 +23,7 @@ export function buildFallbackDataFromTemplate(template) {
23
23
  || base['template-name']
24
24
  || '';
25
25
  return {
26
- smsTemplateId: template._id || '',
26
+ smsTemplateId: base.template_id || '',
27
27
  templateName,
28
28
  content,
29
29
  templateContent,
@@ -13,13 +13,13 @@ describe('smsFallbackUtils', () => {
13
13
  describe('buildFallbackDataFromTemplate', () => {
14
14
  it('maps template versions.base and header sender list', () => {
15
15
  const template = {
16
- _id: 'tid',
17
16
  name: 'My SMS',
18
17
  versions: {
19
18
  base: {
20
19
  'sms-editor': 'Hello {{1}}',
21
20
  header: ['S1', 'S2'],
22
21
  'unicode-validity': false,
22
+ template_id: 'tid',
23
23
  },
24
24
  },
25
25
  };
@@ -746,6 +746,7 @@ export class Creatives extends React.Component {
746
746
  creativeName = "",
747
747
  channel = constants.RCS,
748
748
  rcsCardVarMapped,
749
+ accountId = "",
749
750
  } = templateData || {};
750
751
  const { isFullMode: isFullModeForRcsPayload } = this.props;
751
752
  const firstCardIn = (rcsContent.cardContent && rcsContent.cardContent[0]) || {};
@@ -791,6 +792,7 @@ export class Creatives extends React.Component {
791
792
  RCS: {
792
793
  rcsContent: {
793
794
  ...rcsContent,
795
+ ...(accountId && !isFullMode && { accountId }),
794
796
  cardContent: [
795
797
  {
796
798
  ...cardContent,
@@ -1242,7 +1244,7 @@ export class Creatives extends React.Component {
1242
1244
  };
1243
1245
  }
1244
1246
  break;
1245
- case constants.FACEBOOK: {
1247
+ case constants.FACEBOOK:
1246
1248
  if (template.value) {
1247
1249
  const FacebookAd = template?.value?.versions?.base?.content?.FacebookAd;
1248
1250
  const { type } = FacebookAd[0];
@@ -1286,9 +1288,8 @@ export class Creatives extends React.Component {
1286
1288
  selectedMarketingObjective: template.value.selectedMarketingObjective,
1287
1289
  };
1288
1290
  }
1289
- }
1290
1291
  break;
1291
- case constants.RCS: {
1292
+ case constants.RCS:
1292
1293
  if (template.value) {
1293
1294
  const { isFullMode: isFullModeForRcsConsumerPayload } = this.props;
1294
1295
  const { name = "", versions = {} } = template.value || {};
@@ -1336,6 +1337,7 @@ export class Creatives extends React.Component {
1336
1337
  contentType = "",
1337
1338
  cardType = "",
1338
1339
  cardSettings = {},
1340
+ accountId = "",
1339
1341
  } = get(versions, 'base.content.RCS.rcsContent', {});
1340
1342
  const rootRcsCardVarMappedFromSubmit = get(template, 'value.rcsCardVarMapped');
1341
1343
  const firstCardFromSubmit = Array.isArray(cardContentFromSubmit)
@@ -1365,6 +1367,7 @@ export class Creatives extends React.Component {
1365
1367
  channel,
1366
1368
  creativeName: name,
1367
1369
  rcsContent,
1370
+ accountId,
1368
1371
  ...(includeRootRcsCardVarMappedOnConsumerPayload
1369
1372
  ? { rcsCardVarMapped: cardVarMappedFromFirstRcsCard }
1370
1373
  : {}),
@@ -1387,9 +1390,8 @@ export class Creatives extends React.Component {
1387
1390
  }
1388
1391
  normalizeRcsMessageContentForApi(templateData);
1389
1392
  }
1390
- }
1391
1393
  break;
1392
- case constants.ZALO: {
1394
+ case constants.ZALO:
1393
1395
  if (template.value) {
1394
1396
  templateData = {
1395
1397
  ...template.value,
@@ -1398,7 +1400,6 @@ export class Creatives extends React.Component {
1398
1400
  delete templateData.type;
1399
1401
  }
1400
1402
  }
1401
- }
1402
1403
  break;
1403
1404
  case constants.WEBPUSH: {
1404
1405
  if (template.value) {
@@ -206,8 +206,6 @@ export const RCS_CAROUSEL_IMAGE_DIMENSIONS = {
206
206
 
207
207
  export const RCS_VIDEO_THUMBNAIL_DIMENSIONS = {
208
208
  SHORT_HEIGHT: {
209
- width: 770,
210
- height: 257,
211
209
  type: 'SHORT_HEIGHT',
212
210
  heightType: 'SHORT',
213
211
  label: 'Vertical Short',
@@ -34,6 +34,13 @@ import CapCheckbox from '@capillarytech/cap-ui-library/CapCheckbox';
34
34
  import CapAskAira from '@capillarytech/cap-ui-library/CapAskAira';
35
35
  import CapLink from '@capillarytech/cap-ui-library/CapLink';
36
36
  import CapTab from '@capillarytech/cap-ui-library/CapTab';
37
+ import { flushSync } from 'react-dom';
38
+ import { isUrl, isValidText } from '../Line/Container/Wrapper/utils';
39
+ import {
40
+ invalidVarRegex,
41
+ RCS_CTA_URL_TYPE,
42
+ URL_MAX_LENGTH,
43
+ } from '../../v2Components/CapActionButton/constants';
37
44
 
38
45
  import {
39
46
  CAP_G01,
@@ -352,6 +359,7 @@ export const Rcs = (props) => {
352
359
  useEffect(() => {
353
360
  setSuggestions(isHostIcs ? INITIAL_SUGGESTIONS_DATA_STOP : []);
354
361
  }, [isHostIcs]);
362
+ const [rcsAccount, setRcsAccount] = useState('');
355
363
  useEffect(() => {
356
364
  const accountObj = accountData.selectedRcsAccount || {};
357
365
  if (!isEmpty(accountObj)) {
@@ -367,6 +375,7 @@ export const Rcs = (props) => {
367
375
  setAccessToken(configs.accessToken || '');
368
376
  setHostName(accountObj.hostName || '');
369
377
  setAccountName(accountObj.name || '');
378
+ setRcsAccount(accountObj.id || '');
370
379
  } else {
371
380
  setAccountId('');
372
381
  setWecrmAccountId('');
@@ -1700,6 +1709,10 @@ export const Rcs = (props) => {
1700
1709
  get(details, 'versions.base.content.RCS.rcsContent.cardSettings', '')
1701
1710
  || get(details, 'rcsContent.cardSettings', '');
1702
1711
  setMediaData(mediaData, mediaType, cardSettings);
1712
+ if (details?.edit) {
1713
+ const rcsAccountId = get(details, 'versions.base.content.RCS.rcsContent.accountId', '');
1714
+ setRcsAccount(rcsAccountId);
1715
+ }
1703
1716
 
1704
1717
  const smsFallbackContent = mergeRcsSmsFallBackContentFromDetails(details);
1705
1718
  const base = get(smsFallbackContent, 'versions.base', {});
@@ -1963,8 +1976,8 @@ export const Rcs = (props) => {
1963
1976
  const onTagSelectFallback = (data) => {
1964
1977
  const tempMsg = `${fallbackMessage}{{${data}}}`;
1965
1978
  const error = fallbackMessageErrorHandler(tempMsg);
1966
- setFallbackMessage(tempMsg);
1967
- setFallbackMessageError(error);
1979
+ // setFallbackMessage(tempMsg);
1980
+ // setFallbackMessageError(error);
1968
1981
  };
1969
1982
 
1970
1983
 
@@ -2136,8 +2149,8 @@ export const Rcs = (props) => {
2136
2149
 
2137
2150
  const onFallbackMessageChange = ({ target: { value } }) => {
2138
2151
  const error = fallbackMessageErrorHandler(value);
2139
- setFallbackMessage(value);
2140
- setFallbackMessageError(error);
2152
+ // setFallbackMessage(value);
2153
+ // setFallbackMessageError(error);
2141
2154
  };
2142
2155
 
2143
2156
  const fallbackMessageErrorHandler = (value) => {
@@ -2714,8 +2727,8 @@ const onTitleAddVar = () => {
2714
2727
  const rcsDltCardDeleteHandler = () => {
2715
2728
  closeDltContainerHandler();
2716
2729
  setDltEditData({});
2717
- setFallbackMessage('');
2718
- setFallbackMessageError(false);
2730
+ // setFallbackMessage('');
2731
+ // setFallbackMessageError(false);
2719
2732
  setShowDltCard(false);
2720
2733
  };
2721
2734
 
@@ -3295,6 +3308,36 @@ const onTitleAddVar = () => {
3295
3308
  return hasMeaningfulSmsFallbackShape(mapped) ? mapped : null;
3296
3309
  })();
3297
3310
 
3311
+ const carouselCardContent = isCarouselType
3312
+ ? (carouselData || []).map((card = {}) => {
3313
+ const cardMediaType = card.mediaType;
3314
+ const isCardVideo = cardMediaType === RCS_MEDIA_TYPES.VIDEO;
3315
+ const isCardImage = cardMediaType === RCS_MEDIA_TYPES.IMAGE;
3316
+ const mediaUrl = isCardVideo
3317
+ ? (card.videoAsset?.videoSrc || '')
3318
+ : (card.imageSrc || '');
3319
+ const thumbnailUrl = isCardVideo
3320
+ ? (card.thumbnailSrc || card.videoAsset?.videoThumbnail || '')
3321
+ : '';
3322
+ return {
3323
+ title: card.title || '',
3324
+ description: card.description || '',
3325
+ mediaType: cardMediaType,
3326
+ ...((isCardImage || isCardVideo) && {
3327
+ media: {
3328
+ mediaUrl,
3329
+ thumbnailUrl,
3330
+ height: selectedCarouselHeight || MEDIUM,
3331
+ ...(isCardVideo && card.videoAsset?.videoName && { videoName: card.videoAsset.videoName }),
3332
+ },
3333
+ }),
3334
+ ...(Array.isArray(card.suggestions) && card.suggestions.length > 0 && {
3335
+ suggestions: card.suggestions,
3336
+ }),
3337
+ };
3338
+ })
3339
+ : null;
3340
+
3298
3341
  const payload = {
3299
3342
  name: templateName,
3300
3343
  versions: {
@@ -3302,13 +3345,18 @@ const onTitleAddVar = () => {
3302
3345
  content: {
3303
3346
  RCS: {
3304
3347
  rcsContent: {
3305
- cardType: STANDALONE,
3306
- cardSettings: {
3307
- cardOrientation: isMediaTypeImage ? RCS_IMAGE_DIMENSIONS[selectedDimension]?.orientation || VERTICAL : RCS_VIDEO_THUMBNAIL_DIMENSIONS[selectedDimension]?.orientation || VERTICAL,
3308
- ...(alignment && { mediaAlignment: alignment }),
3309
- cardWidth: cardWidthFromSelection,
3310
- },
3311
- cardContent: [
3348
+ ...(rcsAccount && !isFullMode && { accountId: rcsAccount }),
3349
+ cardType: isCarouselType ? contentType.carousel : STANDALONE,
3350
+ cardSettings: isCarouselType
3351
+ ? { cardWidth: selectedCarouselWidth || SMALL }
3352
+ : {
3353
+ cardOrientation: isMediaTypeImage ? RCS_IMAGE_DIMENSIONS[selectedDimension]?.orientation || VERTICAL : RCS_VIDEO_THUMBNAIL_DIMENSIONS[selectedDimension]?.orientation || VERTICAL,
3354
+ ...(alignment && { mediaAlignment: alignment }),
3355
+ cardWidth: cardWidthFromSelection,
3356
+ },
3357
+ cardContent: isCarouselType
3358
+ ? carouselCardContent
3359
+ : [
3312
3360
  {
3313
3361
  // Persist raw template copy + cardVarMapped — not resolveTemplateWithMap output — so library
3314
3362
  // / getFormData round-trip keeps {{…}} and slot values (resolved strings broke reopen hydration).
@@ -3429,8 +3477,29 @@ const onTitleAddVar = () => {
3429
3477
  }),
3430
3478
  }
3431
3479
  : {
3432
- // campaign payload: non-DLT message only; DLT message + templateConfigs
3480
+ // Round-trip storage: full shape so reopening the editor restores template
3481
+ // name, sender IDs, and var mappings. normalizeRcsMessageContentForApi
3482
+ // (called in CreativesContainer getCreativesData) strips this to
3483
+ // { message, templateConfigs } before the API call — the extra fields here
3484
+ // are only used for re-hydration, never sent to the API.
3433
3485
  message: smsBodyText,
3486
+ ...(smsFallbackForPayload.templateName && {
3487
+ smsTemplateName: smsFallbackForPayload.templateName,
3488
+ }),
3489
+ ...(smsFallbackForPayload.templateContent && {
3490
+ templateContent: smsFallbackForPayload.templateContent,
3491
+ }),
3492
+ ...(typeof smsFallbackForPayload.unicodeValidity === 'boolean' && {
3493
+ unicodeValidity: smsFallbackForPayload.unicodeValidity,
3494
+ }),
3495
+ ...(Array.isArray(registeredSenderIdsForPayload) && {
3496
+ registeredSenderIds: registeredSenderIdsForPayload,
3497
+ }),
3498
+ ...(smsFallbackForPayload[RCS_SMS_FALLBACK_VAR_MAPPED_PROP]
3499
+ && Object.keys(smsFallbackForPayload[RCS_SMS_FALLBACK_VAR_MAPPED_PROP]).length > 0 && {
3500
+ [RCS_SMS_FALLBACK_VAR_MAPPED_PROP]:
3501
+ smsFallbackForPayload[RCS_SMS_FALLBACK_VAR_MAPPED_PROP],
3502
+ }),
3434
3503
  ...(isDltCampaign && smsFallbackTemplateConfigs && {
3435
3504
  templateConfigs: smsFallbackTemplateConfigs,
3436
3505
  }),
@@ -3757,18 +3826,18 @@ const onTitleAddVar = () => {
3757
3826
  return true;
3758
3827
  }
3759
3828
 
3760
- if (isMediaTypeText && templateDesc.trim() === '') {
3829
+ if (!isCarouselType && isMediaTypeText && templateDesc.trim() === '') {
3761
3830
  return true;
3762
3831
  }
3763
- if (isMediaTypeImage && rcsImageSrc === '') {
3832
+ if (!isCarouselType && isMediaTypeImage && rcsImageSrc === '') {
3764
3833
  return true;
3765
3834
  }
3766
- if(isMediaTypeVideo && (rcsThumbnailSrc === '' || rcsVideoSrc.videoSrc === '')) {
3835
+ if (!isCarouselType && isMediaTypeVideo && (rcsThumbnailSrc === '' || rcsVideoSrc.videoSrc === '')) {
3767
3836
  return true;
3768
3837
  }
3769
3838
 
3770
3839
  if (buttonType.includes(CTA)) {
3771
- const hasValidButtons = suggestions.every(suggestion =>
3840
+ const hasValidButtons = suggestions.every(suggestion =>
3772
3841
  suggestion.text && suggestion.url && !suggestionError && !forbiddenCharactersValidation(suggestion.text)
3773
3842
  );
3774
3843
  if (!hasValidButtons) {
@@ -47,10 +47,6 @@ export default defineMessages({
47
47
  id: `${prefix}.btnLabel`,
48
48
  defaultMessage: 'Buttons',
49
49
  },
50
- carouselMediaVideoOption:{
51
- id: `${prefix}.carouselMediaVideoOption`,
52
- defaultMessage: 'Video',
53
- },
54
50
  btnTypeNone: {
55
51
  id: `${prefix}.btnTypeNone`,
56
52
  defaultMessage: 'None',
@@ -1,18 +0,0 @@
1
- diff a/app/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js b/app/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js (rejected hunks)
2
- @@ -226,11 +361,16 @@ const RcsPreviewContent = ({
3
- const timestamp = `${displayHours}:${displayMinutes} ${ampm}`;
4
-
5
- // Render normal RCS preview (same structure as SMS up to sms-message-container)
6
- + const hasCarousel = Array.isArray(content?.carouselData) && content.carouselData.length > 0;
7
- const hasMedia = !!(content?.rcsImageSrc || content?.rcsVideoSrc);
8
- + const contentToRender = hasCarousel
9
- + ? renderCarouselPreviewContent()
10
- + : (hasMedia ? renderMediaPreviewContent() : renderTextPreviewContent());
11
-
12
- return (
13
- + <CapRow
14
- + className={`sms-device-container rcs-device-container ${hasCarousel ? 'rcs-device-container-carousel' : ''}`}
15
- + >
16
- {/* Device Background Image */}
17
- <CapImage
18
- className="sms-device-image"