@capillarytech/creatives-library 9.0.54-alpha.2 → 9.0.54-alpha.4
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 +1 -1
- package/services/api.js +11 -0
- package/v2Containers/CommunicationFlow/CommunicationFlow.js +29 -5
- package/v2Containers/CommunicationFlow/CommunicationFlowCard.js +1 -1
- package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +96 -4
- package/v2Containers/CommunicationFlow/Tests/CommunicationFlowCard.test.js +2 -2
- package/v2Containers/CommunicationFlow/constants.js +6 -5
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.js +6 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +25 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/deliverySettingsConfig.test.js +11 -4
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/deliverySettingsConfig.js +24 -5
package/package.json
CHANGED
package/services/api.js
CHANGED
|
@@ -710,6 +710,17 @@ export const createCommDefinition = (payload) => {
|
|
|
710
710
|
return request(url, getAPICallObject('POST', payload, false, false, false, true));
|
|
711
711
|
};
|
|
712
712
|
|
|
713
|
+
// Opens a new DRAFT version with the given content on an EXISTING
|
|
714
|
+
// CommDefinition (same id/referenceId) — used by CommunicationFlow's edit-mode
|
|
715
|
+
// save (re-editing a rejected alert) instead of createCommDefinition, so the
|
|
716
|
+
// alert keeps its identity rather than becoming a brand-new CommDefinition.
|
|
717
|
+
// Route verified against a real Postman sample against Veyron's own
|
|
718
|
+
// /commdefinition/{id}/edit endpoint.
|
|
719
|
+
export const editCommDefinition = (commDefinitionId, payload) => {
|
|
720
|
+
const url = `${API_ENDPOINT}/comm-definitions/${commDefinitionId}/edit`;
|
|
721
|
+
return request(url, getAPICallObject('POST', payload, false, false, false, true));
|
|
722
|
+
};
|
|
723
|
+
|
|
713
724
|
export const getCentralCommsMetaIds = (metaIds, metaType = TRANSACTION) => {
|
|
714
725
|
const url = `${API_ENDPOINT}/common/central-comms/meta-id/${metaType}?metaIds=${metaIds}`;
|
|
715
726
|
return request(url, getAPICallObject('GET', null, false, false, false, true));
|
|
@@ -21,7 +21,7 @@ import CapLabel from '@capillarytech/cap-ui-library/CapLabel';
|
|
|
21
21
|
// import injectSaga from '../../utils/injectSaga'; // cap-coupons flows disabled
|
|
22
22
|
// import injectReducer from '../../utils/injectReducer';
|
|
23
23
|
import { makeSelectAuthenticated } from '../Cap/selectors';
|
|
24
|
-
import { createCommDefinition } from '../../services/api';
|
|
24
|
+
import { createCommDefinition, editCommDefinition } from '../../services/api';
|
|
25
25
|
import DynamicControlsStep from './steps/DynamicControlsStep';
|
|
26
26
|
import MessageTypeStep from './steps/MessageTypeStep';
|
|
27
27
|
import CommunicationStrategyStep from './steps/CommunicationStrategyStep';
|
|
@@ -215,14 +215,29 @@ const CommunicationFlow = ({
|
|
|
215
215
|
singleChannelStrategy: {
|
|
216
216
|
variant: {
|
|
217
217
|
channel,
|
|
218
|
-
|
|
219
|
-
|
|
218
|
+
// `channel` spreads LAST in both objects below — contentItem.templateData
|
|
219
|
+
// (e.g. mobile push) carries the UI's own internal channel identifier
|
|
220
|
+
// (MOBILEPUSH), which must never win over CCS's normalized enum value
|
|
221
|
+
// (PUSH) once spread order puts it after.
|
|
222
|
+
...(contentKey && { [contentKey]: { ...contentPayload, channel } }),
|
|
223
|
+
...(deliveryKey && { [deliveryKey]: { channelSettings: { ...channelSettings, channel } } }),
|
|
220
224
|
},
|
|
221
225
|
},
|
|
222
226
|
};
|
|
223
227
|
|
|
228
|
+
// Editing an existing (e.g. rejected) alert: config.context.existingCommDefinitionId
|
|
229
|
+
// opens a new DRAFT version on that SAME CommDefinition instead of creating a
|
|
230
|
+
// brand-new one, so the alert keeps its id/referenceId across the edit.
|
|
231
|
+
const { existingCommDefinitionId } = config?.context || {};
|
|
232
|
+
|
|
224
233
|
try {
|
|
225
|
-
const res =
|
|
234
|
+
const res = existingCommDefinitionId
|
|
235
|
+
? await editCommDefinition(existingCommDefinitionId, {
|
|
236
|
+
strategyType: payload.strategyType,
|
|
237
|
+
settings: payload.settings,
|
|
238
|
+
singleChannelStrategy: payload.singleChannelStrategy,
|
|
239
|
+
})
|
|
240
|
+
: await createCommDefinition(payload);
|
|
226
241
|
if (isDuplicateReferenceIdError(res)) {
|
|
227
242
|
// Duplicate referenceId in this org — block the save so the user can
|
|
228
243
|
// change it, rather than silently proceeding without a CCS comm.
|
|
@@ -230,7 +245,16 @@ const CommunicationFlow = ({
|
|
|
230
245
|
return;
|
|
231
246
|
}
|
|
232
247
|
const data = res?.response?.data;
|
|
233
|
-
if (
|
|
248
|
+
if (existingCommDefinitionId) {
|
|
249
|
+
if (data) {
|
|
250
|
+
ccsCommDefinition = {
|
|
251
|
+
id: existingCommDefinitionId,
|
|
252
|
+
referenceId: referenceId || data.referenceId,
|
|
253
|
+
version: data.version?.version ?? data.version ?? 1,
|
|
254
|
+
status: data.status,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
} else if (data?.id) {
|
|
234
258
|
ccsCommDefinition = {
|
|
235
259
|
id: data.id,
|
|
236
260
|
referenceId: data.referenceId,
|
|
@@ -42,7 +42,7 @@ const resolveValue = (val) => {
|
|
|
42
42
|
|
|
43
43
|
const SENDER_ID_RESOLVERS = {
|
|
44
44
|
[SMS]: (setting) => resolveValue(setting?.gsmSenderId),
|
|
45
|
-
[EMAIL]: (setting) => resolveValue(setting?.
|
|
45
|
+
[EMAIL]: (setting) => resolveValue(setting?.senderId),
|
|
46
46
|
[VIBER]: (setting) => resolveValue(setting?.sender) || resolveValue(setting?.gsmSenderId),
|
|
47
47
|
[WHATSAPP]: (setting) => resolveValue(setting?.senderMobNum),
|
|
48
48
|
[RCS]: (setting) => resolveValue(setting?.senderMobNum) || resolveValue(setting?.rcsSender),
|
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
|
|
3
3
|
jest.mock('../../../services/api', () => ({
|
|
4
4
|
createCommDefinition: jest.fn(),
|
|
5
|
+
editCommDefinition: jest.fn(),
|
|
5
6
|
}));
|
|
6
7
|
|
|
7
8
|
jest.mock('../../CreativesContainer', () => function MockCreativesContainer({
|
|
@@ -37,7 +38,7 @@ import { IntlProvider } from 'react-intl';
|
|
|
37
38
|
import history from '../../../utils/history';
|
|
38
39
|
import { initialReducer } from '../../../initialReducer';
|
|
39
40
|
import CommunicationFlow from '../CommunicationFlow';
|
|
40
|
-
import { createCommDefinition } from '../../../services/api';
|
|
41
|
+
import { createCommDefinition, editCommDefinition } from '../../../services/api';
|
|
41
42
|
import { getEnabledSteps } from '../utils/getEnabledSteps';
|
|
42
43
|
import {
|
|
43
44
|
CHANNELS,
|
|
@@ -407,7 +408,7 @@ describe('handleSave — CCS flow', () => {
|
|
|
407
408
|
initialData: {
|
|
408
409
|
contentItems: [{
|
|
409
410
|
channel: 'EMAIL',
|
|
410
|
-
templateData: { emailSubject: 'Order Confirmed',
|
|
411
|
+
templateData: { emailSubject: 'Order Confirmed', emailBody: '<html>Hi</html>' },
|
|
411
412
|
}],
|
|
412
413
|
},
|
|
413
414
|
onSave,
|
|
@@ -478,13 +479,21 @@ describe('handleSave — CCS flow', () => {
|
|
|
478
479
|
);
|
|
479
480
|
});
|
|
480
481
|
|
|
481
|
-
it('normalizes the internal MOBILEPUSH channel to CCS\'s PUSH enum (keys stay mpush*)', async () => {
|
|
482
|
+
it('normalizes the internal MOBILEPUSH channel to CCS\'s PUSH enum (keys stay mpush*), even when templateData/channelSetting carry their own stray channel field', async () => {
|
|
482
483
|
const onSave = jest.fn();
|
|
483
484
|
renderWithFlow({
|
|
484
485
|
features: {},
|
|
485
486
|
config: ccsConfig,
|
|
486
487
|
initialData: {
|
|
487
|
-
|
|
488
|
+
// `channel: 'MOBILEPUSH'` inline on templateData reproduces the real
|
|
489
|
+
// production bug: contentItem.templateData carries the UI's own
|
|
490
|
+
// internal channel identifier, which must not win over the
|
|
491
|
+
// normalized 'PUSH' enum once spread into mpushMessageContent.
|
|
492
|
+
contentItems: [{ channel: 'MOBILEPUSH', templateData: { channel: 'MOBILEPUSH', messageSubject: 'Hi' } }],
|
|
493
|
+
// Likewise, deliverySetting.channelSetting.PUSH carrying its own
|
|
494
|
+
// stray `channel` key must not win over the normalized value once
|
|
495
|
+
// spread into mpushDeliverySettings.channelSettings.
|
|
496
|
+
deliverySetting: { channelSetting: { PUSH: { channel: 'MOBILEPUSH', domainId: 2002 } } },
|
|
488
497
|
},
|
|
489
498
|
onSave,
|
|
490
499
|
});
|
|
@@ -498,6 +507,9 @@ describe('handleSave — CCS flow', () => {
|
|
|
498
507
|
variant: expect.objectContaining({
|
|
499
508
|
channel: 'PUSH',
|
|
500
509
|
mpushMessageContent: { channel: 'PUSH', messageSubject: 'Hi' },
|
|
510
|
+
mpushDeliverySettings: {
|
|
511
|
+
channelSettings: { channel: 'PUSH', domainId: 2002 },
|
|
512
|
+
},
|
|
501
513
|
}),
|
|
502
514
|
}),
|
|
503
515
|
}),
|
|
@@ -727,6 +739,86 @@ describe('handleSave — CCS flow', () => {
|
|
|
727
739
|
gsmSenderId: 'BRAND1',
|
|
728
740
|
});
|
|
729
741
|
});
|
|
742
|
+
|
|
743
|
+
it('does not call editCommDefinition when config.context.existingCommDefinitionId is absent', async () => {
|
|
744
|
+
const onSave = jest.fn();
|
|
745
|
+
renderWithFlow({
|
|
746
|
+
features: {},
|
|
747
|
+
config: ccsConfig,
|
|
748
|
+
initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
|
|
749
|
+
onSave,
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
753
|
+
|
|
754
|
+
await waitFor(() => expect(createCommDefinition).toHaveBeenCalledTimes(1));
|
|
755
|
+
expect(editCommDefinition).not.toHaveBeenCalled();
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
it('calls editCommDefinition (not createCommDefinition) and merges the existing id into ccsCommDefinition when config.context.existingCommDefinitionId is set', async () => {
|
|
759
|
+
editCommDefinition.mockResolvedValue({
|
|
760
|
+
response: { data: { version: { version: 2 }, status: 'DRAFT' } },
|
|
761
|
+
});
|
|
762
|
+
const onSave = jest.fn();
|
|
763
|
+
renderWithFlow({
|
|
764
|
+
features: {},
|
|
765
|
+
config: {
|
|
766
|
+
...ccsConfig,
|
|
767
|
+
context: { ...ccsConfig.context, referenceId: 'ORDER_PLACED', existingCommDefinitionId: 'cd_existing_1' },
|
|
768
|
+
},
|
|
769
|
+
initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
|
|
770
|
+
onSave,
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
774
|
+
|
|
775
|
+
await waitFor(() => expect(editCommDefinition).toHaveBeenCalledTimes(1));
|
|
776
|
+
expect(editCommDefinition).toHaveBeenCalledWith(
|
|
777
|
+
'cd_existing_1',
|
|
778
|
+
expect.objectContaining({
|
|
779
|
+
strategyType: 'SINGLE',
|
|
780
|
+
settings: expect.anything(),
|
|
781
|
+
singleChannelStrategy: expect.anything(),
|
|
782
|
+
}),
|
|
783
|
+
);
|
|
784
|
+
expect(createCommDefinition).not.toHaveBeenCalled();
|
|
785
|
+
|
|
786
|
+
await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));
|
|
787
|
+
expect(onSave).toHaveBeenCalledWith(
|
|
788
|
+
expect.objectContaining({
|
|
789
|
+
ccsCommDefinition: {
|
|
790
|
+
id: 'cd_existing_1',
|
|
791
|
+
referenceId: 'ORDER_PLACED',
|
|
792
|
+
version: 2,
|
|
793
|
+
status: 'DRAFT',
|
|
794
|
+
},
|
|
795
|
+
}),
|
|
796
|
+
);
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
it('blocks save and shows an error when editCommDefinition resolves with a duplicate REFERENCE_ID_EXISTS conflict', async () => {
|
|
800
|
+
editCommDefinition.mockResolvedValue({
|
|
801
|
+
success: false,
|
|
802
|
+
status: { isError: true, code: 409, message: 'REFERENCE_ID_EXISTS' },
|
|
803
|
+
message: 'REFERENCE_ID_EXISTS',
|
|
804
|
+
});
|
|
805
|
+
const onSave = jest.fn();
|
|
806
|
+
renderWithFlow({
|
|
807
|
+
features: {},
|
|
808
|
+
config: {
|
|
809
|
+
...ccsConfig,
|
|
810
|
+
context: { ...ccsConfig.context, referenceId: 'ORDER_PLACED', existingCommDefinitionId: 'cd_existing_1' },
|
|
811
|
+
},
|
|
812
|
+
initialData: { contentItems: [{ channel: 'SMS', templateData: {} }] },
|
|
813
|
+
onSave,
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
|
|
817
|
+
|
|
818
|
+
await waitFor(() => expect(editCommDefinition).toHaveBeenCalledTimes(1));
|
|
819
|
+
expect(await screen.findByText(/already in use in your organization/i)).toBeInTheDocument();
|
|
820
|
+
expect(onSave).not.toHaveBeenCalled();
|
|
821
|
+
});
|
|
730
822
|
});
|
|
731
823
|
|
|
732
824
|
describe('renderSteps — null returns and edge cases', () => {
|
|
@@ -247,11 +247,11 @@ describe('CommunicationFlowCard', () => {
|
|
|
247
247
|
expect(screen.getByText(/Sender ID/)).toBeInTheDocument();
|
|
248
248
|
});
|
|
249
249
|
|
|
250
|
-
it('shows
|
|
250
|
+
it('shows senderId for EMAIL with Sender ID label', () => {
|
|
251
251
|
renderCard({
|
|
252
252
|
initialData: makeSavedData({
|
|
253
253
|
contentItems: [{ channel: 'EMAIL', templateData: {} }],
|
|
254
|
-
deliverySetting: { channelSetting: { EMAIL: {
|
|
254
|
+
deliverySetting: { channelSetting: { EMAIL: { senderId: 'test@example.com' } } },
|
|
255
255
|
}),
|
|
256
256
|
});
|
|
257
257
|
expect(screen.getByText(/test@example.com/)).toBeInTheDocument();
|
|
@@ -68,14 +68,15 @@ export const CCS_CHANNEL_CONTENT_KEY_MAP = {
|
|
|
68
68
|
// editor (messageMeta-oriented field names) — for channels whose legacy field
|
|
69
69
|
// names don't match CCS's own content schema, transform before sending rather
|
|
70
70
|
// than dumping templateData as-is. EMAIL: legacy stores the subject as
|
|
71
|
-
// `emailSubject`
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
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`.
|
|
75
76
|
export const CCS_CONTENT_TRANSFORMS = {
|
|
76
77
|
EMAIL: (templateData = {}) => ({
|
|
77
78
|
messageSubject: templateData.emailSubject,
|
|
78
|
-
messageBody: templateData.
|
|
79
|
+
messageBody: templateData.emailBody || templateData.emailHtml,
|
|
79
80
|
}),
|
|
80
81
|
// WEBPUSH: the legacy editor nests the real data under
|
|
81
82
|
// messageContent.content (see CommunicationFlowCard.js's own comment on
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
getEmailDefaultsForDomainId,
|
|
30
30
|
getSmsDefaultsForDomainId,
|
|
31
31
|
getRcsAccountName,
|
|
32
|
+
getEmailDomainGatewayMapIdByDomainId,
|
|
32
33
|
} from './deliverySettingsConfig';
|
|
33
34
|
import messages from '../../messages';
|
|
34
35
|
import './SenderDetails.scss';
|
|
@@ -151,6 +152,11 @@ const SenderDetails = ({
|
|
|
151
152
|
saveValues.whatsappDomainId = matchedDomain?.domainProperties?.id ?? matchedDomain?.domainId ?? matchedDomain?.id;
|
|
152
153
|
}
|
|
153
154
|
}
|
|
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
|
+
}
|
|
154
160
|
onSave(saveValues);
|
|
155
161
|
}
|
|
156
162
|
onClose();
|
package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js
CHANGED
|
@@ -83,6 +83,7 @@ const ENTITIES = {
|
|
|
83
83
|
emailTwoDomains: {
|
|
84
84
|
EMAIL: [
|
|
85
85
|
{
|
|
86
|
+
id: 'gwmap-a',
|
|
86
87
|
domainProperties: {
|
|
87
88
|
id: 'em-a',
|
|
88
89
|
domainName: 'Mail Alpha',
|
|
@@ -101,6 +102,7 @@ const ENTITIES = {
|
|
|
101
102
|
},
|
|
102
103
|
},
|
|
103
104
|
{
|
|
105
|
+
id: 'gwmap-b',
|
|
104
106
|
domainProperties: {
|
|
105
107
|
id: 'em-b',
|
|
106
108
|
domainName: 'Mail Beta',
|
|
@@ -322,6 +324,29 @@ describe('SenderDetails', () => {
|
|
|
322
324
|
});
|
|
323
325
|
});
|
|
324
326
|
|
|
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
|
+
|
|
325
350
|
it('resets email domain row back to the first gateway', async () => {
|
|
326
351
|
renderSenderDetails({
|
|
327
352
|
channels: ['EMAIL'],
|
|
@@ -438,6 +438,7 @@ describe('deliverySettingsConfig — user-facing flows', () => {
|
|
|
438
438
|
smsDomain: 'd1',
|
|
439
439
|
smsSenderId: 'g1',
|
|
440
440
|
emailDomain: 'ed',
|
|
441
|
+
emailDomainGatewayMapId: 'gwmap-1',
|
|
441
442
|
emailSenderId: 'mail@x.com',
|
|
442
443
|
emailSenderName: 'N',
|
|
443
444
|
emailReplyToId: 'r@x.com',
|
|
@@ -455,9 +456,10 @@ describe('deliverySettingsConfig — user-facing flows', () => {
|
|
|
455
456
|
SMS: { domainId: 'd1', gsmSenderId: 'g1' },
|
|
456
457
|
EMAIL: {
|
|
457
458
|
domainId: 'ed',
|
|
458
|
-
|
|
459
|
+
domainGatewayMapId: 'gwmap-1',
|
|
460
|
+
senderId: 'mail@x.com',
|
|
459
461
|
senderLabel: 'N',
|
|
460
|
-
|
|
462
|
+
replyToId: 'r@x.com',
|
|
461
463
|
},
|
|
462
464
|
WHATSAPP: { domainId: 'wd', senderMobNum: '+w' },
|
|
463
465
|
RCS: { senderMobNum: '+r', rcsSender: '+r' },
|
|
@@ -472,9 +474,10 @@ describe('deliverySettingsConfig — user-facing flows', () => {
|
|
|
472
474
|
SMS: { domainId: 'd', gsmSenderId: 'g' },
|
|
473
475
|
EMAIL: {
|
|
474
476
|
domainId: 'ed',
|
|
475
|
-
|
|
477
|
+
domainGatewayMapId: 'gwmap-2',
|
|
478
|
+
senderId: 'e@e.com',
|
|
476
479
|
senderLabel: 'L',
|
|
477
|
-
|
|
480
|
+
replyToId: 'r@e.com',
|
|
478
481
|
},
|
|
479
482
|
WHATSAPP: { senderMobNum: '+w', domainId: 'wid' },
|
|
480
483
|
RCS: { rcsSender: '+r' },
|
|
@@ -486,6 +489,10 @@ describe('deliverySettingsConfig — user-facing flows', () => {
|
|
|
486
489
|
smsDomain: 'd',
|
|
487
490
|
smsSenderId: 'g',
|
|
488
491
|
emailDomain: 'ed',
|
|
492
|
+
emailDomainGatewayMapId: 'gwmap-2',
|
|
493
|
+
emailSenderId: 'e@e.com',
|
|
494
|
+
emailSenderName: 'L',
|
|
495
|
+
emailReplyToId: 'r@e.com',
|
|
489
496
|
whatsappDomainId: 'wid',
|
|
490
497
|
viberSenderId: 'vx',
|
|
491
498
|
});
|
|
@@ -181,6 +181,14 @@ 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
|
+
|
|
184
192
|
/** Domain name for summary display (parseEntityForDisplay) */
|
|
185
193
|
const getEmailDomainNameForDisplay = (entity) => {
|
|
186
194
|
const emailData = getEmailData(entity);
|
|
@@ -262,6 +270,8 @@ const getEmailDefaultsForDomain = (domainData) => {
|
|
|
262
270
|
* context.fieldValues has current form state (e.g. selected emailDomain)
|
|
263
271
|
* Aligned with adiona-ui/cap-campaigns-v2: default = contactInfo item with default:true, or first
|
|
264
272
|
*/
|
|
273
|
+
export { getEmailDomainGatewayMapIdByDomainId };
|
|
274
|
+
|
|
265
275
|
export const getDefaultValueForField = (fieldKey, entity, context = {}) => {
|
|
266
276
|
if (!entity) return '';
|
|
267
277
|
const fieldValues = context?.fieldValues || {};
|
|
@@ -574,7 +584,11 @@ export const parseEntityForDisplay = (entity, context = {}) => {
|
|
|
574
584
|
senderDetails: entity,
|
|
575
585
|
smsSenderId: getSmsSenderIdValue(entity),
|
|
576
586
|
smsDomain: getSmsDomainValue(entity),
|
|
587
|
+
// emailDomain here is the domain NAME (for display only) - buildChannelSettingFromFieldValues
|
|
588
|
+
// needs the numeric domainId/domainGatewayMapId, sourced separately below.
|
|
577
589
|
emailDomain: getEmailDomainNameForDisplay(entity),
|
|
590
|
+
emailDomainId: getEmailDomainValue(entity),
|
|
591
|
+
emailDomainGatewayMapId: getEmailDomainGatewayMapIdByDomainId(entity, getEmailDomainValue(entity)),
|
|
578
592
|
emailSenderId: getEmailSenderIdValue(entity),
|
|
579
593
|
viberSenderId: getSenderIdFromContactInfo(entity, 'VIBER'),
|
|
580
594
|
zaloSenderId: getSenderIdFromContactInfo(entity, 'ZALO'),
|
|
@@ -600,10 +614,14 @@ export const buildChannelSettingFromFieldValues = (fieldValues = {}) => {
|
|
|
600
614
|
}
|
|
601
615
|
if (fieldValues.emailDomain != null || fieldValues.emailSenderId != null || fieldValues.emailSenderName != null || fieldValues.emailReplyToId != null) {
|
|
602
616
|
channelSetting.EMAIL = {
|
|
603
|
-
|
|
604
|
-
|
|
617
|
+
// emailDomainId (numeric, from the auto-save-defaults path via parseEntityForDisplay)
|
|
618
|
+
// takes priority over emailDomain, which is numeric when sourced from SenderDetails'
|
|
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,
|
|
605
623
|
senderLabel: fieldValues.emailSenderName,
|
|
606
|
-
|
|
624
|
+
replyToId: fieldValues.emailReplyToId,
|
|
607
625
|
};
|
|
608
626
|
}
|
|
609
627
|
if (fieldValues.whatsappSenderNumber != null || fieldValues.whatsappAccount != null) {
|
|
@@ -673,9 +691,10 @@ export const parseChannelSettingForDisplay = (channelSetting = {}) => {
|
|
|
673
691
|
}
|
|
674
692
|
if (channelSetting.EMAIL) {
|
|
675
693
|
out.emailDomain = channelSetting.EMAIL.domainId;
|
|
676
|
-
out.
|
|
694
|
+
out.emailDomainGatewayMapId = channelSetting.EMAIL.domainGatewayMapId;
|
|
695
|
+
out.emailSenderId = channelSetting.EMAIL.senderId;
|
|
677
696
|
out.emailSenderName = channelSetting.EMAIL.senderLabel;
|
|
678
|
-
out.emailReplyToId = channelSetting.EMAIL.
|
|
697
|
+
out.emailReplyToId = channelSetting.EMAIL.replyToId;
|
|
679
698
|
}
|
|
680
699
|
if (channelSetting.WHATSAPP) {
|
|
681
700
|
out.whatsappSenderNumber = channelSetting.WHATSAPP.senderMobNum;
|