@capillarytech/creatives-library 8.0.102 → 8.0.104

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.
@@ -6,14 +6,9 @@
6
6
  import PropTypes from 'prop-types';
7
7
  import React from 'react';
8
8
  import { connect } from 'react-redux';
9
- import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
10
- import { GA } from '@capillarytech/cap-ui-utils';
9
+ import { injectIntl, intlShape } from 'react-intl';
11
10
  import { createStructuredSelector } from 'reselect';
12
11
  import { bindActionCreators } from 'redux';
13
- import _ from 'lodash';
14
- import styled from 'styled-components';
15
- import { CapRadioCard, CapNotification, CapInput, CapUploader, CapSpin, CapButton, CapError } from '@capillarytech/cap-ui-library';
16
- import ComponentWithLabelHOC from '@capillarytech/cap-ui-library/assets/HOCs/ComponentWithLabelHOC';
17
12
  import { UserIsAuthenticated } from '../../utils/authWrapper';
18
13
  import {
19
14
  selectEmailLayout,
@@ -23,302 +18,113 @@ import {
23
18
  selectCmsTemplatesLoader,
24
19
  } from '../Templates/selectors';
25
20
  import * as templatesActionsCreators from '../Templates/actions';
26
- import Email from '../Email';
27
- import CmsTemplatesComponent from '../../v2Components/CmsTemplatesComponent';
28
- import messages from './messages';
29
- import { CHANNEL_CREATE_TRACK_MAPPING } from '../App/constants';
30
- import { gtmPush } from '../../utils/gtmTrackers';
31
- import { EMAIL } from '../CreativesContainer/constants';
32
21
  import { selectCurrentOrgDetails } from "../../v2Containers/Cap/selectors";
22
+ import EmailWrapperView from './components/EmailWrapperView';
23
+ import useEmailWrapper from './hooks/useEmailWrapper';
33
24
 
34
- const CapRadioCardWithLabel = ComponentWithLabelHOC(CapRadioCard);
35
- const { timeTracker } = GA;
36
- const CardContainer = styled.div`
37
- margin-top: 16px;
38
- .ant-radio-group{
39
- .ant-radio-button-wrapper{
40
- &:first-child{
41
- margin-left: unset;
42
- }
43
- }
44
-
45
- }
46
- `;
47
- export class EmailWrapper extends React.Component { // eslint-disable-line react/prefer-stateless-function
48
- constructor(props) {
49
- super(props);
50
- this.emailUploader = React.createRef();
51
- this.state = {
52
- templateName: '',
53
- routeParams: {
54
- pathname: `/email/create`,
55
- query: { module: 'library', type: 'embedded' },
56
- },
57
- modeContent: {
25
+ const EmailWrapper = (props) => {
26
+ // Destructure props for clarity before passing to hook
27
+ const {
28
+ emailCreateMode,
29
+ step,
30
+ isFullMode,
31
+ EmailLayout,
32
+ isUploading,
33
+ onEmailModeChange,
34
+ isGetFormData,
35
+ type,
36
+ templatesActions,
37
+ CmsTemplates,
38
+ SelectedEdmDefaultTemplate,
39
+ showNextStep,
40
+ getFormdata,
41
+ intl,
42
+ cap,
43
+ onResetStep,
44
+ setIsLoadingContent,
45
+ showTemplateName,
46
+ showLiquidErrorInFooter,
47
+ onValidationFail,
48
+ forwardedTags,
49
+ selectedOfferDetails,
50
+ getCmsTemplatesInProgress,
51
+ currentOrgDetails,
52
+ moduleType,
53
+ onEnterTemplateName,
54
+ onRemoveTemplateName,
55
+ eventContextTags,
56
+ isLoyaltyModule,
57
+ cmsTemplatesLoader
58
+ } = props;
58
59
 
59
- },
60
- // selectedCreateMode: '',
61
- isTemplateNameEmpty: true,
62
- };
63
- this.modes = [
64
- {
65
- title: <FormattedMessage {...messages.zipUpload} />,
66
- content: <FormattedMessage {...messages.zipUploadDesc} />,
67
- value: 'upload',
68
- // onClick: () => {
69
- // this.emailUploader.current.click();
70
- // },
71
- },
72
- {
73
- title: <FormattedMessage {...messages.useEditor} />,
74
- content: <FormattedMessage {...messages.useEditorDesc} />,
75
- value: 'editor',
76
- },
77
- ];
78
- }
60
+ // Pass destructured props to the custom hook
61
+ const {
62
+ templateName,
63
+ isTemplateNameEmpty,
64
+ modeContent,
65
+ modes,
66
+ isShowEmailCreate,
67
+ emailProps,
68
+ cmsTemplatesProps,
69
+ uploadButtonLabel,
70
+ onTemplateNameChange,
71
+ onChange,
72
+ useFileUpload,
73
+ } = useEmailWrapper({
74
+ emailCreateMode,
75
+ step,
76
+ isFullMode,
77
+ EmailLayout,
78
+ isUploading,
79
+ onEmailModeChange,
80
+ isGetFormData,
81
+ type,
82
+ templatesActions,
83
+ CmsTemplates,
84
+ SelectedEdmDefaultTemplate,
85
+ showNextStep,
86
+ getFormdata,
87
+ intl,
88
+ cap,
89
+ onResetStep,
90
+ setIsLoadingContent,
91
+ showTemplateName,
92
+ showLiquidErrorInFooter,
93
+ onValidationFail,
94
+ forwardedTags,
95
+ selectedOfferDetails,
96
+ getCmsTemplatesInProgress,
97
+ currentOrgDetails,
98
+ moduleType,
99
+ onEnterTemplateName,
100
+ onRemoveTemplateName,
101
+ eventContextTags,
102
+ isLoyaltyModule,
103
+ cmsTemplatesLoader
104
+ });
79
105
 
80
- componentDidUpdate() {
81
- const { modeContent } = this.state;
82
- // const isValid = this.isValid();
83
- const { emailCreateMode, EmailLayout, CmsTemplates, step, SelectedEdmDefaultTemplate, templatesActions, getCmsTemplatesInProgress = false } = this.props;
84
- if (step === "modeSelection" && !this.state.selectedCreateMode && emailCreateMode === 'upload' && !EmailLayout) {
85
- //document.getElementById('upload-email-template').click();
86
- } else if (step === "templateSelection" && !this.state.selectedCreateMode) {
87
- if (emailCreateMode === "editor" && !CmsTemplates && !getCmsTemplatesInProgress) {
88
- templatesActions.getDefaultBeeTemplates();
89
- }
90
- } else if (step === "createTemplateContent" && !this.state.selectedCreateMode) {
91
- if (emailCreateMode === 'upload' && !_.isEmpty(EmailLayout)) {
92
- this.setCreateMode('upload');
93
- } else if (emailCreateMode === "editor" && _.isEmpty(SelectedEdmDefaultTemplate)) {
94
- this.handleEdmDefaultTemplateSelection(modeContent.id);
95
- }
96
- }
97
- }
98
-
99
-
100
- componentWillUnmount() {
101
- this.props.onResetStep();
102
- this.props.templatesActions.resetTemplateData();
103
- }
104
- onTemplateNameChange = ({target: {value}}) => {
105
- const {onEnterTemplateName, onRemoveTemplateName} = this.props;
106
- const isEmptyTemplateName = !value?.trim();
107
- this.setState({templateName: value, isTemplateNameEmpty: isEmptyTemplateName});
108
- if (value && onEnterTemplateName) {
109
- onEnterTemplateName();
110
- } else if (onRemoveTemplateName) {
111
- onRemoveTemplateName();
112
- }
113
- }
114
- onChange = (e) => {
115
- this.props.onEmailModeChange(e.target.value);
116
- };
117
- //isValid = () => !_.isEmpty(this.state.templateName)
118
- setCreateMode = (emailCreateMode) => {
119
- this.setState({ selectedCreateMode: emailCreateMode });
120
- }
121
- handleZipUploadError = () => {
122
- const message = {
123
- key: "email-upload-error",
124
- message: this.props.intl.formatMessage(messages.invalidUploadFileError2),
125
- description: this.props.intl.formatMessage(messages.invalidUploadFileErrorDesc2),
126
- };
127
- CapNotification.error(message);
128
- }
129
- stopTimerGA = () => {
130
- // stop timer
131
- const timeTaken = timeTracker.stopTimer(CHANNEL_CREATE_TRACK_MAPPING.email, {
132
- category: 'Creatives',
133
- action: 'Create',
134
- label: 'uploadZip',
135
- });
136
- gtmPush('creativeDetails', {
137
- channel: EMAIL,
138
- timeTaken,
139
- mode: 'uploadZip',
140
- });
141
- }
142
- handleFileUpload = (file = {}) => {
143
- const { templatesActions, intl, showNextStep, isUploading } = this.props;
144
- if (!isUploading) {
145
- const fileExtension = file.name.split('.').pop();
146
- const supportedZipFormats = ['zip'];
147
-
148
- //converted file size to MB
149
- const fileSize = file && (file.size / ( 1024 * 1024 ));
150
-
151
-
152
- //Here fileSize is in MB
153
- if (fileSize > 5) {
154
- const message = {
155
- key: "email-upload-error",
156
- message: intl.formatMessage(messages.invalidUploadFileError),
157
- description: intl.formatMessage(messages.invalidUploadFileErrorDesc3),
158
- };
159
- CapNotification.error(message);
160
- } else if (supportedZipFormats.indexOf(fileExtension.toLowerCase()) !== -1) {
161
- templatesActions.handleZipUpload(file.originFileObj, () => { //handle upload success
162
- this.stopTimerGA();
163
- this.setState({ modeContent: { file } }, showNextStep);
164
- }, this.handleZipUploadError);
165
- } else if (fileExtension === 'html' || fileExtension === 'htm') {
166
- const reader = new FileReader();
167
- reader.onload = () => {
168
- const text = reader.result;
169
- this.setState({ modeContent: { file } }, () => {
170
- templatesActions.handleHtmlUpload(text);
171
- });
172
- // showNextStep();
173
- };
174
- reader.readAsText(file.originFileObj);
175
- } else {
176
- const message = {
177
- key: "email-upload-error",
178
- message: intl.formatMessage(messages.invalidUploadFileError),
179
- description: intl.formatMessage(messages.invalidUploadFileErrorDesc),
180
- };
181
- CapNotification.error(message);
182
- }
183
- }
184
- };
185
-
186
- handleEdmDefaultTemplateSelection = (id) => {
187
- const { CmsTemplates, templatesActions } = this.props;
188
- const data = _.find(CmsTemplates, { _id: id });
189
-
190
- templatesActions.setEdmTemplate(data);
191
- templatesActions.setBEETemplate(data);
192
- this.setState({
193
- selectedCreateMode: 'editor',
194
- });
195
- };
196
- useFileUpload = ({ file }) => {
197
- this.setState({ modeContent: {} }, () => {
198
- this.handleFileUpload(file);
199
- });
200
- }
201
- useEditor = (id) => {
202
- this.setState({ modeContent: { id } }, this.props.showNextStep);
203
- }
204
-
205
- isShowEmailCreate = () => !_.isEmpty(this.state.selectedCreateMode) && (!_.isEmpty(this.props.EmailLayout) || this.props.SelectedEdmDefaultTemplate)
206
- render() {
207
- const {
208
- showTemplateName,
209
- emailCreateMode,
210
- isGetFormData,
211
- getFormdata,
212
- type,
213
- CmsTemplates,
214
- step,
215
- cap,
216
- isFullMode,
217
- EmailLayout,
218
- setIsLoadingContent,
219
- onValidationFail,
220
- forwardedTags,
221
- selectedOfferDetails,
222
- onPreviewContentClicked,
223
- onTestContentClicked,
224
- cmsTemplatesLoader,
225
- editor,
226
- currentOrgDetails,
227
- moduleType,
228
- showLiquidErrorInFooter,
229
- eventContextTags,
230
- // Flag to enable loyalty module specific features in the email editor
231
- isLoyaltyModule,
232
- } = this.props;
233
- const {
234
- templateName,
235
- modeContent,
236
- isTemplateNameEmpty,
237
- } = this.state;
238
- const isShowEmailCreate = this.isShowEmailCreate();
239
- return (
240
- <div>
241
- <CapSpin spinning={emailCreateMode === "upload" ? this.props.isUploading : false} >
242
- {step === "modeSelection" || (step === "templateSelection" && emailCreateMode === "upload") ?
243
- <div>
244
- {isFullMode &&
245
- <CapInput
246
- label={<FormattedMessage {...messages.creativeName} />}
247
- onChange={this.onTemplateNameChange}
248
- value={templateName}
249
- labelPosition="top"
250
- size="default"
251
- style={{ width: '68%'}}
252
- />
253
- }
254
- <CardContainer>
255
- <CapRadioCardWithLabel
256
- panes={this.modes}
257
- onChange={this.onChange}
258
- selected={emailCreateMode}
259
- label={<FormattedMessage {...messages.createMode} />}
260
- />
261
- </CardContainer>
262
- <div>
263
- {emailCreateMode === "upload" &&
264
- <div style={{ marginLeft: '8px' }}>
265
- <CapUploader onChange={this.useFileUpload} accept=".zip, .html, .htm" showUploadList={false}>
266
- { (isFullMode && isTemplateNameEmpty) &&
267
- <CapError type="error">
268
- < FormattedMessage {...messages.emptyTemplateName} />
269
- </CapError>
270
- }
271
- <CapButton disabled={isFullMode && isTemplateNameEmpty}>{this.props.intl.formatMessage(messages.upload)}</CapButton>
272
- </CapUploader>
273
- {!_.isEmpty(EmailLayout) &&
274
- <div>{_.get(modeContent, "file.name")}</div>
275
- }
276
- </div>
277
- }
278
- </div>
279
- </div>
280
- :
281
- <div>
282
- {isShowEmailCreate && <Email
283
- setIsLoadingContent={setIsLoadingContent}
284
- key="email-create-template"
285
- location={this.state.routeParams}
286
- route={{ name: 'email' }}
287
- params={{}}
288
- isGetFormData={isGetFormData}
289
- getFormdata={getFormdata}
290
- getFormSubscriptionData={getFormdata}
291
- getDefaultTags={type}
292
- isFullMode={isFullMode}
293
- defaultData={{ 'template-name': templateName }}
294
- cap={cap}
295
- showTemplateName={showTemplateName}
296
- showLiquidErrorInFooter={showLiquidErrorInFooter}
297
- onValidationFail={onValidationFail}
298
- forwardedTags={forwardedTags}
299
- selectedOfferDetails={selectedOfferDetails}
300
- onPreviewContentClicked={onPreviewContentClicked}
301
- onTestContentClicked={onTestContentClicked}
302
- editor={editor}
303
- moduleType={moduleType}
304
- eventContextTags={eventContextTags}
305
- isLoyaltyModule={isLoyaltyModule}
306
- />}
307
- {!isShowEmailCreate && (
308
- <CmsTemplatesComponent
309
- cmsTemplates={CmsTemplates}
310
- handleEdmDefaultTemplateSelection={this.useEditor}
311
- cmsTemplatesLoader={cmsTemplatesLoader}
312
- currentOrgDetails={currentOrgDetails || cap?.currentOrgDetails}
313
- />
314
- )}
315
- </div>
316
- }
317
- </CapSpin>
318
- </div>
319
- );
320
- }
321
- }
106
+ // Render using the presentation component with data from the hook
107
+ return (
108
+ <EmailWrapperView
109
+ isUploading={isUploading}
110
+ emailCreateMode={emailCreateMode}
111
+ step={step}
112
+ isFullMode={isFullMode}
113
+ templateName={templateName}
114
+ onTemplateNameChange={onTemplateNameChange}
115
+ isTemplateNameEmpty={isTemplateNameEmpty}
116
+ modes={modes}
117
+ onChange={onChange}
118
+ EmailLayout={EmailLayout}
119
+ modeContent={modeContent}
120
+ useFileUpload={useFileUpload}
121
+ uploadButtonLabel={uploadButtonLabel}
122
+ isShowEmailCreate={isShowEmailCreate}
123
+ emailProps={emailProps}
124
+ cmsTemplatesProps={cmsTemplatesProps}
125
+ />
126
+ );
127
+ };
322
128
 
323
129
  EmailWrapper.propTypes = {
324
130
  onEmailModeChange: PropTypes.func.isRequired,
@@ -0,0 +1,119 @@
1
+
2
+ // Base mock data that can be shared
3
+ const baseMockData = {
4
+ isUploading: false,
5
+ emailCreateMode: "editor",
6
+ step: "modeSelection",
7
+ isFullMode: true,
8
+ cmsTemplates: [
9
+ {
10
+ _id: "template1",
11
+ name: "Template 1",
12
+ content: "<html><body>Template 1 Content</body></html>"
13
+ },
14
+ {
15
+ _id: "template2",
16
+ name: "Template 2",
17
+ content: "<html><body>Template 2 Content</body></html>"
18
+ }
19
+ ]
20
+ };
21
+
22
+ export const EmailWrapperMockData = {
23
+ ...baseMockData,
24
+ onEmailModeChange: jest.fn(),
25
+ showTemplateName: jest.fn(),
26
+ isGetFormData: false,
27
+ getFormdata: jest.fn(),
28
+ type: "email",
29
+ cap: { currentOrgDetails: { basic_details: {} } },
30
+ setIsLoadingContent: jest.fn(),
31
+ onValidationFail: jest.fn(),
32
+ forwardedTags: {},
33
+ selectedOfferDetails: [],
34
+ onPreviewContentClicked: jest.fn(),
35
+ onTestContentClicked: jest.fn(),
36
+ editor: {},
37
+ moduleType: "email",
38
+ showLiquidErrorInFooter: jest.fn(),
39
+ eventContextTags: [],
40
+ isLoyaltyModule: false,
41
+ templatesActions: {
42
+ resetTemplateData: jest.fn(),
43
+ getDefaultBeeTemplates: jest.fn(),
44
+ handleZipUpload: jest.fn(),
45
+ handleHtmlUpload: jest.fn(),
46
+ setEdmTemplate: jest.fn(),
47
+ setBEETemplate: jest.fn()
48
+ },
49
+ showNextStep: jest.fn(),
50
+ onResetStep: jest.fn(),
51
+ onEnterTemplateName: jest.fn(),
52
+ onRemoveTemplateName: jest.fn(),
53
+ getCmsTemplatesInProgress: false,
54
+ EmailLayout: null,
55
+ SelectedEdmDefaultTemplate: null,
56
+ cmsTemplatesLoader: false,
57
+ currentOrgDetails: { basic_details: {} },
58
+ intl: {
59
+ formatMessage: jest.fn(message => message.defaultMessage || "")
60
+ }
61
+ };
62
+
63
+ export const EmailWrapperViewMockProps = {
64
+ ...baseMockData,
65
+ templateName: "Test Template",
66
+ onTemplateNameChange: jest.fn(),
67
+ isTemplateNameEmpty: false,
68
+ modes: [
69
+ {
70
+ title: "Upload zip file",
71
+ content: "Upload compressed file (Zip) containing HTML & images",
72
+ value: "upload"
73
+ },
74
+ {
75
+ title: "Create using editor",
76
+ content: "Create using in-built template",
77
+ value: "editor"
78
+ }
79
+ ],
80
+ onChange: jest.fn(),
81
+ EmailLayout: null,
82
+ modeContent: {},
83
+ useFileUpload: jest.fn(),
84
+ uploadButtonLabel: "Upload",
85
+ isShowEmailCreate: false,
86
+ emailProps: {
87
+ key: "email-create-template",
88
+ location: {
89
+ pathname: `/email/create`,
90
+ query: { module: "library", type: "embedded" }
91
+ },
92
+ route: { name: "email" },
93
+ params: {},
94
+ isGetFormData: false,
95
+ getFormdata: jest.fn(),
96
+ getFormSubscriptionData: jest.fn(),
97
+ getDefaultTags: "email",
98
+ isFullMode: true,
99
+ defaultData: { "template-name": "Test Template" },
100
+ cap: { currentOrgDetails: { basic_details: {} } },
101
+ showTemplateName: jest.fn(),
102
+ showLiquidErrorInFooter: jest.fn(),
103
+ onValidationFail: jest.fn(),
104
+ forwardedTags: {},
105
+ selectedOfferDetails: [],
106
+ onPreviewContentClicked: jest.fn(),
107
+ onTestContentClicked: jest.fn(),
108
+ editor: {},
109
+ moduleType: "email",
110
+ eventContextTags: [],
111
+ isLoyaltyModule: false
112
+ },
113
+ cmsTemplatesProps: {
114
+ cmsTemplates: baseMockData.cmsTemplates,
115
+ handleEdmDefaultTemplateSelection: jest.fn(),
116
+ cmsTemplatesLoader: false,
117
+ currentOrgDetails: { basic_details: {} }
118
+ }
119
+ };