@capillarytech/creatives-library 9.0.15-alpha.1 → 9.0.16
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/constants/unified.js +0 -29
- package/global-styles.js +1 -1
- package/package.json +1 -1
- package/services/tests/api.test.js +20 -35
- package/utils/commonUtils.js +1 -19
- package/v2Components/CapActionButton/constants.js +0 -7
- package/v2Components/CapActionButton/index.js +109 -168
- package/v2Components/CapActionButton/index.scss +5 -156
- package/v2Components/CapActionButton/messages.js +3 -19
- package/v2Components/CapActionButton/tests/index.test.js +18 -42
- package/v2Components/CapImageUpload/index.js +2 -2
- package/v2Components/CapTagList/index.js +0 -10
- package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +48 -70
- package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +2 -8
- package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +21 -214
- package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +0 -16
- package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +9 -83
- package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +0 -30
- package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +11 -60
- package/v2Components/CommonTestAndPreview/SendTestMessage.js +5 -10
- package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +23 -201
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +76 -355
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +8 -155
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +0 -11
- package/v2Components/CommonTestAndPreview/constants.js +2 -38
- package/v2Components/CommonTestAndPreview/index.js +222 -761
- package/v2Components/CommonTestAndPreview/messages.js +3 -45
- package/v2Components/CommonTestAndPreview/sagas.js +6 -25
- package/v2Components/CommonTestAndPreview/tests/CommonTestAndPreview.addTestCustomer.test.js +0 -1
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +267 -284
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +65 -231
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +5 -118
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +0 -341
- package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +1 -8
- package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +13 -34
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +283 -281
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +1 -199
- package/v2Components/CommonTestAndPreview/tests/index.test.js +4 -133
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +24 -31
- package/v2Components/TemplatePreview/_templatePreview.scss +22 -41
- package/v2Components/TemplatePreview/index.js +31 -143
- package/v2Components/TemplatePreview/tests/index.test.js +0 -142
- package/v2Components/TestAndPreviewSlidebox/CustomValuesEditor.js +6 -6
- package/v2Components/TestAndPreviewSlidebox/index.js +1 -13
- package/v2Components/TestAndPreviewSlidebox/sagas.js +4 -11
- package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +1 -3
- package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +1 -4
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +0 -4
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +20 -20
- package/v2Containers/CreativesContainer/SlideBoxContent.js +7 -36
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +5 -14
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +5 -36
- package/v2Containers/CreativesContainer/constants.js +0 -11
- package/v2Containers/CreativesContainer/index.js +104 -323
- package/v2Containers/CreativesContainer/index.scss +1 -83
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +34 -79
- package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +16 -79
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -8
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +90 -333
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +15 -20
- package/v2Containers/CreativesContainer/tests/index.test.js +9 -71
- package/v2Containers/Email/index.js +5 -2
- package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
- package/v2Containers/Rcs/constants.js +11 -131
- package/v2Containers/Rcs/index.js +810 -2605
- package/v2Containers/Rcs/index.scss +8 -289
- package/v2Containers/Rcs/messages.js +3 -34
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +38537 -73535
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +8 -0
- package/v2Containers/Rcs/tests/index.test.js +36 -147
- package/v2Containers/Rcs/tests/mockData.js +0 -38
- package/v2Containers/Rcs/tests/utils.test.js +30 -646
- package/v2Containers/Rcs/utils.js +11 -478
- package/v2Containers/Sms/Create/index.js +48 -115
- package/v2Containers/SmsTrai/Create/index.js +4 -9
- package/v2Containers/SmsTrai/Edit/constants.js +0 -2
- package/v2Containers/SmsTrai/Edit/index.js +169 -678
- package/v2Containers/SmsTrai/Edit/messages.js +4 -14
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +2854 -5455
- package/v2Containers/SmsWrapper/index.js +8 -37
- package/v2Containers/TagList/index.js +0 -6
- package/v2Containers/Templates/_templates.scss +12 -171
- package/v2Containers/Templates/actions.js +0 -11
- package/v2Containers/Templates/constants.js +0 -2
- package/v2Containers/Templates/index.js +55 -125
- package/v2Containers/Templates/sagas.js +13 -57
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1015 -1060
- package/v2Containers/Templates/tests/sagas.test.js +16 -199
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +1 -72
- package/v2Containers/TemplatesV2/index.js +23 -86
- package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
- package/v2Containers/Whatsapp/index.js +20 -3
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -578
- package/utils/rcsPayloadUtils.js +0 -92
- package/utils/templateVarUtils.js +0 -201
- package/utils/tests/rcsPayloadUtils.test.js +0 -226
- package/utils/tests/templateVarUtils.test.js +0 -204
- package/v2Components/CommonTestAndPreview/previewApiUtils.js +0 -59
- package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +0 -67
- package/v2Components/CommonTestAndPreview/utils.js +0 -84
- package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +0 -91
- package/v2Components/SmsFallback/constants.js +0 -94
- package/v2Components/SmsFallback/index.js +0 -958
- package/v2Components/SmsFallback/index.scss +0 -266
- package/v2Components/SmsFallback/messages.js +0 -78
- package/v2Components/SmsFallback/smsFallbackUtils.js +0 -120
- package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +0 -50
- package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +0 -147
- package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +0 -304
- package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +0 -208
- package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +0 -309
- package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +0 -422
- package/v2Components/SmsFallback/useLocalTemplateList.js +0 -92
- package/v2Components/TemplatePreview/constants.js +0 -2
- package/v2Components/VarSegmentMessageEditor/constants.js +0 -2
- package/v2Components/VarSegmentMessageEditor/index.js +0 -125
- package/v2Components/VarSegmentMessageEditor/index.scss +0 -46
- package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +0 -17
- package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +0 -79
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +0 -90
- package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +0 -258
- package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +0 -125
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +0 -227
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -318
- package/v2Containers/Sms/smsFormDataHelpers.js +0 -67
- package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +0 -253
- package/v2Containers/SmsTrai/Edit/index.scss +0 -126
- package/v2Containers/Templates/TemplatesActionBar.js +0 -101
- package/v2Containers/Templates/tests/TemplatesActionBar.test.js +0 -120
- package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +0 -180
- package/v2Containers/Templates/utils/smsTemplatesListApi.js +0 -79
- package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +0 -131
package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js
CHANGED
|
@@ -9,72 +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
|
-
import { typeMatches, unwrapEntity } from '../../utils';
|
|
14
12
|
|
|
15
|
-
/**
|
|
16
|
-
* Include row unless explicitly invalid — many APIs omit `valid`, which would
|
|
17
|
-
* otherwise filter out every sender (RCS/SMS lists empty in UI).
|
|
18
|
-
*/
|
|
19
13
|
const getSenderOptions = (contactInfo, key) =>
|
|
20
14
|
(contactInfo || [])
|
|
21
|
-
.filter((contactInfoItem) =>
|
|
15
|
+
.filter((contactInfoItem) => contactInfoItem.type === key && contactInfoItem.valid)
|
|
22
16
|
.sort((contact) => (contact.default ? -1 : 0));
|
|
23
17
|
|
|
24
|
-
/** RCS APIs may label senders under several `contactInfo.type` keys — see `RCS_CONTACT_INFO_GSM_TYPE_KEYS`. */
|
|
25
|
-
const getRcsLikeGsmSenders = (contactInfo) => {
|
|
26
|
-
const seen = new Set();
|
|
27
|
-
const mergedSenderRows = [];
|
|
28
|
-
RCS_CONTACT_INFO_GSM_TYPE_KEYS.forEach((key) => {
|
|
29
|
-
getSenderOptions(contactInfo, key).forEach((row) => {
|
|
30
|
-
const senderValue = row?.value;
|
|
31
|
-
// Skip empty/whitespace sender values to avoid polluting the RCS sender dropdown.
|
|
32
|
-
if (senderValue == null || String(senderValue).trim() === '' || seen.has(senderValue)) return;
|
|
33
|
-
seen.add(senderValue);
|
|
34
|
-
mergedSenderRows.push(row);
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
return mergedSenderRows.sort((a, b) => (a.default ? -1 : 0) - (b.default ? -1 : 0));
|
|
38
|
-
};
|
|
39
|
-
|
|
40
18
|
/**
|
|
41
19
|
* Parse raw API response for one channel into { domains: [...] }
|
|
42
|
-
* @param {string} channel - SMS | EMAIL | WHATSAPP
|
|
20
|
+
* @param {string} channel - SMS | EMAIL | WHATSAPP
|
|
43
21
|
* @param {Object} response - API response (e.g. { entity: { SMS: [...] } } or { entity: [...] })
|
|
44
22
|
* @returns {{ domains: Array }} - domains array compatible with campaigns DeliverySettingsV2
|
|
45
23
|
*/
|
|
46
24
|
export function parseSenderDetailsResponse(channel, response) {
|
|
47
|
-
const entity =
|
|
48
|
-
if (entity
|
|
25
|
+
const entity = get(response, 'entity', response);
|
|
26
|
+
if (!entity) {
|
|
49
27
|
return { domains: [] };
|
|
50
28
|
}
|
|
51
29
|
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
channel == null || String(channel).trim() === ''
|
|
55
|
-
? ''
|
|
56
|
-
: String(channel).trim().toUpperCase();
|
|
57
|
-
|
|
58
|
-
// Single-channel API: entity may be { [channel]: [...] } or direct array.
|
|
59
|
-
// Some responses use different casing (e.g. rcs vs RCS) or a single domain object instead of an array.
|
|
60
|
-
let channelSenderDetails =
|
|
61
|
-
get(entity, channel, null)
|
|
62
|
-
?? (normalizedChannel ? get(entity, normalizedChannel, null) : null)
|
|
63
|
-
?? (normalizedChannel ? get(entity, normalizedChannel.toLowerCase(), null) : null);
|
|
64
|
-
|
|
30
|
+
// Single-channel API: entity may be { [channel]: [...] } or direct array
|
|
31
|
+
let channelSenderDetails = get(entity, channel, null);
|
|
65
32
|
if (channelSenderDetails == null && Array.isArray(entity)) {
|
|
66
33
|
channelSenderDetails = entity;
|
|
67
34
|
}
|
|
68
|
-
|
|
69
|
-
if (channelSenderDetails != null && !Array.isArray(channelSenderDetails)) {
|
|
70
|
-
const single = channelSenderDetails;
|
|
71
|
-
if (single && typeof single === 'object' && single.domainProperties) {
|
|
72
|
-
channelSenderDetails = [single];
|
|
73
|
-
} else {
|
|
74
|
-
return { domains: [] };
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
35
|
if (!Array.isArray(channelSenderDetails)) {
|
|
79
36
|
return { domains: [] };
|
|
80
37
|
}
|
|
@@ -85,7 +42,6 @@ export function parseSenderDetailsResponse(channel, response) {
|
|
|
85
42
|
const { id: dgmId, priority, domainProperties = {} } = element;
|
|
86
43
|
const {
|
|
87
44
|
domainName,
|
|
88
|
-
hostName,
|
|
89
45
|
id = -1,
|
|
90
46
|
contactInfo,
|
|
91
47
|
connectionProperties: {
|
|
@@ -95,25 +51,21 @@ export function parseSenderDetailsResponse(channel, response) {
|
|
|
95
51
|
} = {},
|
|
96
52
|
} = domainProperties;
|
|
97
53
|
|
|
98
|
-
const resolvedDomainName = domainName || hostName;
|
|
99
|
-
|
|
100
54
|
const domain = {
|
|
101
55
|
dgmId,
|
|
102
|
-
domainName
|
|
56
|
+
domainName,
|
|
103
57
|
domainId: id,
|
|
104
58
|
priority: priority != null ? priority : 0,
|
|
105
59
|
};
|
|
106
60
|
|
|
107
|
-
if ([CHANNELS.SMS, CHANNELS.WHATSAPP
|
|
61
|
+
if ([CHANNELS.SMS, CHANNELS.WHATSAPP].includes(channel)) {
|
|
108
62
|
domain.cdmaSenders = getSenderOptions(contactInfo, 'cdma_sender_id');
|
|
109
|
-
domain.gsmSenders =
|
|
110
|
-
? getRcsLikeGsmSenders(contactInfo)
|
|
111
|
-
: getSenderOptions(contactInfo, 'gsm_sender_id');
|
|
63
|
+
domain.gsmSenders = getSenderOptions(contactInfo, 'gsm_sender_id');
|
|
112
64
|
domain.sourceAccountIdentifier =
|
|
113
65
|
sourceAccountIdentifier || wabaId || userid || '';
|
|
114
66
|
}
|
|
115
67
|
|
|
116
|
-
if (
|
|
68
|
+
if (channel === CHANNELS.EMAIL) {
|
|
117
69
|
domain.emailSenders = getSenderOptions(contactInfo, 'sender_id');
|
|
118
70
|
domain.emailRepliers = getSenderOptions(contactInfo, 'reply_to_id');
|
|
119
71
|
}
|
|
@@ -124,8 +76,7 @@ export function parseSenderDetailsResponse(channel, response) {
|
|
|
124
76
|
// Sort by priority and dedupe by domainName (match campaigns behaviour)
|
|
125
77
|
domains.sort((a, b) => (a.priority || 0) - (b.priority || 0));
|
|
126
78
|
const deduped = domains.reduce((acc, domain) => {
|
|
127
|
-
|
|
128
|
-
if (!acc.find((existing) => (existing.domainName ?? existing.domainId) === key)) {
|
|
79
|
+
if (!acc.find((d) => d.domainName === domain.domainName)) {
|
|
129
80
|
acc.push(domain);
|
|
130
81
|
}
|
|
131
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
55
|
-
const renderRcsSuggestionsPreview = (suggestionsArg, options = {}) => {
|
|
56
|
-
const { isCarousel = false } = options;
|
|
53
|
+
const renderRcsSuggestionsPreview = () => {
|
|
57
54
|
const renderArray = [];
|
|
58
|
-
const suggestions =
|
|
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
|
|
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=
|
|
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=
|
|
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=
|
|
94
|
-
|
|
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,108 +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" type="flex" noWrap>
|
|
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
|
|
165
|
-
title={formatMessage(messages.videoPreviewTooltip)}
|
|
166
|
-
wrapperClassName="rcs-carousel-video-tooltip-wrapper"
|
|
167
|
-
triggerClassName="rcs-carousel-video-tooltip-trigger"
|
|
168
|
-
>
|
|
169
|
-
<CapRow className="video-preview">
|
|
170
|
-
<CapRow
|
|
171
|
-
className="whatsapp-image rcs-carousel-media-wrap"
|
|
172
|
-
style={getCarouselMediaAspectStyle(true)}
|
|
173
|
-
>
|
|
174
|
-
<CapImage
|
|
175
|
-
src={card?.videoPreviewImg ? card.videoPreviewImg : rcsVideoEmptyPreview}
|
|
176
|
-
className="rcs-carousel-img"
|
|
177
|
-
alt={formatMessage(messages.previewGenerated)}
|
|
178
|
-
/>
|
|
179
|
-
</CapRow>
|
|
180
|
-
<CapRow className="icon-position">
|
|
181
|
-
<CapImage className="video-icon" src={videoPlay} alt="Play" />
|
|
182
|
-
</CapRow>
|
|
183
|
-
</CapRow>
|
|
184
|
-
</CapTooltip>
|
|
185
|
-
)}
|
|
186
|
-
|
|
187
|
-
<CapRow className="carousel-content">
|
|
188
|
-
<CapLabel
|
|
189
|
-
type={card.titleLabelType || 'label1'}
|
|
190
|
-
className={`carousel-title${titleTrimmed ? '' : ' rcs-carousel-field-placeholder'}`}
|
|
191
|
-
>
|
|
192
|
-
{titleShown}
|
|
193
|
-
</CapLabel>
|
|
194
|
-
<CapLabel
|
|
195
|
-
type={card.bodyLabelType || 'label2'}
|
|
196
|
-
className={`carousel-message${bodyTrimmed ? '' : ' rcs-carousel-field-placeholder'}`}
|
|
197
|
-
>
|
|
198
|
-
{bodyShown}
|
|
199
|
-
</CapLabel>
|
|
200
|
-
</CapRow>
|
|
201
|
-
|
|
202
|
-
{!!suggestionsNode && (
|
|
203
|
-
<CapRow className="rcs-carousel-cta-stack" gutter={0}>
|
|
204
|
-
{suggestionsNode}
|
|
205
|
-
</CapRow>
|
|
206
|
-
)}
|
|
207
|
-
</CapRow>
|
|
208
|
-
</CapRow>
|
|
209
|
-
);
|
|
210
|
-
})}
|
|
211
|
-
</CapRow>
|
|
212
|
-
</CapRow>
|
|
213
|
-
);
|
|
214
|
-
|
|
215
96
|
// Render text preview content
|
|
216
97
|
const renderTextPreviewContent = () => {
|
|
217
98
|
const {
|
|
@@ -345,39 +226,11 @@ const RcsPreviewContent = ({
|
|
|
345
226
|
const timestamp = `${displayHours}:${displayMinutes} ${ampm}`;
|
|
346
227
|
|
|
347
228
|
// Render normal RCS preview (same structure as SMS up to sms-message-container)
|
|
348
|
-
const carouselCardsNormalized = Array.isArray(content?.carouselData) ? content?.carouselData : [];
|
|
349
|
-
const hasCarousel = carouselCardsNormalized?.length > 0;
|
|
350
229
|
const hasMedia = !!(content?.rcsImageSrc || content?.rcsVideoSrc);
|
|
351
|
-
|
|
352
|
-
if (hasCarousel) {
|
|
353
|
-
contentToRender = renderCarouselPreviewContent(carouselCardsNormalized);
|
|
354
|
-
} else if (hasMedia) {
|
|
355
|
-
contentToRender = renderMediaPreviewContent();
|
|
356
|
-
} else {
|
|
357
|
-
contentToRender = renderTextPreviewContent();
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
const carouselPanelStyle = hasCarousel ? {
|
|
361
|
-
position: 'absolute',
|
|
362
|
-
left: '50%',
|
|
363
|
-
transform: 'translateX(-50%)',
|
|
364
|
-
width: '100%',
|
|
365
|
-
maxWidth: '26.786rem',
|
|
366
|
-
boxSizing: 'border-box',
|
|
367
|
-
top: device === ANDROID ? '3.1rem' : '4.143rem',
|
|
368
|
-
height: device === ANDROID ? 'calc(100% - 3.8rem)' : device === IOS ? 'calc(100% - 5rem)' : 'calc(100% - 4.5rem)',
|
|
369
|
-
display: 'flex',
|
|
370
|
-
flexDirection: 'column',
|
|
371
|
-
paddingTop: '5.857rem',
|
|
372
|
-
paddingBottom: '1.142rem',
|
|
373
|
-
} : undefined;
|
|
230
|
+
const contentToRender = hasMedia ? renderMediaPreviewContent() : renderTextPreviewContent();
|
|
374
231
|
|
|
375
232
|
return (
|
|
376
|
-
<CapRow
|
|
377
|
-
type='flex' align='middle' justify='center'
|
|
378
|
-
className={`sms-device-container rcs-device-container ${hasCarousel ? 'rcs-device-container-carousel' : ''}`}
|
|
379
|
-
style={{ position: 'relative' }}
|
|
380
|
-
>
|
|
233
|
+
<CapRow type='flex' align='middle' justify='center' className="sms-device-container">
|
|
381
234
|
{/* Device Background Image */}
|
|
382
235
|
<CapImage
|
|
383
236
|
className="sms-device-image"
|
|
@@ -385,10 +238,8 @@ const RcsPreviewContent = ({
|
|
|
385
238
|
alt={`${deviceName} Device`}
|
|
386
239
|
/>
|
|
387
240
|
|
|
388
|
-
{/* Content Overlay
|
|
389
|
-
<CapRow
|
|
390
|
-
className={`sms-content-overlay sms-content-overlay-${device} sms-preview sms-${device} rcs-content-overlay`}
|
|
391
|
-
>
|
|
241
|
+
{/* Content Overlay */}
|
|
242
|
+
<CapRow className={`sms-content-overlay sms-content-overlay-${device} sms-preview sms-${device}`}>
|
|
392
243
|
{/* Navigation Bar - Same as SMS */}
|
|
393
244
|
<CapRow type='flex' className={`sms-navigation-bar ${!showHeader ? 'sms-navigation-bar-no-header' : ''}`}>
|
|
394
245
|
<CapIcon type="chevron-left" className="sms-back-arrow" />
|
|
@@ -403,41 +254,24 @@ const RcsPreviewContent = ({
|
|
|
403
254
|
<FormattedMessage {...messages.timeAgo} defaultMessage="Today" />
|
|
404
255
|
</CapRow>
|
|
405
256
|
|
|
406
|
-
{/* Message Container -
|
|
407
|
-
|
|
408
|
-
<CapRow className="sms-message-
|
|
409
|
-
<CapRow useLegacy className="sms-message-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
</CapRow>
|
|
257
|
+
{/* Message Container - Same structure as SMS, only content inside is RCS-specific */}
|
|
258
|
+
<CapRow className="sms-message-container">
|
|
259
|
+
<CapRow useLegacy className="sms-message-bubble">
|
|
260
|
+
<CapRow useLegacy className="sms-message-text">
|
|
261
|
+
{/* RCS-specific content rendering */}
|
|
262
|
+
<CapRow useLegacy className="message-pop sms">
|
|
263
|
+
{contentToRender}
|
|
414
264
|
</CapRow>
|
|
415
265
|
</CapRow>
|
|
416
|
-
<CapRow useLegacy className="sms-timestamp">
|
|
417
|
-
{timestamp}
|
|
418
|
-
</CapRow>
|
|
419
266
|
</CapRow>
|
|
420
|
-
|
|
421
|
-
</CapRow>
|
|
422
|
-
|
|
423
|
-
{/* Carousel panel: sibling of overlay, no overflow-x:hidden ancestor → scroll-container
|
|
424
|
-
can receive horizontal scroll events. Positioned absolutely over the device image. */}
|
|
425
|
-
{hasCarousel && (
|
|
426
|
-
<CapRow
|
|
427
|
-
className={`rcs-carousel-panel rcs-carousel-panel-${device}`}
|
|
428
|
-
style={carouselPanelStyle}
|
|
429
|
-
>
|
|
430
|
-
{renderCarouselPreviewContent(carouselCardsNormalized)}
|
|
431
|
-
<CapRow useLegacy className="sms-timestamp rcs-carousel-timestamp">
|
|
267
|
+
<CapRow useLegacy className="sms-timestamp">
|
|
432
268
|
{timestamp}
|
|
433
269
|
</CapRow>
|
|
434
270
|
</CapRow>
|
|
435
|
-
|
|
271
|
+
</CapRow>
|
|
436
272
|
</CapRow>
|
|
437
|
-
)
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
|
|
273
|
+
);
|
|
274
|
+
};
|
|
441
275
|
|
|
442
276
|
RcsPreviewContent.propTypes = {
|
|
443
277
|
content: PropTypes.shape({
|
|
@@ -448,18 +282,6 @@ RcsPreviewContent.propTypes = {
|
|
|
448
282
|
rcsImageSrc: PropTypes.string,
|
|
449
283
|
rcsVideoSrc: PropTypes.string,
|
|
450
284
|
rcsThumbnailSrc: PropTypes.string,
|
|
451
|
-
carouselData: PropTypes.arrayOf(
|
|
452
|
-
PropTypes.shape({
|
|
453
|
-
titleLabelType: PropTypes.string,
|
|
454
|
-
bodyLabelType: PropTypes.string,
|
|
455
|
-
})
|
|
456
|
-
),
|
|
457
|
-
carouselPreviewDimensions: PropTypes.shape({
|
|
458
|
-
imageWidth: PropTypes.number,
|
|
459
|
-
imageHeight: PropTypes.number,
|
|
460
|
-
videoThumbWidth: PropTypes.number,
|
|
461
|
-
videoThumbHeight: PropTypes.number,
|
|
462
|
-
}),
|
|
463
285
|
suggestions: PropTypes.arrayOf(
|
|
464
286
|
PropTypes.shape({
|
|
465
287
|
type: PropTypes.string,
|