@capillarytech/creatives-library 9.0.36-alpha.0 → 9.0.36
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/app.js +175 -10
- package/entry.js +1 -67
- package/mfe-exposed-components.js +4 -2
- package/package.json +2 -2
- package/services/api.js +1 -9
- package/styles/containers/layout/_layoutPage.scss +6 -8
- package/utils/gtmTrackers/gtmEvents/creativeDetails.js +1 -2
- package/utils/rcsPayloadUtils.js +2 -5
- package/utils/tests/rcsPayloadUtils.test.js +2 -54
- package/v2Components/CapActionButton/constants.js +0 -1
- package/v2Components/CapActionButton/index.js +9 -77
- package/v2Components/CapActionButton/index.scss +0 -13
- package/v2Components/CapActionButton/messages.js +0 -13
- package/v2Components/CapActionButton/tests/index.test.js +1 -32
- package/v2Components/CommonTestAndPreview/UnifiedPreview/ViberPreviewContent.js +15 -108
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +1 -139
- package/v2Components/CommonTestAndPreview/index.js +41 -284
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/ViberPreviewContent.test.js +0 -364
- package/v2Components/CommonTestAndPreview/tests/index.test.js +0 -78
- package/v2Components/CommonTestAndPreview/utils.js +0 -34
- package/v2Components/NavigationBar/index.js +7 -9
- package/v2Components/NavigationBar/tests/index.test.js +19 -39
- package/v2Components/SmsFallback/index.js +0 -6
- package/v2Containers/Cap/constants.js +0 -1
- package/v2Containers/Cap/index.js +27 -57
- package/v2Containers/CreativesContainer/index.js +8 -11
- package/v2Containers/CreativesContainer/tests/index.test.js +0 -53
- package/v2Containers/Rcs/carouselUtils.js +73 -46
- package/v2Containers/Rcs/components/CarouselCard.js +9 -11
- package/v2Containers/Rcs/components/CarouselCardButtons.js +0 -20
- package/v2Containers/Rcs/constants.js +7 -2
- package/v2Containers/Rcs/index.js +205 -226
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +47 -60
- package/v2Containers/Rcs/tests/CarouselCard.test.js +2 -1
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +0 -286
- package/v2Containers/Rcs/tests/carouselUtils.test.js +32 -28
- package/v2Containers/Rcs/tests/index.test.js +238 -151
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -110
- package/v2Containers/Rcs/tests/utils.test.js +17 -36
- package/v2Containers/Rcs/utils.js +55 -28
- package/v2Containers/SmsTrai/Edit/index.js +24 -35
- package/v2Containers/Templates/_templates.scss +1 -115
- package/v2Containers/Templates/index.js +10 -91
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +0 -5
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +3 -8
- package/v2Containers/TemplatesV2/index.js +9 -22
- package/v2Containers/Viber/constants.js +0 -21
- package/v2Containers/Viber/index.js +49 -719
- package/v2Containers/Viber/index.scss +0 -175
- package/v2Containers/Viber/messages.js +0 -121
- package/v2Containers/Viber/tests/index.test.js +0 -80
- package/AppRoot.js +0 -124
- package/app-config.js +0 -61
- package/bootstrap.js +0 -185
- package/utils/getDataLayer.js +0 -15
- package/utils/mfeDetect.js +0 -1
- package/utils/mfeFirstPaintReady.js +0 -29
- package/utils/mfeHistory.js +0 -62
- package/v2Components/CommonTestAndPreview/UnifiedPreview/ViberCarouselPreviewCards.js +0 -132
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_viberCarouselPreviewCards.scss +0 -131
- package/v2Components/NavigationBar/mfeModuleHeader.config.js +0 -16
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
RCS_NUMERIC_VAR_NAME_REGEX,
|
|
7
7
|
REGEX_SPECIAL_CHARS_ESCAPE_PATTERN,
|
|
8
8
|
RCS_STRIP_MUSTACHE_DELIMITERS_REGEX,
|
|
9
|
-
RCS_MUSTACHE_WRAPPED_REGEX,
|
|
10
9
|
} from './constants';
|
|
11
10
|
import './index.scss';
|
|
12
11
|
// import { formatMessage } from '../../../utils/intl';
|
|
@@ -197,6 +196,50 @@ export function coalesceCardVarMappedToTemplate(
|
|
|
197
196
|
templateVarTokens.forEach((token, slotIndexZeroBased) => {
|
|
198
197
|
const semanticVarName = getVarNameFromToken(token);
|
|
199
198
|
if (!semanticVarName) return;
|
|
199
|
+
|
|
200
|
+
if (RCS_NUMERIC_VAR_NAME_REGEX.test(semanticVarName)) {
|
|
201
|
+
// Carousel numeric placeholder ({{3}}, {{4}}, …): the slot key IS the token digit itself —
|
|
202
|
+
// numbers are allocated globally across the whole carousel (getNextCarouselVarToken), not
|
|
203
|
+
// re-numbered per card, so the position-based `slotIndexZeroBased + 1` key below would target
|
|
204
|
+
// the wrong slot for every card after the first (e.g. card 2's first token is digit "3", not "1").
|
|
205
|
+
const numericSlotKey = semanticVarName;
|
|
206
|
+
const trimmedSlotValue = String(lookupSourceMap[numericSlotKey] ?? '').trim();
|
|
207
|
+
coalescedMap[numericSlotKey] = trimmedSlotValue;
|
|
208
|
+
// The slot's value may itself be a mustache-wrapped tag reference (e.g. "3" -> "{{last_name}}")
|
|
209
|
+
// — mirror it onto the bare semantic key too so VarSegment editors keyed by tag name also
|
|
210
|
+
// prepopulate (same rule as syncCardVarMappedSemanticsFromSlots).
|
|
211
|
+
const mustacheInnerMatch = trimmedSlotValue.match(/^\{\{([^}]+)\}\}$/);
|
|
212
|
+
const innerSemanticName = mustacheInnerMatch?.[1]?.trim();
|
|
213
|
+
if (innerSemanticName && innerSemanticName !== numericSlotKey) {
|
|
214
|
+
const existingInnerValue = String(coalescedMap[innerSemanticName] ?? '').trim();
|
|
215
|
+
if (!existingInnerValue) {
|
|
216
|
+
coalescedMap[innerSemanticName] = trimmedSlotValue;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// A numeric slot may already self-reference this exact tag (e.g. "4" -> "{{last_name}}") when
|
|
223
|
+
// the template's own numeric placeholder has since been resolved to this tag in the text (see
|
|
224
|
+
// mapRcsCardContentForConsumerWithResolvedTags). That numeric key is the source of truth — don't
|
|
225
|
+
// fall through to the position-based legacy lookup below, which targets an unrelated (or
|
|
226
|
+
// nonexistent) slot and would clobber the real value with an empty string.
|
|
227
|
+
const mustacheSelfReference = `{{${semanticVarName}}}`;
|
|
228
|
+
const existingNumericKeyForSemantic = Object.keys(lookupSourceMap).find((key) => (
|
|
229
|
+
RCS_NUMERIC_VAR_NAME_REGEX.test(key) && lookupSourceMap[key] === mustacheSelfReference
|
|
230
|
+
));
|
|
231
|
+
if (existingNumericKeyForSemantic) {
|
|
232
|
+
const trimmedSlotValue = String(lookupSourceMap[existingNumericKeyForSemantic] ?? '').trim();
|
|
233
|
+
coalescedMap[existingNumericKeyForSemantic] = trimmedSlotValue;
|
|
234
|
+
if (!seenSemanticVarNames.has(semanticVarName)) {
|
|
235
|
+
seenSemanticVarNames.add(semanticVarName);
|
|
236
|
+
coalescedMap[semanticVarName] = trimmedSlotValue;
|
|
237
|
+
}
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Legacy: template embeds the semantic token directly ({{user_name}}); older payloads stored
|
|
242
|
+
// the resolved value under a position-based numeric key ("1", "2", …) by order of appearance.
|
|
200
243
|
const numericSlotKey = String(slotIndexZeroBased + 1);
|
|
201
244
|
const isRepeatOfSemanticName = seenSemanticVarNames.has(semanticVarName);
|
|
202
245
|
const skipSharedSemanticLookup =
|
|
@@ -207,12 +250,6 @@ export function coalesceCardVarMappedToTemplate(
|
|
|
207
250
|
valueFromSource = lookupSourceMap[semanticVarName];
|
|
208
251
|
}
|
|
209
252
|
}
|
|
210
|
-
if (valueFromSource === undefined || valueFromSource === null) {
|
|
211
|
-
valueFromSource = lookupSourceMap[String(slotIndexZeroBased + 1)];
|
|
212
|
-
}
|
|
213
|
-
if (valueFromSource === undefined || valueFromSource === null) {
|
|
214
|
-
valueFromSource = lookupSourceMap[slotIndexZeroBased + 1];
|
|
215
|
-
}
|
|
216
253
|
const trimmedSlotValue = valueFromSource == null ? '' : String(valueFromSource).trim();
|
|
217
254
|
coalescedMap[numericSlotKey] = trimmedSlotValue;
|
|
218
255
|
if (!seenSemanticVarNames.has(semanticVarName)) {
|
|
@@ -291,11 +328,6 @@ export function isRcsTextOnlyCardMediaType(mediaType) {
|
|
|
291
328
|
*
|
|
292
329
|
* @param {boolean} [preserveLiteralValueTokens=false] When true, a slot value that is NOT itself a
|
|
293
330
|
* `{{...}}`-wrapped tag (e.g. a literal preview string like "SAVE20" typed for a voucher/offer tag)
|
|
294
|
-
* is left as the raw token instead of being baked into the returned string. Personalization-style
|
|
295
|
-
* values (themselves another mustache tag, e.g. `{{loyalty_points}}`) still resolve either way — those
|
|
296
|
-
* are internal-alias renames, not literal content. Pass true for payloads that get persisted/replayed
|
|
297
|
-
* (see `mapRcsCardContentForConsumerWithResolvedTags`) so a voucher's saved token survives for the
|
|
298
|
-
* editor to re-render an editable slot from, and for the backend to resolve per-recipient at send time.
|
|
299
331
|
*
|
|
300
332
|
* @param {number} [cardSlotOffset=0] Starting global slot index for this card's title. Carousel cards
|
|
301
333
|
* beyond index 0 must pass the running total of every prior card's var count — numeric `{{N}}` tokens
|
|
@@ -309,8 +341,6 @@ export function resolveRcsCardPreviewStrings(
|
|
|
309
341
|
cardVarMapped,
|
|
310
342
|
isLibraryMode = false,
|
|
311
343
|
textOnlyCard = false,
|
|
312
|
-
preserveLiteralValueTokens = false,
|
|
313
|
-
cardSlotOffset = 0,
|
|
314
344
|
) {
|
|
315
345
|
const splitTemplateVarStringRcs = (str) => splitTemplateVarString(str, rcsVarRegex);
|
|
316
346
|
const getVarNameFromToken = (token = '') =>
|
|
@@ -339,7 +369,12 @@ export function resolveRcsCardPreviewStrings(
|
|
|
339
369
|
);
|
|
340
370
|
if (slotValue == null || String(slotValue).trim() === '') return elem;
|
|
341
371
|
const trimmedSlotValue = String(slotValue).trim();
|
|
342
|
-
|
|
372
|
+
const isPlainNumericSlot = RCS_NUMERIC_VAR_NAME_REGEX.test(key);
|
|
373
|
+
if (
|
|
374
|
+
preserveLiteralValueTokens
|
|
375
|
+
&& !isPlainNumericSlot
|
|
376
|
+
&& !RCS_MUSTACHE_WRAPPED_REGEX.test(trimmedSlotValue)
|
|
377
|
+
) {
|
|
343
378
|
return elem;
|
|
344
379
|
}
|
|
345
380
|
return String(slotValue);
|
|
@@ -354,8 +389,8 @@ export function resolveRcsCardPreviewStrings(
|
|
|
354
389
|
? 0
|
|
355
390
|
: (effectiveTitle.match(rcsVarRegex) || []).length;
|
|
356
391
|
return {
|
|
357
|
-
rcsTitle: textOnlyCard ? '' : resolveTemplateWithMap(effectiveTitle,
|
|
358
|
-
rcsDesc: resolveTemplateWithMap(String(description || ''),
|
|
392
|
+
rcsTitle: textOnlyCard ? '' : resolveTemplateWithMap(effectiveTitle, 0),
|
|
393
|
+
rcsDesc: resolveTemplateWithMap(String(description || ''), titleVarCount),
|
|
359
394
|
};
|
|
360
395
|
}
|
|
361
396
|
|
|
@@ -376,7 +411,6 @@ export function mapRcsCardContentForConsumerWithResolvedTags(
|
|
|
376
411
|
: {};
|
|
377
412
|
const list = Array.isArray(cardContentArray) ? cardContentArray : [];
|
|
378
413
|
const isLibraryMode = isFullMode !== true;
|
|
379
|
-
let carouselSlotOffset = 0;
|
|
380
414
|
return list.map((card) => {
|
|
381
415
|
if (!card || typeof card !== 'object') return card;
|
|
382
416
|
const nested =
|
|
@@ -387,22 +421,15 @@ export function mapRcsCardContentForConsumerWithResolvedTags(
|
|
|
387
421
|
const nestedClean = pickRcsCardVarMappedEntries(nested);
|
|
388
422
|
const merged = { ...rootClean, ...nestedClean };
|
|
389
423
|
const textOnly = isRcsTextOnlyCardMediaType(card.mediaType);
|
|
390
|
-
const cardTitle = card.title ?? '';
|
|
391
|
-
const cardDescription = card.description ?? '';
|
|
392
424
|
const { rcsTitle, rcsDesc } = resolveRcsCardPreviewStrings(
|
|
393
|
-
|
|
394
|
-
|
|
425
|
+
card.title ?? '',
|
|
426
|
+
card.description ?? '',
|
|
395
427
|
merged,
|
|
396
428
|
isLibraryMode,
|
|
397
429
|
textOnly,
|
|
398
|
-
true,
|
|
399
|
-
carouselSlotOffset,
|
|
400
430
|
);
|
|
401
|
-
const effectiveTitleForCount = textOnly ? '' : String(cardTitle);
|
|
402
|
-
const titleVarCount = (effectiveTitleForCount.match(rcsVarRegex) || []).length;
|
|
403
|
-
const descVarCount = (String(cardDescription).match(rcsVarRegex) || []).length;
|
|
404
|
-
carouselSlotOffset += titleVarCount + descVarCount;
|
|
405
431
|
const { cardVarMapped: _drop, ...cardRest } = card;
|
|
432
|
+
|
|
406
433
|
return {
|
|
407
434
|
...cardRest,
|
|
408
435
|
title: rcsTitle,
|
|
@@ -169,11 +169,12 @@ export const SmsTraiEdit = (props) => {
|
|
|
169
169
|
return traiDltEnabled || hasTraiDltFeature() || isRcsEditFlow;
|
|
170
170
|
}, [isRcsSmsFallback, traiDltEnabled, isRcsEditFlow]);
|
|
171
171
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
172
|
+
/**
|
|
173
|
+
* RCS SMS fallback: always show character count vs TRAI max (`SMS_TRAI_CONTENT_MAX_LENGTH`).
|
|
174
|
+
* Do not use `totalCharacters` ({smsCount} SMS via length/160) here: resolved template + variable
|
|
175
|
+
* values can exceed one GSM segment while DLT still shows a single registered template — length/160
|
|
176
|
+
* is only a rough segment hint and reads as “wrong SMS count” in campaigns.
|
|
177
|
+
*/
|
|
177
178
|
const renderDescriptionCharacterCount = (className = "rcs-character-count") => (
|
|
178
179
|
<CapLabel type="label1" className={className}>
|
|
179
180
|
{formatMessage(messages.charactersCountLabel, {
|
|
@@ -195,24 +196,18 @@ export const SmsTraiEdit = (props) => {
|
|
|
195
196
|
};
|
|
196
197
|
|
|
197
198
|
const renderRcsFallbackMessage = (str = '') => {
|
|
198
|
-
if (!
|
|
199
|
+
if (!useRcsFallbackVarSegment) {
|
|
199
200
|
return (
|
|
200
201
|
<CapRow className="rcs-create-template-message-input">
|
|
201
202
|
<div className="rcs_text_area_wrapper">
|
|
202
|
-
<
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
if (hasVarToken) setRcsFallbackVarSegmentModeActive(true);
|
|
211
|
-
}}
|
|
212
|
-
placeholder={formatMessage(rcsMessages.fallbackMsgPlaceholder)}
|
|
213
|
-
data-testid="rcs_fallback_plain_text_area"
|
|
214
|
-
/>
|
|
215
|
-
</div>
|
|
203
|
+
<TextArea
|
|
204
|
+
id="rcs_fallback_message_textarea"
|
|
205
|
+
autosize={{ minRows: 4, maxRows: 12 }}
|
|
206
|
+
value={fallbackText}
|
|
207
|
+
onChange={(e) => setFallbackText(e.target.value)}
|
|
208
|
+
placeholder={formatMessage(rcsMessages.fallbackMsgPlaceholder)}
|
|
209
|
+
data-testid="rcs_fallback_plain_text_area"
|
|
210
|
+
/>
|
|
216
211
|
{renderDescriptionCharacterCount()}
|
|
217
212
|
</div>
|
|
218
213
|
</CapRow>
|
|
@@ -367,9 +362,7 @@ export const SmsTraiEdit = (props) => {
|
|
|
367
362
|
const templateBase = get(activeTemplateSourceForInit, 'versions.base', {});
|
|
368
363
|
const unicodeValidity = get(templateBase, 'unicode-validity', true);
|
|
369
364
|
const templateMsg = get(activeTemplateSourceForInit, 'versions.base.sms-editor', '') || '';
|
|
370
|
-
|
|
371
|
-
setRcsFallbackVarSegmentModeActive(templateMsgHasVarToken);
|
|
372
|
-
if (!templateMsgHasVarToken) {
|
|
365
|
+
if (!useRcsFallbackVarSegment) {
|
|
373
366
|
setFallbackText(templateMsg);
|
|
374
367
|
setFallbackVarMappedData({});
|
|
375
368
|
setUpdatedSmsEditor(String(templateMsg).split(''));
|
|
@@ -436,7 +429,7 @@ export const SmsTraiEdit = (props) => {
|
|
|
436
429
|
|
|
437
430
|
useEffect(() => {
|
|
438
431
|
if (!isRcsSmsFallback) return;
|
|
439
|
-
if (!
|
|
432
|
+
if (!useRcsFallbackVarSegment) {
|
|
440
433
|
const plainFallbackSmsText = fallbackText || '';
|
|
441
434
|
setUpdatedSmsEditor(plainFallbackSmsText.split(''));
|
|
442
435
|
setTotalMessageLength(plainFallbackSmsText.length);
|
|
@@ -448,17 +441,15 @@ export const SmsTraiEdit = (props) => {
|
|
|
448
441
|
);
|
|
449
442
|
setUpdatedSmsEditor(resolvedFallbackDisplay.split(''));
|
|
450
443
|
setTotalMessageLength(resolvedFallbackDisplay.length);
|
|
451
|
-
}, [isRcsSmsFallback,
|
|
444
|
+
}, [isRcsSmsFallback, useRcsFallbackVarSegment, fallbackText, fallbackVarMappedData]);
|
|
452
445
|
|
|
453
446
|
useEffect(() => {
|
|
454
447
|
if (!isRcsSmsFallback) return;
|
|
455
|
-
// Skip until hydration populates fallbackVarMappedData, or this wipes the parent's rcsSmsFallbackVarMapped before init restores it.
|
|
456
|
-
if (loading) return;
|
|
457
448
|
if (typeof onRcsFallbackEditorStateChange !== 'function') return;
|
|
458
449
|
onRcsFallbackEditorStateChange({
|
|
459
450
|
rcsSmsFallbackVarMapped: fallbackVarMappedData || {},
|
|
460
451
|
});
|
|
461
|
-
}, [isRcsSmsFallback,
|
|
452
|
+
}, [isRcsSmsFallback, fallbackVarMappedData, onRcsFallbackEditorStateChange]);
|
|
462
453
|
|
|
463
454
|
useEffect(() => {
|
|
464
455
|
if (!isRcsSmsFallback) return;
|
|
@@ -541,7 +532,7 @@ export const SmsTraiEdit = (props) => {
|
|
|
541
532
|
// TRAI/DLT VarSegment: `validateIfTagClosed` only understands paired `{{…}}` and breaks on
|
|
542
533
|
// legitimate `{#…#}` / mixed TRAI shapes (extra `{`/`}` counts). Do not tie Done to it;
|
|
543
534
|
// slot completeness is enforced by `areAllRcsSmsFallbackVarSlotsFilled` on the RCS screen.
|
|
544
|
-
if (
|
|
535
|
+
if (useRcsFallbackVarSegment) {
|
|
545
536
|
tagValidationResponseRef.current = {};
|
|
546
537
|
updateIsTagValidationError(false);
|
|
547
538
|
return;
|
|
@@ -582,7 +573,7 @@ export const SmsTraiEdit = (props) => {
|
|
|
582
573
|
tags,
|
|
583
574
|
isRcsSmsFallback,
|
|
584
575
|
isFullMode,
|
|
585
|
-
|
|
576
|
+
useRcsFallbackVarSegment,
|
|
586
577
|
fallbackText,
|
|
587
578
|
fallbackVarMappedData,
|
|
588
579
|
getDefaultTags,
|
|
@@ -721,8 +712,7 @@ export const SmsTraiEdit = (props) => {
|
|
|
721
712
|
...baseWithoutDerivedFields,
|
|
722
713
|
'sms-editor': fallbackText || '',
|
|
723
714
|
'unicode-validity': isUnicodeAllowed,
|
|
724
|
-
|
|
725
|
-
...(useRcsFallbackVarSegmentForCurrentText && {
|
|
715
|
+
...(useRcsFallbackVarSegment && {
|
|
726
716
|
'rcs-sms-fallback-var-mapped': fallbackVarMappedData || {},
|
|
727
717
|
}),
|
|
728
718
|
};
|
|
@@ -788,9 +778,8 @@ export const SmsTraiEdit = (props) => {
|
|
|
788
778
|
|
|
789
779
|
const onTagSelect = (data) => {
|
|
790
780
|
if (isRcsSmsFallback) {
|
|
791
|
-
if (!
|
|
781
|
+
if (!useRcsFallbackVarSegment) {
|
|
792
782
|
setFallbackText((prev) => `${prev || ''}{{${data}}}`);
|
|
793
|
-
setRcsFallbackVarSegmentModeActive(true);
|
|
794
783
|
return;
|
|
795
784
|
}
|
|
796
785
|
if (!fallbackFocusedId) return;
|
|
@@ -960,7 +949,7 @@ export const SmsTraiEdit = (props) => {
|
|
|
960
949
|
|
|
961
950
|
const calculateTotalMessageLength = () => {
|
|
962
951
|
if (isRcsSmsFallback) {
|
|
963
|
-
if (
|
|
952
|
+
if (useRcsFallbackVarSegment) {
|
|
964
953
|
const resolved = getFallbackResolvedContent(fallbackText || '', fallbackVarMappedData || {});
|
|
965
954
|
setTotalMessageLength(resolved.length);
|
|
966
955
|
} else {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
@import '~@capillarytech/cap-ui-library/styles/_variables.scss';
|
|
2
2
|
|
|
3
3
|
.ant-tabs-content{
|
|
4
|
-
margin-top: $CAP_SPACE_08;
|
|
5
4
|
// .creatives-templates-list.full-mode{
|
|
6
5
|
.v2-pagination-container, .v2-pagination-container-half {
|
|
7
6
|
.ant-tabs-tabpane-active{
|
|
@@ -160,96 +159,6 @@
|
|
|
160
159
|
line-clamp: 3;
|
|
161
160
|
}
|
|
162
161
|
}
|
|
163
|
-
.viber-carousel-static-content {
|
|
164
|
-
width: 100%;
|
|
165
|
-
overflow: hidden;
|
|
166
|
-
.viber-carousel-static-message-box {
|
|
167
|
-
width: 100%;
|
|
168
|
-
height: auto;
|
|
169
|
-
border-radius: $CAP_SPACE_04;
|
|
170
|
-
background: $CAP_WHITE;
|
|
171
|
-
margin-bottom: $CAP_SPACE_08;
|
|
172
|
-
display: flex;
|
|
173
|
-
align-items: flex-start;
|
|
174
|
-
}
|
|
175
|
-
.viber-carousel-static-message {
|
|
176
|
-
display: -webkit-box;
|
|
177
|
-
width: 100%;
|
|
178
|
-
color: $CAP_G01;
|
|
179
|
-
line-height: 1.3;
|
|
180
|
-
overflow: hidden;
|
|
181
|
-
text-overflow: ellipsis;
|
|
182
|
-
-webkit-line-clamp: 2;
|
|
183
|
-
line-clamp: 2;
|
|
184
|
-
-webkit-box-orient: vertical;
|
|
185
|
-
white-space: normal;
|
|
186
|
-
word-break: break-word;
|
|
187
|
-
}
|
|
188
|
-
.viber-carousel-static-cards {
|
|
189
|
-
display: flex;
|
|
190
|
-
gap: $CAP_SPACE_08;
|
|
191
|
-
overflow: hidden;
|
|
192
|
-
}
|
|
193
|
-
.viber-carousel-static-card {
|
|
194
|
-
flex: 1;
|
|
195
|
-
min-width: 0;
|
|
196
|
-
background: $CAP_WHITE;
|
|
197
|
-
border-radius: $CAP_SPACE_04;
|
|
198
|
-
overflow: hidden;
|
|
199
|
-
display: flex;
|
|
200
|
-
flex-direction: column;
|
|
201
|
-
}
|
|
202
|
-
.viber-carousel-static-image {
|
|
203
|
-
width: 100%;
|
|
204
|
-
max-height: 11rem;
|
|
205
|
-
margin-bottom: $CAP_SPACE_04;
|
|
206
|
-
border-radius: $CAP_SPACE_04;
|
|
207
|
-
display: block;
|
|
208
|
-
}
|
|
209
|
-
.viber-carousel-static-image-placeholder {
|
|
210
|
-
width: 100%;
|
|
211
|
-
height: 7.143rem;
|
|
212
|
-
border-radius: $CAP_SPACE_04;
|
|
213
|
-
}
|
|
214
|
-
.viber-carousel-static-image-placeholder {
|
|
215
|
-
background: $CAP_G07;
|
|
216
|
-
}
|
|
217
|
-
.viber-carousel-static-text {
|
|
218
|
-
display: block;
|
|
219
|
-
color: $CAP_G01;
|
|
220
|
-
margin: $CAP_SPACE_04 0;
|
|
221
|
-
line-height: 1.3;
|
|
222
|
-
overflow: hidden;
|
|
223
|
-
text-overflow: ellipsis;
|
|
224
|
-
white-space: normal;
|
|
225
|
-
-webkit-line-clamp: 2;
|
|
226
|
-
line-clamp: 2;
|
|
227
|
-
-webkit-box-orient: vertical;
|
|
228
|
-
display: -webkit-box;
|
|
229
|
-
}
|
|
230
|
-
.viber-carousel-static-buttons {
|
|
231
|
-
display: flex;
|
|
232
|
-
flex-direction: column;
|
|
233
|
-
gap: $CAP_SPACE_04;
|
|
234
|
-
margin-top: auto;
|
|
235
|
-
}
|
|
236
|
-
.viber-carousel-static-button {
|
|
237
|
-
display: block;
|
|
238
|
-
min-height: 1.5rem;
|
|
239
|
-
border-radius: $CAP_SPACE_12;
|
|
240
|
-
background: $CAP_PURPLE01;
|
|
241
|
-
color: $CAP_WHITE;
|
|
242
|
-
text-align: center;
|
|
243
|
-
padding: 0.179rem $CAP_SPACE_08;
|
|
244
|
-
white-space: normal;
|
|
245
|
-
}
|
|
246
|
-
.viber-carousel-static-button-secondary {
|
|
247
|
-
color: $CAP_PURPLE01;
|
|
248
|
-
background: transparent;
|
|
249
|
-
border: none;
|
|
250
|
-
box-shadow: none;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
162
|
|
|
254
163
|
}
|
|
255
164
|
|
|
@@ -258,30 +167,6 @@
|
|
|
258
167
|
word-wrap: break-word;
|
|
259
168
|
}
|
|
260
169
|
}
|
|
261
|
-
|
|
262
|
-
&.viber-carousel-static {
|
|
263
|
-
height: auto;
|
|
264
|
-
min-height: 21.125rem;
|
|
265
|
-
|
|
266
|
-
.ant-card-body {
|
|
267
|
-
padding-bottom: $CAP_SPACE_12;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
.truncate-text-viber {
|
|
271
|
-
.ant-card-meta-description {
|
|
272
|
-
display: block;
|
|
273
|
-
overflow: visible;
|
|
274
|
-
-webkit-line-clamp: unset;
|
|
275
|
-
line-clamp: unset;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
.viber-carousel-static-content,
|
|
280
|
-
.viber-carousel-static-cards,
|
|
281
|
-
.viber-carousel-static-card {
|
|
282
|
-
overflow: visible;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
170
|
|
|
286
171
|
|
|
287
172
|
&.carousel-img-section {
|
|
@@ -1542,6 +1427,7 @@
|
|
|
1542
1427
|
justify-content: space-between;
|
|
1543
1428
|
align-items: center;
|
|
1544
1429
|
gap: $CAP_SPACE_08;
|
|
1430
|
+
margin-right: $CAP_SPACE_32;
|
|
1545
1431
|
}
|
|
1546
1432
|
|
|
1547
1433
|
.template-listing-more-btn {
|
|
@@ -73,7 +73,6 @@ import * as ebillActions from '../Ebill/actions';
|
|
|
73
73
|
import * as emailActions from '../Email/actions';
|
|
74
74
|
import * as lineActions from '../Line/Container/actions';
|
|
75
75
|
import * as viberActions from '../Viber/actions';
|
|
76
|
-
import { VIBER_MEDIA_TYPES } from '../Viber/constants';
|
|
77
76
|
import * as facebookActions from '../Facebook/actions';
|
|
78
77
|
import * as whatsappActions from '../Whatsapp/actions';
|
|
79
78
|
import * as rcsActions from '../Rcs/actions';
|
|
@@ -1397,11 +1396,6 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
1397
1396
|
const image = viberContent.image || {};
|
|
1398
1397
|
const video = viberContent.video || {};
|
|
1399
1398
|
const button = viberContent.button || {};
|
|
1400
|
-
const messageType = viberContent.type || '';
|
|
1401
|
-
const cardsRaw = viberContent.cards;
|
|
1402
|
-
const cards = Array.isArray(cardsRaw) ? cardsRaw : [];
|
|
1403
|
-
const isCarousel =
|
|
1404
|
-
messageType === VIBER_MEDIA_TYPES.CAROUSEL || cards.length > 0;
|
|
1405
1399
|
|
|
1406
1400
|
const viberPreview = {
|
|
1407
1401
|
messageContent: text,
|
|
@@ -1419,39 +1413,14 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
1419
1413
|
};
|
|
1420
1414
|
}
|
|
1421
1415
|
|
|
1422
|
-
if (isCarousel) {
|
|
1423
|
-
viberPreview.type = VIBER_MEDIA_TYPES.CAROUSEL;
|
|
1424
|
-
viberPreview.cards = cards.map((card) => ({
|
|
1425
|
-
text: card?.text || '',
|
|
1426
|
-
mediaUrl: card?.mediaUrl || '',
|
|
1427
|
-
buttons: (card?.buttons || []).map((btn) => ({
|
|
1428
|
-
title: btn?.title || '',
|
|
1429
|
-
action: btn?.action || '',
|
|
1430
|
-
})),
|
|
1431
|
-
}));
|
|
1432
|
-
viberPreview.showCarouselEditorPreview = true;
|
|
1433
|
-
}
|
|
1434
|
-
|
|
1435
1416
|
// Extract account name
|
|
1436
1417
|
const accountName = get(template, 'definition.accountName', '');
|
|
1437
1418
|
|
|
1438
1419
|
// Return Viber content object (same as Viber/index.js getTemplateContent)
|
|
1439
1420
|
return {
|
|
1440
1421
|
viberPreviewContent: viberPreview,
|
|
1441
|
-
accountName: accountName
|
|
1442
|
-
brandName: accountName
|
|
1443
|
-
messageContent: text,
|
|
1444
|
-
...(isCarousel && {
|
|
1445
|
-
type: VIBER_MEDIA_TYPES.CAROUSEL,
|
|
1446
|
-
cards: viberPreview.cards,
|
|
1447
|
-
}),
|
|
1448
|
-
...(!isCarousel && !isEmpty(button) && button.text && (button.url || viberContent.buttonURL) && {
|
|
1449
|
-
button: {
|
|
1450
|
-
text: button.text,
|
|
1451
|
-
url: button.url || viberContent.buttonURL || '',
|
|
1452
|
-
},
|
|
1453
|
-
}),
|
|
1454
|
-
buttonURL: button.url || viberContent.buttonURL || '',
|
|
1422
|
+
accountName: accountName ? [accountName] : [],
|
|
1423
|
+
brandName: accountName ? [accountName] : [],
|
|
1455
1424
|
};
|
|
1456
1425
|
}
|
|
1457
1426
|
|
|
@@ -2472,52 +2441,10 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
2472
2441
|
image = {},
|
|
2473
2442
|
button = {},
|
|
2474
2443
|
video = {},
|
|
2475
|
-
type = '',
|
|
2476
|
-
cards = [],
|
|
2477
2444
|
} = {},
|
|
2478
2445
|
} = {},
|
|
2479
2446
|
} = template.versions.base;
|
|
2480
|
-
const isViberCarousel = type === VIBER_MEDIA_TYPES.CAROUSEL;
|
|
2481
2447
|
templateData.content = text;
|
|
2482
|
-
if (isViberCarousel) {
|
|
2483
|
-
const previewCards = Array.isArray(cards) ? cards.slice(0, 1) : [];
|
|
2484
|
-
templateData.className = 'viber-carousel-static';
|
|
2485
|
-
templateData.content = (
|
|
2486
|
-
<CapRow className="viber-carousel-static-content">
|
|
2487
|
-
<CapRow className="viber-carousel-static-message-box">
|
|
2488
|
-
<CapLabel type="label1" className="viber-carousel-static-message">
|
|
2489
|
-
{text}
|
|
2490
|
-
</CapLabel>
|
|
2491
|
-
</CapRow>
|
|
2492
|
-
<CapRow className="viber-carousel-static-cards">
|
|
2493
|
-
{previewCards.map((card, cardIdx) => (
|
|
2494
|
-
<CapRow className="viber-carousel-static-card" key={`viber-static-card-${cardIdx}`}>
|
|
2495
|
-
{card?.mediaUrl ? (
|
|
2496
|
-
<CapImage src={card.mediaUrl} className="viber-carousel-static-image" />
|
|
2497
|
-
) : (
|
|
2498
|
-
<CapRow className="viber-carousel-static-image-placeholder" />
|
|
2499
|
-
)}
|
|
2500
|
-
<CapLabel type="label1" className="viber-carousel-static-text">
|
|
2501
|
-
{card?.text}
|
|
2502
|
-
</CapLabel>
|
|
2503
|
-
<CapRow className="viber-carousel-static-buttons">
|
|
2504
|
-
{(Array.isArray(card?.buttons) && card.buttons.length ? card.buttons : [{}, {}]).slice(0, 2).map((carouselButton, btnIdx) => (
|
|
2505
|
-
<CapLabel
|
|
2506
|
-
key={`viber-static-btn-${cardIdx}-${btnIdx}`}
|
|
2507
|
-
type="label1"
|
|
2508
|
-
className={`viber-carousel-static-button ${btnIdx === 1 ? 'viber-carousel-static-button-secondary' : ''}`}
|
|
2509
|
-
>
|
|
2510
|
-
{(carouselButton?.title || '').trim()}
|
|
2511
|
-
</CapLabel>
|
|
2512
|
-
))}
|
|
2513
|
-
</CapRow>
|
|
2514
|
-
</CapRow>
|
|
2515
|
-
))}
|
|
2516
|
-
</CapRow>
|
|
2517
|
-
</CapRow>
|
|
2518
|
-
);
|
|
2519
|
-
break;
|
|
2520
|
-
}
|
|
2521
2448
|
if (!isEmpty(image)) {
|
|
2522
2449
|
const { url = '' } = image;
|
|
2523
2450
|
templateData.url = url;
|
|
@@ -4676,7 +4603,6 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
4676
4603
|
<CapButton
|
|
4677
4604
|
className={`create-new-${channelLowerCase} margin-l-8 margin-b-12`}
|
|
4678
4605
|
type={"primary"}
|
|
4679
|
-
isAddBtn
|
|
4680
4606
|
disabled={this.isCreateDisabled()}
|
|
4681
4607
|
onClick={this.createTemplate}
|
|
4682
4608
|
>
|
|
@@ -5138,22 +5064,15 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
5138
5064
|
? this.props.Templates.selectedWhatsappAccount.name
|
|
5139
5065
|
: null
|
|
5140
5066
|
}
|
|
5141
|
-
// Pass formData for
|
|
5067
|
+
// Pass formData for EMAIL and SMS channels for tag extraction
|
|
5142
5068
|
formData={
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
return previewContent.formData || null;
|
|
5151
|
-
}
|
|
5152
|
-
if (channelUpper === VIBER) {
|
|
5153
|
-
return previewContent;
|
|
5154
|
-
}
|
|
5155
|
-
return null;
|
|
5156
|
-
})()
|
|
5069
|
+
this.state.testAndPreviewContent &&
|
|
5070
|
+
(this.state.channel?.toUpperCase() === EMAIL ||
|
|
5071
|
+
this.state.channel?.toUpperCase() === SMS) &&
|
|
5072
|
+
typeof this.state.testAndPreviewContent === 'object' &&
|
|
5073
|
+
this.state.testAndPreviewContent?.formData
|
|
5074
|
+
? this.state.testAndPreviewContent.formData
|
|
5075
|
+
: null
|
|
5157
5076
|
}
|
|
5158
5077
|
/>
|
|
5159
5078
|
)}
|
|
@@ -239,7 +239,6 @@ exports[`Test Templates container Should render sms illustration when no templat
|
|
|
239
239
|
<CapButton
|
|
240
240
|
className="create-new-sms margin-l-8 margin-b-12"
|
|
241
241
|
disabled={false}
|
|
242
|
-
isAddBtn={true}
|
|
243
242
|
onClick={[Function]}
|
|
244
243
|
type="primary"
|
|
245
244
|
>
|
|
@@ -814,7 +813,6 @@ exports[`Test Templates container Should render temlates when whatsapp templates
|
|
|
814
813
|
<CapButton
|
|
815
814
|
className="create-new-whatsapp margin-l-8 margin-b-12"
|
|
816
815
|
disabled={false}
|
|
817
|
-
isAddBtn={true}
|
|
818
816
|
onClick={[Function]}
|
|
819
817
|
type="primary"
|
|
820
818
|
>
|
|
@@ -1225,7 +1223,6 @@ exports[`Test Templates container Test max templates exceeded 1`] = `
|
|
|
1225
1223
|
<CapButton
|
|
1226
1224
|
className="create-new-whatsapp margin-l-8 margin-b-12"
|
|
1227
1225
|
disabled={false}
|
|
1228
|
-
isAddBtn={true}
|
|
1229
1226
|
onClick={[Function]}
|
|
1230
1227
|
type="primary"
|
|
1231
1228
|
>
|
|
@@ -1699,7 +1696,6 @@ exports[`Test Templates container Test max templates not exceeded 1`] = `
|
|
|
1699
1696
|
<CapButton
|
|
1700
1697
|
className="create-new-whatsapp margin-l-8 margin-b-12"
|
|
1701
1698
|
disabled={false}
|
|
1702
|
-
isAddBtn={true}
|
|
1703
1699
|
onClick={[Function]}
|
|
1704
1700
|
type="primary"
|
|
1705
1701
|
>
|
|
@@ -2173,7 +2169,6 @@ exports[`Test Templates container Test max templates warning 1`] = `
|
|
|
2173
2169
|
<CapButton
|
|
2174
2170
|
className="create-new-whatsapp margin-l-8 margin-b-12"
|
|
2175
2171
|
disabled={false}
|
|
2176
|
-
isAddBtn={true}
|
|
2177
2172
|
onClick={[Function]}
|
|
2178
2173
|
type="primary"
|
|
2179
2174
|
>
|
|
@@ -10,9 +10,10 @@ export default css`
|
|
|
10
10
|
|
|
11
11
|
.component-wrapper {
|
|
12
12
|
${(props) => props.isFullMode ? `
|
|
13
|
+
max-width: 71.25rem;
|
|
13
14
|
margin: 0 auto;
|
|
14
15
|
width: 100%;
|
|
15
|
-
padding: 0;
|
|
16
|
+
padding: 0.714rem 0;
|
|
16
17
|
/* Only main channel tabs content, not HTML Editor validation panel tabs */
|
|
17
18
|
> .cap-tab-v2 > .ant-tabs-content-holder > .ant-tabs-content,
|
|
18
19
|
> .cap-tab-v2 > .ant-tabs-content {
|
|
@@ -96,12 +97,6 @@ export default css`
|
|
|
96
97
|
`;
|
|
97
98
|
|
|
98
99
|
export const CapTabStyle = css`
|
|
99
|
-
${(props) => props.isFullMode ? `margin-top: ${CAP_SPACE_24}
|
|
100
|
-
}
|
|
101
|
-
.ant-tabs-nav-list {
|
|
102
|
-
gap: 2rem;
|
|
103
|
-
}
|
|
104
|
-
.ant-tabs-tab + .ant-tabs-tab {
|
|
105
|
-
margin: 0 !important;
|
|
100
|
+
${(props) => props.isFullMode ? `margin-top: ${CAP_SPACE_24}` : ``
|
|
106
101
|
}
|
|
107
102
|
`;
|