@capillarytech/creatives-library 2.0.47 → 2.0.48

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.
@@ -98,6 +98,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
98
98
 
99
99
  componentWillReceiveProps(nextProps) {
100
100
  const type = this.props.location.query.type;
101
+ const isLibraryModule = this.props.location.query.module === "library";
101
102
  if (this.state.usingTabContainer && nextProps.tabCount !== this.props.tabCount) {
102
103
  this.setState({tabCount: nextProps.tabCount});
103
104
  }
@@ -116,7 +117,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
116
117
  // }
117
118
  if (nextProps.isEdit) {
118
119
  if (!_.isEqual(nextProps.formData, this.state.formData) && !_.isEmpty(nextProps.formData)) {
119
- if (type === 'embedded') { //TODO: has to be checked and changed.
120
+ if (type === 'embedded' && !isLibraryModule) { //TODO: has to be checked and changed.
120
121
  this.setState({checkValidation: true, formData: nextProps.formData}, () => {
121
122
  this.validateForm();
122
123
  });
@@ -38,7 +38,7 @@ function SlideBoxContent(props) {
38
38
  isFullMode,
39
39
  } = props;
40
40
  const type = messageDetails.type.toLowerCase(); // type is context in get tags values : outbound | dvs | referral | loyalty | coupons
41
- const query = { type: !isFullMode && 'embedded', module: isFullMode ? 'defualt' : 'library'};
41
+ const query = { type: !isFullMode && 'embedded', module: isFullMode ? 'defualt' : 'library', isLanguageSupport: true};
42
42
  const creativesLocationProps = {
43
43
  pathname: `/sms/edit`,
44
44
  query,
@@ -153,15 +153,14 @@ class Creatives extends React.Component {
153
153
  }
154
154
  };
155
155
  resetStep = () => {
156
- this.setState(prevState => {
156
+ this.setState((prevState) => {
157
157
  let newState = {
158
158
  templateStep: 1,
159
- }
160
-
159
+ };
161
160
  if (prevState.currentChannel.toUpperCase() === constants.EMAIL) {
162
- newState= { ...newState, emailCreateMode: null };
161
+ newState = { ...newState, emailCreateMode: null };
163
162
  }
164
- return newState;
163
+ return newState;
165
164
  });
166
165
  }
167
166
  handleCloseSlideBox = () => {
@@ -198,10 +197,10 @@ class Creatives extends React.Component {
198
197
  const isCreate = (slidBoxContent === 'editTemplate' || slidBoxContent === 'createTemplate') && !isEmailCreate;
199
198
  return isCreate;
200
199
  }
201
- shouldShowContinueFooter = () => { // only for email for now, has to be modified according to channel
200
+ shouldShowContinueFooter = () => { // only for email for now, has to be modified according to channel
202
201
  const {slidBoxContent, templateStep, currentChannel, emailCreateMode} = this.state;
203
202
  let isShowContinueFooter = false;
204
- if (this.props.EmailLayout !== null) {
203
+ if ((emailCreateMode === "upload" && !isEmpty(this.props.EmailLayout)) || emailCreateMode === "editor") {
205
204
  const currentStep = this.creativesTemplateSteps[templateStep];
206
205
  let isEmailCreate = slidBoxContent === 'createTemplate';
207
206
  isEmailCreate = currentChannel.toUpperCase() === constants.EMAIL && ((emailCreateMode === "upload" && currentStep !== 'createTemplateContent') || ( emailCreateMode === "editor" && currentStep !== 'createTemplateContent' && currentStep !== "templateSelection"));
@@ -2556,6 +2556,7 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
2556
2556
  <Col>
2557
2557
  { !_.isEmpty(schema) && (this.state.formData[0] || this.state.formData["0"]) ?
2558
2558
  <FormBuilder
2559
+ isFullMode={this.props.isFullMode}
2559
2560
  schema={schema}
2560
2561
  onSubmit={this.saveFormData}
2561
2562
  onChange={this.onFormDataChange}
@@ -10,9 +10,9 @@ import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
10
10
  import { createStructuredSelector } from 'reselect';
11
11
  import { bindActionCreators } from 'redux';
12
12
  import _ from 'lodash';
13
- import { CapRadioCard, CapHeader, CapNotification, CapInput} from '@capillarytech/cap-ui-library';
13
+ import { CapRadioCard, CapHeader, CapNotification, CapInput, CapUploader, CapSpin, CapButton} from '@capillarytech/cap-ui-library';
14
14
  import { UserIsAuthenticated } from '../../utils/authWrapper';
15
- import {selectEmailLayout, selectCmsTemplates, selectEdmEditor} from '../Templates/selectors';
15
+ import {selectEmailLayout, selectCmsTemplates, selectEdmEditor, uploadSelector} from '../Templates/selectors';
16
16
  import * as templatesActionsCreators from '../Templates/actions';
17
17
  import Email from '../Email';
18
18
  import CmsTemplatesComponent from '../../components/CmsTemplatesComponent';
@@ -38,9 +38,9 @@ export class EmailWrapper extends React.Component { // eslint-disable-line react
38
38
  title: <FormattedMessage {...messages.zipUpload}/>,
39
39
  content: <FormattedMessage {...messages.zipUploadDesc}/>,
40
40
  value: 'upload',
41
- onClick: () => {
42
- this.emailUploader.current.click();
43
- },
41
+ // onClick: () => {
42
+ // this.emailUploader.current.click();
43
+ // },
44
44
  },
45
45
  {
46
46
  title: <FormattedMessage {...messages.useEditor}/>,
@@ -63,8 +63,6 @@ export class EmailWrapper extends React.Component { // eslint-disable-line react
63
63
  } else if (step === "createTemplateContent" && !this.state.selectedCreateMode) {
64
64
  if (emailCreateMode === 'upload' && !_.isEmpty(EmailLayout)) {
65
65
  this.setCreateMode('upload');
66
-
67
- //this.handleFileUpload(modeContent.e, modeContent.files);
68
66
  } else if (emailCreateMode === "editor" && _.isEmpty(SelectedEdmDefaultTemplate)) {
69
67
  this.handleEdmDefaultTemplateSelection(modeContent.id);
70
68
  }
@@ -94,29 +92,28 @@ export class EmailWrapper extends React.Component { // eslint-disable-line react
94
92
  };
95
93
  CapNotification.error(message);
96
94
  }
97
- handleFileUpload = (e, files) => {
95
+ handleFileUpload = (file) => {
98
96
  const { templatesActions, intl, showNextStep } = this.props;
99
- if (files.length === 0) {
100
- return;
101
- }
102
- //this.setCreateMode('upload');
103
- const fileExtension = files[0].name.split('.').pop();
97
+ const validUpload = false;
98
+ const fileExtension = file.name.split('.').pop();
104
99
  const supportedZipFormats = ['zip'];
105
- //TODO: has to be changed based on props.
106
100
 
107
101
 
108
102
  if (supportedZipFormats.indexOf(fileExtension.toLowerCase()) !== -1) {
109
- templatesActions.handleZipUpload(files[0], showNextStep, this.handleZipUploadError);
110
- this.emailUploader.current.value = "";
103
+ templatesActions.handleZipUpload(file.originFileObj, () => { //handle upload success
104
+ this.setState({modeContent: { file}}, showNextStep);
105
+ }, this.handleZipUploadError);
111
106
  } else if (fileExtension === 'html' || fileExtension === 'htm') {
112
107
  const reader = new FileReader();
113
108
  reader.onload = () => {
114
109
  const text = reader.result;
115
- templatesActions.handleHtmlUpload(text);
116
- showNextStep();
117
- this.emailUploader.current.value = "";
110
+ this.setState({modeContent: { file}}, () => {
111
+ templatesActions.handleHtmlUpload(text);
112
+ });
113
+
114
+ // showNextStep();
118
115
  };
119
- reader.readAsText(files[0]);
116
+ reader.readAsText(file.originFileObj);
120
117
  } else {
121
118
  const message = {
122
119
  message: intl.formatMessage(messages.invalidUploadFileError),
@@ -124,6 +121,7 @@ export class EmailWrapper extends React.Component { // eslint-disable-line react
124
121
  };
125
122
  CapNotification.error(message);
126
123
  }
124
+ return validUpload;
127
125
  };
128
126
 
129
127
  handleEdmDefaultTemplateSelection = (id) => {
@@ -134,69 +132,69 @@ export class EmailWrapper extends React.Component { // eslint-disable-line react
134
132
  this.setState({
135
133
  selectedCreateMode: 'editor'});
136
134
  };
137
- useFileUpload = (e, {files}) => {
138
- this.handleFileUpload(e, files);
139
- this.setState({modeContent: {e, files}});
135
+ useFileUpload = ({file}) => {
136
+ this.setState({modeContent: {}}, () => {
137
+ this.handleFileUpload(file);
138
+ });
140
139
  }
141
140
  useEditor = (id) => {
142
141
  this.setState({modeContent: {id}}, this.props.showNextStep);
143
142
  }
144
- resetEmailOptions = (ev) => {
145
- ev.preventDefault();
146
- if (this.props.emailCreateMode === "upload" && _.isEmpty(this.state.modeContent.files)) {
147
- this.props.onEmailModeChange( "" );
148
- }
149
- }
143
+
150
144
  isShowEmailCreate = () => !_.isEmpty(this.state.selectedCreateMode) && (!_.isEmpty(this.props.EmailLayout) || this.props.SelectedEdmDefaultTemplate)
151
145
  render() {
152
- const {emailCreateMode, isGetFormData, getFormdata, type, CmsTemplates, step, cap, isFullMode} = this.props;
153
- const {templateName} = this.state;
146
+ const {emailCreateMode, isGetFormData, getFormdata, type, CmsTemplates, step, cap, isFullMode, EmailLayout} = this.props;
147
+ const {templateName, modeContent} = this.state;
154
148
  const isShowEmailCreate = this.isShowEmailCreate();
155
149
  return (
156
150
  <div>
157
- <input
158
- type="file"
159
- key="upload-email-template"
160
- id="upload-email-template"
161
- ref={this.emailUploader}
162
- style={{ display: 'none'}}
163
- accept=".zip, .html, .htm"
164
- onChange={(event) => this.useFileUpload(event, {files: event.target.files})}
165
- />
166
-
167
- {step === "modeSelection" || (step === "templateSelection" && emailCreateMode === "upload") ?
168
- <div>
169
- {isFullMode && <CapInput
170
- label={<FormattedMessage {...messages.creativeName}/>}
171
- onChange={this.onTemplateNameChange}
172
- value={templateName}
173
- labelPosition="top"/>}
174
- <CapHeader size="small" title={<FormattedMessage {...messages.createMode}/>}/>
175
- <CapRadioCard
176
- panes={this.modes}
177
- onChange={this.onChange}
178
- selected={emailCreateMode}
179
- />
180
- </div>
151
+ <CapSpin spinning={emailCreateMode === "upload" ? this.props.isUploading : false} >
152
+ {step === "modeSelection" || (step === "templateSelection" && emailCreateMode === "upload") ?
153
+ <div>
154
+ {isFullMode &&
155
+ <CapInput
156
+ label={<FormattedMessage {...messages.creativeName}/>}
157
+ onChange={this.onTemplateNameChange}
158
+ value={templateName}
159
+ labelPosition="top"/>
160
+ }
161
+ <CapHeader size="small" title={<FormattedMessage {...messages.createMode}/>}/>
162
+ <CapRadioCard
163
+ panes={this.modes}
164
+ onChange={this.onChange}
165
+ selected={emailCreateMode}
166
+ />
167
+ <div>
168
+ {emailCreateMode === "upload" &&
169
+ <div>
170
+ <CapUploader onChange={this.useFileUpload} accept=".zip, .html, .htm" showUploadList={false}>
171
+ <CapButton>Upload</CapButton>
172
+ </CapUploader>
173
+ {!_.isEmpty(EmailLayout) &&
174
+ <div>{_.get(modeContent, "file.name")}</div>
175
+ }
176
+ </div>
177
+ }
178
+ </div>
179
+ </div>
181
180
  :
182
- <div>
183
- {isShowEmailCreate && <Email
184
- key="email-create-template"
185
- location={this.state.routeParams}
186
- route={{ name: 'email' }}
187
- params={{}}
188
- isGetFormData={isGetFormData}
189
- getFormdata={getFormdata}
190
- getFormSubscriptionData={getFormdata}
191
- getDefaultTags={type}
192
- defaultData={{templateName}}
193
- cap={cap}
194
- />}
195
- {CmsTemplates && !isShowEmailCreate && <CmsTemplatesComponent cmsTemplates={CmsTemplates} handleEdmDefaultTemplateSelection={this.useEditor}/>}
196
-
197
-
198
- </div>
181
+ <div>
182
+ {isShowEmailCreate && <Email
183
+ key="email-create-template"
184
+ location={this.state.routeParams}
185
+ route={{ name: 'email' }}
186
+ params={{}}
187
+ isGetFormData={isGetFormData}
188
+ getFormdata={getFormdata}
189
+ getFormSubscriptionData={getFormdata}
190
+ getDefaultTags={type}
191
+ defaultData={{templateName}}
192
+ cap={cap}
193
+ />}
194
+ {CmsTemplates && !isShowEmailCreate && <CmsTemplatesComponent cmsTemplates={CmsTemplates} handleEdmDefaultTemplateSelection={this.useEditor}/>}
195
+ </div>
199
196
  }
197
+ </CapSpin>
200
198
  </div>
201
199
  );
202
200
  }
@@ -218,12 +216,14 @@ EmailWrapper.propTypes = {
218
216
  cap: PropTypes.object,
219
217
  onResetStep: PropTypes.func,
220
218
  isFullMode: PropTypes.bool,
219
+ isUploading: PropTypes.bool,
221
220
  };
222
221
 
223
222
  const mapStateToProps = createStructuredSelector({
224
223
  EmailLayout: selectEmailLayout(),
225
224
  CmsTemplates: selectCmsTemplates(),
226
225
  SelectedEdmDefaultTemplate: selectEdmEditor(),
226
+ isUploading: uploadSelector(),
227
227
  });
228
228
 
229
229
  function mapDispatchToProps(dispatch) {
@@ -50,4 +50,8 @@ export default defineMessages({
50
50
  id: `app.containers.EmailWrapper.invalidUploadFileDesc`,
51
51
  defaultMessage: `Please select another file with valid file contents`,
52
52
  },
53
+ upload: {
54
+ id: `app.containers.EmailWrapper.upload`,
55
+ defaultMessage: `Upload`,
56
+ },
53
57
  });
@@ -947,6 +947,7 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
947
947
  <Row>
948
948
  <Col>
949
949
  <FormBuilder
950
+ isFullMode={this.props.isFullMode}
950
951
  schema={schema}
951
952
  onSubmit={this.saveFormData}
952
953
  onChange={this.onFormDataChange}
@@ -950,6 +950,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
950
950
  <Row>
951
951
  <Col>
952
952
  <FormBuilder
953
+ isFullMode={this.props.isFullMode}
953
954
  schema={schema}
954
955
  onSubmit={this.saveFormData}
955
956
  onChange={this.onFormDataChange}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "2.0.47",
4
+ "version": "2.0.48",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -1,108 +0,0 @@
1
- /**
2
- *
3
- * EmailPreviewV2
4
- *
5
- */
6
-
7
- import React from 'react';
8
- // import styled from 'styled-components';
9
- import PropTypes from 'prop-types';
10
- import { FormattedMessage } from 'react-intl';
11
- import {isEmpty} from 'lodash';
12
- import { connect } from 'react-redux';
13
- import { bindActionCreators } from 'redux';
14
- import { createStructuredSelector } from 'reselect';
15
- import { CapSpin } from '@capillarytech/cap-ui-library';
16
- import moment from 'moment';
17
- import messages from '../EmailPreviewV2/messages';
18
- import './index.scss';
19
- import mobileBody from '../../assets/mobile.png';
20
-
21
- import {selectTemplateContent} from '../../containers/Templates/selectors';
22
- import * as templateActions from '../../containers/Templates/actions';
23
-
24
- const deviceAspectRatio = {
25
- mobile: {
26
- height: "500",
27
- width: "300",
28
- },
29
- };
30
-
31
- class EmailMobilePreview extends React.Component {
32
- componentWillMount() {
33
- const {templateData, templateContent} = this.props;
34
- if (isEmpty(templateContent) && !isEmpty(templateData) && templateData._id) { // templateData: comes from templates list email preview
35
- this.props.templateActions.getTemplateDetails(templateData._id); // templateContent: html data to be shown in iframe
36
- }
37
- }
38
-
39
- getPreview = ({device, messageContainerName, templateContent}) => (
40
- <div className={"shell align-center"}>
41
- <img src={mobileBody} alt="capillary" width="85%" height="400px" />
42
- <div className={messageContainerName}>
43
- <iframe srcDoc={templateContent} {...deviceAspectRatio[device]} >
44
- <p><FormattedMessage {...messages.noIframeSupport}/></p>
45
- </iframe>
46
- </div>
47
- </div>
48
- );
49
-
50
- render() {
51
- const messageContainerName = 'mobile-message-container';
52
- const {currentDevice} = this.state;
53
- const { templateContent } = this.props;
54
-
55
- return (
56
- <div className="email-preview-v2">
57
-
58
- <CapSpin spinning={!templateContent}>
59
- <div id="emailPreivew-container">
60
- <div id="emailPreivew-content-wrapper">
61
- <div id="emailPreivew-content">
62
- <div className="email-preview-container">
63
- <div className={"shell align-center"}>
64
- <img src={mobileBody} alt="capillary" width="85%" />
65
- <div className={messageContainerName}>
66
- <iframe srcDoc={templateContent} {...deviceAspectRatio[currentDevice]} >
67
- <p><FormattedMessage {...messages.noIframeSupport}/></p>
68
- </iframe>
69
- </div>
70
- </div>
71
- </div>
72
- </div>
73
- </div>
74
- </div>
75
- {this.props.templateData &&
76
- [
77
- <p className="preview-info"><FormattedMessage {...messages.lastModified} />: {moment(this.props.templateData.updatedAt).format('MM-DD-YYYY')}</p>,
78
- <p style={{marginBottom: '8px'}} className="preview-info"><FormattedMessage {...messages.uploadedBy} /> : {this.props.templateData.updatedByName}</p>,
79
- ]
80
- }
81
- </CapSpin>
82
- </div>
83
-
84
- );
85
- }
86
-
87
- }
88
-
89
- EmailMobilePreview.propTypes = {
90
- templateContent: PropTypes.string,
91
- templateData: PropTypes.object,
92
- templateActions: PropTypes.object,
93
- };
94
-
95
- EmailMobilePreview.defaultProps = {
96
- showDeviceSelection: true,
97
- };
98
-
99
- const mapStateToProps = (state, props) => createStructuredSelector({
100
- templateContent: props.templateData ? selectTemplateContent() : () => props.templateContent, // when props has templateContent that means preview with content
101
- });
102
- function mapDispatchToProps(dispatch) {
103
- return {
104
- templateActions: bindActionCreators(templateActions, dispatch),
105
- };
106
- }
107
-
108
- export default connect(mapStateToProps, mapDispatchToProps)(EmailMobilePreview);
@@ -1,66 +0,0 @@
1
- $classPrefix: email-preview-v2;
2
- .#{$classPrefix}{
3
- #emailPreivew-container {
4
- position: relative;
5
- // padding: 0 24px 0 24px;
6
- overflow-y: auto;
7
- // font-family: 'proxima-nova';
8
- overflow: hidden;
9
- #emailPreivew-content-wrapper{
10
- width: 100%;
11
- height: 90%;
12
- overflow: auto;
13
- // display: table;
14
-
15
- #emailPreivew-content {
16
- .device-wrapper {
17
- display: inline-flex;
18
- margin-bottom: 8px;
19
- margin-top: 16px;
20
- .device-name {
21
- padding: 6px 24px;
22
- background: #E6F0FB;
23
- border: 2px solid #E6F0FB;
24
- font-family: "open-sans";
25
- line-height: 20px;
26
- font-size: 14px;
27
- color: #4E92E5;
28
- cursor: pointer;
29
- }
30
- .active {
31
- background: #FFFFFF !important;
32
- border: 2px solid #E6F0FB;
33
- }
34
-
35
- }
36
- .email-preview-container{
37
- .tablet-message-container {
38
- position: absolute;
39
- top: 9%;
40
- left: 10%;
41
- width: 100%;
42
- height: 100%;
43
- overflow: auto;
44
- display: -webkit-box;
45
- display: -ms-flexbox;
46
- display: flex;
47
- }
48
- .mobile-message-container {
49
- position: absolute;
50
- top: 10.3%;
51
- left: 14%;
52
- overflow: auto;
53
- display: -webkit-box;
54
- display: -ms-flexbox;
55
- display: flex;
56
- }
57
- }
58
- padding: 0 0px 0 24px;
59
- // display: table-cell;
60
- // vertical-align: middle;
61
- text-align: center;
62
- margin-bottom: 36px;
63
- }
64
- }
65
- }
66
- }
@@ -1,34 +0,0 @@
1
- /*
2
- *
3
- * TemplatesV2 reducer
4
- *
5
- */
6
-
7
- import { fromJS } from 'immutable';
8
- import * as types from './constants';
9
-
10
- const initialState = fromJS({
11
- loadingTemplates: true,
12
- smsTemplates: [],
13
- emailTemplates: [],
14
- wechatTemplates: [],
15
- mobilepushTemplates: [],
16
- });
17
-
18
- function templatesV2Reducer(state = initialState, action) {
19
- const channelTemplates = `${action.channel}Templates`;
20
- switch (action.type) {
21
- case types.DEFAULT_ACTION:
22
- return state;
23
- case types.GET_TEMPLATES_REQUEST:
24
- return state.set('loadingTemplates', true);
25
- case types.GET_TEMPLATES_SUCESS:
26
- return state.set('loadingTemplates', false).set(channelTemplates, action.templates);
27
- case types.GET_TEMPLATES_FAILURE:
28
- return state.set('loadingTemplates', false).set('error', action.error);
29
- default:
30
- return state;
31
- }
32
- }
33
-
34
- export default templatesV2Reducer;
@@ -1,32 +0,0 @@
1
- import { take, takeLatest, call, put, cancel } from 'redux-saga/effects';
2
- import { LOCATION_CHANGE } from 'react-router-redux';
3
- import * as Api from '../../services/api';
4
-
5
-
6
- import * as types from './constants';
7
- // Individual exports for testing
8
- export function* defaultSaga() {
9
- // See example in containers/HomePage/sagas.js
10
- }
11
- function* getTemplates(action) {
12
- try {
13
- const req = {
14
- channel: action.channel,
15
- queryParams: action.query,
16
- };
17
- const res = yield call(Api.getAllTemplates, req);
18
- yield put({type: types.GET_TEMPLATES_SUCESS, templates: res.response.templates, channel: action.channel});
19
- } catch (error) {
20
- yield put({type: types.GET_TEMPLATES_FAILURE, error});
21
- }
22
- }
23
- function* getTemplatesWatcher() {
24
- const watcher = yield takeLatest(types.GET_TEMPLATES_REQUEST, getTemplates);
25
- yield take(LOCATION_CHANGE);
26
- yield cancel(watcher);
27
- }
28
- // All sagas to be loaded
29
- export default [
30
- defaultSaga,
31
- getTemplatesWatcher,
32
- ];