@capillarytech/creatives-library 7.8.1 → 7.9.1

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 (37) hide show
  1. package/app.js +5 -1
  2. package/components/FormBuilder/index.js +2 -2
  3. package/containers/Email/index.js +8 -3
  4. package/containers/MobilePush/Create/index.js +2 -2
  5. package/containers/MobilePush/Edit/index.js +2 -2
  6. package/containers/WeChat/MapTemplates/index.js +15 -3
  7. package/package.json +1 -1
  8. package/services/api.js +20 -5
  9. package/translations/en.json +113 -2
  10. package/translations/zh.json +112 -1
  11. package/utils/gtmTrackers/gtmEvents/creativeDetails.js +6 -2
  12. package/utils/gtmTrackers/index.js +8 -4
  13. package/v2Components/CapImageUpload/index.js +14 -8
  14. package/v2Components/FormBuilder/index.js +10 -1
  15. package/v2Components/NavigationBar/index.js +63 -29
  16. package/v2Components/NavigationBar/messages.js +5 -0
  17. package/v2Containers/App/constants.js +23 -3
  18. package/v2Containers/Cap/actions.js +2 -2
  19. package/v2Containers/Cap/constants.js +3 -2
  20. package/v2Containers/Cap/index.js +31 -18
  21. package/v2Containers/Cap/messages.js +8 -0
  22. package/v2Containers/Cap/sagas.js +18 -6
  23. package/v2Containers/CapFacebookPreview/constants.js +4 -0
  24. package/v2Containers/CapFacebookPreview/index.js +92 -67
  25. package/v2Containers/CapFacebookPreview/reducer.js +19 -10
  26. package/v2Containers/CreativesContainer/SlideBoxContent.js +2 -0
  27. package/v2Containers/CreativesContainer/index.js +80 -2
  28. package/v2Containers/Facebook/Advertisement/index.js +2 -2
  29. package/v2Containers/Facebook/Advertisement/index.scss +1 -1
  30. package/v2Containers/Facebook/index.js +15 -4
  31. package/v2Containers/Line/Container/Drawer/index.js +1 -1
  32. package/v2Containers/MobilePush/Edit/index.js +2 -2
  33. package/v2Containers/MobilepushWrapper/index.js +1 -1
  34. package/v2Containers/Templates/_templates.scss +4 -2
  35. package/v2Containers/Templates/index.js +6 -2
  36. package/v2Containers/TemplatesV2/index.js +11 -3
  37. package/v2Containers/WeChat/MapTemplates/index.js +12 -2
@@ -30,6 +30,11 @@ import {
30
30
  CAROUSEL,
31
31
  NO_CALL_TO_ACTION,
32
32
  } from '../../v2Containers/Facebook/Advertisement/constant';
33
+ import {
34
+ FETCH_PREVIEW_REQUESTED,
35
+ FETCH_PREVIEW_SUCCESS,
36
+ PREVIEW_NOT_REQUESTED,
37
+ } from './constants';
33
38
  import './index.scss';
34
39
 
35
40
  export const CapFacebookPreview = (props) => {
@@ -55,7 +60,10 @@ export const CapFacebookPreview = (props) => {
55
60
  const [disableAfterPreviewGenerate, setDisableAfterPreviewGenerate] = useState(false);
56
61
  const [random, setRandom] = useState(0);
57
62
  const {pageAccessToken, pageId} = orgUnitFacebookPageSettingsMap;
58
- const {previewIframe = "", isFetchingPreview = false, previewIframeError = ""} = facebookPreviewData;
63
+ const {previewIframe = "", fetchPreviewStatus = PREVIEW_NOT_REQUESTED, previewIframeError = ""} = facebookPreviewData;
64
+ const [previewLoaded, setPreviewLoaded] = useState(false);
65
+ const [isRefreshing, setIsRefreshing] = useState(false);
66
+ let isSpinning = false;
59
67
  const facebookAdOptions = [
60
68
  {
61
69
  value: "DESKTOP_FEED_STANDARD",
@@ -284,9 +292,17 @@ export const CapFacebookPreview = (props) => {
284
292
  };
285
293
 
286
294
  const resetIframe = () => {
295
+ previewLoaded && setPreviewLoaded(false);
296
+ !isRefreshing && setIsRefreshing(true);
287
297
  const r = random + 1;
288
298
  setRandom(r);
289
299
  };
300
+ const unsetLoader = () => {
301
+ setTimeout(function() {
302
+ !previewLoaded && setPreviewLoaded(true);
303
+ isRefreshing && setIsRefreshing(false);
304
+ }.bind(this), 5000);
305
+ }
290
306
  const getIframe = (iframe) => {
291
307
  const divTag = document.createElement('div');
292
308
  divTag.innerHTML = iframe;
@@ -295,13 +311,16 @@ export const CapFacebookPreview = (props) => {
295
311
  <iframe
296
312
  src={src}
297
313
  key={random}
298
- style={{border: "none"}}
314
+ style={{ border: "none" }}
299
315
  width={"600px"}
300
316
  scrolling="no"
301
317
  height={"1000px"}
302
318
  className="cap-facebook-ad-iframe"
319
+ onLoad={
320
+ unsetLoader()
321
+ }
303
322
  />
304
- </>);
323
+ </>);
305
324
  };
306
325
 
307
326
  const showRefreshButton = () => {
@@ -340,74 +359,80 @@ export const CapFacebookPreview = (props) => {
340
359
  }
341
360
  }, [previewIframeError]);
342
361
  return (
343
- <CapSpin spinning={isFetchingPreview}>
344
- <div style={{display: 'inline-block'}}>
345
- <CapSelect
346
- label={formatMessage(messages.previewBasedonAdPlacement)}
347
- key={"select-previewBasedonAdPlacement"}
348
- onChange={onChangeAdPreviewFormat}
349
- style={{width: '328px', paddingBottom: 16 }}
350
- options={adOptions}
351
- value={adPreviewFormat}
362
+ <>
363
+ {isSpinning = (fetchPreviewStatus === FETCH_PREVIEW_REQUESTED) ||
364
+ ((fetchPreviewStatus === FETCH_PREVIEW_SUCCESS) && !previewLoaded) ||
365
+ isRefreshing}
366
+ <CapSpin
367
+ spinning={isSpinning}>
368
+ <div style={{ display: 'inline-block' }}>
369
+ <CapSelect
370
+ label={formatMessage(messages.previewBasedonAdPlacement)}
371
+ key={"select-previewBasedonAdPlacement"}
372
+ onChange={onChangeAdPreviewFormat}
373
+ style={{ width: '328px', paddingBottom: 16 }}
374
+ options={adOptions}
375
+ value={adPreviewFormat}
376
+ >
377
+ </CapSelect>
378
+ </div>
379
+ {!hideInfoText && <CapLabel
380
+ type="label1"
381
+ style={{ paddingBottom: 16, textAlign: 'left', width: 392 }}
352
382
  >
353
- </CapSelect>
354
- </div>
355
- {!hideInfoText && <CapLabel
356
- type="label1"
357
- style={{paddingBottom: 16, textAlign: 'left', width: 392}}
383
+ {formatMessage(messages.previewAdDesc)}
384
+ </CapLabel>}
385
+ <div style={{ marginBottom: 16 }}>
386
+ {(disablePreviewButton || disableAfterPreviewGenerate) ?
387
+ <CapTooltip title={formatMessage(messages.generatePreviewDisableToolTip)}>
388
+ <div className="button-disabled-tooltip-wrapper">
389
+ <CapButton
390
+ type="secondary"
391
+ disabled
358
392
  >
359
- {formatMessage(messages.previewAdDesc)}
360
- </CapLabel>}
361
- <div style={{marginBottom: 16}}>
362
- {(disablePreviewButton || disableAfterPreviewGenerate) ?
363
- <CapTooltip title={formatMessage(messages.generatePreviewDisableToolTip)}>
364
- <div className="button-disabled-tooltip-wrapper">
365
- <CapButton
366
- type="secondary"
367
- disabled
368
- >
369
- <FormattedMessage {...messages.generatePreview} />
370
- </CapButton>
371
- </div>
372
- </CapTooltip> :
373
- <CapButton
393
+ <FormattedMessage {...messages.generatePreview} />
394
+ </CapButton>
395
+ </div>
396
+ </CapTooltip> :
397
+ <CapButton
398
+ type="secondary"
399
+ onClick={generatePreview}
400
+ >
401
+ <FormattedMessage {...messages.generatePreview} />
402
+ </CapButton>}
403
+ {isRefreshButton && (<CapButton
404
+ onClick={resetIframe}
374
405
  type="secondary"
375
- onClick={generatePreview}
406
+ style={{ marginLeft: 16 }}
376
407
  >
377
- <FormattedMessage {...messages.generatePreview} />
378
- </CapButton>}
379
- {isRefreshButton && (<CapButton
380
- onClick={resetIframe}
381
- type="secondary"
382
- style={{marginLeft: 16}}
383
- >
384
- {formatMessage(messages.refreshPreview)}
385
- </CapButton>)}
386
- </div>
387
- {isRefreshButton && <div style={{marginBottom: 16}}>
388
- <CapIcon
389
- type="info"
390
- svgProps={{
391
- width: 16,
392
- height: 16,
393
- }}
394
- >
395
- </CapIcon>
396
- <CapLabel.CapLabelInline
397
- type="label1"
398
- size="s"
399
- style={{marginBottom: 16, width: 392}}
400
- >
401
- {formatMessage(messages.videoNotePreview)}
402
- </CapLabel.CapLabelInline>
403
- </div>}
404
- {previewIframe === "" ? <CapImage
405
- src={facebookEmptyPlaceholder}
406
- alt="default"
407
- width="316px"
408
- height="392px"
409
- /> : getIframe(previewIframe)}
410
- </CapSpin>
408
+ {formatMessage(messages.refreshPreview)}
409
+ </CapButton>)}
410
+ </div>
411
+ {isRefreshButton && <div style={{ marginBottom: 16 }}>
412
+ <CapIcon
413
+ type="info"
414
+ svgProps={{
415
+ width: 16,
416
+ height: 16,
417
+ }}
418
+ >
419
+ </CapIcon>
420
+ <CapLabel.CapLabelInline
421
+ type="label1"
422
+ size="s"
423
+ style={{ marginBottom: 16, width: 392 }}
424
+ >
425
+ {formatMessage(messages.videoNotePreview)}
426
+ </CapLabel.CapLabelInline>
427
+ </div>}
428
+ {previewIframe === "" ? <CapImage
429
+ src={facebookEmptyPlaceholder}
430
+ alt="default"
431
+ width="316px"
432
+ height="392px"
433
+ /> : getIframe(previewIframe)}
434
+ </CapSpin>
435
+ </>
411
436
  );
412
437
  };
413
438
 
@@ -6,29 +6,38 @@
6
6
 
7
7
  import { fromJS } from 'immutable';
8
8
  import get from 'lodash/get';
9
- import * as types from './constants';
9
+ import {
10
+ GENERATE_PREVIEW_REQUEST,
11
+ GENERATE_PREVIEW_SUCCESS,
12
+ GENERATE_PREVIEW_FAILURE,
13
+ CLEAR_PREVIEW,
14
+ FETCH_PREVIEW_REQUESTED,
15
+ FETCH_PREVIEW_SUCCESS,
16
+ FETCH_PREVIEW_FAILURE,
17
+ PREVIEW_NOT_REQUESTED,
18
+ } from './constants';
10
19
 
11
20
  const initialState = fromJS({
12
- isFetchingPreview: false,
21
+ fetchPreviewStatus: PREVIEW_NOT_REQUESTED,
13
22
  previewIframe: "",
14
23
  previewIframeError: "",
15
24
  });
16
25
 
17
26
  function capFacebookPreviewReducer(state = initialState, action) {
18
27
  switch (action.type) {
19
- case types.GENERATE_PREVIEW_REQUEST:
20
- return state.set('isFetchingPreview', true)
28
+ case GENERATE_PREVIEW_REQUEST:
29
+ return state.set('fetchPreviewStatus', FETCH_PREVIEW_REQUESTED)
21
30
  .set('previewIframe', "")
22
31
  .set("previewIframeError", "");
23
- case types.GENERATE_PREVIEW_SUCCESS:
24
- return state.set('isFetchingPreview', false)
32
+ case GENERATE_PREVIEW_SUCCESS:
33
+ return state.set('fetchPreviewStatus', FETCH_PREVIEW_SUCCESS)
25
34
  .set('previewIframe', get(action, 'payload.fbPreview[0].body', ""));
26
- case types.GENERATE_PREVIEW_FAILURE:
27
- return state.set('isFetchingPreview', false)
35
+ case GENERATE_PREVIEW_FAILURE:
36
+ return state.set('fetchPreviewStatus', FETCH_PREVIEW_FAILURE)
28
37
  .set('previewIframe', "")
29
38
  .set("previewIframeError", get(action, 'payload.message', ""));
30
- case types.CLEAR_PREVIEW:
31
- return state.set('isFetchingPreview', false)
39
+ case CLEAR_PREVIEW:
40
+ return state.set('fetchPreviewStatus', PREVIEW_NOT_REQUESTED)
32
41
  .set('previewIframe', "")
33
42
  .set("previewIframeError", "");
34
43
  default:
@@ -578,6 +578,7 @@ function SlideBoxContent(props) {
578
578
  templateData={templateData}
579
579
  messageDetails={messageDetails}
580
580
  cap={cap}
581
+ createNew={onCreateNew}
581
582
  onFacebookSubmit={onFacebookSubmit}
582
583
  onCreateComplete={onCreateComplete}
583
584
  isFullMode={isFullMode}
@@ -586,6 +587,7 @@ function SlideBoxContent(props) {
586
587
  }}
587
588
  getFormSubscriptionData={getFormData}
588
589
  fbAdManager={fbAdManager}
590
+ onSelectTemplate={onSelectTemplate}
589
591
  />
590
592
  )
591
593
  }
@@ -10,6 +10,7 @@ import { connect } from 'react-redux';
10
10
  import { createStructuredSelector } from 'reselect';
11
11
  import { bindActionCreators } from 'redux';
12
12
  import styled from 'styled-components';
13
+ import { GA } from '@capillarytech/cap-ui-utils';
13
14
 
14
15
  import * as actions from './actions';
15
16
  import { selectEmailLayout, uploadSelector, templateUserList, makeSelectTemplates } from '../Templates/selectors';
@@ -18,6 +19,7 @@ import SlideBoxHeader from './SlideBoxHeader';
18
19
  import SlideBoxFooter from './SlideBoxFooter';
19
20
  import * as constants from './constants';
20
21
  import * as commonUtil from '../../utils/common';
22
+ import { gtmPush } from '../../utils/gtmTrackers';
21
23
  import './index.scss';
22
24
  import * as templateActions from '../Templates/actions';
23
25
  import * as globalActions from '../Cap/actions';
@@ -25,11 +27,13 @@ import {isLoading as isLoadingSelector} from './selectors';
25
27
  import messages from './messages';
26
28
  import { MAP_TEMPLATE } from '../WeChat/Wrapper/constants';
27
29
  import { makeSelectFetchingCmsData } from '../Email/selectors';
30
+ import { IMAGE as LINE_IMAGE, IMAGE_MAP, IMAGE_CAROUSEL, VIDEO as LINE_VIDEO, TEMPLATE, STICKER } from '../Line/Container/constants';
28
31
  import {IMAGE, VIDEO } from '../Facebook/Advertisement/constant';
29
32
  import { CREATIVE } from '../Facebook/constants';
30
33
 
31
34
 
32
35
  const classPrefix = 'add-creatives-section';
36
+ const CREATIVES_CONTAINER = 'creativesContainer';
33
37
 
34
38
  const SlideBoxWrapper = styled.div`
35
39
  .cap-slide-box-v2-container{
@@ -68,6 +72,10 @@ class Creatives extends React.Component {
68
72
  this.props.globalActions.clearMetaEntities();
69
73
  }
70
74
 
75
+ componentDidMount() {
76
+ GA.timeTracker.startTimer(CREATIVES_CONTAINER);
77
+ }
78
+
71
79
  onEnterTemplateName = () => {
72
80
  this.setState({templateNameExists: true});
73
81
  };
@@ -91,7 +99,7 @@ class Creatives extends React.Component {
91
99
  this.setState({ slidBoxContent: 'preview', templateData });
92
100
  };
93
101
  onEditTemplate = () => {
94
- this.setState({ slidBoxContent: 'editTemplate', showSlideBox: true });
102
+ this.setState({ slidBoxContent: 'editTemplate', showSlideBox: true, templateNameExists: true });
95
103
  };
96
104
  onCreateNew = (fbAdManager) => {
97
105
  const data = { slidBoxContent: 'createTemplate', showSlideBox: true };
@@ -345,7 +353,7 @@ class Creatives extends React.Component {
345
353
  }
346
354
 
347
355
  getCreativesData = (channel, template, templateRecords) => { //from creatives to consumers
348
- let templateData = {channel };
356
+ let templateData = { channel };
349
357
  switch (channel) {
350
358
  case constants.SMS:
351
359
  if (template.value.base) {
@@ -502,6 +510,75 @@ class Creatives extends React.Component {
502
510
  return creativesMode;
503
511
  }
504
512
 
513
+ logGTMEvent(channel, creativesData) {
514
+ const LIBRARY = 'library';
515
+ const timeTaken = GA.timeTracker.stopTimer(CREATIVES_CONTAINER, {
516
+ category: 'Campaigns',
517
+ action: 'Creatives',
518
+ label: 'Indirect',
519
+ });
520
+ const {
521
+ androidContent: {
522
+ title: androidTitle,
523
+ message: androidMessage,
524
+ type: androidType,
525
+ } = {},
526
+ iosContent: {
527
+ title: iosTitle,
528
+ message: iosMessage,
529
+ type: iosType,
530
+ } = {},
531
+ messageBody = '',
532
+ emailBody = '',
533
+ } = creativesData;
534
+ let gtmDetails = {
535
+ channel,
536
+ timeTaken,
537
+ mode: LIBRARY,
538
+ content: messageBody,
539
+ };
540
+ switch (channel) {
541
+ case constants.SMS:
542
+ case constants.WECHAT:
543
+ case constants.VIBER:
544
+ break;
545
+ case constants.EMAIL:
546
+ gtmDetails = {
547
+ ...gtmDetails,
548
+ content: emailBody,
549
+ };
550
+ break;
551
+ case constants.MOBILE_PUSH:
552
+ gtmDetails = {
553
+ ...gtmDetails,
554
+
555
+ content: `${androidTitle} ${androidMessage} ${iosTitle} ${iosMessage}`,
556
+ imageAdded: androidType === 'IMAGE' || iosType === 'IMAGE',
557
+ };
558
+ break;
559
+ case constants.LINE:
560
+ gtmDetails = Object.assign({
561
+ ...gtmDetails,
562
+ }, this.getLineMessageTypes(messageBody));
563
+ break;
564
+ default:
565
+ return false;
566
+ }
567
+ gtmPush('creativeDetails', gtmDetails);
568
+ }
569
+
570
+ getLineMessageTypes(messageBody) {
571
+ const {
572
+ messages: lineMessages = [],
573
+ } = JSON.parse(messageBody);
574
+ const typeOfMessages = lineMessages.map((message) => message.type);
575
+ return {
576
+ imageAdded: typeOfMessages.some((type) => [LINE_IMAGE, IMAGE_MAP, IMAGE_CAROUSEL, TEMPLATE].includes(type)),
577
+ videoAdded: typeOfMessages.includes(LINE_VIDEO),
578
+ stickerAdded: typeOfMessages.includes(STICKER),
579
+ };
580
+ }
581
+
505
582
  getFormData = (template) => {
506
583
  if (template.validity) {
507
584
  this.setState(
@@ -512,6 +589,7 @@ class Creatives extends React.Component {
512
589
  const templateData = this.state.templateData ? this.state.templateData : template; //select existing or create new content
513
590
  const channel = templateData.type;
514
591
  const creativesData = this.getCreativesData(channel, template, templateData );// convers data to consumer understandable format
592
+ this.logGTMEvent(channel, creativesData);
515
593
  this.props.getCreativesData(creativesData);// send data to consumer
516
594
  },
517
595
  );
@@ -474,9 +474,9 @@ export const Advertisement = (props) => {
474
474
  if (webSiteLink === "" || errorMsg.websiteLinkErrorMsg ) {
475
475
  flag = true;
476
476
  }
477
- if (Object.keys(imageData).length === 0 && subType === IMAGE) {
477
+ if (!imageData?.imageSrc && subType === IMAGE) {
478
478
  flag = true;
479
- } else if (Object.keys(videoData).length === 0 && subType === VIDEO) {
479
+ } else if (!videoData?.videoSrc && subType === VIDEO) {
480
480
  flag = true;
481
481
  }
482
482
  subTypes.push(subType);
@@ -21,7 +21,7 @@ $classPrefix: add-facebook-ad-section;
21
21
  display: inline-block;
22
22
  }
23
23
  .cap-input-edit-name{
24
- width: 500px;
24
+ width: 319px;
25
25
  }
26
26
  .cap-link-edit-name{
27
27
  display: inline-block;
@@ -269,7 +269,11 @@ const Facebook = (props) => {
269
269
  ]);
270
270
  const query = {type: 'embedded', module: 'library'};
271
271
  const location = {pathname: `/FACEBOOK`, search: '', query};
272
- return (showTemplateList ? (
272
+
273
+ // fbAdManager ==cretaives only the case for default startegy and user selected "capillary ad manager"
274
+ // below condition (fbAdManager !==CREATIVE) is for edit fb ad manager from campaign
275
+ //-> select capillary ad manager-> select template
276
+ return ((showTemplateList && fbAdManager !==CREATIVE) ? (
273
277
  <Templates
274
278
  key={"FACEBOOK"}
275
279
  location={location}
@@ -280,11 +284,18 @@ const Facebook = (props) => {
280
284
  onSelectTemplate={onSelectTemplate}
281
285
  renderNewCardGrid={renderNewCardGrid}
282
286
  handlePeviewTemplate={handlePeviewTemplate}
283
- fbAdManager={CREATIVE}
287
+ fbAdManager={CREATIVE} // it means we are selecting capillary ad manager from campaign
284
288
  />
285
289
  ) :
286
- (!isFullMode && (fbAdManager !== CREATIVE && messageStrategy === "DEFAULT" || (templateData?.edit && templateData?.fbContentType !==CREATIVE)) ) ?
287
- (<div className={className}>
290
+ (!isFullMode && ((fbAdManager !== CREATIVE && messageStrategy === "DEFAULT")
291
+ || (templateData?.edit && templateData?.fbContentType !==CREATIVE && fbAdManager !== CREATIVE )) ) ?
292
+
293
+ // not fullmode +
294
+ // default strtaegy and not selected "capillary ad manager" from campaign message +
295
+ //edit template && not coming from campaign message where user selected "capillary ad manager" (means edit "fb ad manager" from campaign) &&
296
+ // & also we are not selecting capillary ad manager from campaign
297
+
298
+ (<div className={className}>
288
299
 
289
300
  <div className="is-scrollable-section" >
290
301
  <div className="account-details-wrapper">
@@ -59,7 +59,7 @@ export const LineDrawer = ({
59
59
  queryParams.page = page;
60
60
  queryParams.perPage = 25;
61
61
 
62
- if (params.name !== "") {
62
+ if (params?.name) {
63
63
  queryParams.name = params.name;
64
64
  queryParams.page = 1;
65
65
  }
@@ -346,7 +346,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
346
346
  });
347
347
  } else {
348
348
  selectedAccount = accounts[0];
349
- formData['mobilepush-accounts'] = accounts[0].id;
349
+ formData['mobilepush-accounts'] = selectedAccount?.id;
350
350
  }
351
351
  this.props.actions.setWeChatAccount(selectedAccount);
352
352
  this.setState({formData, accountsOptions: accounts.map((acc) => ({key: acc.id, label: acc.name, value: acc.id}))});
@@ -361,7 +361,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
361
361
  obj.type = 'MOBILEPUSH';
362
362
  obj.name = formData['template-name'];
363
363
  obj.definition = {
364
- accountId: selectedWeChatAccount.id,
364
+ accountId: selectedWeChatAccount?.id,
365
365
  licenseCode: selectedWeChatAccount.sourceAccountIdentifier,
366
366
  };
367
367
  if (this.props.location.query && this.props.location.query.module !== 'dvs') {
@@ -45,7 +45,7 @@ export class MobilepushWrapper extends React.Component { // eslint-disable-line
45
45
  },
46
46
  {
47
47
  title: <FormattedMessage {...messages.text}/>,
48
- content: <WithNoImage height="124px" width={"224px"}/>,
48
+ content: <WithNoImage height="216px" width={"224px"}/>,
49
49
  value: 'text',
50
50
  // onClick: () => {
51
51
  // this.emailUploader.current.click();
@@ -32,8 +32,7 @@
32
32
  padding: $CAP_SPACE_16 $CAP_SPACE_12;
33
33
 
34
34
  .ant-card-meta-description {
35
- height: 250px;
36
- word-wrap: break-word;
35
+ height: 222px;
37
36
  }
38
37
  }
39
38
 
@@ -41,6 +40,9 @@
41
40
  .ant-card-body {
42
41
  padding: $CAP_SPACE_24 0;
43
42
  }
43
+ .ant-card-meta-description {
44
+ height: 250px;
45
+ }
44
46
  .ant-card-meta {
45
47
  padding: 0;
46
48
  }
@@ -1418,7 +1418,11 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
1418
1418
  }
1419
1419
  }
1420
1420
  if (this.isEnabledInLibraryModule("callSelectFromProps")) {
1421
- this.props.onSelectTemplate(this.selectTemplate(id), this.props.fbAdManager);
1421
+ let data =id;
1422
+ if(this.props.fbAdManager){
1423
+ data = this.selectTemplate(id)
1424
+ }
1425
+ this.props.onSelectTemplate(data, this.props.fbAdManager);
1422
1426
  } else {
1423
1427
  timeTracker.startTimer(CHANNEL_EDIT_TRACK_MAPPING[this.state.channel.toLowerCase()]);
1424
1428
  if (this.state.channel.toLowerCase() === 'ebill') {
@@ -1433,7 +1437,6 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
1433
1437
 
1434
1438
  selectTemplate = (id) => find(this.props.TemplatesList, {_id: id})
1435
1439
 
1436
-
1437
1440
  handlePreviewClick(template, modeType) {
1438
1441
  this.togglePreview();
1439
1442
  const templateInfo = cloneDeep(template);
@@ -2025,6 +2028,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
2025
2028
  onChange={(e) => this.searchTemplate(e.target.value)}
2026
2029
  disabled={this.checkSearchDisabled()}
2027
2030
  onClear={() => this.searchTemplate('')}
2031
+ onScroll={(e) => e.stopPropagation()}
2028
2032
  />}
2029
2033
  {
2030
2034
  channel.toUpperCase() === WECHAT && <CapRadio.CapRadioGroup className="wechat-filters" defaultValue={wechatFilter} onChange={this.setWechatFilter}>
@@ -28,7 +28,7 @@ import FTP from '../FTP';
28
28
  import Gallery from '../Assets/Gallery';
29
29
  import withStyles from '../../hoc/withStyles';
30
30
  import styles, { CapTabStyle } from './TemplatesV2.style';
31
- import { CREATIVES_UI_VIEW } from '../App/constants';
31
+ import { CREATIVES_UI_VIEW, LOYALTY} from '../App/constants';
32
32
  import AccessForbidden from '../../v2Components/AccessForbidden';
33
33
 
34
34
  const {CapCustomCardList} = CapCustomCard;
@@ -39,6 +39,9 @@ export class TemplatesV2 extends React.Component { // eslint-disable-line react/
39
39
  constructor(props) {
40
40
  super(props);
41
41
  let defaultChannel = get(this, 'props.channel') || get(this, 'props.params.channel') || 'sms';
42
+ if (defaultChannel === LOYALTY) {
43
+ defaultChannel = 'sms';
44
+ }
42
45
  const {
43
46
  intl,
44
47
  channelsToHide = [],
@@ -158,7 +161,11 @@ export class TemplatesV2 extends React.Component { // eslint-disable-line react/
158
161
  );
159
162
 
160
163
  getFacebookComponent = () => {
161
- const { messageDetails, cap, onFacebookSubmit, messageStrategy, showDisabledFBInfo, orgUnitId } = this.props;
164
+ const { messageDetails, cap, onFacebookSubmit,
165
+ messageStrategy,
166
+ showDisabledFBInfo,
167
+ orgUnitId,
168
+ onSelectTemplate } = this.props;
162
169
  return (
163
170
  <Facebook
164
171
  {...this.props}
@@ -168,6 +175,7 @@ export class TemplatesV2 extends React.Component { // eslint-disable-line react/
168
175
  messageStrategy={messageStrategy}
169
176
  showDisabledFBInfo={showDisabledFBInfo}
170
177
  orgUnitId={orgUnitId}
178
+ onSelectTemplate={onSelectTemplate}
171
179
  />
172
180
  );
173
181
  }
@@ -220,7 +228,7 @@ export class TemplatesV2 extends React.Component { // eslint-disable-line react/
220
228
  router={this.props.router}
221
229
  isFullMode={this.props.isFullMode}
222
230
  createNew={this.props.createNew}
223
- onSelectTemplate={this.props.onSelectTemplate}
231
+ onSelectTemplate={(id) => this.props.onSelectTemplate(this.selectTemplate(id))}
224
232
  renderNewCardGrid={this.getTemplateDataForGrid}
225
233
  handlePeviewTemplate={this.props.handlePeviewTemplate}
226
234
  messageStrategy={this.props.messageStrategy}
@@ -666,7 +666,16 @@ export class MapTemplates extends React.Component { // eslint-disable-line react
666
666
  type: "radioGroup",
667
667
  metaType: "text",
668
668
  datatype: "string",
669
- options: [intl.formatMessage(messages.redirectOptionURL), intl.formatMessage(messages.redirectOptionMiniProgram)],
669
+ options: [
670
+ {
671
+ value: URL,
672
+ label: intl.formatMessage(messages.redirectOptionURL)
673
+ },
674
+ {
675
+ value: MINI_PROGRAM,
676
+ label: intl.formatMessage(messages.redirectOptionMiniProgram)
677
+ }
678
+ ],
670
679
  errorMessage: intl.formatMessage(messages.redirectionOptionError),
671
680
  required: true,
672
681
  fluid: true,
@@ -764,7 +773,8 @@ export class MapTemplates extends React.Component { // eslint-disable-line react
764
773
  if (!isEmpty(weCrmAccounts)) {
765
774
  forEach(weCrmAccounts, (account) => {
766
775
  if (account.configs && account.configs.is_wecrm_enabled) {
767
- schema.standalone.sections[0].childSections[1].childSections[0].childSections[0].inputFields[0].options.push({
776
+ const options = schema?.standalone?.sections[0]?.childSections[1]?.childSections[0]?.childSections[0]?.inputFields[0]?.options;
777
+ options && options.push({
768
778
  key: account.uuid,
769
779
  label: account.name,
770
780
  value: account.name,