@capillarytech/creatives-library 7.7.0 → 7.7.3

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 -0
  2. package/index.html +2 -2
  3. package/index.js +3 -3
  4. package/package.json +4 -2
  5. package/services/api.js +2 -0
  6. package/utils/gtmTrackers/gtmEvents/creativeDetails.js +41 -0
  7. package/utils/gtmTrackers/index.js +17 -0
  8. package/v2Components/TemplatePreview/index.js +1 -0
  9. package/v2Containers/App/constants.js +11 -0
  10. package/v2Containers/Cap/index.js +23 -29
  11. package/v2Containers/CapFacebookPreview/index.js +9 -9
  12. package/v2Containers/CapFacebookPreview/index.scss +15 -0
  13. package/v2Containers/CreativesContainer/SlideBoxContent.js +16 -1
  14. package/v2Containers/CreativesContainer/index.js +122 -12
  15. package/v2Containers/Email/index.js +14 -3
  16. package/v2Containers/EmailWrapper/index.js +10 -3
  17. package/v2Containers/Facebook/Advertisement/index.js +72 -36
  18. package/v2Containers/Facebook/Advertisement/index.scss +1 -1
  19. package/v2Containers/Facebook/Facebook.style.js +1 -1
  20. package/v2Containers/Facebook/constants.js +4 -0
  21. package/v2Containers/Facebook/index.js +198 -122
  22. package/v2Containers/Facebook/messages.js +24 -4
  23. package/v2Containers/Line/Container/index.js +32 -4
  24. package/v2Containers/MobilePush/Create/index.js +25 -4
  25. package/v2Containers/MobilePush/Edit/index.js +27 -5
  26. package/v2Containers/MobilePush/Edit/sagas.js +1 -1
  27. package/v2Containers/MobilePush/commonMethods.js +19 -1
  28. package/v2Containers/Sms/Create/index.js +14 -2
  29. package/v2Containers/Sms/Edit/index.js +15 -2
  30. package/v2Containers/Templates/index.js +43 -27
  31. package/v2Containers/Templates/messages.js +1 -1
  32. package/v2Containers/Templates/reducer.js +4 -2
  33. package/v2Containers/TemplatesV2/index.js +23 -6
  34. package/v2Containers/TemplatesV2/messages.js +4 -0
  35. package/v2Containers/Viber/index.js +19 -3
  36. package/v2Containers/WeChat/MapTemplates/index.js +12 -3
  37. package/v2Containers/WeChat/RichmediaTemplates/Create/index.js +11 -2
package/app.js CHANGED
@@ -78,6 +78,11 @@ const bugSnagErrorCallback = (event) => {
78
78
  id: orgId,
79
79
  });
80
80
  event.setUser(userId, userEmail, userName);
81
+ if (window.FS && window.FS.getCurrentSessionURL) {
82
+ event.addMetadata('fullstory', {
83
+ urlAtTime: window.FS.getCurrentSessionURL(true),
84
+ });
85
+ }
81
86
  };
82
87
 
83
88
  Bugsnag.start({
package/index.html CHANGED
@@ -19,14 +19,14 @@
19
19
  new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
20
20
  j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
21
21
  'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
22
- })(window,document,'script','dataLayer','GTM-NGLVR5C');</script>
22
+ })(window,document,'script','dataLayer','GTM-MC4TRPX');</script>
23
23
  <!-- End Google Tag Manager -->
24
24
  <script>try{Typekit.load({ async: true });}catch(e){console.log(e)}</script>
25
25
  <title>Capillary - Creatives</title>
26
26
  </head>
27
27
  <body>
28
28
  <noscript>
29
- <iframe src="https://www.googletagmanager.com/ns.html?id=GTM-NGLVR5C"
29
+ <iframe src="https://www.googletagmanager.com/ns.html?id=GTM-MC4TRPX"
30
30
  height="0" width="0" style="display:none;visibility:hidden"></iframe>
31
31
  </noscript>
32
32
  <!-- End Google Tag Manager (noscript) -->
package/index.js CHANGED
@@ -76,8 +76,8 @@ import viberSaga from './v2Containers/Viber/sagas';
76
76
  import TemplatesV2 from './v2Containers/TemplatesV2/index';
77
77
 
78
78
  import FacebookPreview from './v2Containers/CapFacebookPreview';
79
- import FacebookPreviewReducer from './v2Containers/CapFacebookPreview/reducer';
80
- import FacebookPreviewSaga from './v2Containers/CapFacebookPreview/sagas';
79
+ import facebookPreviewReducer from './v2Containers/CapFacebookPreview/reducer';
80
+ import facebookPreviewSaga from './v2Containers/CapFacebookPreview/sagas';
81
81
 
82
82
  import CreativesContainer from './v2Containers/CreativesContainer';
83
83
  import CreativesContainerReducer from './v2Containers/CreativesContainer/reducer';
@@ -105,7 +105,7 @@ const LineCreateContainer = {LineCreate, lineCreateReducer, lineCreateSaga};
105
105
  const TemplatesV2Container = {TemplatesV2, templateReducer, templateSaga};
106
106
  const FacebookContainer = {Facebook, facebookReducer, facebookSaga};
107
107
  const ViberContainer = {Viber, viberReducer, viberSaga};
108
- const FacebookPreviewContainer = { FacebookPreview, FacebookPreviewReducer, FacebookPreviewSaga };
108
+ const FacebookPreviewContainer = { FacebookPreview, facebookPreviewReducer, facebookPreviewSaga };
109
109
 
110
110
  const GalleryContainer = {Gallery, galleryReducer, gallerySagas};
111
111
  const FTPContainer = {FTP, FTPReducer, FTPSagas};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "7.7.0",
4
+ "version": "7.7.3",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -15,10 +15,12 @@
15
15
  "@babel/polyfill": "7.4.3",
16
16
  "@bugsnag/js": "^7.2.1",
17
17
  "@bugsnag/plugin-react": "^7.2.1",
18
- "@capillarytech/cap-ui-utils": "1.3.4",
18
+ "@capillarytech/cap-ui-utils": "1.4.0",
19
19
  "@mailupinc/bee-plugin": "^1.2.0",
20
20
  "babel-cli": "^6.26.0",
21
21
  "chalk": "1.1.3",
22
+ "flow": "^0.2.3",
23
+ "git": "^0.1.5",
22
24
  "jquery": "^3.3.1",
23
25
  "load-script": "^1.0.0",
24
26
  "normalizr": "^3.2.3",
package/services/api.js CHANGED
@@ -70,6 +70,8 @@ function checkStatus(response) {
70
70
  tracker.trackException({
71
71
  description: `API Error ${requestCallerName} returned ${status}`,
72
72
  fatal: true,
73
+ apiError: true,
74
+ statusCode: status
73
75
  });
74
76
  }
75
77
  if ((status >= 200 && status < 300) || [500, 409, 413].includes(response.status)) {
@@ -0,0 +1,41 @@
1
+ import { CREATIVES } from "../../../v2Containers/App/constants";
2
+
3
+ const creativeDetails = ({
4
+ name,
5
+ id,
6
+ channel,
7
+ videoAdded,
8
+ imageAdded,
9
+ stickersAdded,
10
+ timeTaken,
11
+ content,
12
+ mode
13
+ }) => {
14
+ const parsedObj = {
15
+ name,
16
+ id,
17
+ creationSource: CREATIVES,
18
+ channel,
19
+ timeTaken,
20
+ isLabelsUsed: isLabelsUsed(content),
21
+ mode,
22
+ imageAdded,
23
+ videoAdded,
24
+ stickersAdded
25
+ };
26
+ window.dataLayer.push({
27
+ creativeDetails: parsedObj,
28
+ event: 'creativeDetails',
29
+ });
30
+ };
31
+
32
+ const isLabelsUsed = (content = '') => {
33
+ const tagRegex = /{{[(A-Z\w+(\s\w+)*$\(\)@!#$%^&*~.,/\\]+}}/g; // eslint-disable-line no-useless-escape
34
+ content = content.replaceAll('{{optout}}', '');
35
+ content = content.replaceAll('{{unsubscribe}}', '');
36
+ const tags = [...content.matchAll(tagRegex)];
37
+ return !!tags.length;
38
+ };
39
+
40
+
41
+ export default creativeDetails;
@@ -0,0 +1,17 @@
1
+ import Bugsnag from '@bugsnag/js';
2
+
3
+ const gtmEvents = require.context('./gtmEvents', true, /\.js$/, 'lazy');
4
+
5
+ export const gtmPush = (eventType, eventObject) => {
6
+ try {
7
+ gtmEvents(`./${eventType}.js`)
8
+ .then(event => {
9
+ event.default(eventObject);
10
+ })
11
+ .catch(err => {
12
+ Bugsnag.notify(err);
13
+ });
14
+ } catch (e) {
15
+ Bugsnag.notify(e);
16
+ }
17
+ };
@@ -651,6 +651,7 @@ class TemplatePreview extends React.Component { // eslint-disable-line react/pre
651
651
  pageId: content.pageId}}
652
652
  accountId={content.accountId}
653
653
  accessToken={content.accessToken}
654
+ defaultGeneratePreview
654
655
  />
655
656
  </div>
656
657
  )}
@@ -19,6 +19,8 @@ export const TRACK_CREATE_MPUSH = 'createMpush';
19
19
  export const TRACK_CREATE_WECHAT = 'createWeChat';
20
20
  export const TRACK_CREATE_IMAGE = 'createImage';
21
21
  export const TRACK_CREATE_LINE = 'createLine';
22
+ export const TRACK_CREATE_VIBER = 'createViber';
23
+ export const TRACK_CREATE_FACEBOOK = 'createFacebook';
22
24
 
23
25
  export const CREATE = 'create';
24
26
  export const EDIT = 'edit';
@@ -33,6 +35,8 @@ export const TRACK_EDIT_MPUSH = 'editMpush';
33
35
  export const TRACK_EDIT_WECHAT = 'editWeChat';
34
36
  export const TRACK_EDIT_IMAGE = 'editImage';
35
37
  export const TRACK_EDIT_LINE = 'editLine';
38
+ export const TRACK_EDIT_VIBER = 'editViber';
39
+ export const TRACK_EDIT_FACEBOOK = 'editFacebook';
36
40
 
37
41
  export const CHANNEL_CREATE_TRACK_MAPPING = {
38
42
  sms: TRACK_CREATE_SMS,
@@ -41,6 +45,8 @@ export const CHANNEL_CREATE_TRACK_MAPPING = {
41
45
  wechat: TRACK_CREATE_WECHAT,
42
46
  gallery: TRACK_CREATE_IMAGE,
43
47
  line: TRACK_CREATE_LINE,
48
+ viber: TRACK_CREATE_VIBER,
49
+ facebook: TRACK_CREATE_FACEBOOK
44
50
  };
45
51
 
46
52
  export const CHANNEL_EDIT_TRACK_MAPPING = {
@@ -50,6 +56,8 @@ export const CHANNEL_EDIT_TRACK_MAPPING = {
50
56
  wechat: TRACK_EDIT_WECHAT,
51
57
  gallery: TRACK_EDIT_IMAGE,
52
58
  line: TRACK_EDIT_LINE,
59
+ viber: TRACK_EDIT_VIBER,
60
+ facebook: TRACK_EDIT_FACEBOOK
53
61
  };
54
62
  export const GTM_TRACKING_ID = 'UA-110024621-2';
55
63
  export const BEE_PLUGIN = 'BEE_PLUGIN';
@@ -75,3 +83,6 @@ export const FB_AD_CALL_TO_ACTION = {
75
83
  SUBSCRIBE,
76
84
  WATCH_MORE,
77
85
  };
86
+
87
+
88
+ export const CREATIVES = 'creatives';
@@ -77,13 +77,11 @@ export class Cap extends React.Component { // eslint-disable-line react/prefer-s
77
77
  if (!userData.accessiblePermissions.includes(CREATIVES_UI_VIEW)) {
78
78
  this.setState({ isCreativesAccessible: false });
79
79
  }
80
- this.setDimensionData();
80
+ const userGtmData = this.getUserGtmData();
81
+ this.setDimensionData(userGtmData);
82
+ gtm.push({...userGtmData, event: 'userAuthenticated'});
81
83
  });
82
84
  this.props.actions.getTopbarMenuData();
83
- if (this.props.Global.user) {
84
- const userGtmData = this.getUserGtmData();
85
- gtm.push(userGtmData);
86
- }
87
85
  if (this.props.Global.orgID !== undefined) {
88
86
  gtm.push({orgId: this.props.Global.orgID});
89
87
  }
@@ -133,18 +131,6 @@ export class Cap extends React.Component { // eslint-disable-line react/prefer-s
133
131
  if (nextPropsUser && user && nextProps.Global.isLoggedIn && nextProps.Global.isLoggedIn !== this.props.Global.isLoggedIn) {
134
132
  this.props.appActions.getSidebar();
135
133
  }
136
-
137
- if (nextProps.Global.user && this.props.Global.user && (nextProps.Global.user.refID !== this.props.Global.user.refID)) {
138
- const userGtmData = this.getUserGtmData(nextProps);
139
- gtm.push(userGtmData);
140
- }
141
-
142
- if (nextProps.Global.isLoggedIn && nextProps.Global.isLoggedIn !== this.props.Global.isLoggedIn) {
143
- if (nextProps.Global.orgID !== undefined && !_.isEqual(nextProps.Global.orgID, this.props.Global.orgID)) {
144
- const userGtmData = this.getUserGtmData(nextProps);
145
- gtm.push(userGtmData);
146
- }
147
- }
148
134
  }
149
135
 
150
136
  componentDidUpdate(prevProps) {
@@ -182,26 +168,34 @@ export class Cap extends React.Component { // eslint-disable-line react/prefer-s
182
168
  logNewTab();
183
169
  }
184
170
 
185
- setDimensionData() {
186
- const userGtmData = this.getUserGtmData();
171
+ setDimensionData(userGtmData) {
187
172
  Object.values(userGtmData).forEach((value, index) => {
188
173
  GA.setCustomDimension({ [`dimension${index + 1}`]: value });
189
174
  });
190
175
  }
191
176
  getUserGtmData(props) {
192
177
  const selectedProps = props || this.props;
193
- const { user: userData } = selectedProps.Global;
178
+ const { user: userData, orgID} = selectedProps?.Global || {};
194
179
  if (userData) {
195
- const userName = userData.attributes.USERNAME;
196
- const userEmail = userData.attributes.EMAIL;
197
- const orgObj = _.find(userData.proxyOrgList, {orgID: selectedProps.Global.orgID});
180
+ const {
181
+ attributes: {
182
+ USERNAME : userName,
183
+ EMAIL : userEmail
184
+ } = {},
185
+ proxyOrgList,
186
+ isCapUser,
187
+ refID
188
+ } = userData;
189
+ const {
190
+ orgName
191
+ } = _.find(proxyOrgList, {orgID});
198
192
  const gtmData = {
199
- isCapUser: userData.isCapUser,
200
- orgId: selectedProps.Global.orgID,
201
- orgName: orgObj && orgObj.orgName,
202
- userId: userData.refID,
203
- userName: userName && userName.value,
204
- userEmail: userEmail && userEmail.value,
193
+ isCapUser: isCapUser,
194
+ orgId: orgID,
195
+ orgName,
196
+ userId: refID,
197
+ userName: userName?.value,
198
+ userEmail: userEmail?.value,
205
199
  };
206
200
  return gtmData;
207
201
  }
@@ -30,7 +30,7 @@ import {
30
30
  CAROUSEL,
31
31
  NO_CALL_TO_ACTION,
32
32
  } from '../../v2Containers/Facebook/Advertisement/constant';
33
-
33
+ import './index.scss';
34
34
 
35
35
  export const CapFacebookPreview = (props) => {
36
36
  const {
@@ -45,6 +45,7 @@ export const CapFacebookPreview = (props) => {
45
45
  orgUnitFacebookPageSettingsMap = {},
46
46
  accessToken,
47
47
  accountId,
48
+ defaultGeneratePreview,
48
49
  } = props;
49
50
  const {
50
51
  formatMessage,
@@ -283,22 +284,19 @@ export const CapFacebookPreview = (props) => {
283
284
  const r = random + 1;
284
285
  setRandom(r);
285
286
  };
286
-
287
287
  const getIframe = (iframe) => {
288
288
  const divTag = document.createElement('div');
289
289
  divTag.innerHTML = iframe;
290
290
  const src = divTag.getElementsByTagName('iframe')[0].getAttribute('src');
291
- const width = divTag.getElementsByTagName('iframe')[0].getAttribute('width');
292
- const height = divTag.getElementsByTagName('iframe')[0].getAttribute('height');
293
291
  return (<>
294
292
  <iframe
295
293
  src={src}
296
294
  key={random}
297
- scrolling="yes"
298
295
  style={{border: "none"}}
299
- width={width}
300
- height={height}
301
- loading="lazy"
296
+ width={"800px"}
297
+ scrolling="yes"
298
+ height={"1000px"}
299
+ className="cap-facebook-ad-iframe"
302
300
  />
303
301
  </>);
304
302
  };
@@ -317,6 +315,9 @@ export const CapFacebookPreview = (props) => {
317
315
 
318
316
  useEffect(() => {
319
317
  facebookPreviewActions.clearPreview();
318
+ if (defaultGeneratePreview) {
319
+ generatePreview();
320
+ }
320
321
  }, []);
321
322
 
322
323
  useEffect(() => {
@@ -335,7 +336,6 @@ export const CapFacebookPreview = (props) => {
335
336
  setDisableAfterPreviewGenerate(false);
336
337
  }
337
338
  }, [previewIframeError]);
338
-
339
339
  return (
340
340
  <CapSpin spinning={isFetchingPreview}>
341
341
  <div style={{display: 'inline-block'}}>
@@ -0,0 +1,15 @@
1
+ .cap-facebook-ad-iframe{
2
+ -moz-transform: scale(0.75, 0.75);
3
+ -webkit-transform: scale(0.75, 0.75);
4
+ -o-transform: scale(0.75, 0.75);
5
+ -ms-transform: scale(0.75, 0.75);
6
+ transform: scale(0.75, 0.75);
7
+ -moz-transform-origin: top left;
8
+ -webkit-transform-origin: top left;
9
+ -o-transform-origin: top left;
10
+ -ms-transform-origin: top left;
11
+ transform-origin: top left;
12
+ #facebook{
13
+ position: absolute;
14
+ }
15
+ }
@@ -137,6 +137,10 @@ function SlideBoxContent(props) {
137
137
  handleClose,
138
138
  onFTPSubmit,
139
139
  campaignSettings,
140
+ messageStrategy,
141
+ fbAdManager,
142
+ showDisabledFBInfo,
143
+ orgUnitId,
140
144
  } = props;
141
145
  const type = (messageDetails.type || '').toLowerCase(); // type is context in get tags values : outbound | dvs | referral | loyalty | coupons
142
146
  const query = { type: !isFullMode && 'embedded', module: isFullMode ? 'default' : 'library', isEditFromCampaigns: (templateData || {}).isEditFromCampaigns};
@@ -334,6 +338,9 @@ function SlideBoxContent(props) {
334
338
  slidBoxContent={slidBoxContent}
335
339
  FTPMode="create"
336
340
  selectedOfferDetails={selectedOfferDetails}
341
+ messageStrategy={messageStrategy}
342
+ showDisabledFBInfo={showDisabledFBInfo}
343
+ orgUnitId={orgUnitId}
337
344
  />
338
345
  )}
339
346
  {isPreview && (
@@ -558,7 +565,10 @@ function SlideBoxContent(props) {
558
565
  isFullMode={isFullMode}
559
566
  createNew
560
567
  getFormSubscriptionData={getFormData}
561
-
568
+ messageStrategy={messageStrategy}
569
+ fbAdManager={fbAdManager}
570
+ onSelectTemplate={onSelectTemplate}
571
+ orgUnitId={orgUnitId}
562
572
  />
563
573
  )
564
574
  }
@@ -575,6 +585,7 @@ function SlideBoxContent(props) {
575
585
  id: templateData._id,
576
586
  }}
577
587
  getFormSubscriptionData={getFormData}
588
+ fbAdManager={fbAdManager}
578
589
  />
579
590
  )
580
591
  }
@@ -687,5 +698,9 @@ SlideBoxContent.propTypes = {
687
698
  saveMessage: PropTypes.func,
688
699
  selectedAccount: PropTypes.object,
689
700
  onFTPSubmit: PropTypes.func,
701
+ messageStrategy: PropTypes.string,
702
+ fbAdManager: PropTypes.string,
703
+ showDisabledFBInfo: PropTypes.boolean,
704
+ orgUnitId: PropTypes.any,
690
705
  };
691
706
  export default SlideBoxContent;
@@ -25,6 +25,9 @@ import {isLoading as isLoadingSelector} from './selectors';
25
25
  import messages from './messages';
26
26
  import { MAP_TEMPLATE } from '../WeChat/Wrapper/constants';
27
27
  import { makeSelectFetchingCmsData } from '../Email/selectors';
28
+ import {IMAGE, VIDEO } from '../Facebook/Advertisement/constant';
29
+ import { CREATIVE } from '../Facebook/constants';
30
+
28
31
 
29
32
  const classPrefix = 'add-creatives-section';
30
33
 
@@ -51,7 +54,6 @@ class Creatives extends React.Component {
51
54
  currentChannel: this.props.channel || 'sms',
52
55
  weChatTemplateType: '',
53
56
  weChatMaptemplateStep: 0,
54
-
55
57
  };
56
58
  this.creativesTemplateSteps = {
57
59
  1: 'modeSelection',
@@ -74,8 +76,12 @@ class Creatives extends React.Component {
74
76
  this.setState({templateNameExists: false});
75
77
  }
76
78
 
77
- onSelectTemplate = (template) => {
78
- this.setState({ slidBoxContent: 'editTemplate', templateData: template });
79
+ onSelectTemplate = (template, fbAdManager) => {
80
+ const data = {slidBoxContent: 'editTemplate', templateData: template};
81
+ if (fbAdManager) {
82
+ data.fbAdManager = fbAdManager;
83
+ }
84
+ this.setState(data);
79
85
  };
80
86
  onPreviewTemplate = (template) => {
81
87
  const templateData = template;
@@ -87,8 +93,12 @@ class Creatives extends React.Component {
87
93
  onEditTemplate = () => {
88
94
  this.setState({ slidBoxContent: 'editTemplate', showSlideBox: true });
89
95
  };
90
- onCreateNew = () => {
91
- this.setState({ slidBoxContent: 'createTemplate', showSlideBox: true });
96
+ onCreateNew = (fbAdManager) => {
97
+ const data = { slidBoxContent: 'createTemplate', showSlideBox: true };
98
+ if (fbAdManager) {
99
+ data.fbAdManager = fbAdManager;
100
+ }
101
+ this.setState(data);
92
102
  };
93
103
 
94
104
  onShowTemplates = () => {
@@ -220,11 +230,61 @@ class Creatives extends React.Component {
220
230
  break;
221
231
  }
222
232
  case constants.FACEBOOK: {
223
- creativesTemplateData = {
224
- selectedMarketingObjective: templateData.selectedMarketingObjective,
225
- edit: true,
226
- type: channel,
227
- };
233
+ if (templateData.fbContentType === CREATIVE) {
234
+ const {
235
+ creativeType = "",
236
+ selectedFacebookAccount = {},
237
+ facebookCreativeList: fbCreativeList = [],
238
+ } = templateData || {};
239
+ const fBContent = fbCreativeList;
240
+ const facebookCreativeList = [];
241
+ fBContent.forEach((obj) => {
242
+ const data = cloneDeep(obj);
243
+ const {subType, linkDescription, imageLink, websiteLink, videoId, videoName, videoUrl} = obj || {};
244
+ delete data.linkDescription;
245
+ delete data.websiteLink;
246
+ data.linkDesc = linkDescription;
247
+ data.webSiteLink = websiteLink;
248
+ data.type = creativeType;
249
+ switch (subType) {
250
+ case IMAGE:
251
+ data.imgSrc = imageLink;
252
+ delete data.imageLink;
253
+ break;
254
+ case VIDEO:
255
+ data.video = {
256
+ previewImageUrl: imageLink,
257
+ videoId,
258
+ videoSrc: videoUrl,
259
+ videoName,
260
+ };
261
+ delete data.imageLink;
262
+ break;
263
+ default:
264
+ break;
265
+ }
266
+ facebookCreativeList.push(data);
267
+ });
268
+ creativesTemplateData = {
269
+ versions: {
270
+ base: {
271
+ content: {
272
+ FacebookAd: {...facebookCreativeList},
273
+ pageOrgUnitId: this.props.orgUnitId,
274
+ },
275
+ },
276
+ },
277
+ type: constants.FACEBOOK,
278
+ edit: true,
279
+ selectedFacebookAccount,
280
+ };
281
+ } else {
282
+ creativesTemplateData = {
283
+ selectedMarketingObjective: templateData.selectedMarketingObjective,
284
+ edit: true,
285
+ type: channel,
286
+ };
287
+ }
228
288
  break;
229
289
  }
230
290
  case constants.LINE: {
@@ -376,6 +436,50 @@ class Creatives extends React.Component {
376
436
  };
377
437
  }
378
438
  break;
439
+ case constants.FACEBOOK: {
440
+ if (template.value) {
441
+ const FacebookAd = template?.value?.versions?.base?.content?.FacebookAd;
442
+ const type = FacebookAd[0].type;
443
+ const {accountId} = this.props.Templates.selectedFacebookAccount || template.value || {};
444
+ const facebookCreativeList = [];
445
+ const fBContent = Object.values(FacebookAd);
446
+ fBContent.forEach((obj) => {
447
+ const data = cloneDeep(obj);
448
+ const {subType, linkDesc, imgSrc, webSiteLink, video} = obj;
449
+ delete data.type;
450
+ delete data.linkDesc;
451
+ delete data.webSiteLink;
452
+ data.linkDescription = linkDesc;
453
+ data.websiteLink = webSiteLink;
454
+
455
+ switch (subType) {
456
+ case IMAGE:
457
+ data.imageLink = imgSrc;
458
+ delete data.imgSrc;
459
+ break;
460
+ case VIDEO:
461
+ data.imageLink = video.previewImageUrl;
462
+ data.videoId = video.videoId;
463
+ data.videoUrl = video.videoSrc;
464
+ data.videoName = video.videoName;
465
+ delete data.video;
466
+ break;
467
+ default:
468
+ break;
469
+ }
470
+ facebookCreativeList.push(data);
471
+ });
472
+ templateData = {
473
+ fbContentType: CREATIVE,
474
+ creativeType: type,
475
+ facebookCreativeList,
476
+ channel: constants.FACEBOOK,
477
+ accountId,
478
+ selectedMarketingObjective: template.value.selectedMarketingObjective,
479
+ };
480
+ }
481
+ }
482
+ break;
379
483
  default:
380
484
  break;
381
485
  }
@@ -578,8 +682,8 @@ class Creatives extends React.Component {
578
682
  return false;
579
683
  }
580
684
  shouldShowHeader = () => {
581
- const {currentChannel} = this.state;
582
- if (currentChannel === constants.FACEBOOK) {
685
+ const {currentChannel, slidBoxContent} = this.state;
686
+ if (currentChannel.toUpperCase() === constants.FACEBOOK && slidBoxContent === 'createTemplate') {
583
687
  return false;
584
688
  }
585
689
  return true;
@@ -622,6 +726,7 @@ class Creatives extends React.Component {
622
726
  campaignSettings={this.props.Templates.campaignSettings}
623
727
  location={this.props.location}
624
728
  messageDetails={this.props.messageDetails}
729
+ showDisabledFBInfo={this.props.showDisabledFBInfo}
625
730
  getFormData={this.getFormData}
626
731
  onCallTaskSubmit={this.onCallTaskSubmit}
627
732
  onCreateNew={this.onCreateNew}
@@ -637,6 +742,7 @@ class Creatives extends React.Component {
637
742
  onEnterTemplateName={this.onEnterTemplateName}
638
743
  onRemoveTemplateName={this.onRemoveTemplateName}
639
744
  onResetStep={this.resetStep}
745
+ fbAdManager={this.state.fbAdManager}
640
746
  cap={cap}
641
747
  setIsLoadingContent={this.setIsLoadingContent}
642
748
  onMobilepushModeChange={this.onMobilepushModeChange}
@@ -661,6 +767,8 @@ class Creatives extends React.Component {
661
767
  handleClose={this.handleCloseSlideBox}
662
768
  onFTPSubmit={getCreativesData}
663
769
  editor={editor}
770
+ messageStrategy={this.props.strategy}
771
+ orgUnitId={this.props.orgUnitId}
664
772
  />
665
773
  }
666
774
  footer={this.shouldShowFooter() &&
@@ -713,6 +821,8 @@ Creatives.propTypes = {
713
821
  selectedWeChatAccount: PropTypes.object,
714
822
  Templates: PropTypes.object,
715
823
  selectedAccount: PropTypes.object,
824
+ strategy: PropTypes.string,
825
+ orgUnitId: PropTypes.number,
716
826
  };
717
827
  const mapStatesToProps = () => createStructuredSelector({
718
828
  isLoading: isLoadingSelector(),
@@ -31,8 +31,9 @@ import * as creativesContainerActions from '../CreativesContainer/actions';
31
31
  import withCreatives from '../../hoc/withCreatives';
32
32
  import { EMAIL } from '../CreativesContainer/constants';
33
33
  import { GA } from '@capillarytech/cap-ui-utils';
34
- import { TRACK_CREATE_EMAIL, TRACK_EDIT_EMAIL, BEE_PLUGIN } from '../App/constants';
34
+ import { TRACK_CREATE_EMAIL, TRACK_EDIT_EMAIL, BEE_PLUGIN, CREATE, EDIT } from '../App/constants';
35
35
  import { FONT_COLOR_05 } from '@capillarytech/cap-ui-library/styled/variables';
36
+ import { gtmPush } from '../../utils/gtmTrackers';
36
37
  const {CapCustomCardList} = CapCustomCard;
37
38
  export class Email extends React.Component { // eslint-disable-line react/prefer-stateless-function
38
39
  constructor(props) {
@@ -656,8 +657,9 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
656
657
  });
657
658
  }
658
659
  onUpdateTemplateComplete = (createResponse) => {
659
- const {isEdit, formData = {} } = this.state || {};
660
+ const {isEdit, formData = {} } = _.cloneDeep(this.state) || {};
660
661
  const base = formData.base || {};
662
+ const { activeTab } = base;
661
663
  const isDragDrop = _.get(base[base.activeTab], 'is_drag_drop');
662
664
  let editorType = '';
663
665
  if ( isDragDrop === true && this.checkBeeEditorAllowedForLibrary()) {
@@ -665,12 +667,21 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
665
667
  } else if (isDragDrop === false && !this.checkBeeEditorAllowedForLibrary()) {
666
668
  editorType = 'ckEditor';
667
669
  }
668
- GA.timeTracker.stopTimer(isEdit ? TRACK_EDIT_EMAIL : TRACK_CREATE_EMAIL, {
670
+ const timeTaken = GA.timeTracker.stopTimer(isEdit ? TRACK_EDIT_EMAIL : TRACK_CREATE_EMAIL, {
669
671
  category: 'Creatives',
670
672
  action: isEdit ? TRACK_EDIT_EMAIL : TRACK_CREATE_EMAIL,
671
673
  label: `using ${editorType}`,
672
674
  });
673
675
  if (createResponse && createResponse.templateId) {
676
+ gtmPush('creativeDetails', {
677
+ id: createResponse.templateId._id || createResponse.templateId,
678
+ name: formData['template-name'],
679
+ channel: EMAIL,
680
+ timeTaken,
681
+ content: base?.[activeTab]?.['template-content'],
682
+ mode: isEdit ? EDIT : CREATE
683
+ });
684
+
674
685
  // this.resetSchema();
675
686
  let message;
676
687
  if (isEdit) {