@capillarytech/creatives-library 9.0.54-alpha.4 → 9.0.54
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 +1 -0
- package/package.json +1 -1
- package/services/api.js +0 -20
- package/utils/common.js +4 -0
- package/v2Components/FormBuilder/Classic.js +2 -2
- package/v2Containers/CommunicationFlow/CommunicationFlow.js +56 -118
- package/v2Containers/CommunicationFlow/CommunicationFlowCard.js +5 -21
- package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +49 -365
- package/v2Containers/CommunicationFlow/Tests/CommunicationFlowCard.test.js +2 -18
- package/v2Containers/CommunicationFlow/constants.js +1 -81
- package/v2Containers/CommunicationFlow/index.js +20 -15
- package/v2Containers/CommunicationFlow/messages.js +0 -4
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.js +0 -6
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +0 -25
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/deliverySettingsConfig.test.js +4 -11
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/deliverySettingsConfig.js +5 -24
- package/v2Containers/MobilePush/Edit/index.js +1 -2
|
@@ -38,86 +38,6 @@ export const CHANNEL_PRIORITY = 'CHANNEL_PRIORITY';
|
|
|
38
38
|
export const AB_TEST = 'AB_TEST';
|
|
39
39
|
export const SINGLE_TEMPLATE = 'SINGLE_TEMPLATE';
|
|
40
40
|
|
|
41
|
-
// CCS CommDefinition strategyType — distinct from SINGLE_TEMPLATE above, which
|
|
42
|
-
// is this UI's own communicationStrategy value. Only SINGLE is supported this
|
|
43
|
-
// phase; CCS create is skipped entirely for CHANNEL_PRIORITY/AB_TEST.
|
|
44
|
-
export const CCS_STRATEGY_TYPE_SINGLE = 'SINGLE';
|
|
45
|
-
|
|
46
|
-
// Mirrors CCS's SingleChannelStrategy field names exactly (Cap Notify API
|
|
47
|
-
// Design doc sample payloads, verified against real create responses). Kept
|
|
48
|
-
// separate from CHANNEL_CONTENT_KEY_MAP/CHANNEL_DELIVERY_KEY_MAP below, which
|
|
49
|
-
// are the legacy messageMeta payload's keys.
|
|
50
|
-
export const CCS_CHANNEL_CONTENT_KEY_MAP = {
|
|
51
|
-
SMS: 'smsMessageContent',
|
|
52
|
-
EMAIL: 'emailMessageContent',
|
|
53
|
-
WHATSAPP: 'whatsappMessageContent',
|
|
54
|
-
// CCS's channel enum value for mobile push is 'PUSH' (verified against real
|
|
55
|
-
// create responses), even though the content/delivery keys stay 'mpush*'.
|
|
56
|
-
PUSH: 'mpushMessageContent',
|
|
57
|
-
INAPP: 'inAppMessageContent',
|
|
58
|
-
ANDROID: 'androidMessageContent',
|
|
59
|
-
IOS: 'iosMessageContent',
|
|
60
|
-
ZALO: 'zaloMessageContent',
|
|
61
|
-
VIBER: 'viberMessageContent',
|
|
62
|
-
LINE: 'lineMessageContent',
|
|
63
|
-
WEBPUSH: 'webPushMessageContent',
|
|
64
|
-
RCS: 'rcsMessageContent',
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
// contentItem.templateData is built by the legacy CreativesContainer content
|
|
68
|
-
// editor (messageMeta-oriented field names) — for channels whose legacy field
|
|
69
|
-
// names don't match CCS's own content schema, transform before sending rather
|
|
70
|
-
// than dumping templateData as-is. EMAIL: legacy stores the subject as
|
|
71
|
-
// `emailSubject` and the HTML body as `emailBody` (see
|
|
72
|
-
// extractContentForPreview.js and CreativesContainer/index.js, where the Bee
|
|
73
|
-
// editor's output is written back into templateData.emailBody — also
|
|
74
|
-
// mirrored by the existing legacy emailMessageContent builder in
|
|
75
|
-
// utils/transformerUtils.js). CCS expects `messageSubject`/`messageBody`.
|
|
76
|
-
export const CCS_CONTENT_TRANSFORMS = {
|
|
77
|
-
EMAIL: (templateData = {}) => ({
|
|
78
|
-
messageSubject: templateData.emailSubject,
|
|
79
|
-
messageBody: templateData.emailBody || templateData.emailHtml,
|
|
80
|
-
}),
|
|
81
|
-
// WEBPUSH: the legacy editor nests the real data under
|
|
82
|
-
// messageContent.content (see CommunicationFlowCard.js's own comment on
|
|
83
|
-
// this same wrapping, for the edit-mode case) — extracting it flat here
|
|
84
|
-
// matches CCS's shape ({ messageSubject, accountId, content }); `offers`
|
|
85
|
-
// (a legacy-only field) is deliberately dropped, not part of CCS's schema.
|
|
86
|
-
WEBPUSH: (templateData = {}) => {
|
|
87
|
-
const inner = templateData.messageContent?.content || templateData;
|
|
88
|
-
return {
|
|
89
|
-
messageSubject: inner.messageSubject,
|
|
90
|
-
accountId: inner.accountId,
|
|
91
|
-
content: inner.content,
|
|
92
|
-
};
|
|
93
|
-
},
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
export const CCS_CHANNEL_DELIVERY_KEY_MAP = {
|
|
97
|
-
SMS: 'smsDeliverySettings',
|
|
98
|
-
EMAIL: 'emailDeliverySettings',
|
|
99
|
-
WHATSAPP: 'whatsappDeliverySettings',
|
|
100
|
-
PUSH: 'mpushDeliverySettings',
|
|
101
|
-
INAPP: 'inAppDeliverySettings',
|
|
102
|
-
ANDROID: 'androidDeliverySettings',
|
|
103
|
-
IOS: 'iosDeliverySettings',
|
|
104
|
-
ZALO: 'zaloDeliverySettings',
|
|
105
|
-
VIBER: 'viberDeliverySettings',
|
|
106
|
-
LINE: 'lineDeliverySettings',
|
|
107
|
-
WEBPUSH: 'webPushDeliverySettings',
|
|
108
|
-
RCS: 'rcsDeliverySettings',
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
// The UI's own internal channel identifier for mobile push is 'MOBILEPUSH'
|
|
112
|
-
// (see CreativesContainer/constants.js MOBILE_PUSH), but CCS's channel enum
|
|
113
|
-
// value is 'PUSH' (verified against real create responses — the content/
|
|
114
|
-
// delivery KEYS still say 'mpush*', only the enum VALUE is 'PUSH') —
|
|
115
|
-
// normalize before building the CCS payload. Every other channel identifier
|
|
116
|
-
// matches CCS as-is.
|
|
117
|
-
export const CCS_CHANNEL_NAME_MAP = {
|
|
118
|
-
MOBILEPUSH: 'PUSH',
|
|
119
|
-
};
|
|
120
|
-
|
|
121
41
|
// Channel config - single source of truth for CreativesContainer and TemplatesV2
|
|
122
42
|
// paneKey: TemplatesV2 defaultPanes object key (for channelsToHide)
|
|
123
43
|
// channelProp: CreativesContainer channel prop (must match pane.key for tab to be active)
|
|
@@ -312,4 +232,4 @@ export const INCENTIVE_TYPES = [
|
|
|
312
232
|
{
|
|
313
233
|
value: 'badges', label: <FormattedMessage {...messages.badges} />, isActive: false, disabled: false,
|
|
314
234
|
},
|
|
315
|
-
];
|
|
235
|
+
];
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import React from 'react';
|
|
10
10
|
import PropTypes from 'prop-types';
|
|
11
11
|
import CommunicationFlow from './CommunicationFlow';
|
|
12
|
+
import { hasSupportEngagementModule } from '../../utils/common';
|
|
12
13
|
|
|
13
14
|
const CommunicationFlowContainer = ({
|
|
14
15
|
config,
|
|
@@ -17,16 +18,22 @@ const CommunicationFlowContainer = ({
|
|
|
17
18
|
onCancel,
|
|
18
19
|
onChange,
|
|
19
20
|
...otherProps
|
|
20
|
-
}) =>
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
}) => {
|
|
22
|
+
if (!hasSupportEngagementModule()) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<CommunicationFlow
|
|
28
|
+
config={config}
|
|
29
|
+
initialData={initialData}
|
|
30
|
+
onSave={onSave}
|
|
31
|
+
onCancel={onCancel}
|
|
32
|
+
onChange={onChange}
|
|
33
|
+
{...otherProps}
|
|
34
|
+
/>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
30
37
|
|
|
31
38
|
CommunicationFlowContainer.propTypes = {
|
|
32
39
|
config: PropTypes.shape({
|
|
@@ -80,13 +87,11 @@ CommunicationFlowContainer.propTypes = {
|
|
|
80
87
|
controls: PropTypes.array,
|
|
81
88
|
}),
|
|
82
89
|
}),
|
|
83
|
-
context: PropTypes.object, // ouId, campaignId, programId
|
|
84
|
-
//
|
|
85
|
-
useCCS: PropTypes.bool, // If false, skips the CCS createCommDefinition call on save. Defaults to true.
|
|
90
|
+
context: PropTypes.object, // ouId, campaignId, programId, etc.
|
|
91
|
+
useCCS: PropTypes.bool, // If false, skips CCS bulk-claim-approve on save. Defaults to true.
|
|
86
92
|
}).isRequired,
|
|
87
93
|
initialData: PropTypes.object, // for edit/preview mode
|
|
88
|
-
onSave: PropTypes.func.isRequired, // (data) => void - called when user saves
|
|
89
|
-
// ({id, referenceId, version, status}) is present when the CCS create succeeded
|
|
94
|
+
onSave: PropTypes.func.isRequired, // (data) => void - called when user saves
|
|
90
95
|
onCancel: PropTypes.func.isRequired, // () => void - called when user cancels
|
|
91
96
|
onChange: PropTypes.func, // (data) => void - optional, called on data changes
|
|
92
97
|
};
|
|
@@ -363,8 +363,4 @@ export default {
|
|
|
363
363
|
id: `${prefix}.senderNotConfiguredError`,
|
|
364
364
|
defaultMessage: 'Selected domain gateway id is not correct. Please change the domain id or contact the gateway team to register them with Capillary.',
|
|
365
365
|
},
|
|
366
|
-
duplicateReferenceIdError: {
|
|
367
|
-
id: `${prefix}.duplicateReferenceIdError`,
|
|
368
|
-
defaultMessage: 'This reference ID is already in use in your organization. Please use a different reference ID.',
|
|
369
|
-
},
|
|
370
366
|
};
|
|
@@ -29,7 +29,6 @@ import {
|
|
|
29
29
|
getEmailDefaultsForDomainId,
|
|
30
30
|
getSmsDefaultsForDomainId,
|
|
31
31
|
getRcsAccountName,
|
|
32
|
-
getEmailDomainGatewayMapIdByDomainId,
|
|
33
32
|
} from './deliverySettingsConfig';
|
|
34
33
|
import messages from '../../messages';
|
|
35
34
|
import './SenderDetails.scss';
|
|
@@ -152,11 +151,6 @@ const SenderDetails = ({
|
|
|
152
151
|
saveValues.whatsappDomainId = matchedDomain?.domainProperties?.id ?? matchedDomain?.domainId ?? matchedDomain?.id;
|
|
153
152
|
}
|
|
154
153
|
}
|
|
155
|
-
// Include EMAIL domainGatewayMapId derived from the selected domain for persistence -
|
|
156
|
-
// CCS needs it alongside domainId, but it's not a user-facing field.
|
|
157
|
-
if (entity && fieldValues.emailDomain != null && fieldValues.emailDomain !== '') {
|
|
158
|
-
saveValues.emailDomainGatewayMapId = getEmailDomainGatewayMapIdByDomainId(entity, fieldValues.emailDomain);
|
|
159
|
-
}
|
|
160
154
|
onSave(saveValues);
|
|
161
155
|
}
|
|
162
156
|
onClose();
|
package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js
CHANGED
|
@@ -83,7 +83,6 @@ const ENTITIES = {
|
|
|
83
83
|
emailTwoDomains: {
|
|
84
84
|
EMAIL: [
|
|
85
85
|
{
|
|
86
|
-
id: 'gwmap-a',
|
|
87
86
|
domainProperties: {
|
|
88
87
|
id: 'em-a',
|
|
89
88
|
domainName: 'Mail Alpha',
|
|
@@ -102,7 +101,6 @@ const ENTITIES = {
|
|
|
102
101
|
},
|
|
103
102
|
},
|
|
104
103
|
{
|
|
105
|
-
id: 'gwmap-b',
|
|
106
104
|
domainProperties: {
|
|
107
105
|
id: 'em-b',
|
|
108
106
|
domainName: 'Mail Beta',
|
|
@@ -324,29 +322,6 @@ describe('SenderDetails', () => {
|
|
|
324
322
|
});
|
|
325
323
|
});
|
|
326
324
|
|
|
327
|
-
it('persists emailDomainGatewayMapId derived from the selected email domain on save', async () => {
|
|
328
|
-
const { onSave } = renderSenderDetails({
|
|
329
|
-
channels: ['EMAIL'],
|
|
330
|
-
preloadedDomainProperties: ENTITIES.emailTwoDomains,
|
|
331
|
-
});
|
|
332
|
-
const root = document.querySelector('.sender-details');
|
|
333
|
-
await waitFor(() => expect(within(root).getByText('Mail Alpha')).toBeInTheDocument());
|
|
334
|
-
|
|
335
|
-
await openSelectAndChoose(root, 0, 'Mail Beta');
|
|
336
|
-
await waitFor(() => expect(within(root).getByText('beta@other.com')).toBeInTheDocument());
|
|
337
|
-
|
|
338
|
-
const saveBtn = within(root).getByRole('button', { name: /save changes/i });
|
|
339
|
-
await waitFor(() => expect(saveBtn).not.toBeDisabled());
|
|
340
|
-
fireEvent.click(saveBtn);
|
|
341
|
-
|
|
342
|
-
expect(onSave).toHaveBeenCalledWith(
|
|
343
|
-
expect.objectContaining({
|
|
344
|
-
emailDomain: 'em-b',
|
|
345
|
-
emailDomainGatewayMapId: 'gwmap-b',
|
|
346
|
-
}),
|
|
347
|
-
);
|
|
348
|
-
});
|
|
349
|
-
|
|
350
325
|
it('resets email domain row back to the first gateway', async () => {
|
|
351
326
|
renderSenderDetails({
|
|
352
327
|
channels: ['EMAIL'],
|
|
@@ -438,7 +438,6 @@ describe('deliverySettingsConfig — user-facing flows', () => {
|
|
|
438
438
|
smsDomain: 'd1',
|
|
439
439
|
smsSenderId: 'g1',
|
|
440
440
|
emailDomain: 'ed',
|
|
441
|
-
emailDomainGatewayMapId: 'gwmap-1',
|
|
442
441
|
emailSenderId: 'mail@x.com',
|
|
443
442
|
emailSenderName: 'N',
|
|
444
443
|
emailReplyToId: 'r@x.com',
|
|
@@ -456,10 +455,9 @@ describe('deliverySettingsConfig — user-facing flows', () => {
|
|
|
456
455
|
SMS: { domainId: 'd1', gsmSenderId: 'g1' },
|
|
457
456
|
EMAIL: {
|
|
458
457
|
domainId: 'ed',
|
|
459
|
-
|
|
460
|
-
senderId: 'mail@x.com',
|
|
458
|
+
senderEmail: 'mail@x.com',
|
|
461
459
|
senderLabel: 'N',
|
|
462
|
-
|
|
460
|
+
senderReplyTo: 'r@x.com',
|
|
463
461
|
},
|
|
464
462
|
WHATSAPP: { domainId: 'wd', senderMobNum: '+w' },
|
|
465
463
|
RCS: { senderMobNum: '+r', rcsSender: '+r' },
|
|
@@ -474,10 +472,9 @@ describe('deliverySettingsConfig — user-facing flows', () => {
|
|
|
474
472
|
SMS: { domainId: 'd', gsmSenderId: 'g' },
|
|
475
473
|
EMAIL: {
|
|
476
474
|
domainId: 'ed',
|
|
477
|
-
|
|
478
|
-
senderId: 'e@e.com',
|
|
475
|
+
senderEmail: 'e@e.com',
|
|
479
476
|
senderLabel: 'L',
|
|
480
|
-
|
|
477
|
+
senderReplyTo: 'r@e.com',
|
|
481
478
|
},
|
|
482
479
|
WHATSAPP: { senderMobNum: '+w', domainId: 'wid' },
|
|
483
480
|
RCS: { rcsSender: '+r' },
|
|
@@ -489,10 +486,6 @@ describe('deliverySettingsConfig — user-facing flows', () => {
|
|
|
489
486
|
smsDomain: 'd',
|
|
490
487
|
smsSenderId: 'g',
|
|
491
488
|
emailDomain: 'ed',
|
|
492
|
-
emailDomainGatewayMapId: 'gwmap-2',
|
|
493
|
-
emailSenderId: 'e@e.com',
|
|
494
|
-
emailSenderName: 'L',
|
|
495
|
-
emailReplyToId: 'r@e.com',
|
|
496
489
|
whatsappDomainId: 'wid',
|
|
497
490
|
viberSenderId: 'vx',
|
|
498
491
|
});
|
|
@@ -181,14 +181,6 @@ const getEmailDomainValue = (entity) => {
|
|
|
181
181
|
return emailData.domainProperties?.id ?? emailData.domainId ?? emailData.id ?? '';
|
|
182
182
|
};
|
|
183
183
|
|
|
184
|
-
// CCS's domainGatewayMapId is the domainProperties API's own outer `id`
|
|
185
|
-
// (distinct from `domainProperties.id`, which is the numeric domainId) - the
|
|
186
|
-
// domain-gateway-mapping id for the selected domain entry.
|
|
187
|
-
const getEmailDomainGatewayMapIdByDomainId = (entity, domainId) => {
|
|
188
|
-
const domainEntry = getEmailDomainById(entity, domainId);
|
|
189
|
-
return domainEntry?.id ?? '';
|
|
190
|
-
};
|
|
191
|
-
|
|
192
184
|
/** Domain name for summary display (parseEntityForDisplay) */
|
|
193
185
|
const getEmailDomainNameForDisplay = (entity) => {
|
|
194
186
|
const emailData = getEmailData(entity);
|
|
@@ -270,8 +262,6 @@ const getEmailDefaultsForDomain = (domainData) => {
|
|
|
270
262
|
* context.fieldValues has current form state (e.g. selected emailDomain)
|
|
271
263
|
* Aligned with adiona-ui/cap-campaigns-v2: default = contactInfo item with default:true, or first
|
|
272
264
|
*/
|
|
273
|
-
export { getEmailDomainGatewayMapIdByDomainId };
|
|
274
|
-
|
|
275
265
|
export const getDefaultValueForField = (fieldKey, entity, context = {}) => {
|
|
276
266
|
if (!entity) return '';
|
|
277
267
|
const fieldValues = context?.fieldValues || {};
|
|
@@ -584,11 +574,7 @@ export const parseEntityForDisplay = (entity, context = {}) => {
|
|
|
584
574
|
senderDetails: entity,
|
|
585
575
|
smsSenderId: getSmsSenderIdValue(entity),
|
|
586
576
|
smsDomain: getSmsDomainValue(entity),
|
|
587
|
-
// emailDomain here is the domain NAME (for display only) - buildChannelSettingFromFieldValues
|
|
588
|
-
// needs the numeric domainId/domainGatewayMapId, sourced separately below.
|
|
589
577
|
emailDomain: getEmailDomainNameForDisplay(entity),
|
|
590
|
-
emailDomainId: getEmailDomainValue(entity),
|
|
591
|
-
emailDomainGatewayMapId: getEmailDomainGatewayMapIdByDomainId(entity, getEmailDomainValue(entity)),
|
|
592
578
|
emailSenderId: getEmailSenderIdValue(entity),
|
|
593
579
|
viberSenderId: getSenderIdFromContactInfo(entity, 'VIBER'),
|
|
594
580
|
zaloSenderId: getSenderIdFromContactInfo(entity, 'ZALO'),
|
|
@@ -614,14 +600,10 @@ export const buildChannelSettingFromFieldValues = (fieldValues = {}) => {
|
|
|
614
600
|
}
|
|
615
601
|
if (fieldValues.emailDomain != null || fieldValues.emailSenderId != null || fieldValues.emailSenderName != null || fieldValues.emailReplyToId != null) {
|
|
616
602
|
channelSetting.EMAIL = {
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
// own field state but a display NAME string when sourced from parseEntityForDisplay.
|
|
620
|
-
domainId: fieldValues.emailDomainId ?? fieldValues.emailDomain,
|
|
621
|
-
domainGatewayMapId: fieldValues.emailDomainGatewayMapId,
|
|
622
|
-
senderId: fieldValues.emailSenderId,
|
|
603
|
+
domainId: fieldValues.emailDomain,
|
|
604
|
+
senderEmail: fieldValues.emailSenderId,
|
|
623
605
|
senderLabel: fieldValues.emailSenderName,
|
|
624
|
-
|
|
606
|
+
senderReplyTo: fieldValues.emailReplyToId,
|
|
625
607
|
};
|
|
626
608
|
}
|
|
627
609
|
if (fieldValues.whatsappSenderNumber != null || fieldValues.whatsappAccount != null) {
|
|
@@ -691,10 +673,9 @@ export const parseChannelSettingForDisplay = (channelSetting = {}) => {
|
|
|
691
673
|
}
|
|
692
674
|
if (channelSetting.EMAIL) {
|
|
693
675
|
out.emailDomain = channelSetting.EMAIL.domainId;
|
|
694
|
-
out.
|
|
695
|
-
out.emailSenderId = channelSetting.EMAIL.senderId;
|
|
676
|
+
out.emailSenderId = channelSetting.EMAIL.senderEmail;
|
|
696
677
|
out.emailSenderName = channelSetting.EMAIL.senderLabel;
|
|
697
|
-
out.emailReplyToId = channelSetting.EMAIL.
|
|
678
|
+
out.emailReplyToId = channelSetting.EMAIL.senderReplyTo;
|
|
698
679
|
}
|
|
699
680
|
if (channelSetting.WHATSAPP) {
|
|
700
681
|
out.whatsappSenderNumber = channelSetting.WHATSAPP.senderMobNum;
|
|
@@ -1139,8 +1139,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
1139
1139
|
this.props.globalActions.addMessageToQueue(message);
|
|
1140
1140
|
} else {
|
|
1141
1141
|
const name = data.file.name.split('.');
|
|
1142
|
-
const
|
|
1143
|
-
const newFile = new File([blob], `${name[0]}${Date.now()}.${name[1]}`, {type: 'image'});
|
|
1142
|
+
const newFile = new File([data.file], `${name[0]}${Date.now()}.${name[1]}`, {type: 'image'});
|
|
1144
1143
|
this.props.actions.uploadAsset(newFile, data.type, data.fileParams);
|
|
1145
1144
|
}
|
|
1146
1145
|
};
|