@capillarytech/creatives-library 8.0.221 → 8.0.223-alpha.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/config/app.js +0 -1
- package/constants/unified.js +0 -2
- package/package.json +1 -1
- package/services/api.js +0 -2
- package/v2Components/TestAndPreviewSlidebox/SendTestMessage.js +7 -1
- package/v2Components/TestAndPreviewSlidebox/index.js +251 -20
- package/v2Components/TestAndPreviewSlidebox/messages.js +8 -0
- package/v2Containers/Cap/index.js +2 -7
- package/v2Containers/Login/index.js +2 -7
- package/v2Containers/Rcs/index.js +14 -3
- package/v2Containers/Rcs/messages.js +1 -5
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +176 -12
package/config/app.js
CHANGED
|
@@ -21,7 +21,6 @@ const config = {
|
|
|
21
21
|
},
|
|
22
22
|
development: {
|
|
23
23
|
api_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/arya/api/v1/creatives',
|
|
24
|
-
// api_endpoint: 'http://localhost:2022/arya/api/v1/creatives',
|
|
25
24
|
campaigns_api_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/iris/v2/campaigns',
|
|
26
25
|
campaigns_api_org_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/iris/v2/org/campaign',
|
|
27
26
|
auth_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/arya/api/v1/auth',
|
package/constants/unified.js
CHANGED
|
@@ -187,5 +187,3 @@ export const LOGOUT_FAILURE = 'cap/LOGOUT_FAILURE';
|
|
|
187
187
|
export const JAPANESE_HELP_TEXT = 'ヘルプ :トークンの定義';
|
|
188
188
|
|
|
189
189
|
export const TAG_TRANSLATION_DOC = 'https://docs.capillarytech.com/docs/tags-translation';
|
|
190
|
-
|
|
191
|
-
export const CAPILLARY_LOADING_LOGO = 'https://storage.crm.n.content-cdn.io/capillary/capillary_loading_logo.gif';
|
package/package.json
CHANGED
package/services/api.js
CHANGED
|
@@ -264,7 +264,6 @@ export const getUserData = () => {
|
|
|
264
264
|
|
|
265
265
|
export const createTemplate = ({template}) => {
|
|
266
266
|
const url = `${API_ENDPOINT}/templates/SMS`;
|
|
267
|
-
console.log("creating template",template);
|
|
268
267
|
return request(url, getAPICallObject('POST', template));
|
|
269
268
|
};
|
|
270
269
|
|
|
@@ -347,7 +346,6 @@ export const getAllTemplates = async ({channel, queryParams = {}}) => {
|
|
|
347
346
|
|
|
348
347
|
export const deleteTemplate = ({channel, id}) => {
|
|
349
348
|
const url = `${API_ENDPOINT}/templates/${id}/${channel}`;
|
|
350
|
-
console.log("deleting template", url);
|
|
351
349
|
return request(url, getAPICallObject('DELETE'));
|
|
352
350
|
//return API.deleteResource(url);
|
|
353
351
|
};
|
|
@@ -19,6 +19,7 @@ const SendTestMessage = ({
|
|
|
19
19
|
formData,
|
|
20
20
|
isSendingTestMessage,
|
|
21
21
|
formatMessage,
|
|
22
|
+
isContentValid = true,
|
|
22
23
|
}) => (
|
|
23
24
|
<CapStepsAccordian
|
|
24
25
|
showNumberSteps={false}
|
|
@@ -43,7 +44,11 @@ const SendTestMessage = ({
|
|
|
43
44
|
multiple
|
|
44
45
|
placeholder={formatMessage(messages.testCustomersPlaceholder)}
|
|
45
46
|
/>
|
|
46
|
-
<CapButton
|
|
47
|
+
<CapButton
|
|
48
|
+
onClick={handleSendTestMessage}
|
|
49
|
+
disabled={isEmpty(selectedTestEntities) || (isEmpty(formData['template-subject']) && isEmpty(formData[0]?.['template-subject'])) || isSendingTestMessage || !isContentValid}
|
|
50
|
+
title={!isContentValid ? formatMessage(messages.contentInvalid) : ''}
|
|
51
|
+
>
|
|
47
52
|
<FormattedMessage {...messages.sendTestButton} />
|
|
48
53
|
</CapButton>
|
|
49
54
|
</CapRow>),
|
|
@@ -63,6 +68,7 @@ SendTestMessage.propTypes = {
|
|
|
63
68
|
formData: PropTypes.object.isRequired,
|
|
64
69
|
isSendingTestMessage: PropTypes.bool.isRequired,
|
|
65
70
|
formatMessage: PropTypes.func.isRequired,
|
|
71
|
+
isContentValid: PropTypes.bool,
|
|
66
72
|
};
|
|
67
73
|
|
|
68
74
|
export default SendTestMessage;
|
|
@@ -52,6 +52,7 @@ import {
|
|
|
52
52
|
INITIAL_PAYLOAD, EMAIL, TEST, DESKTOP, ACTIVE, MOBILE,
|
|
53
53
|
} from './constants';
|
|
54
54
|
import { GLOBAL_CONVERT_OPTIONS } from '../FormBuilder/constants';
|
|
55
|
+
import { validateIfTagClosed } from '../../utils/tagValidations';
|
|
55
56
|
|
|
56
57
|
const TestAndPreviewSlidebox = (props) => {
|
|
57
58
|
const {
|
|
@@ -103,10 +104,147 @@ const TestAndPreviewSlidebox = (props) => {
|
|
|
103
104
|
const [selectedTestEntities, setSelectedTestEntities] = useState([]);
|
|
104
105
|
const [beeContent, setBeeContent] = useState(''); // Track BEE editor content separately
|
|
105
106
|
const previousBeeContentRef = useRef(''); // Track previous BEE content to prevent unnecessary updates
|
|
107
|
+
const [isContentValid, setIsContentValid] = useState(true); // Track if content tags are valid
|
|
106
108
|
|
|
107
109
|
const isUpdatePreviewDisabled = useMemo(() => (
|
|
108
|
-
requiredTags.some((tag) => !customValues[tag.fullPath])
|
|
109
|
-
), [requiredTags, customValues]);
|
|
110
|
+
requiredTags.some((tag) => !customValues[tag.fullPath]) || !isContentValid
|
|
111
|
+
), [requiredTags, customValues, isContentValid]);
|
|
112
|
+
|
|
113
|
+
// Function to validate tags in content
|
|
114
|
+
const validateContentTags = (content) => {
|
|
115
|
+
if (!content) return true;
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
// Convert HTML to text (same as what's used for tag extraction)
|
|
119
|
+
// This ensures we validate the same content that will be used for tag extraction
|
|
120
|
+
const textContent = convert(content, GLOBAL_CONVERT_OPTIONS);
|
|
121
|
+
|
|
122
|
+
// Check if there are any braces in the content
|
|
123
|
+
const hasBraces = textContent.includes('{') || textContent.includes('}');
|
|
124
|
+
|
|
125
|
+
// If no braces exist, content is valid (no tag validation needed)
|
|
126
|
+
if (!hasBraces) {
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// First check if tags are properly closed using the utility function
|
|
131
|
+
// This validates that all opening braces have corresponding closing braces
|
|
132
|
+
if (!validateIfTagClosed(textContent)) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Now validate tag format: tags must be in format {{tag_name}}
|
|
137
|
+
// Find all valid tag patterns {{tag_name}}
|
|
138
|
+
const tagPattern = /{{[^}]*}}/g;
|
|
139
|
+
const matches = textContent.match(tagPattern) || [];
|
|
140
|
+
|
|
141
|
+
// Remove all valid {{tag}} patterns from content to check for invalid braces
|
|
142
|
+
let contentWithoutValidTags = textContent;
|
|
143
|
+
matches.forEach((match) => {
|
|
144
|
+
contentWithoutValidTags = contentWithoutValidTags.replace(match, '');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Check if there are any remaining braces (single braces or unclosed braces)
|
|
148
|
+
// These would be invalid patterns like {tag}, {first, first}, etc.
|
|
149
|
+
if (contentWithoutValidTags.includes('{') || contentWithoutValidTags.includes('}')) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Check each tag for valid format
|
|
154
|
+
for (const match of matches) {
|
|
155
|
+
// Valid tag format: {{tag_name}} - must start with {{ and end with }}
|
|
156
|
+
if (!match.startsWith('{{') || !match.endsWith('}}')) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Extract tag name (content between {{ and }})
|
|
161
|
+
const tagName = match.slice(2, -2).trim();
|
|
162
|
+
|
|
163
|
+
// Tag name should not be empty
|
|
164
|
+
if (!tagName) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Check for invalid patterns in tag name
|
|
169
|
+
// Invalid patterns: "first or first", "first and first", etc.
|
|
170
|
+
const invalidPatterns = [
|
|
171
|
+
/\s+or\s+/i, // " or " as separate word (e.g., "first or first")
|
|
172
|
+
/\s+and\s+/i, // " and " as separate word
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
for (const pattern of invalidPatterns) {
|
|
176
|
+
if (pattern.test(tagName)) {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Check for unclosed single braces in tag name (e.g., {{first{name}})
|
|
182
|
+
const singleOpenBraces = (tagName.match(/{/g) || []).length;
|
|
183
|
+
const singleCloseBraces = (tagName.match(/}/g) || []).length;
|
|
184
|
+
if (singleOpenBraces !== singleCloseBraces) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return true;
|
|
190
|
+
} catch (error) {
|
|
191
|
+
// If conversion fails, fall back to validating the original content
|
|
192
|
+
console.warn('Error converting content for validation:', error);
|
|
193
|
+
const hasBraces = content.includes('{') || content.includes('}');
|
|
194
|
+
if (!hasBraces) {
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Apply same validation to original content
|
|
199
|
+
if (!validateIfTagClosed(content)) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const tagPattern = /{{[^}]*}}/g;
|
|
204
|
+
const matches = content.match(tagPattern) || [];
|
|
205
|
+
|
|
206
|
+
// Remove all valid {{tag}} patterns from content to check for invalid braces
|
|
207
|
+
let contentWithoutValidTags = content;
|
|
208
|
+
matches.forEach((match) => {
|
|
209
|
+
contentWithoutValidTags = contentWithoutValidTags.replace(match, '');
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// Check if there are any remaining braces (single braces or unclosed braces)
|
|
213
|
+
if (contentWithoutValidTags.includes('{') || contentWithoutValidTags.includes('}')) {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
for (const match of matches) {
|
|
218
|
+
if (!match.startsWith('{{') || !match.endsWith('}}')) {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const tagName = match.slice(2, -2).trim();
|
|
223
|
+
if (!tagName) {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const invalidPatterns = [
|
|
228
|
+
/\s+or\s+/i,
|
|
229
|
+
/\s+and\s+/i,
|
|
230
|
+
];
|
|
231
|
+
|
|
232
|
+
for (const pattern of invalidPatterns) {
|
|
233
|
+
if (pattern.test(tagName)) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const singleOpenBraces = (tagName.match(/{/g) || []).length;
|
|
239
|
+
const singleCloseBraces = (tagName.match(/}/g) || []).length;
|
|
240
|
+
if (singleOpenBraces !== singleCloseBraces) {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
};
|
|
110
248
|
|
|
111
249
|
// Function to resolve tags in text with custom values
|
|
112
250
|
const resolveTagsInText = (text, tagValues) => {
|
|
@@ -153,6 +291,10 @@ const TestAndPreviewSlidebox = (props) => {
|
|
|
153
291
|
if (existingContent && existingContent.trim() !== '') {
|
|
154
292
|
// We already have content, update local state only if it's different
|
|
155
293
|
if (existingContent !== previousBeeContentRef.current) {
|
|
294
|
+
// Validate content tags for BEE editor
|
|
295
|
+
const isValid = validateContentTags(existingContent);
|
|
296
|
+
setIsContentValid(isValid);
|
|
297
|
+
|
|
156
298
|
previousBeeContentRef.current = existingContent;
|
|
157
299
|
setBeeContent(existingContent);
|
|
158
300
|
setPreviewDataHtml({
|
|
@@ -186,6 +328,10 @@ const TestAndPreviewSlidebox = (props) => {
|
|
|
186
328
|
}
|
|
187
329
|
|
|
188
330
|
if (htmlFile) {
|
|
331
|
+
// Validate content tags
|
|
332
|
+
const isValid = validateContentTags(htmlFile);
|
|
333
|
+
setIsContentValid(isValid);
|
|
334
|
+
|
|
189
335
|
// Update our states
|
|
190
336
|
previousBeeContentRef.current = htmlFile;
|
|
191
337
|
setBeeContent(htmlFile);
|
|
@@ -194,9 +340,16 @@ const TestAndPreviewSlidebox = (props) => {
|
|
|
194
340
|
resolvedTitle: formData['template-subject'] || ''
|
|
195
341
|
});
|
|
196
342
|
|
|
197
|
-
//
|
|
198
|
-
|
|
199
|
-
|
|
343
|
+
// Only extract tags if content is valid
|
|
344
|
+
if (isValid) {
|
|
345
|
+
const payloadContent = convert(htmlFile, GLOBAL_CONVERT_OPTIONS);
|
|
346
|
+
actions.extractTagsRequested(formData['template-subject'] || '', payloadContent);
|
|
347
|
+
} else {
|
|
348
|
+
// Show error notification for invalid content
|
|
349
|
+
CapNotification.error({
|
|
350
|
+
message: formatMessage(messages.contentInvalid),
|
|
351
|
+
});
|
|
352
|
+
}
|
|
200
353
|
}
|
|
201
354
|
|
|
202
355
|
// Restore original handler
|
|
@@ -211,23 +364,45 @@ const TestAndPreviewSlidebox = (props) => {
|
|
|
211
364
|
const templateContent = currentTabData?.[activeTab]?.['template-content'];
|
|
212
365
|
|
|
213
366
|
if (templateContent) {
|
|
367
|
+
// Validate content tags
|
|
368
|
+
const isValid = validateContentTags(templateContent);
|
|
369
|
+
setIsContentValid(isValid);
|
|
370
|
+
|
|
214
371
|
// Update preview with initial content
|
|
215
372
|
setPreviewDataHtml({
|
|
216
373
|
resolvedBody: templateContent,
|
|
217
374
|
resolvedTitle: formData['template-subject'] || ''
|
|
218
375
|
});
|
|
219
376
|
|
|
220
|
-
//
|
|
221
|
-
|
|
222
|
-
|
|
377
|
+
// Only extract tags if content is valid
|
|
378
|
+
if (isValid) {
|
|
379
|
+
const payloadContent = convert(templateContent, GLOBAL_CONVERT_OPTIONS);
|
|
380
|
+
actions.extractTagsRequested(formData['template-subject'] || '', payloadContent);
|
|
381
|
+
} else {
|
|
382
|
+
// Show error notification for invalid content
|
|
383
|
+
CapNotification.error({
|
|
384
|
+
message: formatMessage(messages.contentInvalid),
|
|
385
|
+
});
|
|
386
|
+
}
|
|
223
387
|
} else {
|
|
224
388
|
// Fallback to content prop if no template content
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
//
|
|
230
|
-
|
|
389
|
+
const contentToValidate = getCurrentContent;
|
|
390
|
+
const isValid = validateContentTags(contentToValidate);
|
|
391
|
+
setIsContentValid(isValid);
|
|
392
|
+
|
|
393
|
+
// Only extract tags if content is valid
|
|
394
|
+
if (isValid) {
|
|
395
|
+
const payloadContent = convert(
|
|
396
|
+
contentToValidate,
|
|
397
|
+
GLOBAL_CONVERT_OPTIONS
|
|
398
|
+
);
|
|
399
|
+
actions.extractTagsRequested(formData['template-subject'] || '', payloadContent);
|
|
400
|
+
} else {
|
|
401
|
+
// Show error notification for invalid content
|
|
402
|
+
CapNotification.error({
|
|
403
|
+
message: formatMessage(messages.contentInvalid),
|
|
404
|
+
});
|
|
405
|
+
}
|
|
231
406
|
}
|
|
232
407
|
}
|
|
233
408
|
|
|
@@ -243,17 +418,28 @@ const TestAndPreviewSlidebox = (props) => {
|
|
|
243
418
|
const isDragDrop = currentTabData?.[activeTab]?.is_drag_drop;
|
|
244
419
|
const templateContent = currentTabData?.[activeTab]?.['template-content'];
|
|
245
420
|
|
|
246
|
-
if (templateContent && templateContent.trim() !== '') {
|
|
247
|
-
// Common function to handle content update
|
|
421
|
+
if (templateContent && templateContent.trim() !== '' && show) {
|
|
422
|
+
// Common function to handle content update with validation
|
|
248
423
|
const handleContentUpdate = (content) => {
|
|
424
|
+
// Validate content tags for each update
|
|
425
|
+
const isValid = validateContentTags(content);
|
|
426
|
+
setIsContentValid(isValid);
|
|
427
|
+
|
|
249
428
|
setPreviewDataHtml({
|
|
250
429
|
resolvedBody: content,
|
|
251
430
|
resolvedTitle: formData['template-subject'] || ''
|
|
252
431
|
});
|
|
253
432
|
|
|
254
|
-
//
|
|
255
|
-
|
|
256
|
-
|
|
433
|
+
// Only extract tags if content is valid
|
|
434
|
+
if (isValid) {
|
|
435
|
+
const payloadContent = convert(content, GLOBAL_CONVERT_OPTIONS);
|
|
436
|
+
actions.extractTagsRequested(formData['template-subject'] || '', payloadContent);
|
|
437
|
+
} else {
|
|
438
|
+
// Show error notification for invalid content
|
|
439
|
+
CapNotification.error({
|
|
440
|
+
message: formatMessage(messages.contentInvalid),
|
|
441
|
+
});
|
|
442
|
+
}
|
|
257
443
|
};
|
|
258
444
|
|
|
259
445
|
if (isDragDrop) {
|
|
@@ -287,6 +473,7 @@ const TestAndPreviewSlidebox = (props) => {
|
|
|
287
473
|
setTagsExtracted(false);
|
|
288
474
|
setPreviewDevice('desktop');
|
|
289
475
|
setSelectedTestEntities([]);
|
|
476
|
+
setIsContentValid(true);
|
|
290
477
|
actions.clearPrefilledValues();
|
|
291
478
|
}
|
|
292
479
|
}, [show]);
|
|
@@ -530,6 +717,22 @@ const TestAndPreviewSlidebox = (props) => {
|
|
|
530
717
|
|
|
531
718
|
// Handle update preview
|
|
532
719
|
const handleUpdatePreview = async () => {
|
|
720
|
+
// Re-validate content to get latest state (in case liquid errors were fixed)
|
|
721
|
+
const currentTabData = formData[currentTab - 1];
|
|
722
|
+
const activeTab = currentTabData?.activeTab;
|
|
723
|
+
const templateContent = currentTabData?.[activeTab]?.['template-content'];
|
|
724
|
+
const contentToValidate = templateContent || getCurrentContent;
|
|
725
|
+
const isValid = validateContentTags(contentToValidate);
|
|
726
|
+
setIsContentValid(isValid);
|
|
727
|
+
|
|
728
|
+
// Check if content is valid before updating preview
|
|
729
|
+
if (!isValid) {
|
|
730
|
+
CapNotification.error({
|
|
731
|
+
message: formatMessage(messages.contentInvalid),
|
|
732
|
+
});
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
|
|
533
736
|
try {
|
|
534
737
|
// Include unsubscribe tag if content contains it
|
|
535
738
|
const resolvedTags = { ...customValues };
|
|
@@ -559,9 +762,20 @@ const TestAndPreviewSlidebox = (props) => {
|
|
|
559
762
|
const currentTabData = formData[currentTab - 1];
|
|
560
763
|
const activeTab = currentTabData?.activeTab;
|
|
561
764
|
const templateContent = currentTabData?.[activeTab]?.['template-content'];
|
|
765
|
+
const content = templateContent || getCurrentContent;
|
|
766
|
+
|
|
767
|
+
// Validate content tags before extracting
|
|
768
|
+
const isValid = validateContentTags(content);
|
|
769
|
+
setIsContentValid(isValid);
|
|
770
|
+
|
|
771
|
+
if (!isValid) {
|
|
772
|
+
CapNotification.error({
|
|
773
|
+
message: formatMessage(messages.contentInvalid),
|
|
774
|
+
});
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
562
777
|
|
|
563
778
|
// Check for personalization tags (excluding unsubscribe)
|
|
564
|
-
const content = templateContent || getCurrentContent;
|
|
565
779
|
const tags = content.match(/{{[^}]+}}/g) || [];
|
|
566
780
|
const hasPersonalizationTags = tags.some(tag => !tag.includes('unsubscribe'));
|
|
567
781
|
|
|
@@ -590,6 +804,22 @@ const TestAndPreviewSlidebox = (props) => {
|
|
|
590
804
|
};
|
|
591
805
|
|
|
592
806
|
const handleSendTestMessage = () => {
|
|
807
|
+
// Re-validate content to get latest state (in case liquid errors were fixed)
|
|
808
|
+
const currentTabData = formData[currentTab - 1];
|
|
809
|
+
const activeTab = currentTabData?.activeTab;
|
|
810
|
+
const templateContent = currentTabData?.[activeTab]?.['template-content'];
|
|
811
|
+
const contentToValidate = templateContent || getCurrentContent;
|
|
812
|
+
const isValid = validateContentTags(contentToValidate);
|
|
813
|
+
setIsContentValid(isValid);
|
|
814
|
+
|
|
815
|
+
// Check if content is valid before sending test message
|
|
816
|
+
if (!isValid) {
|
|
817
|
+
CapNotification.error({
|
|
818
|
+
message: formatMessage(messages.contentInvalid),
|
|
819
|
+
});
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
|
|
593
823
|
const allUserIds = [];
|
|
594
824
|
selectedTestEntities.forEach((entityId) => {
|
|
595
825
|
const group = testGroups.find((g) => g.groupId === entityId);
|
|
@@ -685,6 +915,7 @@ const TestAndPreviewSlidebox = (props) => {
|
|
|
685
915
|
formData={formData}
|
|
686
916
|
isSendingTestMessage={isSendingTestMessage}
|
|
687
917
|
formatMessage={formatMessage}
|
|
918
|
+
isContentValid={isContentValid}
|
|
688
919
|
/>
|
|
689
920
|
);
|
|
690
921
|
|
|
@@ -144,4 +144,12 @@ export default defineMessages({
|
|
|
144
144
|
id: `${scope}.invalidJSON`,
|
|
145
145
|
defaultMessage: 'Invalid JSON input',
|
|
146
146
|
},
|
|
147
|
+
contentInvalid: {
|
|
148
|
+
id: `${scope}.contentInvalid`,
|
|
149
|
+
defaultMessage: 'Content is invalid. Please fix the tags in your content before testing or previewing.',
|
|
150
|
+
},
|
|
151
|
+
previewUpdateError: {
|
|
152
|
+
id: `${scope}.previewUpdateError`,
|
|
153
|
+
defaultMessage: 'Failed to update preview',
|
|
154
|
+
},
|
|
147
155
|
});
|
|
@@ -54,7 +54,6 @@ import { v2ViberSagas } from '../Viber/sagas';
|
|
|
54
54
|
import { v2FacebookSagas } from '../Facebook/sagas';
|
|
55
55
|
import createReducer from '../Line/Container/reducer';
|
|
56
56
|
import { DAEMON } from '@capillarytech/vulcan-react-sdk/utils/sagaInjectorTypes';
|
|
57
|
-
import {CAPILLARY_LOADING_LOGO} from '../../constants/unified';
|
|
58
57
|
const gtm = window.dataLayer || [];
|
|
59
58
|
const {
|
|
60
59
|
logNewTab,
|
|
@@ -511,12 +510,8 @@ export class Cap extends React.Component { // eslint-disable-line react/prefer-s
|
|
|
511
510
|
<div className="cap-loader-box">
|
|
512
511
|
<img
|
|
513
512
|
className="loader-image"
|
|
514
|
-
src=
|
|
515
|
-
alt="Capillary"
|
|
516
|
-
loading="lazy"
|
|
517
|
-
data-testid="capillary-logo"
|
|
518
|
-
aria-label="Capillary loading logo"
|
|
519
|
-
/>
|
|
513
|
+
src="https://s3.amazonaws.com/fileservice.in/intouch_creative_assets/88561f46de9407021cad.gif"
|
|
514
|
+
alt="Capillary"/>
|
|
520
515
|
</div> : <>
|
|
521
516
|
<Helmet
|
|
522
517
|
titleTemplate="Capillary - %s"
|
|
@@ -14,7 +14,6 @@ import LoginForm from './components/LoginForm';
|
|
|
14
14
|
import * as actions from '../Cap/actions';
|
|
15
15
|
import { UserIsNotAuthenticated } from '../../utils/authWrapper';
|
|
16
16
|
const logo = require('./assets/images/capillary_logo.png');
|
|
17
|
-
import {CAPILLARY_LOADING_LOGO} from '../../constants/unified';
|
|
18
17
|
|
|
19
18
|
export class Login extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
|
20
19
|
constructor(props) {
|
|
@@ -66,12 +65,8 @@ export class Login extends React.Component { // eslint-disable-line react/prefer
|
|
|
66
65
|
? <div className="cap-loader-box">
|
|
67
66
|
<img
|
|
68
67
|
className="loader-image"
|
|
69
|
-
src={
|
|
70
|
-
alt="Capillary"
|
|
71
|
-
loading="lazy"
|
|
72
|
-
data-testid="capillary-logo"
|
|
73
|
-
aria-label="Capillary loading logo"
|
|
74
|
-
/>
|
|
68
|
+
src={"https://storage.crm.n.content-cdn.io/capillary/capillary_loading_logo.gif"}
|
|
69
|
+
alt="Capillary"/>
|
|
75
70
|
</div>
|
|
76
71
|
: <Col className="login-box" style={{textAlign: 'center'}}>
|
|
77
72
|
<h2 className="ui image header">
|
|
@@ -611,6 +611,9 @@ export const Rcs = (props) => {
|
|
|
611
611
|
|
|
612
612
|
useEffect(() => {
|
|
613
613
|
if (templateType === contentType.text_message) {
|
|
614
|
+
setTemplateMediaType(RCS_MEDIA_TYPES.NONE);
|
|
615
|
+
setTemplateTitle('');
|
|
616
|
+
setTemplateTitleError('');
|
|
614
617
|
if (!isEditFlow && isFullMode) {
|
|
615
618
|
setUpdateRcsImageSrc('');
|
|
616
619
|
setUpdateRcsVideoSrc({});
|
|
@@ -631,6 +634,7 @@ export const Rcs = (props) => {
|
|
|
631
634
|
updateRcsImageSrc('');
|
|
632
635
|
setRcsThumbnailSrc('');
|
|
633
636
|
}
|
|
637
|
+
onTemplateDescChange({ target: { value: templateDesc } });
|
|
634
638
|
}, [templateType, isEditFlow, isFullMode]);
|
|
635
639
|
|
|
636
640
|
useEffect(() => {
|
|
@@ -875,9 +879,16 @@ export const Rcs = (props) => {
|
|
|
875
879
|
};
|
|
876
880
|
|
|
877
881
|
const onTemplateDescChange = ({ target: { value } }) => {
|
|
878
|
-
|
|
882
|
+
let errorMessage = false;
|
|
883
|
+
if(templateType === contentType.text_message && value?.length > RCS_TEXT_MESSAGE_MAX_LENGTH){
|
|
884
|
+
errorMessage = formatMessage(messages.templateMessageLengthError);
|
|
885
|
+
} else if(templateType === contentType.rich_card && value?.length > RCS_RICH_CARD_MAX_LENGTH){
|
|
886
|
+
errorMessage = formatMessage(messages.templateMessageLengthError);
|
|
887
|
+
} else {
|
|
888
|
+
errorMessage = false;
|
|
889
|
+
}
|
|
879
890
|
const varError = variableErrorHandling(value);
|
|
880
|
-
const error =
|
|
891
|
+
const error = errorMessage || varError;
|
|
881
892
|
setTemplateDesc(value);
|
|
882
893
|
setTemplateDescError(error);
|
|
883
894
|
};
|
|
@@ -900,7 +911,7 @@ export const Rcs = (props) => {
|
|
|
900
911
|
if (value === '' && isMediaTypeText) {
|
|
901
912
|
errorMessage = formatMessage(messages.emptyTemplateDescErrorMessage);
|
|
902
913
|
} else if (value?.length > maxLength) {
|
|
903
|
-
errorMessage = formatMessage(messages.
|
|
914
|
+
errorMessage = formatMessage(messages.templateMessageLengthError);
|
|
904
915
|
}
|
|
905
916
|
|
|
906
917
|
if (isBraceError) {
|
|
@@ -127,7 +127,7 @@ export default defineMessages({
|
|
|
127
127
|
},
|
|
128
128
|
templateHeaderLengthError: {
|
|
129
129
|
id: `${prefix}.templateHeaderLengthError`,
|
|
130
|
-
defaultMessage: '
|
|
130
|
+
defaultMessage: 'Title text exceeds the character limit.',
|
|
131
131
|
},
|
|
132
132
|
emptyTemplateMessageErrorMessage: {
|
|
133
133
|
id: `${prefix}.emptyTemplateMessageErrorMessage`,
|
|
@@ -242,10 +242,6 @@ export default defineMessages({
|
|
|
242
242
|
id: `${prefix}.carousel`,
|
|
243
243
|
defaultMessage: 'carousel',
|
|
244
244
|
},
|
|
245
|
-
templateDescLengthError: {
|
|
246
|
-
id: `${prefix}.templateDescLengthError`,
|
|
247
|
-
defaultMessage: 'Template message length cannot exceed {maxLength} characters',
|
|
248
|
-
},
|
|
249
245
|
rcsDoneBtnToolTip: {
|
|
250
246
|
id: `${prefix}.rcsDoneBtnToolTip`,
|
|
251
247
|
defaultMessage: 'Please add template name {type} to proceed further',
|
|
@@ -64825,7 +64825,7 @@ new message content.",
|
|
|
64825
64825
|
className="rcs-template-title-input rcs-edit-disabled"
|
|
64826
64826
|
data-testid="template_title"
|
|
64827
64827
|
disabled={false}
|
|
64828
|
-
errorMessage=
|
|
64828
|
+
errorMessage=""
|
|
64829
64829
|
labelPosition="top"
|
|
64830
64830
|
onChange={[Function]}
|
|
64831
64831
|
size="default"
|
|
@@ -64834,13 +64834,13 @@ new message content.",
|
|
|
64834
64834
|
<ComponentWithLabelHOC__CapComponentStyled
|
|
64835
64835
|
className="component-with-label rcs-template-title-input rcs-edit-disabled"
|
|
64836
64836
|
disabled={false}
|
|
64837
|
-
errorMessage=
|
|
64837
|
+
errorMessage=""
|
|
64838
64838
|
labelPosition="top"
|
|
64839
64839
|
>
|
|
64840
64840
|
<div
|
|
64841
64841
|
className="ComponentWithLabelHOC__CapComponentStyled-sc-1qk6bpg-0 kOOkix component-with-label rcs-template-title-input rcs-edit-disabled"
|
|
64842
64842
|
disabled={false}
|
|
64843
|
-
errorMessage=
|
|
64843
|
+
errorMessage=""
|
|
64844
64844
|
labelPosition="top"
|
|
64845
64845
|
>
|
|
64846
64846
|
<ComponentWithLabelHOC__ComponentWithLabelWrapper
|
|
@@ -64853,7 +64853,7 @@ new message content.",
|
|
|
64853
64853
|
<CapInput
|
|
64854
64854
|
data-testid="template_title"
|
|
64855
64855
|
disabled={false}
|
|
64856
|
-
errorMessage=
|
|
64856
|
+
errorMessage=""
|
|
64857
64857
|
onChange={[Function]}
|
|
64858
64858
|
size="default"
|
|
64859
64859
|
value=""
|
|
@@ -78317,7 +78317,7 @@ new message content.",
|
|
|
78317
78317
|
className="rcs-template-title-input rcs-edit-disabled"
|
|
78318
78318
|
data-testid="template_title"
|
|
78319
78319
|
disabled={false}
|
|
78320
|
-
errorMessage=
|
|
78320
|
+
errorMessage=""
|
|
78321
78321
|
labelPosition="top"
|
|
78322
78322
|
onChange={[Function]}
|
|
78323
78323
|
size="default"
|
|
@@ -78326,13 +78326,13 @@ new message content.",
|
|
|
78326
78326
|
<ComponentWithLabelHOC__CapComponentStyled
|
|
78327
78327
|
className="component-with-label rcs-template-title-input rcs-edit-disabled"
|
|
78328
78328
|
disabled={false}
|
|
78329
|
-
errorMessage=
|
|
78329
|
+
errorMessage=""
|
|
78330
78330
|
labelPosition="top"
|
|
78331
78331
|
>
|
|
78332
78332
|
<div
|
|
78333
78333
|
className="ComponentWithLabelHOC__CapComponentStyled-sc-1qk6bpg-0 kOOkix component-with-label rcs-template-title-input rcs-edit-disabled"
|
|
78334
78334
|
disabled={false}
|
|
78335
|
-
errorMessage=
|
|
78335
|
+
errorMessage=""
|
|
78336
78336
|
labelPosition="top"
|
|
78337
78337
|
>
|
|
78338
78338
|
<ComponentWithLabelHOC__ComponentWithLabelWrapper
|
|
@@ -78345,7 +78345,7 @@ new message content.",
|
|
|
78345
78345
|
<CapInput
|
|
78346
78346
|
data-testid="template_title"
|
|
78347
78347
|
disabled={false}
|
|
78348
|
-
errorMessage=
|
|
78348
|
+
errorMessage=""
|
|
78349
78349
|
onChange={[Function]}
|
|
78350
78350
|
size="default"
|
|
78351
78351
|
value=""
|
|
@@ -88907,6 +88907,12 @@ new message content.",
|
|
|
88907
88907
|
Array [
|
|
88908
88908
|
0,
|
|
88909
88909
|
],
|
|
88910
|
+
Array [
|
|
88911
|
+
0,
|
|
88912
|
+
],
|
|
88913
|
+
Array [
|
|
88914
|
+
1,
|
|
88915
|
+
],
|
|
88910
88916
|
],
|
|
88911
88917
|
"results": Array [
|
|
88912
88918
|
Object {
|
|
@@ -88945,6 +88951,14 @@ new message content.",
|
|
|
88945
88951
|
"type": "return",
|
|
88946
88952
|
"value": undefined,
|
|
88947
88953
|
},
|
|
88954
|
+
Object {
|
|
88955
|
+
"type": "return",
|
|
88956
|
+
"value": undefined,
|
|
88957
|
+
},
|
|
88958
|
+
Object {
|
|
88959
|
+
"type": "return",
|
|
88960
|
+
"value": undefined,
|
|
88961
|
+
},
|
|
88948
88962
|
],
|
|
88949
88963
|
},
|
|
88950
88964
|
"createTemplate": [MockFunction],
|
|
@@ -89822,6 +89836,100 @@ new message content.",
|
|
|
89822
89836
|
"id": "creatives.containersV2.Rcs.btnDesc",
|
|
89823
89837
|
},
|
|
89824
89838
|
],
|
|
89839
|
+
Array [
|
|
89840
|
+
Object {
|
|
89841
|
+
"defaultMessage": "Image",
|
|
89842
|
+
"id": "creatives.containersV2.Rcs.mediaImage",
|
|
89843
|
+
},
|
|
89844
|
+
],
|
|
89845
|
+
Array [
|
|
89846
|
+
Object {
|
|
89847
|
+
"defaultMessage": "Video/Slideshow",
|
|
89848
|
+
"id": "creatives.containersV2.Rcs.mediaVideo",
|
|
89849
|
+
},
|
|
89850
|
+
],
|
|
89851
|
+
Array [
|
|
89852
|
+
Object {
|
|
89853
|
+
"defaultMessage": "text message",
|
|
89854
|
+
"id": "creatives.containersV2.Rcs.text_message",
|
|
89855
|
+
},
|
|
89856
|
+
],
|
|
89857
|
+
Array [
|
|
89858
|
+
Object {
|
|
89859
|
+
"defaultMessage": "rich card",
|
|
89860
|
+
"id": "creatives.containersV2.Rcs.richCard",
|
|
89861
|
+
},
|
|
89862
|
+
],
|
|
89863
|
+
Array [
|
|
89864
|
+
Object {
|
|
89865
|
+
"defaultMessage": "Not yet enabled. Coming soon!",
|
|
89866
|
+
"id": "creatives.containersV2.Rcs.disabledCarouselTooltip",
|
|
89867
|
+
},
|
|
89868
|
+
],
|
|
89869
|
+
Array [
|
|
89870
|
+
Object {
|
|
89871
|
+
"defaultMessage": "carousel",
|
|
89872
|
+
"id": "creatives.containersV2.Rcs.carousel",
|
|
89873
|
+
},
|
|
89874
|
+
],
|
|
89875
|
+
Array [
|
|
89876
|
+
Object {
|
|
89877
|
+
"defaultMessage": "Enter template name",
|
|
89878
|
+
"id": "creatives.containersV2.templateNamePlaceholder",
|
|
89879
|
+
},
|
|
89880
|
+
],
|
|
89881
|
+
Array [
|
|
89882
|
+
Object {
|
|
89883
|
+
"defaultMessage": "Creative name",
|
|
89884
|
+
"id": "creatives.containersV2.creativeNameLabel",
|
|
89885
|
+
},
|
|
89886
|
+
],
|
|
89887
|
+
Array [
|
|
89888
|
+
Object {
|
|
89889
|
+
"defaultMessage": "Template Type",
|
|
89890
|
+
"id": "creatives.containersV2.Rcs.templateTypeLabel",
|
|
89891
|
+
},
|
|
89892
|
+
],
|
|
89893
|
+
Array [
|
|
89894
|
+
Object {
|
|
89895
|
+
"defaultMessage": "Text message",
|
|
89896
|
+
"id": "creatives.containersV2.Rcs.templateDescLabel",
|
|
89897
|
+
},
|
|
89898
|
+
],
|
|
89899
|
+
Array [
|
|
89900
|
+
Object {
|
|
89901
|
+
"defaultMessage": "Add variables",
|
|
89902
|
+
"id": "creatives.containersV2.Rcs.addVar",
|
|
89903
|
+
},
|
|
89904
|
+
],
|
|
89905
|
+
Array [
|
|
89906
|
+
Object {
|
|
89907
|
+
"defaultMessage": "Enter the text message",
|
|
89908
|
+
"id": "creatives.containersV2.Rcs.templateDescPlaceholder",
|
|
89909
|
+
},
|
|
89910
|
+
],
|
|
89911
|
+
Array [
|
|
89912
|
+
Object {
|
|
89913
|
+
"defaultMessage": "Characters count: {currentLength}/{maxLength}",
|
|
89914
|
+
"id": "creatives.containersV2.Rcs.templateMessageLength",
|
|
89915
|
+
},
|
|
89916
|
+
Object {
|
|
89917
|
+
"currentLength": 0,
|
|
89918
|
+
"maxLength": 160,
|
|
89919
|
+
},
|
|
89920
|
+
],
|
|
89921
|
+
Array [
|
|
89922
|
+
Object {
|
|
89923
|
+
"defaultMessage": "Buttons",
|
|
89924
|
+
"id": "creatives.containersV2.Rcs.btnLabel",
|
|
89925
|
+
},
|
|
89926
|
+
],
|
|
89927
|
+
Array [
|
|
89928
|
+
Object {
|
|
89929
|
+
"defaultMessage": "Use buttons to redirect user to respective link or quick response/ action.",
|
|
89930
|
+
"id": "creatives.containersV2.Rcs.btnDesc",
|
|
89931
|
+
},
|
|
89932
|
+
],
|
|
89825
89933
|
],
|
|
89826
89934
|
"results": Array [
|
|
89827
89935
|
Object {
|
|
@@ -90344,6 +90452,66 @@ new message content.",
|
|
|
90344
90452
|
"type": "return",
|
|
90345
90453
|
"value": undefined,
|
|
90346
90454
|
},
|
|
90455
|
+
Object {
|
|
90456
|
+
"type": "return",
|
|
90457
|
+
"value": undefined,
|
|
90458
|
+
},
|
|
90459
|
+
Object {
|
|
90460
|
+
"type": "return",
|
|
90461
|
+
"value": undefined,
|
|
90462
|
+
},
|
|
90463
|
+
Object {
|
|
90464
|
+
"type": "return",
|
|
90465
|
+
"value": undefined,
|
|
90466
|
+
},
|
|
90467
|
+
Object {
|
|
90468
|
+
"type": "return",
|
|
90469
|
+
"value": undefined,
|
|
90470
|
+
},
|
|
90471
|
+
Object {
|
|
90472
|
+
"type": "return",
|
|
90473
|
+
"value": undefined,
|
|
90474
|
+
},
|
|
90475
|
+
Object {
|
|
90476
|
+
"type": "return",
|
|
90477
|
+
"value": undefined,
|
|
90478
|
+
},
|
|
90479
|
+
Object {
|
|
90480
|
+
"type": "return",
|
|
90481
|
+
"value": undefined,
|
|
90482
|
+
},
|
|
90483
|
+
Object {
|
|
90484
|
+
"type": "return",
|
|
90485
|
+
"value": undefined,
|
|
90486
|
+
},
|
|
90487
|
+
Object {
|
|
90488
|
+
"type": "return",
|
|
90489
|
+
"value": undefined,
|
|
90490
|
+
},
|
|
90491
|
+
Object {
|
|
90492
|
+
"type": "return",
|
|
90493
|
+
"value": undefined,
|
|
90494
|
+
},
|
|
90495
|
+
Object {
|
|
90496
|
+
"type": "return",
|
|
90497
|
+
"value": undefined,
|
|
90498
|
+
},
|
|
90499
|
+
Object {
|
|
90500
|
+
"type": "return",
|
|
90501
|
+
"value": undefined,
|
|
90502
|
+
},
|
|
90503
|
+
Object {
|
|
90504
|
+
"type": "return",
|
|
90505
|
+
"value": undefined,
|
|
90506
|
+
},
|
|
90507
|
+
Object {
|
|
90508
|
+
"type": "return",
|
|
90509
|
+
"value": undefined,
|
|
90510
|
+
},
|
|
90511
|
+
Object {
|
|
90512
|
+
"type": "return",
|
|
90513
|
+
"value": undefined,
|
|
90514
|
+
},
|
|
90347
90515
|
],
|
|
90348
90516
|
},
|
|
90349
90517
|
}
|
|
@@ -97024,7 +97192,6 @@ new message content.",
|
|
|
97024
97192
|
Object {
|
|
97025
97193
|
"rcsPreviewContent": Object {
|
|
97026
97194
|
"rcsDesc": "",
|
|
97027
|
-
"rcsImageSrc": "",
|
|
97028
97195
|
"rcsSuggestions": Array [
|
|
97029
97196
|
Object {
|
|
97030
97197
|
"index": 0,
|
|
@@ -97037,7 +97204,6 @@ new message content.",
|
|
|
97037
97204
|
},
|
|
97038
97205
|
],
|
|
97039
97206
|
"rcsTitle": "",
|
|
97040
|
-
"rcsVideoSrc": "",
|
|
97041
97207
|
},
|
|
97042
97208
|
}
|
|
97043
97209
|
}
|
|
@@ -97051,7 +97217,6 @@ new message content.",
|
|
|
97051
97217
|
Object {
|
|
97052
97218
|
"rcsPreviewContent": Object {
|
|
97053
97219
|
"rcsDesc": "",
|
|
97054
|
-
"rcsImageSrc": "",
|
|
97055
97220
|
"rcsSuggestions": Array [
|
|
97056
97221
|
Object {
|
|
97057
97222
|
"index": 0,
|
|
@@ -97064,7 +97229,6 @@ new message content.",
|
|
|
97064
97229
|
},
|
|
97065
97230
|
],
|
|
97066
97231
|
"rcsTitle": "",
|
|
97067
|
-
"rcsVideoSrc": "",
|
|
97068
97232
|
},
|
|
97069
97233
|
}
|
|
97070
97234
|
}
|