@capillarytech/creatives-library 8.0.213 → 8.0.214-beta.0
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/HOW_BEE_EDITOR_WORKS.md +375 -0
- package/constants/unified.js +1 -0
- package/package.json +1 -1
- package/services/api.js +5 -0
- package/utils/common.js +6 -1
- package/v2Components/CapTagList/index.js +2 -1
- package/v2Components/CapTagListWithInput/index.js +5 -1
- package/v2Components/CapTagListWithInput/messages.js +1 -1
- package/v2Components/ErrorInfoNote/style.scss +1 -1
- package/v2Components/HtmlEditor/HTMLEditor.js +86 -14
- package/v2Components/HtmlEditor/_htmlEditor.scss +4 -4
- package/v2Components/HtmlEditor/_index.lazy.scss +1 -1
- package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +107 -96
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +68 -92
- package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
- package/v2Components/HtmlEditor/hooks/useEditorContent.js +5 -2
- package/v2Containers/CreativesContainer/SlideBoxContent.js +85 -35
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +9 -3
- package/v2Containers/CreativesContainer/index.js +107 -35
- package/v2Containers/CreativesContainer/messages.js +4 -0
- package/v2Containers/Email/actions.js +7 -0
- package/v2Containers/Email/constants.js +5 -1
- package/v2Containers/Email/index.js +13 -0
- package/v2Containers/Email/messages.js +32 -0
- package/v2Containers/Email/reducer.js +12 -1
- package/v2Containers/Email/sagas.js +17 -0
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +1005 -0
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +193 -7
- package/v2Containers/EmailWrapper/constants.js +2 -0
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +470 -71
- package/v2Containers/EmailWrapper/index.js +102 -23
- package/v2Containers/EmailWrapper/messages.js +61 -1
- package/v2Containers/EmailWrapper/tests/EmailHTMLEditor.test.js +177 -0
- package/v2Containers/EmailWrapper/tests/EmailHTMLEditorValidation.test.js +90 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +49 -49
- package/v2Containers/TagList/index.js +2 -0
- package/v2Containers/Templates/index.js +5 -0
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
align-items: center;
|
|
14
14
|
min-height: 25rem; // 400px = 25rem
|
|
15
15
|
background: $CAP_G11; // Light background similar to #fafbfc
|
|
16
|
-
border: 0.0625rem solid $CAP_G07; // 1px border similar to #dfe2e7
|
|
16
|
+
// border: 0.0625rem solid $CAP_G07; // 1px border similar to #dfe2e7
|
|
17
17
|
border-radius: 0.5rem; // 8px = 0.5rem
|
|
18
18
|
flex-direction: column;
|
|
19
19
|
gap: 1rem; // 16px = 1rem
|
|
@@ -32,78 +32,78 @@
|
|
|
32
32
|
align-items: center;
|
|
33
33
|
gap: 0.5rem;
|
|
34
34
|
|
|
35
|
-
.cap-button,
|
|
36
|
-
.ant-btn,
|
|
37
|
-
button {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
.tooltip-add-label-container {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
.cap-button-flat,
|
|
102
|
-
.cap-button-add {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
35
|
+
// .cap-button,
|
|
36
|
+
// .ant-btn,
|
|
37
|
+
// button {
|
|
38
|
+
// color: map-get($CAP_PRIMARY, base);
|
|
39
|
+
// border: none;
|
|
40
|
+
// background: $CAP_WHITE;
|
|
41
|
+
// border-radius: 0.25rem;
|
|
42
|
+
// padding: 0.375rem 0.5rem;
|
|
43
|
+
// font-size: 0.875rem;
|
|
44
|
+
// font-family: $FONT_FAMILY;
|
|
45
|
+
// font-weight: 500;
|
|
46
|
+
// height: auto;
|
|
47
|
+
// min-width: 5.9375rem;
|
|
48
|
+
// display: flex;
|
|
49
|
+
// align-items: center;
|
|
50
|
+
// gap: 0.25rem;
|
|
51
|
+
// box-shadow: 0 0 0.0625rem 0 rgba(9, 30, 66, 0.31), 0 0.25rem 0.5rem -0.125rem rgba(9, 30, 66, 0.25);
|
|
52
|
+
// line-height: 1.25rem;
|
|
53
|
+
// text-align: left;
|
|
54
|
+
|
|
55
|
+
// &:hover {
|
|
56
|
+
// background: $CAP_G09;
|
|
57
|
+
// box-shadow: 0 0 0.0625rem 0 rgba(9, 30, 66, 0.31), 0 0.375rem 0.75rem -0.125rem rgba(9, 30, 66, 0.25);
|
|
58
|
+
// color: map-get($CAP_PRIMARY, base);
|
|
59
|
+
// border: none;
|
|
60
|
+
// }
|
|
61
|
+
|
|
62
|
+
// &:active,
|
|
63
|
+
// &:focus {
|
|
64
|
+
// background: $CAP_G08;
|
|
65
|
+
// box-shadow: 0 0 0.0625rem 0 rgba(9, 30, 66, 0.31), 0 0.125rem 0.25rem -0.125rem rgba(9, 30, 66, 0.25);
|
|
66
|
+
// color: map-get($CAP_PRIMARY, base);
|
|
67
|
+
// border: none;
|
|
68
|
+
// }
|
|
69
|
+
|
|
70
|
+
// .anticon,
|
|
71
|
+
// .cap-icon {
|
|
72
|
+
// font-size: 1rem;
|
|
73
|
+
// color: map-get($CAP_PRIMARY, base);
|
|
74
|
+
// }
|
|
75
|
+
|
|
76
|
+
// span {
|
|
77
|
+
// font-size: 0.875rem;
|
|
78
|
+
// font-weight: 500;
|
|
79
|
+
// line-height: 1.25rem;
|
|
80
|
+
// color: map-get($CAP_PRIMARY, base);
|
|
81
|
+
// white-space: nowrap;
|
|
82
|
+
// }
|
|
83
|
+
|
|
84
|
+
// &:before,
|
|
85
|
+
// &:after {
|
|
86
|
+
// display: none;
|
|
87
|
+
// }
|
|
88
|
+
// }
|
|
89
|
+
|
|
90
|
+
// .tooltip-add-label-container {
|
|
91
|
+
|
|
92
|
+
// .cap-button,
|
|
93
|
+
// .ant-btn {
|
|
94
|
+
// color: map-get($CAP_PRIMARY, base);
|
|
95
|
+
// background: $CAP_WHITE;
|
|
96
|
+
// border: none;
|
|
97
|
+
// box-shadow: 0 0 0.0625rem 0 rgba(9, 30, 66, 0.31), 0 0.25rem 0.5rem -0.125rem rgba(9, 30, 66, 0.25);
|
|
98
|
+
// }
|
|
99
|
+
// }
|
|
100
|
+
|
|
101
|
+
// .cap-button-flat,
|
|
102
|
+
// .cap-button-add {
|
|
103
|
+
// background: $CAP_WHITE;
|
|
104
|
+
// color: map-get($CAP_PRIMARY, base);
|
|
105
|
+
// border: none;
|
|
106
|
+
// }
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
&__content {
|
|
@@ -130,6 +130,17 @@
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
.code-editor-pane__actions {
|
|
134
|
+
opacity: 0;
|
|
135
|
+
pointer-events: none;
|
|
136
|
+
transition: opacity 0.2s ease;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.code-editor-pane__content:hover .code-editor-pane__actions {
|
|
140
|
+
opacity: 1;
|
|
141
|
+
pointer-events: auto;
|
|
142
|
+
}
|
|
143
|
+
|
|
133
144
|
.cm-foldGutter {
|
|
134
145
|
width: 1rem;
|
|
135
146
|
|
|
@@ -235,30 +246,30 @@
|
|
|
235
246
|
right: 0.5rem;
|
|
236
247
|
z-index: 20;
|
|
237
248
|
|
|
238
|
-
.cap-button,
|
|
239
|
-
.ant-btn,
|
|
240
|
-
button {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}
|
|
249
|
+
// .cap-button,
|
|
250
|
+
// .ant-btn,
|
|
251
|
+
// button {
|
|
252
|
+
// background: $CAP_WHITE;
|
|
253
|
+
// color: map-get($CAP_PRIMARY, base);
|
|
254
|
+
// border: none;
|
|
255
|
+
// border-radius: 0.25rem;
|
|
256
|
+
// padding: 0.375rem 0.5rem;
|
|
257
|
+
// font-size: 0.875rem;
|
|
258
|
+
// font-family: $FONT_FAMILY;
|
|
259
|
+
// font-weight: 500;
|
|
260
|
+
// min-width: 5.9375rem;
|
|
261
|
+
// box-shadow: 0 0 0.0625rem 0 rgba(9, 30, 66, 0.31), 0 0.25rem 0.5rem -0.125rem rgba(9, 30, 66, 0.25);
|
|
262
|
+
|
|
263
|
+
// &:hover {
|
|
264
|
+
// background: $CAP_G09;
|
|
265
|
+
// color: map-get($CAP_PRIMARY, base);
|
|
266
|
+
// }
|
|
267
|
+
|
|
268
|
+
// &:active {
|
|
269
|
+
// background: $CAP_G08;
|
|
270
|
+
// color: map-get($CAP_PRIMARY, base);
|
|
271
|
+
// }
|
|
272
|
+
// }
|
|
262
273
|
}
|
|
263
274
|
|
|
264
275
|
.codemirror-editor {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - Theme support with proper styling
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import React, { forwardRef, useImperativeHandle, useRef, useEffect, useState } from 'react';
|
|
11
|
+
import React, { forwardRef, useImperativeHandle, useRef, useEffect, useState, useCallback } from 'react';
|
|
12
12
|
import PropTypes from 'prop-types';
|
|
13
13
|
|
|
14
14
|
// CodeMirror 6 imports
|
|
@@ -30,6 +30,8 @@ import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
|
30
30
|
// Components
|
|
31
31
|
import TagList from '../../../../v2Containers/TagList';
|
|
32
32
|
|
|
33
|
+
// Constants - removed unused imports since tag fetching is handled by parent
|
|
34
|
+
|
|
33
35
|
// Context
|
|
34
36
|
import { useEditorContext } from '../common/EditorContext';
|
|
35
37
|
|
|
@@ -44,7 +46,17 @@ const CodeEditorPaneComponent = ({
|
|
|
44
46
|
className = '',
|
|
45
47
|
isFullscreenMode = false,
|
|
46
48
|
onLabelInsert,
|
|
47
|
-
forwardedRef
|
|
49
|
+
forwardedRef,
|
|
50
|
+
// Tag-related props - tags are fetched and managed by parent component
|
|
51
|
+
tags = [],
|
|
52
|
+
injectedTags = {},
|
|
53
|
+
location,
|
|
54
|
+
eventContextTags = [],
|
|
55
|
+
selectedOfferDetails = [],
|
|
56
|
+
channel,
|
|
57
|
+
userLocale = 'en',
|
|
58
|
+
moduleFilterEnabled = true,
|
|
59
|
+
onTagContextChange
|
|
48
60
|
}) => {
|
|
49
61
|
const { content, validation } = useEditorContext();
|
|
50
62
|
const { content: contentValue, updateContent } = content;
|
|
@@ -147,7 +159,7 @@ const CodeEditorPaneComponent = ({
|
|
|
147
159
|
// For unified HTML editor, insert as template variable
|
|
148
160
|
const formattedTag = `{{${tagText}}}`;
|
|
149
161
|
|
|
150
|
-
// Insert the tag at cursor position
|
|
162
|
+
// Insert the tag at cursor position directly
|
|
151
163
|
view.dispatch({
|
|
152
164
|
changes: { from: pos, insert: formattedTag },
|
|
153
165
|
selection: { anchor: pos + formattedTag.length }
|
|
@@ -156,31 +168,43 @@ const CodeEditorPaneComponent = ({
|
|
|
156
168
|
// Focus back to editor
|
|
157
169
|
view.focus();
|
|
158
170
|
|
|
159
|
-
//
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
171
|
+
// Note: We don't call onLabelInsert here because:
|
|
172
|
+
// 1. The tag is already inserted directly into the editor
|
|
173
|
+
// 2. onLabelInsert (handleLabelInsert from HTMLEditor) would try to insert again
|
|
174
|
+
// 3. This causes "Editor method not available" error
|
|
175
|
+
// The direct insertion via view.dispatch is sufficient
|
|
163
176
|
}
|
|
164
177
|
};
|
|
165
178
|
|
|
179
|
+
// Handle tag context change - delegate to parent component
|
|
180
|
+
// Tags are fetched in parent components (EmailHTMLEditor, INAPP, etc.)
|
|
181
|
+
// This component just passes the context change event up
|
|
182
|
+
const handleTagContextChange = useCallback((data) => {
|
|
183
|
+
if (onTagContextChange) {
|
|
184
|
+
// Parent component handles tag fetching and updates
|
|
185
|
+
onTagContextChange(data);
|
|
186
|
+
}
|
|
187
|
+
// No fallback - tags must be managed by parent component
|
|
188
|
+
}, [onTagContextChange]);
|
|
189
|
+
|
|
166
190
|
// Initialize CodeMirror effect
|
|
167
191
|
useEffect(() => {
|
|
168
192
|
if (editorRef.current && !viewRef.current) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
193
|
+
// Use the comprehensive extensions from properSyntaxHighlighting.js
|
|
194
|
+
// This includes: html(), syntaxHighlighting(comprehensiveVSCodeTheme), cleanEditorTheme
|
|
195
|
+
const robustExtensions = createRobustExtensions();
|
|
196
|
+
|
|
197
|
+
// Add additional extensions for line numbers, active line, and update listener
|
|
198
|
+
const extensions = [
|
|
199
|
+
lineNumbers(),
|
|
200
|
+
highlightActiveLine(),
|
|
201
|
+
...robustExtensions, // Spread the robust extensions (html, syntax highlighting, theme)
|
|
202
|
+
EditorView.updateListener.of((update) => {
|
|
203
|
+
if (update.docChanged) {
|
|
204
|
+
updateContentRef.current(update.state.doc.toString());
|
|
205
|
+
}
|
|
206
|
+
})
|
|
207
|
+
];
|
|
184
208
|
|
|
185
209
|
const state = EditorState.create({
|
|
186
210
|
doc: contentValue || '',
|
|
@@ -233,75 +257,18 @@ const CodeEditorPaneComponent = ({
|
|
|
233
257
|
key="html-editor-taglist"
|
|
234
258
|
label={intl.formatMessage(messages.addLabel)}
|
|
235
259
|
onTagSelect={handleTagSelect}
|
|
236
|
-
onContextChange={
|
|
237
|
-
}}
|
|
260
|
+
onContextChange={handleTagContextChange}
|
|
238
261
|
className="tag-list-trigger"
|
|
239
|
-
tags={
|
|
240
|
-
injectedTags={
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
desc: 'Customer information tags',
|
|
245
|
-
resolved: true,
|
|
246
|
-
'tag-header': true,
|
|
247
|
-
subtags: {
|
|
248
|
-
'customer.firstName': {
|
|
249
|
-
name: 'First Name',
|
|
250
|
-
desc: 'Customer first name',
|
|
251
|
-
resolved: true
|
|
252
|
-
},
|
|
253
|
-
'customer.lastName': {
|
|
254
|
-
name: 'Last Name',
|
|
255
|
-
desc: 'Customer last name',
|
|
256
|
-
resolved: true
|
|
257
|
-
},
|
|
258
|
-
'customer.email': {
|
|
259
|
-
name: 'Email',
|
|
260
|
-
desc: 'Customer email address',
|
|
261
|
-
resolved: true
|
|
262
|
-
},
|
|
263
|
-
'customer.phone': {
|
|
264
|
-
name: 'Phone',
|
|
265
|
-
desc: 'Customer phone number',
|
|
266
|
-
resolved: true
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
},
|
|
270
|
-
'Common Tags': {
|
|
271
|
-
name: 'Common Tags',
|
|
272
|
-
desc: 'Commonly used template tags',
|
|
273
|
-
resolved: true,
|
|
274
|
-
'tag-header': true,
|
|
275
|
-
subtags: {
|
|
276
|
-
'organization.name': {
|
|
277
|
-
name: 'Organization Name',
|
|
278
|
-
desc: 'Organization name',
|
|
279
|
-
resolved: true
|
|
280
|
-
},
|
|
281
|
-
'currentDate': {
|
|
282
|
-
name: 'Current Date',
|
|
283
|
-
desc: 'Current date',
|
|
284
|
-
resolved: true
|
|
285
|
-
},
|
|
286
|
-
'unsubscribeLink': {
|
|
287
|
-
name: 'Unsubscribe Link',
|
|
288
|
-
desc: 'Unsubscribe link',
|
|
289
|
-
resolved: true
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}}
|
|
294
|
-
moduleFilterEnabled={true}
|
|
295
|
-
userLocale="en"
|
|
296
|
-
channel="email"
|
|
262
|
+
tags={tags}
|
|
263
|
+
injectedTags={injectedTags}
|
|
264
|
+
moduleFilterEnabled={moduleFilterEnabled}
|
|
265
|
+
userLocale={userLocale}
|
|
266
|
+
channel={channel}
|
|
297
267
|
disabled={readOnly}
|
|
298
|
-
location={
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
}}
|
|
303
|
-
selectedOfferDetails={[]}
|
|
304
|
-
eventContextTags={[]}
|
|
268
|
+
location={location}
|
|
269
|
+
selectedOfferDetails={selectedOfferDetails}
|
|
270
|
+
eventContextTags={eventContextTags}
|
|
271
|
+
popoverPlacement="rightTop"
|
|
305
272
|
/>
|
|
306
273
|
</CapRow>
|
|
307
274
|
</div>
|
|
@@ -323,9 +290,18 @@ CodeEditorPane.propTypes = {
|
|
|
323
290
|
readOnly: PropTypes.bool,
|
|
324
291
|
className: PropTypes.string,
|
|
325
292
|
isFullscreenMode: PropTypes.bool,
|
|
326
|
-
onLabelInsert: PropTypes.func
|
|
293
|
+
onLabelInsert: PropTypes.func,
|
|
294
|
+
// Tag-related props - tags are fetched and managed by parent component
|
|
295
|
+
tags: PropTypes.array,
|
|
296
|
+
injectedTags: PropTypes.object,
|
|
297
|
+
location: PropTypes.object,
|
|
298
|
+
eventContextTags: PropTypes.array,
|
|
299
|
+
selectedOfferDetails: PropTypes.array,
|
|
300
|
+
channel: PropTypes.string,
|
|
301
|
+
userLocale: PropTypes.string,
|
|
302
|
+
moduleFilterEnabled: PropTypes.bool,
|
|
303
|
+
onTagContextChange: PropTypes.func, // Required - parent must handle tag fetching
|
|
327
304
|
};
|
|
328
305
|
|
|
329
306
|
// Export with injectIntl - ref forwarding is handled by forwardRef wrapper
|
|
330
|
-
export default injectIntl(CodeEditorPane);
|
|
331
|
-
|
|
307
|
+
export default injectIntl(CodeEditorPane);
|
|
@@ -69,7 +69,10 @@ export const useEditorContent = (
|
|
|
69
69
|
} = options;
|
|
70
70
|
|
|
71
71
|
// Unified content state
|
|
72
|
-
|
|
72
|
+
// Use DEFAULT_CONTENT only if initialContent is null or undefined (not empty string)
|
|
73
|
+
// This allows explicitly passing empty string for empty content
|
|
74
|
+
const initialContentValue = initialContent == null ? DEFAULT_CONTENT : initialContent;
|
|
75
|
+
const [content, setContent] = useState(initialContentValue);
|
|
73
76
|
const [isDirty, setIsDirty] = useState(false);
|
|
74
77
|
const [lastSaved, setLastSaved] = useState(null);
|
|
75
78
|
const [isAutoSaveEnabled, setIsAutoSaveEnabled] = useState(autoSave);
|
|
@@ -79,7 +82,7 @@ export const useEditorContent = (
|
|
|
79
82
|
const validationDebounceRef = useRef(null);
|
|
80
83
|
const autoSaveRef = useRef(null);
|
|
81
84
|
const validationCallbackRef = useRef(null);
|
|
82
|
-
const lastContentRef = useRef(
|
|
85
|
+
const lastContentRef = useRef(initialContentValue);
|
|
83
86
|
|
|
84
87
|
// Smart debouncing hooks
|
|
85
88
|
const debouncedOnChange = useSmartDebounce(onChange || (() => {}), PERFORMANCE.PREVIEW_UPDATE_DEBOUNCE);
|
|
@@ -4,6 +4,7 @@ import styled from 'styled-components';
|
|
|
4
4
|
import get from 'lodash/get';
|
|
5
5
|
import isEmpty from 'lodash/isEmpty';
|
|
6
6
|
import cloneDeep from 'lodash/cloneDeep';
|
|
7
|
+
import { CapSpin } from '@capillarytech/cap-ui-library';
|
|
7
8
|
import TemplatesV2 from '../TemplatesV2';
|
|
8
9
|
import TemplatePreview from '../../v2Components/TemplatePreview';
|
|
9
10
|
import SmsWrapper from '../SmsWrapper';
|
|
@@ -164,6 +165,7 @@ export function SlideBoxContent(props) {
|
|
|
164
165
|
handleTestAndPreview,
|
|
165
166
|
handleCloseTestAndPreview,
|
|
166
167
|
isTestAndPreviewMode,
|
|
168
|
+
isLoadingContent = false,
|
|
167
169
|
} = props;
|
|
168
170
|
const type = (messageDetails.type || '').toLowerCase(); // type is context in get tags values : outbound | dvs | referral | loyalty | coupons
|
|
169
171
|
const query = { type: !isFullMode && 'embedded', module: isFullMode ? 'default' : 'library', isEditFromCampaigns: (templateData || {}).isEditFromCampaigns};
|
|
@@ -629,44 +631,92 @@ export function SlideBoxContent(props) {
|
|
|
629
631
|
handleTestAndPreview={handleTestAndPreview}
|
|
630
632
|
handleCloseTestAndPreview={handleCloseTestAndPreview}
|
|
631
633
|
isTestAndPreviewMode={isTestAndPreviewMode}
|
|
634
|
+
location={location}
|
|
632
635
|
/>
|
|
633
636
|
)}
|
|
634
637
|
{(isEditEmailWithId || isEmailEditWithContent) && (
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
638
|
+
(() => {
|
|
639
|
+
const supportCKEditor = commonUtil.hasSupportCKEditor();
|
|
640
|
+
// When supportCKEditor is true: Always use Email component (legacy flow)
|
|
641
|
+
if (supportCKEditor || templateData?.is_drag_drop) {
|
|
642
|
+
return (
|
|
643
|
+
<Email
|
|
644
|
+
key="cretives-container-email-edit"
|
|
645
|
+
setIsLoadingContent={setIsLoadingContent}
|
|
646
|
+
location={{
|
|
647
|
+
pathname: `/email/edit`,
|
|
648
|
+
query: { type: 'embedded', module: 'library'},
|
|
649
|
+
}}
|
|
650
|
+
route={{ name: 'email' }}
|
|
651
|
+
isGetFormData={isGetFormData}
|
|
652
|
+
getFormdata={getFormData}
|
|
653
|
+
params={{ id: templateData._id }}
|
|
654
|
+
templateData={templateData}
|
|
655
|
+
getFormSubscriptionData={getFormData}
|
|
656
|
+
getDefaultTags={type}
|
|
657
|
+
isFullMode={isFullMode}
|
|
658
|
+
editor={editor}
|
|
659
|
+
cap={cap}
|
|
660
|
+
showTemplateName={showTemplateName}
|
|
661
|
+
onValidationFail={onValidationFail}
|
|
662
|
+
forwardedTags={forwardedTags}
|
|
663
|
+
selectedOfferDetails={selectedOfferDetails}
|
|
664
|
+
onPreviewContentClicked={onPreviewContentClicked}
|
|
665
|
+
onTestContentClicked={onTestContentClicked}
|
|
666
|
+
moduleType={moduleType}
|
|
667
|
+
showLiquidErrorInFooter={showLiquidErrorInFooter}
|
|
668
|
+
eventContextTags={eventContextTags}
|
|
669
|
+
isLoyaltyModule={isLoyaltyModule}
|
|
670
|
+
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
671
|
+
handleTestAndPreview={handleTestAndPreview}
|
|
672
|
+
handleCloseTestAndPreview={handleCloseTestAndPreview}
|
|
673
|
+
isTestAndPreviewMode={isTestAndPreviewMode}
|
|
674
|
+
/>
|
|
675
|
+
);
|
|
676
|
+
}
|
|
677
|
+
// HTML template: Use EmailWrapper component (which uses EmailWithoutSaga)
|
|
678
|
+
return (
|
|
679
|
+
<EmailWrapper
|
|
680
|
+
key="cretives-container-email-edit-wrapper"
|
|
681
|
+
setIsLoadingContent={setIsLoadingContent}
|
|
682
|
+
onEmailModeChange={onEmailModeChange}
|
|
683
|
+
emailCreateMode="editor"
|
|
684
|
+
isGetFormData={isGetFormData}
|
|
685
|
+
getFormdata={getFormData}
|
|
686
|
+
templateData={templateData}
|
|
687
|
+
type={type}
|
|
688
|
+
step="createTemplateContent"
|
|
689
|
+
showNextStep={onCreateNextStep}
|
|
690
|
+
isFullMode={isFullMode}
|
|
691
|
+
editor={editor}
|
|
692
|
+
cap={cap}
|
|
693
|
+
onResetStep={onResetStep}
|
|
694
|
+
showTemplateName={showTemplateName}
|
|
695
|
+
onEnterTemplateName={onEnterTemplateName}
|
|
696
|
+
onRemoveTemplateName={onRemoveTemplateName}
|
|
697
|
+
onValidationFail={onValidationFail}
|
|
698
|
+
forwardedTags={forwardedTags}
|
|
699
|
+
selectedOfferDetails={selectedOfferDetails}
|
|
700
|
+
onPreviewContentClicked={onPreviewContentClicked}
|
|
701
|
+
onTestContentClicked={onTestContentClicked}
|
|
702
|
+
getCmsTemplatesInProgress={getCmsTemplatesInProgress}
|
|
703
|
+
moduleType={moduleType}
|
|
704
|
+
showLiquidErrorInFooter={showLiquidErrorInFooter}
|
|
705
|
+
eventContextTags={eventContextTags}
|
|
706
|
+
isLoyaltyModule={isLoyaltyModule}
|
|
707
|
+
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
708
|
+
handleTestAndPreview={handleTestAndPreview}
|
|
709
|
+
handleCloseTestAndPreview={handleCloseTestAndPreview}
|
|
710
|
+
isTestAndPreviewMode={isTestAndPreviewMode}
|
|
711
|
+
location={{
|
|
712
|
+
pathname: `/email/edit/${templateData._id}`,
|
|
713
|
+
query: { type: 'embedded', module: 'library', id: templateData._id },
|
|
714
|
+
}}
|
|
715
|
+
params={{ id: templateData._id }}
|
|
716
|
+
/>
|
|
717
|
+
);
|
|
718
|
+
})()
|
|
719
|
+
)}
|
|
670
720
|
{isEditMPush && (
|
|
671
721
|
(isFullMode && !commonUtil.hasNewMobilePushFeatureEnabled()) ||
|
|
672
722
|
(!isFullMode && isLoyaltyModule) ||
|
|
@@ -31,8 +31,9 @@ function SlideBoxFooter(props) {
|
|
|
31
31
|
showTestAndPreviewButton,
|
|
32
32
|
shouldShowDoneFooter,
|
|
33
33
|
shouldShowContinueFooter,
|
|
34
|
+
isContinueButtonDisabled,
|
|
35
|
+
continueButtonLabel,
|
|
34
36
|
} = props;
|
|
35
|
-
|
|
36
37
|
return (
|
|
37
38
|
<div className='template-footer-width'>
|
|
38
39
|
{isLiquidValidationError && (<ErrorInfoNote errorMessages={errorMessages} currentTab={currentTab?.toUpperCase()} />)}
|
|
@@ -70,8 +71,11 @@ function SlideBoxFooter(props) {
|
|
|
70
71
|
</div>
|
|
71
72
|
)}
|
|
72
73
|
{shouldShowContinueFooter() && (
|
|
73
|
-
<CapButton
|
|
74
|
-
|
|
74
|
+
<CapButton
|
|
75
|
+
onClick={onCreateNextStep}
|
|
76
|
+
disabled={isContinueButtonDisabled || false}
|
|
77
|
+
>
|
|
78
|
+
<FormattedMessage {...(continueButtonLabel || messages.continue)} />
|
|
75
79
|
</CapButton>
|
|
76
80
|
)}
|
|
77
81
|
{slidBoxContent === PREVIEW && (
|
|
@@ -99,5 +103,7 @@ SlideBoxFooter.propTypes = {
|
|
|
99
103
|
onTestAndPreview: PropTypes.func,
|
|
100
104
|
isEmptyContent: PropTypes.bool,
|
|
101
105
|
showTestAndPreviewButton: PropTypes.bool,
|
|
106
|
+
isContinueButtonDisabled: PropTypes.bool,
|
|
107
|
+
continueButtonLabel: PropTypes.object,
|
|
102
108
|
};
|
|
103
109
|
export default SlideBoxFooter;
|