@capillarytech/creatives-library 7.5.4 → 7.5.6

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 (48) hide show
  1. package/assets/facebookEmptyPlaceholder.png +0 -0
  2. package/config/app.js +2 -0
  3. package/index.js +6 -0
  4. package/package.json +1 -1
  5. package/reducers.js +2 -1
  6. package/routes.js +5 -0
  7. package/services/api.js +34 -1
  8. package/utils/common.js +13 -1
  9. package/v2Components/CapImageUpload/index.js +260 -0
  10. package/v2Components/CapImageUpload/index.scss +32 -0
  11. package/v2Components/CapImageUpload/messages.js +49 -0
  12. package/v2Components/CapRadioCardCustom/index.js +66 -0
  13. package/v2Components/CapVideoUpload/index.js +299 -0
  14. package/v2Components/CapVideoUpload/index.scss +29 -0
  15. package/v2Components/CapVideoUpload/messages.js +54 -0
  16. package/v2Components/TemplatePreview/index.js +19 -2
  17. package/v2Containers/App/constants.js +21 -0
  18. package/v2Containers/Cap/messages.js +30 -0
  19. package/v2Containers/CapFacebookPreview/actions.js +31 -0
  20. package/v2Containers/CapFacebookPreview/constants.js +21 -0
  21. package/v2Containers/CapFacebookPreview/index.js +396 -0
  22. package/v2Containers/CapFacebookPreview/messages.js +138 -0
  23. package/v2Containers/CapFacebookPreview/reducer.js +37 -0
  24. package/v2Containers/CapFacebookPreview/sagas.js +99 -0
  25. package/v2Containers/CapFacebookPreview/selectors.js +25 -0
  26. package/v2Containers/CreativesContainer/SlideBoxContent.js +55 -1
  27. package/v2Containers/CreativesContainer/index.js +19 -9
  28. package/v2Containers/Facebook/Advertisement/constant.js +12 -0
  29. package/v2Containers/Facebook/Advertisement/index.js +955 -0
  30. package/v2Containers/Facebook/Advertisement/index.scss +49 -0
  31. package/v2Containers/Facebook/Advertisement/messages.js +155 -0
  32. package/v2Containers/Facebook/Advertisement/video.js +0 -0
  33. package/v2Containers/Facebook/actions.js +62 -0
  34. package/v2Containers/Facebook/constants.js +25 -1
  35. package/v2Containers/Facebook/index.js +133 -107
  36. package/v2Containers/Facebook/reducer.js +95 -1
  37. package/v2Containers/Facebook/sagas.js +136 -0
  38. package/v2Containers/Facebook/selectors.js +10 -0
  39. package/v2Containers/Line/Container/Video/index.js +38 -41
  40. package/v2Containers/Templates/_templates.scss +26 -0
  41. package/v2Containers/Templates/actions.js +14 -1
  42. package/v2Containers/Templates/constants.js +8 -0
  43. package/v2Containers/Templates/index.js +117 -10
  44. package/v2Containers/Templates/messages.js +8 -4
  45. package/v2Containers/Templates/reducer.js +22 -0
  46. package/v2Containers/Templates/sagas.js +26 -1
  47. package/v2Containers/TemplatesV2/index.js +13 -13
  48. package/v2Containers/Viber/index.js +2 -1
@@ -0,0 +1,955 @@
1
+ import PropTypes from "prop-types";
2
+ import React, { useState, useEffect, useCallback} from "react";
3
+ import { injectIntl, FormattedMessage, intlShape } from 'react-intl';
4
+ import { isUrl } from '../../Line/Container/Wrapper/utils';
5
+ import get from 'lodash/get';
6
+ import {
7
+ CapInput,
8
+ CapRadioCard,
9
+ CapHeading,
10
+ CapIcon,
11
+ CapSpin,
12
+ CapRow,
13
+ CapColumn,
14
+ CapTooltipWithInfo,
15
+ CapLabel,
16
+ CapSelect,
17
+ CapRadioGroup,
18
+ CapButton,
19
+ CapNotification,
20
+ CapLink,
21
+ CapHeader,
22
+ CapTab,
23
+ CapTooltip,
24
+ CapDivider,
25
+ } from "@capillarytech/cap-ui-library";
26
+ import {
27
+ CAP_SPACE_32,
28
+ CAP_SPACE_24,
29
+ CAP_WHITE,
30
+ CAP_SPACE_16,
31
+ CAP_G08,
32
+ FONT_COLOR_02,
33
+ FONT_COLOR_01,
34
+ } from '@capillarytech/cap-ui-library/styled/variables';
35
+ import styled from 'styled-components';
36
+ import CapImageUpload from '../../../v2Components/CapImageUpload';
37
+ import CapVideoUpload from '../../../v2Components/CapVideoUpload';
38
+ import messages from "./messages";
39
+ import CapRadioCardCustom from '../../../v2Components/CapRadioCardCustom';
40
+ import { FB_AD_CALL_TO_ACTION } from '../../App/constants';
41
+ import CapFacebookPreview from '../../CapFacebookPreview';
42
+ import './index.scss';
43
+ import {
44
+ ALLOWED_EXTENSIONS_REGEX,
45
+ FB_AD_IMG_HEIGHT,
46
+ FB_AD_IMG_WIDTH,
47
+ FB_AD_IMG_SIZE,
48
+ ALLOWED_EXTENSIONS_VIDEO_REGEX,
49
+ FB_AD_VIDEO_SIZE,
50
+ MAX_CAROUSEL_ALLOWED,
51
+ IMAGE,
52
+ VIDEO,
53
+ CAROUSEL,
54
+ IMAGE_VIDEO,
55
+ } from './constant';
56
+
57
+ export const Advertisement = (props) => {
58
+ const CarouselContainer = styled.div`
59
+ width: ${(styledProps) => styledProps.width || '22px'};
60
+ height: 23px;
61
+ margin: 0 1px 0px 1px;
62
+ border: ${CAP_G08};
63
+ background-color: ${CAP_G08};
64
+ display:inline;
65
+ `;
66
+ const FbAdFooter = styled.div`
67
+ background-color: ${CAP_WHITE};
68
+ position: fixed;
69
+ bottom: 0;
70
+ width: 100%;
71
+ margin-left: -32px;
72
+ padding: ${CAP_SPACE_32} ${CAP_SPACE_24};
73
+
74
+ .ant-btn {
75
+ margin-right: ${CAP_SPACE_16};
76
+ }
77
+ `;
78
+ const {
79
+ intl,
80
+ isFullMode,
81
+ actions,
82
+ fbADData = {},
83
+ onCreateComplete,
84
+ templateData,
85
+ params,
86
+ getFormSubscriptionData,
87
+ facebookTemplateData,
88
+ } = props;
89
+ const {
90
+ formatMessage,
91
+ } = intl || {};
92
+ const defaultActiveIndex = 0;
93
+ const defaultCarouselContent = {
94
+ subType: IMAGE,
95
+ imageData: {},
96
+ videoData: {},
97
+ webSiteLink: '',
98
+ linkHeadLine: '',
99
+ linkDesc: '',
100
+ errorMsg: {websiteLinkErrorMsg: false},
101
+ };
102
+ const { TextArea } = CapInput;
103
+ const [carouselData, updateCarouselData] = useState([defaultCarouselContent]);
104
+ const [selectedAd, setSelectPane] = useState('');
105
+ const [primaryText, setPrimaryText] = useState('');
106
+ const [pageId, setPageId] = useState(false);
107
+ const [displayLink, setDisplayLink] = useState('');
108
+ const [callToAction, setCallToAction] = useState("NO_CALL_TO_ACTION");
109
+ const [callToActionError, setCallToActionError] = useState(false);
110
+
111
+ const [messageTitle, updateMessageTitle] = useState('');
112
+ const [step, updateStep] = useState('modeSelection');
113
+ const [activeIndex, updateActiveIndex] = useState(`${defaultActiveIndex}`);
114
+ const [isEditLoading, updateEditLoading] = useState(false);
115
+ const [isEditFlow, checkEditFlow] = useState(false);
116
+ const [editNameState, setEditNameState] = useState(false);
117
+ const isCarouselSelectedAd = selectedAd === CAROUSEL;
118
+ const isImgVideoSelectedAd = selectedAd === IMAGE_VIDEO;
119
+
120
+ const activeCarouselData = carouselData[activeIndex];
121
+
122
+ const uploadFbAdAsset = useCallback(( file,
123
+ type,
124
+ fileParams,
125
+ indexFile) => {
126
+ actions.uploadFbAdAsset(file,
127
+ type,
128
+ fileParams,
129
+ indexFile);
130
+ }, []);
131
+
132
+ const paramObj = params || {};
133
+
134
+ useEffect(() => {
135
+ const { id } = paramObj;
136
+ if (id && !get(templateData, `versions.base.content`)) {
137
+ updateEditLoading(true);
138
+ actions.getTemplateDetails(id, updateEditLoading);
139
+ checkEditFlow(true);
140
+ updateStep('createFacebookAd');
141
+ }
142
+ }, [paramObj.id]);
143
+
144
+ useEffect(() => {
145
+ if ((params && params.id) || (templateData || {}).edit) {
146
+ const { FacebookAd = [], pageId: editPageId} = get(templateData, `versions.base.content`) || get(fbADData, `templateDetails.versions.base.content`) || {};
147
+ const editMessageTitle = (templateData || {}).name || get(fbADData, 'templateDetails.name');
148
+ const editFBContent = Object.values(FacebookAd);
149
+ if (editPageId) {
150
+ setPageId(editPageId);
151
+ }
152
+ if (editFBContent.length > 0 ) {
153
+ updateMessageTitle(editMessageTitle);
154
+ const {
155
+ type,
156
+ primaryText: pt,
157
+ callToAction: cta,
158
+ displayLink: dl,
159
+ } = (editFBContent || [])[0];
160
+ setSelectPane(type);
161
+ setPrimaryText(pt);
162
+ setCallToAction(cta);
163
+ if (type !== CAROUSEL) {
164
+ setDisplayLink(dl);
165
+ }
166
+ const newCarouselData = [...carouselData];
167
+ editFBContent.forEach((obj, index) => {
168
+ const data = {
169
+ subType: obj.subType,
170
+ webSiteLink: obj.webSiteLink,
171
+ linkHeadLine: obj.linkHeadLine,
172
+ linkDesc: obj.linkDesc,
173
+ };
174
+ if (obj.subType === IMAGE) {
175
+ data.imageData = {
176
+ imageSrc: obj.imgSrc,
177
+ };
178
+ }
179
+ if (obj.subType === VIDEO) {
180
+ const {
181
+ previewImageUrl: previewUrl,
182
+ originalContentUrl: videoSrc,
183
+ videoName,
184
+ videoHeight,
185
+ videoWidth,
186
+ } = obj.video;
187
+ data.videoData = {
188
+ videoSrc,
189
+ videoName,
190
+ videoHeight,
191
+ videoWidth,
192
+ previewUrl,
193
+ };
194
+ }
195
+ newCarouselData[index] = {...defaultCarouselContent, ...data};
196
+ });
197
+ updateCarouselData(newCarouselData);
198
+ }
199
+ }
200
+ }, [fbADData[`templateDetails`] || templateData]);
201
+
202
+ const CustomToolTip = useCallback((msg) => <CapTooltipWithInfo
203
+ infoIconProps={{svgProps: {width: 12, height: 12}, style: {marginLeft: 5}}}
204
+ title={msg}
205
+ />, []);
206
+
207
+ const advertisementTypePanes = [
208
+ {
209
+ title: <FormattedMessage {...messages.imageVideoTitle} />,
210
+ content: <FormattedMessage {...messages.imageVideoDesc} />,
211
+ value: IMAGE_VIDEO,
212
+ customComponent: <CapRadioCardCustom
213
+ showSelected={isImgVideoSelectedAd}
214
+ component={<CapIcon
215
+ type="media" svgProps={{ color: '#b3bac5',
216
+ width: '20px',
217
+ height: '20px'}}>
218
+ </CapIcon>}/>,
219
+ },
220
+ {
221
+ title: <FormattedMessage {...messages.carouselTitle} />,
222
+ content: <FormattedMessage {...messages.carouselDesc} />,
223
+ value: CAROUSEL,
224
+ customComponent: <CapRadioCardCustom
225
+ wrapperStyle={{padding: '9px 0px 8px'}}
226
+ showSelected={isCarouselSelectedAd}
227
+ component={<>
228
+ <CarouselContainer style={{float: 'left'}}/>
229
+ <CarouselContainer style={{float: 'left'}}/>
230
+ <CarouselContainer style={{float: 'left', marginRight: '0px'}} width="10.5px"/>
231
+ </>}
232
+ />,
233
+ },
234
+ ];
235
+
236
+ const radioOptions = [{
237
+ label: formatMessage(messages.image), value: IMAGE,
238
+ }, {
239
+ label: formatMessage(messages.video_slideshow), value: VIDEO,
240
+ }];
241
+
242
+ const OptionalComponent =
243
+ <CapLabel.CapLabelInline type="label14">{formatMessage(messages.optional)}</CapLabel.CapLabelInline>;
244
+
245
+ const callToActionOptions = Object.entries(FB_AD_CALL_TO_ACTION).map(([key, val]) => ({label: val, value: key}));
246
+
247
+ const onChangeAdvType = useCallback( ({ target: { value } }) => {
248
+ setSelectPane(value);
249
+ }, [selectedAd]);
250
+
251
+ const updateOnImageReUpload = useCallback(() => {
252
+ const newCarouselData = [...carouselData];
253
+ newCarouselData[activeIndex].imageData.imageSrc = '';
254
+ updateCarouselData(newCarouselData);
255
+ }, [carouselData, activeIndex]);
256
+
257
+ const setUpdateImageSrc = useCallback((val) => {
258
+ const newCarouselData = [...carouselData];
259
+ newCarouselData[activeIndex].imageData.imageSrc = val;
260
+ updateCarouselData(newCarouselData);
261
+ actions.clearFbAdAsset(activeIndex);
262
+ }, [carouselData, activeIndex]);
263
+
264
+ const onChangePrimaryText = useCallback((e) => {
265
+ e.preventDefault();
266
+ setPrimaryText(e.target.value);
267
+ }, [primaryText]);
268
+
269
+ const onChangeDisplayLink = useCallback(({ target: { value } }) => {
270
+ setDisplayLink(value);
271
+ }, [displayLink]);
272
+
273
+ const onChangeCallToAction = useCallback((value) => {
274
+ setCallToAction(value);
275
+ }, [callToAction]);
276
+
277
+ const onChangeMediaOption = useCallback(({ target: { value } }) => {
278
+ const newCarouselData = [...carouselData];
279
+ newCarouselData[activeIndex].subType = value;
280
+ newCarouselData[activeIndex].imageData = {};
281
+ updateCarouselData(newCarouselData);
282
+ actions.clearFbAdAsset(`Video_${activeIndex}`);
283
+ }, [carouselData, activeIndex]);
284
+
285
+
286
+ const formatSubmitPayload = useCallback(() => {
287
+ const messageData = [];
288
+ let data = { };
289
+ // for image/video selected Ad
290
+
291
+ carouselData.forEach((obj) => {
292
+ data = {
293
+ type: selectedAd !== CAROUSEL ? obj.subType : selectedAd,
294
+ subType: obj.subType,
295
+ webSiteLink: obj.webSiteLink,
296
+ linkHeadLine: obj.linkHeadLine,
297
+ linkDesc: obj.linkDesc,
298
+ primaryText,
299
+ callToAction,
300
+ };
301
+ if (!isCarouselSelectedAd) {
302
+ data = {
303
+ ...data,
304
+ primaryText,
305
+ displayLink,
306
+ callToAction,
307
+ };
308
+ }
309
+ if (obj.subType === IMAGE) {
310
+ data.imgSrc = obj.imageData.imageSrc;
311
+ } else {
312
+ const {
313
+ videoSrc,
314
+ videoName,
315
+ videoHeight,
316
+ videoWidth,
317
+ previewUrl,
318
+ } = obj.videoData;
319
+ data.video = {
320
+ previewImageUrl: previewUrl,
321
+ originalContentUrl: videoSrc,
322
+ videoName,
323
+ baseUrl: previewUrl.replace('/1040', ''),
324
+ videoHeight,
325
+ videoWidth,
326
+ };
327
+ }
328
+ messageData.push(data);
329
+ });
330
+
331
+ return {
332
+ versions: {
333
+ base: {
334
+ content: {
335
+ FacebookAd: {...messageData},
336
+ pageId,
337
+ },
338
+ },
339
+ },
340
+ type: "FACEBOOK",
341
+ name: messageTitle,
342
+ };
343
+ }, [carouselData,
344
+ pageId,
345
+ messageTitle,
346
+ primaryText,
347
+ callToAction,
348
+ displayLink]);
349
+
350
+ const onCreateFacebookAd = useCallback( () => {
351
+ actions.createTemplate(
352
+ formatSubmitPayload(),
353
+ (resp, errorMessage) => {
354
+ createCallback(errorMessage);
355
+ }
356
+ );
357
+ }, [carouselData,
358
+ pageId,
359
+ messageTitle,
360
+ primaryText,
361
+ callToAction,
362
+ displayLink]);
363
+
364
+ const createCallback = useCallback((errorMessage, isEdit) => {
365
+ if (!errorMessage) {
366
+ CapNotification.success({
367
+ message: isEdit ? formatMessage(messages.editNotification) : formatMessage(messages.createNotification),
368
+ });
369
+ if (isEdit) {
370
+ actions.clearEditResponse();
371
+ } else {
372
+ actions.clearCreateResponse();
373
+ }
374
+ onCreateComplete();
375
+ } else {
376
+ CapNotification.error({
377
+ message: errorMessage,
378
+ });
379
+ }
380
+ }, []);
381
+
382
+ const onEditFacebookAd = useCallback(() => {
383
+ actions.editTemplate(
384
+ {
385
+ ...formatSubmitPayload(),
386
+ _id: params.id,
387
+ },
388
+ (resp, errorMessage) => {
389
+ createCallback(errorMessage, true);
390
+ onCreateComplete();
391
+ });
392
+ }, [carouselData,
393
+ pageId,
394
+ messageTitle,
395
+ primaryText,
396
+ callToAction,
397
+ displayLink, params]);
398
+
399
+ const onDoneCallback = useCallback(() => {
400
+ if (isFullMode) {
401
+ if (isEditFlow) {
402
+ return onEditFacebookAd;
403
+ }
404
+ return onCreateFacebookAd;
405
+ }
406
+ return () => getFormSubscriptionData({
407
+ value: formatSubmitPayload(),
408
+ _id: params && params.id,
409
+ validity: true,
410
+ type: 'FACEBOOK',
411
+ });
412
+ }, [carouselData,
413
+ pageId,
414
+ messageTitle,
415
+ primaryText,
416
+ callToAction,
417
+ displayLink, params]);
418
+
419
+ const onTextTitleChange = useCallback((e) => {
420
+ const val = e.target.value;
421
+ updateMessageTitle(val);
422
+ }, [messageTitle]);
423
+
424
+ const isDisableDone = useCallback((isPreview) => {
425
+ let flag = false;
426
+ if (primaryText === "" ) {
427
+ flag = true;
428
+ }
429
+ if (selectedAd === CAROUSEL && carouselData.length === 1 && !isPreview) {
430
+ flag = true;
431
+ return flag;
432
+ }
433
+ carouselData.forEach((obj) => {
434
+ const {
435
+ webSiteLink,
436
+ imageData,
437
+ videoData,
438
+ subType,
439
+ errorMsg,
440
+ } = obj;
441
+ if (webSiteLink === "" || errorMsg.websiteLinkErrorMsg ) {
442
+ flag = true;
443
+ }
444
+ if (Object.keys(imageData).length === 0 && subType === IMAGE) {
445
+ flag = true;
446
+ } else if (Object.keys(videoData).length === 0 && subType === VIDEO) {
447
+ flag = true;
448
+ }
449
+ if (subType === VIDEO) {
450
+ if (callToAction === "NO_CALL_TO_ACTION" && !callToActionError) {
451
+ setCallToActionError(messages.callToActionMandatoryError);
452
+ flag = true;
453
+ } else if (callToAction !== "NO_CALL_TO_ACTION" && callToActionError) {
454
+ setCallToActionError(false);
455
+ }
456
+ }
457
+ });
458
+ if (callToAction === "NO_CALL_TO_ACTION" && callToActionError) {
459
+ flag = true;
460
+ }
461
+ return flag;
462
+ }, [
463
+ callToActionError,
464
+ carouselData,
465
+ callToAction,
466
+ primaryText,
467
+ selectedAd,
468
+ ]
469
+ );
470
+
471
+ const isDisableContinue = () => messageTitle.trim() === "" || selectedAd === "";
472
+
473
+ const onClickContinue = useCallback(() => { updateStep('createFacebookAd'); }, [step]);
474
+
475
+ const onVideoUploadUpdateAssestList = useCallback((index, data) => {
476
+ const newCarouselData = [...carouselData];
477
+ newCarouselData[index].videoData = data;
478
+ updateCarouselData(newCarouselData);
479
+ }, [carouselData]);
480
+
481
+ const shiftRightContent = useCallback(() => {
482
+ const newActiveIndex = Number(activeIndex) + 1;
483
+ updateActiveIndex(`${newActiveIndex}`);
484
+ }, [activeIndex]);
485
+
486
+ const shiftLeftContent = useCallback(() => {
487
+ const newActiveIndex = Number(activeIndex) - 1;
488
+ updateActiveIndex(`${newActiveIndex}`);
489
+ }, [activeIndex]);
490
+
491
+ const onTabChange = useCallback((index) => {
492
+ updateActiveIndex(index);
493
+ }, [activeIndex]);
494
+
495
+ const spinLoader = fbADData.createTemplateInProgress || isEditLoading || false;
496
+ const showMedia = activeCarouselData.subType === IMAGE;
497
+ const adSpinLoader = get(fbADData, 'orgOuData.status', '') === 'REQUEST';
498
+
499
+ const MediaComponent = ({index = 0}) => <>
500
+ <CapRadioGroup
501
+ style={{paddingBottom: '18px'}}
502
+ options={radioOptions}
503
+ onChange={onChangeMediaOption}
504
+ value={activeCarouselData.subType}
505
+ index={index}
506
+ key={`${index}-fb-radio-card`}
507
+ />
508
+
509
+ {showMedia ? <CapImageUpload
510
+ style={{paddingBottom: '21px', width: '460px'}}
511
+ allowedExtensionsRegex={ALLOWED_EXTENSIONS_REGEX}
512
+ imgWidth={FB_AD_IMG_WIDTH}
513
+ imgHeight={FB_AD_IMG_HEIGHT}
514
+ imgSize={FB_AD_IMG_SIZE}
515
+ uploadAsset={uploadFbAdAsset}
516
+ isFullMode={isFullMode}
517
+ imageSrc={activeCarouselData.imageData.imageSrc || ''}
518
+ updateImageSrc={setUpdateImageSrc}
519
+ updateOnReUpload={updateOnImageReUpload}
520
+ index={index}
521
+ className={`cap-image-upload-${selectedAd}`}
522
+ key={`${index}-fb-image-upload`}
523
+ imageData={fbADData}
524
+ /> :
525
+ <CapVideoUpload
526
+ style={{paddingBottom: '21px'}}
527
+ index={index}
528
+ allowedExtensionsRegex={ALLOWED_EXTENSIONS_VIDEO_REGEX}
529
+ videoSize={FB_AD_VIDEO_SIZE}
530
+ isFullMode={isFullMode}
531
+ uploadAsset={uploadFbAdAsset}
532
+ uploadedAssetList={carouselData[index].videoData}
533
+ onVideoUploadUpdateAssestList={onVideoUploadUpdateAssestList}
534
+ key={`${index}-fb-video-upload`}
535
+ videoData={fbADData}
536
+ />
537
+ }
538
+ </>;
539
+
540
+ const PrimaryTextComponent = (
541
+ <TextArea
542
+ id={'fbAd_textarea'}
543
+ label={<>
544
+ {formatMessage(messages.primaryText)}
545
+ {CustomToolTip(formatMessage(messages.primaryTextToolTip))}
546
+ </>}
547
+ className="cap-input-wrapper"
548
+ autosize={false}
549
+ onChange={onChangePrimaryText}
550
+ defaultValue={primaryText || ''}
551
+ value={primaryText || ''}
552
+ rows={3}
553
+ cols={2}
554
+ placeholder={formatMessage(messages.primaryTextPlaceholder)}
555
+ />);
556
+
557
+ const linkHeadlineComponent = (index = 0) => {
558
+ const onChangeLinkHeadLine = (e) => {
559
+ e.preventDefault();
560
+ const newCarouselData = [...carouselData];
561
+ newCarouselData[activeIndex].linkHeadLine = e.target.value;
562
+ updateCarouselData(newCarouselData);
563
+ };
564
+ return (<CapInput
565
+ className="cap-input-wrapper"
566
+ id="fbAd-link-headline"
567
+ type="input"
568
+ onChange={onChangeLinkHeadLine}
569
+ key={`${index}-line-headline`}
570
+ label={<>
571
+ {formatMessage(messages.linkHeadline)}{' '}
572
+ {OptionalComponent}
573
+ {CustomToolTip(formatMessage(messages.linkHeadlineToolTip))}
574
+ </>}
575
+ value={carouselData[index].linkHeadLine}
576
+ maxLength={40}
577
+ index={index}
578
+ placeholder={formatMessage(messages.linkHeadlinePlaceHolder)}
579
+ />);
580
+ };
581
+
582
+ const linkDescComponent = (index = 0) => {
583
+ const onChangeLinkDesc = (e) => {
584
+ e.preventDefault();
585
+ const newCarouselData = [...carouselData];
586
+ newCarouselData[activeIndex].linkDesc = e.target.value;
587
+ updateCarouselData(newCarouselData);
588
+ };
589
+ return (<CapInput
590
+ className="cap-input-wrapper"
591
+ id="fbAd-link-desc"
592
+ type="input"
593
+ onChange={onChangeLinkDesc}
594
+ key={`${index}-line-desc`}
595
+ label={<>
596
+ {formatMessage(messages.linkDesc)}{' '}
597
+ {OptionalComponent}
598
+ {CustomToolTip(formatMessage(messages.linkDescToolTip))}
599
+ </>}
600
+ value={(carouselData[index] || {}).linkDesc}
601
+ maxLength={40}
602
+ index={index}
603
+ placeholder={formatMessage(messages.linkDescPlaceHolder)}
604
+ />);
605
+ };
606
+
607
+ const WebsiteLinkComponent = (index = 0 ) => {
608
+ const onChangeWebSiteLink = (e) => {
609
+ e.preventDefault();
610
+ let errorMsg = false;
611
+ const value = e.target.value;
612
+ const newCarouselData = [...carouselData];
613
+ if (!isUrl(value)) {
614
+ errorMsg = formatMessage(messages.inValidUrliErrorMessage);
615
+ }
616
+ newCarouselData[activeIndex].webSiteLink = value;
617
+ newCarouselData[activeIndex].errorMsg = {
618
+ websiteLinkErrorMsg: errorMsg,
619
+ };
620
+ updateCarouselData(newCarouselData);
621
+ };
622
+
623
+ const {webSiteLink = "", errorMsg = {} } = carouselData[index] || {};
624
+ return (<CapInput
625
+ className="cap-input-wrapper"
626
+ id="fbAd-web-site-link"
627
+ type="input"
628
+ key={`${index}-webSite-link`}
629
+ onChange={onChangeWebSiteLink}
630
+ label={formatMessage(messages.webSiteLink)}
631
+ value={webSiteLink}
632
+ placeholder={formatMessage(messages.websiteLinkPlaceHolder)}
633
+ errorMessage={errorMsg.websiteLinkErrorMsg}
634
+ index={index}
635
+ />);
636
+ };
637
+
638
+ const DisplayLinkComponent = (false && <CapInput
639
+ className="cap-input-wrapper"
640
+ id="fbAd-display-link"
641
+ type="input"
642
+ style={{display: 'none'}}
643
+ onChange={onChangeDisplayLink}
644
+ label={<>
645
+ {formatMessage(messages.displayLink)}{' '}
646
+ {OptionalComponent}
647
+ </>
648
+ }
649
+ defaultValue={displayLink}
650
+ value={displayLink}
651
+ placeholder={formatMessage(messages.displayLinkPlaceHolder)}
652
+ />);
653
+
654
+ const CallToActionComponent = (<CapSelect
655
+ label={formatMessage(messages.callToAction)}
656
+ key={"select-account"}
657
+ onChange={onChangeCallToAction}
658
+ style={{width: '324px'}}
659
+ options={callToActionOptions}
660
+ value={callToAction}
661
+ errorMessage={callToActionError ? formatMessage(callToActionError) : ""}
662
+ ></CapSelect>);
663
+
664
+ const addContent = useCallback(() => {
665
+ const newCarouselData = [
666
+ ...carouselData,
667
+ {
668
+ ...defaultCarouselContent,
669
+ activeIndex: carouselData.length,
670
+ },
671
+ ];
672
+ updateCarouselData(newCarouselData);
673
+ }, [carouselData]);
674
+
675
+ const deleteContent = useCallback(() => {
676
+ const newCarouselData = [...carouselData];
677
+ newCarouselData.splice(activeIndex, 1);
678
+ updateCarouselData(newCarouselData);
679
+ const parsedActiveIndex = Number(activeIndex);
680
+ const newActiveIndex = parsedActiveIndex === 0 ? parsedActiveIndex : parsedActiveIndex - 1;
681
+ updateActiveIndex(`${newActiveIndex}`);
682
+ }, [carouselData, activeIndex]);
683
+
684
+ const operations = (
685
+ <>
686
+ <CapButton
687
+ onClick={addContent}
688
+ type="flat"
689
+ disabled={MAX_CAROUSEL_ALLOWED === carouselData.length}
690
+ isAddBtn
691
+ style={{ padding: 0, marginTop: 12 }}
692
+ >
693
+ <FormattedMessage {...messages.addCard} />
694
+ </CapButton>
695
+ <div
696
+ style={{
697
+ top: 54,
698
+ right: 0,
699
+ }}
700
+ className="extra-button-group"
701
+ >
702
+ <CapTooltip
703
+ title={<FormattedMessage {...messages.shiftLeftTooltipLabel} />}
704
+ >
705
+ <CapButton
706
+ onClick={shiftLeftContent}
707
+ disabled={defaultActiveIndex === Number(activeIndex)}
708
+ type="flat">
709
+ <CapIcon type="left" size="s" />
710
+ </CapButton>
711
+ </CapTooltip>
712
+ <CapTooltip
713
+ title={<FormattedMessage {...messages.shiftRightTooltipLabel} />}>
714
+ <CapButton
715
+ onClick={shiftRightContent}
716
+ disabled={carouselData.length === (Number(activeIndex) + 1)}
717
+ type="flat">
718
+ <CapIcon type="right" size="s" />
719
+ </CapButton>
720
+ </CapTooltip>
721
+ <CapTooltip
722
+ title={<FormattedMessage {...messages.deleteTooltipLabel} />}>
723
+ <CapButton
724
+ onClick={deleteContent}
725
+ disabled={carouselData.length === 1}
726
+ type="flat">
727
+ <CapIcon type="delete" size="s" />
728
+ </CapButton>
729
+ </CapTooltip>
730
+ </div>
731
+ </>
732
+ );
733
+
734
+ const getTabPanes = () => carouselData.map((data, index) => {
735
+ const isSelected = Number(activeIndex) === index;
736
+ return {
737
+ key: index,
738
+ tab: (
739
+ <span
740
+ style={{
741
+ display: 'inline-block',
742
+ borderRadius: '50%',
743
+ color: CAP_WHITE,
744
+ backgroundColor: !isSelected ? FONT_COLOR_02 : FONT_COLOR_01,
745
+ height: CAP_SPACE_24,
746
+ width: CAP_SPACE_24,
747
+ textAlign: 'center',
748
+ paddingTop: 4,
749
+ }}
750
+ >
751
+ {index + 1}
752
+ </span>
753
+ ),
754
+ content: <div key={`${index}-card-container`}>
755
+ <MediaComponent index={index}/>
756
+ {WebsiteLinkComponent(index)}
757
+ {linkHeadlineComponent(index)}
758
+ {linkDescComponent(index)}
759
+ </div>,
760
+ };
761
+ });
762
+
763
+ const onClickEditName = useCallback(() => {
764
+ setEditNameState(true);
765
+ }, [editNameState]);
766
+
767
+ const onEditFocusOut = useCallback((e) => {
768
+ const data = e.target.value;
769
+ if (data.trim() !== "") {
770
+ setEditNameState(false);
771
+ updateMessageTitle(e.target.value);
772
+ }
773
+ }, [messageTitle, editNameState]);
774
+
775
+ const onChangeFacebookPage = useCallback((value) => {
776
+ setPageId(value);
777
+ }, [pageId]);
778
+
779
+ const selectedFacebookAccount = get(facebookTemplateData, 'selectedFacebookAccount', {});
780
+ const {orgUnitFacebookPageSettingsMap = {}, accessToken = "", accountId = "" } = selectedFacebookAccount;
781
+
782
+ const getPageAccessOrgs = useCallback(() => {
783
+ const {status, data } = fbADData.orgOuData || {};
784
+ const pageAccessOrgsOptions = [];
785
+ const { proxyOrgList } = JSON.parse(window.localStorage.getItem('user'));
786
+ const orgId = window.localStorage.getItem('orgID');
787
+ const orgName = (
788
+ proxyOrgList.find(({ orgID }) => orgID === Number(orgId)) || {}
789
+ ).orgName;
790
+ if (status === 'SUCCESS') {
791
+ Object.keys(data).forEach((obj) => {
792
+ if ((orgUnitFacebookPageSettingsMap[data[obj]] || {}).pageAccessToken) {
793
+ pageAccessOrgsOptions.push({label: data[obj] === -1 ? orgName : obj, value: data[obj]});
794
+ }
795
+ });
796
+ if (!pageId) {
797
+ setPageId((pageAccessOrgsOptions[0] || {} ).value);
798
+ }
799
+ }
800
+ return pageAccessOrgsOptions;
801
+ }, [pageId, fbADData]);
802
+
803
+ const options = getPageAccessOrgs() || [];
804
+ const { data = {} } = fbADData.orgOuData || {};
805
+ const selectedPageName = Object.keys(data).find((key) => data[key] === pageId);
806
+ return ( (step === 'modeSelection') ?
807
+ ( <CapSpin spinning={adSpinLoader} className="add-facebook-ad-section">
808
+ <div style={{ position: 'fixed', top: '25px', zIndex: 1}}>
809
+ <CapHeader
810
+ inline
811
+ title={formatMessage(messages.newFacebookCreatives)}
812
+ className={"cap-header-facebook-ad"}
813
+ />
814
+ </div>
815
+ <CapInput
816
+ id={`fbAd_input`}
817
+ onChange={onTextTitleChange}
818
+ className="text-template-title"
819
+ defaultValue={messageTitle || ''}
820
+ value={messageTitle || ''}
821
+ style={{marginBottom: 27, width: '762px'}}
822
+ size="default"
823
+ label={formatMessage(messages.creativeName)}
824
+ />
825
+ {isFullMode && <CapSelect
826
+ label={formatMessage(messages.facebookPage)}
827
+ key={"select-facebook-page"}
828
+ onChange={onChangeFacebookPage}
829
+ options={options}
830
+ defaultValue={(options[0] || {} ).value}
831
+ value={pageId || (options[0] || {} ).value}
832
+ style={{marginBottom: 27, width: '372px'}}
833
+ ></CapSelect>}
834
+ <CapHeading
835
+ type="h4"
836
+ style={{marginBottom: 11}}
837
+ >
838
+ {formatMessage(messages.AdvertisementType)}
839
+ </CapHeading>
840
+ <CapRadioCard
841
+ panes={advertisementTypePanes}
842
+ onChange={onChangeAdvType}
843
+ selected={selectedAd}
844
+ className="facebook-ad-type-card"
845
+ />
846
+ <FbAdFooter>
847
+ <CapButton
848
+ onClick={onClickContinue}
849
+ disabled={isDisableContinue()}
850
+ className="create-msg"
851
+ >
852
+ <FormattedMessage {...messages.clickButtonLabel} />
853
+ </CapButton>
854
+ </FbAdFooter>
855
+ </CapSpin> ) : (
856
+ <CapSpin spinning={spinLoader}>
857
+ <CapRow className="add-facebook-ad-section" >
858
+ <div className="cap-header-facebook-ad">
859
+ <CapHeading
860
+ type="h2"
861
+ style={{display: 'inline'}}
862
+ >
863
+ {editNameState ? <CapInput
864
+ type="input"
865
+ style={{display: 'inline-block'}}
866
+ onBlur={onEditFocusOut}
867
+ defaultValue={messageTitle || ''}
868
+ /> : messageTitle
869
+ }
870
+ {!editNameState && <CapLink
871
+ style={{display: "inline-flex"}}
872
+ title={<FormattedMessage {...messages.creativesTemplatesEditName}/>}
873
+ onClick={onClickEditName}
874
+ />}
875
+ </CapHeading>
876
+ </div>
877
+ <CapColumn span={12}>
878
+ {isFullMode && <><CapHeading
879
+ type="h4"
880
+ style={{marginBottom: 4}}
881
+ >
882
+ {formatMessage(messages.facebookPage)}
883
+ </CapHeading>
884
+ <CapHeading
885
+ type="h6"
886
+ style={{marginBottom: 24}}
887
+ >
888
+ {selectedPageName}
889
+ </CapHeading></>}
890
+ {!isCarouselSelectedAd ? <>
891
+ <MediaComponent />
892
+ {PrimaryTextComponent}
893
+ {linkHeadlineComponent()}
894
+ {linkDescComponent()}
895
+ {WebsiteLinkComponent()}
896
+ {DisplayLinkComponent}
897
+ {CallToActionComponent}
898
+ </> : <>
899
+ {PrimaryTextComponent}
900
+ {CallToActionComponent}
901
+ <CapDivider style={{width: '460px', minWidth: '460px'}}/>
902
+ <CapTab
903
+ style={{width: '460px'}}
904
+ defaultActiveKey={`${defaultActiveIndex}`}
905
+ activeKey={activeIndex}
906
+ tabBarExtraContent={operations}
907
+ onChange={onTabChange}
908
+ panes={getTabPanes()}
909
+ />
910
+ </>
911
+ }
912
+ </CapColumn>
913
+ <CapColumn span={8}>
914
+ <CapFacebookPreview
915
+ disablePreviewButton={isDisableDone(true)}
916
+ selectedAd={selectedAd}
917
+ previewData={carouselData}
918
+ primaryText={primaryText}
919
+ callToAction={callToAction}
920
+ displayLink={displayLink}
921
+ orgUnitFacebookPageSettingsMap={orgUnitFacebookPageSettingsMap[pageId] || {}}
922
+ accessToken={accessToken}
923
+ accountId={accountId}
924
+ key={`facebookPreview-${pageId}`}
925
+ />
926
+ </CapColumn>
927
+ </CapRow>
928
+ <FbAdFooter>
929
+ <CapButton
930
+ onClick={onDoneCallback()}
931
+ disabled={isDisableDone()}
932
+ >
933
+ <FormattedMessage {...messages.doneButtonLabel} />
934
+ </CapButton>
935
+ </FbAdFooter>
936
+ </CapSpin>
937
+ )
938
+ );
939
+ };
940
+
941
+ Advertisement.propTypes = {
942
+ intl: intlShape,
943
+ isFullMode: PropTypes.bool,
944
+ onCreateComplete: PropTypes.func,
945
+ fbADData: PropTypes.object,
946
+ actions: PropTypes.any,
947
+ getFormSubscriptionData: PropTypes.func,
948
+ facebookTemplateData: PropTypes.object,
949
+ templateData: PropTypes.object,
950
+ params: PropTypes.object,
951
+
952
+ };
953
+
954
+ export default injectIntl(Advertisement);
955
+