@capillarytech/creatives-library 8.0.102 → 8.0.105

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