@capillarytech/creatives-library 8.0.273 → 8.0.274

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "8.0.273",
4
+ "version": "8.0.274",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Utility functions for uploading images from URLs
3
- *
3
+ *
4
4
  * NOTE: CORS-limited; will be replaced with backend implementation.
5
5
  * Flow currently hidden (not removed) from frontend.
6
6
  */
@@ -13,14 +13,14 @@ import {
13
13
 
14
14
  /**
15
15
  * Fetches an image from a URL
16
- *
16
+ *
17
17
  * @param {string} url - The image URL to fetch
18
18
  * @returns {Promise<Response>} - The fetch response object
19
19
  * @throws {Error} - If the fetch fails (network/CORS error)
20
20
  */
21
21
  export const fetchImageFromUrl = async (url) => {
22
22
  const trimmedUrl = url?.trim() || '';
23
-
23
+
24
24
  if (!trimmedUrl) {
25
25
  throw new Error('URL is required');
26
26
  }
@@ -42,7 +42,7 @@ export const fetchImageFromUrl = async (url) => {
42
42
  /**
43
43
  * Helper function to upload image from URL
44
44
  * Fetches image, validates content type and size, converts to File, and uploads via uploadAsset
45
- *
45
+ *
46
46
  * @param {string} url - The image URL to upload
47
47
  * @param {Function} formatMessage - React Intl formatMessage function
48
48
  * @param {Object} messages - React Intl messages object
@@ -51,7 +51,7 @@ export const fetchImageFromUrl = async (url) => {
51
51
  * @param {number} maxSize - Maximum file size in bytes
52
52
  * @param {string[]} allowedContentTypes - Array of allowed MIME types (defaults to DEFAULT_ALLOWED_CONTENT_TYPES)
53
53
  * @returns {Promise<{success: boolean, error: string}>} - Result object with success status and error message
54
- *
54
+ *
55
55
  * @example
56
56
  * const result = await uploadImageFromUrlHelper(
57
57
  * 'https://example.com/image.jpg',
@@ -73,14 +73,14 @@ export const uploadImageFromUrlHelper = async (
73
73
  allowedContentTypes = DEFAULT_ALLOWED_CONTENT_TYPES,
74
74
  ) => {
75
75
  const trimmedUrl = url?.trim() || '';
76
-
76
+
77
77
  try {
78
78
  const response = await fetchImageFromUrl(trimmedUrl);
79
79
 
80
80
  // Validate Content-Type
81
81
  const contentType = response.headers?.get('Content-Type') || '';
82
82
  const normalizedContentType = contentType.split(';')[0].toLowerCase().trim();
83
-
83
+
84
84
  if (!allowedContentTypes.includes(normalizedContentType)) {
85
85
  return {
86
86
  success: false,
@@ -89,7 +89,7 @@ export const uploadImageFromUrlHelper = async (
89
89
  }
90
90
 
91
91
  const blob = await response.blob();
92
-
92
+
93
93
  if (blob.size > maxSize) {
94
94
  return {
95
95
  success: false,
@@ -101,7 +101,7 @@ export const uploadImageFromUrlHelper = async (
101
101
  return new Promise((resolve) => {
102
102
  const img = new Image();
103
103
  const objectUrl = URL.createObjectURL(blob);
104
-
104
+
105
105
  img.onload = () => {
106
106
  const extension = MIME_TYPE_TO_EXTENSION[normalizedContentType] || DEFAULT_IMAGE_EXTENSION;
107
107
  const fileName = `${fileNamePrefix}.${extension}`;
@@ -111,16 +111,16 @@ export const uploadImageFromUrlHelper = async (
111
111
  height: img.height,
112
112
  error: false,
113
113
  };
114
-
114
+
115
115
  uploadAssetFn(file, 'image', fileParams);
116
116
  URL.revokeObjectURL(objectUrl);
117
-
117
+
118
118
  resolve({
119
119
  success: true,
120
120
  error: '',
121
121
  });
122
122
  };
123
-
123
+
124
124
  img.onerror = () => {
125
125
  URL.revokeObjectURL(objectUrl);
126
126
  resolve({
@@ -128,7 +128,7 @@ export const uploadImageFromUrlHelper = async (
128
128
  error: formatMessage(messages.imageLoadError),
129
129
  });
130
130
  };
131
-
131
+
132
132
  img.src = objectUrl;
133
133
  });
134
134
  } catch (error) {
@@ -138,3 +138,4 @@ export const uploadImageFromUrlHelper = async (
138
138
  };
139
139
  }
140
140
  };
141
+
@@ -26,7 +26,7 @@ import * as globalActions from '../Cap/actions';
26
26
  import './_email.scss';
27
27
  import {getMessageObject} from '../../utils/messageUtils';
28
28
  import EmailPreview from '../../v2Components/EmailPreview';
29
- import { getDecodedFileName ,hasLiquidSupportFeature} from '../../utils/common';
29
+ import { getDecodedFileName, hasLiquidSupportFeature, hasSupportCKEditor } from '../../utils/common';
30
30
  import Pagination from '../../v2Components/Pagination';
31
31
  import * as creativesContainerActions from '../CreativesContainer/actions';
32
32
  import withCreatives from '../../hoc/withCreatives';
@@ -325,6 +325,7 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
325
325
  }
326
326
  if (nextProps.metaEntities && nextProps.metaEntities.layouts && nextProps.metaEntities.layouts.length > 0 && _.isEmpty(this.state.schema)) {
327
327
  const newSchema = this.injectEvents(nextProps.metaEntities.layouts[0].definition);
328
+ this.applyTabOptionIconVisibility(newSchema);
328
329
 
329
330
  this.setState({schema: newSchema, loadingStatus: this.state.loadingStatus + 1});
330
331
  if (this.props.location.query.module !== 'library' || (this.props.location.query.module === 'library' && this.props.getDefaultTags)) {
@@ -1752,6 +1753,16 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
1752
1753
  newTabPopoverSection.cols[0].style.display = isDragDrop ? "" : "none";
1753
1754
  }
1754
1755
  });
1756
+ // Hide tab-option-icon (switch editor trigger) when SUPPORT_CK_EDITOR is disabled
1757
+ if (containerInputFieldCol.value && containerInputFieldCol.value.sections) {
1758
+ _.forEach(containerInputFieldCol.value.sections[0].inputFields, (valueInputField) => {
1759
+ _.forEach(valueInputField.cols, (valueCol) => {
1760
+ if (valueCol.id === 'tab-option-icon') {
1761
+ valueCol.colStyle = { ...valueCol.colStyle, display: hasSupportCKEditor() ? 'flex' : 'none' };
1762
+ }
1763
+ });
1764
+ });
1765
+ }
1755
1766
  }
1756
1767
  });
1757
1768
  }
@@ -1760,6 +1771,28 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
1760
1771
  this.setState({schema, isSchemaChanged: true});
1761
1772
  }
1762
1773
 
1774
+ /**
1775
+ * Hides the tab-option-icon (switch editor trigger) in schema when SUPPORT_CK_EDITOR is disabled,
1776
+ * so users cannot switch editor if the feature is not enabled.
1777
+ */
1778
+ applyTabOptionIconVisibility = (schema) => {
1779
+ if (!schema || !schema.containers) return;
1780
+ _.forEach(schema.containers, (container) => {
1781
+ if (!container.isActive || !container.tabBarExtraContent?.sections?.[0]?.inputFields?.[0]?.cols) return;
1782
+ _.forEach(container.tabBarExtraContent.sections[0].inputFields[0].cols, (col) => {
1783
+ if (col.id === 'tab-options-popover' && col.value?.sections?.[0]?.inputFields) {
1784
+ _.forEach(col.value.sections[0].inputFields, (inputField) => {
1785
+ _.forEach(inputField.cols, (c) => {
1786
+ if (c.id === 'tab-option-icon') {
1787
+ c.colStyle = { ...(c.colStyle || {}), display: hasSupportCKEditor() ? 'flex' : 'none' };
1788
+ }
1789
+ });
1790
+ });
1791
+ }
1792
+ });
1793
+ });
1794
+ };
1795
+
1763
1796
  showInsertImageButton = (passedSchema) => {
1764
1797
  const schema = passedSchema || _.cloneDeep(this.state.schema);
1765
1798
  _.forEach(schema.containers, (container) => {