@capillarytech/creatives-library 8.0.130 → 8.0.132
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/containers/App/constants.js +1 -0
- package/containers/Login/index.js +1 -2
- package/package.json +1 -1
- package/services/api.js +5 -0
- package/tests/integration/TemplateCreation/TemplateCreation.integration.test.js +8 -3
- package/tests/integration/TemplateCreation/api-response.js +5 -0
- package/tests/integration/TemplateCreation/msw-handler.js +42 -63
- package/utils/common.js +7 -0
- package/utils/commonUtils.js +2 -6
- package/utils/createMobilePushPayload.js +322 -0
- package/utils/tests/createMobilePushPayload.test.js +1054 -0
- package/v2Components/CapDeviceContent/index.js +1 -1
- package/v2Components/CapImageUpload/index.js +57 -44
- package/v2Components/CapInAppCTA/index.js +1 -0
- package/v2Components/CapMpushCTA/constants.js +25 -0
- package/v2Components/CapMpushCTA/index.js +403 -0
- package/v2Components/CapMpushCTA/index.scss +95 -0
- package/v2Components/CapMpushCTA/messages.js +101 -0
- package/v2Components/CapTagList/index.js +178 -121
- package/v2Components/CapVideoUpload/constants.js +3 -0
- package/v2Components/CapVideoUpload/index.js +182 -115
- package/v2Components/CapVideoUpload/messages.js +16 -0
- package/v2Components/Carousel/index.js +15 -13
- package/v2Components/ErrorInfoNote/style.scss +1 -0
- package/v2Components/MobilePushPreviewV2/index.js +57 -12
- package/v2Components/TemplatePreview/_templatePreview.scss +218 -74
- package/v2Components/TemplatePreview/assets/images/Android_With_date_and_time.svg +29 -0
- package/v2Components/TemplatePreview/assets/images/android.svg +9 -0
- package/v2Components/TemplatePreview/assets/images/iOS_With_date_and_time.svg +26 -0
- package/v2Components/TemplatePreview/assets/images/ios.svg +9 -0
- package/v2Components/TemplatePreview/index.js +234 -107
- package/v2Components/TemplatePreview/messages.js +4 -0
- package/v2Components/TemplatePreview/tests/__snapshots__/index.test.js.snap +10 -10
- package/v2Containers/CreativesContainer/SlideBoxContent.js +127 -62
- package/v2Containers/CreativesContainer/index.js +193 -136
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -22
- package/v2Containers/InApp/constants.js +1 -0
- package/v2Containers/InApp/index.js +13 -13
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +4748 -4658
- package/v2Containers/Login/index.js +1 -2
- package/v2Containers/MobilePush/Create/index.js +1 -0
- package/v2Containers/MobilePush/commonMethods.js +7 -14
- package/v2Containers/MobilePush/tests/commonMethods.test.js +401 -0
- package/v2Containers/MobilePushNew/actions.js +116 -0
- package/v2Containers/MobilePushNew/components/CtaButtons.js +183 -0
- package/v2Containers/MobilePushNew/components/MediaUploaders.js +835 -0
- package/v2Containers/MobilePushNew/components/PlatformContentFields.js +346 -0
- package/v2Containers/MobilePushNew/components/index.js +5 -0
- package/v2Containers/MobilePushNew/components/tests/CtaButtons.test.js +565 -0
- package/v2Containers/MobilePushNew/components/tests/MediaUploaders.test.js +3180 -0
- package/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +654 -0
- package/v2Containers/MobilePushNew/constants.js +116 -0
- package/v2Containers/MobilePushNew/hooks/tests/usePlatformSync.test.js +1462 -0
- package/v2Containers/MobilePushNew/hooks/tests/useUpload.test.js +1459 -0
- package/v2Containers/MobilePushNew/hooks/usePlatformSync.js +366 -0
- package/v2Containers/MobilePushNew/hooks/useUpload.js +740 -0
- package/v2Containers/MobilePushNew/index.js +2158 -0
- package/v2Containers/MobilePushNew/index.scss +308 -0
- package/v2Containers/MobilePushNew/messages.js +272 -0
- package/v2Containers/MobilePushNew/reducer.js +160 -0
- package/v2Containers/MobilePushNew/sagas.js +193 -0
- package/v2Containers/MobilePushNew/selectors.js +55 -0
- package/v2Containers/MobilePushNew/tests/reducer.test.js +741 -0
- package/v2Containers/MobilePushNew/tests/sagas.test.js +864 -0
- package/v2Containers/MobilePushNew/tests/selectors.test.js +665 -0
- package/v2Containers/MobilePushNew/tests/utils.test.js +421 -0
- package/v2Containers/MobilePushNew/utils.js +84 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +1176 -976
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +684 -424
- package/v2Containers/TagList/index.js +56 -10
- package/v2Containers/Templates/_templates.scss +100 -1
- package/v2Containers/Templates/index.js +170 -31
- package/v2Containers/Templates/messages.js +8 -0
- package/v2Containers/Templates/sagas.js +1 -0
- package/v2Containers/Whatsapp/constants.js +1 -0
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +3992 -3677
- package/assets/loading_img.gif +0 -0
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
* CapVideoUpload
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
|
-
import React, {
|
|
6
|
+
import React, {
|
|
7
|
+
useCallback, useState, Fragment, useRef, useEffect,
|
|
8
|
+
} from 'react';
|
|
7
9
|
import PropTypes from "prop-types";
|
|
8
10
|
import get from 'lodash/get';
|
|
9
11
|
import CapDrawer from '@capillarytech/cap-ui-library/CapDrawer';
|
|
@@ -19,9 +21,12 @@ import {
|
|
|
19
21
|
} from '@capillarytech/cap-ui-library';
|
|
20
22
|
import messages from './messages';
|
|
21
23
|
import {bytes2Size, getDecodedFileName} from '../../utils/common';
|
|
22
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
SUPPORTED_FILE_FORMATS, WHATSAPP, DEFAULT, MAX_DURATION, MOBILEPUSH,
|
|
26
|
+
} from './constants';
|
|
23
27
|
import './index.scss';
|
|
24
28
|
import { VIBER } from '../../v2Containers/CreativesContainer/constants';
|
|
29
|
+
import { GIF, VIDEO } from '../../v2Containers/MobilePushNew/constants';
|
|
25
30
|
|
|
26
31
|
function CapVideoUpload(props) {
|
|
27
32
|
const {
|
|
@@ -40,6 +45,9 @@ function CapVideoUpload(props) {
|
|
|
40
45
|
showVideoNameAndDuration = true,
|
|
41
46
|
formClassName = 'video-form',
|
|
42
47
|
showReUploadButton = true,
|
|
48
|
+
mediaType = VIDEO.toLowerCase(),
|
|
49
|
+
assetUploading = false, // Add assetUploading prop
|
|
50
|
+
videoSrc: propVideoSrc = '', // Add videoSrc prop for fallback
|
|
43
51
|
} = props;
|
|
44
52
|
const [isVideoError, updateVideoErrorMessage] = useState(false);
|
|
45
53
|
const [isVideo, updateVideoStatus] = useState(false);
|
|
@@ -50,7 +58,7 @@ function CapVideoUpload(props) {
|
|
|
50
58
|
|
|
51
59
|
const videoEl = useRef(null);
|
|
52
60
|
const {
|
|
53
|
-
videoSrc = '',
|
|
61
|
+
videoSrc: uploadedVideoSrc = '',
|
|
54
62
|
videoName,
|
|
55
63
|
previewUrl,
|
|
56
64
|
videoHeight,
|
|
@@ -59,6 +67,10 @@ function CapVideoUpload(props) {
|
|
|
59
67
|
fileHandle = '',
|
|
60
68
|
} = uploadedAssetList;
|
|
61
69
|
|
|
70
|
+
// Use uploadedAssetList.videoSrc first, then fall back to prop videoSrc
|
|
71
|
+
// Only use propVideoSrc if uploadedVideoSrc is empty to avoid conflicts with upload logic
|
|
72
|
+
const videoSrc = uploadedVideoSrc || (uploadedVideoSrc === '' ? propVideoSrc : '');
|
|
73
|
+
|
|
62
74
|
const [isTemplateDrawerRequired, updateTemplateDrawerRequirement] = useState(false);
|
|
63
75
|
|
|
64
76
|
const uploadVideo = useCallback((e, { files }) => {
|
|
@@ -68,6 +80,7 @@ function CapVideoUpload(props) {
|
|
|
68
80
|
const _URL = window.URL || window.webkitURL;
|
|
69
81
|
let incorrectFile = false;
|
|
70
82
|
const file = files[0];
|
|
83
|
+
|
|
71
84
|
if (!allowedExtensionsRegex.test(file.name)) {
|
|
72
85
|
incorrectFile = true;
|
|
73
86
|
}
|
|
@@ -79,7 +92,7 @@ function CapVideoUpload(props) {
|
|
|
79
92
|
error: false,
|
|
80
93
|
isGenerateVideoThumbnail: true,
|
|
81
94
|
};
|
|
82
|
-
submitVideoAction({ file, type:
|
|
95
|
+
submitVideoAction({ file, type: mediaType, fileParams }, incorrectFile);
|
|
83
96
|
if (e) {
|
|
84
97
|
const event = e;
|
|
85
98
|
event.target.value = null;
|
|
@@ -87,10 +100,18 @@ function CapVideoUpload(props) {
|
|
|
87
100
|
}, []);
|
|
88
101
|
|
|
89
102
|
useEffect(() => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
103
|
+
}, [videoData, index]);
|
|
104
|
+
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
if (!isEmpty(videoData[`uploadedAssetData${index}`])) {
|
|
107
|
+
const {
|
|
108
|
+
metaInfo: {
|
|
109
|
+
secure_file_path: metaVideoSrc = '',
|
|
110
|
+
file_name: metaVideoName = '',
|
|
111
|
+
preview_image_url: previewImgUrl = '',
|
|
112
|
+
} = {},
|
|
113
|
+
} = videoData[`uploadedAssetData${index}`] || {};
|
|
114
|
+
|
|
94
115
|
const metaVideoId = get(videoData, `uploadedAssetData${index}.videoIdResponse.fbVideo.id`, '');
|
|
95
116
|
const karixFileHandle = get(videoData, `uploadedAssetData${index}.metaInfo.karixFileHandle`, '');
|
|
96
117
|
|
|
@@ -102,18 +123,15 @@ function CapVideoUpload(props) {
|
|
|
102
123
|
videoId: metaVideoId,
|
|
103
124
|
fileHandle: karixFileHandle,
|
|
104
125
|
videoDuration: null,
|
|
105
|
-
}
|
|
106
|
-
);
|
|
126
|
+
});
|
|
107
127
|
}
|
|
108
128
|
}
|
|
109
|
-
}, [videoData
|
|
129
|
+
}, [videoData, index, videoSrc, onVideoUploadUpdateAssestList]);
|
|
110
130
|
|
|
111
131
|
useEffect(() => {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
}, [videoData[`assetUploadingVideo_${index}`]]);
|
|
132
|
+
// Use the assetUploading prop directly for loading state
|
|
133
|
+
setSpinning(assetUploading);
|
|
134
|
+
}, [assetUploading]);
|
|
117
135
|
|
|
118
136
|
|
|
119
137
|
useEffect(() => {
|
|
@@ -123,7 +141,12 @@ function CapVideoUpload(props) {
|
|
|
123
141
|
} = uploadedAssetList || {};
|
|
124
142
|
if (metaVideoSrc) {
|
|
125
143
|
updateVideoStatus(true);
|
|
144
|
+
} else {
|
|
145
|
+
updateVideoStatus(false);
|
|
126
146
|
}
|
|
147
|
+
} else {
|
|
148
|
+
// When uploadedAssetList is empty, reset video status to show upload interface
|
|
149
|
+
updateVideoStatus(false);
|
|
127
150
|
}
|
|
128
151
|
}, [uploadedAssetList]);
|
|
129
152
|
|
|
@@ -136,6 +159,7 @@ function CapVideoUpload(props) {
|
|
|
136
159
|
fileParams,
|
|
137
160
|
type,
|
|
138
161
|
} = data;
|
|
162
|
+
|
|
139
163
|
if (incorrectFile || size > videoSize) {
|
|
140
164
|
if (errorMessage) {
|
|
141
165
|
updateVideoErrorMessage(errorMessage);
|
|
@@ -155,11 +179,7 @@ function CapVideoUpload(props) {
|
|
|
155
179
|
|
|
156
180
|
const {
|
|
157
181
|
formatMessage,
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const capUploaderCustomVideoRequest = useCallback((uploadData) => {
|
|
161
|
-
uploadVideo(undefined, { files: [uploadData.file] });
|
|
162
|
-
}, []);
|
|
182
|
+
} = intl || {};
|
|
163
183
|
|
|
164
184
|
const playVideo = useCallback((e) => {
|
|
165
185
|
if (e.target.paused && !isPlaying) {
|
|
@@ -173,78 +193,90 @@ function CapVideoUpload(props) {
|
|
|
173
193
|
}
|
|
174
194
|
}, [isPlaying]);
|
|
175
195
|
|
|
196
|
+
const onReUpload = useCallback(() => {
|
|
197
|
+
updateVideoStatus(false);
|
|
198
|
+
updateVideoDuration(null);
|
|
199
|
+
onVideoUploadUpdateAssestList(
|
|
200
|
+
index,
|
|
201
|
+
{
|
|
202
|
+
previewUrl: "",
|
|
203
|
+
videoName: "",
|
|
204
|
+
videoHeight: "",
|
|
205
|
+
videoWidth: "",
|
|
206
|
+
videoSrc: "",
|
|
207
|
+
videoDuration: null,
|
|
208
|
+
videoId: "",
|
|
209
|
+
fileHandle: "",
|
|
210
|
+
}
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
// Reset file input value to allow re-upload of same file
|
|
214
|
+
setTimeout(() => {
|
|
215
|
+
const fileInput = document.getElementById("videoFileName");
|
|
216
|
+
if (fileInput) {
|
|
217
|
+
// eslint-disable-next-line no-param-reassign
|
|
218
|
+
fileInput.value = '';
|
|
219
|
+
fileInput.click();
|
|
220
|
+
}
|
|
221
|
+
}, 100);
|
|
222
|
+
}, [index, onVideoUploadUpdateAssestList]);
|
|
223
|
+
|
|
224
|
+
const updateMetadataLoaded = useCallback(() => {
|
|
225
|
+
const { current: { duration, videoHeight: metaVideoHeight, videoWidth: metaVideoWidth } = {} } = videoEl;
|
|
226
|
+
if (duration) {
|
|
227
|
+
updateVideoDuration(duration);
|
|
228
|
+
if (videoWidth === undefined && videoHeight === undefined) {
|
|
229
|
+
if (duration <= MAX_DURATION) {
|
|
230
|
+
onVideoUploadUpdateAssestList(index, {
|
|
231
|
+
videoSrc,
|
|
232
|
+
videoId,
|
|
233
|
+
videoName,
|
|
234
|
+
videoHeight: metaVideoHeight,
|
|
235
|
+
videoWidth: metaVideoWidth,
|
|
236
|
+
previewUrl,
|
|
237
|
+
fileHandle,
|
|
238
|
+
videoDuration: duration,
|
|
239
|
+
});
|
|
240
|
+
} else {
|
|
241
|
+
onReUpload();
|
|
242
|
+
updateVideoErrorMessage(formatMessage(messages.videoDurationError));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}, [videoSrc, videoId, videoName, previewUrl, fileHandle, videoWidth, videoHeight, index, onVideoUploadUpdateAssestList, formatMessage, onReUpload]);
|
|
247
|
+
|
|
248
|
+
const videoDurationValue = videoDuration ? moment('1900-01-01 00:00:00').add(videoDuration, 'seconds').format("HH.mm.ss") : '';
|
|
249
|
+
|
|
250
|
+
const capUploaderCustomVideoRequest = useCallback((uploadData) => {
|
|
251
|
+
uploadVideo(undefined, { files: [uploadData.file] });
|
|
252
|
+
}, [uploadVideo]);
|
|
253
|
+
|
|
176
254
|
const getVideoSection = () => {
|
|
177
255
|
if (!isVideo) {
|
|
178
256
|
return (
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
>
|
|
186
|
-
<
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
<
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
<
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
</>
|
|
200
|
-
)
|
|
257
|
+
<>
|
|
258
|
+
<CapUploader.CapDragger
|
|
259
|
+
customRequest={(data) => capUploaderCustomVideoRequest(data)}
|
|
260
|
+
className="form-builder-dragger whatsapp-background"
|
|
261
|
+
showUploadList={!isVideoError}
|
|
262
|
+
>
|
|
263
|
+
<CapHeading className="dragger-title" type="h7">
|
|
264
|
+
<FormattedMessage {...messages.dragAndDrop} />
|
|
265
|
+
</CapHeading>
|
|
266
|
+
<CapHeading className="dragger-or" type="label6">
|
|
267
|
+
<FormattedMessage {...messages.or} />
|
|
268
|
+
</CapHeading>
|
|
269
|
+
<CapButton className="dragger-button upload-video" type="secondary">
|
|
270
|
+
<FormattedMessage {...messages.selectFromComputer} />
|
|
271
|
+
</CapButton>
|
|
272
|
+
</CapUploader.CapDragger>
|
|
273
|
+
<CapError type="error" className="upload-video-error">
|
|
274
|
+
{isVideoError}
|
|
275
|
+
</CapError>
|
|
276
|
+
</>
|
|
201
277
|
);
|
|
202
278
|
}
|
|
203
|
-
const onReUpload = () => {
|
|
204
|
-
updateVideoStatus(false);
|
|
205
|
-
updateVideoDuration(null);
|
|
206
|
-
onVideoUploadUpdateAssestList(
|
|
207
|
-
index,
|
|
208
|
-
{
|
|
209
|
-
previewUrl: "",
|
|
210
|
-
videoName: "",
|
|
211
|
-
videoHeight: "",
|
|
212
|
-
videoWidth: "",
|
|
213
|
-
videoSrc: "",
|
|
214
|
-
videoDuration: null,
|
|
215
|
-
videoId: "",
|
|
216
|
-
fileHandle: "",
|
|
217
|
-
}
|
|
218
|
-
);
|
|
219
|
-
};
|
|
220
279
|
|
|
221
|
-
const updateMetadataLoaded = () => {
|
|
222
|
-
const { current: { duration, videoHeight: metaVideoHeight, videoWidth: metaVideoWidth } = {} } = videoEl;
|
|
223
|
-
if (duration) {
|
|
224
|
-
updateVideoDuration(duration);
|
|
225
|
-
if (videoWidth === undefined && videoHeight === undefined) {
|
|
226
|
-
if (
|
|
227
|
-
channel !== VIBER ||
|
|
228
|
-
(channel === VIBER && duration <= VIBER_MAX_DURATION)
|
|
229
|
-
) {
|
|
230
|
-
onVideoUploadUpdateAssestList(index, {
|
|
231
|
-
videoSrc,
|
|
232
|
-
videoId,
|
|
233
|
-
videoName,
|
|
234
|
-
videoHeight: metaVideoHeight,
|
|
235
|
-
videoWidth: metaVideoWidth,
|
|
236
|
-
previewUrl,
|
|
237
|
-
fileHandle,
|
|
238
|
-
videoDuration: duration,
|
|
239
|
-
});
|
|
240
|
-
} else {
|
|
241
|
-
onReUpload();
|
|
242
|
-
updateVideoErrorMessage(formatMessage(messages.videoDurationError));
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
};
|
|
247
|
-
const videoDurationValue = moment('1900-01-01 00:00:00').add(videoDuration, 'seconds').format("HH.mm.ss"); // to get the duration of video
|
|
248
280
|
return (
|
|
249
281
|
<Fragment key={videoSrc}>
|
|
250
282
|
{showReUploadButton && (
|
|
@@ -259,21 +291,35 @@ function CapVideoUpload(props) {
|
|
|
259
291
|
</div>
|
|
260
292
|
)}
|
|
261
293
|
<div className={showVideoNameAndDuration ? 'video-panel' : 'video-panel-wp'}>
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
294
|
+
{mediaType === GIF.toLowerCase() ? (
|
|
295
|
+
<img
|
|
296
|
+
width="230"
|
|
297
|
+
src={videoSrc}
|
|
298
|
+
alt="GIF preview"
|
|
299
|
+
className="line-image-src"
|
|
300
|
+
key={`${index}-gif`}
|
|
301
|
+
style={{ maxWidth: '230px', maxHeight: '200px', objectFit: 'contain' }}
|
|
302
|
+
/>
|
|
303
|
+
) : (
|
|
304
|
+
<video
|
|
305
|
+
width="230"
|
|
306
|
+
poster={previewUrl}
|
|
307
|
+
className="line-image-src"
|
|
308
|
+
key={`${index}-video`}
|
|
309
|
+
onLoadedMetadata={updateMetadataLoaded}
|
|
310
|
+
onPlaying={() => updateIsPlaying(true)}
|
|
311
|
+
onPause={() => updateIsPlaying(false)}
|
|
312
|
+
onMouseOver={playVideo}
|
|
313
|
+
onMouseOut={pauseVideo}
|
|
314
|
+
onFocus={playVideo}
|
|
315
|
+
onBlur={pauseVideo}
|
|
316
|
+
ref={videoEl}
|
|
317
|
+
>
|
|
318
|
+
<source src={videoSrc} type="video/mp4" />
|
|
319
|
+
<track kind="captions" />
|
|
320
|
+
</video>
|
|
321
|
+
)}
|
|
322
|
+
{showVideoNameAndDuration && (
|
|
277
323
|
<div className="video-info">
|
|
278
324
|
<CapHeading type="h4">
|
|
279
325
|
{getDecodedFileName(videoName)}
|
|
@@ -282,7 +328,7 @@ function CapVideoUpload(props) {
|
|
|
282
328
|
{videoDurationValue}
|
|
283
329
|
</CapHeading>
|
|
284
330
|
</div>
|
|
285
|
-
}
|
|
331
|
+
)}
|
|
286
332
|
</div>
|
|
287
333
|
</Fragment>
|
|
288
334
|
);
|
|
@@ -300,23 +346,24 @@ function CapVideoUpload(props) {
|
|
|
300
346
|
return (
|
|
301
347
|
<CapSpin spinning={isSpinning}>
|
|
302
348
|
<div style={style} className="cap-custom-video-upload">
|
|
303
|
-
<form encType="multipart/form-data" id=
|
|
349
|
+
<form encType="multipart/form-data" id="form" className={formClassName}>
|
|
304
350
|
<input
|
|
305
|
-
key={`videoFile`}
|
|
351
|
+
key={`videoFile-${index}-${isVideo ? 'uploaded' : 'empty'}`}
|
|
306
352
|
style={{ display: 'none' }}
|
|
307
|
-
id="
|
|
353
|
+
id="videoFileName"
|
|
308
354
|
type="file"
|
|
309
355
|
onChange={(e) => uploadVideo(e, { files: e.target.files })}
|
|
310
|
-
accept={supportedExtensions || "video/*"}
|
|
311
|
-
|
|
356
|
+
accept={mediaType === GIF.toLowerCase() ? '.gif' : (supportedExtensions || "video/*")}
|
|
357
|
+
/>
|
|
312
358
|
{getVideoSection()}
|
|
313
359
|
<CapDrawer
|
|
314
360
|
visible={isTemplateDrawerRequired}
|
|
315
361
|
width={624}
|
|
316
362
|
onClose={() => updateTemplateDrawerRequirement(false)}
|
|
317
|
-
|
|
363
|
+
/>
|
|
318
364
|
</form>
|
|
319
|
-
{![WHATSAPP, VIBER].includes(channel)
|
|
365
|
+
{![WHATSAPP, VIBER, MOBILEPUSH].includes(channel)
|
|
366
|
+
&& (
|
|
320
367
|
<>
|
|
321
368
|
<CapHeading.CapHeadingSpan type="h6" className="video-description">
|
|
322
369
|
<FormattedMessage {...messages.videoRatioDescription} />
|
|
@@ -328,15 +375,18 @@ function CapVideoUpload(props) {
|
|
|
328
375
|
<CapHeading.CapHeadingSpan type="h6" className="video-description video-details">
|
|
329
376
|
<FormattedMessage {...messages.videoSizeDescription} values={{size: bytes2Size(videoSize)}} />
|
|
330
377
|
</CapHeading.CapHeadingSpan>
|
|
331
|
-
</>
|
|
332
|
-
|
|
378
|
+
</>
|
|
379
|
+
)}
|
|
380
|
+
{channel === WHATSAPP
|
|
381
|
+
&& (
|
|
333
382
|
<>
|
|
334
383
|
{getVideoSizeDescription()}
|
|
335
384
|
<CapHeading.CapHeadingSpan type="label2" className="whatsapp-format">
|
|
336
385
|
<FormattedMessage {...messages.channelFileFormat} values={{ format: SUPPORTED_FILE_FORMATS[DEFAULT] }} />
|
|
337
386
|
</CapHeading.CapHeadingSpan>
|
|
338
|
-
</>
|
|
339
|
-
|
|
387
|
+
</>
|
|
388
|
+
)}
|
|
389
|
+
{channel === VIBER && (
|
|
340
390
|
<>
|
|
341
391
|
{getVideoSizeDescription()}
|
|
342
392
|
<CapHeading.CapHeadingSpan type="label2" className="whatsapp-format">
|
|
@@ -345,7 +395,20 @@ function CapVideoUpload(props) {
|
|
|
345
395
|
<CapHeading.CapHeadingSpan type="label2" className="video-duration">
|
|
346
396
|
<FormattedMessage {...messages.viberMaxDuration} />
|
|
347
397
|
</CapHeading.CapHeadingSpan>
|
|
348
|
-
</>
|
|
398
|
+
</>
|
|
399
|
+
)}
|
|
400
|
+
{channel === MOBILEPUSH
|
|
401
|
+
&& (
|
|
402
|
+
<>
|
|
403
|
+
{getVideoSizeDescription()}
|
|
404
|
+
<CapHeading.CapHeadingSpan type="label2" className="whatsapp-format">
|
|
405
|
+
<FormattedMessage {...messages.channelFileFormat} values={{ format: SUPPORTED_FILE_FORMATS.MOBILEPUSH }} />
|
|
406
|
+
</CapHeading.CapHeadingSpan>
|
|
407
|
+
<CapHeading.CapHeadingSpan type="label2" className="video-duration">
|
|
408
|
+
<FormattedMessage {...messages.maxDuration} />
|
|
409
|
+
</CapHeading.CapHeadingSpan>
|
|
410
|
+
</>
|
|
411
|
+
)}
|
|
349
412
|
</div>
|
|
350
413
|
</CapSpin>
|
|
351
414
|
);
|
|
@@ -366,6 +429,10 @@ CapVideoUpload.propTypes = {
|
|
|
366
429
|
channel: PropTypes.string,
|
|
367
430
|
errorMessage: PropTypes.string,
|
|
368
431
|
formClassName: PropTypes.string,
|
|
432
|
+
showReUploadButton: PropTypes.bool,
|
|
433
|
+
mediaType: PropTypes.string,
|
|
434
|
+
assetUploading: PropTypes.bool,
|
|
435
|
+
videoSrc: PropTypes.string,
|
|
369
436
|
};
|
|
370
437
|
|
|
371
438
|
export default injectIntl(CapVideoUpload);
|
|
@@ -63,8 +63,24 @@ export default defineMessages({
|
|
|
63
63
|
id: `${scope}.viberMaxDuration`,
|
|
64
64
|
defaultMessage: 'Max Duration: 600 seconds',
|
|
65
65
|
},
|
|
66
|
+
maxDuration: {
|
|
67
|
+
id: `${scope}.maxDuration`,
|
|
68
|
+
defaultMessage: 'Max duration: 600 seconds',
|
|
69
|
+
},
|
|
66
70
|
videoDurationError: {
|
|
67
71
|
id: `${scope}.videoDurationError`,
|
|
68
72
|
defaultMessage: 'Video duration should not exceed 600 seconds',
|
|
69
73
|
},
|
|
74
|
+
uploadVideo: {
|
|
75
|
+
id: `${scope}.uploadVideo`,
|
|
76
|
+
defaultMessage: 'Upload Video',
|
|
77
|
+
},
|
|
78
|
+
reUpload: {
|
|
79
|
+
id: `${scope}.reUpload`,
|
|
80
|
+
defaultMessage: 'Re-upload',
|
|
81
|
+
},
|
|
82
|
+
videoDuration: {
|
|
83
|
+
id: `${scope}.videoDuration`,
|
|
84
|
+
defaultMessage: 'Duration: {duration}',
|
|
85
|
+
},
|
|
70
86
|
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import { Carousel
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Carousel } from 'antd';
|
|
3
3
|
import './style.scss';
|
|
4
4
|
import CapImage from '@capillarytech/cap-ui-library/CapImage';
|
|
5
5
|
import CapButton from '@capillarytech/cap-ui-library/CapButton';
|
|
6
6
|
import CapIcon from '@capillarytech/cap-ui-library/CapIcon';
|
|
7
|
+
import { CAP_WHITE } from '@capillarytech/cap-ui-library/styled/variables';
|
|
7
8
|
const lineImgPlaceholder = require('../../assets/line-image-placeholder.svg');
|
|
8
|
-
import { CAP_WHITE, CAP_G08 } from '@capillarytech/cap-ui-library/styled/variables';
|
|
9
9
|
|
|
10
10
|
const arrowStyle = {
|
|
11
11
|
background: 'rgba(0, 0, 0, 0.1)',
|
|
@@ -16,10 +16,12 @@ const arrowStyle = {
|
|
|
16
16
|
height: 24,
|
|
17
17
|
width: 24,
|
|
18
18
|
borderRadius: '50%',
|
|
19
|
-
}
|
|
19
|
+
};
|
|
20
20
|
|
|
21
|
-
const Arrow = props => {
|
|
22
|
-
const {
|
|
21
|
+
const Arrow = (props) => {
|
|
22
|
+
const {
|
|
23
|
+
className, style, onClick, extraStyle, type,
|
|
24
|
+
} = props;
|
|
23
25
|
return (
|
|
24
26
|
<CapButton
|
|
25
27
|
className={className}
|
|
@@ -35,8 +37,8 @@ const Arrow = props => {
|
|
|
35
37
|
type={type}
|
|
36
38
|
/>
|
|
37
39
|
</CapButton>
|
|
38
|
-
)
|
|
39
|
-
}
|
|
40
|
+
);
|
|
41
|
+
};
|
|
40
42
|
|
|
41
43
|
const settings = {
|
|
42
44
|
nextArrow: (
|
|
@@ -56,7 +58,7 @@ const settings = {
|
|
|
56
58
|
type="chevron-left"
|
|
57
59
|
/>
|
|
58
60
|
),
|
|
59
|
-
}
|
|
61
|
+
};
|
|
60
62
|
|
|
61
63
|
const CarouselComponent = ({
|
|
62
64
|
imageCarousel,
|
|
@@ -81,11 +83,11 @@ const CarouselComponent = ({
|
|
|
81
83
|
|
|
82
84
|
return (
|
|
83
85
|
<div style={{ position: 'relative' }} className={`template-carousel ${imageCarouselLength ? 'single-img' : ''}`}>
|
|
84
|
-
<Carousel ref={node => (carousel = node)} {...prop} {...settings}>
|
|
86
|
+
<Carousel ref={(node) => (carousel = node)} {...prop} {...settings}>
|
|
85
87
|
{
|
|
86
88
|
imageCarousel.map(({
|
|
87
89
|
actionLabel,
|
|
88
|
-
imageUrl = lineImgPlaceholder
|
|
90
|
+
imageUrl = lineImgPlaceholder,
|
|
89
91
|
}) => (
|
|
90
92
|
<div className="carousel-section">
|
|
91
93
|
<CapImage
|
|
@@ -115,6 +117,6 @@ const CarouselComponent = ({
|
|
|
115
117
|
</Carousel>
|
|
116
118
|
</div>
|
|
117
119
|
);
|
|
118
|
-
}
|
|
120
|
+
};
|
|
119
121
|
|
|
120
|
-
export default CarouselComponent;
|
|
122
|
+
export default CarouselComponent;
|
|
@@ -8,13 +8,14 @@ import PropTypes from 'prop-types';
|
|
|
8
8
|
|
|
9
9
|
import React from 'react';
|
|
10
10
|
import { CapTab, CapIcon } from '@capillarytech/cap-ui-library';
|
|
11
|
-
import { get,
|
|
11
|
+
import { get, isEmpty} from 'lodash';
|
|
12
12
|
import TemplatePreview from '../TemplatePreview';
|
|
13
13
|
import '../PreviewSideBar/_previewsidebar.scss';
|
|
14
14
|
import { MOBILE_PUSH } from '../../v2Containers/CreativesContainer/constants';
|
|
15
15
|
import { INAPP } from '../../v2Containers/App/constants';
|
|
16
16
|
import { ANDROID, IOS } from '../../v2Containers/InApp/constants';
|
|
17
17
|
import { getCtaObject } from '../../v2Containers/InApp/utils';
|
|
18
|
+
import { CAROUSEL, VIDEO } from '../../v2Containers/MobilePushNew/constants';
|
|
18
19
|
|
|
19
20
|
class MobilePushPreviewV2 extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
|
20
21
|
constructor(props) {
|
|
@@ -64,25 +65,65 @@ class MobilePushPreviewV2 extends React.Component { // eslint-disable-line react
|
|
|
64
65
|
const androidContent = get(templateData, 'versions.base.ANDROID') || get(templateData, 'androidContent');
|
|
65
66
|
const iosContent = get(templateData, 'versions.base.IOS') || get(templateData, 'iosContent');
|
|
66
67
|
|
|
67
|
-
const data = device === "android" ? androidContent : iosContent;
|
|
68
|
-
const {
|
|
68
|
+
const data = device?.toLowerCase() === "android" ? androidContent : iosContent;
|
|
69
|
+
const {
|
|
70
|
+
title = '', message = '', type = '', expandableDetails: {
|
|
71
|
+
ctas = [], image = '', media = [], carouselData = [],
|
|
72
|
+
} = {},
|
|
73
|
+
} = data || {};
|
|
74
|
+
|
|
75
|
+
// Handle video/GIF content from expandableDetails.media array (new format)
|
|
76
|
+
let bodyVideo = {};
|
|
77
|
+
let bodyGif = '';
|
|
78
|
+
let bodyImage = image;
|
|
79
|
+
|
|
80
|
+
if (media?.length > 0) {
|
|
81
|
+
const mediaItem = media[0];
|
|
82
|
+
const { type, url } = mediaItem;
|
|
83
|
+
if (type === VIDEO) {
|
|
84
|
+
// Distinguish between actual video and GIF based on URL extension
|
|
85
|
+
if (url && url?.toLowerCase()?.includes('.gif')) {
|
|
86
|
+
bodyGif = url;
|
|
87
|
+
} else {
|
|
88
|
+
bodyVideo = {
|
|
89
|
+
videoSrc: url,
|
|
90
|
+
videoPreview: url,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
// Clear bodyImage when we have video/GIF content
|
|
94
|
+
bodyImage = '';
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
69
98
|
content = {
|
|
70
99
|
header: title,
|
|
71
100
|
bodyText: message,
|
|
72
|
-
bodyImage
|
|
101
|
+
bodyImage,
|
|
102
|
+
bodyVideo,
|
|
103
|
+
bodyGif,
|
|
73
104
|
actions: [],
|
|
74
105
|
appName: templateData?.appName,
|
|
106
|
+
carouselData,
|
|
75
107
|
};
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
108
|
+
|
|
109
|
+
// Map CTAs consistently for both Android and iOS
|
|
110
|
+
if (ctas.length > 0 && type !== CAROUSEL) {
|
|
111
|
+
content.actions = ctas.map((cta) => {
|
|
112
|
+
const {
|
|
113
|
+
actionText, type: Type, actionLink, deepLinkKeys,
|
|
114
|
+
} = cta || {};
|
|
115
|
+
return {
|
|
116
|
+
label: actionText || '',
|
|
117
|
+
type: Type || '',
|
|
118
|
+
url: actionLink || '',
|
|
119
|
+
deepLinkKeys: deepLinkKeys || [],
|
|
120
|
+
};
|
|
121
|
+
});
|
|
82
122
|
}
|
|
83
123
|
}
|
|
84
124
|
return content;
|
|
85
125
|
}
|
|
126
|
+
|
|
86
127
|
getPreview(device) {
|
|
87
128
|
const deviceParam = device === ANDROID.toLowerCase() ? ANDROID : IOS;
|
|
88
129
|
return (
|
|
@@ -95,17 +136,21 @@ class MobilePushPreviewV2 extends React.Component { // eslint-disable-line react
|
|
|
95
136
|
/>
|
|
96
137
|
);
|
|
97
138
|
}
|
|
139
|
+
|
|
98
140
|
goToDuplicate() {
|
|
99
141
|
this.props.onDuplicateClick(this.props.templateData);
|
|
100
142
|
this.props.handleClose();
|
|
101
143
|
}
|
|
144
|
+
|
|
102
145
|
changeDevice(device) {
|
|
103
146
|
const content = this.setContent(this.props.templateData, device, this.props.channel);
|
|
104
147
|
this.setState({device, content });
|
|
105
148
|
}
|
|
149
|
+
|
|
106
150
|
goToEdit(e, path) {
|
|
107
151
|
this.props.onEditClick(e, this.props.templateData._id, this.props.templateData.modeType, path);
|
|
108
152
|
}
|
|
153
|
+
|
|
109
154
|
render() {
|
|
110
155
|
const {templateData} = this.props;
|
|
111
156
|
let hasAndroid;
|
|
@@ -121,8 +166,8 @@ class MobilePushPreviewV2 extends React.Component { // eslint-disable-line react
|
|
|
121
166
|
return (
|
|
122
167
|
<div>
|
|
123
168
|
<div className="devices">
|
|
124
|
-
{!isEmpty(templateData)
|
|
125
|
-
( hasBothAndroidAndIos ? (
|
|
169
|
+
{!isEmpty(templateData)
|
|
170
|
+
&& ( hasBothAndroidAndIos ? (
|
|
126
171
|
<CapTab
|
|
127
172
|
panes={[
|
|
128
173
|
{
|