@capillarytech/creatives-library 3.3.1 → 3.3.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 (39) hide show
  1. package/config/app.js +2 -0
  2. package/containers/Cap/messsages.js +63 -0
  3. package/index.js +6 -0
  4. package/initialState.js +3 -0
  5. package/package.json +2 -1
  6. package/routes.js +6 -1
  7. package/services/api.js +25 -9
  8. package/translations/en.json +47 -0
  9. package/translations/zh.json +47 -0
  10. package/v2Components/Header/index.js +46 -0
  11. package/v2Components/Header/tests/index.test.js +10 -0
  12. package/v2Components/MarketingObjective/MarketingObjective.style.js +73 -0
  13. package/v2Components/MarketingObjective/index.js +107 -0
  14. package/v2Components/MarketingObjective/messages.js +23 -0
  15. package/v2Containers/App/constants.js +29 -0
  16. package/v2Containers/Cap/index.js +3 -0
  17. package/v2Containers/CreativesContainer/SlideBoxContent.js +18 -0
  18. package/v2Containers/CreativesContainer/constants.js +1 -0
  19. package/v2Containers/CreativesContainer/index.js +10 -1
  20. package/v2Containers/Email/index.js +7 -0
  21. package/v2Containers/EmailWrapper/index.js +15 -1
  22. package/v2Containers/Facebook/Facebook.style.js +75 -0
  23. package/v2Containers/Facebook/actions.js +13 -0
  24. package/v2Containers/Facebook/constants.js +24 -0
  25. package/v2Containers/Facebook/index.js +358 -0
  26. package/v2Containers/Facebook/messages.js +167 -0
  27. package/v2Containers/Facebook/reducer.js +31 -0
  28. package/v2Containers/Facebook/sagas.js +41 -0
  29. package/v2Containers/Facebook/selectors.js +20 -0
  30. package/v2Containers/MobilePush/Create/index.js +8 -0
  31. package/v2Containers/MobilePush/Edit/index.js +8 -0
  32. package/v2Containers/Sms/Create/index.js +6 -1
  33. package/v2Containers/Sms/Edit/index.js +6 -1
  34. package/v2Containers/Templates/index.js +9 -3
  35. package/v2Containers/TemplatesV2/_templatesV2.scss +5 -0
  36. package/v2Containers/TemplatesV2/index.js +53 -22
  37. package/v2Containers/TemplatesV2/messages.js +4 -0
  38. package/v2Containers/WeChat/MapTemplates/index.js +9 -1
  39. package/v2Containers/WeChat/RichmediaTemplates/Create/index.js +9 -2
@@ -0,0 +1,23 @@
1
+ /*
2
+ * Marketing Objective Messages
3
+ *
4
+ * This contains all the text for the Facebook component.
5
+ */
6
+ import { defineMessages } from 'react-intl';
7
+
8
+ const messagePrefix = 'creatives.containersV2.FacebookMarketingObjective';
9
+
10
+ export default defineMessages({
11
+ fbMarketingObjectiveTitle: {
12
+ id: `${messagePrefix}.fbMarketingObjectiveTitle`,
13
+ defaultMessage: 'Facebook Marketing Objective',
14
+ },
15
+ fbMarketingObjectiveDescription: {
16
+ id: `${messagePrefix}.fbMarketingObjectiveDescription`,
17
+ defaultMessage: 'Objectives help break reporting into a more granular level',
18
+ },
19
+ fbMarketingObjectiveDone: {
20
+ id: `${messagePrefix}.fbMarketingObjectiveDone`,
21
+ defaultMessage: 'Done',
22
+ },
23
+ });
@@ -12,3 +12,32 @@ export const getTopbarMenuDataValue = () => ([
12
12
  { label: <FormattedMessage {...globalMessages.incentive} />, link: '/coupons/ui/', key: 'incentive' },
13
13
  { label: <FormattedMessage {...globalMessages.creatives} />, link: '/creatives/ui/v2', key: 'creatives' },
14
14
  ]);
15
+
16
+ export const TRACK_CREATE_SMS = 'createSms';
17
+ export const TRACK_CREATE_EMAIL = 'createEmail';
18
+ export const TRACK_CREATE_MPUSH = 'createMpush';
19
+ export const TRACK_CREATE_WECHAT = 'createWeChat';
20
+ export const TRACK_CREATE_IMAGE = 'createImage';
21
+
22
+
23
+ export const TRACK_EDIT_SMS = 'editSms';
24
+ export const TRACK_EDIT_EMAIL = 'editEmail';
25
+ export const TRACK_EDIT_MPUSH = 'editMpush';
26
+ export const TRACK_EDIT_WECHAT = 'editWeChat';
27
+ export const TRACK_EDIT_IMAGE = 'editImage';
28
+
29
+ export const CHANNEL_CREATE_TRACK_MAPPING = {
30
+ sms: TRACK_CREATE_SMS,
31
+ email: TRACK_CREATE_EMAIL,
32
+ mobilepush: TRACK_CREATE_MPUSH,
33
+ wechat: TRACK_CREATE_WECHAT,
34
+ gallery: TRACK_CREATE_IMAGE,
35
+ };
36
+
37
+ export const CHANNEL_EDIT_TRACK_MAPPING = {
38
+ sms: TRACK_EDIT_SMS,
39
+ email: TRACK_EDIT_EMAIL,
40
+ mobilepush: TRACK_EDIT_MPUSH,
41
+ wechat: TRACK_EDIT_WECHAT,
42
+ gallery: TRACK_EDIT_IMAGE,
43
+ };
@@ -9,6 +9,7 @@ import { createStructuredSelector } from 'reselect';
9
9
  import _ from 'lodash';
10
10
  import moment from 'moment';
11
11
  // import 'moment/locale/zh-cn';
12
+ import { GA } from '@capillarytech/cap-ui-utils';
12
13
  import { injectIntl, FormattedMessage } from 'react-intl';
13
14
  import messages from './messages';
14
15
  import { makeSelectAuthenticated, makeSelectUser } from './selectors';
@@ -33,6 +34,8 @@ const CapWrapper = styled.div`
33
34
  flex-direction: column;
34
35
  `;
35
36
 
37
+ GA.initialize({ accessKey: 'UA-152081629-1' });
38
+
36
39
  export class Cap extends React.Component { // eslint-disable-line react/prefer-stateless-function
37
40
 
38
41
  constructor(props) {
@@ -12,6 +12,7 @@ import MobilepushWrapper from '../MobilepushWrapper';
12
12
  import EmailPreviewV2 from '../../v2Components/EmailPreviewV2';
13
13
  import MobilePushPreview from '../../v2Components/MobilePushPreviewV2';
14
14
  import WechatWrapper from '../WeChat/Wrapper';
15
+ import Facebook from '../Facebook';
15
16
  import { RICH_MEDIA, MAP_TEMPLATE, CREATE } from '../WeChat/Wrapper/constants';
16
17
  import CallTask from '../CallTask';
17
18
  import MobliPushEdit from '../MobilePush/Edit';
@@ -30,6 +31,7 @@ function getWechatTemplateType(mode, templateData, weChatTemplateType = '') {
30
31
  }
31
32
  return weChatTemplateType;
32
33
  }
34
+
33
35
  function SlideBoxContent(props) {
34
36
  const {
35
37
  slidBoxContent,
@@ -67,6 +69,7 @@ function SlideBoxContent(props) {
67
69
  selectedWeChatAccount,
68
70
  weChatMaptemplateStep,
69
71
  onWeChatMaptemplateStepChange,
72
+ onFacebookSubmit,
70
73
  } = props;
71
74
  const type = messageDetails.type.toLowerCase(); // type is context in get tags values : outbound | dvs | referral | loyalty | coupons
72
75
  const query = { type: !isFullMode && 'embedded', module: isFullMode ? 'default' : 'library', isEditFromCampaigns: (templateData || {}).isEditFromCampaigns};
@@ -87,6 +90,7 @@ function SlideBoxContent(props) {
87
90
  let isMpushPreview = false;
88
91
  let isEditCallTask = false;
89
92
  let isEditMPush = false;
93
+ let isEditFacebook = false;
90
94
  const isEmailCreate = slidBoxContent === 'createTemplate' && channel === constants.EMAIL;
91
95
  if (templateData && channel) {
92
96
  channel = templateData.type;// for edit mode with template data
@@ -95,6 +99,7 @@ function SlideBoxContent(props) {
95
99
  isEditMPush = slidBoxContent === 'editTemplate' && channel === constants.MOBILE_PUSH;
96
100
  isEditEmailWithId = slidBoxContent === 'editTemplate' && channel === constants.EMAIL && templateData._id;
97
101
  isEmailEditWithContent = slidBoxContent === 'editTemplate' && channel === constants.EMAIL && !templateData._id;
102
+ isEditFacebook = slidBoxContent === 'editTemplate' && channel === constants.FACEBOOK;
98
103
  isPreview = slidBoxContent === 'preview' && channel === constants.SMS;
99
104
  isEmailPreview = slidBoxContent === 'preview' && channel === constants.EMAIL;
100
105
  isMpushPreview = slidBoxContent === 'preview' && channel === constants.MOBILE_PUSH;
@@ -116,6 +121,8 @@ function SlideBoxContent(props) {
116
121
  channelsToHide={channelsToHide}
117
122
  forwardedTags={forwardedTags}
118
123
  channelsToDisable={channelsToDisable}
124
+ messageDetails={messageDetails}
125
+ onFacebookSubmit={onFacebookSubmit}
119
126
  />
120
127
  )}
121
128
  {isPreview && (
@@ -302,6 +309,16 @@ function SlideBoxContent(props) {
302
309
  onValidationFail={onValidationFail}
303
310
  selectedOfferDetails={selectedOfferDetails}/>
304
311
  }
312
+ {
313
+ isEditFacebook && (
314
+ <Facebook
315
+ templateData={templateData}
316
+ messageDetails={messageDetails}
317
+ cap={cap}
318
+ onFacebookSubmit={onFacebookSubmit}
319
+ />
320
+ )
321
+ }
305
322
  </CreativesWrapper>
306
323
  );
307
324
  }
@@ -341,5 +358,6 @@ SlideBoxContent.propTypes = {
341
358
  selectedWeChatAccount: PropTypes.object,
342
359
  onWeChatMaptemplateStepChange: PropTypes.func,
343
360
  weChatMaptemplateStep: PropTypes.string,
361
+ onFacebookSubmit: PropTypes.func,
344
362
  };
345
363
  export default SlideBoxContent;
@@ -12,5 +12,6 @@ export const LINE = "LINE";
12
12
  export const CALL_TASK = "CALL_TASK";
13
13
  export const MOBILE_PUSH = "MOBILEPUSH";
14
14
  export const WECHAT = "WECHAT";
15
+ export const FACEBOOK = "FACEBOOK";
15
16
  export const SHOW_CONTANER_LOADER = "app/CreativesContainer/SHOW_CONTANER_LOADER";
16
17
  export const HIDE_CONTAINER_LOADER = "app/CreativesContainer/HIDE_CONTAINER_LOADER";
@@ -207,6 +207,14 @@ class Creatives extends React.Component {
207
207
  };
208
208
  break;
209
209
  }
210
+ case constants.FACEBOOK: {
211
+ creativesTemplateData = {
212
+ selectedMarketingObjective: templateData.selectedMarketingObjective,
213
+ edit: true,
214
+ type: channel,
215
+ };
216
+ break;
217
+ }
210
218
  default:
211
219
  break;
212
220
  }
@@ -465,7 +473,7 @@ class Creatives extends React.Component {
465
473
  }
466
474
  render() {
467
475
  const {slidBoxContent, isGetFormData, showSlideBox, templateData, currentChannel, emailCreateMode, templateStep, isLoadingContent, mobilePushCreateMode, isDiscardMessage, weChatTemplateType, weChatMaptemplateStep} = this.state;
468
- const {isFullMode, creativesMode, cap, isUploading, channelsToHide, selectedWeChatAccount, forwardedTags, channelsToDisable, selectedOfferDetails} = this.props;
476
+ const {isFullMode, creativesMode, cap, isUploading, channelsToHide, selectedWeChatAccount, forwardedTags, channelsToDisable, selectedOfferDetails, getCreativesData} = this.props;
469
477
  const mapTemplateCreate = slidBoxContent === 'createTemplate' && weChatTemplateType === MAP_TEMPLATE && templateStep !== 'modeSelection';
470
478
  /* TODO: Instead of passing down same props separately to each component down, write common function to these props and pass it accordingly */
471
479
  return (
@@ -530,6 +538,7 @@ class Creatives extends React.Component {
530
538
  weChatMaptemplateStep={weChatMaptemplateStep}
531
539
  selectedWeChatAccount={selectedWeChatAccount}
532
540
  onWeChatMaptemplateStepChange={this.onWeChatMaptemplateStepChange}
541
+ onFacebookSubmit={getCreativesData}
533
542
  />
534
543
  }
535
544
  footer={this.shouldShowFooter() &&
@@ -29,6 +29,8 @@ import EmailPreview from '../../v2Components/EmailPreview';
29
29
  import Pagination from '../../v2Components/Pagination';
30
30
  import * as creativesContainerActions from '../CreativesContainer/actions';
31
31
  import withCreatives from '../../hoc/withCreatives';
32
+ import { GA } from '@capillarytech/cap-ui-utils';
33
+ import { TRACK_CREATE_EMAIL, TRACK_EDIT_EMAIL } from '../App/constants'
32
34
 
33
35
  const {CapCustomCardList} = CapCustomCard;
34
36
  export class Email extends React.Component { // eslint-disable-line react/prefer-stateless-function
@@ -620,6 +622,11 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
620
622
  });
621
623
  }
622
624
  onUpdateTemplateComplete = (createResponse) => {
625
+ GA.timeTracker.stopTimer(this.state.isEdit ? TRACK_EDIT_EMAIL : TRACK_CREATE_EMAIL, {
626
+ category: 'Creatives',
627
+ action: this.state.isEdit ? 'Create' : 'Edit',
628
+ label: 'using editor',
629
+ });
623
630
  if (createResponse && createResponse.templateId) {
624
631
  // this.resetSchema();
625
632
  let message;
@@ -7,6 +7,7 @@ import PropTypes from 'prop-types';
7
7
  import React from 'react';
8
8
  import { connect } from 'react-redux';
9
9
  import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
10
+ import { GA } from '@capillarytech/cap-ui-utils';
10
11
  import { createStructuredSelector } from 'reselect';
11
12
  import { bindActionCreators } from 'redux';
12
13
  import _ from 'lodash';
@@ -19,7 +20,10 @@ import * as templatesActionsCreators from '../Templates/actions';
19
20
  import Email from '../Email';
20
21
  import CmsTemplatesComponent from '../../v2Components/CmsTemplatesComponent';
21
22
  import messages from './messages';
23
+ import { CHANNEL_CREATE_TRACK_MAPPING } from '../App/constants'
24
+
22
25
  const CapRadioCardWithLabel = ComponentWithLabelHOC(CapRadioCard);
26
+ const { timeTracker } = GA;
23
27
  const CardContainer = styled.div`
24
28
  margin-top: 16px;
25
29
  .ant-radio-group{
@@ -106,7 +110,16 @@ export class EmailWrapper extends React.Component { // eslint-disable-line react
106
110
  };
107
111
  CapNotification.error(message);
108
112
  }
113
+ stopTimerGA=()=>{
114
+ // stop timer
115
+ timeTracker.stopTimer(CHANNEL_CREATE_TRACK_MAPPING['email'], {
116
+ category: 'Creatives',
117
+ action: 'Create',
118
+ label: 'uploadZip',
119
+ });
120
+ }
109
121
  handleFileUpload = (file) => {
122
+
110
123
  const { templatesActions, intl, showNextStep, isUploading } = this.props;
111
124
  if (!isUploading) {
112
125
  const fileExtension = file.name.split('.').pop();
@@ -116,7 +129,9 @@ export class EmailWrapper extends React.Component { // eslint-disable-line react
116
129
  if (supportedZipFormats.indexOf(fileExtension.toLowerCase()) !== -1) {
117
130
  templatesActions.handleZipUpload(file.originFileObj, () => { //handle upload success
118
131
  this.setState({ modeContent: { file } }, showNextStep);
132
+ stopTimerGA();
119
133
  }, this.handleZipUploadError);
134
+
120
135
  } else if (fileExtension === 'html' || fileExtension === 'htm') {
121
136
  const reader = new FileReader();
122
137
  reader.onload = () => {
@@ -124,7 +139,6 @@ export class EmailWrapper extends React.Component { // eslint-disable-line react
124
139
  this.setState({ modeContent: { file } }, () => {
125
140
  templatesActions.handleHtmlUpload(text);
126
141
  });
127
-
128
142
  // showNextStep();
129
143
  };
130
144
  reader.readAsText(file.originFileObj);
@@ -0,0 +1,75 @@
1
+ import { css } from 'styled-components';
2
+ import {
3
+ CAP_SPACE_44,
4
+ CAP_SPACE_28,
5
+ CAP_SPACE_20,
6
+ CAP_SPACE_12,
7
+ CAP_SPACE_08,
8
+ CAP_G07,
9
+ CAP_G12,
10
+ CAP_G06,
11
+ FONT_COLOR_05,
12
+ } from '@capillarytech/cap-ui-library/styled/variables';
13
+
14
+ export default css`
15
+ margin-left: ${CAP_SPACE_44};
16
+
17
+ .is-scrollable-section {
18
+ height: calc(100vh - 220px);
19
+ overflow-y: auto;
20
+ }
21
+
22
+ .account-details-wrapper {
23
+ border-bottom: 1px solid ${CAP_G12};
24
+ margin-bottom: ${CAP_SPACE_20};
25
+ }
26
+
27
+ .account-name-section {
28
+ margin-bottom: ${CAP_SPACE_28};
29
+ }
30
+
31
+ .account-section-container {
32
+ margin-bottom: ${CAP_SPACE_20};
33
+ max-width: 564px;
34
+ }
35
+
36
+ .ad-section {
37
+ margin-bottom: ${CAP_SPACE_44};
38
+ }
39
+
40
+ .dynamic-content-section {
41
+ max-width: 140px;
42
+
43
+ .facebook-dynamic-content {
44
+ color: ${CAP_G06};
45
+ }
46
+ }
47
+
48
+ .parameter-list {
49
+ padding: ${CAP_SPACE_08} ${CAP_SPACE_28};
50
+
51
+ .parameter-list-item {
52
+ list-style: none;
53
+ margin-bottom: ${CAP_SPACE_28};
54
+
55
+ .parameter-index {
56
+ float: left;
57
+ margin-right: ${CAP_SPACE_12};
58
+ background: ${CAP_G07};
59
+ padding: 6px 10px;
60
+ border-radius: 50%;
61
+ }
62
+ }
63
+ }
64
+
65
+ .cap-button-v2 {
66
+ &.marketingObjective-change-button {
67
+ color: ${FONT_COLOR_05};
68
+ height: ${CAP_SPACE_20};
69
+ }
70
+ }
71
+ `;
72
+
73
+ export const CampaignDetailCapColumn = css`
74
+ margin-bottom: ${CAP_SPACE_20};
75
+ `;
@@ -0,0 +1,13 @@
1
+ /*
2
+ *
3
+ * Facebook actions
4
+ *
5
+ */
6
+
7
+ import {
8
+ GET_MARKETING_OBJECTIVES,
9
+ } from './constants';
10
+
11
+ export const getMarketingObjectives = () => ({
12
+ type: GET_MARKETING_OBJECTIVES,
13
+ });
@@ -0,0 +1,24 @@
1
+ /*
2
+ *
3
+ * Facebook constants
4
+ *
5
+ */
6
+
7
+ const prefix = 'app/Facebook';
8
+
9
+ export const GET_MARKETING_OBJECTIVES = `${prefix}/GET_MARKETING_OBJECTIVES`;
10
+ export const SET_MARKETING_OBJECTIVES_SUCCESS = `${prefix}/SET_MARKETING_OBJECTIVES_SUCCESS`;
11
+ export const SET_MARKETING_OBJECTIVES_FAILURE = `${prefix}/SET_MARKETING_OBJECTIVES_FAILURE`;
12
+
13
+ // marketing objectives constants
14
+
15
+ export const VALUE_APP_INSTALLS = 'VALUE_APP_INSTALLS';
16
+ export const VALUE_BRAND_AWARENESS = 'VALUE_BRAND_AWARENESS';
17
+ export const VALUE_CONVERSIONS = 'VALUE_CONVERSIONS';
18
+ export const VALUE_LEAD_GENERATION = 'VALUE_LEAD_GENERATION';
19
+ export const VALUE_LOCAL_AWARENESS = 'VALUE_LOCAL_AWARENESS';
20
+ export const VALUE_MESSAGES = 'VALUE_MESSAGES';
21
+ export const VALUE_PRODUCT_CATALOG_SALES = 'VALUE_PRODUCT_CATALOG_SALES';
22
+ export const VALUE_REACH = 'VALUE_REACH';
23
+ export const VALUE_VIDEO_VIEWS = 'VALUE_VIDEO_VIEWS';
24
+ export const VALUE_LINK_CLICKS = 'VALUE_LINK_CLICKS';