@capillarytech/creatives-library 8.0.254 → 8.0.255-alpha.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/assets/Android.png +0 -0
- package/assets/iOS.png +0 -0
- package/constants/unified.js +2 -1
- package/initialReducer.js +2 -0
- package/package.json +1 -1
- package/services/api.js +10 -0
- package/services/tests/api.test.js +34 -0
- package/utils/common.js +5 -0
- package/utils/commonUtils.js +28 -5
- package/utils/tests/commonUtil.test.js +224 -0
- package/utils/transformTemplateConfig.js +0 -10
- package/v2Components/CapDeviceContent/index.js +61 -56
- package/v2Components/CapTagList/index.js +6 -1
- package/v2Components/CapTagListWithInput/index.js +5 -1
- package/v2Components/CapTagListWithInput/messages.js +1 -1
- package/v2Components/CapWhatsappCTA/tests/index.test.js +5 -0
- package/v2Components/ErrorInfoNote/constants.js +1 -0
- package/v2Components/ErrorInfoNote/index.js +457 -72
- package/v2Components/ErrorInfoNote/messages.js +36 -6
- package/v2Components/ErrorInfoNote/style.scss +282 -6
- package/v2Components/FormBuilder/tests/index.test.js +13 -4
- package/v2Components/HtmlEditor/HTMLEditor.js +547 -94
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +874 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +1358 -133
- package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +27 -16
- package/v2Components/HtmlEditor/_htmlEditor.scss +108 -45
- package/v2Components/HtmlEditor/_index.lazy.scss +0 -1
- package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +22 -101
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +149 -140
- package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +2 -1
- package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
- package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +9 -0
- package/v2Components/HtmlEditor/components/EditorToolbar/index.js +1 -1
- package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +22 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +4 -7
- package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +35 -45
- package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +1 -3
- package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
- package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +7 -6
- package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +3 -6
- package/v2Components/HtmlEditor/components/PreviewPane/index.js +24 -34
- package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +49 -31
- package/v2Components/HtmlEditor/components/ValidationPanel/_validationPanel.scss +50 -34
- package/v2Components/HtmlEditor/components/ValidationPanel/constants.js +6 -0
- package/v2Components/HtmlEditor/components/ValidationPanel/index.js +70 -41
- package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +254 -0
- package/v2Components/HtmlEditor/components/ValidationTabs/index.js +364 -0
- package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +51 -0
- package/v2Components/HtmlEditor/constants.js +42 -20
- package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +373 -16
- package/v2Components/HtmlEditor/hooks/__tests__/useValidation.apiErrors.test.js +794 -0
- package/v2Components/HtmlEditor/hooks/useEditorContent.js +5 -2
- package/v2Components/HtmlEditor/hooks/useInAppContent.js +88 -146
- package/v2Components/HtmlEditor/hooks/useValidation.js +189 -53
- package/v2Components/HtmlEditor/index.js +1 -1
- package/v2Components/HtmlEditor/messages.js +95 -85
- package/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +94 -45
- package/v2Components/HtmlEditor/utils/__tests__/validationAdapter.test.js +134 -0
- package/v2Components/HtmlEditor/utils/contentSanitizer.js +40 -41
- package/v2Components/HtmlEditor/utils/htmlValidator.js +71 -72
- package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +134 -102
- package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +23 -25
- package/v2Components/HtmlEditor/utils/validationAdapter.js +66 -41
- package/v2Components/HtmlEditor/utils/validationConstants.js +40 -0
- package/v2Components/MobilePushPreviewV2/index.js +32 -7
- package/v2Components/TemplatePreview/_templatePreview.scss +55 -24
- package/v2Components/TemplatePreview/index.js +47 -32
- package/v2Components/TemplatePreview/messages.js +4 -0
- package/v2Components/TestAndPreviewSlidebox/_testAndPreviewSlidebox.scss +1 -0
- package/v2Containers/BeeEditor/index.js +172 -90
- package/v2Containers/BeePopupEditor/_beePopupEditor.scss +14 -0
- package/v2Containers/BeePopupEditor/constants.js +10 -0
- package/v2Containers/BeePopupEditor/index.js +194 -0
- package/v2Containers/BeePopupEditor/tests/index.test.js +627 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +128 -51
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +163 -13
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +2 -1
- package/v2Containers/CreativesContainer/constants.js +1 -0
- package/v2Containers/CreativesContainer/index.js +239 -46
- package/v2Containers/CreativesContainer/messages.js +8 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +11 -2
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +38 -50
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +106 -0
- package/v2Containers/Email/actions.js +7 -0
- package/v2Containers/Email/constants.js +5 -1
- package/v2Containers/Email/index.js +234 -29
- package/v2Containers/Email/messages.js +32 -0
- package/v2Containers/Email/reducer.js +12 -1
- package/v2Containers/Email/sagas.js +61 -7
- package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +2 -0
- package/v2Containers/Email/tests/reducer.test.js +46 -0
- package/v2Containers/Email/tests/sagas.test.js +320 -29
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +1285 -0
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +207 -19
- package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +40 -74
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +1870 -0
- package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +520 -0
- package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +2 -67
- package/v2Containers/EmailWrapper/constants.js +2 -0
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +629 -77
- package/v2Containers/EmailWrapper/index.js +103 -23
- package/v2Containers/EmailWrapper/messages.js +61 -1
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +643 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +594 -77
- package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +376 -0
- package/v2Containers/InApp/__tests__/sagas.test.js +363 -0
- package/v2Containers/InApp/actions.js +7 -0
- package/v2Containers/InApp/constants.js +20 -4
- package/v2Containers/InApp/index.js +802 -359
- package/v2Containers/InApp/index.scss +4 -3
- package/v2Containers/InApp/messages.js +7 -3
- package/v2Containers/InApp/reducer.js +21 -3
- package/v2Containers/InApp/sagas.js +29 -9
- package/v2Containers/InApp/selectors.js +25 -5
- package/v2Containers/InApp/tests/index.test.js +154 -50
- package/v2Containers/InApp/tests/reducer.test.js +34 -0
- package/v2Containers/InApp/tests/sagas.test.js +61 -9
- package/v2Containers/InApp/tests/selectors.test.js +612 -0
- package/v2Containers/InAppWrapper/components/InAppWrapperView.js +151 -0
- package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +267 -0
- package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +23 -0
- package/v2Containers/InAppWrapper/constants.js +16 -0
- package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +473 -0
- package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +198 -0
- package/v2Containers/InAppWrapper/index.js +148 -0
- package/v2Containers/InAppWrapper/messages.js +49 -0
- package/v2Containers/InappAdvance/index.js +1099 -0
- package/v2Containers/InappAdvance/index.scss +10 -0
- package/v2Containers/InappAdvance/tests/index.test.js +448 -0
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +3 -0
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +2 -0
- package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +2 -0
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +9 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +12 -0
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4 -0
- package/v2Containers/TagList/index.js +62 -19
- package/v2Containers/Templates/_templates.scss +60 -1
- package/v2Containers/Templates/index.js +89 -4
- package/v2Containers/Templates/messages.js +4 -0
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -0
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +0 -152
- package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +0 -214
|
@@ -2281,6 +2281,7 @@ new message content.",
|
|
|
2281
2281
|
"email": [Function],
|
|
2282
2282
|
"facebookPreview": [Function],
|
|
2283
2283
|
"gallery": [Function],
|
|
2284
|
+
"inApp": [Function],
|
|
2284
2285
|
"language": [Function],
|
|
2285
2286
|
"navigationConfig": [Function],
|
|
2286
2287
|
"previewAndTest": [Function],
|
|
@@ -13327,6 +13328,7 @@ new message content.",
|
|
|
13327
13328
|
"email": [Function],
|
|
13328
13329
|
"facebookPreview": [Function],
|
|
13329
13330
|
"gallery": [Function],
|
|
13331
|
+
"inApp": [Function],
|
|
13330
13332
|
"language": [Function],
|
|
13331
13333
|
"navigationConfig": [Function],
|
|
13332
13334
|
"previewAndTest": [Function],
|
|
@@ -24119,6 +24121,7 @@ new message content.",
|
|
|
24119
24121
|
"email": [Function],
|
|
24120
24122
|
"facebookPreview": [Function],
|
|
24121
24123
|
"gallery": [Function],
|
|
24124
|
+
"inApp": [Function],
|
|
24122
24125
|
"language": [Function],
|
|
24123
24126
|
"navigationConfig": [Function],
|
|
24124
24127
|
"previewAndTest": [Function],
|
|
@@ -34911,6 +34914,7 @@ new message content.",
|
|
|
34911
34914
|
"email": [Function],
|
|
34912
34915
|
"facebookPreview": [Function],
|
|
34913
34916
|
"gallery": [Function],
|
|
34917
|
+
"inApp": [Function],
|
|
34914
34918
|
"language": [Function],
|
|
34915
34919
|
"navigationConfig": [Function],
|
|
34916
34920
|
"previewAndTest": [Function],
|
|
@@ -40,6 +40,7 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
|
|
|
40
40
|
tags: [],
|
|
41
41
|
tagsError: false,
|
|
42
42
|
currentContext: null, // Track current context to detect changes
|
|
43
|
+
hasTriggeredInitialApiCall: false, // Track if we've triggered API call when popover opens
|
|
43
44
|
};
|
|
44
45
|
this.renderTags = this.renderTags.bind(this);
|
|
45
46
|
this.populateTags = this.populateTags.bind(this);
|
|
@@ -51,6 +52,14 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
|
|
|
51
52
|
|
|
52
53
|
componentDidMount() {
|
|
53
54
|
this.generateTags(this.props);
|
|
55
|
+
// Trigger initial API call if tags are empty (similar to Email/SMS behavior)
|
|
56
|
+
const { tags, injectedTags, onContextChange } = this.props;
|
|
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
|
+
}
|
|
54
63
|
}
|
|
55
64
|
|
|
56
65
|
componentWillReceiveProps(nextProps) {
|
|
@@ -59,23 +68,27 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
|
|
|
59
68
|
// 2. Context change is happening (detected by different tag arrays)
|
|
60
69
|
const { injectedTags: currentInjectedTags, tags: currentTags } = this.props;
|
|
61
70
|
const { injectedTags: nextInjectedTags, tags: nextTags, fetchingSchemaError } = nextProps;
|
|
62
|
-
|
|
71
|
+
|
|
63
72
|
const isInitialLoad = _.isEmpty(currentInjectedTags) && _.isEmpty(currentTags);
|
|
64
73
|
const isContextChange = !_.isEqual(nextTags, currentTags) && !_.isEmpty(currentTags);
|
|
65
|
-
|
|
74
|
+
|
|
66
75
|
if (isInitialLoad || isContextChange) {
|
|
67
76
|
this.setState({loading: true});
|
|
68
77
|
}
|
|
69
|
-
|
|
78
|
+
|
|
70
79
|
// Only reset loading for injectedTags changes if we're not currently loading due to context change
|
|
71
80
|
if (!_.isEqual(nextInjectedTags, currentInjectedTags) && !this.state.loading) {
|
|
72
81
|
this.setState({loading: false});
|
|
73
82
|
this.clearLoadingTimeout();
|
|
74
83
|
}
|
|
75
|
-
|
|
84
|
+
|
|
76
85
|
if (!_.isEqual(nextTags, currentTags)) {
|
|
77
86
|
this.setState({loading: false});
|
|
78
87
|
this.clearLoadingTimeout();
|
|
88
|
+
// Reset the flag when tags are received, so we can trigger API call again if needed
|
|
89
|
+
if (nextTags && nextTags.length > 0) {
|
|
90
|
+
this.setState({ hasTriggeredInitialApiCall: false });
|
|
91
|
+
}
|
|
79
92
|
}
|
|
80
93
|
if (fetchingSchemaError) {
|
|
81
94
|
this.setState({tagsError: fetchingSchemaError, loading: false});
|
|
@@ -86,7 +99,7 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
|
|
|
86
99
|
componentDidUpdate(prevProps) {
|
|
87
100
|
const { tags, injectedTags, selectedOfferDetails } = this.props;
|
|
88
101
|
const { tags: prevTags, injectedTags: prevInjectedTags, selectedOfferDetails: prevSelectedOfferDetails } = prevProps;
|
|
89
|
-
|
|
102
|
+
|
|
90
103
|
if (tags !== prevTags || injectedTags !== prevInjectedTags || selectedOfferDetails !== prevSelectedOfferDetails) {
|
|
91
104
|
this.generateTags(this.props);
|
|
92
105
|
}
|
|
@@ -111,17 +124,44 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
|
|
|
111
124
|
getTagsforContext = (data) => {
|
|
112
125
|
// Set loading state when context change is requested
|
|
113
126
|
this.setState({loading: true, currentContext: data});
|
|
114
|
-
|
|
127
|
+
|
|
115
128
|
// Set a timeout to prevent infinite loading (fallback safety)
|
|
116
129
|
this.clearLoadingTimeout();
|
|
117
130
|
this.loadingTimeout = setTimeout(() => {
|
|
118
131
|
this.setState({loading: false});
|
|
119
132
|
}, 5000); // Reduced timeout to 5 seconds for better UX
|
|
120
|
-
|
|
133
|
+
|
|
121
134
|
const { onContextChange } = this.props;
|
|
122
|
-
onContextChange
|
|
135
|
+
// Always call onContextChange if available - this triggers the API call
|
|
136
|
+
// The API call will fetch tags from /meta/TAG endpoint
|
|
137
|
+
if (onContextChange) {
|
|
138
|
+
onContextChange(data);
|
|
139
|
+
} else {
|
|
140
|
+
console.warn('TagList: onContextChange is not available. API call will not be triggered.');
|
|
141
|
+
}
|
|
123
142
|
}
|
|
124
143
|
|
|
144
|
+
handlePopoverVisibilityChange = (visible) => {
|
|
145
|
+
// When popover opens, trigger API call if tags are empty or if we haven't triggered it yet
|
|
146
|
+
// This ensures API call happens when user clicks "Add Label" button
|
|
147
|
+
if (visible && this.props.onContextChange) {
|
|
148
|
+
const { tags, injectedTags } = this.props;
|
|
149
|
+
// Check if tags array is empty or if state tags are empty
|
|
150
|
+
const hasNoTags = (!tags || tags.length === 0) && _.isEmpty(injectedTags);
|
|
151
|
+
const hasNoStateTags = _.isEmpty(this.state.tags);
|
|
152
|
+
const hasNotTriggeredApiCall = !this.state.hasTriggeredInitialApiCall;
|
|
153
|
+
|
|
154
|
+
// Trigger API call if tags are not loaded yet OR if we haven't triggered it yet
|
|
155
|
+
if ((hasNoTags || hasNoStateTags || hasNotTriggeredApiCall)) {
|
|
156
|
+
// Mark that we've triggered the API call
|
|
157
|
+
this.setState({ hasTriggeredInitialApiCall: true });
|
|
158
|
+
// Trigger API call with default 'Outbound' context to match CapTagList default
|
|
159
|
+
// This will call onContextChange which triggers handleOnTagsContextChange in InApp
|
|
160
|
+
this.getTagsforContext('Outbound');
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
125
165
|
generateTags = (props) => {
|
|
126
166
|
let tags = {};
|
|
127
167
|
let injectedTags = {};
|
|
@@ -149,11 +189,11 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
|
|
|
149
189
|
if (eventContextTags?.length) {
|
|
150
190
|
const TAG_HEADER_MSG_LABEL = this.props.intl.formatMessage(messages.entryEvent);
|
|
151
191
|
eventContextTagsObj.eventContextTags = {
|
|
152
|
-
name: TAG_HEADER_MSG_LABEL,
|
|
153
|
-
desc: TAG_HEADER_MSG_LABEL,
|
|
154
|
-
resolved: true,
|
|
192
|
+
"name": TAG_HEADER_MSG_LABEL,
|
|
193
|
+
"desc": TAG_HEADER_MSG_LABEL,
|
|
194
|
+
"resolved": true,
|
|
155
195
|
'tag-header': true,
|
|
156
|
-
subtags: {},
|
|
196
|
+
"subtags": {},
|
|
157
197
|
};
|
|
158
198
|
|
|
159
199
|
eventContextTags.forEach((tag) => {
|
|
@@ -164,11 +204,11 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
|
|
|
164
204
|
// Initializing the tags profile if it doesn't exist
|
|
165
205
|
if (!eventContextTagsObj?.eventContextTags?.subtags?.[profileId]) {
|
|
166
206
|
eventContextTagsObj.eventContextTags.subtags[profileId] = {
|
|
167
|
-
name: profileName,
|
|
168
|
-
desc: profileName,
|
|
169
|
-
resolved: true,
|
|
207
|
+
"name": profileName,
|
|
208
|
+
"desc": profileName,
|
|
209
|
+
"resolved": true,
|
|
170
210
|
'tag-header': true,
|
|
171
|
-
subtags: {},
|
|
211
|
+
"subtags": {},
|
|
172
212
|
};
|
|
173
213
|
}
|
|
174
214
|
// Adding the current tag to the profile group
|
|
@@ -201,7 +241,7 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
|
|
|
201
241
|
_.forEach(tagsList, (temp) => {
|
|
202
242
|
const tag = temp.definition;
|
|
203
243
|
const { intl } = this.props;
|
|
204
|
-
|
|
244
|
+
const { locale: userLocale } = intl || {};
|
|
205
245
|
|
|
206
246
|
// Check if the tag.value should be skipped based on feature control
|
|
207
247
|
if (_.includes(excludedTags, tag.value)) {
|
|
@@ -209,8 +249,8 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
|
|
|
209
249
|
}
|
|
210
250
|
if (!tag['tag-header']) {
|
|
211
251
|
mainTags[tag.value] = {
|
|
212
|
-
|
|
213
|
-
|
|
252
|
+
name: tag?.label[userLocale] ? tag?.label[userLocale] : tag?.label?.en,
|
|
253
|
+
desc: tag?.label[userLocale] ? tag?.label[userLocale] : tag?.label?.en,
|
|
214
254
|
};
|
|
215
255
|
} else if (tag['tag-header'] && mainTags[tag.value]) {
|
|
216
256
|
mainTags[tag.value].subtags = _.concat(mainTags[tag.value].subtags, tag.subtags);
|
|
@@ -366,12 +406,14 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
|
|
|
366
406
|
visibleTaglist={this.props.visibleTaglist}
|
|
367
407
|
hidePopover={this.props.hidePopover}
|
|
368
408
|
onContextChange={this.getTagsforContext}
|
|
409
|
+
onVisibleChange={this.handlePopoverVisibilityChange}
|
|
369
410
|
moduleFilterEnabled={this.props.moduleFilterEnabled}
|
|
370
411
|
modalProps={this.props.modalProps}
|
|
371
412
|
currentOrgDetails={this.props.currentOrgDetails}
|
|
372
413
|
channel={this.props.channel}
|
|
373
414
|
disabled={this.props.disabled}
|
|
374
415
|
fetchingSchemaError={this?.state?.tagsError}
|
|
416
|
+
popoverPlacement={this.props.popoverPlacement}
|
|
375
417
|
/>
|
|
376
418
|
</div>
|
|
377
419
|
);
|
|
@@ -402,6 +444,7 @@ TagList.propTypes = {
|
|
|
402
444
|
disabled: PropTypes.bool,
|
|
403
445
|
fetchingSchemaError: PropTypes.bool,
|
|
404
446
|
eventContextTags: PropTypes.array,
|
|
447
|
+
popoverPlacement: PropTypes.string,
|
|
405
448
|
intl: PropTypes.shape({
|
|
406
449
|
formatMessage: PropTypes.func.isRequired,
|
|
407
450
|
locale: PropTypes.string,
|
|
@@ -313,6 +313,64 @@
|
|
|
313
313
|
}
|
|
314
314
|
}
|
|
315
315
|
}
|
|
316
|
+
.INAPP {
|
|
317
|
+
margin-bottom: $CAP_SPACE_12;
|
|
318
|
+
.inapp-container {
|
|
319
|
+
margin-top: $CAP_SPACE_24;
|
|
320
|
+
}
|
|
321
|
+
// Modal Layout - centered
|
|
322
|
+
.inapp-modal-layout {
|
|
323
|
+
position: absolute;
|
|
324
|
+
display: flex;
|
|
325
|
+
width: 12rem;
|
|
326
|
+
top: 10%;
|
|
327
|
+
left: 10%;
|
|
328
|
+
bottom: 5%;
|
|
329
|
+
overflow: hidden;
|
|
330
|
+
background-color: $CAP_WHITE;
|
|
331
|
+
border-radius: $CAP_SPACE_08;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Full Screen Layout
|
|
335
|
+
.inapp-fullscreen-layout {
|
|
336
|
+
position: absolute;
|
|
337
|
+
display: flex;
|
|
338
|
+
width: 12rem;
|
|
339
|
+
left: 10%;
|
|
340
|
+
top: 1%;
|
|
341
|
+
bottom: 1%;
|
|
342
|
+
overflow: hidden;
|
|
343
|
+
background-color: $CAP_WHITE;
|
|
344
|
+
border-radius: $CAP_SPACE_08;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Top Banner Layout
|
|
348
|
+
.inapp-top-banner-layout {
|
|
349
|
+
position: absolute;
|
|
350
|
+
display: flex;
|
|
351
|
+
width: 12rem;
|
|
352
|
+
left: 10%;
|
|
353
|
+
top: 1%;
|
|
354
|
+
bottom: 20%;
|
|
355
|
+
overflow: hidden;
|
|
356
|
+
background-color: $CAP_WHITE;
|
|
357
|
+
border-radius: $CAP_SPACE_08;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Bottom Banner Layout
|
|
361
|
+
.inapp-bottom-banner-layout {
|
|
362
|
+
position: absolute;
|
|
363
|
+
display: flex;
|
|
364
|
+
justify-content: center;
|
|
365
|
+
width: 12rem;
|
|
366
|
+
left: 10%;
|
|
367
|
+
top: 50%;
|
|
368
|
+
bottom: 2%;
|
|
369
|
+
overflow: hidden;
|
|
370
|
+
background-color: $CAP_WHITE;
|
|
371
|
+
border-radius: $CAP_SPACE_08;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
316
374
|
}
|
|
317
375
|
|
|
318
376
|
.create-new-link{
|
|
@@ -695,7 +753,8 @@
|
|
|
695
753
|
}
|
|
696
754
|
|
|
697
755
|
.whatsapp-filters,
|
|
698
|
-
.zalo-filters
|
|
756
|
+
.zalo-filters,
|
|
757
|
+
.inapp-filters {
|
|
699
758
|
display: flex;
|
|
700
759
|
width: 100%;
|
|
701
760
|
padding-left: 8px;
|
|
@@ -127,13 +127,14 @@ import {
|
|
|
127
127
|
VIDEO,
|
|
128
128
|
GIF,
|
|
129
129
|
} from '../Whatsapp/constants';
|
|
130
|
-
import { INAPP_LAYOUT_DETAILS } from '../InApp/constants';
|
|
130
|
+
import { INAPP_LAYOUT_DETAILS, INAPP_MESSAGE_LAYOUT_TYPES, INAPP_MEDIA_TYPES, BIG_HTML, ANDROID, IOS } from '../InApp/constants';
|
|
131
131
|
import { ZALO_STATUS_OPTIONS, ZALO_STATUSES } from '../Zalo/constants';
|
|
132
132
|
import { getWhatsappContent, getWhatsappStatus, getWhatsappCategory, getWhatsappCta, getWhatsappQuickReply, getWhatsappAutoFill, getWhatsappCarouselButtonView } from '../Whatsapp/utils';
|
|
133
133
|
import { getRCSContent } from '../Rcs/utils';
|
|
134
134
|
import {RCS_STATUSES} from '../Rcs/constants';
|
|
135
135
|
import zaloMessages from '../Zalo/messages';
|
|
136
136
|
import rcsMessages from '../Rcs/messages';
|
|
137
|
+
import inAppMessages from '../InApp/messages';
|
|
137
138
|
import globalMessages from '../../v2Containers/Cap/messages';
|
|
138
139
|
import { handlePreviewInNewTab } from '../../utils/common';
|
|
139
140
|
|
|
@@ -200,6 +201,29 @@ const SMS_FILTERS = {
|
|
|
200
201
|
SERVICE_IMPLICIT: 'implicit',
|
|
201
202
|
};
|
|
202
203
|
|
|
204
|
+
const INAPP_LAYOUT_OPTIONS = [
|
|
205
|
+
{
|
|
206
|
+
key: 'popup',
|
|
207
|
+
value: INAPP_MESSAGE_LAYOUT_TYPES.MODAL,
|
|
208
|
+
label: <FormattedMessage {...inAppMessages.layoutModal} />,
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
key: 'topBanner',
|
|
212
|
+
value: INAPP_MESSAGE_LAYOUT_TYPES.TOPBANNER,
|
|
213
|
+
label: <FormattedMessage {...inAppMessages.layoutTopBanner} />,
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
key: 'bottomBanner',
|
|
217
|
+
value: INAPP_MESSAGE_LAYOUT_TYPES.BOTTOMBANNER,
|
|
218
|
+
label: <FormattedMessage {...inAppMessages.layoutBottomBanner} />,
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
key: 'fullScreen',
|
|
222
|
+
value: INAPP_MESSAGE_LAYOUT_TYPES.FULLSCREEN,
|
|
223
|
+
label: <FormattedMessage {...inAppMessages.layoutFullScreen} />,
|
|
224
|
+
},
|
|
225
|
+
];
|
|
226
|
+
|
|
203
227
|
const WHATSAPP_LOWERCASE = WHATSAPP.toLowerCase();
|
|
204
228
|
const RCS_LOWERCASE = RCS.toLowerCase();
|
|
205
229
|
const SMS_LOWERCASE = SMS.toLowerCase();
|
|
@@ -250,6 +274,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
250
274
|
selectedWhatsappStatus: '',
|
|
251
275
|
selectedWhatsappCategory: '',
|
|
252
276
|
selectedZaloStatus: '',
|
|
277
|
+
selectedInAppLayout: '',
|
|
253
278
|
hostName: '',
|
|
254
279
|
searchedZaloTemplates: [],
|
|
255
280
|
searchingZaloTemplate: false,
|
|
@@ -1648,6 +1673,19 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
1648
1673
|
return templates;
|
|
1649
1674
|
}
|
|
1650
1675
|
|
|
1676
|
+
filterInAppTemplates = (templates) => {
|
|
1677
|
+
const { selectedInAppLayout } = this.state;
|
|
1678
|
+
if (!selectedInAppLayout) {
|
|
1679
|
+
return templates;
|
|
1680
|
+
}
|
|
1681
|
+
return templates.filter((template) => {
|
|
1682
|
+
const androidBodyType = get(template, 'versions.base.content.ANDROID.bodyType');
|
|
1683
|
+
const iosBodyType = get(template, 'versions.base.content.IOS.bodyType');
|
|
1684
|
+
const inappBodyType = androidBodyType || iosBodyType;
|
|
1685
|
+
return inappBodyType === selectedInAppLayout;
|
|
1686
|
+
});
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1651
1689
|
filterSMSTemplates = (templates) => {
|
|
1652
1690
|
const { smsFilter } = this.state;
|
|
1653
1691
|
if (SMS_FILTERS.ALL === smsFilter) {
|
|
@@ -1734,6 +1772,9 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
1734
1772
|
case ZALO:
|
|
1735
1773
|
filteredTemplates = this.filterZaloTemplates(templates);
|
|
1736
1774
|
break;
|
|
1775
|
+
case INAPP:
|
|
1776
|
+
filteredTemplates = this.filterInAppTemplates(templates);
|
|
1777
|
+
break;
|
|
1737
1778
|
default:
|
|
1738
1779
|
break;
|
|
1739
1780
|
}
|
|
@@ -2023,9 +2064,12 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
2023
2064
|
templateData.isNewMobilePush = commonUtil.hasNewMobilePushFeatureEnabled();
|
|
2024
2065
|
}
|
|
2025
2066
|
break;
|
|
2026
|
-
case INAPP:
|
|
2067
|
+
case INAPP: {
|
|
2068
|
+
// Pass the full template object to CapCustomCard so getInAppContent can extract the data
|
|
2069
|
+
// Similar to how MOBILE_PUSH passes the full template when new feature is enabled
|
|
2027
2070
|
templateData.content = template;
|
|
2028
2071
|
break;
|
|
2072
|
+
}
|
|
2029
2073
|
case WECHAT:
|
|
2030
2074
|
templateData.content = this.prepareWeChatPreviewData(template);
|
|
2031
2075
|
break;
|
|
@@ -2339,7 +2383,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
2339
2383
|
return (<div>
|
|
2340
2384
|
{[WECHAT, MOBILE_PUSH, INAPP, WHATSAPP, ZALO,RCS].includes(currentChannel) && this.showAccountName()}
|
|
2341
2385
|
{filterContent}
|
|
2342
|
-
{[WHATSAPP, ZALO,RCS].includes(currentChannel) && this.selectedFilters()}
|
|
2386
|
+
{[WHATSAPP, ZALO, INAPP,RCS].includes(currentChannel) && this.selectedFilters()}
|
|
2343
2387
|
{<div>
|
|
2344
2388
|
{!isEmpty(filteredTemplates) || !isEmpty(this.state.searchText) || !isEmpty(this.props.Templates.templateError) ? (
|
|
2345
2389
|
<div className={!isEmpty(this.state.searchText) && isEmpty(cardDataList) ? '' : this.isFullMode() ? "v2-pagination-container" : "v2-pagination-container-half"}>
|
|
@@ -2549,6 +2593,9 @@ return (<div>
|
|
|
2549
2593
|
|
|
2550
2594
|
prepareWeChatMappedPreviewData(content, templateTags, tagData) {
|
|
2551
2595
|
let formattedContent = cloneDeep(content);
|
|
2596
|
+
if (!formattedContent || typeof formattedContent !== 'string') {
|
|
2597
|
+
return formattedContent || '';
|
|
2598
|
+
}
|
|
2552
2599
|
forEach(templateTags, (tag) => {
|
|
2553
2600
|
if (tagData[tag].value !== undefined) {
|
|
2554
2601
|
formattedContent = formattedContent.replace(`{{${tag}.DATA}}`, tagData[tag].value);
|
|
@@ -3746,14 +3793,19 @@ return (<div>
|
|
|
3746
3793
|
}
|
|
3747
3794
|
|
|
3748
3795
|
removeZaloFilter = () => this.setState({ selectedZaloStatus: null });
|
|
3796
|
+
removeInAppLayoutFilter = () => this.setState({ selectedInAppLayout: '' });
|
|
3749
3797
|
|
|
3750
3798
|
selectedFilters = () => {
|
|
3751
|
-
const { selectedWhatsappStatus, selectedWhatsappCategory, selectedZaloStatus } = this.state;
|
|
3799
|
+
const { selectedWhatsappStatus, selectedWhatsappCategory, selectedZaloStatus, selectedInAppLayout } = this.state;
|
|
3752
3800
|
const {
|
|
3753
3801
|
intl: {
|
|
3754
3802
|
formatMessage,
|
|
3755
3803
|
},
|
|
3756
3804
|
} = this.props;
|
|
3805
|
+
const getInAppLayoutLabel = (layoutValue) => {
|
|
3806
|
+
const layoutOption = INAPP_LAYOUT_OPTIONS.find(opt => opt.value === layoutValue);
|
|
3807
|
+
return layoutOption ? layoutOption.label : layoutValue;
|
|
3808
|
+
};
|
|
3757
3809
|
return (
|
|
3758
3810
|
<CapRow type="flex" align="middle" className="selected-whatsapp-filters">
|
|
3759
3811
|
{
|
|
@@ -3788,6 +3840,23 @@ return (<div>
|
|
|
3788
3840
|
</CapTag>
|
|
3789
3841
|
) : null
|
|
3790
3842
|
}
|
|
3843
|
+
{
|
|
3844
|
+
selectedInAppLayout ? (
|
|
3845
|
+
<CapTag closable onClose={this.removeInAppLayoutFilter}>
|
|
3846
|
+
{formatMessage(messages.layout)}: {getInAppLayoutLabel(selectedInAppLayout)}
|
|
3847
|
+
</CapTag>
|
|
3848
|
+
) : null
|
|
3849
|
+
}
|
|
3850
|
+
{
|
|
3851
|
+
selectedInAppLayout ? (
|
|
3852
|
+
<CapLink
|
|
3853
|
+
onClick={() => {
|
|
3854
|
+
this.removeInAppLayoutFilter();
|
|
3855
|
+
}}
|
|
3856
|
+
title={this.props.intl.formatMessage(messages.clearAll)}
|
|
3857
|
+
/>
|
|
3858
|
+
) : null
|
|
3859
|
+
}
|
|
3791
3860
|
</CapRow>
|
|
3792
3861
|
);
|
|
3793
3862
|
}
|
|
@@ -3798,6 +3867,7 @@ return (<div>
|
|
|
3798
3867
|
setLineFilter = (e) => this.setState({lineFilter: e.target.value});
|
|
3799
3868
|
setSMSFilter = (e) => this.setState({smsFilter: e.target.value});
|
|
3800
3869
|
setZaloStatus = (value) => this.setState({selectedZaloStatus: value?.item?.props?.value});
|
|
3870
|
+
setInAppLayout = (value) => this.setState({selectedInAppLayout: value?.item?.props?.value});
|
|
3801
3871
|
|
|
3802
3872
|
openCreativesFullMode = () => {
|
|
3803
3873
|
const channelLowerCase = this.state.channel.toLowerCase();
|
|
@@ -4050,6 +4120,21 @@ return (<div>
|
|
|
4050
4120
|
)
|
|
4051
4121
|
: () => null
|
|
4052
4122
|
}
|
|
4123
|
+
{
|
|
4124
|
+
channel.toUpperCase() === INAPP && (
|
|
4125
|
+
<div className="inapp-filters">
|
|
4126
|
+
<CapSelectFilter
|
|
4127
|
+
placement="bottomLeft"
|
|
4128
|
+
data={INAPP_LAYOUT_OPTIONS}
|
|
4129
|
+
onSelect={this.setInAppLayout}
|
|
4130
|
+
selectedValue={this.state.selectedInAppLayout}
|
|
4131
|
+
placeholder="Layout"
|
|
4132
|
+
showBadge
|
|
4133
|
+
width="120px"
|
|
4134
|
+
/>
|
|
4135
|
+
</div>
|
|
4136
|
+
)
|
|
4137
|
+
}
|
|
4053
4138
|
<div style={{display: "flex", justifyContent: "space-between", alignItems: 'center'}}>
|
|
4054
4139
|
{
|
|
4055
4140
|
this.state?.channel?.toLowerCase() === WHATSAPP_LOWERCASE && (isWhatsappCountExeeded)? (
|
|
@@ -534,6 +534,10 @@ export default defineMessages({
|
|
|
534
534
|
id: `${scope}.rcsOnlyApprovedTemplates`,
|
|
535
535
|
defaultMessage: 'Only "Approved" templates are available here, as you can use those templates to create a message.',
|
|
536
536
|
},
|
|
537
|
+
"layout": {
|
|
538
|
+
id: `${scope}.layout`,
|
|
539
|
+
defaultMessage: `Layout`,
|
|
540
|
+
},
|
|
537
541
|
"status": {
|
|
538
542
|
id: `${scope}.status`,
|
|
539
543
|
defaultMessage: 'Status',
|