@capillarytech/creatives-library 8.0.268 → 8.0.269
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/constants/unified.js +1 -0
- package/package.json +1 -1
- package/services/api.js +5 -0
- package/utils/common.js +6 -0
- package/utils/imageUrlUpload.js +141 -0
- package/utils/tagValidations.js +2 -1
- package/utils/tests/transformerUtils.test.js +297 -0
- package/utils/transformerUtils.js +40 -0
- package/v2Components/CapImageUpload/constants.js +2 -0
- package/v2Components/CapImageUpload/index.js +65 -16
- package/v2Components/CapImageUpload/index.scss +4 -1
- package/v2Components/CapImageUpload/messages.js +5 -1
- package/v2Components/CapImageUrlUpload/constants.js +26 -0
- package/v2Components/CapImageUrlUpload/index.js +365 -0
- package/v2Components/CapImageUrlUpload/index.scss +35 -0
- package/v2Components/CapImageUrlUpload/messages.js +47 -0
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +2 -2
- package/v2Components/CommonTestAndPreview/index.js +4 -15
- package/v2Components/FormBuilder/index.js +8 -8
- package/v2Containers/App/constants.js +5 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +57 -2
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +1 -0
- package/v2Containers/CreativesContainer/constants.js +3 -0
- package/v2Containers/CreativesContainer/index.js +168 -0
- package/v2Containers/CreativesContainer/messages.js +4 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +210 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +304 -0
- package/v2Containers/FTP/index.js +1 -1
- package/v2Containers/InApp/index.js +1 -0
- package/v2Containers/Line/Container/Text/index.js +1 -0
- package/v2Containers/MobilePushNew/index.js +1 -0
- package/v2Containers/Rcs/index.js +3 -0
- package/v2Containers/SmsTrai/Edit/index.js +2 -12
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +36 -648
- package/v2Containers/Templates/ChannelTypeIllustration.js +13 -1
- package/v2Containers/Templates/_templates.scss +205 -0
- package/v2Containers/Templates/actions.js +2 -1
- package/v2Containers/Templates/constants.js +1 -0
- package/v2Containers/Templates/index.js +274 -34
- package/v2Containers/Templates/messages.js +24 -0
- package/v2Containers/Templates/reducer.js +2 -0
- package/v2Containers/Templates/tests/index.test.js +10 -0
- package/v2Containers/TemplatesV2/index.js +15 -7
- package/v2Containers/TemplatesV2/messages.js +4 -0
- package/v2Containers/Viber/index.js +1 -0
- package/v2Containers/WebPush/Create/components/BrandIconSection.js +108 -0
- package/v2Containers/WebPush/Create/components/ButtonForm.js +172 -0
- package/v2Containers/WebPush/Create/components/ButtonItem.js +101 -0
- package/v2Containers/WebPush/Create/components/ButtonList.js +145 -0
- package/v2Containers/WebPush/Create/components/ButtonsLinksSection.js +164 -0
- package/v2Containers/WebPush/Create/components/ButtonsLinksSection.test.js +463 -0
- package/v2Containers/WebPush/Create/components/FormActions.js +54 -0
- package/v2Containers/WebPush/Create/components/FormActions.test.js +163 -0
- package/v2Containers/WebPush/Create/components/MediaSection.js +142 -0
- package/v2Containers/WebPush/Create/components/MediaSection.test.js +341 -0
- package/v2Containers/WebPush/Create/components/MessageSection.js +103 -0
- package/v2Containers/WebPush/Create/components/MessageSection.test.js +268 -0
- package/v2Containers/WebPush/Create/components/NotificationTitleSection.js +87 -0
- package/v2Containers/WebPush/Create/components/NotificationTitleSection.test.js +210 -0
- package/v2Containers/WebPush/Create/components/TemplateNameSection.js +54 -0
- package/v2Containers/WebPush/Create/components/TemplateNameSection.test.js +143 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/ButtonsLinksSection.test.js.snap +86 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/FormActions.test.js.snap +16 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/MediaSection.test.js.snap +41 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/MessageSection.test.js.snap +54 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/NotificationTitleSection.test.js.snap +37 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/TemplateNameSection.test.js.snap +21 -0
- package/v2Containers/WebPush/Create/components/_buttons.scss +246 -0
- package/v2Containers/WebPush/Create/components/tests/ButtonForm.test.js +554 -0
- package/v2Containers/WebPush/Create/components/tests/ButtonItem.test.js +607 -0
- package/v2Containers/WebPush/Create/components/tests/ButtonList.test.js +633 -0
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonForm.test.js.snap +666 -0
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonItem.test.js.snap +74 -0
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonList.test.js.snap +78 -0
- package/v2Containers/WebPush/Create/hooks/useButtonManagement.js +138 -0
- package/v2Containers/WebPush/Create/hooks/useButtonManagement.test.js +406 -0
- package/v2Containers/WebPush/Create/hooks/useCharacterCount.js +30 -0
- package/v2Containers/WebPush/Create/hooks/useCharacterCount.test.js +151 -0
- package/v2Containers/WebPush/Create/hooks/useImageUpload.js +104 -0
- package/v2Containers/WebPush/Create/hooks/useImageUpload.test.js +538 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.js +122 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +633 -0
- package/v2Containers/WebPush/Create/index.js +1148 -0
- package/v2Containers/WebPush/Create/index.scss +134 -0
- package/v2Containers/WebPush/Create/messages.js +211 -0
- package/v2Containers/WebPush/Create/preview/DevicePreviewContent.js +228 -0
- package/v2Containers/WebPush/Create/preview/NotificationContainer.js +294 -0
- package/v2Containers/WebPush/Create/preview/PreviewContent.js +90 -0
- package/v2Containers/WebPush/Create/preview/PreviewControls.js +305 -0
- package/v2Containers/WebPush/Create/preview/PreviewDisclaimer.js +25 -0
- package/v2Containers/WebPush/Create/preview/WebPushPreview.js +156 -0
- package/v2Containers/WebPush/Create/preview/assets/Light.svg +53 -0
- package/v2Containers/WebPush/Create/preview/assets/Top.svg +5 -0
- package/v2Containers/WebPush/Create/preview/assets/android-arrow-down.svg +9 -0
- package/v2Containers/WebPush/Create/preview/assets/android-arrow-up.svg +9 -0
- package/v2Containers/WebPush/Create/preview/assets/chrome-icon.png +0 -0
- package/v2Containers/WebPush/Create/preview/assets/edge-icon.png +0 -0
- package/v2Containers/WebPush/Create/preview/assets/firefox-icon.svg +106 -0
- package/v2Containers/WebPush/Create/preview/assets/iOS.svg +26 -0
- package/v2Containers/WebPush/Create/preview/assets/macos-arrow-down-icon.svg +9 -0
- package/v2Containers/WebPush/Create/preview/assets/macos-triple-dot-icon.svg +9 -0
- package/v2Containers/WebPush/Create/preview/assets/opera-icon.svg +18 -0
- package/v2Containers/WebPush/Create/preview/assets/safari-icon.svg +29 -0
- package/v2Containers/WebPush/Create/preview/assets/windows-close-icon.svg +9 -0
- package/v2Containers/WebPush/Create/preview/assets/windows-triple-dot-icon.svg +9 -0
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileChromeHeader.js +51 -0
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +145 -0
- package/v2Containers/WebPush/Create/preview/components/IOSHeader.js +45 -0
- package/v2Containers/WebPush/Create/preview/components/NotificationExpandedContent.js +68 -0
- package/v2Containers/WebPush/Create/preview/components/NotificationHeader.js +61 -0
- package/v2Containers/WebPush/Create/preview/components/WindowsChromeExpanded.js +99 -0
- package/v2Containers/WebPush/Create/preview/components/tests/AndroidMobileExpanded.test.js +733 -0
- package/v2Containers/WebPush/Create/preview/components/tests/WindowsChromeExpanded.test.js +571 -0
- package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/AndroidMobileExpanded.test.js.snap +85 -0
- package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/WindowsChromeExpanded.test.js.snap +81 -0
- package/v2Containers/WebPush/Create/preview/config/notificationMappings.js +50 -0
- package/v2Containers/WebPush/Create/preview/constants.js +637 -0
- package/v2Containers/WebPush/Create/preview/notification-container.scss +79 -0
- package/v2Containers/WebPush/Create/preview/preview.scss +358 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-chrome.scss +370 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-edge.scss +12 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-firefox.scss +12 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-opera.scss +12 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-chrome.scss +47 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-edge.scss +11 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-firefox.scss +11 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-opera.scss +11 -0
- package/v2Containers/WebPush/Create/preview/styles/_base.scss +207 -0
- package/v2Containers/WebPush/Create/preview/styles/_ios.scss +153 -0
- package/v2Containers/WebPush/Create/preview/styles/_ipados.scss +107 -0
- package/v2Containers/WebPush/Create/preview/styles/_macos-chrome.scss +101 -0
- package/v2Containers/WebPush/Create/preview/styles/_windows-chrome.scss +229 -0
- package/v2Containers/WebPush/Create/preview/tests/DevicePreviewContent.test.js +906 -0
- package/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +1081 -0
- package/v2Containers/WebPush/Create/preview/tests/PreviewControls.test.js +723 -0
- package/v2Containers/WebPush/Create/preview/tests/WebPushPreview.test.js +1327 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/DevicePreviewContent.test.js.snap +131 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/NotificationContainer.test.js.snap +112 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/PreviewControls.test.js.snap +144 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/WebPushPreview.test.js.snap +129 -0
- package/v2Containers/WebPush/Create/utils/payloadBuilder.js +96 -0
- package/v2Containers/WebPush/Create/utils/payloadBuilder.test.js +396 -0
- package/v2Containers/WebPush/Create/utils/previewUtils.js +89 -0
- package/v2Containers/WebPush/Create/utils/urlValidation.js +115 -0
- package/v2Containers/WebPush/Create/utils/urlValidation.test.js +449 -0
- package/v2Containers/WebPush/Create/utils/validation.js +76 -0
- package/v2Containers/WebPush/Create/utils/validation.test.js +283 -0
- package/v2Containers/WebPush/actions.js +60 -0
- package/v2Containers/WebPush/constants.js +132 -0
- package/v2Containers/WebPush/index.js +2 -0
- package/v2Containers/WebPush/reducer.js +104 -0
- package/v2Containers/WebPush/sagas.js +119 -0
- package/v2Containers/WebPush/selectors.js +65 -0
- package/v2Containers/WebPush/tests/reducer.test.js +863 -0
- package/v2Containers/WebPush/tests/sagas.test.js +566 -0
- package/v2Containers/WebPush/tests/selectors.test.js +960 -0
- package/v2Containers/Whatsapp/index.js +1 -0
- package/v2Containers/Zalo/index.js +1 -0
- package/v2Containers/Zalo/tests/index.test.js +1 -5
package/constants/unified.js
CHANGED
|
@@ -51,6 +51,7 @@ export const EXTENDED_TAG = 'ExtendedTagMessage';
|
|
|
51
51
|
export const BADGES_UI_ENABLED = 'BADGES_UI_ENABLED';
|
|
52
52
|
export const JP_LOCALE_HIDE_FEATURE = 'JP_LOCALE_HIDE_FEATURE';
|
|
53
53
|
export const ENABLE_WECHAT = 'ENABLE_WECHAT';
|
|
54
|
+
export const ENABLE_WEBPUSH = 'ENABLE_WEBPUSH';
|
|
54
55
|
export const ENABLE_CUSTOMER_BARCODE_TAG = 'ENABLE_CUSTOMER_BARCODE_TAG';
|
|
55
56
|
export const EMAIL_UNSUBSCRIBE_TAG_MANDATORY = 'EMAIL_UNSUBSCRIBE_TAG_MANDATORY';
|
|
56
57
|
export const ENABLE_AI_SUGGESTIONS = 'ENABLE_AI_SUGGESTIONS';
|
package/package.json
CHANGED
package/services/api.js
CHANGED
|
@@ -287,6 +287,11 @@ export const createMobilePushTemplateV2 = (template) => {
|
|
|
287
287
|
return request(url, getAPICallObject('POST', template));
|
|
288
288
|
};
|
|
289
289
|
|
|
290
|
+
export const createWebPushTemplate = (template) => {
|
|
291
|
+
const url = `${API_ENDPOINT}/templates/WEBPUSH`;
|
|
292
|
+
return request(url, getAPICallObject('POST', template));
|
|
293
|
+
};
|
|
294
|
+
|
|
290
295
|
export const duplicateTemplate = ({id, channel}) => {
|
|
291
296
|
const url = `${API_ENDPOINT}/templates/duplicate/${id}/${channel}`;
|
|
292
297
|
return request(url, getAPICallObject('GET'));
|
package/utils/common.js
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
EMAIL_UNSUBSCRIBE_TAG_MANDATORY,
|
|
22
22
|
BADGES_ISSUE,
|
|
23
23
|
ENABLE_WECHAT,
|
|
24
|
+
ENABLE_WEBPUSH,
|
|
24
25
|
LIQUID_SUPPORT,
|
|
25
26
|
ENABLE_NEW_MPUSH
|
|
26
27
|
} from '../constants/unified';
|
|
@@ -116,6 +117,11 @@ export const hasWechatFeatureEnabled = Auth.hasFeatureAccess.bind(
|
|
|
116
117
|
ENABLE_WECHAT,
|
|
117
118
|
);
|
|
118
119
|
|
|
120
|
+
export const hasWebPushFeatureEnabled = Auth.hasFeatureAccess.bind(
|
|
121
|
+
null,
|
|
122
|
+
ENABLE_WEBPUSH,
|
|
123
|
+
);
|
|
124
|
+
|
|
119
125
|
export const hasCustomerBarcodeFeatureEnabled = Auth.hasFeatureAccess.bind(
|
|
120
126
|
null,
|
|
121
127
|
ENABLE_CUSTOMER_BARCODE_TAG,
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for uploading images from URLs
|
|
3
|
+
*
|
|
4
|
+
* NOTE: CORS-limited; will be replaced with backend implementation.
|
|
5
|
+
* Flow currently hidden (not removed) from frontend.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
DEFAULT_ALLOWED_CONTENT_TYPES,
|
|
10
|
+
MIME_TYPE_TO_EXTENSION,
|
|
11
|
+
DEFAULT_IMAGE_EXTENSION,
|
|
12
|
+
} from '../v2Components/CapImageUrlUpload/constants';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Fetches an image from a URL
|
|
16
|
+
*
|
|
17
|
+
* @param {string} url - The image URL to fetch
|
|
18
|
+
* @returns {Promise<Response>} - The fetch response object
|
|
19
|
+
* @throws {Error} - If the fetch fails (network/CORS error)
|
|
20
|
+
*/
|
|
21
|
+
export const fetchImageFromUrl = async (url) => {
|
|
22
|
+
const trimmedUrl = url?.trim() || '';
|
|
23
|
+
|
|
24
|
+
if (!trimmedUrl) {
|
|
25
|
+
throw new Error('URL is required');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// CORS-limited: fails for images without proper CORS headers
|
|
29
|
+
const response = await fetch(trimmedUrl, {
|
|
30
|
+
method: 'GET',
|
|
31
|
+
redirect: 'follow',
|
|
32
|
+
mode: 'cors',
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
throw new Error(`Failed to fetch image: ${response.status} ${response.statusText}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return response;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Helper function to upload image from URL
|
|
44
|
+
* Fetches image, validates content type and size, converts to File, and uploads via uploadAsset
|
|
45
|
+
*
|
|
46
|
+
* @param {string} url - The image URL to upload
|
|
47
|
+
* @param {Function} formatMessage - React Intl formatMessage function
|
|
48
|
+
* @param {Object} messages - React Intl messages object
|
|
49
|
+
* @param {Function} uploadAssetFn - Function to upload the asset (file, type, fileParams)
|
|
50
|
+
* @param {string} fileNamePrefix - Prefix for the generated file name
|
|
51
|
+
* @param {number} maxSize - Maximum file size in bytes
|
|
52
|
+
* @param {string[]} allowedContentTypes - Array of allowed MIME types (defaults to DEFAULT_ALLOWED_CONTENT_TYPES)
|
|
53
|
+
* @returns {Promise<{success: boolean, error: string}>} - Result object with success status and error message
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* const result = await uploadImageFromUrlHelper(
|
|
57
|
+
* 'https://example.com/image.jpg',
|
|
58
|
+
* formatMessage,
|
|
59
|
+
* messages,
|
|
60
|
+
* uploadAsset,
|
|
61
|
+
* 'my-image',
|
|
62
|
+
* 5000000,
|
|
63
|
+
* ['image/jpeg', 'image/png']
|
|
64
|
+
* );
|
|
65
|
+
*/
|
|
66
|
+
export const uploadImageFromUrlHelper = async (
|
|
67
|
+
url,
|
|
68
|
+
formatMessage,
|
|
69
|
+
messages,
|
|
70
|
+
uploadAssetFn,
|
|
71
|
+
fileNamePrefix,
|
|
72
|
+
maxSize,
|
|
73
|
+
allowedContentTypes = DEFAULT_ALLOWED_CONTENT_TYPES,
|
|
74
|
+
) => {
|
|
75
|
+
const trimmedUrl = url?.trim() || '';
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
const response = await fetchImageFromUrl(trimmedUrl);
|
|
79
|
+
|
|
80
|
+
// Validate Content-Type
|
|
81
|
+
const contentType = response.headers?.get('Content-Type') || '';
|
|
82
|
+
const normalizedContentType = contentType.split(';')[0].toLowerCase().trim();
|
|
83
|
+
|
|
84
|
+
if (!allowedContentTypes.includes(normalizedContentType)) {
|
|
85
|
+
return {
|
|
86
|
+
success: false,
|
|
87
|
+
error: formatMessage(messages.imageTypeInvalid),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const blob = await response.blob();
|
|
92
|
+
|
|
93
|
+
if (blob.size > maxSize) {
|
|
94
|
+
return {
|
|
95
|
+
success: false,
|
|
96
|
+
error: formatMessage(messages.imageSizeInvalid),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Load image to get dimensions and verify validity
|
|
101
|
+
return new Promise((resolve) => {
|
|
102
|
+
const img = new Image();
|
|
103
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
104
|
+
|
|
105
|
+
img.onload = () => {
|
|
106
|
+
const extension = MIME_TYPE_TO_EXTENSION[normalizedContentType] || DEFAULT_IMAGE_EXTENSION;
|
|
107
|
+
const fileName = `${fileNamePrefix}.${extension}`;
|
|
108
|
+
const file = new File([blob], fileName, { type: blob.type });
|
|
109
|
+
const fileParams = {
|
|
110
|
+
width: img.width,
|
|
111
|
+
height: img.height,
|
|
112
|
+
error: false,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
uploadAssetFn(file, 'image', fileParams);
|
|
116
|
+
URL.revokeObjectURL(objectUrl);
|
|
117
|
+
|
|
118
|
+
resolve({
|
|
119
|
+
success: true,
|
|
120
|
+
error: '',
|
|
121
|
+
});
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
img.onerror = () => {
|
|
125
|
+
URL.revokeObjectURL(objectUrl);
|
|
126
|
+
resolve({
|
|
127
|
+
success: false,
|
|
128
|
+
error: formatMessage(messages.imageLoadError),
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
img.src = objectUrl;
|
|
133
|
+
});
|
|
134
|
+
} catch (error) {
|
|
135
|
+
return {
|
|
136
|
+
success: false,
|
|
137
|
+
error: formatMessage(messages.imageLoadError),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
package/utils/tagValidations.js
CHANGED
|
@@ -187,6 +187,7 @@ export const validateTags = ({
|
|
|
187
187
|
location,
|
|
188
188
|
tagModule,
|
|
189
189
|
eventContextTags,
|
|
190
|
+
isFullMode,
|
|
190
191
|
}) => {
|
|
191
192
|
const tags = tagsParam;
|
|
192
193
|
const injectedTags = transformInjectedTags(injectedTagsParams);
|
|
@@ -200,7 +201,7 @@ export const validateTags = ({
|
|
|
200
201
|
unsupportedTags: [],
|
|
201
202
|
isBraceError: false,
|
|
202
203
|
};
|
|
203
|
-
if (tags && tags.length) {
|
|
204
|
+
if (tags && tags.length && !isFullMode) {
|
|
204
205
|
lodashForEach(tags, ({
|
|
205
206
|
definition: {
|
|
206
207
|
supportedModules,
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
RCS,
|
|
16
16
|
LINE,
|
|
17
17
|
VIBER,
|
|
18
|
+
WEBPUSH,
|
|
18
19
|
} from "../../v2Containers/CreativesContainer/constants";
|
|
19
20
|
|
|
20
21
|
describe("transformerUtils", () => {
|
|
@@ -1182,6 +1183,302 @@ describe("transformerUtils", () => {
|
|
|
1182
1183
|
});
|
|
1183
1184
|
});
|
|
1184
1185
|
|
|
1186
|
+
describe("WebPush payload transformation", () => {
|
|
1187
|
+
it("should transform WebPush data correctly with minimal data", () => {
|
|
1188
|
+
const mockData = {
|
|
1189
|
+
channel: WEBPUSH,
|
|
1190
|
+
messageSubject: "test webpush notification"
|
|
1191
|
+
};
|
|
1192
|
+
|
|
1193
|
+
const result = transformChannelPayload(mockData);
|
|
1194
|
+
|
|
1195
|
+
expect(result.centralCommsPayload).toBeDefined();
|
|
1196
|
+
expect(result.centralCommsPayload.channel).toEqual(WEBPUSH);
|
|
1197
|
+
expect(result.centralCommsPayload.webpushMessageContent.messageSubject).toEqual(
|
|
1198
|
+
"test webpush notification"
|
|
1199
|
+
);
|
|
1200
|
+
expect(result.centralCommsPayload.clientName).toEqual("VENENO");
|
|
1201
|
+
});
|
|
1202
|
+
|
|
1203
|
+
it("should transform WebPush data with all options", () => {
|
|
1204
|
+
const mockData = {
|
|
1205
|
+
channel: WEBPUSH,
|
|
1206
|
+
messageSubject: "test webpush notification",
|
|
1207
|
+
messageContent: {
|
|
1208
|
+
content: {
|
|
1209
|
+
accountId: 12345,
|
|
1210
|
+
content: {
|
|
1211
|
+
title: "WebPush Title",
|
|
1212
|
+
message: "WebPush Message",
|
|
1213
|
+
iconImageUrl: "https://example.com/icon.png",
|
|
1214
|
+
cta: {
|
|
1215
|
+
actionLink: "https://example.com/action",
|
|
1216
|
+
actionText: "Click Here"
|
|
1217
|
+
},
|
|
1218
|
+
expandableDetails: {
|
|
1219
|
+
style: "BIG_TEXT",
|
|
1220
|
+
message: "Expanded Message"
|
|
1221
|
+
}
|
|
1222
|
+
},
|
|
1223
|
+
offers: [
|
|
1224
|
+
{ id: "offer-1", title: "Offer 1" },
|
|
1225
|
+
{ id: "offer-2", title: "Offer 2" }
|
|
1226
|
+
]
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
};
|
|
1230
|
+
|
|
1231
|
+
const options = {
|
|
1232
|
+
loyaltyMetaData: {
|
|
1233
|
+
actionId: "action-123",
|
|
1234
|
+
ouId: 456,
|
|
1235
|
+
clientName: "TestClient",
|
|
1236
|
+
module: "TestModule",
|
|
1237
|
+
transformedMessageDetails: {
|
|
1238
|
+
webpushDeliverySettings: {
|
|
1239
|
+
sendDate: "2023-01-01",
|
|
1240
|
+
priority: "HIGH"
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
};
|
|
1245
|
+
|
|
1246
|
+
const result = transformChannelPayload(mockData, options);
|
|
1247
|
+
|
|
1248
|
+
// Check base payload
|
|
1249
|
+
expect(result.centralCommsPayload.sourceEntityId).toEqual("action-123");
|
|
1250
|
+
expect(result.centralCommsPayload.ouId).toEqual(456);
|
|
1251
|
+
expect(result.centralCommsPayload.clientName).toEqual("TestClient");
|
|
1252
|
+
expect(result.centralCommsPayload.module).toEqual("TestModule");
|
|
1253
|
+
|
|
1254
|
+
// Check WebPush-specific content
|
|
1255
|
+
expect(result.centralCommsPayload.webpushMessageContent.channel).toEqual(WEBPUSH);
|
|
1256
|
+
expect(result.centralCommsPayload.webpushMessageContent.accountId).toEqual(12345);
|
|
1257
|
+
expect(result.centralCommsPayload.webpushMessageContent.messageSubject).toEqual(
|
|
1258
|
+
"test webpush notification"
|
|
1259
|
+
);
|
|
1260
|
+
expect(result.centralCommsPayload.webpushMessageContent.content.title).toEqual(
|
|
1261
|
+
"WebPush Title"
|
|
1262
|
+
);
|
|
1263
|
+
expect(result.centralCommsPayload.webpushMessageContent.content.message).toEqual(
|
|
1264
|
+
"WebPush Message"
|
|
1265
|
+
);
|
|
1266
|
+
expect(result.centralCommsPayload.webpushMessageContent.content.iconImageUrl).toEqual(
|
|
1267
|
+
"https://example.com/icon.png"
|
|
1268
|
+
);
|
|
1269
|
+
expect(result.centralCommsPayload.webpushMessageContent.content.cta).toEqual({
|
|
1270
|
+
actionLink: "https://example.com/action",
|
|
1271
|
+
actionText: "Click Here"
|
|
1272
|
+
});
|
|
1273
|
+
expect(result.centralCommsPayload.webpushMessageContent.content.expandableDetails).toEqual({
|
|
1274
|
+
style: "BIG_TEXT",
|
|
1275
|
+
message: "Expanded Message"
|
|
1276
|
+
});
|
|
1277
|
+
expect(result.centralCommsPayload.webpushMessageContent.offers).toEqual([
|
|
1278
|
+
{ id: "offer-1", title: "Offer 1" },
|
|
1279
|
+
{ id: "offer-2", title: "Offer 2" }
|
|
1280
|
+
]);
|
|
1281
|
+
|
|
1282
|
+
// Check delivery settings
|
|
1283
|
+
expect(result.centralCommsPayload.webpushDeliverySettings).toEqual({
|
|
1284
|
+
sendDate: "2023-01-01",
|
|
1285
|
+
priority: "HIGH"
|
|
1286
|
+
});
|
|
1287
|
+
});
|
|
1288
|
+
|
|
1289
|
+
it("should handle missing messageContent structure", () => {
|
|
1290
|
+
const mockData = {
|
|
1291
|
+
channel: WEBPUSH,
|
|
1292
|
+
messageSubject: "test webpush notification"
|
|
1293
|
+
};
|
|
1294
|
+
|
|
1295
|
+
const result = transformChannelPayload(mockData);
|
|
1296
|
+
|
|
1297
|
+
expect(result.centralCommsPayload.webpushMessageContent.accountId).toEqual(0);
|
|
1298
|
+
expect(result.centralCommsPayload.webpushMessageContent.content.title).toEqual("");
|
|
1299
|
+
expect(result.centralCommsPayload.webpushMessageContent.content.message).toEqual("");
|
|
1300
|
+
expect(result.centralCommsPayload.webpushMessageContent.offers).toEqual([]);
|
|
1301
|
+
});
|
|
1302
|
+
|
|
1303
|
+
it("should handle missing content properties", () => {
|
|
1304
|
+
const mockData = {
|
|
1305
|
+
channel: WEBPUSH,
|
|
1306
|
+
messageSubject: "test webpush notification",
|
|
1307
|
+
messageContent: {
|
|
1308
|
+
content: {
|
|
1309
|
+
accountId: 12345,
|
|
1310
|
+
content: {}
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
};
|
|
1314
|
+
|
|
1315
|
+
const result = transformChannelPayload(mockData);
|
|
1316
|
+
|
|
1317
|
+
expect(result.centralCommsPayload.webpushMessageContent.accountId).toEqual(12345);
|
|
1318
|
+
expect(result.centralCommsPayload.webpushMessageContent.content.title).toEqual("");
|
|
1319
|
+
expect(result.centralCommsPayload.webpushMessageContent.content.message).toEqual("");
|
|
1320
|
+
expect(result.centralCommsPayload.webpushMessageContent.content.iconImageUrl).toBeUndefined();
|
|
1321
|
+
expect(result.centralCommsPayload.webpushMessageContent.content.cta).toBeUndefined();
|
|
1322
|
+
expect(result.centralCommsPayload.webpushMessageContent.content.expandableDetails).toBeUndefined();
|
|
1323
|
+
});
|
|
1324
|
+
|
|
1325
|
+
it("should conditionally include iconImageUrl only when present", () => {
|
|
1326
|
+
const mockDataWithoutIcon = {
|
|
1327
|
+
channel: WEBPUSH,
|
|
1328
|
+
messageSubject: "test",
|
|
1329
|
+
messageContent: {
|
|
1330
|
+
content: {
|
|
1331
|
+
content: {
|
|
1332
|
+
title: "Title",
|
|
1333
|
+
message: "Message"
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
};
|
|
1338
|
+
|
|
1339
|
+
const resultWithoutIcon = transformChannelPayload(mockDataWithoutIcon);
|
|
1340
|
+
expect(resultWithoutIcon.centralCommsPayload.webpushMessageContent.content.iconImageUrl).toBeUndefined();
|
|
1341
|
+
|
|
1342
|
+
const mockDataWithIcon = {
|
|
1343
|
+
channel: WEBPUSH,
|
|
1344
|
+
messageSubject: "test",
|
|
1345
|
+
messageContent: {
|
|
1346
|
+
content: {
|
|
1347
|
+
content: {
|
|
1348
|
+
title: "Title",
|
|
1349
|
+
message: "Message",
|
|
1350
|
+
iconImageUrl: "https://example.com/icon.png"
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
};
|
|
1355
|
+
|
|
1356
|
+
const resultWithIcon = transformChannelPayload(mockDataWithIcon);
|
|
1357
|
+
expect(resultWithIcon.centralCommsPayload.webpushMessageContent.content.iconImageUrl).toEqual(
|
|
1358
|
+
"https://example.com/icon.png"
|
|
1359
|
+
);
|
|
1360
|
+
});
|
|
1361
|
+
|
|
1362
|
+
it("should conditionally include cta only when present", () => {
|
|
1363
|
+
const mockDataWithoutCta = {
|
|
1364
|
+
channel: WEBPUSH,
|
|
1365
|
+
messageSubject: "test",
|
|
1366
|
+
messageContent: {
|
|
1367
|
+
content: {
|
|
1368
|
+
content: {
|
|
1369
|
+
title: "Title",
|
|
1370
|
+
message: "Message"
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
};
|
|
1375
|
+
|
|
1376
|
+
const resultWithoutCta = transformChannelPayload(mockDataWithoutCta);
|
|
1377
|
+
expect(resultWithoutCta.centralCommsPayload.webpushMessageContent.content.cta).toBeUndefined();
|
|
1378
|
+
|
|
1379
|
+
const mockDataWithCta = {
|
|
1380
|
+
channel: WEBPUSH,
|
|
1381
|
+
messageSubject: "test",
|
|
1382
|
+
messageContent: {
|
|
1383
|
+
content: {
|
|
1384
|
+
content: {
|
|
1385
|
+
title: "Title",
|
|
1386
|
+
message: "Message",
|
|
1387
|
+
cta: {
|
|
1388
|
+
actionLink: "https://example.com",
|
|
1389
|
+
actionText: "Click"
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
};
|
|
1395
|
+
|
|
1396
|
+
const resultWithCta = transformChannelPayload(mockDataWithCta);
|
|
1397
|
+
expect(resultWithCta.centralCommsPayload.webpushMessageContent.content.cta).toEqual({
|
|
1398
|
+
actionLink: "https://example.com",
|
|
1399
|
+
actionText: "Click"
|
|
1400
|
+
});
|
|
1401
|
+
});
|
|
1402
|
+
|
|
1403
|
+
it("should conditionally include expandableDetails only when present", () => {
|
|
1404
|
+
const mockDataWithoutExpandable = {
|
|
1405
|
+
channel: WEBPUSH,
|
|
1406
|
+
messageSubject: "test",
|
|
1407
|
+
messageContent: {
|
|
1408
|
+
content: {
|
|
1409
|
+
content: {
|
|
1410
|
+
title: "Title",
|
|
1411
|
+
message: "Message"
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
};
|
|
1416
|
+
|
|
1417
|
+
const resultWithoutExpandable = transformChannelPayload(mockDataWithoutExpandable);
|
|
1418
|
+
expect(resultWithoutExpandable.centralCommsPayload.webpushMessageContent.content.expandableDetails).toBeUndefined();
|
|
1419
|
+
|
|
1420
|
+
const mockDataWithExpandable = {
|
|
1421
|
+
channel: WEBPUSH,
|
|
1422
|
+
messageSubject: "test",
|
|
1423
|
+
messageContent: {
|
|
1424
|
+
content: {
|
|
1425
|
+
content: {
|
|
1426
|
+
title: "Title",
|
|
1427
|
+
message: "Message",
|
|
1428
|
+
expandableDetails: {
|
|
1429
|
+
style: "BIG_TEXT",
|
|
1430
|
+
message: "Expanded"
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
};
|
|
1436
|
+
|
|
1437
|
+
const resultWithExpandable = transformChannelPayload(mockDataWithExpandable);
|
|
1438
|
+
expect(resultWithExpandable.centralCommsPayload.webpushMessageContent.content.expandableDetails).toEqual({
|
|
1439
|
+
style: "BIG_TEXT",
|
|
1440
|
+
message: "Expanded"
|
|
1441
|
+
});
|
|
1442
|
+
});
|
|
1443
|
+
|
|
1444
|
+
it("should handle undefined webpushDeliverySettings", () => {
|
|
1445
|
+
const mockData = {
|
|
1446
|
+
channel: WEBPUSH,
|
|
1447
|
+
messageSubject: "test webpush notification"
|
|
1448
|
+
};
|
|
1449
|
+
|
|
1450
|
+
const options = {
|
|
1451
|
+
loyaltyMetaData: {
|
|
1452
|
+
transformedMessageDetails: {}
|
|
1453
|
+
}
|
|
1454
|
+
};
|
|
1455
|
+
|
|
1456
|
+
const result = transformChannelPayload(mockData, options);
|
|
1457
|
+
|
|
1458
|
+
expect(result.centralCommsPayload.webpushDeliverySettings).toEqual({});
|
|
1459
|
+
});
|
|
1460
|
+
|
|
1461
|
+
it("should handle empty offers array", () => {
|
|
1462
|
+
const mockData = {
|
|
1463
|
+
channel: WEBPUSH,
|
|
1464
|
+
messageSubject: "test",
|
|
1465
|
+
messageContent: {
|
|
1466
|
+
content: {
|
|
1467
|
+
content: {
|
|
1468
|
+
title: "Title",
|
|
1469
|
+
message: "Message"
|
|
1470
|
+
},
|
|
1471
|
+
offers: []
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
};
|
|
1475
|
+
|
|
1476
|
+
const result = transformChannelPayload(mockData);
|
|
1477
|
+
|
|
1478
|
+
expect(result.centralCommsPayload.webpushMessageContent.offers).toEqual([]);
|
|
1479
|
+
});
|
|
1480
|
+
});
|
|
1481
|
+
|
|
1185
1482
|
describe("getTemplateDiffState", () => {
|
|
1186
1483
|
it("should return false for unsupported channel", () => {
|
|
1187
1484
|
const result = getTemplateDiffState("UNSUPPORTED_CHANNEL", {}, {});
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
RCS,
|
|
11
11
|
LINE,
|
|
12
12
|
VIBER,
|
|
13
|
+
WEBPUSH,
|
|
13
14
|
EMF,
|
|
14
15
|
VENENO,
|
|
15
16
|
TEXT,
|
|
@@ -63,6 +64,8 @@ export const transformChannelPayload = (data, options = {}) => {
|
|
|
63
64
|
return transformLinePayload(data, options);
|
|
64
65
|
case VIBER:
|
|
65
66
|
return transformViberPayload(data, options);
|
|
67
|
+
case WEBPUSH:
|
|
68
|
+
return transformWebpushPayload(data, options);
|
|
66
69
|
default:
|
|
67
70
|
return data; // Return unchanged for unsupported channels
|
|
68
71
|
}
|
|
@@ -317,6 +320,43 @@ const transformViberPayload = (viberData, options = {}) => {
|
|
|
317
320
|
return payload;
|
|
318
321
|
};
|
|
319
322
|
|
|
323
|
+
/**
|
|
324
|
+
* Transforms WebPush data to the required payload format
|
|
325
|
+
* @param {Object} webpushData - Current WebPush data
|
|
326
|
+
* @param {Object} options - Additional options (ouId, sourceEntityId, etc.)
|
|
327
|
+
* @returns {Object} - Transformed WebPush payload
|
|
328
|
+
*/
|
|
329
|
+
const transformWebpushPayload = (webpushData, options = {}) => {
|
|
330
|
+
const { loyaltyMetaData = {} } = options;
|
|
331
|
+
const { transformedMessageDetails = {} } = loyaltyMetaData;
|
|
332
|
+
const { webpushDeliverySettings = {} } = transformedMessageDetails || {};
|
|
333
|
+
|
|
334
|
+
// Get base payload structure
|
|
335
|
+
const payload = createBasePayload(WEBPUSH, loyaltyMetaData);
|
|
336
|
+
|
|
337
|
+
// Extract webpush content from messageContent.content.content structure
|
|
338
|
+
const webpushContent = webpushData?.messageContent?.content?.content || {};
|
|
339
|
+
const accountId = webpushData?.messageContent?.content?.accountId || 0;
|
|
340
|
+
|
|
341
|
+
// Add WebPush-specific properties
|
|
342
|
+
payload.centralCommsPayload.webpushMessageContent = {
|
|
343
|
+
channel: WEBPUSH,
|
|
344
|
+
accountId,
|
|
345
|
+
content: {
|
|
346
|
+
title: webpushContent?.title || '',
|
|
347
|
+
message: webpushContent?.message || '',
|
|
348
|
+
...(webpushContent?.iconImageUrl && { iconImageUrl: webpushContent.iconImageUrl }),
|
|
349
|
+
...(webpushContent?.cta && { cta: webpushContent.cta }),
|
|
350
|
+
...(webpushContent?.expandableDetails && { expandableDetails: webpushContent.expandableDetails }),
|
|
351
|
+
},
|
|
352
|
+
messageSubject: webpushData?.messageSubject || "",
|
|
353
|
+
offers: webpushData?.messageContent?.content?.offers || [],
|
|
354
|
+
};
|
|
355
|
+
payload.centralCommsPayload.webpushDeliverySettings = webpushDeliverySettings;
|
|
356
|
+
|
|
357
|
+
return payload;
|
|
358
|
+
};
|
|
359
|
+
|
|
320
360
|
// Checks if the template has changed
|
|
321
361
|
export const getTemplateDiffState = (channel, oldData, newData) => {
|
|
322
362
|
switch (channel.toUpperCase()) {
|