@capillarytech/creatives-library 9.0.56-alpha.7 → 9.0.56-betaa.0
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 +4 -2
- package/package.json +1 -1
- package/services/api.js +0 -20
- package/utils/common.js +12 -0
- package/utils/templateVarUtils.js +0 -16
- package/utils/tests/templateVarUtils.test.js +0 -44
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +0 -13
- package/v2Components/CommonTestAndPreview/actions.js +0 -13
- package/v2Components/CommonTestAndPreview/constants.js +0 -8
- package/v2Components/CommonTestAndPreview/index.js +3 -55
- package/v2Components/CommonTestAndPreview/reducer.js +0 -20
- package/v2Components/CommonTestAndPreview/sagas.js +0 -28
- package/v2Components/CommonTestAndPreview/selectors.js +0 -6
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +0 -106
- package/v2Components/CommonTestAndPreview/tests/actions.test.js +0 -15
- package/v2Components/CommonTestAndPreview/tests/constants.test.js +1 -9
- package/v2Components/CommonTestAndPreview/tests/index.test.js +0 -101
- package/v2Components/CommonTestAndPreview/tests/reducer.test.js +0 -41
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +0 -84
- package/v2Components/CommonTestAndPreview/tests/selectors.test.js +0 -12
- package/v2Components/FormBuilder/Functional/FormBuilderShell.js +320 -46
- package/v2Components/FormBuilder/Functional/channels/mobilepush/buildSubmitPayload.js +10 -0
- package/v2Components/FormBuilder/Functional/channels/mobilepush/config.js +82 -0
- package/v2Components/FormBuilder/Functional/channels/mobilepush/getEditorErrorDescriptor.js +74 -0
- package/v2Components/FormBuilder/Functional/channels/mobilepush/index.js +28 -0
- package/v2Components/FormBuilder/Functional/channels/mobilepush/modals.js +19 -0
- package/v2Components/FormBuilder/Functional/channels/mobilepush/runSubmitPipeline.js +45 -0
- package/v2Components/FormBuilder/Functional/channels/mobilepush/tests/getEditorErrorDescriptor.test.js +162 -0
- package/v2Components/FormBuilder/Functional/channels/mobilepush/tests/modals.test.js +37 -0
- package/v2Components/FormBuilder/Functional/channels/mobilepush/tests/runSubmitPipeline.test.js +70 -0
- package/v2Components/FormBuilder/Functional/channels/mobilepush/tests/validate.test.js +274 -0
- package/v2Components/FormBuilder/Functional/channels/mobilepush/validate.js +251 -0
- package/v2Components/FormBuilder/Functional/channels/registry.js +2 -0
- package/v2Components/FormBuilder/Functional/constants.js +43 -8
- package/v2Components/FormBuilder/Functional/core/schema/initializeFormState.js +175 -28
- package/v2Components/FormBuilder/Functional/core/store/formReducer.js +75 -6
- package/v2Components/FormBuilder/Functional/core/store/toLegacyFormData.js +10 -20
- package/v2Components/FormBuilder/Functional/layout/FieldSlot.js +9 -1
- package/v2Components/FormBuilder/Functional/layout/SchemaForm.js +20 -3
- package/v2Components/FormBuilder/Functional/layout/Section.js +6 -1
- package/v2Components/FormBuilder/Functional/layout/TabsContainer.js +89 -0
- package/v2Components/FormBuilder/Functional/renderers/mpushRenderers.js +440 -0
- package/v2Components/FormBuilder/Functional/tests/fieldSlot.test.js +9 -2
- package/v2Components/FormBuilder/Functional/tests/mpush.crossFlowParity.test.js +430 -0
- package/v2Components/FormBuilder/Functional/tests/mpush.ctaFlows.parity.test.js +282 -0
- package/v2Components/FormBuilder/Functional/tests/mpush.editContainer.parity.test.js +141 -0
- package/v2Components/FormBuilder/Functional/tests/mpush.engine.test.js +306 -0
- package/v2Components/FormBuilder/Functional/tests/mpush.shellEvents.test.js +151 -0
- package/v2Components/FormBuilder/Functional/tests/mpushRenderers.test.js +342 -0
- package/v2Components/FormBuilder/Functional/tests/schemaForm.test.js +17 -0
- package/v2Components/FormBuilder/Functional/tests/tabsContainer.test.js +110 -0
- package/v2Components/FormBuilder/index.js +34 -12
- package/v2Components/FormBuilder/tests/entryGate.test.js +94 -7
- package/v2Components/FormBuilder/tests/mpush.characterization.test.js +459 -0
- package/v2Components/TestAndPreviewSlidebox/index.js +0 -9
- package/v2Containers/CommunicationFlow/CommunicationFlow.js +75 -140
- package/v2Containers/CommunicationFlow/CommunicationFlow.scss +2 -18
- package/v2Containers/CommunicationFlow/CommunicationFlowCard.js +27 -58
- package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +51 -503
- package/v2Containers/CommunicationFlow/Tests/CommunicationFlowCard.test.js +4 -40
- package/v2Containers/CommunicationFlow/constants.js +4 -65
- package/v2Containers/CommunicationFlow/index.js +23 -16
- package/v2Containers/CommunicationFlow/messages.js +3 -11
- package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.js +11 -24
- package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.scss +0 -4
- package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/Tests/ChannelSelectionStep.test.js +4 -176
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.js +0 -3
- 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 -19
- package/v2Containers/CreativesContainer/index.js +3 -2
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +5 -5
- package/v2Containers/CreativesContainer/tests/index.test.js +0 -12
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +19 -115
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +3 -27
- package/v2Containers/WebPush/Create/preview/WebPushPreview.js +12 -17
- package/v2Containers/WebPush/Create/preview/tests/WebPushPreview.test.js +0 -5
- package/v2Containers/Whatsapp/index.js +3 -6
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -306
- package/v2Containers/mockdata.js +0 -25
- package/v2Containers/CommunicationFlow/Tests/constants.test.js +0 -85
|
@@ -108,22 +108,6 @@ describe('CommunicationFlowCard', () => {
|
|
|
108
108
|
fireEvent.click(screen.getByText('Add creatives'));
|
|
109
109
|
expect(screen.getByTestId('comm-flow-mock')).toHaveAttribute('data-mode', 'create');
|
|
110
110
|
});
|
|
111
|
-
|
|
112
|
-
it('disables the Add creatives button when disabled prop is true', () => {
|
|
113
|
-
renderCard({ disabled: true, disabledTooltip: 'Enter an Alert name to add content' });
|
|
114
|
-
expect(screen.getByText('Add creatives').closest('button')).toBeDisabled();
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('does not open SlideBox when Add creatives is clicked while disabled', () => {
|
|
118
|
-
renderCard({ disabled: true, disabledTooltip: 'Enter an Alert name to add content' });
|
|
119
|
-
fireEvent.click(screen.getByText('Add creatives'));
|
|
120
|
-
expect(screen.queryByTestId('slide-box')).not.toBeInTheDocument();
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it('Add creatives button is enabled by default (disabled prop absent)', () => {
|
|
124
|
-
renderCard();
|
|
125
|
-
expect(screen.getByText('Add creatives').closest('button')).not.toBeDisabled();
|
|
126
|
-
});
|
|
127
111
|
});
|
|
128
112
|
|
|
129
113
|
describe('configured state (initialData provided)', () => {
|
|
@@ -202,26 +186,6 @@ describe('CommunicationFlowCard', () => {
|
|
|
202
186
|
renderCard({ initialData: makeSavedData() });
|
|
203
187
|
expect(screen.getByText('Other controls')).toBeInTheDocument();
|
|
204
188
|
});
|
|
205
|
-
|
|
206
|
-
it('hides the Other controls column when config.features.showDynamicControls is false', () => {
|
|
207
|
-
renderCard({
|
|
208
|
-
config: { ...baseConfig, features: { showDynamicControls: false } },
|
|
209
|
-
initialData: makeSavedData({
|
|
210
|
-
dynamicControls: {
|
|
211
|
-
sendToControlCustomers: false, sendToBrandPocs: false, useTinyUrl: false, overrideDailyLimit: false,
|
|
212
|
-
},
|
|
213
|
-
}),
|
|
214
|
-
});
|
|
215
|
-
expect(screen.queryByText('Other controls')).not.toBeInTheDocument();
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
it('still shows the Other controls column when showDynamicControls is unset (Engagement Module default)', () => {
|
|
219
|
-
renderCard({
|
|
220
|
-
config: { ...baseConfig, features: {} },
|
|
221
|
-
initialData: makeSavedData(),
|
|
222
|
-
});
|
|
223
|
-
expect(screen.getByText('Other controls')).toBeInTheDocument();
|
|
224
|
-
});
|
|
225
189
|
});
|
|
226
190
|
|
|
227
191
|
describe('channel config resolution', () => {
|
|
@@ -267,11 +231,11 @@ describe('CommunicationFlowCard', () => {
|
|
|
267
231
|
expect(screen.getByText(/Sender ID/)).toBeInTheDocument();
|
|
268
232
|
});
|
|
269
233
|
|
|
270
|
-
it('shows
|
|
234
|
+
it('shows senderEmail for EMAIL with Sender ID label', () => {
|
|
271
235
|
renderCard({
|
|
272
236
|
initialData: makeSavedData({
|
|
273
237
|
contentItems: [{ channel: 'EMAIL', templateData: {} }],
|
|
274
|
-
deliverySetting: { channelSetting: { EMAIL: {
|
|
238
|
+
deliverySetting: { channelSetting: { EMAIL: { senderEmail: 'test@example.com' } } },
|
|
275
239
|
}),
|
|
276
240
|
});
|
|
277
241
|
expect(screen.getByText(/test@example.com/)).toBeInTheDocument();
|
|
@@ -581,10 +545,10 @@ describe('CommunicationFlowCard', () => {
|
|
|
581
545
|
});
|
|
582
546
|
|
|
583
547
|
describe('SlideBox header', () => {
|
|
584
|
-
it('renders Add
|
|
548
|
+
it('renders Add message title in the slidebox header', () => {
|
|
585
549
|
renderCard();
|
|
586
550
|
fireEvent.click(screen.getByText('Add creatives'));
|
|
587
|
-
expect(screen.getByText('Add
|
|
551
|
+
expect(screen.getByText('Add message')).toBeInTheDocument();
|
|
588
552
|
});
|
|
589
553
|
});
|
|
590
554
|
|
|
@@ -38,68 +38,9 @@ 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
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// Mirrors CCS SingleChannelStrategy field names; kept separate from the legacy
|
|
45
|
-
// messageMeta CHANNEL_CONTENT_KEY_MAP/CHANNEL_DELIVERY_KEY_MAP.
|
|
46
|
-
export const CCS_CHANNEL_CONTENT_KEY_MAP = {
|
|
47
|
-
SMS: 'smsMessageContent',
|
|
48
|
-
EMAIL: 'emailMessageContent',
|
|
49
|
-
WHATSAPP: 'whatsappMessageContent',
|
|
50
|
-
// CCS's channel enum for mobile push is 'PUSH', but content/delivery keys stay 'mpush*'.
|
|
51
|
-
PUSH: 'mpushMessageContent',
|
|
52
|
-
INAPP: 'inAppMessageContent',
|
|
53
|
-
ANDROID: 'androidMessageContent',
|
|
54
|
-
IOS: 'iosMessageContent',
|
|
55
|
-
ZALO: 'zaloMessageContent',
|
|
56
|
-
VIBER: 'viberMessageContent',
|
|
57
|
-
LINE: 'lineMessageContent',
|
|
58
|
-
WEBPUSH: 'webPushMessageContent',
|
|
59
|
-
RCS: 'rcsMessageContent',
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
// Transforms legacy messageMeta field names to CCS's before sending, for channels
|
|
63
|
-
// where the two shapes don't already match.
|
|
64
|
-
export const CCS_CONTENT_TRANSFORMS = {
|
|
65
|
-
EMAIL: (templateData = {}) => ({
|
|
66
|
-
messageSubject: templateData.emailSubject,
|
|
67
|
-
messageBody: templateData.emailBody || templateData.emailHtml,
|
|
68
|
-
}),
|
|
69
|
-
SMS: (templateData = {}) => ({
|
|
70
|
-
message: templateData.messageBody || '',
|
|
71
|
-
}),
|
|
72
|
-
WEBPUSH: (templateData = {}) => {
|
|
73
|
-
const inner = templateData.messageContent?.content || templateData;
|
|
74
|
-
return {
|
|
75
|
-
messageSubject: inner.messageSubject,
|
|
76
|
-
accountId: inner.accountId,
|
|
77
|
-
content: inner.content,
|
|
78
|
-
};
|
|
79
|
-
},
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
export const CCS_CHANNEL_DELIVERY_KEY_MAP = {
|
|
83
|
-
SMS: 'smsDeliverySettings',
|
|
84
|
-
EMAIL: 'emailDeliverySettings',
|
|
85
|
-
WHATSAPP: 'whatsappDeliverySettings',
|
|
86
|
-
PUSH: 'mpushDeliverySettings',
|
|
87
|
-
INAPP: 'inAppDeliverySettings',
|
|
88
|
-
ANDROID: 'androidDeliverySettings',
|
|
89
|
-
IOS: 'iosDeliverySettings',
|
|
90
|
-
ZALO: 'zaloDeliverySettings',
|
|
91
|
-
VIBER: 'viberDeliverySettings',
|
|
92
|
-
LINE: 'lineDeliverySettings',
|
|
93
|
-
WEBPUSH: 'webPushDeliverySettings',
|
|
94
|
-
RCS: 'rcsDeliverySettings',
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
// UI uses `MOBILEPUSH`; CCS uses `PUSH` for the channel enum. Other channels pass through.
|
|
98
|
-
export const CCS_CHANNEL_NAME_MAP = {
|
|
99
|
-
MOBILEPUSH: 'PUSH',
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
// Channel config is the shared source of truth: paneKey maps TemplatesV2 panes, channelProp maps CreativesContainer tabs.
|
|
41
|
+
// Channel config - single source of truth for CreativesContainer and TemplatesV2
|
|
42
|
+
// paneKey: TemplatesV2 defaultPanes object key (for channelsToHide)
|
|
43
|
+
// channelProp: CreativesContainer channel prop (must match pane.key for tab to be active)
|
|
103
44
|
export const CHANNELS = [
|
|
104
45
|
{
|
|
105
46
|
value: 'SMS',
|
|
@@ -291,6 +232,4 @@ export const INCENTIVE_TYPES = [
|
|
|
291
232
|
{
|
|
292
233
|
value: 'badges', label: <FormattedMessage {...messages.badges} />, isActive: false, disabled: false,
|
|
293
234
|
},
|
|
294
|
-
];
|
|
295
|
-
|
|
296
|
-
export const REFERENCE_ID_EXISTS = 'REFERENCE_ID_EXISTS';
|
|
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,20 +18,26 @@ 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({
|
|
33
|
-
consumer: PropTypes.oneOf(['campaigns', 'loyalty', 'adiona'
|
|
40
|
+
consumer: PropTypes.oneOf(['campaigns', 'loyalty', 'adiona']).isRequired,
|
|
34
41
|
channel: PropTypes.string, // optional if channel step is skipped
|
|
35
42
|
mode: PropTypes.oneOf(['create', 'edit', 'preview']).isRequired,
|
|
36
43
|
channelsToHide: PropTypes.arrayOf(PropTypes.string),
|
|
@@ -80,13 +87,13 @@ CommunicationFlowContainer.propTypes = {
|
|
|
80
87
|
controls: PropTypes.array,
|
|
81
88
|
}),
|
|
82
89
|
}),
|
|
83
|
-
context: PropTypes.object, // ouId, campaignId, programId,
|
|
84
|
-
useCCS: PropTypes.bool, // skips
|
|
90
|
+
context: PropTypes.object, // ouId, campaignId, programId, etc.
|
|
91
|
+
useCCS: PropTypes.bool, // If false, skips CCS bulk-claim-approve on save. Defaults to true.
|
|
85
92
|
}).isRequired,
|
|
86
93
|
initialData: PropTypes.object, // for edit/preview mode
|
|
87
|
-
onSave: PropTypes.func.isRequired, // (data) => void
|
|
88
|
-
onCancel: PropTypes.func.isRequired, // () => void
|
|
89
|
-
onChange: PropTypes.func, // (data) => void
|
|
94
|
+
onSave: PropTypes.func.isRequired, // (data) => void - called when user saves
|
|
95
|
+
onCancel: PropTypes.func.isRequired, // () => void - called when user cancels
|
|
96
|
+
onChange: PropTypes.func, // (data) => void - optional, called on data changes
|
|
90
97
|
};
|
|
91
98
|
|
|
92
99
|
CommunicationFlowContainer.defaultProps = {
|
|
@@ -64,9 +64,9 @@ export default {
|
|
|
64
64
|
},
|
|
65
65
|
|
|
66
66
|
// Slidebox header
|
|
67
|
-
|
|
68
|
-
id: `${prefix}.
|
|
69
|
-
defaultMessage: 'Add
|
|
67
|
+
addMessage: {
|
|
68
|
+
id: `${prefix}.addMessage`,
|
|
69
|
+
defaultMessage: 'Add message',
|
|
70
70
|
},
|
|
71
71
|
|
|
72
72
|
// Step prompts
|
|
@@ -363,12 +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
|
-
genericSaveError: {
|
|
371
|
-
id: `${prefix}.genericSaveError`,
|
|
372
|
-
defaultMessage: 'Something went wrong while saving your content. Please try again.',
|
|
373
|
-
},
|
|
374
366
|
};
|
|
@@ -45,7 +45,6 @@ const ChannelSelectionStep = ({
|
|
|
45
45
|
onChange,
|
|
46
46
|
channelsToHide = [],
|
|
47
47
|
channelsToDisable = [],
|
|
48
|
-
disablePreviewAndTest = false,
|
|
49
48
|
creativesMode = 'create',
|
|
50
49
|
selectedOfferDetails = [],
|
|
51
50
|
incentivesData,
|
|
@@ -64,7 +63,6 @@ const ChannelSelectionStep = ({
|
|
|
64
63
|
const [showIncentivesMenuMap, setShowIncentivesMenuMap] = useState({});
|
|
65
64
|
const [showTestAndPreview, setShowTestAndPreview] = useState(false);
|
|
66
65
|
const [testAndPreviewItem, setTestAndPreviewItem] = useState(null);
|
|
67
|
-
const [domainPropertiesData, setDomainPropertiesData] = useState(null);
|
|
68
66
|
const { formatMessage } = intl || {};
|
|
69
67
|
|
|
70
68
|
// Available channels (filter out hidden ones)
|
|
@@ -78,19 +76,6 @@ const ChannelSelectionStep = ({
|
|
|
78
76
|
const selectedChannelLowerCase = selectedChannel?.toLowerCase();
|
|
79
77
|
return CHANNELS.find((channel) => channel?.value?.toLowerCase() === selectedChannelLowerCase || channel?.channelProp === selectedChannelLowerCase) || null;
|
|
80
78
|
}, [selectedChannel]);
|
|
81
|
-
|
|
82
|
-
const editingZaloHostName = useMemo(() => {
|
|
83
|
-
if (!editingContentId) return '';
|
|
84
|
-
const editingItem = contentItems.find((c) => c.contentId === editingContentId);
|
|
85
|
-
if (editingItem?.channel?.toUpperCase() !== ZALO) return '';
|
|
86
|
-
const accountId = editingItem?.templateData?.accountId;
|
|
87
|
-
if (!accountId) return '';
|
|
88
|
-
const zaloDomains = domainPropertiesData?.ZALO || [];
|
|
89
|
-
const matchedDomain = zaloDomains.find(
|
|
90
|
-
(domain) => String(domain?.domainProperties?.connectionProperties?.oa_id) === String(accountId),
|
|
91
|
-
);
|
|
92
|
-
return matchedDomain?.domainProperties?.hostName || '';
|
|
93
|
-
}, [editingContentId, contentItems, domainPropertiesData]);
|
|
94
79
|
/**
|
|
95
80
|
* Handle CreativesContainer close
|
|
96
81
|
*/
|
|
@@ -373,7 +358,7 @@ const ChannelSelectionStep = ({
|
|
|
373
358
|
>
|
|
374
359
|
{formatMessage(messages.edit)}
|
|
375
360
|
</CapMenu.Item>
|
|
376
|
-
{!
|
|
361
|
+
{!PREVIEW_TEST_UNSUPPORTED_CHANNELS.includes(item?.channel?.toUpperCase()) && (
|
|
377
362
|
<CapMenu.Item
|
|
378
363
|
id="preview-menu-item"
|
|
379
364
|
className="ant-dropdown-menu-item"
|
|
@@ -422,6 +407,10 @@ const ChannelSelectionStep = ({
|
|
|
422
407
|
return (
|
|
423
408
|
<>
|
|
424
409
|
<CapRow className="channel-selection-step">
|
|
410
|
+
<CapHeading type="h3" className="margin-b-8">
|
|
411
|
+
{formatMessage(messages.contentTemplate)}
|
|
412
|
+
</CapHeading>
|
|
413
|
+
|
|
425
414
|
<CapRow
|
|
426
415
|
useLegacy
|
|
427
416
|
className={`content-template-container ${contentItems?.length > 0 ? 'content-template-container--has-content' : ''}`}
|
|
@@ -433,7 +422,7 @@ const ChannelSelectionStep = ({
|
|
|
433
422
|
)}
|
|
434
423
|
|
|
435
424
|
{contentItems?.length === 0 ? (
|
|
436
|
-
<CapRow className=
|
|
425
|
+
<CapRow className="content-template-section">
|
|
437
426
|
<CapDropdown
|
|
438
427
|
overlay={renderChannelDropdownOverlay() || <CapMenu />}
|
|
439
428
|
onVisibleChange={handleChannelsVisibleChange}
|
|
@@ -481,7 +470,6 @@ const ChannelSelectionStep = ({
|
|
|
481
470
|
deliverySettingsData={deliverySettingsData}
|
|
482
471
|
deliverySetting={value?.deliverySetting}
|
|
483
472
|
onDeliverySettingChange={(deliverySetting) => onChange({ deliverySetting })}
|
|
484
|
-
onDomainPropertiesLoaded={setDomainPropertiesData}
|
|
485
473
|
intl={intl}
|
|
486
474
|
/>
|
|
487
475
|
)}
|
|
@@ -502,13 +490,14 @@ const ChannelSelectionStep = ({
|
|
|
502
490
|
getCreativesData={handleCreativesData}
|
|
503
491
|
handleCloseCreatives={handleCloseCreatives}
|
|
504
492
|
isFullMode={false}
|
|
505
|
-
|
|
506
|
-
messageDetails={{ type: (config?.context?.module || '').toLowerCase() || 'default' }}
|
|
507
|
-
location={{ query: { type: 'embedded', module: config?.context?.module } }}
|
|
493
|
+
messageDetails={{ type: 'default' }}
|
|
508
494
|
templateData={editingContentId ? (() => {
|
|
509
495
|
const saved = contentItems.find((c) => c.contentId === editingContentId)?.templateData;
|
|
496
|
+
// getTemplateData in CreativesContainer reads 'content', 'accountId', 'messageSubject' at
|
|
497
|
+
// top-level and needs 'type' for SlideBoxContent to set isEditWebPush. Our stored WEBPUSH
|
|
498
|
+
// templateData wraps those fields inside messageContent.content, so extract them here.
|
|
510
499
|
if (saved?.channel?.toUpperCase() === WEBPUSH && saved?.messageContent?.content) {
|
|
511
|
-
return { ...saved.messageContent.content, type: WEBPUSH
|
|
500
|
+
return { ...saved.messageContent.content, type: WEBPUSH };
|
|
512
501
|
}
|
|
513
502
|
return saved;
|
|
514
503
|
})() : null}
|
|
@@ -566,7 +555,6 @@ ChannelSelectionStep.propTypes = {
|
|
|
566
555
|
onChange: PropTypes.func.isRequired,
|
|
567
556
|
channelsToHide: PropTypes.array,
|
|
568
557
|
channelsToDisable: PropTypes.array,
|
|
569
|
-
disablePreviewAndTest: PropTypes.bool,
|
|
570
558
|
creativesMode: PropTypes.oneOf(['create', 'edit', 'preview']),
|
|
571
559
|
selectedOfferDetails: PropTypes.array,
|
|
572
560
|
incentivesData: PropTypes.shape({
|
|
@@ -588,7 +576,6 @@ ChannelSelectionStep.defaultProps = {
|
|
|
588
576
|
error: null,
|
|
589
577
|
channelsToHide: [],
|
|
590
578
|
channelsToDisable: [],
|
|
591
|
-
disablePreviewAndTest: false,
|
|
592
579
|
creativesMode: 'create',
|
|
593
580
|
selectedOfferDetails: [],
|
|
594
581
|
incentivesData: null,
|
package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/Tests/ChannelSelectionStep.test.js
CHANGED
|
@@ -37,21 +37,9 @@ jest.mock('../../../../CreativesContainer', () => function MockCreativesContaine
|
|
|
37
37
|
handleCloseCreatives,
|
|
38
38
|
creativesMode,
|
|
39
39
|
channel,
|
|
40
|
-
templateData,
|
|
41
|
-
hostName,
|
|
42
|
-
messageDetails,
|
|
43
|
-
location,
|
|
44
40
|
}) {
|
|
45
41
|
return (
|
|
46
|
-
<div
|
|
47
|
-
data-testid="creatives-mock"
|
|
48
|
-
data-creatives-mode={creativesMode}
|
|
49
|
-
data-creatives-channel={channel}
|
|
50
|
-
data-template-data={JSON.stringify(templateData)}
|
|
51
|
-
data-host-name={hostName}
|
|
52
|
-
data-message-details={JSON.stringify(messageDetails)}
|
|
53
|
-
data-location={JSON.stringify(location)}
|
|
54
|
-
>
|
|
42
|
+
<div data-testid="creatives-mock" data-creatives-mode={creativesMode} data-creatives-channel={channel}>
|
|
55
43
|
<button
|
|
56
44
|
type="button"
|
|
57
45
|
data-testid="creatives-save"
|
|
@@ -74,7 +62,7 @@ jest.mock('../../../../CreativesContainer', () => function MockCreativesContaine
|
|
|
74
62
|
});
|
|
75
63
|
|
|
76
64
|
jest.mock('../../DeliverySettingsStep', () => ({
|
|
77
|
-
DeliverySettingsSection: function MockDeliverySettings({ onDeliverySettingChange
|
|
65
|
+
DeliverySettingsSection: function MockDeliverySettings({ onDeliverySettingChange }) {
|
|
78
66
|
return (
|
|
79
67
|
<div data-testid="delivery-settings-section">
|
|
80
68
|
<button
|
|
@@ -84,23 +72,6 @@ jest.mock('../../DeliverySettingsStep', () => ({
|
|
|
84
72
|
>
|
|
85
73
|
Apply delivery
|
|
86
74
|
</button>
|
|
87
|
-
<button
|
|
88
|
-
type="button"
|
|
89
|
-
data-testid="domain-properties-loaded"
|
|
90
|
-
onClick={() => onDomainPropertiesLoaded?.({
|
|
91
|
-
ZALO: [{
|
|
92
|
-
id: 267284,
|
|
93
|
-
domainProperties: {
|
|
94
|
-
id: 4977,
|
|
95
|
-
domainName: 'Gapit_Automation',
|
|
96
|
-
connectionProperties: { oa_id: '300086756699856746' },
|
|
97
|
-
hostName: 'gapitzalotrans',
|
|
98
|
-
},
|
|
99
|
-
}],
|
|
100
|
-
})}
|
|
101
|
-
>
|
|
102
|
-
Load domain properties
|
|
103
|
-
</button>
|
|
104
75
|
</div>
|
|
105
76
|
);
|
|
106
77
|
},
|
|
@@ -123,7 +94,7 @@ describe('ChannelSelectionStep', () => {
|
|
|
123
94
|
console.log.mockRestore();
|
|
124
95
|
});
|
|
125
96
|
|
|
126
|
-
it('empty state: shows
|
|
97
|
+
it('empty state: shows content template heading and add-template entry point', () => {
|
|
127
98
|
const onChange = jest.fn();
|
|
128
99
|
renderStep(
|
|
129
100
|
<ChannelSelectionStep
|
|
@@ -133,7 +104,7 @@ describe('ChannelSelectionStep', () => {
|
|
|
133
104
|
/>,
|
|
134
105
|
);
|
|
135
106
|
|
|
136
|
-
expect(screen.getAllByText('
|
|
107
|
+
expect(screen.getAllByText('Content template').length).toBeGreaterThanOrEqual(1);
|
|
137
108
|
expect(screen.getByRole('button', { name: /add creative/i })).toBeInTheDocument();
|
|
138
109
|
expect(screen.queryByTestId('creatives-mock')).not.toBeInTheDocument();
|
|
139
110
|
});
|
|
@@ -1712,149 +1683,6 @@ describe('ChannelSelectionStep', () => {
|
|
|
1712
1683
|
expect(screen.getByTestId('creatives-mock')).toHaveAttribute('data-creatives-mode', 'edit');
|
|
1713
1684
|
});
|
|
1714
1685
|
|
|
1715
|
-
it('edit WEBPUSH item includes `channel: WEBPUSH` (not just `type`) in the unwrapped templateData (regression: CreativesContainer.getTemplateData\'s switch reads templateData.channel, not templateData.type — without it the switch never matched WEBPUSH and the edit screen rendered blank below its header)', async () => {
|
|
1716
|
-
renderStep(
|
|
1717
|
-
<ChannelSelectionStep
|
|
1718
|
-
value={{
|
|
1719
|
-
contentItems: [{
|
|
1720
|
-
contentId: 'wp-edit-channel',
|
|
1721
|
-
channel: 'WEBPUSH',
|
|
1722
|
-
templateData: {
|
|
1723
|
-
channel: 'WEBPUSH',
|
|
1724
|
-
messageContent: {
|
|
1725
|
-
content: { messageSubject: 'dasd', accountId: 13792, content: { title: 'dasd', message: 'dasd' } },
|
|
1726
|
-
},
|
|
1727
|
-
},
|
|
1728
|
-
}],
|
|
1729
|
-
}}
|
|
1730
|
-
onChange={jest.fn()}
|
|
1731
|
-
channels={CHANNELS}
|
|
1732
|
-
/>,
|
|
1733
|
-
);
|
|
1734
|
-
await userEvent.click(screen.getByLabelText('Show more content options icon'));
|
|
1735
|
-
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
1736
|
-
await userEvent.click(within(screen.getByRole('menu')).getByText('Edit'));
|
|
1737
|
-
await waitFor(() => expect(screen.getByTestId('creatives-mock')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
1738
|
-
const passedTemplateData = JSON.parse(screen.getByTestId('creatives-mock').getAttribute('data-template-data'));
|
|
1739
|
-
expect(passedTemplateData.channel).toBe('WEBPUSH');
|
|
1740
|
-
expect(passedTemplateData.type).toBe('WEBPUSH');
|
|
1741
|
-
expect(passedTemplateData.messageSubject).toBe('dasd');
|
|
1742
|
-
expect(passedTemplateData.accountId).toBe(13792);
|
|
1743
|
-
});
|
|
1744
|
-
|
|
1745
|
-
// ── ZALO edit: hostName resolved from domainProperties ────────────────────────
|
|
1746
|
-
|
|
1747
|
-
it('resolves a Zalo item\'s hostName from the domainProperties fetch by matching accountId to connectionProperties.oa_id, and passes it to CreativesContainer (regression: CCS\'s zaloMessageContent never carries hostName, and without it Zalo/index.js\'s getTemplateInfoById guard never passes, so the edit view never loads live template data)', async () => {
|
|
1748
|
-
renderStep(
|
|
1749
|
-
<ChannelSelectionStep
|
|
1750
|
-
value={{
|
|
1751
|
-
contentItems: [{
|
|
1752
|
-
contentId: 'zalo-edit',
|
|
1753
|
-
channel: 'ZALO',
|
|
1754
|
-
templateData: {
|
|
1755
|
-
channel: 'ZALO',
|
|
1756
|
-
accountId: '300086756699856746',
|
|
1757
|
-
accountName: 'gapit_automation_account',
|
|
1758
|
-
token: 'zalo-token',
|
|
1759
|
-
templateConfigs: { id: '630142', name: '1592_Chí Linh_D1' },
|
|
1760
|
-
},
|
|
1761
|
-
}],
|
|
1762
|
-
}}
|
|
1763
|
-
onChange={jest.fn()}
|
|
1764
|
-
channels={CHANNELS}
|
|
1765
|
-
deliverySettingsData={{ required: false }}
|
|
1766
|
-
/>,
|
|
1767
|
-
);
|
|
1768
|
-
await userEvent.click(screen.getByTestId('domain-properties-loaded'));
|
|
1769
|
-
await userEvent.click(screen.getByLabelText('Show more content options icon'));
|
|
1770
|
-
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
1771
|
-
await userEvent.click(within(screen.getByRole('menu')).getByText('Edit'));
|
|
1772
|
-
await waitFor(() => expect(screen.getByTestId('creatives-mock')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
1773
|
-
expect(screen.getByTestId('creatives-mock')).toHaveAttribute('data-host-name', 'gapitzalotrans');
|
|
1774
|
-
});
|
|
1775
|
-
|
|
1776
|
-
it('resolves an empty hostName for a Zalo item when no matching domainProperties account is loaded', async () => {
|
|
1777
|
-
renderStep(
|
|
1778
|
-
<ChannelSelectionStep
|
|
1779
|
-
value={{
|
|
1780
|
-
contentItems: [{
|
|
1781
|
-
contentId: 'zalo-edit-no-match',
|
|
1782
|
-
channel: 'ZALO',
|
|
1783
|
-
templateData: { channel: 'ZALO', accountId: 'unmatched-account-id' },
|
|
1784
|
-
}],
|
|
1785
|
-
}}
|
|
1786
|
-
onChange={jest.fn()}
|
|
1787
|
-
channels={CHANNELS}
|
|
1788
|
-
deliverySettingsData={{ required: false }}
|
|
1789
|
-
/>,
|
|
1790
|
-
);
|
|
1791
|
-
await userEvent.click(screen.getByLabelText('Show more content options icon'));
|
|
1792
|
-
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
1793
|
-
await userEvent.click(within(screen.getByRole('menu')).getByText('Edit'));
|
|
1794
|
-
await waitFor(() => expect(screen.getByTestId('creatives-mock')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
1795
|
-
expect(screen.getByTestId('creatives-mock')).toHaveAttribute('data-host-name', '');
|
|
1796
|
-
});
|
|
1797
|
-
|
|
1798
|
-
// ── Tag-context pass-through (config.context.module) ──────────────────────────
|
|
1799
|
-
|
|
1800
|
-
it('passes config.context.module through to messageDetails.type (lowercased) and location.query.module, unchanged, for tag-fetch scoping (regression: this used to be hardcoded to messageDetails={{type: \'default\'}} with no location prop at all, so every consumer\'s tag-fetch was scoped generically instead of per-consumer)', async () => {
|
|
1801
|
-
renderStep(
|
|
1802
|
-
<ChannelSelectionStep
|
|
1803
|
-
value={{ contentItems: [] }}
|
|
1804
|
-
onChange={jest.fn()}
|
|
1805
|
-
channels={CHANNELS}
|
|
1806
|
-
config={{ context: { module: 'CAMPAIGNS' } }}
|
|
1807
|
-
/>,
|
|
1808
|
-
);
|
|
1809
|
-
await userEvent.click(screen.getByRole('button', { name: /add creative/i }));
|
|
1810
|
-
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
1811
|
-
await userEvent.click(within(screen.getByRole('menu')).getByText('SMS'));
|
|
1812
|
-
await waitFor(() => expect(screen.getByTestId('creatives-mock')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
1813
|
-
|
|
1814
|
-
const mock = screen.getByTestId('creatives-mock');
|
|
1815
|
-
expect(JSON.parse(mock.getAttribute('data-message-details'))).toEqual({ type: 'campaigns' });
|
|
1816
|
-
expect(JSON.parse(mock.getAttribute('data-location'))).toEqual({
|
|
1817
|
-
query: { type: 'embedded', module: 'CAMPAIGNS' },
|
|
1818
|
-
});
|
|
1819
|
-
});
|
|
1820
|
-
|
|
1821
|
-
it('passes through whatever module value a coupons/cartPromotions-style config sets, with no special-casing on our end', async () => {
|
|
1822
|
-
renderStep(
|
|
1823
|
-
<ChannelSelectionStep
|
|
1824
|
-
value={{ contentItems: [] }}
|
|
1825
|
-
onChange={jest.fn()}
|
|
1826
|
-
channels={CHANNELS}
|
|
1827
|
-
config={{ context: { module: 'coupons' } }}
|
|
1828
|
-
/>,
|
|
1829
|
-
);
|
|
1830
|
-
await userEvent.click(screen.getByRole('button', { name: /add creative/i }));
|
|
1831
|
-
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
1832
|
-
await userEvent.click(within(screen.getByRole('menu')).getByText('SMS'));
|
|
1833
|
-
await waitFor(() => expect(screen.getByTestId('creatives-mock')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
1834
|
-
|
|
1835
|
-
const mock = screen.getByTestId('creatives-mock');
|
|
1836
|
-
expect(JSON.parse(mock.getAttribute('data-message-details'))).toEqual({ type: 'coupons' });
|
|
1837
|
-
expect(JSON.parse(mock.getAttribute('data-location'))).toEqual({
|
|
1838
|
-
query: { type: 'embedded', module: 'coupons' },
|
|
1839
|
-
});
|
|
1840
|
-
});
|
|
1841
|
-
|
|
1842
|
-
it('falls back to messageDetails={{type: "default"}} when config.context.module is absent (unset consumers keep prior behavior)', async () => {
|
|
1843
|
-
renderStep(
|
|
1844
|
-
<ChannelSelectionStep
|
|
1845
|
-
value={{ contentItems: [] }}
|
|
1846
|
-
onChange={jest.fn()}
|
|
1847
|
-
channels={CHANNELS}
|
|
1848
|
-
/>,
|
|
1849
|
-
);
|
|
1850
|
-
await userEvent.click(screen.getByRole('button', { name: /add creative/i }));
|
|
1851
|
-
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
1852
|
-
await userEvent.click(within(screen.getByRole('menu')).getByText('SMS'));
|
|
1853
|
-
await waitFor(() => expect(screen.getByTestId('creatives-mock')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
1854
|
-
|
|
1855
|
-
expect(JSON.parse(screen.getByTestId('creatives-mock').getAttribute('data-message-details'))).toEqual({ type: 'default' });
|
|
1856
|
-
});
|
|
1857
|
-
|
|
1858
1686
|
// ── FTP channel filtered from dropdown ───────────────────────────────────────
|
|
1859
1687
|
|
|
1860
1688
|
it('FTP channel is filtered out of the channel dropdown', async () => {
|
package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.js
CHANGED
|
@@ -33,7 +33,6 @@ const DeliverySettingsSection = ({
|
|
|
33
33
|
deliverySettingsData,
|
|
34
34
|
deliverySetting = {},
|
|
35
35
|
onDeliverySettingChange,
|
|
36
|
-
onDomainPropertiesLoaded,
|
|
37
36
|
intl,
|
|
38
37
|
}) => {
|
|
39
38
|
const [showSlidebox, setShowSlidebox] = useState(false);
|
|
@@ -103,7 +102,6 @@ const DeliverySettingsSection = ({
|
|
|
103
102
|
)
|
|
104
103
|
: raw;
|
|
105
104
|
setDomainPropertiesData(entity);
|
|
106
|
-
onDomainPropertiesLoaded?.(entity);
|
|
107
105
|
}
|
|
108
106
|
} catch (err) {
|
|
109
107
|
if (!cancelled) setDomainPropertiesData(null);
|
|
@@ -318,7 +316,6 @@ DeliverySettingsSection.propTypes = {
|
|
|
318
316
|
deliverySettingsData: PropTypes.object,
|
|
319
317
|
deliverySetting: PropTypes.object,
|
|
320
318
|
onDeliverySettingChange: PropTypes.func,
|
|
321
|
-
onDomainPropertiesLoaded: PropTypes.func,
|
|
322
319
|
intl: PropTypes.object.isRequired,
|
|
323
320
|
};
|
|
324
321
|
|
|
@@ -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();
|