@capillarytech/creatives-library 8.0.347 → 8.0.348
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/services/api.js +0 -20
- package/services/tests/api.test.js +0 -59
- package/utils/tests/v2Common.test.js +1 -46
- package/utils/v2common.js +0 -18
- package/v2Components/CapCustomSkeleton/index.js +1 -1
- package/v2Components/CapCustomSkeleton/tests/__snapshots__/index.test.js.snap +12 -12
- package/v2Components/CommonTestAndPreview/UnifiedPreview/WhatsAppPreviewContent.js +18 -6
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +27 -0
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/WhatsAppPreviewContent.test.js +48 -0
- package/v2Components/TemplatePreview/_templatePreview.scss +21 -0
- package/v2Components/TemplatePreview/index.js +18 -6
- package/v2Components/TemplatePreview/tests/__snapshots__/index.test.js.snap +1 -0
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +1 -3
- package/v2Containers/CreativesContainer/index.js +9 -6
- package/v2Containers/CreativesContainer/messages.js +0 -4
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +0 -3
- package/v2Containers/Templates/ChannelTypeIllustration.js +6 -23
- package/v2Containers/Templates/_templates.scss +24 -179
- package/v2Containers/Templates/actions.js +0 -44
- package/v2Containers/Templates/constants.js +0 -23
- package/v2Containers/Templates/index.js +58 -378
- package/v2Containers/Templates/messages.js +0 -88
- package/v2Containers/Templates/reducer.js +1 -84
- package/v2Containers/Templates/sagas.js +0 -64
- package/v2Containers/Templates/selectors.js +0 -12
- package/v2Containers/Templates/tests/ChannelTypeIllustration.test.js +0 -12
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1122 -1345
- package/v2Containers/Templates/tests/index.test.js +0 -6
- package/v2Containers/Templates/tests/reducer.test.js +0 -178
- package/v2Containers/Templates/tests/sagas.test.js +8 -390
- package/v2Containers/Templates/tests/selector.test.js +0 -32
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +1 -1
- package/v2Containers/Whatsapp/constants.js +8 -0
- package/v2Containers/Whatsapp/index.js +142 -5
- package/v2Containers/Whatsapp/index.scss +8 -0
- package/v2Containers/Whatsapp/messages.js +16 -0
- package/v2Containers/Assets/images/archive_Empty_Illustration.svg +0 -9
package/package.json
CHANGED
package/services/api.js
CHANGED
|
@@ -361,26 +361,6 @@ export const deleteTemplate = ({channel, id}) => {
|
|
|
361
361
|
//return API.deleteResource(url);
|
|
362
362
|
};
|
|
363
363
|
|
|
364
|
-
export const archiveTemplate = ({ channel, id }) => {
|
|
365
|
-
const url = `${API_ENDPOINT}/templates/archive/${id}/${channel}`;
|
|
366
|
-
return request(url, getAPICallObject('PUT'));
|
|
367
|
-
};
|
|
368
|
-
|
|
369
|
-
export const unarchiveTemplate = ({ channel, id }) => {
|
|
370
|
-
const url = `${API_ENDPOINT}/templates/unarchive/${id}/${channel}`;
|
|
371
|
-
return request(url, getAPICallObject('PUT'));
|
|
372
|
-
};
|
|
373
|
-
|
|
374
|
-
export const bulkArchiveTemplates = ({ channel, ids }) => {
|
|
375
|
-
const url = `${API_ENDPOINT}/templates/archive/bulk/${channel}`;
|
|
376
|
-
return request(url, getAPICallObject('PUT', { ids }));
|
|
377
|
-
};
|
|
378
|
-
|
|
379
|
-
export const bulkUnarchiveTemplates = ({ channel, ids }) => {
|
|
380
|
-
const url = `${API_ENDPOINT}/templates/unarchive/bulk/${channel}`;
|
|
381
|
-
return request(url, getAPICallObject('PUT', { ids }));
|
|
382
|
-
};
|
|
383
|
-
|
|
384
364
|
export const deleteRcsTemplate = ({ templateName }) => {
|
|
385
365
|
const url = `${API_ENDPOINT}/templates/${templateName}/RCS`;
|
|
386
366
|
return request(url, getAPICallObject('DELETE'))
|
|
@@ -1086,62 +1086,3 @@ describe('createTestCustomer', () => {
|
|
|
1086
1086
|
expect(lastCall[1].body).toBe(JSON.stringify(payload));
|
|
1087
1087
|
});
|
|
1088
1088
|
});
|
|
1089
|
-
|
|
1090
|
-
import {
|
|
1091
|
-
archiveTemplate,
|
|
1092
|
-
unarchiveTemplate,
|
|
1093
|
-
bulkArchiveTemplates,
|
|
1094
|
-
bulkUnarchiveTemplates,
|
|
1095
|
-
} from '../api';
|
|
1096
|
-
|
|
1097
|
-
describe('archiveTemplate', () => {
|
|
1098
|
-
beforeEach(() => {
|
|
1099
|
-
global.fetch = jest.fn().mockReturnValue(Promise.resolve({ json: () => Promise.resolve({}) }));
|
|
1100
|
-
});
|
|
1101
|
-
|
|
1102
|
-
it('should call PUT on archive endpoint', () => {
|
|
1103
|
-
archiveTemplate({ channel: 'EMAIL', id: 'id123' });
|
|
1104
|
-
expect(global.fetch).toHaveBeenCalled();
|
|
1105
|
-
const lastCall = global.fetch.mock.calls[global.fetch.mock.calls.length - 1];
|
|
1106
|
-
expect(lastCall[1].method).toBe('PUT');
|
|
1107
|
-
});
|
|
1108
|
-
});
|
|
1109
|
-
|
|
1110
|
-
describe('unarchiveTemplate', () => {
|
|
1111
|
-
beforeEach(() => {
|
|
1112
|
-
global.fetch = jest.fn().mockReturnValue(Promise.resolve({ json: () => Promise.resolve({}) }));
|
|
1113
|
-
});
|
|
1114
|
-
|
|
1115
|
-
it('should call PUT on unarchive endpoint', () => {
|
|
1116
|
-
unarchiveTemplate({ channel: 'EMAIL', id: 'id123' });
|
|
1117
|
-
expect(global.fetch).toHaveBeenCalled();
|
|
1118
|
-
const lastCall = global.fetch.mock.calls[global.fetch.mock.calls.length - 1];
|
|
1119
|
-
expect(lastCall[1].method).toBe('PUT');
|
|
1120
|
-
});
|
|
1121
|
-
});
|
|
1122
|
-
|
|
1123
|
-
describe('bulkArchiveTemplates', () => {
|
|
1124
|
-
beforeEach(() => {
|
|
1125
|
-
global.fetch = jest.fn().mockReturnValue(Promise.resolve({ json: () => Promise.resolve({}) }));
|
|
1126
|
-
});
|
|
1127
|
-
|
|
1128
|
-
it('should call PUT on bulk archive endpoint with ids', () => {
|
|
1129
|
-
bulkArchiveTemplates({ channel: 'EMAIL', ids: ['id1', 'id2'] });
|
|
1130
|
-
expect(global.fetch).toHaveBeenCalled();
|
|
1131
|
-
const lastCall = global.fetch.mock.calls[global.fetch.mock.calls.length - 1];
|
|
1132
|
-
expect(lastCall[1].method).toBe('PUT');
|
|
1133
|
-
});
|
|
1134
|
-
});
|
|
1135
|
-
|
|
1136
|
-
describe('bulkUnarchiveTemplates', () => {
|
|
1137
|
-
beforeEach(() => {
|
|
1138
|
-
global.fetch = jest.fn().mockReturnValue(Promise.resolve({ json: () => Promise.resolve({}) }));
|
|
1139
|
-
});
|
|
1140
|
-
|
|
1141
|
-
it('should call PUT on bulk unarchive endpoint with ids', () => {
|
|
1142
|
-
bulkUnarchiveTemplates({ channel: 'EMAIL', ids: ['id1', 'id2'] });
|
|
1143
|
-
expect(global.fetch).toHaveBeenCalled();
|
|
1144
|
-
const lastCall = global.fetch.mock.calls[global.fetch.mock.calls.length - 1];
|
|
1145
|
-
expect(lastCall[1].method).toBe('PUT');
|
|
1146
|
-
});
|
|
1147
|
-
});
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { getObjFromQueryParams, buildTemplateNameDescription } from '../v2common';
|
|
2
|
+
import { getObjFromQueryParams } from '../v2common';
|
|
4
3
|
|
|
5
4
|
describe('Test v2common container', () => {
|
|
6
5
|
it('test getObjFromQueryParams', () => {
|
|
@@ -10,47 +9,3 @@ describe('Test v2common container', () => {
|
|
|
10
9
|
});
|
|
11
10
|
});
|
|
12
11
|
});
|
|
13
|
-
|
|
14
|
-
describe('buildTemplateNameDescription', () => {
|
|
15
|
-
it('returns undefined when templateName is empty string', () => {
|
|
16
|
-
expect(buildTemplateNameDescription('Template name', '')).toBeUndefined();
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('returns undefined when templateName is null', () => {
|
|
20
|
-
expect(buildTemplateNameDescription('Template name', null)).toBeUndefined();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('returns undefined when templateName is undefined', () => {
|
|
24
|
-
expect(buildTemplateNameDescription('Template name', undefined)).toBeUndefined();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('renders a span wrapper when templateName is provided', () => {
|
|
28
|
-
const result = buildTemplateNameDescription('Template name', 'Welcome 01');
|
|
29
|
-
const wrapper = shallow(result);
|
|
30
|
-
expect(wrapper.type()).toBe('span');
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('renders label text in the first CapLabelInline with correct class', () => {
|
|
34
|
-
const result = buildTemplateNameDescription('Template name', 'Welcome 01');
|
|
35
|
-
const wrapper = shallow(result);
|
|
36
|
-
const firstLabel = wrapper.childAt(0);
|
|
37
|
-
expect(firstLabel.prop('className')).toBe('notification-template-label');
|
|
38
|
-
expect(firstLabel.prop('children')).toBe('Template name');
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('renders template name in the second CapLabelInline with correct class', () => {
|
|
42
|
-
const result = buildTemplateNameDescription('Template name', 'Welcome 01');
|
|
43
|
-
const wrapper = shallow(result);
|
|
44
|
-
const secondLabel = wrapper.childAt(1);
|
|
45
|
-
expect(secondLabel.prop('className')).toBe('notification-template-name');
|
|
46
|
-
expect(secondLabel.prop('children')).toBe('Welcome 01');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('both CapLabelInline elements have type="label1"', () => {
|
|
50
|
-
const result = buildTemplateNameDescription('Template name', 'Welcome 01');
|
|
51
|
-
const wrapper = shallow(result);
|
|
52
|
-
wrapper.children().forEach((node) => {
|
|
53
|
-
expect(node.prop('type')).toBe('label1');
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
});
|
package/utils/v2common.js
CHANGED
|
@@ -1,21 +1,3 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import CapLabel from '@capillarytech/cap-ui-library/CapLabel';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Builds a JSX description for template archive/unarchive notifications.
|
|
6
|
-
* @param {string} labelText - Localised label (e.g. "Template name ")
|
|
7
|
-
* @param {string} templateName - The template name to display
|
|
8
|
-
*/
|
|
9
|
-
export const buildTemplateNameDescription = (labelText, templateName) => (
|
|
10
|
-
templateName
|
|
11
|
-
? (
|
|
12
|
-
<span>
|
|
13
|
-
<CapLabel.CapLabelInline type="label1" className="notification-template-label">{labelText}</CapLabel.CapLabelInline>
|
|
14
|
-
<CapLabel.CapLabelInline type="label1" className="notification-template-name">{templateName}</CapLabel.CapLabelInline>
|
|
15
|
-
</span>
|
|
16
|
-
)
|
|
17
|
-
: undefined
|
|
18
|
-
);
|
|
19
1
|
|
|
20
2
|
// returns query items as obj when query string is passed
|
|
21
3
|
/**
|
|
@@ -20,7 +20,7 @@ exports[`CapCustomSkeleton test renders correct CapCustomSkeleton component 1`]
|
|
|
20
20
|
>
|
|
21
21
|
<CapColumn
|
|
22
22
|
key="0"
|
|
23
|
-
lg={
|
|
23
|
+
lg={6}
|
|
24
24
|
md={8}
|
|
25
25
|
sm={12}
|
|
26
26
|
xs={24}
|
|
@@ -40,7 +40,7 @@ exports[`CapCustomSkeleton test renders correct CapCustomSkeleton component 1`]
|
|
|
40
40
|
</CapColumn>
|
|
41
41
|
<CapColumn
|
|
42
42
|
key="1"
|
|
43
|
-
lg={
|
|
43
|
+
lg={6}
|
|
44
44
|
md={8}
|
|
45
45
|
sm={12}
|
|
46
46
|
xs={24}
|
|
@@ -60,7 +60,7 @@ exports[`CapCustomSkeleton test renders correct CapCustomSkeleton component 1`]
|
|
|
60
60
|
</CapColumn>
|
|
61
61
|
<CapColumn
|
|
62
62
|
key="2"
|
|
63
|
-
lg={
|
|
63
|
+
lg={6}
|
|
64
64
|
md={8}
|
|
65
65
|
sm={12}
|
|
66
66
|
xs={24}
|
|
@@ -80,7 +80,7 @@ exports[`CapCustomSkeleton test renders correct CapCustomSkeleton component 1`]
|
|
|
80
80
|
</CapColumn>
|
|
81
81
|
<CapColumn
|
|
82
82
|
key="3"
|
|
83
|
-
lg={
|
|
83
|
+
lg={6}
|
|
84
84
|
md={8}
|
|
85
85
|
sm={12}
|
|
86
86
|
xs={24}
|
|
@@ -100,7 +100,7 @@ exports[`CapCustomSkeleton test renders correct CapCustomSkeleton component 1`]
|
|
|
100
100
|
</CapColumn>
|
|
101
101
|
<CapColumn
|
|
102
102
|
key="4"
|
|
103
|
-
lg={
|
|
103
|
+
lg={6}
|
|
104
104
|
md={8}
|
|
105
105
|
sm={12}
|
|
106
106
|
xs={24}
|
|
@@ -120,7 +120,7 @@ exports[`CapCustomSkeleton test renders correct CapCustomSkeleton component 1`]
|
|
|
120
120
|
</CapColumn>
|
|
121
121
|
<CapColumn
|
|
122
122
|
key="5"
|
|
123
|
-
lg={
|
|
123
|
+
lg={6}
|
|
124
124
|
md={8}
|
|
125
125
|
sm={12}
|
|
126
126
|
xs={24}
|
|
@@ -140,7 +140,7 @@ exports[`CapCustomSkeleton test renders correct CapCustomSkeleton component 1`]
|
|
|
140
140
|
</CapColumn>
|
|
141
141
|
<CapColumn
|
|
142
142
|
key="6"
|
|
143
|
-
lg={
|
|
143
|
+
lg={6}
|
|
144
144
|
md={8}
|
|
145
145
|
sm={12}
|
|
146
146
|
xs={24}
|
|
@@ -160,7 +160,7 @@ exports[`CapCustomSkeleton test renders correct CapCustomSkeleton component 1`]
|
|
|
160
160
|
</CapColumn>
|
|
161
161
|
<CapColumn
|
|
162
162
|
key="7"
|
|
163
|
-
lg={
|
|
163
|
+
lg={6}
|
|
164
164
|
md={8}
|
|
165
165
|
sm={12}
|
|
166
166
|
xs={24}
|
|
@@ -180,7 +180,7 @@ exports[`CapCustomSkeleton test renders correct CapCustomSkeleton component 1`]
|
|
|
180
180
|
</CapColumn>
|
|
181
181
|
<CapColumn
|
|
182
182
|
key="8"
|
|
183
|
-
lg={
|
|
183
|
+
lg={6}
|
|
184
184
|
md={8}
|
|
185
185
|
sm={12}
|
|
186
186
|
xs={24}
|
|
@@ -200,7 +200,7 @@ exports[`CapCustomSkeleton test renders correct CapCustomSkeleton component 1`]
|
|
|
200
200
|
</CapColumn>
|
|
201
201
|
<CapColumn
|
|
202
202
|
key="9"
|
|
203
|
-
lg={
|
|
203
|
+
lg={6}
|
|
204
204
|
md={8}
|
|
205
205
|
sm={12}
|
|
206
206
|
xs={24}
|
|
@@ -220,7 +220,7 @@ exports[`CapCustomSkeleton test renders correct CapCustomSkeleton component 1`]
|
|
|
220
220
|
</CapColumn>
|
|
221
221
|
<CapColumn
|
|
222
222
|
key="10"
|
|
223
|
-
lg={
|
|
223
|
+
lg={6}
|
|
224
224
|
md={8}
|
|
225
225
|
sm={12}
|
|
226
226
|
xs={24}
|
|
@@ -240,7 +240,7 @@ exports[`CapCustomSkeleton test renders correct CapCustomSkeleton component 1`]
|
|
|
240
240
|
</CapColumn>
|
|
241
241
|
<CapColumn
|
|
242
242
|
key="11"
|
|
243
|
-
lg={
|
|
243
|
+
lg={6}
|
|
244
244
|
md={8}
|
|
245
245
|
sm={12}
|
|
246
246
|
xs={24}
|
|
@@ -18,7 +18,7 @@ import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
|
18
18
|
import { ANDROID, IOS } from '../constants';
|
|
19
19
|
import messages from '../messages';
|
|
20
20
|
import { getWhatsappQuickReply, getWhatsappCarouselButtonView } from '../../../v2Containers/Whatsapp/utils';
|
|
21
|
-
import { QUICK_REPLY, PHONE_NUMBER, WHATSAPP_CATEGORIES } from '../../../v2Containers/Whatsapp/constants';
|
|
21
|
+
import { QUICK_REPLY, PHONE_NUMBER, WHATSAPP_CATEGORIES, TEMPLATE_VARIABLE_REGEX } from '../../../v2Containers/Whatsapp/constants';
|
|
22
22
|
import videoPlay from '../../../assets/videoPlay.svg';
|
|
23
23
|
import whatsappImageEmptyPreview from '../../TemplatePreview/assets/images/empty_image_preview.svg';
|
|
24
24
|
import whatsappVideoEmptyPreview from '../../TemplatePreview/assets/images/empty_video_preview.svg';
|
|
@@ -27,6 +27,8 @@ import whatsappVideoEmptyPreview from '../../TemplatePreview/assets/images/empty
|
|
|
27
27
|
const whatsappMobileAndroid = require('../../../assets/whatsapp_android.png');
|
|
28
28
|
const whatsappMobileIos = require('../../../assets/whatsapp_ios.png');
|
|
29
29
|
|
|
30
|
+
const { CapLabelInline } = CapLabel;
|
|
31
|
+
|
|
30
32
|
const WhatsAppPreviewContent = ({
|
|
31
33
|
content,
|
|
32
34
|
device,
|
|
@@ -214,11 +216,21 @@ const WhatsAppPreviewContent = ({
|
|
|
214
216
|
|
|
215
217
|
{/* Image Preview */}
|
|
216
218
|
{content?.whatsappImageSrc && (
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
219
|
+
TEMPLATE_VARIABLE_REGEX.test(content.whatsappImageSrc) ? (
|
|
220
|
+
<CapRow className="whatsapp-image-url-placeholder">
|
|
221
|
+
<CapIcon type="picture" size="s" className="whatsapp-image-url-placeholder-icon" />
|
|
222
|
+
<CapLabelInline type="label2" className="whatsapp-image-url-placeholder-text">
|
|
223
|
+
{content.whatsappImageSrc}
|
|
224
|
+
</CapLabelInline>
|
|
225
|
+
</CapRow>
|
|
226
|
+
) : (
|
|
227
|
+
<CapImage
|
|
228
|
+
src={content.whatsappImageSrc}
|
|
229
|
+
className="whatsapp-image"
|
|
230
|
+
alt={formatMessage(messages.previewGenerated)}
|
|
231
|
+
onError={(e) => { e.target.src = whatsappImageEmptyPreview; }}
|
|
232
|
+
/>
|
|
233
|
+
)
|
|
222
234
|
)}
|
|
223
235
|
|
|
224
236
|
{/* Video Preview */}
|
|
@@ -940,6 +940,33 @@
|
|
|
940
940
|
}
|
|
941
941
|
}
|
|
942
942
|
|
|
943
|
+
.whatsapp-image-url-placeholder {
|
|
944
|
+
display: flex;
|
|
945
|
+
flex-direction: column;
|
|
946
|
+
align-items: center;
|
|
947
|
+
justify-content: center;
|
|
948
|
+
gap: $CAP_SPACE_08;
|
|
949
|
+
width: 100%;
|
|
950
|
+
min-height: 5rem;
|
|
951
|
+
max-height: 8.786rem;
|
|
952
|
+
margin-bottom: $CAP_SPACE_04;
|
|
953
|
+
background-color: $CAP_G09;
|
|
954
|
+
border-radius: $CAP_SPACE_04;
|
|
955
|
+
padding: $CAP_SPACE_08;
|
|
956
|
+
|
|
957
|
+
.whatsapp-image-url-placeholder-icon {
|
|
958
|
+
color: $CAP_G05;
|
|
959
|
+
font-size: 1.5rem;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
.whatsapp-image-url-placeholder-text {
|
|
963
|
+
font-size: $FONT_SIZE_S;
|
|
964
|
+
color: $CAP_G04;
|
|
965
|
+
text-align: center;
|
|
966
|
+
word-break: break-all;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
|
|
943
970
|
.whatsapp-image {
|
|
944
971
|
width: 100%;
|
|
945
972
|
max-height: 8.786rem;
|
package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/WhatsAppPreviewContent.test.js
CHANGED
|
@@ -26,6 +26,7 @@ jest.mock('../../../../v2Containers/Whatsapp/constants', () => ({
|
|
|
26
26
|
WHATSAPP_CATEGORIES: {
|
|
27
27
|
authentication: 'authentication',
|
|
28
28
|
},
|
|
29
|
+
TEMPLATE_VARIABLE_REGEX: /\{\{.*?\}\}/,
|
|
29
30
|
}));
|
|
30
31
|
|
|
31
32
|
// Convert messages object to format expected by IntlProvider
|
|
@@ -238,6 +239,53 @@ describe('WhatsAppPreviewContent', () => {
|
|
|
238
239
|
expect(image.getAttribute('src')).toBe('https://image.url');
|
|
239
240
|
});
|
|
240
241
|
|
|
242
|
+
it('should render placeholder when whatsappImageSrc is a template variable', () => {
|
|
243
|
+
const props = {
|
|
244
|
+
...defaultProps,
|
|
245
|
+
content: {
|
|
246
|
+
templateMsg: 'Message',
|
|
247
|
+
whatsappImageSrc: '{{imageUrl}}',
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const { container } = render(
|
|
252
|
+
<TestWrapper>
|
|
253
|
+
<ComponentToRender {...props} />
|
|
254
|
+
</TestWrapper>
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
expect(container.querySelector('.whatsapp-image-url-placeholder')).toBeTruthy();
|
|
258
|
+
expect(container.querySelector('.whatsapp-image-url-placeholder-icon')).toBeTruthy();
|
|
259
|
+
expect(container.querySelector('.whatsapp-image-url-placeholder-text').textContent).toBe('{{imageUrl}}');
|
|
260
|
+
expect(container.querySelector('img.whatsapp-image')).toBeFalsy();
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('should fall back to empty preview image when image fails to load', () => {
|
|
264
|
+
const props = {
|
|
265
|
+
...defaultProps,
|
|
266
|
+
content: {
|
|
267
|
+
templateMsg: 'Message',
|
|
268
|
+
whatsappImageSrc: 'https://broken.url/image.jpg',
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const { container } = render(
|
|
273
|
+
<TestWrapper>
|
|
274
|
+
<ComponentToRender {...props} />
|
|
275
|
+
</TestWrapper>
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
const image = container.querySelector('img.whatsapp-image');
|
|
279
|
+
expect(image).toBeTruthy();
|
|
280
|
+
expect(image.getAttribute('src')).toBe('https://broken.url/image.jpg');
|
|
281
|
+
|
|
282
|
+
// Trigger onError to swap src to fallback
|
|
283
|
+
const errorEvent = new Event('error');
|
|
284
|
+
image.dispatchEvent(errorEvent);
|
|
285
|
+
|
|
286
|
+
expect(image.getAttribute('src')).not.toBe('https://broken.url/image.jpg');
|
|
287
|
+
});
|
|
288
|
+
|
|
241
289
|
it('should render video preview when whatsappVideoPreviewImg is present', () => {
|
|
242
290
|
const props = {
|
|
243
291
|
...defaultProps,
|
|
@@ -816,6 +816,27 @@
|
|
|
816
816
|
}
|
|
817
817
|
}
|
|
818
818
|
|
|
819
|
+
.whatsapp-image-url-placeholder {
|
|
820
|
+
display: flex;
|
|
821
|
+
flex-direction: column;
|
|
822
|
+
align-items: center;
|
|
823
|
+
justify-content: center;
|
|
824
|
+
background-color: $CAP_G09;
|
|
825
|
+
border-radius: $CAP_SPACE_04;
|
|
826
|
+
width: 100%;
|
|
827
|
+
min-height: 5rem;
|
|
828
|
+
max-height: 8.786rem;
|
|
829
|
+
margin-bottom: $CAP_SPACE_04;
|
|
830
|
+
.whatsapp-image-url-placeholder-text {
|
|
831
|
+
font-size: 0.786rem;
|
|
832
|
+
color: $CAP_G04;
|
|
833
|
+
margin-top: $CAP_SPACE_04;
|
|
834
|
+
text-align: center;
|
|
835
|
+
word-break: break-all;
|
|
836
|
+
padding: 0 $CAP_SPACE_04;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
|
|
819
840
|
.msg-container-carousel {
|
|
820
841
|
display: flex;
|
|
821
842
|
flex-direction: column;
|
|
@@ -48,7 +48,7 @@ import { TEMPLATE, IMAGE_CAROUSEL, IMAGE, STICKER, TEXT, IMAGE_MAP, VIDEO } from
|
|
|
48
48
|
import CapFacebookPreview from '../../v2Containers/CapFacebookPreview';
|
|
49
49
|
import WhatsappStatusContainer from '../WhatsappStatusContainer';
|
|
50
50
|
import { getWhatsappQuickReply, getWhatsappCarouselButtonView } from '../../v2Containers/Whatsapp/utils';
|
|
51
|
-
import { QUICK_REPLY, WHATSAPP_CATEGORIES, PHONE_NUMBER } from '../../v2Containers/Whatsapp/constants';
|
|
51
|
+
import { QUICK_REPLY, WHATSAPP_CATEGORIES, PHONE_NUMBER, TEMPLATE_VARIABLE_REGEX } from '../../v2Containers/Whatsapp/constants';
|
|
52
52
|
import { RCS_BUTTON_TYPES, LEFT, HORIZONTAL, VERTICAL, RIGHT} from '../../v2Containers/Rcs/constants';
|
|
53
53
|
import { ANDROID, INAPP_MESSAGE_LAYOUT_TYPES } from '../../v2Containers/InApp/constants';
|
|
54
54
|
import { CAROUSEL } from '../../v2Containers/MobilePushNew/constants';
|
|
@@ -66,6 +66,8 @@ const lineVideoPlaceholder = require('../../assets/rich-video-placeholder.svg');
|
|
|
66
66
|
const androidPushMessagePhone = require('./assets/images/Android_With_date_and_time.svg');
|
|
67
67
|
const iPhonePushMessagePhone = require('./assets/images/iOS_With_date_and_time.svg');
|
|
68
68
|
|
|
69
|
+
const { CapLabelInline } = CapLabel;
|
|
70
|
+
|
|
69
71
|
export class TemplatePreview extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
|
70
72
|
onPreviewContentClicked = (channel) => {
|
|
71
73
|
const IOSContent = (this.props.templateDataRaw && this.props.templateDataRaw.versions.base.IOS) ||
|
|
@@ -1194,11 +1196,21 @@ export class TemplatePreview extends React.Component { // eslint-disable-line re
|
|
|
1194
1196
|
{content?.showUrlPreview
|
|
1195
1197
|
&& renderUrlPreview(content?.metaTagsDetails)}
|
|
1196
1198
|
{content?.whatsappImageSrc && (
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1199
|
+
TEMPLATE_VARIABLE_REGEX.test(content.whatsappImageSrc) ? (
|
|
1200
|
+
<div className="whatsapp-image-url-placeholder">
|
|
1201
|
+
<CapIcon type="picture" size="s" className="whatsapp-image-url-placeholder-icon" />
|
|
1202
|
+
<CapLabelInline type="label2" className="whatsapp-image-url-placeholder-text">
|
|
1203
|
+
{content.whatsappImageSrc}
|
|
1204
|
+
</CapLabelInline>
|
|
1205
|
+
</div>
|
|
1206
|
+
) : (
|
|
1207
|
+
<CapImage
|
|
1208
|
+
src={content.whatsappImageSrc}
|
|
1209
|
+
className="whatsapp-image"
|
|
1210
|
+
alt={formatMessage(messages.previewGenerated)}
|
|
1211
|
+
onError={(e) => { e.target.src = whatsappImageEmptyPreview; }}
|
|
1212
|
+
/>
|
|
1213
|
+
)
|
|
1202
1214
|
)}
|
|
1203
1215
|
{content?.whatsappVideoPreviewImg && (
|
|
1204
1216
|
<CapTooltip
|
|
@@ -43,6 +43,7 @@ exports[`Test Templates container Should render correct preview component for wh
|
|
|
43
43
|
<CapImage
|
|
44
44
|
alt="Preview is being generated"
|
|
45
45
|
className="whatsapp-image"
|
|
46
|
+
onError={[Function]}
|
|
46
47
|
src="https://crm-nightly-new-fileservice.s3.amazonaws.com/intouch_creative_assets/c9edc114-923b-4ac7-82d0-d6682213.jpg"
|
|
47
48
|
/>
|
|
48
49
|
You have received {{1}} points
|
|
@@ -24,7 +24,6 @@ function SlideBoxFooter(props) {
|
|
|
24
24
|
slidBoxContent,
|
|
25
25
|
onSave,
|
|
26
26
|
onEditTemplate,
|
|
27
|
-
isTemplateArchived,
|
|
28
27
|
onCreateNextStep,
|
|
29
28
|
isFullMode,
|
|
30
29
|
fetchingCmsData,
|
|
@@ -215,7 +214,7 @@ function SlideBoxFooter(props) {
|
|
|
215
214
|
<FormattedMessage {...(continueButtonLabel || messages.continue)} />
|
|
216
215
|
</CapButton>
|
|
217
216
|
)}
|
|
218
|
-
{slidBoxContent === PREVIEW &&
|
|
217
|
+
{slidBoxContent === PREVIEW && (
|
|
219
218
|
<CapButton onClick={onEditTemplate} type="secondary">
|
|
220
219
|
<FormattedMessage {...messages.creativesTemplatesEdit} />
|
|
221
220
|
</CapButton>
|
|
@@ -228,7 +227,6 @@ SlideBoxFooter.propTypes = {
|
|
|
228
227
|
slidBoxContent: PropTypes.node,
|
|
229
228
|
onSave: PropTypes.func,
|
|
230
229
|
onEditTemplate: PropTypes.func,
|
|
231
|
-
isTemplateArchived: PropTypes.bool,
|
|
232
230
|
onCreateNextStep: PropTypes.func,
|
|
233
231
|
shouldShowContinueFooter: PropTypes.func,
|
|
234
232
|
shouldShowDoneFooter: PropTypes.func,
|
|
@@ -50,7 +50,7 @@ import { RCS_STATUSES } from '../Rcs/constants';
|
|
|
50
50
|
import { CREATIVE } from '../Facebook/constants';
|
|
51
51
|
import { LOYALTY } from '../App/constants';
|
|
52
52
|
import {
|
|
53
|
-
WHATSAPP_STATUSES, WHATSAPP_MEDIA_TYPES, PHONE_NUMBER, URL,
|
|
53
|
+
WHATSAPP_STATUSES, WHATSAPP_MEDIA_TYPES, PHONE_NUMBER, URL, ADD_IMAGE_URL_PREVIEW_MARKER,
|
|
54
54
|
} from '../Whatsapp/constants';
|
|
55
55
|
import { updateImagesInHtml } from '../../utils/cdnTransformation';
|
|
56
56
|
|
|
@@ -260,10 +260,6 @@ export class Creatives extends React.Component {
|
|
|
260
260
|
};
|
|
261
261
|
|
|
262
262
|
onEditTemplate = () => {
|
|
263
|
-
if (this.props.templateData && this.props.templateData.isArchived) {
|
|
264
|
-
CapNotification.error({ message: this.props.intl.formatMessage(messages.cannotEditArchivedTemplate) });
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
263
|
this.setState({ slidBoxContent: 'editTemplate', showSlideBox: true, templateNameExists: true });
|
|
268
264
|
};
|
|
269
265
|
|
|
@@ -688,6 +684,8 @@ export class Creatives extends React.Component {
|
|
|
688
684
|
switch (mediaType) {
|
|
689
685
|
case (WHATSAPP_MEDIA_TYPES.IMAGE):
|
|
690
686
|
mediaParams.imageUrl = url;
|
|
687
|
+
// Detect isAddImageUrl from previewUrl marker (previewUrl is unused for IMAGE type)
|
|
688
|
+
mediaParams.isAddImageUrl = previewUrl === ADD_IMAGE_URL_PREVIEW_MARKER;
|
|
691
689
|
break;
|
|
692
690
|
case (WHATSAPP_MEDIA_TYPES.VIDEO):
|
|
693
691
|
mediaParams.videoUrl = url;
|
|
@@ -1146,6 +1144,7 @@ export class Creatives extends React.Component {
|
|
|
1146
1144
|
headerTemplate = '',
|
|
1147
1145
|
} = {},
|
|
1148
1146
|
isPreviewUrl = false,
|
|
1147
|
+
isAddImageUrl = false,
|
|
1149
1148
|
carouselData = [],
|
|
1150
1149
|
} = cloneDeep(versions.base.content.whatsapp);
|
|
1151
1150
|
|
|
@@ -1182,6 +1181,11 @@ export class Creatives extends React.Component {
|
|
|
1182
1181
|
switch (mediaType) {
|
|
1183
1182
|
case (WHATSAPP_MEDIA_TYPES.IMAGE):
|
|
1184
1183
|
whatsappMedia.url = imageUrl;
|
|
1184
|
+
// previewUrl is unused for IMAGE type — reuse it to persist isAddImageUrl flag
|
|
1185
|
+
// without adding any new field that the backend would reject
|
|
1186
|
+
if (isAddImageUrl) {
|
|
1187
|
+
whatsappMedia.previewUrl = ADD_IMAGE_URL_PREVIEW_MARKER;
|
|
1188
|
+
}
|
|
1185
1189
|
break;
|
|
1186
1190
|
case (WHATSAPP_MEDIA_TYPES.VIDEO):
|
|
1187
1191
|
whatsappMedia.url = videoUrl;
|
|
@@ -2140,7 +2144,6 @@ export class Creatives extends React.Component {
|
|
|
2140
2144
|
onSave={this.saveMessage}
|
|
2141
2145
|
onDiscard={this.discardMessage}
|
|
2142
2146
|
onEditTemplate={this.onEditTemplate}
|
|
2143
|
-
isTemplateArchived={!!(this.props.templateData && this.props.templateData.isArchived)}
|
|
2144
2147
|
slidBoxContent={slidBoxContent}
|
|
2145
2148
|
onCreateNextStep={this.onCreateNextStep}
|
|
2146
2149
|
currentChannel={currentChannel.toUpperCase()}
|
|
@@ -390,8 +390,4 @@ export default defineMessages({
|
|
|
390
390
|
id: `${scope}.personalizationTokensErrorMessage`,
|
|
391
391
|
defaultMessage: `Personalization tags are not supported for anonymous customers, please remove the tags.`,
|
|
392
392
|
},
|
|
393
|
-
"cannotEditArchivedTemplate": {
|
|
394
|
-
id: `${scope}.cannotEditArchivedTemplate`,
|
|
395
|
-
defaultMessage: 'Cannot edit an archived template. Please unarchive it first.',
|
|
396
|
-
},
|
|
397
393
|
});
|
|
@@ -295,7 +295,6 @@ exports[`Test SlideBoxContent container campaign message, whatsapp edit all data
|
|
|
295
295
|
isEmptyContent={false}
|
|
296
296
|
isFullMode={false}
|
|
297
297
|
isLiquidValidationError={false}
|
|
298
|
-
isTemplateArchived={false}
|
|
299
298
|
isTemplateNameEmpty={false}
|
|
300
299
|
onCreateNextStep={[Function]}
|
|
301
300
|
onDiscard={[Function]}
|
|
@@ -435,7 +434,6 @@ exports[`Test SlideBoxContent container campaign message, whatsapp edit min data
|
|
|
435
434
|
isEmptyContent={false}
|
|
436
435
|
isFullMode={false}
|
|
437
436
|
isLiquidValidationError={false}
|
|
438
|
-
isTemplateArchived={false}
|
|
439
437
|
isTemplateNameEmpty={false}
|
|
440
438
|
onCreateNextStep={[Function]}
|
|
441
439
|
onDiscard={[Function]}
|
|
@@ -575,7 +573,6 @@ exports[`Test SlideBoxContent container it should clear the url, on channel chan
|
|
|
575
573
|
isEmptyContent={false}
|
|
576
574
|
isFullMode={false}
|
|
577
575
|
isLiquidValidationError={false}
|
|
578
|
-
isTemplateArchived={false}
|
|
579
576
|
isTemplateNameEmpty={false}
|
|
580
577
|
onCreateNextStep={[Function]}
|
|
581
578
|
onDiscard={[Function]}
|