@capillarytech/creatives-library 8.0.345-alpha.12 → 8.0.345-alpha.14

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 (129) hide show
  1. package/constants/unified.js +0 -29
  2. package/package.json +1 -1
  3. package/services/tests/api.test.js +0 -13
  4. package/utils/commonUtils.js +1 -19
  5. package/v2Components/CapActionButton/constants.js +0 -7
  6. package/v2Components/CapActionButton/index.js +109 -167
  7. package/v2Components/CapActionButton/index.scss +6 -157
  8. package/v2Components/CapActionButton/messages.js +3 -19
  9. package/v2Components/CapActionButton/tests/index.test.js +17 -41
  10. package/v2Components/CapTagList/index.js +0 -10
  11. package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +49 -70
  12. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +2 -8
  13. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +21 -207
  14. package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +0 -16
  15. package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +10 -85
  16. package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +0 -30
  17. package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +11 -79
  18. package/v2Components/CommonTestAndPreview/SendTestMessage.js +5 -10
  19. package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +15 -160
  20. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +76 -341
  21. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +4 -133
  22. package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +0 -11
  23. package/v2Components/CommonTestAndPreview/constants.js +2 -38
  24. package/v2Components/CommonTestAndPreview/index.js +186 -676
  25. package/v2Components/CommonTestAndPreview/messages.js +3 -49
  26. package/v2Components/CommonTestAndPreview/sagas.js +6 -15
  27. package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +284 -308
  28. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +65 -231
  29. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +5 -118
  30. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +0 -341
  31. package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +1 -8
  32. package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +13 -34
  33. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +283 -281
  34. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +1 -199
  35. package/v2Components/CommonTestAndPreview/tests/index.test.js +4 -132
  36. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +2 -2
  37. package/v2Components/FormBuilder/index.js +10 -8
  38. package/v2Components/TemplatePreview/_templatePreview.scss +23 -33
  39. package/v2Components/TemplatePreview/index.js +28 -143
  40. package/v2Components/TemplatePreview/tests/index.test.js +0 -142
  41. package/v2Components/TestAndPreviewSlidebox/index.js +1 -13
  42. package/v2Components/TestAndPreviewSlidebox/sagas.js +4 -11
  43. package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +1 -3
  44. package/v2Containers/CreativesContainer/SlideBoxContent.js +4 -36
  45. package/v2Containers/CreativesContainer/SlideBoxFooter.js +1 -10
  46. package/v2Containers/CreativesContainer/SlideBoxHeader.js +4 -29
  47. package/v2Containers/CreativesContainer/constants.js +0 -9
  48. package/v2Containers/CreativesContainer/index.js +103 -300
  49. package/v2Containers/CreativesContainer/index.scss +1 -51
  50. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +34 -78
  51. package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +16 -79
  52. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -8
  53. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +98 -357
  54. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +15 -20
  55. package/v2Containers/CreativesContainer/tests/index.test.js +9 -71
  56. package/v2Containers/Email/reducer.js +11 -3
  57. package/v2Containers/Email/sagas.js +9 -5
  58. package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +4 -0
  59. package/v2Containers/Email/tests/sagas.test.js +21 -3
  60. package/v2Containers/Rcs/constants.js +8 -119
  61. package/v2Containers/Rcs/index.js +812 -2375
  62. package/v2Containers/Rcs/index.scss +6 -276
  63. package/v2Containers/Rcs/messages.js +3 -38
  64. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +70345 -98302
  65. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +5 -0
  66. package/v2Containers/Rcs/tests/index.test.js +121 -152
  67. package/v2Containers/Rcs/tests/mockData.js +0 -38
  68. package/v2Containers/Rcs/tests/utils.test.js +30 -646
  69. package/v2Containers/Rcs/utils.js +11 -478
  70. package/v2Containers/Sms/Create/index.js +40 -100
  71. package/v2Containers/SmsTrai/Create/index.js +4 -9
  72. package/v2Containers/SmsTrai/Edit/constants.js +0 -2
  73. package/v2Containers/SmsTrai/Edit/index.js +130 -636
  74. package/v2Containers/SmsTrai/Edit/messages.js +4 -14
  75. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +2296 -4249
  76. package/v2Containers/SmsWrapper/index.js +8 -37
  77. package/v2Containers/TagList/index.js +0 -6
  78. package/v2Containers/Templates/_templates.scss +2 -163
  79. package/v2Containers/Templates/actions.js +0 -11
  80. package/v2Containers/Templates/constants.js +0 -2
  81. package/v2Containers/Templates/index.js +54 -119
  82. package/v2Containers/Templates/sagas.js +12 -57
  83. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1079 -1043
  84. package/v2Containers/Templates/tests/sagas.test.js +123 -193
  85. package/v2Containers/TemplatesV2/TemplatesV2.style.js +1 -72
  86. package/v2Containers/TemplatesV2/index.js +23 -86
  87. package/v2Containers/Whatsapp/index.js +20 -3
  88. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -578
  89. package/utils/rcsPayloadUtils.js +0 -92
  90. package/utils/templateVarUtils.js +0 -201
  91. package/utils/tests/templateVarUtils.test.js +0 -204
  92. package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js.rej +0 -18
  93. package/v2Components/CommonTestAndPreview/previewApiUtils.js +0 -59
  94. package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +0 -67
  95. package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +0 -87
  96. package/v2Components/SmsFallback/constants.js +0 -73
  97. package/v2Components/SmsFallback/index.js +0 -955
  98. package/v2Components/SmsFallback/index.scss +0 -265
  99. package/v2Components/SmsFallback/messages.js +0 -78
  100. package/v2Components/SmsFallback/smsFallbackUtils.js +0 -118
  101. package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +0 -50
  102. package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +0 -147
  103. package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +0 -304
  104. package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +0 -197
  105. package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +0 -277
  106. package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +0 -422
  107. package/v2Components/SmsFallback/useLocalTemplateList.js +0 -92
  108. package/v2Components/TemplatePreview/constants.js +0 -2
  109. package/v2Components/VarSegmentMessageEditor/constants.js +0 -2
  110. package/v2Components/VarSegmentMessageEditor/index.js +0 -125
  111. package/v2Components/VarSegmentMessageEditor/index.scss +0 -46
  112. package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +0 -43
  113. package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +0 -67
  114. package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +0 -90
  115. package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +0 -258
  116. package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +0 -125
  117. package/v2Containers/Rcs/index.js.rej +0 -1336
  118. package/v2Containers/Rcs/index.scss.rej +0 -74
  119. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +0 -225
  120. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap.rej +0 -128
  121. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -318
  122. package/v2Containers/Sms/smsFormDataHelpers.js +0 -67
  123. package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +0 -253
  124. package/v2Containers/SmsTrai/Edit/index.scss +0 -121
  125. package/v2Containers/Templates/TemplatesActionBar.js +0 -101
  126. package/v2Containers/Templates/tests/TemplatesActionBar.test.js +0 -120
  127. package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +0 -180
  128. package/v2Containers/Templates/utils/smsTemplatesListApi.js +0 -79
  129. package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +0 -131
@@ -9,91 +9,29 @@
9
9
 
10
10
  import get from 'lodash/get';
11
11
  import { CHANNELS } from '../../constants';
12
- import { RCS_CONTACT_INFO_GSM_TYPE_KEYS } from '../constants';
13
12
 
14
- /** Match API contactInfo.type (some envs use different casing). */
15
- const typeMatches = (itemType, expectedKey) => {
16
- if (!itemType || !expectedKey) return false;
17
- const a = String(itemType).toLowerCase().replace(/-/g, '_');
18
- const b = String(expectedKey).toLowerCase().replace(/-/g, '_');
19
- return a === b;
20
- };
21
-
22
- /**
23
- * Include row unless explicitly invalid — many APIs omit `valid`, which would
24
- * otherwise filter out every sender (RCS/SMS lists empty in UI).
25
- */
26
13
  const getSenderOptions = (contactInfo, key) =>
27
14
  (contactInfo || [])
28
- .filter((contactInfoItem) => typeMatches(contactInfoItem.type, key) && contactInfoItem.valid !== false)
15
+ .filter((contactInfoItem) => contactInfoItem.type === key && contactInfoItem.valid)
29
16
  .sort((contact) => (contact.default ? -1 : 0));
30
17
 
31
- /** RCS APIs may label senders under several `contactInfo.type` keys — see `RCS_CONTACT_INFO_GSM_TYPE_KEYS`. */
32
- const getRcsLikeGsmSenders = (contactInfo) => {
33
- const seen = new Set();
34
- const merged = [];
35
- RCS_CONTACT_INFO_GSM_TYPE_KEYS.forEach((key) => {
36
- getSenderOptions(contactInfo, key).forEach((row) => {
37
- const v = row?.value;
38
- // Skip empty/whitespace — they still pass `v != null` for "" and pollute RCS sender dropdowns.
39
- if (v == null || String(v).trim() === '' || seen.has(v)) return;
40
- seen.add(v);
41
- merged.push(row);
42
- });
43
- });
44
- return merged.sort((a, b) => (a.default ? -1 : 0) - (b.default ? -1 : 0));
45
- };
46
-
47
- /**
48
- * Campaigns domainProperties may return { entity } or { result: { entity } } / { data: { entity } }.
49
- */
50
- function unwrapEntity(response) {
51
- if (!response || typeof response !== 'object') return null;
52
- if (response.entity != null) return response.entity;
53
- const nested = get(response, 'result.entity') ?? get(response, 'data.entity');
54
- if (nested != null) return nested;
55
- if (response.entity === null) return null;
56
- return response;
57
- }
58
-
59
18
  /**
60
19
  * Parse raw API response for one channel into { domains: [...] }
61
- * @param {string} channel - SMS | EMAIL | WHATSAPP | RCS
20
+ * @param {string} channel - SMS | EMAIL | WHATSAPP
62
21
  * @param {Object} response - API response (e.g. { entity: { SMS: [...] } } or { entity: [...] })
63
22
  * @returns {{ domains: Array }} - domains array compatible with campaigns DeliverySettingsV2
64
23
  */
65
24
  export function parseSenderDetailsResponse(channel, response) {
66
- const entity = unwrapEntity(response);
67
- if (entity == null || entity === '') {
25
+ const entity = get(response, 'entity', response);
26
+ if (!entity) {
68
27
  return { domains: [] };
69
28
  }
70
29
 
71
- // Normalize once: entity keys may be any casing (SMS/sms/rcs) but downstream branches use CHANNELS.* (uppercase).
72
- const normalizedChannel =
73
- channel == null || String(channel).trim() === ''
74
- ? ''
75
- : String(channel).trim().toUpperCase();
76
-
77
- // Single-channel API: entity may be { [channel]: [...] } or direct array.
78
- // Some responses use different casing (e.g. rcs vs RCS) or a single domain object instead of an array.
79
- let channelSenderDetails =
80
- get(entity, channel, null)
81
- ?? (normalizedChannel ? get(entity, normalizedChannel, null) : null)
82
- ?? (normalizedChannel ? get(entity, normalizedChannel.toLowerCase(), null) : null);
83
-
30
+ // Single-channel API: entity may be { [channel]: [...] } or direct array
31
+ let channelSenderDetails = get(entity, channel, null);
84
32
  if (channelSenderDetails == null && Array.isArray(entity)) {
85
33
  channelSenderDetails = entity;
86
34
  }
87
-
88
- if (channelSenderDetails != null && !Array.isArray(channelSenderDetails)) {
89
- const single = channelSenderDetails;
90
- if (single && typeof single === 'object' && single.domainProperties) {
91
- channelSenderDetails = [single];
92
- } else {
93
- return { domains: [] };
94
- }
95
- }
96
-
97
35
  if (!Array.isArray(channelSenderDetails)) {
98
36
  return { domains: [] };
99
37
  }
@@ -104,7 +42,6 @@ export function parseSenderDetailsResponse(channel, response) {
104
42
  const { id: dgmId, priority, domainProperties = {} } = element;
105
43
  const {
106
44
  domainName,
107
- hostName,
108
45
  id = -1,
109
46
  contactInfo,
110
47
  connectionProperties: {
@@ -114,25 +51,21 @@ export function parseSenderDetailsResponse(channel, response) {
114
51
  } = {},
115
52
  } = domainProperties;
116
53
 
117
- const resolvedDomainName = domainName || hostName;
118
-
119
54
  const domain = {
120
55
  dgmId,
121
- domainName: resolvedDomainName,
56
+ domainName,
122
57
  domainId: id,
123
58
  priority: priority != null ? priority : 0,
124
59
  };
125
60
 
126
- if ([CHANNELS.SMS, CHANNELS.WHATSAPP, CHANNELS.RCS].includes(normalizedChannel)) {
61
+ if ([CHANNELS.SMS, CHANNELS.WHATSAPP].includes(channel)) {
127
62
  domain.cdmaSenders = getSenderOptions(contactInfo, 'cdma_sender_id');
128
- domain.gsmSenders = normalizedChannel === CHANNELS.RCS
129
- ? getRcsLikeGsmSenders(contactInfo)
130
- : getSenderOptions(contactInfo, 'gsm_sender_id');
63
+ domain.gsmSenders = getSenderOptions(contactInfo, 'gsm_sender_id');
131
64
  domain.sourceAccountIdentifier =
132
65
  sourceAccountIdentifier || wabaId || userid || '';
133
66
  }
134
67
 
135
- if (normalizedChannel === CHANNELS.EMAIL) {
68
+ if (channel === CHANNELS.EMAIL) {
136
69
  domain.emailSenders = getSenderOptions(contactInfo, 'sender_id');
137
70
  domain.emailRepliers = getSenderOptions(contactInfo, 'reply_to_id');
138
71
  }
@@ -143,8 +76,7 @@ export function parseSenderDetailsResponse(channel, response) {
143
76
  // Sort by priority and dedupe by domainName (match campaigns behaviour)
144
77
  domains.sort((a, b) => (a.priority || 0) - (b.priority || 0));
145
78
  const deduped = domains.reduce((acc, domain) => {
146
- const key = domain.domainName ?? domain.domainId;
147
- if (!acc.find((existing) => (existing.domainName ?? existing.domainId) === key)) {
79
+ if (!acc.find((d) => d.domainName === domain.domainName)) {
148
80
  acc.push(domain);
149
81
  }
150
82
  return acc;
@@ -6,13 +6,12 @@ import CapButton from '@capillarytech/cap-ui-library/CapButton';
6
6
  import CapHeader from '@capillarytech/cap-ui-library/CapHeader';
7
7
  import CapStepsAccordian from '@capillarytech/cap-ui-library/CapStepsAccordian';
8
8
  import CapTreeSelect from '@capillarytech/cap-ui-library/CapTreeSelect';
9
- import CapSelect from '@capillarytech/cap-ui-library/CapSelect';
10
9
  import isEmpty from 'lodash/isEmpty';
11
10
  import messages from './messages';
12
11
  import DeliverySettings from './DeliverySettings';
13
12
  import { CHANNELS } from './constants';
14
13
 
15
- const CHANNELS_WITH_DELIVERY_SETTINGS = [CHANNELS.SMS, CHANNELS.EMAIL, CHANNELS.WHATSAPP, CHANNELS.RCS];
14
+ const CHANNELS_WITH_DELIVERY_SETTINGS = [CHANNELS.SMS, CHANNELS.EMAIL, CHANNELS.WHATSAPP];
16
15
 
17
16
  const SendTestMessage = ({
18
17
  isFetchingTestCustomers,
@@ -29,13 +28,12 @@ const SendTestMessage = ({
29
28
  searchValue,
30
29
  setSearchValue,
31
30
  deliverySettings,
32
- senderDetailsByChannel = {},
31
+ senderDetailsOptions,
33
32
  wecrmAccounts,
34
33
  onSaveDeliverySettings,
35
34
  isLoadingSenderDetails,
36
35
  smsTraiDltEnabled,
37
36
  registeredSenderIds,
38
- isChannelSmsFallbackPreviewEnabled,
39
37
  }) => {
40
38
  const addCustomerContent = renderAddTestCustomerButton ? renderAddTestCustomerButton() : null;
41
39
  return (
@@ -79,14 +77,13 @@ const SendTestMessage = ({
79
77
  <DeliverySettings
80
78
  channel={channel}
81
79
  deliverySettings={deliverySettings || {}}
82
- senderDetailsByChannel={senderDetailsByChannel}
80
+ senderDetailsOptions={senderDetailsOptions}
83
81
  wecrmAccounts={wecrmAccounts || []}
84
82
  onSaveDeliverySettings={onSaveDeliverySettings}
85
83
  isLoadingSenderDetails={isLoadingSenderDetails}
86
84
  formatMessage={formatMessage}
87
85
  smsTraiDltEnabled={smsTraiDltEnabled}
88
86
  registeredSenderIds={registeredSenderIds}
89
- isChannelSmsFallbackPreviewEnabled={isChannelSmsFallbackPreviewEnabled}
90
87
  whatsappAccountFromForm={
91
88
  channel === CHANNELS.WHATSAPP && formData?.accountName
92
89
  ? { accountName: formData.accountName }
@@ -124,13 +121,12 @@ SendTestMessage.propTypes = {
124
121
  searchValue: PropTypes.string,
125
122
  setSearchValue: PropTypes.func,
126
123
  deliverySettings: PropTypes.object,
127
- senderDetailsByChannel: PropTypes.object,
124
+ senderDetailsOptions: PropTypes.array,
128
125
  wecrmAccounts: PropTypes.array,
129
126
  onSaveDeliverySettings: PropTypes.func,
130
127
  isLoadingSenderDetails: PropTypes.bool,
131
128
  smsTraiDltEnabled: PropTypes.bool,
132
129
  registeredSenderIds: PropTypes.array,
133
- isChannelSmsFallbackPreviewEnabled: PropTypes.bool,
134
130
  };
135
131
 
136
132
  SendTestMessage.defaultProps = {
@@ -140,13 +136,12 @@ SendTestMessage.defaultProps = {
140
136
  searchValue: '',
141
137
  setSearchValue: () => {}, // no-op when not provided; required by TreeSelect when showSearch is true
142
138
  deliverySettings: {},
143
- senderDetailsByChannel: {},
139
+ senderDetailsOptions: [],
144
140
  wecrmAccounts: [],
145
141
  onSaveDeliverySettings: undefined,
146
142
  isLoadingSenderDetails: false,
147
143
  smsTraiDltEnabled: false,
148
144
  registeredSenderIds: [],
149
- isChannelSmsFallbackPreviewEnabled: false,
150
145
  };
151
146
 
152
147
  export default SendTestMessage;
@@ -25,7 +25,6 @@ import {
25
25
  TIME_FORMAT_MINUTE_PADDING_THRESHOLD,
26
26
  TIME_FORMAT_AM,
27
27
  TIME_FORMAT_PM,
28
- MEDIA_TYPE_VIDEO,
29
28
  } from '../constants';
30
29
  import messages from '../messages';
31
30
  import { RCS_BUTTON_TYPES } from '../../../v2Containers/Rcs/constants';
@@ -51,57 +50,41 @@ const RcsPreviewContent = ({
51
50
  const deviceName = device === ANDROID ? ANDROID_DEVICE_NAME : IOS_DEVICE_NAME;
52
51
 
53
52
  // Render RCS suggestions (Quick Reply, CTA, Phone Number)
54
- // options.isCarousel: stacked bars below card body with gap (Figma), no dividers between CTAs
55
- const renderRcsSuggestionsPreview = (suggestionsArg, options = {}) => {
56
- const { isCarousel = false } = options;
53
+ const renderRcsSuggestionsPreview = () => {
57
54
  const renderArray = [];
58
- const suggestions = Array.isArray(suggestionsArg)
59
- ? suggestionsArg
60
- : (content?.suggestions || []);
55
+ const { suggestions = [] } = content || {};
61
56
 
62
57
  if (suggestions.length === 0) {
63
58
  return null;
64
59
  }
65
60
 
66
- const ctaClass = isCarousel ? 'rcs-cta-preview rcs-cta-preview--carousel-bar' : 'rcs-cta-preview';
67
-
68
61
  suggestions.forEach((suggestion) => {
69
62
  const { type, text } = suggestion || {};
70
63
  const suggestionKey = `${type}-${text || Math.random()}`;
71
64
 
72
- if (renderArray.length > 0 && !isCarousel) {
65
+ if (renderArray.length > 0) {
73
66
  renderArray.push(<CapDivider key={`divider-${suggestionKey}`} className="whatsapp-divider" />);
74
67
  }
75
68
 
76
69
  if (type === RCS_BUTTON_TYPES.QUICK_REPLY) {
77
70
  renderArray.push(
78
- <CapLabel key={suggestionKey} type="label21" className={ctaClass}>
71
+ <CapLabel key={suggestionKey} type="label21" className="rcs-cta-preview">
79
72
  <CapIcon type="small-link" size="xs" />
80
73
  {text}
81
74
  </CapLabel>
82
75
  );
83
76
  } else if (type === RCS_BUTTON_TYPES.CTA) {
84
77
  renderArray.push(
85
- <CapLabel key={suggestionKey} type="label21" className={ctaClass}>
78
+ <CapLabel key={suggestionKey} type="label21" className="rcs-cta-preview">
86
79
  <CapIcon type="launch" size="xs" />
87
80
  {text}
88
81
  </CapLabel>
89
82
  );
90
83
  } else if (type === RCS_BUTTON_TYPES.PHONE_NUMBER) {
91
- // Carousel: label text then phone icon (matches device-style RCS preview)
92
84
  renderArray.push(
93
- <CapLabel key={suggestionKey} type="label21" className={ctaClass}>
94
- {isCarousel ? (
95
- <>
96
- {text}
97
- <CapIcon type="call" size="xs" className="rcs-cta-preview-phone-icon-end" />
98
- </>
99
- ) : (
100
- <>
101
- <CapIcon type="call" size="xs" />
102
- {text}
103
- </>
104
- )}
85
+ <CapLabel key={suggestionKey} type="label21" className="rcs-cta-preview">
86
+ <CapIcon type="call" size="xs" />
87
+ {text}
105
88
  </CapLabel>
106
89
  );
107
90
  }
@@ -110,104 +93,6 @@ const RcsPreviewContent = ({
110
93
  return renderArray?.length > 0 ? renderArray : null;
111
94
  };
112
95
 
113
- // Carousel media box: aspect matches RCS editor card size (SHORT/MEDIUM × SMALL/MEDIUM).
114
- const getCarouselMediaAspectStyle = (isVideo) => {
115
- const d = content?.carouselPreviewDimensions;
116
- if (!d) return undefined;
117
- if (isVideo) {
118
- const { videoThumbWidth, videoThumbHeight } = d;
119
- if (!videoThumbWidth || !videoThumbHeight) return undefined;
120
- return { aspectRatio: `${videoThumbWidth} / ${videoThumbHeight}` };
121
- }
122
- const { imageWidth, imageHeight } = d;
123
- if (!imageWidth || !imageHeight) return undefined;
124
- return { aspectRatio: `${imageWidth} / ${imageHeight}` };
125
- };
126
-
127
- // Carousel preview (WhatsApp-style static horizontal scroll).
128
- // Caller passes a non-empty array only (see hasCarousel); avoids duplicate guards that Sonar
129
- // flagged as partially covered because inner checks were unreachable when hasCarousel was true.
130
- const renderCarouselPreviewContent = (carouselCards) => (
131
- <CapRow className="msg-container-carousel">
132
- <CapRow className="scroll-container">
133
- {carouselCards.map((card, idx) => {
134
- const key = `rcs-carousel-${idx}-${card?.bodyText || card?.imageSrc || card?.videoPreviewImg || ''}`;
135
- const isVideo =
136
- (card?.mediaType || '').toLowerCase() === String(MEDIA_TYPE_VIDEO).toLowerCase();
137
- const cardSuggestions = Array.isArray(card?.suggestions) ? card.suggestions : [];
138
- const suggestionsNode = cardSuggestions.length > 0
139
- ? renderRcsSuggestionsPreview(cardSuggestions, { isCarousel: true })
140
- : null;
141
- const titleTrimmed = String(card?.title ?? '').trim();
142
- const bodyTrimmed = String(card?.bodyText ?? '').trim();
143
- const titleShown = titleTrimmed || formatMessage(messages.rcsCarouselPreviewTitlePlaceholder);
144
- const bodyShown = bodyTrimmed || formatMessage(messages.rcsCarouselPreviewBodyPlaceholder);
145
- return (
146
- <CapRow
147
- key={key}
148
- className="message-pop align-left message-pop-carousel"
149
- >
150
- <CapRow className="whatsapp-content">
151
- {!isVideo && (
152
- <CapRow
153
- className="whatsapp-image rcs-carousel-media-wrap"
154
- style={getCarouselMediaAspectStyle(false)}
155
- >
156
- <CapImage
157
- src={card?.imageSrc ? card.imageSrc : rcsImageEmptyPreview}
158
- className="rcs-carousel-img"
159
- alt={formatMessage(messages.previewGenerated)}
160
- />
161
- </CapRow>
162
- )}
163
- {isVideo && (
164
- <CapTooltip title={formatMessage(messages.videoPreviewTooltip)}>
165
- <CapRow className="video-preview">
166
- <CapRow
167
- className="whatsapp-image rcs-carousel-media-wrap"
168
- style={getCarouselMediaAspectStyle(true)}
169
- >
170
- <CapImage
171
- src={card?.videoPreviewImg ? card.videoPreviewImg : rcsVideoEmptyPreview}
172
- className="rcs-carousel-img"
173
- alt={formatMessage(messages.previewGenerated)}
174
- />
175
- </CapRow>
176
- <CapRow className="icon-position">
177
- <CapImage className="video-icon" src={videoPlay} alt="Play" />
178
- </CapRow>
179
- </CapRow>
180
- </CapTooltip>
181
- )}
182
-
183
- <CapRow className="carousel-content">
184
- <CapLabel
185
- type={card.titleLabelType || 'label1'}
186
- className={`carousel-title${titleTrimmed ? '' : ' rcs-carousel-field-placeholder'}`}
187
- >
188
- {titleShown}
189
- </CapLabel>
190
- <CapLabel
191
- type={card.bodyLabelType || 'label2'}
192
- className={`carousel-message${bodyTrimmed ? '' : ' rcs-carousel-field-placeholder'}`}
193
- >
194
- {bodyShown}
195
- </CapLabel>
196
- </CapRow>
197
-
198
- {!!suggestionsNode && (
199
- <CapRow className="rcs-carousel-cta-stack" gutter={0}>
200
- {suggestionsNode}
201
- </CapRow>
202
- )}
203
- </CapRow>
204
- </CapRow>
205
- );
206
- })}
207
- </CapRow>
208
- </CapRow>
209
- );
210
-
211
96
  // Render text preview content
212
97
  const renderTextPreviewContent = () => {
213
98
  const {
@@ -242,9 +127,6 @@ const RcsPreviewContent = ({
242
127
  {description}
243
128
  </CapLabel>
244
129
  )}
245
- {Array.isArray(content?.suggestions) && content.suggestions.length > 0 && (
246
- <CapDivider className="whatsapp-divider" />
247
- )}
248
130
  {renderRcsSuggestionsPreview()}
249
131
  </>
250
132
  );
@@ -344,22 +226,11 @@ const RcsPreviewContent = ({
344
226
  const timestamp = `${displayHours}:${displayMinutes} ${ampm}`;
345
227
 
346
228
  // Render normal RCS preview (same structure as SMS up to sms-message-container)
347
- const carouselCardsNormalized = Array.isArray(content?.carouselData) ? content?.carouselData : [];
348
- const hasCarousel = carouselCardsNormalized?.length > 0;
349
229
  const hasMedia = !!(content?.rcsImageSrc || content?.rcsVideoSrc);
350
- let contentToRender;
351
- if (hasCarousel) {
352
- contentToRender = renderCarouselPreviewContent(carouselCardsNormalized);
353
- } else if (hasMedia) {
354
- contentToRender = renderMediaPreviewContent();
355
- } else {
356
- contentToRender = renderTextPreviewContent();
357
- }
230
+ const contentToRender = hasMedia ? renderMediaPreviewContent() : renderTextPreviewContent();
358
231
 
359
232
  return (
360
- <CapRow
361
- className={`sms-device-container rcs-device-container ${hasCarousel ? 'rcs-device-container-carousel' : ''}`}
362
- >
233
+ <CapRow className="sms-device-container">
363
234
  {/* Device Background Image */}
364
235
  <CapImage
365
236
  className="sms-device-image"
@@ -368,9 +239,7 @@ const RcsPreviewContent = ({
368
239
  />
369
240
 
370
241
  {/* Content Overlay */}
371
- <CapRow
372
- className={`sms-content-overlay sms-content-overlay-${device} sms-preview sms-${device} rcs-content-overlay`}
373
- >
242
+ <CapRow className={`sms-content-overlay sms-content-overlay-${device} sms-preview sms-${device}`}>
374
243
  {/* Navigation Bar - Same as SMS */}
375
244
  <CapRow className={`sms-navigation-bar ${!showHeader ? 'sms-navigation-bar-no-header' : ''}`}>
376
245
  <CapIcon type="chevron-left" className="sms-back-arrow" />
@@ -386,8 +255,8 @@ const RcsPreviewContent = ({
386
255
  </CapRow>
387
256
 
388
257
  {/* Message Container - Same structure as SMS, only content inside is RCS-specific */}
389
- <CapRow className={`sms-message-container ${hasCarousel ? 'rcs-message-container-carousel' : ''}`}>
390
- <CapRow className={`sms-message-bubble ${hasCarousel ? 'rcs-message-bubble-carousel' : ''}`}>
258
+ <CapRow className="sms-message-container">
259
+ <CapRow className="sms-message-bubble">
391
260
  <CapRow className="sms-message-text">
392
261
  {/* RCS-specific content rendering */}
393
262
  <CapRow className="message-pop sms">
@@ -401,10 +270,8 @@ const RcsPreviewContent = ({
401
270
  </CapRow>
402
271
  </CapRow>
403
272
  </CapRow>
404
- )
405
- }
406
-
407
-
273
+ );
274
+ };
408
275
 
409
276
  RcsPreviewContent.propTypes = {
410
277
  content: PropTypes.shape({
@@ -415,18 +282,6 @@ RcsPreviewContent.propTypes = {
415
282
  rcsImageSrc: PropTypes.string,
416
283
  rcsVideoSrc: PropTypes.string,
417
284
  rcsThumbnailSrc: PropTypes.string,
418
- carouselData: PropTypes.arrayOf(
419
- PropTypes.shape({
420
- titleLabelType: PropTypes.string,
421
- bodyLabelType: PropTypes.string,
422
- })
423
- ),
424
- carouselPreviewDimensions: PropTypes.shape({
425
- imageWidth: PropTypes.number,
426
- imageHeight: PropTypes.number,
427
- videoThumbWidth: PropTypes.number,
428
- videoThumbHeight: PropTypes.number,
429
- }),
430
285
  suggestions: PropTypes.arrayOf(
431
286
  PropTypes.shape({
432
287
  type: PropTypes.string,