@capillarytech/creatives-library 6.9.2 → 6.9.7

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.
Files changed (32) hide show
  1. package/components/TemplatePreview/_templatePreview.scss +6 -0
  2. package/components/TemplatePreview/index.js +35 -28
  3. package/config/app.js +1 -1
  4. package/index.html +0 -2
  5. package/package.json +1 -1
  6. package/v2Components/Carousel/index.js +120 -0
  7. package/v2Components/Carousel/style.scss +40 -0
  8. package/v2Components/TemplatePreview/_templatePreview.scss +1 -0
  9. package/v2Components/TemplatePreview/index.js +36 -29
  10. package/v2Containers/CreativesContainer/SlideBoxContent.js +7 -1
  11. package/v2Containers/Line/Container/Image/index.js +21 -19
  12. package/v2Containers/Line/Container/ImageCarousel/Content.js +554 -0
  13. package/v2Containers/Line/Container/ImageCarousel/constants.js +10 -0
  14. package/v2Containers/Line/Container/ImageCarousel/index.js +526 -0
  15. package/v2Containers/Line/Container/ImageCarousel/messages.js +178 -0
  16. package/v2Containers/Line/Container/ImageCarousel/style.js +61 -0
  17. package/v2Containers/Line/Container/ImageMap/constants.js +2 -1
  18. package/v2Containers/Line/Container/ImageMap/index.js +31 -6
  19. package/v2Containers/Line/Container/ImageMap/messages.js +12 -0
  20. package/v2Containers/Line/Container/Wrapper/index.js +5 -1
  21. package/v2Containers/Line/Container/Wrapper/messages.js +4 -0
  22. package/v2Containers/Line/Container/Wrapper/utils.js +15 -16
  23. package/v2Containers/Line/Container/_lineCreate.scss +2 -2
  24. package/v2Containers/Line/Container/actions.js +4 -2
  25. package/v2Containers/Line/Container/constants.js +3 -0
  26. package/v2Containers/Line/Container/index.js +49 -11
  27. package/v2Containers/Line/Container/reducer.js +2 -2
  28. package/v2Containers/Line/Container/sagas.js +2 -2
  29. package/v2Containers/Line/Container/style.js +2 -1
  30. package/v2Containers/Templates/_templates.scss +9 -0
  31. package/v2Containers/Templates/index.js +28 -1
  32. package/v2Containers/Templates/messages.js +4 -0
@@ -0,0 +1,554 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { injectIntl, FormattedMessage } from 'react-intl';
3
+ import get from 'lodash/get';
4
+ import CapInput from '@capillarytech/cap-ui-library/CapInput';
5
+ import CapSelect from '@capillarytech/cap-ui-library/CapSelect';
6
+ import CapUploader from '@capillarytech/cap-ui-library/CapUploader';
7
+ import CapHeading from '@capillarytech/cap-ui-library/CapHeading';
8
+ import CapButton from '@capillarytech/cap-ui-library/CapButton';
9
+ import CapDrawer from '@capillarytech/cap-ui-library/CapDrawer';
10
+ import CapImage from '@capillarytech/cap-ui-library/CapImage';
11
+ import CapHeader from '@capillarytech/cap-ui-library/CapHeader';
12
+ import CapRow from '@capillarytech/cap-ui-library/CapRow';
13
+ import CapColumn from '@capillarytech/cap-ui-library/CapColumn';
14
+ import LabelHOC from '@capillarytech/cap-ui-library/assets/HOCs/ComponentWithLabelHOC';
15
+ import lineImgPlaceholder from '../../../../assets/line-image-placeholder.svg';
16
+ import { isUrl } from '../Wrapper/utils';
17
+ import { CAP_SPACE_12, CAP_SPACE_08, FONT_COLOR_05, CAP_WHITE, FONT_COLOR_01, CAP_G09, CAP_G08 } from '@capillarytech/cap-ui-library/styled/variables';
18
+ import Gallery from '../../../Assets/Gallery';
19
+ import style from './style';
20
+ import withStyles from '../../../../hoc/withStyles';
21
+
22
+ import messages from './messages';
23
+ import {
24
+ LINE_IMG_HEIGHT,
25
+ LINE_IMG_WIDTH,
26
+ LINE_IMG_SIZE,
27
+ ALLOWED_EXTENSIONS_REGEX,
28
+ URL_ACTION_TYPE,
29
+ TEXT_ACTION_TYPE,
30
+ MAX_ACTION_LABEL_LENGTH,
31
+ } from './constants';
32
+
33
+ export const LineImageCarouselContent = ({
34
+ id,
35
+ intl: { formatMessage },
36
+ isFullMode,
37
+ supportedExtensions,
38
+ actions = {},
39
+ Line,
40
+ index,
41
+ updateCarouselMessageState,
42
+ content,
43
+ uploadedAssetList,
44
+ updateUploadedAssetList,
45
+ activeIndex,
46
+ }) => {
47
+ const [isDrawerRequired, updateDrawerRequirement] = useState(false);
48
+ const [isImageError, updateImageErrorMessage] = useState(false);
49
+ const [imageSrc, updateImageSrc] = useState();
50
+ const [isImage, updateImageStatus] = useState(false);
51
+ const [selectedActionType, updateActionType] = useState('');
52
+ const [actionLabel, updateActionLabel] = useState('');
53
+ const [actionContent, updateActionContent] = useState('');
54
+ const [actionContentErrorMessage, updateActionContentErrorMessage] = useState(false);
55
+ const [actionLabelErrorMessage, updateActionLabelErrorMessage] = useState(false);
56
+
57
+ useEffect(() => {
58
+ const {
59
+ originalContentUrl = '',
60
+ type,
61
+ selectedActionType = '',
62
+ actionLabel = '',
63
+ actionContent = '',
64
+ } = content;
65
+ if (type === 'image_carousel') {
66
+ updateImageStatus(!!originalContentUrl);
67
+ updateImageSrc(originalContentUrl);
68
+ updateActionType(selectedActionType);
69
+ updateActionLabel(actionLabel);
70
+ updateActionContent(actionContent);
71
+ }
72
+ }, [content]);
73
+
74
+ useEffect(() => {
75
+ if (imageSrc) {
76
+ updateCarouselMessageState({
77
+ activeIndex,
78
+ originalContentUrl: imageSrc,
79
+ selectedActionType,
80
+ actionContent,
81
+ actionLabel,
82
+ actionContentErrorMessage,
83
+ actionLabelErrorMessage,
84
+ index,
85
+ type: 'image_carousel',
86
+ messageType: 'originalContentUrl',
87
+ });
88
+ }
89
+ }, [imageSrc, isImageError]);
90
+
91
+ useEffect(() => {
92
+ if (Line.uploadedAssetDataImageCarousel && Object.keys(Line.uploadedAssetDataImageCarousel).length) {
93
+ const imgSrc = get(Line, 'uploadedAssetDataImageCarousel.metaInfo.secure_file_path', '');
94
+ if (imgSrc) {
95
+ updateUploadedAssetList({
96
+ ...uploadedAssetList,
97
+ [index]: {
98
+ ...uploadedAssetList[index],
99
+ [activeIndex]: {
100
+ imgSrc,
101
+ }
102
+ },
103
+ });
104
+ actions.clearAsset('ImageCarousel');
105
+ }
106
+ }
107
+ }, [Line.uploadedAssetDataImageCarousel]);
108
+
109
+ useEffect(() => {
110
+ const imgSrc = get(uploadedAssetList[index], `${activeIndex}.imgSrc`, '');
111
+
112
+ if (imgSrc) {
113
+ updateImageSrc(imgSrc);
114
+ updateImageStatus(true);
115
+
116
+ updateCarouselMessageState({
117
+ activeIndex,
118
+ isError: !imgSrc,
119
+ originalContentUrl: imgSrc,
120
+ selectedActionType,
121
+ actionContent,
122
+ actionLabel,
123
+ actionContentErrorMessage,
124
+ actionLabelErrorMessage,
125
+ index,
126
+ type: 'image_carousel',
127
+ messageType: 'originalContentUrl',
128
+ });
129
+ }
130
+ }, [uploadedAssetList]);
131
+
132
+ const submitAction = (data, incorrectFile) => {
133
+ const {
134
+ file: {
135
+ size,
136
+ },
137
+ fileParams: {
138
+ height,
139
+ width,
140
+ },
141
+ type,
142
+ } = data;
143
+ if (incorrectFile || size > LINE_IMG_SIZE || height > LINE_IMG_HEIGHT || width > LINE_IMG_WIDTH || height / width !== 1) {
144
+ updateImageErrorMessage(formatMessage(messages.lineImageIncorrectSize));
145
+ } else {
146
+ updateImageErrorMessage('');
147
+ actions.uploadAsset(
148
+ data.file,
149
+ data.type,
150
+ data.fileParams,
151
+ 'ImageCarousel',
152
+ );
153
+ }
154
+ }
155
+
156
+
157
+
158
+ const uploadImages = (e, { files }) => {
159
+ if (e) {
160
+ e.preventDefault();
161
+ }
162
+ const _URL = window.URL || window.webkitURL;
163
+ let incorrectFile = false;
164
+ const file = files[0];
165
+ if (!ALLOWED_EXTENSIONS_REGEX.test(file.name)) {
166
+ incorrectFile = true;
167
+ }
168
+ const img = new Image();
169
+ img.src = _URL.createObjectURL(file);
170
+ img.onload = () => {
171
+ const fileParams = {
172
+ width: img.width,
173
+ height: img.height,
174
+ error: file && (file.size / (1e+6) > 3),
175
+ };
176
+ submitAction({ file, type: 'image', fileParams }, incorrectFile);
177
+ };
178
+ if (e) {
179
+ const event = e;
180
+ event.target.value = null;
181
+ }
182
+ };
183
+
184
+ const capUploaderCustomRequest = (uploadData) => {
185
+ uploadImages(undefined, { files: [uploadData.file] });
186
+ }
187
+
188
+ const setDrawerVisibility = (drawervisibleFlag) => updateDrawerRequirement(drawervisibleFlag);
189
+
190
+ const onGalleryClick = (event) => {
191
+ event.stopPropagation();
192
+ setDrawerVisibility(true);
193
+ }
194
+
195
+ const ImageComponent = (props) => (
196
+ <div key={`${id}_imgComponent`}>
197
+ <CapHeader
198
+ title={formatMessage(messages.uploadImageLabel)}
199
+ description={formatMessage(messages.uploadImageDescription)}
200
+ size="regular"
201
+ />
202
+ <div
203
+ className={`image-container ${props.ifError ? 'error' : ''}`}
204
+ style={{
205
+ marginTop: isImage ? 20 : 8,
206
+ backgroundColor: CAP_G09,
207
+ }}
208
+ >
209
+ {isImage
210
+ ? (
211
+ <CapImage src={imageSrc} alt="line-image-src" style={props.style} height="400" />
212
+ )
213
+ : (
214
+ <div style={{ width: "100%", textAlign: "center" }}>
215
+ <span className="image-placeholder">{props.placeholder}</span>
216
+ </div>
217
+ )
218
+ }
219
+ </div>
220
+ </div>
221
+ );
222
+
223
+ const WithLabel = LabelHOC(ImageComponent);
224
+
225
+ const onReUpload = () => {
226
+ updateImageStatus(false);
227
+ updateUploadedAssetList({
228
+ ...uploadedAssetList,
229
+ [index]: {
230
+ ...uploadedAssetList[index],
231
+ [activeIndex]: null,
232
+ },
233
+ });
234
+ updateImageSrc('');
235
+ updateCarouselMessageState({
236
+ activeIndex,
237
+ isError: true,
238
+ originalContentUrl: '',
239
+ previewImageUrl: '',
240
+ selectedActionType,
241
+ actionContent,
242
+ actionLabel,
243
+ actionContentErrorMessage,
244
+ actionLabelErrorMessage,
245
+ index,
246
+ type: 'image_carousel',
247
+ messageType: 'originalContentUrl',
248
+ });
249
+ }
250
+
251
+ const getLineImageSection = (isImage) => {
252
+ if (!isImage) {
253
+ return (
254
+ <>
255
+ <CapUploader.CapDragger
256
+ customRequest={(data) => capUploaderCustomRequest(data)}
257
+ className="form-builder-dragger"
258
+ >
259
+ <CapHeading className="dragger-title" type="h7">
260
+ <FormattedMessage {...messages.dragAndDrop} />
261
+ </CapHeading>
262
+ <CapHeading className="dragger-or" type="label6">
263
+ <FormattedMessage {...messages.or} />
264
+ </CapHeading>
265
+ <CapButton className="dragger-button" type="secondary" style={{ marginRight: CAP_SPACE_08 }}>
266
+ <FormattedMessage {...messages.uploadComputer} />
267
+ </CapButton>
268
+ <CapButton
269
+ className="dragger-button"
270
+ type="secondary"
271
+ style={{ marginLeft: CAP_SPACE_08 }}
272
+ onClick={onGalleryClick}
273
+ >
274
+ <FormattedMessage {...messages.uploadGallery} />
275
+ </CapButton>
276
+ </CapUploader.CapDragger>
277
+ <CapHeading type="h6" style={{ marginTop: CAP_SPACE_12 }}>
278
+ <FormattedMessage {...messages.imageDimenstionDescription} />
279
+ </CapHeading>
280
+ </>);
281
+ }
282
+ return (
283
+ <CapButton
284
+ className="dragger-button"
285
+ type="flat"
286
+ style={{
287
+ top: 0,
288
+ position: 'absolute',
289
+ right: 0,
290
+ color: FONT_COLOR_05,
291
+ padding: 0,
292
+ height: 'min-content',
293
+ }}
294
+ onClick={onReUpload}
295
+ >
296
+ <FormattedMessage {...messages.imageReUpload} />
297
+ </CapButton>
298
+ );
299
+ }
300
+
301
+ const onGalleryImageSelect = (imageTemplate) => {
302
+ const image = get(imageTemplate, 'metaInfo.secure_file_path');
303
+ const imageHeight = get(imageTemplate, 'metaInfo.height');
304
+ const imageWidth = get(imageTemplate, 'metaInfo.width');
305
+ const imageSize = get(imageTemplate, 'metaInfo.file_size');
306
+ updateDrawerRequirement(false);
307
+ if (
308
+ !ALLOWED_EXTENSIONS_REGEX.test(image)
309
+ || imageHeight / imageWidth !== 1
310
+ || imageHeight > LINE_IMG_HEIGHT
311
+ || imageWidth > LINE_IMG_WIDTH
312
+ || imageSize > LINE_IMG_SIZE
313
+ ) {
314
+ updateImageErrorMessage(formatMessage(messages.lineImageIncorrectSize));
315
+ } else {
316
+ updateImageErrorMessage('');
317
+ updateImageStatus(true);
318
+ updateImageSrc(image);
319
+ updateCarouselMessageState({
320
+ activeIndex,
321
+ isError: !image || isImageError,
322
+ originalContentUrl: image,
323
+ selectedActionType,
324
+ actionContent,
325
+ actionLabel,
326
+ actionContentErrorMessage,
327
+ actionLabelErrorMessage,
328
+ index,
329
+ type: 'image_carousel',
330
+ messageType: 'originalContentUrl',
331
+ });
332
+ }
333
+ }
334
+
335
+ const getGalleryDrawerContent = () => {
336
+ const location = {
337
+ pathname: `/assets`,
338
+ search: '',
339
+ query: !isFullMode ? { type: 'embedded', module: 'library' } : {},
340
+ };
341
+ return (
342
+ <>
343
+ <CapHeading type="h3">
344
+ {formatMessage(messages.imageGallery)}
345
+ </CapHeading>
346
+ <Gallery
347
+ location={location}
348
+ isFullMode={isFullMode}
349
+ isLineAsset
350
+ onGalleryImageSelect={onGalleryImageSelect}
351
+ />
352
+ </>
353
+ );
354
+ };
355
+
356
+ const getActionTypes = () => {
357
+ return [TEXT_ACTION_TYPE, URL_ACTION_TYPE].map(type => ({
358
+ value: type,
359
+ label: formatMessage(
360
+ messages[
361
+ type !== URL_ACTION_TYPE ? 'textActionTypeTitle' : 'urlActionTypeTitle'
362
+ ],
363
+ ),
364
+ key: type,
365
+ }));
366
+ }
367
+
368
+ const updateActionLabelError = (value) => {
369
+ if (value.length > MAX_ACTION_LABEL_LENGTH) {
370
+ updateActionLabelErrorMessage(formatMessage(messages.emptyActionContentErrorMessage));
371
+ return formatMessage(messages.emptyActionContentErrorMessage);
372
+ } else {
373
+ updateActionLabelErrorMessage();
374
+ }
375
+ }
376
+
377
+ const onActionLabelChange = ({ target: { value } }) => {
378
+ updateActionLabel(value);
379
+ const actionLabelErrorMessage = updateActionLabelError(value);
380
+ updateCarouselMessageState({
381
+ activeIndex,
382
+ originalContentUrl: imageSrc,
383
+ selectedActionType,
384
+ actionContent,
385
+ actionLabel: value,
386
+ actionContentErrorMessage,
387
+ actionLabelErrorMessage,
388
+ index,
389
+ type: 'image_carousel',
390
+ messageType: 'originalContentUrl',
391
+ });
392
+ }
393
+
394
+ const onActionChange = (type) => {
395
+ updateActionType(type);
396
+ updateActionContent('');
397
+ updateCarouselMessageState({
398
+ activeIndex,
399
+ originalContentUrl: imageSrc,
400
+ selectedActionType: type,
401
+ actionContent: '',
402
+ actionLabel,
403
+ actionContentErrorMessage,
404
+ actionLabelErrorMessage,
405
+ index,
406
+ type: 'image_carousel',
407
+ messageType: 'originalContentUrl',
408
+ });
409
+ }
410
+
411
+ const updateActionContentError = (value, passedActionType) => {
412
+ const actionType = passedActionType || selectedActionType;
413
+ if (!value) {
414
+ updateActionContentErrorMessage(formatMessage(messages.emptyActionContentErrorMessage));
415
+ return formatMessage(messages.emptyActionContentErrorMessage);
416
+ } else if (actionType === URL_ACTION_TYPE && !isUrl(value)) {
417
+ updateActionContentErrorMessage(formatMessage(messages.inValidUrliErrorMessage));
418
+ return formatMessage(messages.inValidUrliErrorMessage);
419
+ } else {
420
+ updateActionContentErrorMessage();
421
+ }
422
+ }
423
+
424
+ const onActionContentChange = ({ target: { value } }) => {
425
+ updateActionContent(value);
426
+ const actionContentErrorMessage = updateActionContentError(value);
427
+ updateCarouselMessageState({
428
+ activeIndex,
429
+ originalContentUrl: imageSrc,
430
+ selectedActionType,
431
+ actionContent: value,
432
+ actionLabel,
433
+ actionContentErrorMessage,
434
+ actionLabelErrorMessage,
435
+ index,
436
+ type: 'image_carousel',
437
+ messageType: 'originalContentUrl',
438
+ });
439
+ }
440
+
441
+ const getActionSection = () => {
442
+ return (
443
+ <>
444
+ <CapInput
445
+ onChange={onActionLabelChange}
446
+ placeholder={formatMessage(messages.actionLabelPlaceholder)}
447
+ value={actionLabel}
448
+ errorMessage={actionLabelErrorMessage}
449
+ label={formatMessage(messages.actionLabelTitle)}
450
+ addonAfter={<span>{actionLabel.length} / ({MAX_ACTION_LABEL_LENGTH})</span>}
451
+ className="action-type-section"
452
+ />
453
+ <CapSelect
454
+ onChange={onActionChange}
455
+ options={getActionTypes()}
456
+ placeholder={formatMessage(messages.actionTypePlaceholder)}
457
+ style={{ width: '100%' }}
458
+ value={selectedActionType}
459
+ label={formatMessage(messages.actionTypeTitle)}
460
+ />
461
+ {
462
+ selectedActionType
463
+ ? (
464
+ <CapInput
465
+ onChange={onActionContentChange}
466
+ placeholder={formatMessage(
467
+ messages[
468
+ selectedActionType !== URL_ACTION_TYPE ? 'enterTextActionTypeTitle' : 'enterUrlActionTypeTitle'
469
+ ],
470
+ )}
471
+ value={actionContent}
472
+ errorMessage={actionContentErrorMessage}
473
+ style={{ marginTop: 12 }}
474
+ />
475
+ )
476
+ : null
477
+ }
478
+ </>
479
+ )
480
+ }
481
+
482
+ return (
483
+ <div className="carousel-content">
484
+ <CapRow>
485
+ <CapColumn span="4">
486
+ <div
487
+ style={{
488
+ background: CAP_G08,
489
+ color: FONT_COLOR_01,
490
+ borderRadius: 8,
491
+ position: 'relative',
492
+ height: 'auto',
493
+ overflow: 'initial',
494
+ maxHeight: 'initial',
495
+ minHeight: 120,
496
+ minWidth: 124,
497
+ display: 'flex',
498
+ justifyContent: 'center',
499
+ alignItems: 'center',
500
+ padding: '0 6px',
501
+ }}
502
+ >
503
+ <CapImage
504
+ src={imageSrc || lineImgPlaceholder}
505
+ alt="line-image-src"
506
+ height="40"
507
+ rest={{
508
+ style: {
509
+ maxWidth: '100%',
510
+ marginBottom: 5,
511
+ },
512
+ }}
513
+ />
514
+ <span
515
+ style={{
516
+ position: 'absolute',
517
+ bottom: 10,
518
+ background: 'rgba(94, 108, 132, 0.33)',
519
+ borderRadius: '42%',
520
+ padding: '0 12px',
521
+ color: CAP_WHITE,
522
+ }}
523
+ >
524
+ {actionLabel}
525
+ </span>
526
+ </div>
527
+ </CapColumn>
528
+ <CapColumn span="16" offset="4">
529
+ <WithLabel key={`${id}-with-label`} errorMessage={isImageError} ifError={!!isImageError} />
530
+ <form encType="multipart/form-data" id={`${id}_form`}>
531
+ <input
532
+ key={`${id}_imgFile`}
533
+ style={{ display: 'none' }}
534
+ id="fileName"
535
+ type="file"
536
+ onChange={(e) => uploadImages(e, { files: e.target.files })}
537
+ accept={supportedExtensions ? supportedExtensions : "image/*"}
538
+ />
539
+ {getLineImageSection(isImage)}
540
+ {getActionSection()}
541
+ <CapDrawer
542
+ content={getGalleryDrawerContent()}
543
+ visible={isDrawerRequired}
544
+ width={430}
545
+ onClose={() => updateDrawerRequirement(false)}
546
+ />
547
+ </form>
548
+ </CapColumn>
549
+ </CapRow>
550
+ </div>
551
+ )
552
+ }
553
+
554
+ export default injectIntl(withStyles(LineImageCarouselContent, style));
@@ -0,0 +1,10 @@
1
+ export const LINE_IMG_HEIGHT = 1024;
2
+ export const LINE_IMG_WIDTH = 1024;
3
+ export const LINE_IMG_SIZE = 1000000;
4
+ export const ALLOWED_EXTENSIONS_REGEX = (/\.(jpeg|png)$/i);
5
+ export const MAX_CAROUSEL_ALLOWED = 10;
6
+ export const TEXT_ACTION_TYPE = 'text';
7
+ export const MESSAGE_ACTION_TYPE = 'message';
8
+ export const URL_ACTION_TYPE = 'uri';
9
+ export const MAX_ACTION_LABEL_LENGTH = 12;
10
+ export const MAX_ALLOWED_TITLE_LENGTH = 20;