@capillarytech/creatives-library 8.0.329 → 8.0.330-alpha.1
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 -0
- package/package.json +1 -1
- package/utils/commonUtils.js +19 -1
- package/utils/templateVarUtils.js +35 -6
- package/utils/tests/tagValidations.test.js +20 -0
- package/utils/tests/templateVarUtils.test.js +44 -0
- package/v2Components/CapActionButton/constants.js +7 -0
- package/v2Components/CapActionButton/index.js +167 -109
- package/v2Components/CapActionButton/index.scss +157 -6
- package/v2Components/CapActionButton/messages.js +19 -3
- package/v2Components/CapActionButton/tests/index.test.js +41 -17
- package/v2Components/CapTagList/index.js +28 -23
- package/v2Components/CapTagList/style.scss +29 -0
- package/v2Components/CapTagListWithInput/__tests__/CapTagListWithInput.test.js +63 -0
- package/v2Components/CapTagListWithInput/index.js +4 -0
- package/v2Components/CapWhatsappCTA/index.js +2 -0
- package/v2Components/CommonTestAndPreview/ExistingCustomerModal.js +1 -0
- package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +160 -15
- package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js.rej +18 -0
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +323 -77
- package/v2Components/CommonTestAndPreview/index.js +49 -57
- package/v2Components/CommonTestAndPreview/messages.js +8 -0
- package/v2Components/CommonTestAndPreview/reducer.js +3 -1
- package/v2Components/CommonTestAndPreview/sagas.js +2 -1
- package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +8 -1
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +281 -283
- package/v2Components/FormBuilder/index.js +1 -0
- package/v2Components/HtmlEditor/HTMLEditor.js +6 -1
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +927 -2
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +3 -0
- package/v2Components/SmsFallback/smsFallbackUtils.js +14 -3
- package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +16 -0
- package/v2Components/TemplatePreview/_templatePreview.scss +33 -23
- package/v2Components/TemplatePreview/constants.js +2 -0
- package/v2Components/TemplatePreview/index.js +143 -28
- package/v2Components/TemplatePreview/tests/index.test.js +142 -0
- package/v2Components/TestAndPreviewSlidebox/index.js +5 -0
- package/v2Components/mockdata.js +1 -0
- package/v2Containers/BeeEditor/index.js +19 -1
- package/v2Containers/CreativesContainer/SlideBoxContent.js +28 -1
- package/v2Containers/CreativesContainer/index.js +9 -3
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +5 -0
- package/v2Containers/Email/index.js +78 -39
- package/v2Containers/Email/reducer.js +2 -2
- package/v2Containers/Email/sagas.js +3 -1
- package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +2 -2
- package/v2Containers/Email/tests/sagas.test.js +230 -0
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +6 -1
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +3 -0
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +20 -2
- package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +16 -1
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +3 -1
- package/v2Containers/EmailWrapper/index.js +4 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +1 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +9 -0
- package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +1 -0
- package/v2Containers/MobilePush/Create/index.js +2 -0
- package/v2Containers/MobilePush/Edit/index.js +2 -0
- package/v2Containers/MobilepushWrapper/index.js +3 -1
- package/v2Containers/Rcs/constants.js +85 -7
- package/v2Containers/Rcs/index.js +1592 -156
- package/v2Containers/Rcs/index.js.rej +1336 -0
- package/v2Containers/Rcs/index.scss +191 -0
- package/v2Containers/Rcs/index.scss.rej +74 -0
- package/v2Containers/Rcs/messages.js +28 -2
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +20 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +69178 -117691
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap.rej +128 -0
- package/v2Containers/Rcs/tests/index.test.js +132 -94
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +67 -0
- package/v2Containers/Rcs/tests/utils.test.js +276 -38
- package/v2Containers/Rcs/utils.js +130 -7
- package/v2Containers/Sms/Edit/index.js +2 -0
- package/v2Containers/SmsTrai/Edit/index.js +27 -0
- package/v2Containers/SmsTrai/Edit/messages.js +5 -0
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +6 -6
- package/v2Containers/SmsWrapper/index.js +2 -0
- package/v2Containers/TagList/index.js +73 -20
- package/v2Containers/TagList/messages.js +4 -0
- package/v2Containers/TagList/tests/TagList.test.js +124 -20
- package/v2Containers/TagList/tests/mockdata.js +17 -0
- package/v2Containers/Templates/_templates.scss +99 -0
- package/v2Containers/Templates/index.js +29 -14
- package/v2Containers/Viber/index.js +3 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.js +0 -2
- package/v2Containers/WebPush/Create/index.js +10 -2
- package/v2Containers/Whatsapp/index.js +5 -0
- package/v2Containers/Zalo/index.js +2 -0
|
@@ -1102,6 +1102,33 @@ export const SmsTraiEdit = (props) => {
|
|
|
1102
1102
|
</CapLabelInline>
|
|
1103
1103
|
</TraiEditTemplateDetails>
|
|
1104
1104
|
)}
|
|
1105
|
+
{isRcsSmsFallback &&
|
|
1106
|
+
traiDataRef.current &&
|
|
1107
|
+
!isEmpty(traiDataRef.current) &&
|
|
1108
|
+
!loading && (
|
|
1109
|
+
<TraiEditTemplateDetails className="sms-trai-edit-rcs-fallback__template-meta">
|
|
1110
|
+
<CapLabelInline type="label1">
|
|
1111
|
+
{formatMessage(messages.templateNameLabel)}
|
|
1112
|
+
</CapLabelInline>
|
|
1113
|
+
<CapLabelInline type="label2">
|
|
1114
|
+
{get(traiDataRef.current, 'versions.base.template_name', '')
|
|
1115
|
+
|| get(traiDataRef.current, 'name', '')}
|
|
1116
|
+
</CapLabelInline>
|
|
1117
|
+
{traiDltEnabled ? (
|
|
1118
|
+
<>
|
|
1119
|
+
<CapLabelInline type="label1">
|
|
1120
|
+
{formatMessage(messages.traiEditSeperator)}
|
|
1121
|
+
</CapLabelInline>
|
|
1122
|
+
<CapLabelInline type="label1">
|
|
1123
|
+
{formatMessage(messages.senderIdlabel)}
|
|
1124
|
+
</CapLabelInline>
|
|
1125
|
+
<CapLabelInline type="label2">
|
|
1126
|
+
{[...get(traiDataRef.current, 'versions.base.header', [])].join(', ')}
|
|
1127
|
+
</CapLabelInline>
|
|
1128
|
+
</>
|
|
1129
|
+
) : null}
|
|
1130
|
+
</TraiEditTemplateDetails>
|
|
1131
|
+
)}
|
|
1105
1132
|
<CapColumn span={shouldShowPreview ? 14 : 24}>
|
|
1106
1133
|
<CapRow>
|
|
1107
1134
|
<CapHeader
|
|
@@ -48,6 +48,11 @@ export default defineMessages({
|
|
|
48
48
|
id: `${prefix}.templateLabel`,
|
|
49
49
|
defaultMessage: 'Template',
|
|
50
50
|
},
|
|
51
|
+
/** RCS → SMS fallback slidebox: label above selected template metadata. */
|
|
52
|
+
templateNameLabel: {
|
|
53
|
+
id: `${prefix}.templateNameLabel`,
|
|
54
|
+
defaultMessage: 'Template name',
|
|
55
|
+
},
|
|
51
56
|
traiEditSeperator: {
|
|
52
57
|
id: `${prefix}.traiEditSeperator`,
|
|
53
58
|
defaultMessage: '|',
|
|
@@ -3292,7 +3292,7 @@ FREE GIFTS-
|
|
|
3292
3292
|
</div>
|
|
3293
3293
|
</Edit__TraiEditTemplateDetails>
|
|
3294
3294
|
<CapColumn
|
|
3295
|
-
key=".
|
|
3295
|
+
key=".2"
|
|
3296
3296
|
span={14}
|
|
3297
3297
|
>
|
|
3298
3298
|
<Col
|
|
@@ -4552,7 +4552,7 @@ FREE GIFTS-
|
|
|
4552
4552
|
</Col>
|
|
4553
4553
|
</CapColumn>
|
|
4554
4554
|
<CapColumn
|
|
4555
|
-
key=".
|
|
4555
|
+
key=".3"
|
|
4556
4556
|
offset={1}
|
|
4557
4557
|
span={8}
|
|
4558
4558
|
>
|
|
@@ -14962,7 +14962,7 @@ FREE GIFTS-
|
|
|
14962
14962
|
</div>
|
|
14963
14963
|
</Edit__TraiEditTemplateDetails>
|
|
14964
14964
|
<CapColumn
|
|
14965
|
-
key=".
|
|
14965
|
+
key=".2"
|
|
14966
14966
|
span={14}
|
|
14967
14967
|
>
|
|
14968
14968
|
<Col
|
|
@@ -16222,7 +16222,7 @@ FREE GIFTS-
|
|
|
16222
16222
|
</Col>
|
|
16223
16223
|
</CapColumn>
|
|
16224
16224
|
<CapColumn
|
|
16225
|
-
key=".
|
|
16225
|
+
key=".3"
|
|
16226
16226
|
offset={1}
|
|
16227
16227
|
span={8}
|
|
16228
16228
|
>
|
|
@@ -26632,7 +26632,7 @@ FREE GIFTS-
|
|
|
26632
26632
|
</div>
|
|
26633
26633
|
</Edit__TraiEditTemplateDetails>
|
|
26634
26634
|
<CapColumn
|
|
26635
|
-
key=".
|
|
26635
|
+
key=".2"
|
|
26636
26636
|
span={14}
|
|
26637
26637
|
>
|
|
26638
26638
|
<Col
|
|
@@ -27892,7 +27892,7 @@ FREE GIFTS-
|
|
|
27892
27892
|
</Col>
|
|
27893
27893
|
</CapColumn>
|
|
27894
27894
|
<CapColumn
|
|
27895
|
-
key=".
|
|
27895
|
+
key=".3"
|
|
27896
27896
|
offset={1}
|
|
27897
27897
|
span={8}
|
|
27898
27898
|
>
|
|
@@ -32,6 +32,7 @@ const SmsWrapper = (props) => {
|
|
|
32
32
|
smsRegister,
|
|
33
33
|
onShowTemplates,
|
|
34
34
|
eventContextTags,
|
|
35
|
+
waitEventContextTags,
|
|
35
36
|
showLiquidErrorInFooter,
|
|
36
37
|
getLiquidTags,
|
|
37
38
|
showTestAndPreviewSlidebox,
|
|
@@ -73,6 +74,7 @@ const SmsWrapper = (props) => {
|
|
|
73
74
|
onPreviewContentClicked,
|
|
74
75
|
onTestContentClicked,
|
|
75
76
|
eventContextTags,
|
|
77
|
+
waitEventContextTags,
|
|
76
78
|
showLiquidErrorInFooter,
|
|
77
79
|
getLiquidTags,
|
|
78
80
|
showTestAndPreviewSlidebox,
|
|
@@ -22,7 +22,7 @@ import messages, { scope } from './messages';
|
|
|
22
22
|
// import styled from styled-components;
|
|
23
23
|
import CapTagList from '../../v2Components/CapTagList';
|
|
24
24
|
import './_tagList.scss';
|
|
25
|
-
import { selectCurrentOrgDetails, makeSelectFetchingSchemaError } from '../Cap/selectors';
|
|
25
|
+
import { selectCurrentOrgDetails, makeSelectFetchingSchemaError, makeSelectFetchingSchema } from '../Cap/selectors';
|
|
26
26
|
import {
|
|
27
27
|
handleInjectedData, hasGiftVoucherFeature, hasPromoFeature, hasBadgesFeature, transformBadgeTags,
|
|
28
28
|
} from '../../utils/common';
|
|
@@ -35,12 +35,14 @@ const {TreeNode} = Tree;
|
|
|
35
35
|
export class TagList extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
|
36
36
|
constructor(props) {
|
|
37
37
|
super(props);
|
|
38
|
+
const { tags, injectedTags } = props;
|
|
39
|
+
const hasInitialData = (tags && tags.length > 0) || !_.isEmpty(injectedTags);
|
|
38
40
|
this.state = {
|
|
39
41
|
loading: false,
|
|
40
42
|
tags: [],
|
|
41
43
|
tagsError: false,
|
|
42
44
|
currentContext: null, // Track current context to detect changes
|
|
43
|
-
hasTriggeredInitialApiCall:
|
|
45
|
+
hasTriggeredInitialApiCall: hasInitialData, // Seed from initial props to avoid duplicate fetch on popover open
|
|
44
46
|
};
|
|
45
47
|
this.renderTags = this.renderTags.bind(this);
|
|
46
48
|
this.populateTags = this.populateTags.bind(this);
|
|
@@ -52,14 +54,8 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
|
|
|
52
54
|
|
|
53
55
|
componentDidMount() {
|
|
54
56
|
this.generateTags(this.props);
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
const hasNoTags = (!tags || tags.length === 0) && _.isEmpty(injectedTags);
|
|
58
|
-
if (hasNoTags && onContextChange) {
|
|
59
|
-
// Trigger API call with default 'Outbound' context to match CapTagList default
|
|
60
|
-
// This ensures tags are loaded when component mounts
|
|
61
|
-
this.getTagsforContext('Outbound');
|
|
62
|
-
}
|
|
57
|
+
// Initial schema fetch is the parent's responsibility (useTagManagement hook handles it)
|
|
58
|
+
// This avoids duplicate requests when both parent and child try to fetch on mount
|
|
63
59
|
}
|
|
64
60
|
|
|
65
61
|
componentWillReceiveProps(nextProps) {
|
|
@@ -85,9 +81,10 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
|
|
|
85
81
|
if (!_.isEqual(nextTags, currentTags)) {
|
|
86
82
|
this.setState({loading: false});
|
|
87
83
|
this.clearLoadingTimeout();
|
|
88
|
-
//
|
|
84
|
+
// Tags received (from prefetch or button-click API call) — mark as triggered
|
|
85
|
+
// so handlePopoverVisibilityChange won't fire a duplicate call on popover open
|
|
89
86
|
if (nextTags && nextTags.length > 0) {
|
|
90
|
-
this.setState({ hasTriggeredInitialApiCall:
|
|
87
|
+
this.setState({ hasTriggeredInitialApiCall: true });
|
|
91
88
|
}
|
|
92
89
|
}
|
|
93
90
|
if (fetchingSchemaError) {
|
|
@@ -97,10 +94,28 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
|
|
|
97
94
|
}
|
|
98
95
|
|
|
99
96
|
componentDidUpdate(prevProps) {
|
|
100
|
-
const {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
97
|
+
const {
|
|
98
|
+
tags,
|
|
99
|
+
injectedTags,
|
|
100
|
+
selectedOfferDetails,
|
|
101
|
+
eventContextTags,
|
|
102
|
+
waitEventContextTags,
|
|
103
|
+
} = this.props;
|
|
104
|
+
const {
|
|
105
|
+
tags: prevTags,
|
|
106
|
+
injectedTags: prevInjectedTags,
|
|
107
|
+
selectedOfferDetails: prevSelectedOfferDetails,
|
|
108
|
+
eventContextTags: prevEventContextTags,
|
|
109
|
+
waitEventContextTags: prevWaitEventContextTags,
|
|
110
|
+
} = prevProps;
|
|
111
|
+
|
|
112
|
+
if (
|
|
113
|
+
tags !== prevTags
|
|
114
|
+
|| injectedTags !== prevInjectedTags
|
|
115
|
+
|| selectedOfferDetails !== prevSelectedOfferDetails
|
|
116
|
+
|| !_.isEqual(eventContextTags, prevEventContextTags)
|
|
117
|
+
|| !_.isEqual(waitEventContextTags, prevWaitEventContextTags)
|
|
118
|
+
) {
|
|
104
119
|
this.generateTags(this.props);
|
|
105
120
|
}
|
|
106
121
|
}
|
|
@@ -155,9 +170,7 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
|
|
|
155
170
|
if ((hasNoTags || hasNoStateTags || hasNotTriggeredApiCall)) {
|
|
156
171
|
// Mark that we've triggered the API call
|
|
157
172
|
this.setState({ hasTriggeredInitialApiCall: true });
|
|
158
|
-
|
|
159
|
-
// This will call onContextChange which triggers handleOnTagsContextChange in InApp
|
|
160
|
-
this.getTagsforContext('Outbound');
|
|
173
|
+
this.getTagsforContext('Outbound'); // Default to Outbound context
|
|
161
174
|
}
|
|
162
175
|
}
|
|
163
176
|
};
|
|
@@ -167,7 +180,7 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
|
|
|
167
180
|
let injectedTags = {};
|
|
168
181
|
const eventContextTagsObj = {};
|
|
169
182
|
|
|
170
|
-
const {selectedOfferDetails, eventContextTags } = props;
|
|
183
|
+
const {selectedOfferDetails, eventContextTags, waitEventContextTags } = props;
|
|
171
184
|
if (props.injectedTags && !_.isEmpty(props.injectedTags)) {
|
|
172
185
|
const formattedInjectedTags = handleInjectedData(
|
|
173
186
|
props.injectedTags,
|
|
@@ -219,6 +232,43 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
|
|
|
219
232
|
};
|
|
220
233
|
});
|
|
221
234
|
}
|
|
235
|
+
// Wait event context tags should be displayed in the Add Labels when node is next to Event based wait node.
|
|
236
|
+
if (waitEventContextTags && Object.keys(waitEventContextTags)?.length) {
|
|
237
|
+
|
|
238
|
+
Object.keys(waitEventContextTags).forEach((blockId) => {
|
|
239
|
+
const WAIT_EVENT_HEADER_MSG_LABEL = `${waitEventContextTags[blockId].eventName} (${waitEventContextTags[blockId].blockName})`;
|
|
240
|
+
eventContextTagsObj[blockId] = {
|
|
241
|
+
"name": WAIT_EVENT_HEADER_MSG_LABEL,
|
|
242
|
+
"desc": WAIT_EVENT_HEADER_MSG_LABEL,
|
|
243
|
+
"resolved": true,
|
|
244
|
+
'tag-header': true,
|
|
245
|
+
"subtags": {},
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
waitEventContextTags?.[blockId]?.tags?.forEach((tag) => {
|
|
249
|
+
const {
|
|
250
|
+
tagName, label, profileId, profileName, blockName, eventName
|
|
251
|
+
} = tag || {};
|
|
252
|
+
if (!profileId || !tagName || !label || !profileName) return;
|
|
253
|
+
// Initializing the tags profile if it doesn't exist
|
|
254
|
+
if (!eventContextTagsObj?.[blockId]?.subtags?.[profileId]) {
|
|
255
|
+
eventContextTagsObj[blockId].subtags[profileId] = {
|
|
256
|
+
"name": profileName,
|
|
257
|
+
"desc": profileName,
|
|
258
|
+
"resolved": true,
|
|
259
|
+
'tag-header': true,
|
|
260
|
+
"subtags": {},
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
// Adding the current tag to the profile group
|
|
264
|
+
eventContextTagsObj[blockId].subtags[profileId].subtags[tagName] = {
|
|
265
|
+
name: label,
|
|
266
|
+
desc: label,
|
|
267
|
+
resolved: true,
|
|
268
|
+
};
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
}
|
|
222
272
|
this.setState({tags: _.merge( {}, tags, injectedTags, eventContextTagsObj )});
|
|
223
273
|
}
|
|
224
274
|
|
|
@@ -440,6 +490,7 @@ TagList.defaultProps = {
|
|
|
440
490
|
isNewVersionFlow: false,
|
|
441
491
|
userLocale: 'en',
|
|
442
492
|
eventContextTags: [],
|
|
493
|
+
waitEventContextTags: {},
|
|
443
494
|
};
|
|
444
495
|
|
|
445
496
|
TagList.propTypes = {
|
|
@@ -460,6 +511,7 @@ TagList.propTypes = {
|
|
|
460
511
|
disabled: PropTypes.bool,
|
|
461
512
|
fetchingSchemaError: PropTypes.bool,
|
|
462
513
|
eventContextTags: PropTypes.array,
|
|
514
|
+
waitEventContextTags: PropTypes.object,
|
|
463
515
|
popoverPlacement: PropTypes.string,
|
|
464
516
|
// message to show when Add Label button is disabled (e.g. personalization restriction)
|
|
465
517
|
disableTooltipMsg: PropTypes.string,
|
|
@@ -477,6 +529,7 @@ const mapStateToProps = createStructuredSelector({
|
|
|
477
529
|
TagList: makeSelectTagList(),
|
|
478
530
|
currentOrgDetails: selectCurrentOrgDetails(),
|
|
479
531
|
fetchingSchemaError: makeSelectFetchingSchemaError(),
|
|
532
|
+
fetchingSchema: makeSelectFetchingSchema(),
|
|
480
533
|
});
|
|
481
534
|
|
|
482
535
|
function mapDispatchToProps(dispatch) {
|
|
@@ -19,4 +19,8 @@ export default defineMessages({
|
|
|
19
19
|
id: `${scope}.personalizationNotSupportedAnonymous`,
|
|
20
20
|
defaultMessage: 'Personalization tags are not supported for anonymous customers',
|
|
21
21
|
},
|
|
22
|
+
waitEvent: {
|
|
23
|
+
id: `${scope}.waitEvent`,
|
|
24
|
+
defaultMessage: 'Wait Event',
|
|
25
|
+
},
|
|
22
26
|
});
|
|
@@ -5,28 +5,34 @@ import { initialReducer } from '../../../initialReducer';
|
|
|
5
5
|
import { injectIntl } from "react-intl";
|
|
6
6
|
import { fireEvent } from "@testing-library/react";
|
|
7
7
|
import { TagList } from '../index';
|
|
8
|
-
import { TagListData, eventContextTags } from './mockdata';
|
|
8
|
+
import { TagListData, eventContextTags, waitEventContextTags } from './mockdata';
|
|
9
|
+
import { OfferTag, badgesTags, offer } from '../../../utils/tests/common.mockdata';
|
|
10
|
+
import * as commonUtils from "../../../utils/common";
|
|
9
11
|
import { Provider } from 'react-redux';
|
|
10
12
|
import { screen, render } from '../../../utils/test-utils';
|
|
11
13
|
import history from '../../../utils/history';
|
|
12
14
|
const { getByText, queryByText } = screen;
|
|
13
15
|
|
|
16
|
+
const buildProps = (props = {}) => ({
|
|
17
|
+
...TagListData,
|
|
18
|
+
onTagSelect: jest.fn(),
|
|
19
|
+
...props,
|
|
20
|
+
});
|
|
14
21
|
|
|
15
|
-
const initializeTagList = (props) => {
|
|
22
|
+
const initializeTagList = (props = {}) => {
|
|
16
23
|
const store = configureStore({}, initialReducer, history);
|
|
17
24
|
const Component = injectIntl(TagList);
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
...
|
|
21
|
-
|
|
22
|
-
|
|
25
|
+
const propsObj = buildProps(props);
|
|
26
|
+
return {
|
|
27
|
+
...render(
|
|
28
|
+
<Provider store={store}>
|
|
29
|
+
<Component {...propsObj} />
|
|
30
|
+
</Provider>
|
|
31
|
+
),
|
|
32
|
+
store,
|
|
33
|
+
Component,
|
|
34
|
+
propsObj,
|
|
23
35
|
};
|
|
24
|
-
|
|
25
|
-
return render(
|
|
26
|
-
<Provider store={store}>
|
|
27
|
-
<Component {...propsObj} />
|
|
28
|
-
</Provider>
|
|
29
|
-
);
|
|
30
36
|
};
|
|
31
37
|
|
|
32
38
|
const addLabelBtnAssertion = () => {
|
|
@@ -41,19 +47,117 @@ describe("TagList test : UNIT", () => {
|
|
|
41
47
|
addLabelBtnAssertion();
|
|
42
48
|
});
|
|
43
49
|
|
|
44
|
-
it('should render event context
|
|
45
|
-
initializeTagList({eventContextTags});
|
|
50
|
+
it('should render event context tag section from generateTags', () => {
|
|
51
|
+
initializeTagList({ eventContextTags, moduleFilterEnabled: false });
|
|
46
52
|
addLabelBtnAssertion();
|
|
47
53
|
const EVENT_CONTEXT_TAG_HEADER = getByText(/Entry event/i);
|
|
48
54
|
expect(EVENT_CONTEXT_TAG_HEADER).toBeInTheDocument();
|
|
49
|
-
fireEvent.click(EVENT_CONTEXT_TAG_HEADER);
|
|
50
|
-
// Customer profile tags
|
|
51
|
-
const CUSTOMER_PROFILE = getByText(/Current Customer/i);
|
|
52
|
-
fireEvent.click(CUSTOMER_PROFILE);
|
|
53
|
-
expect(getByText(/lifetimePurchases/i)).toBeInTheDocument();
|
|
54
55
|
|
|
55
56
|
// Behavioural event profile tags should not be visible as label and profile name is not present
|
|
56
57
|
const BEHAVIOURAL_EVENT_PROFILE = queryByText(/Behavioural event/i);
|
|
57
58
|
expect(BEHAVIOURAL_EVENT_PROFILE).not.toBeInTheDocument();
|
|
58
59
|
});
|
|
60
|
+
|
|
61
|
+
it('should render wait event context section when waitEventContextTags is provided', () => {
|
|
62
|
+
initializeTagList({ waitEventContextTags, moduleFilterEnabled: false });
|
|
63
|
+
addLabelBtnAssertion();
|
|
64
|
+
const WAIT_EVENT_HEADER = getByText(/Order Placed \(Wait Block\)/i);
|
|
65
|
+
expect(WAIT_EVENT_HEADER).toBeInTheDocument();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should merge empty waitEventContextTags with entry event tags', () => {
|
|
69
|
+
initializeTagList({ eventContextTags, waitEventContextTags: {}, moduleFilterEnabled: false });
|
|
70
|
+
addLabelBtnAssertion();
|
|
71
|
+
expect(getByText(/Entry event/i)).toBeInTheDocument();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('calls parent onContextChange with Outbound when tags and injectedTags are empty on popover open', () => {
|
|
75
|
+
const onContextChange = jest.fn();
|
|
76
|
+
initializeTagList({
|
|
77
|
+
tags: [],
|
|
78
|
+
injectedTags: {},
|
|
79
|
+
onContextChange,
|
|
80
|
+
onTagSelect: jest.fn(),
|
|
81
|
+
});
|
|
82
|
+
// Default fetch is triggered when the Add Label popover opens (not on mount)
|
|
83
|
+
addLabelBtnAssertion();
|
|
84
|
+
expect(onContextChange).toHaveBeenCalledWith('Outbound');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('applies fetchingSchemaError from props via componentWillReceiveProps', () => {
|
|
88
|
+
const { rerender, Component, propsObj, store } = initializeTagList({ fetchingSchemaError: false });
|
|
89
|
+
addLabelBtnAssertion();
|
|
90
|
+
rerender(
|
|
91
|
+
<Provider store={store}>
|
|
92
|
+
<Component {...propsObj} fetchingSchemaError />
|
|
93
|
+
</Provider>
|
|
94
|
+
);
|
|
95
|
+
expect(screen.getByText(/add label/i)).toBeInTheDocument();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('disables Add label when restrictPersonalization is true', () => {
|
|
99
|
+
initializeTagList({
|
|
100
|
+
restrictPersonalization: true,
|
|
101
|
+
disabled: false,
|
|
102
|
+
moduleFilterEnabled: false,
|
|
103
|
+
});
|
|
104
|
+
const btn = screen.getByText(/add label/i).closest('button');
|
|
105
|
+
expect(btn).toBeDisabled();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('calls transformCouponTags when selectedOfferDetails and coupon tags are present', () => {
|
|
109
|
+
const spy = jest.spyOn(TagList.prototype, 'transformCouponTags');
|
|
110
|
+
initializeTagList({
|
|
111
|
+
tags: OfferTag,
|
|
112
|
+
injectedTags: {},
|
|
113
|
+
selectedOfferDetails: [{ id: 'c1', couponName: 'Promo Coupon', couponSeriesId: 'c1' }],
|
|
114
|
+
moduleFilterEnabled: false,
|
|
115
|
+
});
|
|
116
|
+
expect(spy).toHaveBeenCalled();
|
|
117
|
+
spy.mockRestore();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('calls transformBadgeTags from common when badge offer and Badge tags are present', () => {
|
|
121
|
+
const spy = jest.spyOn(commonUtils, 'transformBadgeTags');
|
|
122
|
+
initializeTagList({
|
|
123
|
+
tags: badgesTags,
|
|
124
|
+
injectedTags: {},
|
|
125
|
+
selectedOfferDetails: offer,
|
|
126
|
+
moduleFilterEnabled: false,
|
|
127
|
+
});
|
|
128
|
+
expect(spy).toHaveBeenCalled();
|
|
129
|
+
spy.mockRestore();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('unmounts without throwing', () => {
|
|
133
|
+
const { unmount } = initializeTagList();
|
|
134
|
+
expect(() => unmount()).not.toThrow();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('regenerates tags when props.tags change (componentDidUpdate)', () => {
|
|
138
|
+
const { rerender, Component, store } = initializeTagList({ tags: TagListData.tags });
|
|
139
|
+
const extra = [
|
|
140
|
+
...TagListData.tags,
|
|
141
|
+
{
|
|
142
|
+
_id: 'extra-tag',
|
|
143
|
+
type: 'TAG',
|
|
144
|
+
definition: {
|
|
145
|
+
label: { en: 'Extra' },
|
|
146
|
+
value: 'extra_value',
|
|
147
|
+
subtags: [],
|
|
148
|
+
'tag-header': false,
|
|
149
|
+
supportedModules: [{ context: 'default', layout: 'sms', mandatory: false }],
|
|
150
|
+
},
|
|
151
|
+
scope: { tag: 'STANDARD', orgId: -1, verticals: [] },
|
|
152
|
+
isActive: true,
|
|
153
|
+
},
|
|
154
|
+
];
|
|
155
|
+
rerender(
|
|
156
|
+
<Provider store={store}>
|
|
157
|
+
<Component {...buildProps({ tags: extra })} />
|
|
158
|
+
</Provider>
|
|
159
|
+
);
|
|
160
|
+
addLabelBtnAssertion();
|
|
161
|
+
expect(screen.getByText(/add label/i)).toBeInTheDocument();
|
|
162
|
+
});
|
|
59
163
|
});
|
|
@@ -149,3 +149,20 @@ export const eventContextTags = [
|
|
|
149
149
|
"isDynamicFact": false
|
|
150
150
|
}
|
|
151
151
|
];
|
|
152
|
+
|
|
153
|
+
export const waitEventContextTags = {
|
|
154
|
+
block1: {
|
|
155
|
+
eventName: 'Order Placed',
|
|
156
|
+
blockName: 'Wait Block',
|
|
157
|
+
tags: [
|
|
158
|
+
{
|
|
159
|
+
tagName: 'waitEvent.orderId',
|
|
160
|
+
label: 'Order ID',
|
|
161
|
+
profileId: 'ORDER_PROFILE',
|
|
162
|
+
profileName: 'Order Profile',
|
|
163
|
+
blockName: 'Wait Block',
|
|
164
|
+
eventName: 'Order Placed',
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
},
|
|
168
|
+
};
|
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
.ant-tabs-content{
|
|
4
4
|
margin-top: 16px;
|
|
5
|
+
// .creatives-templates-list.full-mode{
|
|
6
|
+
.v2-pagination-container, .v2-pagination-container-half {
|
|
5
7
|
.ant-tabs-tabpane-active{
|
|
6
8
|
padding: unset;
|
|
7
9
|
}
|
|
8
10
|
}
|
|
11
|
+
}
|
|
9
12
|
|
|
10
13
|
@media screen and (max-width: 1172px) {
|
|
11
14
|
.creatives-templates-list.full-mode{
|
|
@@ -20,8 +23,11 @@
|
|
|
20
23
|
}
|
|
21
24
|
}
|
|
22
25
|
}
|
|
26
|
+
// }
|
|
23
27
|
|
|
24
28
|
@media screen and (min-width: 1172px) {
|
|
29
|
+
.creatives-templates-list.full-mode{
|
|
30
|
+
.v2-pagination-container, .v2-pagination-container-half {
|
|
25
31
|
.creatives-templates-list.full-mode{
|
|
26
32
|
.v2-pagination-container {
|
|
27
33
|
.cap-custom-card-list-row {
|
|
@@ -33,16 +39,21 @@
|
|
|
33
39
|
}
|
|
34
40
|
}
|
|
35
41
|
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
36
44
|
}
|
|
37
45
|
|
|
46
|
+
|
|
38
47
|
.creatives-templates-list {
|
|
39
48
|
|
|
40
49
|
.delete-template-confirm {
|
|
41
50
|
.ant-modal-footer {
|
|
42
51
|
padding: $CAP_SPACE_16 $CAP_SPACE_24 $CAP_SPACE_24 $CAP_SPACE_24;
|
|
43
52
|
}
|
|
53
|
+
}
|
|
44
54
|
|
|
45
55
|
.ant-modal-header {
|
|
56
|
+
.v2-pagination-container, .v2-pagination-container-half {
|
|
46
57
|
padding: $CAP_SPACE_24 $CAP_SPACE_24 $CAP_SPACE_08 $CAP_SPACE_24;
|
|
47
58
|
}
|
|
48
59
|
|
|
@@ -181,10 +192,13 @@
|
|
|
181
192
|
.whatsapp-container {
|
|
182
193
|
background-color: $CAP_WHITE;
|
|
183
194
|
padding: $CAP_SPACE_12;
|
|
195
|
+
overflow-y: hidden;
|
|
184
196
|
}
|
|
185
197
|
.scroll-container {
|
|
186
198
|
overflow-x: auto;
|
|
187
199
|
display: flex;
|
|
200
|
+
flex-wrap: nowrap;
|
|
201
|
+
width: 100%;
|
|
188
202
|
padding-top: $CAP_SPACE_06;
|
|
189
203
|
padding-right: $CAP_SPACE_06;
|
|
190
204
|
white-space: nowrap;
|
|
@@ -218,6 +232,91 @@
|
|
|
218
232
|
}
|
|
219
233
|
}
|
|
220
234
|
|
|
235
|
+
// RCS template listing preview: match WhatsApp carousel "peek" behavior
|
|
236
|
+
.RCS {
|
|
237
|
+
.cap-custom-card {
|
|
238
|
+
.ant-card-body {
|
|
239
|
+
.ant-card-meta {
|
|
240
|
+
background-color: $CAP_G09;
|
|
241
|
+
padding: 0;
|
|
242
|
+
.ant-card-meta-description {
|
|
243
|
+
.whatsapp-container,.cap-rcs-creatives {
|
|
244
|
+
background-color: $CAP_WHITE;
|
|
245
|
+
padding: $CAP_SPACE_12;
|
|
246
|
+
border-radius: 0.25rem;
|
|
247
|
+
.cap-divider-v2{
|
|
248
|
+
margin: $CAP_SPACE_12 0;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
.scroll-container {
|
|
252
|
+
overflow-x: auto;
|
|
253
|
+
display: flex;
|
|
254
|
+
padding-top: $CAP_SPACE_06;
|
|
255
|
+
padding-right: $CAP_SPACE_06;
|
|
256
|
+
white-space: nowrap;
|
|
257
|
+
scrollbar-width: none; // Hide scrollbar in Firefox
|
|
258
|
+
&::-webkit-scrollbar {
|
|
259
|
+
display: none; // Hide scrollbar in Chrome/Safari/Opera
|
|
260
|
+
}
|
|
261
|
+
overflow-y: hidden;
|
|
262
|
+
.whatsapp-carousel-container {
|
|
263
|
+
padding: $CAP_SPACE_04 0px $CAP_SPACE_08;
|
|
264
|
+
border-radius: $CAP_SPACE_06;
|
|
265
|
+
background-color: $CAP_WHITE;
|
|
266
|
+
width: 80%;
|
|
267
|
+
flex-shrink: 0;
|
|
268
|
+
margin-right: $CAP_SPACE_04;
|
|
269
|
+
white-space: pre-wrap;
|
|
270
|
+
word-break: break-word;
|
|
271
|
+
overflow: auto;
|
|
272
|
+
text-align: left;
|
|
273
|
+
.whatsapp-carousel-card {
|
|
274
|
+
margin: $CAP_SPACE_02 $CAP_SPACE_06 $CAP_SPACE_01 $CAP_SPACE_08;
|
|
275
|
+
.whatsapp-carousel-body {
|
|
276
|
+
margin-bottom: $CAP_SPACE_08;
|
|
277
|
+
white-space: pre-wrap;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// RCS CTA buttons in listing (reuse WhatsApp-ish look)
|
|
284
|
+
.rcs-cta-preview {
|
|
285
|
+
margin: $CAP_SPACE_12 0;
|
|
286
|
+
display: flex;
|
|
287
|
+
justify-content: center;
|
|
288
|
+
font-size: $FONT_SIZE_M;
|
|
289
|
+
align-items: center;
|
|
290
|
+
color: #1970DA;
|
|
291
|
+
svg {
|
|
292
|
+
margin-right: $CAP_SPACE_04;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.rcs-video-preview-placeholder {
|
|
297
|
+
background: #f5f5f5;
|
|
298
|
+
display: flex;
|
|
299
|
+
align-items: center;
|
|
300
|
+
justify-content: center;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.rcs-video-preview-label {
|
|
304
|
+
color: #7a7a7a;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.rcs-listing-title {
|
|
308
|
+
font-weight: 600;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.whatsapp-divider {
|
|
312
|
+
margin: 0;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
221
320
|
.MOBILEPUSH {
|
|
222
321
|
.ant-card-body {
|
|
223
322
|
padding: 0;
|