@capillarytech/creatives-library 7.17.105 → 7.17.106

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": "7.17.105",
4
+ "version": "7.17.106",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
package/services/api.js CHANGED
@@ -304,7 +304,18 @@ export const deleteAssetById = ({assetId, assetType}) => {
304
304
 
305
305
  export const uploadFile = ({file, assetType, fileParams, mode, wechatParams, whatsappParams}) => {
306
306
  const data = new FormData();
307
- data.append('file', file);
307
+ let fileName = '';
308
+ try {
309
+ fileName = encodeURIComponent(file?.name || '');
310
+ } catch (error) {
311
+ fileName = file?.name || '';
312
+ }
313
+ // Creating a new File object with the modified filename
314
+ const modifiedFile = new File([file], fileName, {
315
+ type: file?.type,
316
+ });
317
+ // Append the modified file to the FormData object
318
+ data.append('file', modifiedFile);
308
319
  data.append('fileParam', JSON.stringify(fileParams));
309
320
  if (mode) {
310
321
  data.append('mode', mode);
@@ -38,6 +38,25 @@ describe('uploadFile -- whatsapp image upload', () => {
38
38
  },
39
39
  }),
40
40
  ).toEqual(Promise.resolve()));
41
+
42
+ it('Uploads the file with the original filename when encodeURIComponent fails', async () => {
43
+ // Mocking the encodeURIComponent function to throw an error
44
+ global.encodeURIComponent = jest.fn(() => { throw new Error('encodeURIComponent error'); });
45
+ const blob = new Blob([''], { type: 'image/jpeg' });
46
+ const file = new File([blob], '@%test.jpeg', { type: 'image/jpeg' });
47
+ expect(
48
+ uploadFile({
49
+ file,
50
+ assetType: 'image',
51
+ fileParams: {
52
+ width: 275,
53
+ height: 183,
54
+ error: false,
55
+ },
56
+ whatsappParams: {},
57
+ }),
58
+ ).toEqual(Promise.resolve());
59
+ });
41
60
  });
42
61
 
43
62
  describe('createWhatsappTemplate -- Test with valid responses', () => {
package/utils/common.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import _ from 'lodash';
2
+ import Bugsnag from '@bugsnag/js';
2
3
  import { Auth } from '@capillarytech/cap-ui-utils';
3
4
  import {
4
5
  STORE2DOOR_PLUS_ENABLED,
@@ -427,4 +428,22 @@ export const handleInjectedData = (data, scope) => {
427
428
 
428
429
  export const handlePreviewInNewTab = (previewUrl) => {
429
430
  window.open(previewUrl, '_blank');
430
- }
431
+ };
432
+
433
+ export const getDecodedFileName = (templateName = '') => {
434
+ try {
435
+ return decodeURIComponent(templateName);
436
+ } catch (error) {
437
+ // If decoding fails due to URIError, using the original encoded filename
438
+ if (error instanceof URIError) {
439
+ return templateName;
440
+ } else {
441
+ // For other errors, registering the exception in Bugsnag
442
+ Bugsnag.leaveBreadcrumb("Error decoding the string:", error);
443
+ Bugsnag.notify(error, (event) => {
444
+ event.severity = "error";
445
+ });
446
+ }
447
+ }
448
+ return templateName;
449
+ };
@@ -1,19 +1,29 @@
1
1
  import React from 'react';
2
+ import Bugsnag from '@bugsnag/js';
2
3
  import { FormattedMessage } from 'react-intl';
3
4
  import "@testing-library/jest-dom";
4
- import { filterTags, getTreeStructuredTags, handleInjectedData, intlKeyGenerator, bytes2Size, getUserNameById, iframePreviewAdjustWidth } from "../common";
5
+ import {
6
+ filterTags,
7
+ getTreeStructuredTags,
8
+ handleInjectedData,
9
+ intlKeyGenerator,
10
+ bytes2Size,
11
+ getUserNameById,
12
+ iframePreviewAdjustWidth,
13
+ getDecodedFileName
14
+ } from "../common";
5
15
  import * as mockdata from "./common.mockdata";
6
16
 
7
17
  describe("getTreeStructuredTags test", () => {
8
18
  it("test for getTreeStructuredTags when tagsList is not empty", () => {
9
- expect(getTreeStructuredTags({tagsList: mockdata.tagsList})).toEqual(mockdata.output1);
19
+ expect(getTreeStructuredTags({ tagsList: mockdata.tagsList })).toEqual(mockdata.output1);
10
20
  });
11
21
  it("test for getTreeStructuredTags when tagsList is empty", () => {
12
- expect(getTreeStructuredTags({tagsList: []})).toEqual([]);
22
+ expect(getTreeStructuredTags({ tagsList: [] })).toEqual([]);
13
23
  });
14
24
 
15
25
  it("test for getTreeStructuredTags when incentive attached is BADGES", () => {
16
- expect(getTreeStructuredTags({tagsList: mockdata.badgesTags, offerDetails: mockdata.offer})).toEqual(mockdata.expectedOffer);
26
+ expect(getTreeStructuredTags({ tagsList: mockdata.badgesTags, offerDetails: mockdata.offer })).toEqual(mockdata.expectedOffer);
17
27
  });
18
28
  it("test for filterTags", () => {
19
29
  expect(filterTags(mockdata.tagsToFilter, mockdata.tagsList)).toEqual([mockdata.tagsList[1]]);
@@ -22,7 +32,7 @@ describe("getTreeStructuredTags test", () => {
22
32
  expect(filterTags([], [])).toEqual([]);
23
33
  });
24
34
  it("test for getTreeStructuredTags when incentive attached is offer", () => {
25
- expect(getTreeStructuredTags({tagsList: mockdata.OfferTag, offerDetails: [{id: '12', couponName: 'mac'}]})).toEqual(mockdata.offerOutput);
35
+ expect(getTreeStructuredTags({ tagsList: mockdata.OfferTag, offerDetails: [{ id: '12', couponName: 'mac' }] })).toEqual(mockdata.offerOutput);
26
36
  });
27
37
  });
28
38
 
@@ -221,3 +231,43 @@ describe('iframeAdjustWidth', () => {
221
231
  expect(iframePreviewAdjustWidth(data)).toBe("<html><head></head><body>[object Object]</body></html>");
222
232
  });
223
233
  });
234
+
235
+ describe('getDecodedFileName function', () => {
236
+ it('Returns an empty string when templateName is undefined', () => {
237
+ expect(getDecodedFileName()).toEqual('');
238
+ });
239
+
240
+ it('Returns the decoded filename from encoded filename', () => {
241
+ expect(getDecodedFileName('%24Test.jpeg')).toEqual('$Test.jpeg');
242
+ expect(getDecodedFileName('cap%24.logo.%23.jpg')).toEqual('cap$.logo.#.jpg');
243
+ expect(getDecodedFileName("%24L_i%40n%26e__%60AL%60L%2BI'ma_g__e%2Bco_pyAI____Copy____Copy_wek1SeS0.jpg")).toEqual("$L_i@n&e__`AL`L+I'ma_g__e+co_pyAI____Copy____Copy_wek1SeS0.jpg");
244
+ expect(getDecodedFileName('test.jpeg')).toEqual('test.jpeg');
245
+ });
246
+
247
+ it('Returns the original filename when decoding fails due to URIError', () => {
248
+ const fileName = '@Test%ZZ.jpeg';
249
+ expect(getDecodedFileName(fileName)).toEqual(fileName);
250
+ });
251
+
252
+ it('Returns the original filename and notifies Bugsnag for other decoding errors', () => {
253
+ // Mocking Bugsnag methods for testing
254
+ const originalLeaveBreadcrumb = Bugsnag.leaveBreadcrumb;
255
+ const originalNotify = Bugsnag.notify;
256
+ Bugsnag.leaveBreadcrumb = jest.fn();
257
+ Bugsnag.notify = jest.fn((error, callback) => {
258
+ const event = {};
259
+ callback(event);
260
+ expect(event.severity).toEqual("error");
261
+ });
262
+ const fileName = '@Test%20ZZ.jpg';
263
+ const error = new Error('Some other decoding error');
264
+ // Mocking decodeURIComponent to throw the error
265
+ global.decodeURIComponent = jest.fn(() => { throw error; });
266
+
267
+ expect(getDecodedFileName(fileName)).toEqual(fileName);
268
+ expect(Bugsnag.notify).toHaveBeenCalled();
269
+ // Restoring original Bugsnag methods
270
+ Bugsnag.leaveBreadcrumb = originalLeaveBreadcrumb;
271
+ Bugsnag.notify = originalNotify;
272
+ });
273
+ });
@@ -18,7 +18,7 @@ import {
18
18
  CapSpin,
19
19
  } from '@capillarytech/cap-ui-library';
20
20
  import messages from './messages';
21
- import {bytes2Size} from '../../utils/common';
21
+ import {bytes2Size, getDecodedFileName} from '../../utils/common';
22
22
  import { WHATSAPP } from './constants';
23
23
  import './index.scss';
24
24
 
@@ -265,7 +265,7 @@ function CapVideoUpload(props) {
265
265
  {showVideoNameAndDuration &&
266
266
  <div className="video-info">
267
267
  <CapHeading type="h6">
268
- {videoName}
268
+ {getDecodedFileName(videoName)}
269
269
  </CapHeading>
270
270
  <CapHeading type="h6">
271
271
  {videoDuration}
@@ -307,6 +307,7 @@ export class Gallery extends React.Component { // eslint-disable-line react/pref
307
307
  const currentChannel = 'gallery';
308
308
  const { searchLoader, searchText } = this.state;
309
309
  const cardDataList = templates?.length ? _.map(templates, (template) => {
310
+ template.name = commonUtil.getDecodedFileName(template?.name);
310
311
  const templateData =
311
312
  {
312
313
  key: `${currentChannel}-card-${template.name}`,
@@ -25,6 +25,7 @@ import messages from './messages';
25
25
  import './_email.scss';
26
26
  import {getMessageObject} from '../../utils/messageUtils';
27
27
  import EmailPreview from '../../v2Components/EmailPreview';
28
+ import { getDecodedFileName } from '../../utils/common';
28
29
 
29
30
  import Pagination from '../../v2Components/Pagination';
30
31
  import * as creativesContainerActions from '../CreativesContainer/actions';
@@ -2448,6 +2449,7 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
2448
2449
  getTemplateDataForGrid = ({templates, handlers, isLoading, loadingTip}) => {
2449
2450
  const currentChannel = 'gallery';
2450
2451
  const cardDataList = templates.length ? _.map(templates, (template) => {
2452
+ template.name = getDecodedFileName(template?.name);
2451
2453
  const templateData =
2452
2454
  {
2453
2455
  key: `${currentChannel}-card-${template.name}`,
@@ -11,6 +11,7 @@ import CapHeader from '@capillarytech/cap-ui-library/CapHeader';
11
11
  import CapError from '@capillarytech/cap-ui-library/CapError';
12
12
  import CapRadioGroup from '@capillarytech/cap-ui-library/CapRadioGroup';
13
13
  import { isUrl } from '../Wrapper/utils';
14
+ import { getDecodedFileName } from '../../../../utils/common';
14
15
  import LineDrawer from '../Drawer';
15
16
  import { CAP_SPACE_12, CAP_SPACE_08, FONT_COLOR_05, CAP_SPACE_24, CAP_SPACE_04 } from '@capillarytech/cap-ui-library/styled/variables';
16
17
  import style from './style';
@@ -414,7 +415,7 @@ export const LineVideo = ({
414
415
  </video>
415
416
  <div style={{ marginLeft: CAP_SPACE_24 }}>
416
417
  <CapHeading type="h6">
417
- {videoName}
418
+ {getDecodedFileName(videoName)}
418
419
  </CapHeading>
419
420
  <CapHeading type="h6">
420
421
  {videoDuration}
@@ -23,6 +23,7 @@ import {
23
23
  import './styles.scss';
24
24
  import pdfIcon from "../../assets/pdfIcon.svg";
25
25
  import messages from './messages';
26
+ import { getDecodedFileName } from '../../utils/common';
26
27
 
27
28
  export function bytesConversion(x) {
28
29
  // the function accepts bytes and convert in appropriate size following the,
@@ -47,7 +48,7 @@ export const getWhatsappDocPreview = (whatsappDocParams) => {
47
48
  <CapImage src={pdfIcon} />
48
49
  <div className="pdf-info">
49
50
  <div className="pdf-name-div">
50
- <CapLabel type="label9" className="pdf-name">{whatsappDocName}</CapLabel>
51
+ <CapLabel type="label9" className="pdf-name">{getDecodedFileName(whatsappDocName)}</CapLabel>
51
52
  </div>
52
53
  <CapLabel className="pdf-info-sec">
53
54
  {whatsappDocPages} {whatsappDocPages > 1 ? <FormattedMessage {...messages.pages} /> : <FormattedMessage {...messages.page} />}{` · ${bytesConversion(whatsappDocParams?.whatsappDocSize)} · `}