@capillarytech/creatives-library 8.0.242-alpha.16 → 8.0.242-alpha.17
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/translations/en.json +4 -3
- package/utils/common.js +6 -0
- package/utils/imageUrlUpload.js +141 -0
- package/utils/transformerUtils.js +42 -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/v2Containers/App/constants.js +5 -0
- package/v2Containers/Cap/tests/__snapshots__/index.test.js.snap +4 -3
- package/v2Containers/CreativesContainer/SlideBoxContent.js +57 -2
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +1 -0
- package/v2Containers/CreativesContainer/constants.js +2 -0
- package/v2Containers/CreativesContainer/index.js +152 -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/Email/index.js +3 -21
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +12 -9
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +8 -6
- package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +100 -75
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +72 -54
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +184 -138
- package/v2Containers/SmsTrai/Create/tests/__snapshots__/index.test.js.snap +16 -12
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +32 -24
- 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 +4 -0
- package/v2Containers/Templates/tests/index.test.js +10 -0
- package/v2Containers/TemplatesV2/index.js +10 -3
- package/v2Containers/TemplatesV2/messages.js +4 -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 +107 -0
- package/v2Containers/WebPush/Create/components/ButtonsLinksSection.js +160 -0
- package/v2Containers/WebPush/Create/components/ButtonsLinksSection.test.js +476 -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 +143 -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 +81 -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 +515 -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 +46 -0
- package/v2Containers/WebPush/Create/hooks/useButtonManagement.js +150 -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 +1135 -0
- package/v2Containers/WebPush/Create/index.scss +134 -0
- package/v2Containers/WebPush/Create/messages.js +203 -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 +23 -0
- package/v2Containers/WebPush/Create/preview/WebPushPreview.js +155 -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 +47 -0
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +141 -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 +81 -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 +351 -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 +909 -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 +943 -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 +94 -0
- package/v2Containers/WebPush/Create/utils/payloadBuilder.test.js +390 -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 +75 -0
- package/v2Containers/WebPush/Create/utils/validation.test.js +283 -0
- package/v2Containers/WebPush/actions.js +60 -0
- package/v2Containers/WebPush/constants.js +128 -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/tests/__snapshots__/index.test.js.snap +528 -396
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/translations/en.json
CHANGED
|
@@ -165,7 +165,7 @@
|
|
|
165
165
|
"creatives.componentsV2.CapDocumentUpload.imageDimenstionDescription": "Dimensions upto: {width}px x {height}px",
|
|
166
166
|
"creatives.componentsV2.CapDocumentUpload.or": "OR",
|
|
167
167
|
"creatives.componentsV2.CapDocumentUpload.uploadComputer": "Select from computer",
|
|
168
|
-
"creatives.componentsV2.CapDocumentUpload.whatsappDocSize": "Size
|
|
168
|
+
"creatives.componentsV2.CapDocumentUpload.whatsappDocSize": "Size up to: {size}",
|
|
169
169
|
"creatives.componentsV2.CapImageUpload.aspectRatio": "Aspect ratio: 1:1",
|
|
170
170
|
"creatives.componentsV2.CapImageUpload.dragAndDrop": "Drag and drop image here",
|
|
171
171
|
"creatives.componentsV2.CapImageUpload.format": "Format: JPEG, JPG, PNG",
|
|
@@ -173,13 +173,13 @@
|
|
|
173
173
|
"creatives.componentsV2.CapImageUpload.imageErrorDesc": "Please upload the image with allowed file extension, size, dimension and aspect ratio",
|
|
174
174
|
"creatives.componentsV2.CapImageUpload.imageGallery": "Gallery",
|
|
175
175
|
"creatives.componentsV2.CapImageUpload.imageReUpload": "Reupload",
|
|
176
|
-
"creatives.componentsV2.CapImageUpload.imageSize": "Size
|
|
176
|
+
"creatives.componentsV2.CapImageUpload.imageSize": "Size up to: 2MB",
|
|
177
177
|
"creatives.componentsV2.CapImageUpload.or": "OR",
|
|
178
178
|
"creatives.componentsV2.CapImageUpload.uploadComputer": "Select from computer",
|
|
179
179
|
"creatives.componentsV2.CapImageUpload.uploadGallery": "Gallery",
|
|
180
180
|
"creatives.componentsV2.CapImageUpload.uploadImageDescription": "The relevant image that complements the message context.",
|
|
181
181
|
"creatives.componentsV2.CapImageUpload.whatsappAspectRatio": "Max aspect ratio: 1.91:1",
|
|
182
|
-
"creatives.componentsV2.CapImageUpload.whatsappImageSize": "Size
|
|
182
|
+
"creatives.componentsV2.CapImageUpload.whatsappImageSize": "Size up to: 5MB",
|
|
183
183
|
"creatives.componentsV2.CapTagList.Cancel": "Cancel",
|
|
184
184
|
"creatives.componentsV2.CapTagList.Ok": "Ok",
|
|
185
185
|
"creatives.componentsV2.CapTagList.all": "All",
|
|
@@ -2022,6 +2022,7 @@
|
|
|
2022
2022
|
"creatives.containersV2.Whatsapp.vietnamese": "Vietnamese",
|
|
2023
2023
|
"creatives.containersV2.Whatsapp.whatsappCreateNotification": "{name} has been sent for approval",
|
|
2024
2024
|
"creatives.containersV2.Whatsapp.zulu": "Zulu",
|
|
2025
|
+
"creatives.containersV2.WebPush.addLabels": "Add labels",
|
|
2025
2026
|
"creatives.containersV2.addLabels": "Add labels",
|
|
2026
2027
|
"creatives.containersV2.appName": "App Name",
|
|
2027
2028
|
"creatives.containersV2.applyNow": "Apply now",
|
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
|
+
|
|
@@ -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,45 @@ 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
|
+
isDefault: webpushData?.messageContent?.content?.isDefault || false,
|
|
346
|
+
storeType: webpushData?.messageContent?.content?.storeType || 'REGISTERED_STORE',
|
|
347
|
+
content: {
|
|
348
|
+
title: webpushContent?.title || '',
|
|
349
|
+
message: webpushContent?.message || '',
|
|
350
|
+
...(webpushContent?.iconImageUrl && { iconImageUrl: webpushContent.iconImageUrl }),
|
|
351
|
+
...(webpushContent?.cta && { cta: webpushContent.cta }),
|
|
352
|
+
...(webpushContent?.expandableDetails && { expandableDetails: webpushContent.expandableDetails }),
|
|
353
|
+
},
|
|
354
|
+
messageSubject: webpushData?.messageSubject || "",
|
|
355
|
+
offers: webpushData?.messageContent?.content?.offers || [],
|
|
356
|
+
};
|
|
357
|
+
payload.centralCommsPayload.webpushDeliverySettings = webpushDeliverySettings;
|
|
358
|
+
|
|
359
|
+
return payload;
|
|
360
|
+
};
|
|
361
|
+
|
|
320
362
|
// Checks if the template has changed
|
|
321
363
|
export const getTemplateDiffState = (channel, oldData, newData) => {
|
|
322
364
|
switch (channel.toUpperCase()) {
|
|
@@ -17,17 +17,18 @@ import {
|
|
|
17
17
|
CapImage,
|
|
18
18
|
CapError,
|
|
19
19
|
} from '@capillarytech/cap-ui-library';
|
|
20
|
-
import { injectIntl, FormattedMessage, intlShape} from 'react-intl';
|
|
20
|
+
import { injectIntl, FormattedMessage, intlShape } from 'react-intl';
|
|
21
21
|
import { isEmpty, get } from 'lodash';
|
|
22
22
|
import './index.scss';
|
|
23
23
|
import Gallery from '../../v2Containers/Assets/Gallery';
|
|
24
24
|
import { MAX_SUPPORTED_IMAGE_SIZE } from './constants';
|
|
25
25
|
import {
|
|
26
|
-
FACEBOOK, INAPP, RCS, WHATSAPP, VIBER,
|
|
26
|
+
FACEBOOK, INAPP, RCS, WHATSAPP, VIBER, WEBPUSH, WEBPUSH_BRAND_ICON
|
|
27
27
|
} from "../../v2Containers/CreativesContainer/constants";
|
|
28
28
|
|
|
29
29
|
import messages from './messages';
|
|
30
30
|
import { MOBILEPUSH } from '../CapVideoUpload/constants';
|
|
31
|
+
import { CAP_SPACE_16 } from '@capillarytech/cap-ui-library/styled/variables';
|
|
31
32
|
function CapImageUpload(props) {
|
|
32
33
|
const {
|
|
33
34
|
intl,
|
|
@@ -50,6 +51,8 @@ function CapImageUpload(props) {
|
|
|
50
51
|
channelSpecificStyle,
|
|
51
52
|
showReUploadButton = true,
|
|
52
53
|
disableAutoRestore = false, // New prop to disable automatic restoration
|
|
54
|
+
recommendedDimensions, // Array of {width, height} objects for recommended dimensions
|
|
55
|
+
disabled = false,
|
|
53
56
|
} = props;
|
|
54
57
|
const {
|
|
55
58
|
formatMessage,
|
|
@@ -72,7 +75,7 @@ function CapImageUpload(props) {
|
|
|
72
75
|
const [isImageError, updateImageErrorMessage] = useState(false);
|
|
73
76
|
const [isDrawerRequired, updateDrawerRequirement] = useState(false);
|
|
74
77
|
|
|
75
|
-
const {CapHeadingSpan} = CapHeading;
|
|
78
|
+
const { CapHeadingSpan } = CapHeading;
|
|
76
79
|
const ImageComponent = useCallback(
|
|
77
80
|
() => (
|
|
78
81
|
<>
|
|
@@ -91,7 +94,7 @@ function CapImageUpload(props) {
|
|
|
91
94
|
|
|
92
95
|
const WithLabel = LabelHOC(ImageComponent);
|
|
93
96
|
|
|
94
|
-
const uploadImages = useCallback((e, {files}) => {
|
|
97
|
+
const uploadImages = useCallback((e, { files }) => {
|
|
95
98
|
if (e) {
|
|
96
99
|
e.preventDefault();
|
|
97
100
|
}
|
|
@@ -109,13 +112,13 @@ function CapImageUpload(props) {
|
|
|
109
112
|
height: img.height,
|
|
110
113
|
error: file && (file.size / (1e+6) > 5), // Checking if file exists and its size is greater than 5MB (5 * 10^6 bytes)
|
|
111
114
|
};
|
|
112
|
-
submitAction({file, type: 'image', fileParams}, incorrectFile);
|
|
115
|
+
submitAction({ file, type: 'image', fileParams }, incorrectFile);
|
|
113
116
|
};
|
|
114
117
|
img.onerror = () => {
|
|
115
118
|
const fileParams = {
|
|
116
119
|
error: true,
|
|
117
120
|
};
|
|
118
|
-
submitAction({fileParams}, incorrectFile);
|
|
121
|
+
submitAction({ fileParams }, incorrectFile);
|
|
119
122
|
};
|
|
120
123
|
if (e) {
|
|
121
124
|
const event = e;
|
|
@@ -123,7 +126,7 @@ function CapImageUpload(props) {
|
|
|
123
126
|
}
|
|
124
127
|
}, []);
|
|
125
128
|
|
|
126
|
-
const rcsValidation = useCallback((incorrectFile, data, size, height, width, error) => {
|
|
129
|
+
const rcsValidation = useCallback((incorrectFile, data, size, height, width, error) => {
|
|
127
130
|
if (incorrectFile || size < minImgSize || size > imgSize || height !== imgHeight || width !== imgWidth || error) {
|
|
128
131
|
updateImageErrorMessage(formatMessage(messages.imageErrorDesc));
|
|
129
132
|
} else {
|
|
@@ -146,6 +149,19 @@ function CapImageUpload(props) {
|
|
|
146
149
|
const { height, width, error } = fileParams || {};
|
|
147
150
|
if (channel === RCS) {
|
|
148
151
|
rcsValidation(incorrectFile, data, size, height, width, error);
|
|
152
|
+
} else if ([WEBPUSH, WEBPUSH_BRAND_ICON].includes(channel)) {
|
|
153
|
+
// For WEBPUSH, only validate file extension, size, and format - no dimension validation
|
|
154
|
+
if (incorrectFile || size > imgSize || error) {
|
|
155
|
+
updateImageErrorMessage(formatMessage(messages.imageErrorDesc));
|
|
156
|
+
} else {
|
|
157
|
+
updateImageErrorMessage('');
|
|
158
|
+
uploadAsset(
|
|
159
|
+
data.file,
|
|
160
|
+
data.type,
|
|
161
|
+
data.fileParams,
|
|
162
|
+
index,
|
|
163
|
+
);
|
|
164
|
+
}
|
|
149
165
|
} else if (incorrectFile || size > imgSize || height > imgHeight || width > imgWidth || error) {
|
|
150
166
|
updateImageErrorMessage(formatMessage(messages.imageErrorDesc));
|
|
151
167
|
} else {
|
|
@@ -160,7 +176,7 @@ function CapImageUpload(props) {
|
|
|
160
176
|
}, [isImageError]);
|
|
161
177
|
|
|
162
178
|
const capUploaderCustomRequest = useCallback((uploadData) => {
|
|
163
|
-
uploadImages(undefined, {files: [uploadData.file]});
|
|
179
|
+
uploadImages(undefined, { files: [uploadData.file] });
|
|
164
180
|
}, [uploadImages]);
|
|
165
181
|
|
|
166
182
|
const setDrawerVisibility = useCallback((drawervisibleFlag) => updateDrawerRequirement(drawervisibleFlag), [isDrawerRequired]);
|
|
@@ -181,19 +197,27 @@ function CapImageUpload(props) {
|
|
|
181
197
|
secure_file_path: image, width, height, file_size: size,
|
|
182
198
|
} = get(imageTemplate, 'metaInfo', {});
|
|
183
199
|
updateDrawerRequirement(false);
|
|
184
|
-
|
|
200
|
+
// For WEBPUSH, skip dimension validation - only check extension, size
|
|
201
|
+
if ([WEBPUSH, WEBPUSH_BRAND_ICON].includes(channel)) {
|
|
202
|
+
if (!allowedExtensionsRegex.test(image) || size > imgSize) {
|
|
203
|
+
updateImageErrorMessage(formatMessage(messages.imageErrorDesc));
|
|
204
|
+
} else {
|
|
205
|
+
updateImageErrorMessage('');
|
|
206
|
+
updateImageSrc(image);
|
|
207
|
+
}
|
|
208
|
+
} else if (!allowedExtensionsRegex.test(image) || height > imgHeight || width > imgWidth || size > imgSize) {
|
|
185
209
|
updateImageErrorMessage(formatMessage(messages.imageErrorDesc));
|
|
186
210
|
} else {
|
|
187
211
|
updateImageErrorMessage('');
|
|
188
212
|
updateImageSrc(image);
|
|
189
213
|
}
|
|
190
|
-
}, [isImageError, isDrawerRequired]);
|
|
214
|
+
}, [isImageError, isDrawerRequired, channel, allowedExtensionsRegex, imgSize, formatMessage]);
|
|
191
215
|
|
|
192
216
|
const getGalleryDrawerContent = useCallback(() => {
|
|
193
217
|
const locationGallery = {
|
|
194
218
|
pathname: `/assets`,
|
|
195
219
|
search: '',
|
|
196
|
-
query: !isFullMode ? {type: 'embedded', module: 'library'} : {},
|
|
220
|
+
query: !isFullMode ? { type: 'embedded', module: 'library' } : {},
|
|
197
221
|
};
|
|
198
222
|
return (
|
|
199
223
|
<>
|
|
@@ -230,6 +254,7 @@ function CapImageUpload(props) {
|
|
|
230
254
|
customRequest={capUploaderCustomRequest}
|
|
231
255
|
className="form-builder-dragger grey-background"
|
|
232
256
|
showUploadList={!isImageError}
|
|
257
|
+
disabled={disabled}
|
|
233
258
|
>
|
|
234
259
|
<CapHeading className="dragger-title" type="h7">
|
|
235
260
|
<FormattedMessage {...messages.dragAndDrop} />
|
|
@@ -237,7 +262,7 @@ function CapImageUpload(props) {
|
|
|
237
262
|
<CapHeading className="dragger-or" type="label6">
|
|
238
263
|
<FormattedMessage {...messages.or} />
|
|
239
264
|
</CapHeading>
|
|
240
|
-
<CapButton className="dragger-button upload-image" type="secondary">
|
|
265
|
+
<CapButton className="dragger-button upload-image" type="secondary" disabled={disabled} tabIndex={disabled ? -1 : undefined}>
|
|
241
266
|
<FormattedMessage {...messages.uploadComputer} />
|
|
242
267
|
</CapButton>
|
|
243
268
|
{channel !== WHATSAPP && (
|
|
@@ -245,6 +270,8 @@ function CapImageUpload(props) {
|
|
|
245
270
|
className="dragger-button gallery-select"
|
|
246
271
|
type="secondary"
|
|
247
272
|
onClick={onGalleryClick}
|
|
273
|
+
disabled={disabled}
|
|
274
|
+
tabIndex={disabled ? -1 : undefined}
|
|
248
275
|
>
|
|
249
276
|
<FormattedMessage {...messages.uploadGallery} />
|
|
250
277
|
</CapButton>
|
|
@@ -262,13 +289,15 @@ function CapImageUpload(props) {
|
|
|
262
289
|
className="dragger-button re-upload"
|
|
263
290
|
type="flat"
|
|
264
291
|
onClick={onReUpload}
|
|
265
|
-
style={channelSpecificStyle ? { marginTop:
|
|
292
|
+
style={channelSpecificStyle ? { marginTop: `-${CAP_SPACE_16}` } : {}}
|
|
293
|
+
disabled={disabled}
|
|
294
|
+
tabIndex={disabled ? -1 : undefined}
|
|
266
295
|
>
|
|
267
296
|
<FormattedMessage {...messages.imageReUpload} />
|
|
268
297
|
</CapButton>
|
|
269
298
|
);
|
|
270
299
|
}
|
|
271
|
-
}, [isImageError, imageSrc]);
|
|
300
|
+
}, [isImageError, imageSrc, disabled, showReUploadButton, channel, channelSpecificStyle, capUploaderCustomRequest, onGalleryClick, onReUpload]);
|
|
272
301
|
|
|
273
302
|
return (
|
|
274
303
|
<div style={style} className="cap-custom-image-upload">
|
|
@@ -285,6 +314,8 @@ function CapImageUpload(props) {
|
|
|
285
314
|
type="file"
|
|
286
315
|
onChange={(e) => uploadImages(e, { files: e.target.files })}
|
|
287
316
|
accept={supportedExtensions || "image/*"}
|
|
317
|
+
disabled={disabled}
|
|
318
|
+
tabIndex={disabled ? -1 : undefined}
|
|
288
319
|
/>
|
|
289
320
|
{getImageSection()}
|
|
290
321
|
<CapDrawer
|
|
@@ -305,7 +336,18 @@ function CapImageUpload(props) {
|
|
|
305
336
|
)}
|
|
306
337
|
{![WHATSAPP, INAPP].includes(channel) && (
|
|
307
338
|
<CapHeadingSpan type="label2" className="image-dimension">
|
|
308
|
-
|
|
339
|
+
{[WEBPUSH, WEBPUSH_BRAND_ICON].includes(channel) && recommendedDimensions?.length ? (
|
|
340
|
+
<FormattedMessage
|
|
341
|
+
{...messages.recommendedDimensions}
|
|
342
|
+
values={{
|
|
343
|
+
dimensions: recommendedDimensions
|
|
344
|
+
.map((dim) => `${dim.width} x ${dim.height}px`)
|
|
345
|
+
.join(', '),
|
|
346
|
+
}}
|
|
347
|
+
/>
|
|
348
|
+
) : (
|
|
349
|
+
<FormattedMessage {...messages.imageDimenstionDescription} values={{ width: imgWidth, height: imgHeight }} />
|
|
350
|
+
)}
|
|
309
351
|
</CapHeadingSpan>
|
|
310
352
|
)}
|
|
311
353
|
{channel === FACEBOOK && (
|
|
@@ -328,7 +370,7 @@ function CapImageUpload(props) {
|
|
|
328
370
|
getImageSizeLabel()
|
|
329
371
|
)
|
|
330
372
|
)}
|
|
331
|
-
{[VIBER, INAPP, MOBILEPUSH].includes(channel) && getImageSizeLabel()}
|
|
373
|
+
{[VIBER, INAPP, MOBILEPUSH, WEBPUSH, WEBPUSH_BRAND_ICON].includes(channel) && getImageSizeLabel()}
|
|
332
374
|
<CapHeadingSpan type="label2" className="image-format">
|
|
333
375
|
{channel === INAPP ? <FormattedMessage {...messages.format2} /> : <FormattedMessage {...messages.format} />}
|
|
334
376
|
</CapHeadingSpan>
|
|
@@ -357,6 +399,13 @@ CapImageUpload.propTypes = {
|
|
|
357
399
|
channel: PropTypes.string,
|
|
358
400
|
channelSpecificStyle: PropTypes.bool,
|
|
359
401
|
disableAutoRestore: PropTypes.bool,
|
|
402
|
+
recommendedDimensions: PropTypes.arrayOf(
|
|
403
|
+
PropTypes.shape({
|
|
404
|
+
width: PropTypes.number.isRequired,
|
|
405
|
+
height: PropTypes.number.isRequired,
|
|
406
|
+
})
|
|
407
|
+
),
|
|
408
|
+
disabled: PropTypes.bool,
|
|
360
409
|
};
|
|
361
410
|
|
|
362
411
|
export default injectIntl(CapImageUpload);
|
|
@@ -34,6 +34,10 @@ export default defineMessages({
|
|
|
34
34
|
id: `${scope}.imageDimenstionDescription`,
|
|
35
35
|
defaultMessage: 'Dimensions upto: {width}px x {height}px',
|
|
36
36
|
},
|
|
37
|
+
recommendedDimensions: {
|
|
38
|
+
id: `${scope}.recommendedDimensions`,
|
|
39
|
+
defaultMessage: 'Recommended dimensions: {dimensions}',
|
|
40
|
+
},
|
|
37
41
|
format: {
|
|
38
42
|
id: `${scope}.format`,
|
|
39
43
|
defaultMessage: 'Format: JPEG, JPG, PNG',
|
|
@@ -57,7 +61,7 @@ export default defineMessages({
|
|
|
57
61
|
},
|
|
58
62
|
channelImageSize: {
|
|
59
63
|
id: `${scope}.channelImageSize`,
|
|
60
|
-
defaultMessage: 'Size
|
|
64
|
+
defaultMessage: 'Size up to: {size}MB',
|
|
61
65
|
},
|
|
62
66
|
RcschannelImageSize: {
|
|
63
67
|
id: `${scope}.RcschannelImageSize`,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Default allowed content types for image URL validation
|
|
2
|
+
export const DEFAULT_ALLOWED_CONTENT_TYPES = ['image/jpeg', 'image/jpg', 'image/png'];
|
|
3
|
+
|
|
4
|
+
// Default maximum file size (5MB)
|
|
5
|
+
export const DEFAULT_MAX_SIZE = 5000000;
|
|
6
|
+
|
|
7
|
+
// Default allowed extensions regex
|
|
8
|
+
export const DEFAULT_ALLOWED_EXTENSIONS_REGEX = /\.(jpe?g|png)$/i;
|
|
9
|
+
|
|
10
|
+
// MIME type to file extension mapping
|
|
11
|
+
export const MIME_TYPE_TO_EXTENSION = {
|
|
12
|
+
'image/jpeg': 'jpg',
|
|
13
|
+
'image/jpg': 'jpg',
|
|
14
|
+
'image/png': 'png',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// Default image extension fallback
|
|
18
|
+
export const DEFAULT_IMAGE_EXTENSION = 'png';
|
|
19
|
+
|
|
20
|
+
// Upload status state machine states
|
|
21
|
+
export const UPLOAD_STATUS = {
|
|
22
|
+
IDLE: 'idle',
|
|
23
|
+
UPLOADING: 'uploading',
|
|
24
|
+
WAITING: 'waiting',
|
|
25
|
+
};
|
|
26
|
+
|