@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.
package/config/app.js CHANGED
@@ -17,16 +17,16 @@ const config = {
17
17
  accountConfig: (strs, accountId) => `${window.location.origin}/org/config/AccountAdd?q=a&channelId=2&accountId=${accountId}&edit=1`,
18
18
  },
19
19
  development: {
20
- api_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/arya/api/v1/creatives',
21
- campaigns_api_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/iris/v2/campaigns',
22
- campaigns_api_org_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/iris/v2/org/campaign',
23
- auth_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/arya/api/v1/auth',
24
- arya_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/arya/api/v1',
25
- subscription_api_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/arya/api/v1/org-settings/subscription',
26
- exports_api_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/arya/api/v1/export/data',
20
+ api_endpoint: 'https://devenv-crm.cc.capillarytech.com/arya/api/v1/creatives',
21
+ campaigns_api_endpoint: 'https://devenv-crm.cc.capillarytech.com/iris/v2/campaigns',
22
+ campaigns_api_org_endpoint: 'https://devenv-crm.cc.capillarytech.com/iris/v2/org/campaign',
23
+ auth_endpoint: 'https://devenv-crm.cc.capillarytech.com/arya/api/v1/auth',
24
+ arya_endpoint: 'https://devenv-crm.cc.capillarytech.com/arya/api/v1',
25
+ subscription_api_endpoint: 'https://devenv-crm.cc.capillarytech.com/arya/api/v1/org-settings/subscription',
26
+ exports_api_endpoint: 'https://devenv-crm.cc.capillarytech.com/arya/api/v1/export/data',
27
27
  login_url: '/auth/login',
28
28
  dashboard_url: '/sms',
29
- liquid_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/iris/v2/template',
29
+ liquid_endpoint: 'https://devenv-crm.cc.capillarytech.com/iris/v2/template',
30
30
  dashboard_url_v2: '/v2',
31
31
  },
32
32
  testing: {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "8.0.102",
4
+ "version": "8.0.104",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -0,0 +1,192 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { FormattedMessage } from 'react-intl';
4
+ import styled from 'styled-components';
5
+ import isEmpty from 'lodash/isEmpty';
6
+ import get from 'lodash/get';
7
+ import CapRadioCard from '@capillarytech/cap-ui-library/CapRadioCard';
8
+ import CapInput from '@capillarytech/cap-ui-library/CapInput';
9
+ import CapUploader from '@capillarytech/cap-ui-library/CapUploader';
10
+ import CapSpin from '@capillarytech/cap-ui-library/CapSpin';
11
+ import CapButton from '@capillarytech/cap-ui-library/CapButton';
12
+ import CapError from '@capillarytech/cap-ui-library/CapError';
13
+ import ComponentWithLabelHOC from '@capillarytech/cap-ui-library/assets/HOCs/ComponentWithLabelHOC';
14
+ import Email from '../../Email';
15
+ import CmsTemplatesComponent from '../../../v2Components/CmsTemplatesComponent';
16
+ import messages from '../messages';
17
+ import { EMAIL_CREATE_MODES, STEPS } from '../constants';
18
+
19
+ const CapRadioCardWithLabel = ComponentWithLabelHOC(CapRadioCard);
20
+
21
+ const CardContainer = styled.div`
22
+ margin-top: 16px;
23
+ .ant-radio-group{
24
+ .ant-radio-button-wrapper{
25
+ &:first-child{
26
+ margin-left: unset;
27
+ }
28
+ }
29
+ }
30
+ `;
31
+
32
+ // Mode selection component that handles the creation mode selection UI
33
+ const ModeSelectionUI = ({
34
+ isFullMode,
35
+ templateName,
36
+ onTemplateNameChange,
37
+ isTemplateNameEmpty,
38
+ modes,
39
+ emailCreateMode,
40
+ onChange,
41
+ EmailLayout,
42
+ modeContent,
43
+ useFileUpload,
44
+ uploadButtonLabel,
45
+ }) => (
46
+ <>
47
+ {isFullMode && (
48
+ <CapInput
49
+ label={<FormattedMessage {...messages.creativeName} />}
50
+ onChange={onTemplateNameChange}
51
+ value={templateName}
52
+ labelPosition="top"
53
+ size="default"
54
+ style={{ width: '68%'}}
55
+ />
56
+ )}
57
+ <CardContainer>
58
+ <CapRadioCardWithLabel
59
+ panes={modes}
60
+ onChange={onChange}
61
+ selected={emailCreateMode}
62
+ label={<FormattedMessage {...messages.createMode} />}
63
+ />
64
+ </CardContainer>
65
+ <>
66
+ {emailCreateMode === EMAIL_CREATE_MODES.UPLOAD && (
67
+ <div style={{ marginLeft: '8px' }}>
68
+ <CapUploader onChange={useFileUpload} accept=".zip, .html, .htm" showUploadList={false}>
69
+ {(isFullMode && isTemplateNameEmpty) && (
70
+ <CapError type="error">
71
+ <FormattedMessage {...messages.emptyTemplateName} />
72
+ </CapError>
73
+ )}
74
+ <CapButton disabled={isFullMode && isTemplateNameEmpty}>
75
+ {uploadButtonLabel}
76
+ </CapButton>
77
+ </CapUploader>
78
+ {!isEmpty(EmailLayout) && (
79
+ <>{get(modeContent, "file.name")}</>
80
+ )}
81
+ </div>
82
+ )}
83
+ </>
84
+ </>
85
+ );
86
+
87
+ ModeSelectionUI.propTypes = {
88
+ isFullMode: PropTypes.bool,
89
+ templateName: PropTypes.string,
90
+ onTemplateNameChange: PropTypes.func.isRequired,
91
+ isTemplateNameEmpty: PropTypes.bool,
92
+ modes: PropTypes.array.isRequired,
93
+ emailCreateMode: PropTypes.string,
94
+ onChange: PropTypes.func.isRequired,
95
+ EmailLayout: PropTypes.object,
96
+ modeContent: PropTypes.object,
97
+ useFileUpload: PropTypes.func.isRequired,
98
+ uploadButtonLabel: PropTypes.node.isRequired,
99
+ };
100
+
101
+ // Content creation component that handles the email or template selection UI
102
+ const ContentCreationUI = ({
103
+ isShowEmailCreate,
104
+ emailProps,
105
+ cmsTemplatesProps,
106
+ }) => (
107
+ <>
108
+ {isShowEmailCreate ? (
109
+ <Email {...emailProps} />
110
+ ) : (
111
+ <CmsTemplatesComponent {...cmsTemplatesProps} />
112
+ )}
113
+ </>
114
+ );
115
+
116
+ ContentCreationUI.propTypes = {
117
+ isShowEmailCreate: PropTypes.bool.isRequired,
118
+ emailProps: PropTypes.object.isRequired,
119
+ cmsTemplatesProps: PropTypes.object.isRequired,
120
+ };
121
+
122
+ // Main EmailWrapper presentational component
123
+ const EmailWrapperView = ({
124
+ isUploading,
125
+ emailCreateMode,
126
+ step,
127
+ isFullMode,
128
+ templateName,
129
+ onTemplateNameChange,
130
+ isTemplateNameEmpty,
131
+ modes,
132
+ onChange,
133
+ EmailLayout,
134
+ modeContent,
135
+ useFileUpload,
136
+ uploadButtonLabel,
137
+ isShowEmailCreate,
138
+ emailProps,
139
+ cmsTemplatesProps,
140
+ }) => {
141
+ console.log("EmailLayout", step, emailCreateMode);
142
+ const isShowTemplateSelection = step === STEPS.MODE_SELECTION || (step === STEPS.TEMPLATE_SELECTION && emailCreateMode === EMAIL_CREATE_MODES.UPLOAD);
143
+
144
+ return (
145
+ <>
146
+ <CapSpin spinning={emailCreateMode === EMAIL_CREATE_MODES.UPLOAD ? isUploading : false}>
147
+ {isShowTemplateSelection ? (
148
+ <ModeSelectionUI
149
+ isFullMode={isFullMode}
150
+ templateName={templateName}
151
+ onTemplateNameChange={onTemplateNameChange}
152
+ isTemplateNameEmpty={isTemplateNameEmpty}
153
+ modes={modes}
154
+ emailCreateMode={emailCreateMode}
155
+ onChange={onChange}
156
+ EmailLayout={EmailLayout}
157
+ modeContent={modeContent}
158
+ useFileUpload={useFileUpload}
159
+ uploadButtonLabel={uploadButtonLabel}
160
+ />
161
+ ) : (
162
+ <ContentCreationUI
163
+ isShowEmailCreate={isShowEmailCreate}
164
+ emailProps={emailProps}
165
+ cmsTemplatesProps={cmsTemplatesProps}
166
+ />
167
+ )}
168
+ </CapSpin>
169
+ </>
170
+ );
171
+ };
172
+
173
+ EmailWrapperView.propTypes = {
174
+ isUploading: PropTypes.bool,
175
+ emailCreateMode: PropTypes.string,
176
+ step: PropTypes.string,
177
+ isFullMode: PropTypes.bool,
178
+ templateName: PropTypes.string,
179
+ onTemplateNameChange: PropTypes.func.isRequired,
180
+ isTemplateNameEmpty: PropTypes.bool,
181
+ modes: PropTypes.array.isRequired,
182
+ onChange: PropTypes.func.isRequired,
183
+ EmailLayout: PropTypes.string,
184
+ modeContent: PropTypes.object,
185
+ useFileUpload: PropTypes.func.isRequired,
186
+ uploadButtonLabel: PropTypes.node.isRequired,
187
+ isShowEmailCreate: PropTypes.bool.isRequired,
188
+ emailProps: PropTypes.object.isRequired,
189
+ cmsTemplatesProps: PropTypes.object.isRequired,
190
+ };
191
+
192
+ export default EmailWrapperView;
@@ -4,4 +4,14 @@
4
4
  *
5
5
  */
6
6
 
7
- export const DEFAULT_ACTION = 'app/EmailWrapper/DEFAULT_ACTION';
7
+ export const DEFAULT_ACTION = "app/EmailWrapper/DEFAULT_ACTION";
8
+ export const EMAIL_CREATE_MODES = {
9
+ UPLOAD: "upload",
10
+ EDITOR: "editor",
11
+ };
12
+
13
+ export const STEPS = {
14
+ MODE_SELECTION: "modeSelection",
15
+ TEMPLATE_SELECTION: "templateSelection",
16
+ CREATE_TEMPLATE_CONTENT: "createTemplateContent",
17
+ };
@@ -0,0 +1,342 @@
1
+ import { useState, useEffect, useMemo, useCallback } from 'react';
2
+ import isEmpty from 'lodash/isEmpty';
3
+ import get from 'lodash/get';
4
+ import { GA } from '@capillarytech/cap-ui-utils';
5
+ import CapNotification from '@capillarytech/cap-ui-library/CapNotification';
6
+ import { CHANNEL_CREATE_TRACK_MAPPING } from '../../App/constants';
7
+ import { gtmPush } from '../../../utils/gtmTrackers';
8
+ import { EMAIL } from '../../CreativesContainer/constants';
9
+ import messages from '../messages';
10
+ import { STEPS } from '../constants';
11
+ import { EMAIL_CREATE_MODES } from '../constants';
12
+
13
+ /**
14
+ * Custom hook to handle EmailWrapper component business logic
15
+ */
16
+ const useEmailWrapper = ({
17
+ intl: { formatMessage },
18
+ onEmailModeChange,
19
+ emailCreateMode,
20
+ step,
21
+ EmailLayout,
22
+ CmsTemplates,
23
+ SelectedEdmDefaultTemplate,
24
+ isUploading,
25
+ templatesActions,
26
+ showNextStep,
27
+ onResetStep,
28
+ onEnterTemplateName,
29
+ onRemoveTemplateName,
30
+ getCmsTemplatesInProgress,
31
+ // Props for Email component
32
+ setIsLoadingContent,
33
+ isGetFormData,
34
+ getFormdata,
35
+ type,
36
+ isFullMode,
37
+ cap,
38
+ showTemplateName,
39
+ showLiquidErrorInFooter,
40
+ onValidationFail,
41
+ forwardedTags,
42
+ selectedOfferDetails,
43
+ onPreviewContentClicked,
44
+ onTestContentClicked,
45
+ editor,
46
+ moduleType,
47
+ eventContextTags,
48
+ isLoyaltyModule,
49
+ // Props for CmsTemplates component
50
+ cmsTemplatesLoader,
51
+ currentOrgDetails,
52
+ }) => {
53
+ // State management
54
+ const [templateName, setTemplateName] = useState('');
55
+ const [isTemplateNameEmpty, setIsTemplateNameEmpty] = useState(true);
56
+ const [selectedCreateMode, setSelectedCreateMode] = useState('');
57
+ const [modeContent, setModeContent] = useState({});
58
+ const [routeParams] = useState({
59
+ pathname: `/email/create`,
60
+ query: { module: 'library', type: 'embedded' },
61
+ });
62
+
63
+ // Cleanup effect
64
+ useEffect(() => {
65
+ return () => {
66
+ onResetStep();
67
+ templatesActions.resetTemplateData();
68
+ };
69
+ }, [onResetStep, templatesActions]);
70
+
71
+ // Event handlers
72
+ const onTemplateNameChange = useCallback(({target: {value}}) => {
73
+ const isEmptyTemplateName = !value?.trim();
74
+ setTemplateName(value);
75
+ setIsTemplateNameEmpty(isEmptyTemplateName);
76
+
77
+ if (value && onEnterTemplateName) {
78
+ onEnterTemplateName();
79
+ } else if (onRemoveTemplateName) {
80
+ onRemoveTemplateName();
81
+ }
82
+ }, [onEnterTemplateName, onRemoveTemplateName]);
83
+
84
+ const onChange = useCallback((e) => {
85
+ onEmailModeChange(e.target.value);
86
+ }, [onEmailModeChange]);
87
+
88
+ const handleZipUploadError = useCallback(() => {
89
+ const message = {
90
+ key: "email-upload-error",
91
+ message: formatMessage(messages.invalidUploadFileError2),
92
+ description: formatMessage(messages.invalidUploadFileErrorDesc2),
93
+ };
94
+ CapNotification.error(message);
95
+ }, [formatMessage]);
96
+
97
+ const stopTimerGA = useCallback(() => {
98
+ const timeTaken = GA.timeTracker.stopTimer(CHANNEL_CREATE_TRACK_MAPPING.email, {
99
+ category: 'Creatives',
100
+ action: 'Create',
101
+ label: 'uploadZip',
102
+ });
103
+ gtmPush('creativeDetails', {
104
+ channel: EMAIL,
105
+ timeTaken,
106
+ mode: 'uploadZip',
107
+ });
108
+ }, [formatMessage]);
109
+
110
+ const handleFileUpload = useCallback((file = {}) => {
111
+ if (!isUploading) {
112
+ // Validate file object
113
+ if (!file || !file.name) {
114
+ const message = {
115
+ key: "email-upload-error",
116
+ message: formatMessage(messages.invalidUploadFileError),
117
+ description: formatMessage(messages.invalidUploadFileErrorDesc3),
118
+ };
119
+ CapNotification.error(message);
120
+ return;
121
+ }
122
+
123
+ const fileExtension = (file.name || '').split('.').pop().toLowerCase();
124
+ const supportedZipFormats = ['zip'];
125
+
126
+ // Converted file size to MB - added defensive check
127
+ const fileSize = file && file.size ? (file.size / (1024 * 1024)) : 0;
128
+
129
+ // Here fileSize is in MB
130
+ if (fileSize > 5) {
131
+ const message = {
132
+ key: "email-upload-error",
133
+ message: formatMessage(messages.invalidUploadFileError),
134
+ description: formatMessage(messages.invalidUploadFileErrorDesc3),
135
+ };
136
+ CapNotification.error(message);
137
+ } else if (supportedZipFormats.includes(fileExtension)) {
138
+ // Verify originFileObj exists
139
+ if (!file.originFileObj) {
140
+ handleZipUploadError();
141
+ return;
142
+ }
143
+
144
+ templatesActions.handleZipUpload(file.originFileObj, () => { // Handle upload success
145
+ stopTimerGA();
146
+ setModeContent({ file });
147
+ showNextStep();
148
+ }, handleZipUploadError);
149
+ } else if (fileExtension === 'html' || fileExtension === 'htm') {
150
+ // Verify originFileObj exists
151
+ if (!file.originFileObj) {
152
+ handleZipUploadError();
153
+ return;
154
+ }
155
+
156
+ const reader = new FileReader();
157
+ reader.onload = () => {
158
+ const text = reader.result;
159
+ // Add defensive check for empty or invalid content
160
+ if (!text || typeof text !== 'string') {
161
+ handleZipUploadError();
162
+ return;
163
+ }
164
+ setModeContent({ file });
165
+ templatesActions.handleHtmlUpload(text);
166
+ };
167
+ reader.onerror = () => {
168
+ handleZipUploadError();
169
+ };
170
+ reader.readAsText(file.originFileObj);
171
+ } else {
172
+ const message = {
173
+ key: "email-upload-error",
174
+ message: formatMessage(messages.invalidUploadFileError),
175
+ description: formatMessage(messages.invalidUploadFileErrorDesc),
176
+ };
177
+ CapNotification.error(message);
178
+ }
179
+ }
180
+ }, [isUploading, formatMessage, templatesActions, stopTimerGA, handleZipUploadError, showNextStep]);
181
+
182
+ const handleEdmDefaultTemplateSelection = useCallback((id) => {
183
+ const data = find(CmsTemplates, { _id: id });
184
+ templatesActions.setEdmTemplate(data);
185
+ templatesActions.setBEETemplate(data);
186
+ setSelectedCreateMode(EMAIL_CREATE_MODES.EDITOR);
187
+ }, [CmsTemplates, templatesActions]);
188
+
189
+ const useFileUpload = useCallback(({ file }) => {
190
+ setModeContent({});
191
+ handleFileUpload(file);
192
+ }, [handleFileUpload]);
193
+
194
+ const useEditor = useCallback((id) => {
195
+ setModeContent({ id });
196
+ showNextStep();
197
+ }, [showNextStep]);
198
+
199
+ // Main logic effect - MOVED AFTER function declarations
200
+ useEffect(() => {
201
+ // Skip if user has already made a selection
202
+ if (selectedCreateMode) return;
203
+
204
+ // Handle different steps
205
+ switch (step) {
206
+ case STEPS.MODE_SELECTION:
207
+ if (emailCreateMode === EMAIL_CREATE_MODES.UPLOAD && !EmailLayout) {
208
+ // Commented out: document.getElementById('upload-email-template').click();
209
+ }
210
+ break;
211
+
212
+ case STEPS.TEMPLATE_SELECTION:
213
+ const needsTemplates = emailCreateMode === EMAIL_CREATE_MODES.EDITOR
214
+ && !CmsTemplates
215
+ && !getCmsTemplatesInProgress;
216
+
217
+ if (needsTemplates) {
218
+ templatesActions.getDefaultBeeTemplates();
219
+ }
220
+ break;
221
+
222
+ case STEPS.CREATE_TEMPLATE_CONTENT:
223
+ if (emailCreateMode === EMAIL_CREATE_MODES.UPLOAD && !isEmpty(EmailLayout)) {
224
+ setSelectedCreateMode(EMAIL_CREATE_MODES.UPLOAD);
225
+ } else if (emailCreateMode === EMAIL_CREATE_MODES.EDITOR && isEmpty(SelectedEdmDefaultTemplate)) {
226
+ handleEdmDefaultTemplateSelection(modeContent.id);
227
+ }
228
+ break;
229
+
230
+ default:
231
+ // No operation for other steps
232
+ break;
233
+ }
234
+ }, [
235
+ step,
236
+ selectedCreateMode,
237
+ emailCreateMode,
238
+ EmailLayout,
239
+ CmsTemplates,
240
+ getCmsTemplatesInProgress,
241
+ modeContent.id,
242
+ SelectedEdmDefaultTemplate,
243
+ templatesActions,
244
+ handleEdmDefaultTemplateSelection
245
+ ]);
246
+
247
+ // Derived state
248
+ const isShowEmailCreate = !isEmpty(selectedCreateMode) && (!isEmpty(EmailLayout) || SelectedEdmDefaultTemplate);
249
+
250
+ // Memoize static data
251
+ const modes = useMemo(() => [
252
+ {
253
+ title: formatMessage(messages.zipUpload),
254
+ content: formatMessage(messages.zipUploadDesc),
255
+ value: EMAIL_CREATE_MODES.UPLOAD,
256
+ },
257
+ {
258
+ title: formatMessage(messages.useEditor),
259
+ content: formatMessage(messages.useEditorDesc),
260
+ value: EMAIL_CREATE_MODES.EDITOR,
261
+ },
262
+ ], [formatMessage]);
263
+
264
+ // Prepare props for Email component
265
+ const emailProps = useMemo(() => ({
266
+ setIsLoadingContent,
267
+ key: "email-create-template",
268
+ location: routeParams,
269
+ route: { name: 'email' },
270
+ params: {},
271
+ isGetFormData,
272
+ getFormdata,
273
+ getFormSubscriptionData: getFormdata,
274
+ getDefaultTags: type,
275
+ isFullMode,
276
+ defaultData: { 'template-name': templateName },
277
+ cap,
278
+ showTemplateName,
279
+ showLiquidErrorInFooter,
280
+ onValidationFail,
281
+ forwardedTags,
282
+ selectedOfferDetails,
283
+ onPreviewContentClicked,
284
+ onTestContentClicked,
285
+ editor,
286
+ moduleType,
287
+ eventContextTags,
288
+ isLoyaltyModule,
289
+ }), [
290
+ setIsLoadingContent,
291
+ routeParams,
292
+ isGetFormData,
293
+ getFormdata,
294
+ type,
295
+ isFullMode,
296
+ templateName,
297
+ cap,
298
+ showTemplateName,
299
+ showLiquidErrorInFooter,
300
+ onValidationFail,
301
+ forwardedTags,
302
+ selectedOfferDetails,
303
+ onPreviewContentClicked,
304
+ onTestContentClicked,
305
+ editor,
306
+ moduleType,
307
+ eventContextTags,
308
+ isLoyaltyModule,
309
+ ]);
310
+
311
+ // Prepare props for CmsTemplatesComponent
312
+ const cmsTemplatesProps = useMemo(() => ({
313
+ cmsTemplates: CmsTemplates,
314
+ handleEdmDefaultTemplateSelection: useEditor,
315
+ cmsTemplatesLoader,
316
+ currentOrgDetails: currentOrgDetails || cap?.currentOrgDetails,
317
+ }), [CmsTemplates, useEditor, cmsTemplatesLoader, currentOrgDetails, cap]);
318
+
319
+ // Upload button label
320
+ const uploadButtonLabel = formatMessage(messages.upload);
321
+
322
+ return {
323
+ // State
324
+ templateName,
325
+ isTemplateNameEmpty,
326
+ modeContent,
327
+
328
+ // Derived values
329
+ modes,
330
+ isShowEmailCreate,
331
+ emailProps,
332
+ cmsTemplatesProps,
333
+ uploadButtonLabel,
334
+
335
+ // Event handlers
336
+ onTemplateNameChange,
337
+ onChange,
338
+ useFileUpload,
339
+ };
340
+ };
341
+
342
+ export default useEmailWrapper;