@capillarytech/creatives-library 8.0.143 → 8.0.145
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 +1 -1
- package/v2Components/MobilePushPreviewV2/index.js +2 -2
- package/v2Components/TemplatePreview/index.js +4 -4
- package/v2Components/TestAndPreviewSlidebox/tests/PreviewSection.test.js +99 -0
- package/v2Containers/CreativesContainer/index.js +56 -12
- package/v2Containers/Line/Container/Text/index.js +6 -6
- package/v2Containers/Templates/_templates.scss +0 -3
- package/v2Containers/Templates/index.js +4 -4
- package/assets/loading_img.gif +0 -0
package/package.json
CHANGED
|
@@ -87,8 +87,8 @@ class MobilePushPreviewV2 extends React.Component { // eslint-disable-line react
|
|
|
87
87
|
|
|
88
88
|
if (media?.length > 0) {
|
|
89
89
|
const mediaItem = media[0];
|
|
90
|
-
const { type, url } = mediaItem;
|
|
91
|
-
if (
|
|
90
|
+
const { type: mediaType, url } = mediaItem;
|
|
91
|
+
if (mediaType === VIDEO) {
|
|
92
92
|
// Distinguish between actual video and GIF based on URL extension
|
|
93
93
|
if (url && url?.toLowerCase()?.includes('.gif')) {
|
|
94
94
|
bodyGif = url;
|
|
@@ -182,17 +182,17 @@ export class TemplatePreview extends React.Component { // eslint-disable-line re
|
|
|
182
182
|
key={`carousel-card-${idx}`}
|
|
183
183
|
className="mobile-push-carousel-card message-pop align-left message-pop-carousel"
|
|
184
184
|
>
|
|
185
|
-
{item?.mediaType === IMAGE
|
|
185
|
+
{item?.mediaType?.toLowerCase() === IMAGE && (item?.imageUrl || item?.url) && (
|
|
186
186
|
<CapImage
|
|
187
|
-
src={item?.imageUrl}
|
|
187
|
+
src={item?.imageUrl || item?.url}
|
|
188
188
|
alt="carousel-img"
|
|
189
189
|
className="carousel-image"
|
|
190
190
|
/>
|
|
191
191
|
)}
|
|
192
|
-
{item?.mediaType === VIDEO
|
|
192
|
+
{item?.mediaType?.toLowerCase() === VIDEO && item?.videoPreviewImg && (
|
|
193
193
|
<CapRow className="video-preview">
|
|
194
194
|
<CapImage
|
|
195
|
-
src={item?.videoPreviewImg}
|
|
195
|
+
src={item?.videoPreviewImg || item?.url}
|
|
196
196
|
alt="carousel-video-preview"
|
|
197
197
|
className="carousel-video-preview"
|
|
198
198
|
/>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { IntlProvider } from 'react-intl';
|
|
4
|
+
import PropTypes from 'prop-types';
|
|
5
|
+
import '@testing-library/jest-dom';
|
|
6
|
+
import PreviewSection from '../PreviewSection';
|
|
7
|
+
|
|
8
|
+
// Mock messages for testing
|
|
9
|
+
const mockMessages = {
|
|
10
|
+
'app.v2Components.TestAndPreviewSlidebox.updatingPreview': 'Updating preview with the latest changes',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// Test wrapper with IntlProvider
|
|
14
|
+
const TestWrapper = ({ children, locale = 'en' }) => (
|
|
15
|
+
<IntlProvider locale={locale} messages={mockMessages}>
|
|
16
|
+
{children}
|
|
17
|
+
</IntlProvider>
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
TestWrapper.propTypes = {
|
|
21
|
+
children: PropTypes.node.isRequired,
|
|
22
|
+
locale: PropTypes.string,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
TestWrapper.defaultProps = {
|
|
26
|
+
locale: 'en',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Mock PreviewChrome component
|
|
30
|
+
const MockPreviewChrome = ({
|
|
31
|
+
children,
|
|
32
|
+
device,
|
|
33
|
+
subject,
|
|
34
|
+
}) => (
|
|
35
|
+
<div data-testid="preview-chrome" data-device={device} data-subject={subject}>
|
|
36
|
+
{children}
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
MockPreviewChrome.propTypes = {
|
|
41
|
+
children: PropTypes.node,
|
|
42
|
+
device: PropTypes.string,
|
|
43
|
+
subject: PropTypes.string,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
MockPreviewChrome.defaultProps = {
|
|
47
|
+
children: null,
|
|
48
|
+
device: 'desktop',
|
|
49
|
+
subject: '',
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Default props for testing
|
|
53
|
+
const defaultProps = {
|
|
54
|
+
previewDevice: 'desktop',
|
|
55
|
+
setPreviewDevice: jest.fn(),
|
|
56
|
+
selectedCustomer: { id: 'customer-1', name: 'John Doe' },
|
|
57
|
+
formData: { 'template-subject': 'Test Email Subject' },
|
|
58
|
+
isUpdatingPreview: false,
|
|
59
|
+
previewDataHtml: null,
|
|
60
|
+
content: '<p>Default email content</p>',
|
|
61
|
+
formatMessage: jest.fn((msg) => msg.defaultMessage || 'Updating preview with the latest changes'),
|
|
62
|
+
PreviewChrome: MockPreviewChrome,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
describe('PreviewSection Component', () => {
|
|
66
|
+
beforeEach(() => {
|
|
67
|
+
jest.clearAllMocks();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should render the component with basic structure', () => {
|
|
71
|
+
render(
|
|
72
|
+
<TestWrapper>
|
|
73
|
+
<PreviewSection {...defaultProps} />
|
|
74
|
+
</TestWrapper>
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// Check if the main container is rendered
|
|
78
|
+
expect(screen.getByTestId('preview-chrome')).toBeInTheDocument();
|
|
79
|
+
|
|
80
|
+
// Check if PreviewChrome receives the correct props
|
|
81
|
+
const previewChrome = screen.getByTestId('preview-chrome');
|
|
82
|
+
expect(previewChrome).toHaveAttribute('data-device', 'desktop');
|
|
83
|
+
expect(previewChrome).toHaveAttribute('data-subject', 'Test Email Subject');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should show loading spinner when updating preview', () => {
|
|
87
|
+
render(
|
|
88
|
+
<TestWrapper>
|
|
89
|
+
<PreviewSection {...defaultProps} isUpdatingPreview />
|
|
90
|
+
</TestWrapper>
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
// Check if loading container is displayed
|
|
94
|
+
expect(document.querySelector('.loading-container')).toBeInTheDocument();
|
|
95
|
+
|
|
96
|
+
// Check if CapSpin component is rendered (ant-spin class)
|
|
97
|
+
expect(document.querySelector('.ant-spin')).toBeInTheDocument();
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -363,16 +363,16 @@ export class Creatives extends React.Component {
|
|
|
363
363
|
const iosContent = { ...(templateData?.iosContent || {}) };
|
|
364
364
|
if (androidCarouselMedia?.length) {
|
|
365
365
|
androidContent.expandableDetails.carouselData = androidCarouselMedia.map((media) => ({
|
|
366
|
-
mediaType: media
|
|
367
|
-
imageUrl: media
|
|
366
|
+
mediaType: media?.type,
|
|
367
|
+
imageUrl: media?.url,
|
|
368
368
|
buttons: [],
|
|
369
369
|
videoSrc: '',
|
|
370
370
|
}));
|
|
371
371
|
}
|
|
372
372
|
if (iosCarouselMedia?.length) {
|
|
373
373
|
iosContent.expandableDetails.carouselData = iosCarouselMedia.map((media) => ({
|
|
374
|
-
mediaType: media
|
|
375
|
-
imageUrl: media
|
|
374
|
+
mediaType: media?.type,
|
|
375
|
+
imageUrl: media?.url,
|
|
376
376
|
buttons: [],
|
|
377
377
|
videoSrc: '',
|
|
378
378
|
}));
|
|
@@ -398,8 +398,22 @@ export class Creatives extends React.Component {
|
|
|
398
398
|
versions: {
|
|
399
399
|
base: {
|
|
400
400
|
content: {
|
|
401
|
-
ANDROID: templateData?.androidContent
|
|
402
|
-
|
|
401
|
+
ANDROID: templateData?.androidContent?.type === 'HTML' ? {
|
|
402
|
+
type: templateData?.androidContent?.type,
|
|
403
|
+
bodyType: templateData?.androidContent?.bodyType,
|
|
404
|
+
deviceType: constants.ANDROID,
|
|
405
|
+
beeHtml: { value: templateData?.androidContent?.message },
|
|
406
|
+
beeJson: templateData?.androidContent?.expandableDetails?.message,
|
|
407
|
+
isBEEeditor: true,
|
|
408
|
+
} : templateData?.androidContent,
|
|
409
|
+
IOS: templateData?.iosContent?.type === 'HTML' ? {
|
|
410
|
+
type: templateData?.iosContent?.type,
|
|
411
|
+
bodyType: templateData?.iosContent?.bodyType,
|
|
412
|
+
deviceType: constants.IOS,
|
|
413
|
+
beeHtml: { value: templateData?.iosContent?.message },
|
|
414
|
+
beeJson: templateData?.iosContent?.expandableDetails?.message,
|
|
415
|
+
isBEEeditor: true,
|
|
416
|
+
} : templateData?.iosContent,
|
|
403
417
|
},
|
|
404
418
|
},
|
|
405
419
|
},
|
|
@@ -801,9 +815,24 @@ export class Creatives extends React.Component {
|
|
|
801
815
|
if (channel === constants.MOBILE_PUSH && androidContent?.expandableDetails?.carouselData?.length) {
|
|
802
816
|
androidContent.expandableDetails = this.getMobilePushCarouselData({...androidContent?.expandableDetails});
|
|
803
817
|
}
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
818
|
+
if (androidContent?.isBEEeditor && androidContent?.beeHtml?.value) {
|
|
819
|
+
templateData.androidContent = {};
|
|
820
|
+
templateData.androidContent.type = 'TEXT';
|
|
821
|
+
// replace the TEXT in above line when backend supports HTML
|
|
822
|
+
templateData.androidContent.message = androidContent?.beeHtml?.value || '';
|
|
823
|
+
templateData.androidContent.title = 'bee free template';
|
|
824
|
+
templateData.androidContent.bodyType = androidContent?.bodyType;
|
|
825
|
+
templateData.androidContent.deviceType = constants.ANDROID;
|
|
826
|
+
templateData.androidContent.expandableDetails = {
|
|
827
|
+
style: 'BIG_TEXT',
|
|
828
|
+
// replace the BIG_TEXT in above line when backend supports HTML
|
|
829
|
+
message: androidContent?.beeJson || '',
|
|
830
|
+
};
|
|
831
|
+
} else if (!androidContent?.isBEEeditor) {
|
|
832
|
+
templateData.androidContent = androidContent;
|
|
833
|
+
templateData.androidContent.type = androidContent?.type || get(channelTemplate, 'definition.mode', '')?.toUpperCase() || constants.TEXT;
|
|
834
|
+
templateData.androidContent.deviceType = constants.ANDROID;
|
|
835
|
+
}
|
|
807
836
|
}
|
|
808
837
|
const iosContent = channel === constants.INAPP ? get(channelTemplate, 'versions.base.content.IOS') : get(channelTemplate, 'versions.base.IOS');
|
|
809
838
|
if (!isEmpty(iosContent)) {
|
|
@@ -823,9 +852,24 @@ export class Creatives extends React.Component {
|
|
|
823
852
|
if (channel === constants.MOBILE_PUSH && iosContent?.expandableDetails?.carouselData?.length) {
|
|
824
853
|
iosContent.expandableDetails = this.getMobilePushCarouselData({...iosContent?.expandableDetails});
|
|
825
854
|
}
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
855
|
+
if (iosContent?.isBEEeditor && iosContent?.beeHtml?.value) {
|
|
856
|
+
templateData.iosContent = {};
|
|
857
|
+
templateData.iosContent.type = 'TEXT';
|
|
858
|
+
// replace the TEXT in above line when backend supports HTML
|
|
859
|
+
templateData.iosContent.message = iosContent?.beeHtml?.value || '';
|
|
860
|
+
templateData.iosContent.title = 'bee free template';
|
|
861
|
+
templateData.iosContent.bodyType = iosContent?.bodyType;
|
|
862
|
+
templateData.iosContent.deviceType = constants.IOS;
|
|
863
|
+
templateData.iosContent.expandableDetails = {
|
|
864
|
+
style: 'BIG_TEXT',
|
|
865
|
+
// replace the BIG_TEXT in above line when backend supports HTML
|
|
866
|
+
message: iosContent?.beeJson || '',
|
|
867
|
+
};
|
|
868
|
+
} else if (!iosContent?.isBEEeditor) {
|
|
869
|
+
templateData.iosContent = iosContent;
|
|
870
|
+
templateData.iosContent.type = iosContent?.type || get(channelTemplate, 'definition.mode', '')?.toUpperCase() || 'TEXT';
|
|
871
|
+
templateData.iosContent.deviceType = constants.IOS;
|
|
872
|
+
}
|
|
829
873
|
}
|
|
830
874
|
templateData.messageSubject = channelTemplate?.name ? channelTemplate?.name : "messageSubject";
|
|
831
875
|
}
|
|
@@ -104,12 +104,12 @@ export const LineText = ({
|
|
|
104
104
|
layout: 'LINE',
|
|
105
105
|
type: 'TAG',
|
|
106
106
|
context:
|
|
107
|
-
location
|
|
107
|
+
location?.query?.type === 'embedded'
|
|
108
108
|
? 'outbound'
|
|
109
109
|
: 'default',
|
|
110
110
|
embedded:
|
|
111
|
-
location
|
|
112
|
-
? location
|
|
111
|
+
location?.query?.type === 'embedded'
|
|
112
|
+
? location?.query?.type
|
|
113
113
|
: 'full',
|
|
114
114
|
};
|
|
115
115
|
if (getDefaultTags) {
|
|
@@ -125,8 +125,8 @@ export const LineText = ({
|
|
|
125
125
|
context:
|
|
126
126
|
(data || '').toLowerCase() === 'all' ? 'default' : (data || '').toLowerCase(),
|
|
127
127
|
embedded:
|
|
128
|
-
location
|
|
129
|
-
? location
|
|
128
|
+
location?.query?.type === 'embedded'
|
|
129
|
+
? location?.query?.type
|
|
130
130
|
: 'full',
|
|
131
131
|
};
|
|
132
132
|
globalActions.fetchSchemaForEntity(query);
|
|
@@ -266,7 +266,7 @@ export const LineText = ({
|
|
|
266
266
|
/>
|
|
267
267
|
<TagList
|
|
268
268
|
key={`${id}_tags`}
|
|
269
|
-
moduleFilterEnabled={location && location
|
|
269
|
+
moduleFilterEnabled={location && location?.query && location?.query?.type !== 'embedded'}
|
|
270
270
|
label={formatMessage(messages.addLabels)}
|
|
271
271
|
onTagSelect={onTagSelect}
|
|
272
272
|
onContextChange={handleOnTagsContextChange}
|
|
@@ -1309,9 +1309,9 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
1309
1309
|
</div>
|
|
1310
1310
|
</div>
|
|
1311
1311
|
)}
|
|
1312
|
-
{
|
|
1312
|
+
{[MANUAL_CAROUSEL, AUTO_CAROUSEL, FILMSTRIP_CAROUSEL].includes(style) && (
|
|
1313
1313
|
<div className="scroll-container">
|
|
1314
|
-
{carouselData
|
|
1314
|
+
{carouselData?.map((data, index) => {
|
|
1315
1315
|
return (
|
|
1316
1316
|
<div
|
|
1317
1317
|
key={`carousel-${index + 1}`}
|
|
@@ -1321,14 +1321,14 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
1321
1321
|
<div className="whatsapp-carousel-card">
|
|
1322
1322
|
{data?.mediaType === IMAGE.toLowerCase() && (
|
|
1323
1323
|
<CapImage
|
|
1324
|
-
src={data?.imageUrl ? data?.imageUrl : whatsappImageEmptyPreview}
|
|
1324
|
+
src={data?.imageUrl ? data?.imageUrl : data?.url ? data?.url : whatsappImageEmptyPreview}
|
|
1325
1325
|
className="whatsapp-image"
|
|
1326
1326
|
/>
|
|
1327
1327
|
)}
|
|
1328
1328
|
{data?.mediaType === VIDEO.toLowerCase() && (
|
|
1329
1329
|
<div className="video-preview">
|
|
1330
1330
|
<CapImage
|
|
1331
|
-
src={data?.videoPreviewImg ? data?.videoPreviewImg : whatsappVideoEmptyPreview}
|
|
1331
|
+
src={data?.videoPreviewImg ? data?.videoPreviewImg : data?.url ? data?.url : whatsappVideoEmptyPreview}
|
|
1332
1332
|
className="whatsapp-image"
|
|
1333
1333
|
/>
|
|
1334
1334
|
<div className="icon-position">
|
package/assets/loading_img.gif
DELETED
|
Binary file
|