@capillarytech/creatives-library 3.3.0 → 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.
- package/config/app.js +2 -0
- package/containers/Cap/messsages.js +63 -0
- package/index.js +6 -0
- package/initialState.js +3 -0
- package/package.json +2 -1
- package/routes.js +6 -1
- package/services/api.js +25 -9
- package/translations/en.json +56 -0
- package/translations/zh.json +56 -0
- package/v2Components/Header/index.js +46 -0
- package/v2Components/Header/tests/index.test.js +10 -0
- package/v2Components/MarketingObjective/MarketingObjective.style.js +73 -0
- package/v2Components/MarketingObjective/index.js +107 -0
- package/v2Components/MarketingObjective/messages.js +23 -0
- package/v2Components/NavigationBar/index.js +5 -10
- package/v2Components/NavigationBar/messages.js +28 -0
- package/v2Containers/App/constants.js +29 -0
- package/v2Containers/Assets/Gallery/index.js +11 -5
- package/v2Containers/Cap/index.js +3 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +18 -0
- package/v2Containers/CreativesContainer/constants.js +1 -0
- package/v2Containers/CreativesContainer/index.js +10 -1
- package/v2Containers/Email/index.js +7 -0
- package/v2Containers/Email/messages.js +8 -0
- package/v2Containers/EmailWrapper/index.js +15 -1
- package/v2Containers/Facebook/Facebook.style.js +75 -0
- package/v2Containers/Facebook/actions.js +13 -0
- package/v2Containers/Facebook/constants.js +24 -0
- package/v2Containers/Facebook/index.js +358 -0
- package/v2Containers/Facebook/messages.js +167 -0
- package/v2Containers/Facebook/reducer.js +31 -0
- package/v2Containers/Facebook/sagas.js +41 -0
- package/v2Containers/Facebook/selectors.js +20 -0
- package/v2Containers/MobilePush/Create/index.js +8 -0
- package/v2Containers/MobilePush/Edit/index.js +8 -0
- package/v2Containers/Sms/Create/index.js +6 -1
- package/v2Containers/Sms/Edit/index.js +6 -1
- package/v2Containers/Templates/index.js +10 -4
- package/v2Containers/TemplatesV2/_templatesV2.scss +5 -0
- package/v2Containers/TemplatesV2/index.js +53 -22
- package/v2Containers/TemplatesV2/messages.js +4 -0
- package/v2Containers/WeChat/MapTemplates/index.js +9 -1
- package/v2Containers/WeChat/RichmediaTemplates/Create/index.js +9 -2
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { injectIntl, FormattedMessage } from "react-intl";
|
|
4
|
+
import {
|
|
5
|
+
CapHeading,
|
|
6
|
+
CapRadioCard,
|
|
7
|
+
CapLabel,
|
|
8
|
+
CapButton,
|
|
9
|
+
CapSpin,
|
|
10
|
+
} from '@capillarytech/cap-ui-library';
|
|
11
|
+
import messages from './messages';
|
|
12
|
+
import styles from './MarketingObjective.style';
|
|
13
|
+
import withStyles from '../../hoc/withStyles';
|
|
14
|
+
|
|
15
|
+
const renderMarketingObjectiveList = ({
|
|
16
|
+
onMarketingObjectiveChange,
|
|
17
|
+
marketingObjectiveSelectedOption,
|
|
18
|
+
defaultmarketingObjective,
|
|
19
|
+
marketingObjectiveList = [],
|
|
20
|
+
}) => {
|
|
21
|
+
const marketingList = (marketingObjective) => {
|
|
22
|
+
const { label, panes = [] } = marketingObjective;
|
|
23
|
+
const selectedPaneExists = panes.some((item) => item.value === marketingObjectiveSelectedOption);
|
|
24
|
+
const modifiedPanes = !selectedPaneExists
|
|
25
|
+
? [...panes, {
|
|
26
|
+
value: marketingObjectiveSelectedOption,
|
|
27
|
+
}]
|
|
28
|
+
: panes;
|
|
29
|
+
return (
|
|
30
|
+
<div key={label} className={selectedPaneExists ? 'selected-radio-group' : 'non-selected-radio-group'}>
|
|
31
|
+
<CapHeading type="h4" className="radio-group-heading">{label}</CapHeading>
|
|
32
|
+
<CapRadioCard
|
|
33
|
+
onChange={({ target: { value } }) => onMarketingObjectiveChange(value)}
|
|
34
|
+
panes={modifiedPanes}
|
|
35
|
+
cardWidth="324px"
|
|
36
|
+
cardHeight="auto"
|
|
37
|
+
selected={marketingObjectiveSelectedOption}
|
|
38
|
+
defaultValue={defaultmarketingObjective}
|
|
39
|
+
/>
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return marketingObjectiveList.map((marketinObjective) => marketingList(marketinObjective));
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const MarketingObjective = ({
|
|
48
|
+
onMarketingObjectiveSelect,
|
|
49
|
+
selectedMarketingObjective,
|
|
50
|
+
defaultmarketingObjective,
|
|
51
|
+
onSubmit,
|
|
52
|
+
className,
|
|
53
|
+
marketingObjectiveList,
|
|
54
|
+
}) => {
|
|
55
|
+
const [marketingObjectiveSelectedOption, onMarketingObjectiveChange] = useState(selectedMarketingObjective || defaultmarketingObjective);
|
|
56
|
+
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
[...document.querySelectorAll('.non-selected-radio-group .ant-radio-group')].forEach((node) => {
|
|
59
|
+
const paneToSelect = node.lastChild;
|
|
60
|
+
paneToSelect.click();
|
|
61
|
+
});
|
|
62
|
+
}, [marketingObjectiveSelectedOption]);
|
|
63
|
+
|
|
64
|
+
const onSubmitAction = () => {
|
|
65
|
+
onMarketingObjectiveSelect(marketingObjectiveSelectedOption);
|
|
66
|
+
onSubmit(false);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<div className={className}>
|
|
71
|
+
<>
|
|
72
|
+
<CapHeading type="h3">
|
|
73
|
+
<FormattedMessage {...messages.fbMarketingObjectiveTitle} />
|
|
74
|
+
</CapHeading>
|
|
75
|
+
<CapLabel type="label1">
|
|
76
|
+
<FormattedMessage {...messages.fbMarketingObjectiveDescription} />
|
|
77
|
+
</CapLabel>
|
|
78
|
+
</>
|
|
79
|
+
<CapSpin spinning={!marketingObjectiveList.length}>
|
|
80
|
+
{renderMarketingObjectiveList({
|
|
81
|
+
onMarketingObjectiveChange,
|
|
82
|
+
marketingObjectiveSelectedOption,
|
|
83
|
+
defaultmarketingObjective,
|
|
84
|
+
marketingObjectiveList,
|
|
85
|
+
})}
|
|
86
|
+
</CapSpin>
|
|
87
|
+
<CapButton
|
|
88
|
+
type="primary"
|
|
89
|
+
className="submit-button-section"
|
|
90
|
+
onClick={() => onSubmitAction(false)}
|
|
91
|
+
>
|
|
92
|
+
<FormattedMessage {...messages.fbMarketingObjectiveDone} />
|
|
93
|
+
</CapButton>
|
|
94
|
+
</div>
|
|
95
|
+
);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
MarketingObjective.propTypes = {
|
|
99
|
+
onMarketingObjectiveSelect: PropTypes.func,
|
|
100
|
+
selectedMarketingObjective: PropTypes.string,
|
|
101
|
+
defaultmarketingObjective: PropTypes.string,
|
|
102
|
+
onSubmit: PropTypes.func,
|
|
103
|
+
className: PropTypes.string,
|
|
104
|
+
marketingObjectiveList: PropTypes.arrayOf(PropTypes.object),
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export default injectIntl(withStyles(MarketingObjective, styles));
|
|
@@ -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
|
+
});
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import PropTypes from 'prop-types';
|
|
9
9
|
import styled from 'styled-components';
|
|
10
|
-
import { isEmpty, forEach
|
|
10
|
+
import { isEmpty, forEach } from 'lodash';
|
|
11
11
|
import { loadItem } from 'services/localStorageApi';
|
|
12
12
|
import { intlShape, injectIntl } from 'react-intl';
|
|
13
13
|
import TopBar from '../TopBar';
|
|
@@ -86,14 +86,16 @@ class NavigationBar extends React.Component {
|
|
|
86
86
|
|
|
87
87
|
getProductsList = () => {
|
|
88
88
|
const { formatMessage } = this.props.intl;
|
|
89
|
-
const { campaignOrgV2Status } = this.props;
|
|
90
89
|
const { currentOrgDetails } = this.props.userData;
|
|
91
90
|
const productsList = [];
|
|
92
91
|
if (!isEmpty(currentOrgDetails)) {
|
|
93
92
|
forEach(currentOrgDetails.module_details, (module) => {
|
|
94
93
|
if (module.name.toLowerCase() !== PRODUCT_MASTERS) {
|
|
94
|
+
const productName = module.code;
|
|
95
|
+
const intlProductName = messages[productName];
|
|
96
|
+
const moduleName = intlProductName ? formatMessage(intlProductName) : module.name.toLowerCase();
|
|
95
97
|
productsList.push({
|
|
96
|
-
value:
|
|
98
|
+
value: moduleName,
|
|
97
99
|
url: module.url,
|
|
98
100
|
key: module.code,
|
|
99
101
|
});
|
|
@@ -101,12 +103,6 @@ class NavigationBar extends React.Component {
|
|
|
101
103
|
});
|
|
102
104
|
//below changes are temporary and should be fixed once we get correct modules list
|
|
103
105
|
//changing campaigns module name to engage+
|
|
104
|
-
if ( !campaignOrgV2Status ) {
|
|
105
|
-
const campaignsModule = find(productsList, ['value', 'campaigns']);
|
|
106
|
-
if (campaignsModule) {
|
|
107
|
-
campaignsModule.value = 'Engage+';
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
106
|
//adding insights+ to module list
|
|
111
107
|
productsList.push({
|
|
112
108
|
value: formatMessage(messages.insights),
|
|
@@ -224,7 +220,6 @@ NavigationBar.propTypes = {
|
|
|
224
220
|
intl: intlShape.isRequired,
|
|
225
221
|
location: PropTypes.object,
|
|
226
222
|
type: PropTypes.string,
|
|
227
|
-
campaignOrgV2Status: PropTypes.bool,
|
|
228
223
|
};
|
|
229
224
|
|
|
230
225
|
export default injectIntl(NavigationBar);
|
|
@@ -29,4 +29,32 @@ export default defineMessages({
|
|
|
29
29
|
id: `${scope}.logout`,
|
|
30
30
|
defaultMessage: 'Logout',
|
|
31
31
|
},
|
|
32
|
+
businessProcesses: {
|
|
33
|
+
id: `${scope}.businessProcesses`,
|
|
34
|
+
defaultMessage: 'Workbench',
|
|
35
|
+
},
|
|
36
|
+
campaign: {
|
|
37
|
+
id: `${scope}.campaign`,
|
|
38
|
+
defaultMessage: 'Engage+',
|
|
39
|
+
},
|
|
40
|
+
wecrm: {
|
|
41
|
+
id: `${scope}.wecrm`,
|
|
42
|
+
defaultMessage: 'Wecrm',
|
|
43
|
+
},
|
|
44
|
+
loyaltyProgram: {
|
|
45
|
+
id: `${scope}.loyaltyProgram`,
|
|
46
|
+
defaultMessage: 'Loyalty+',
|
|
47
|
+
},
|
|
48
|
+
storePerformance: {
|
|
49
|
+
id: `${scope}.storePerformance`,
|
|
50
|
+
defaultMessage: 'Store Performance',
|
|
51
|
+
},
|
|
52
|
+
memberCare: {
|
|
53
|
+
id: `${scope}.memberCare`,
|
|
54
|
+
defaultMessage: 'Member Care',
|
|
55
|
+
},
|
|
56
|
+
storeCare: {
|
|
57
|
+
id: `${scope}.storeCare`,
|
|
58
|
+
defaultMessage: 'Store Care',
|
|
59
|
+
},
|
|
32
60
|
});
|
|
@@ -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
|
+
};
|
|
@@ -120,15 +120,18 @@ export class Gallery extends React.Component { // eslint-disable-line react/pref
|
|
|
120
120
|
getAllAssets = ({params, getNextPage, resetPage}, isReRender = false) => {
|
|
121
121
|
let queryParams = params;
|
|
122
122
|
let page = this.state.page;
|
|
123
|
+
let shouldFetchGalleryAssets = false;
|
|
123
124
|
if (!this.props.Gallery.fetchingAllAssets && ((resetPage || (page === 1 && this.state.totalCount === 0) || page <= (this.state.totalCount / this.state.perPageLimit)) || isReRender )) {
|
|
124
125
|
if (getNextPage) {
|
|
125
126
|
page += 1;
|
|
127
|
+
shouldFetchGalleryAssets = true;
|
|
126
128
|
}
|
|
127
129
|
|
|
128
130
|
let totalCount = this.state.totalCount;
|
|
129
131
|
if (resetPage) {
|
|
130
132
|
page = 1;
|
|
131
133
|
totalCount = 0;
|
|
134
|
+
shouldFetchGalleryAssets = true;
|
|
132
135
|
}
|
|
133
136
|
if ((!params || _.isEmpty(params))) {
|
|
134
137
|
queryParams = {
|
|
@@ -137,12 +140,15 @@ export class Gallery extends React.Component { // eslint-disable-line react/pref
|
|
|
137
140
|
}
|
|
138
141
|
if (this.state.searchText !== "") {
|
|
139
142
|
queryParams = {...queryParams, name: this.state.searchText};
|
|
143
|
+
shouldFetchGalleryAssets = true;
|
|
144
|
+
}
|
|
145
|
+
if (!this.props.Gallery.fetchingAllAssets && (_.isEmpty(this.props.Gallery.assetList) || shouldFetchGalleryAssets)) {
|
|
146
|
+
this.setState({page, totalCount}, () => {
|
|
147
|
+
queryParams.page = page;
|
|
148
|
+
queryParams.perPage = this.state.perPageLimit;
|
|
149
|
+
this.props.actions.getAllAssets('image', queryParams);
|
|
150
|
+
});
|
|
140
151
|
}
|
|
141
|
-
this.setState({page, totalCount}, () => {
|
|
142
|
-
queryParams.page = page;
|
|
143
|
-
queryParams.perPage = this.state.perPageLimit;
|
|
144
|
-
this.props.actions.getAllAssets('image', queryParams);
|
|
145
|
-
});
|
|
146
152
|
}
|
|
147
153
|
};
|
|
148
154
|
handleGallery = (e) => {
|
|
@@ -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;
|
|
@@ -286,4 +286,12 @@ export default defineMessages({
|
|
|
286
286
|
id: 'creatives.containersV2.Email.h3imageSelection',
|
|
287
287
|
defaultMessage: 'Image selection',
|
|
288
288
|
},
|
|
289
|
+
"English": {
|
|
290
|
+
id: 'creatives.containersV2.Email.english',
|
|
291
|
+
defaultMessage: 'English',
|
|
292
|
+
},
|
|
293
|
+
"Add label": {
|
|
294
|
+
id: 'creatives.containersV2.Email.addLabel',
|
|
295
|
+
defaultMessage: 'Add label',
|
|
296
|
+
},
|
|
289
297
|
});
|
|
@@ -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,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';
|