@capillarytech/creatives-library 8.0.353-alpha.5 → 8.0.353-alpha.6
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/constants/unified.js +29 -0
- package/package.json +1 -1
- package/services/tests/api.test.js +35 -20
- package/utils/commonUtils.js +19 -1
- package/utils/rcsPayloadUtils.js +92 -0
- package/utils/templateVarUtils.js +201 -0
- package/utils/tests/rcsPayloadUtils.test.js +226 -0
- package/utils/tests/templateVarUtils.test.js +204 -0
- package/v2Components/CapActionButton/constants.js +7 -0
- package/v2Components/CapActionButton/index.js +166 -108
- package/v2Components/CapActionButton/index.scss +157 -6
- package/v2Components/CapActionButton/messages.js +19 -3
- package/v2Components/CapActionButton/tests/index.test.js +41 -17
- package/v2Components/CapTagList/index.js +10 -0
- package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +72 -49
- package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +8 -2
- package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +213 -21
- package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +16 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +85 -10
- package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +30 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +79 -11
- package/v2Components/CommonTestAndPreview/SendTestMessage.js +10 -5
- package/v2Components/CommonTestAndPreview/UnifiedPreview/PreviewHeader.js +0 -17
- package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +157 -15
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +346 -146
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +138 -48
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +11 -0
- package/v2Components/CommonTestAndPreview/constants.js +38 -4
- package/v2Components/CommonTestAndPreview/index.js +691 -235
- package/v2Components/CommonTestAndPreview/messages.js +45 -3
- package/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
- package/v2Components/CommonTestAndPreview/sagas.js +25 -6
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +308 -284
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +231 -65
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +118 -5
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +341 -0
- package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +8 -1
- package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +34 -13
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/PreviewHeader.test.js +0 -159
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +281 -283
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +199 -256
- package/v2Components/CommonTestAndPreview/tests/constants.test.js +1 -2
- package/v2Components/CommonTestAndPreview/tests/index.test.js +132 -198
- package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +36 -26
- package/v2Components/FormBuilder/index.js +11 -6
- package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +91 -0
- package/v2Components/SmsFallback/constants.js +73 -0
- package/v2Components/SmsFallback/index.js +956 -0
- package/v2Components/SmsFallback/index.scss +265 -0
- package/v2Components/SmsFallback/messages.js +78 -0
- package/v2Components/SmsFallback/smsFallbackUtils.js +119 -0
- package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +50 -0
- package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +147 -0
- package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +304 -0
- package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +223 -0
- package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +309 -0
- package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +422 -0
- package/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
- package/v2Components/TemplatePreview/_templatePreview.scss +38 -23
- package/v2Components/TemplatePreview/constants.js +2 -0
- package/v2Components/TemplatePreview/index.js +143 -31
- package/v2Components/TemplatePreview/tests/index.test.js +142 -0
- package/v2Components/TestAndPreviewSlidebox/index.js +15 -3
- package/v2Components/TestAndPreviewSlidebox/sagas.js +11 -4
- package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +3 -1
- package/v2Components/VarSegmentMessageEditor/constants.js +2 -0
- package/v2Components/VarSegmentMessageEditor/index.js +125 -0
- package/v2Components/VarSegmentMessageEditor/index.scss +46 -0
- package/v2Containers/App/constants.js +0 -3
- package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +43 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +36 -4
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +10 -1
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +29 -4
- package/v2Containers/CreativesContainer/constants.js +9 -0
- package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +79 -0
- package/v2Containers/CreativesContainer/index.js +322 -103
- package/v2Containers/CreativesContainer/index.scss +51 -1
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +78 -34
- package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +79 -16
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +8 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +357 -98
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +20 -15
- package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
- package/v2Containers/CreativesContainer/tests/index.test.js +71 -9
- package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +125 -0
- package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
- package/v2Containers/Rcs/constants.js +119 -10
- package/v2Containers/Rcs/index.js +2445 -813
- package/v2Containers/Rcs/index.scss +280 -8
- package/v2Containers/Rcs/messages.js +34 -3
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +225 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +98018 -70073
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +0 -5
- package/v2Containers/Rcs/tests/index.test.js +152 -121
- package/v2Containers/Rcs/tests/mockData.js +38 -0
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +318 -0
- package/v2Containers/Rcs/tests/utils.test.js +646 -30
- package/v2Containers/Rcs/utils.js +478 -11
- package/v2Containers/Sms/Create/index.js +106 -40
- package/v2Containers/Sms/smsFormDataHelpers.js +67 -0
- package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +253 -0
- package/v2Containers/SmsTrai/Create/index.js +9 -4
- package/v2Containers/SmsTrai/Edit/constants.js +2 -0
- package/v2Containers/SmsTrai/Edit/index.js +640 -130
- package/v2Containers/SmsTrai/Edit/index.scss +121 -0
- package/v2Containers/SmsTrai/Edit/messages.js +14 -4
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4328 -2375
- package/v2Containers/SmsWrapper/index.js +37 -8
- package/v2Containers/TagList/index.js +6 -0
- package/v2Containers/Templates/TemplatesActionBar.js +101 -0
- package/v2Containers/Templates/_templates.scss +166 -9
- package/v2Containers/Templates/actions.js +11 -0
- package/v2Containers/Templates/constants.js +2 -0
- package/v2Containers/Templates/index.js +122 -120
- package/v2Containers/Templates/sagas.js +56 -12
- package/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1062 -1017
- package/v2Containers/Templates/tests/sagas.test.js +199 -16
- package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +180 -0
- package/v2Containers/Templates/utils/smsTemplatesListApi.js +79 -0
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +72 -1
- package/v2Containers/TemplatesV2/index.js +86 -23
- package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +131 -0
- package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
- package/v2Containers/WebPush/Create/index.js +8 -91
- package/v2Containers/WebPush/Create/index.scss +0 -7
- package/v2Containers/Whatsapp/index.js +3 -20
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +578 -34
- package/v2Components/CommonTestAndPreview/UnifiedPreview/WebPushPreviewContent.js +0 -169
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/WebPushPreviewContent.test.js +0 -522
- package/v2Containers/App/tests/constants.test.js +0 -61
- package/v2Containers/Templates/tests/webpush.test.js +0 -375
- package/v2Containers/WebPush/Create/tests/getTemplateContent.test.js +0 -338
- package/v2Containers/WebPush/Create/tests/testAndPreviewIntegration.test.js +0 -325
|
@@ -52,6 +52,7 @@ import { QUICK_REPLY, WHATSAPP_CATEGORIES, PHONE_NUMBER, TEMPLATE_VARIABLE_REGEX
|
|
|
52
52
|
import { RCS_BUTTON_TYPES, LEFT, HORIZONTAL, VERTICAL, RIGHT} from '../../v2Containers/Rcs/constants';
|
|
53
53
|
import { ANDROID, INAPP_MESSAGE_LAYOUT_TYPES } from '../../v2Containers/InApp/constants';
|
|
54
54
|
import { CAROUSEL } from '../../v2Containers/MobilePushNew/constants';
|
|
55
|
+
import { TEMPLATE_VAR_REGEX } from './constants';
|
|
55
56
|
|
|
56
57
|
const wechatBodyNew = require('./assets/images/wechat_mobile_android.svg');
|
|
57
58
|
const smsMobileAndroid = require('./assets/images/sms_mobile_android.svg');
|
|
@@ -236,7 +237,23 @@ export class TemplatePreview extends React.Component { // eslint-disable-line re
|
|
|
236
237
|
let content = channel && channel.toLowerCase() === 'sms' ? [this.props.content] : this.props.content;
|
|
237
238
|
const { formatMessage } = intl;
|
|
238
239
|
const { rcsPreviewContent, inAppPreviewContent, viberPreviewContent, isBeeFreeTemplate } = content || {};
|
|
239
|
-
const
|
|
240
|
+
const normalizedRcsPreviewContent = Array.isArray(rcsPreviewContent)
|
|
241
|
+
? { carouselData: rcsPreviewContent }
|
|
242
|
+
: (rcsPreviewContent || {});
|
|
243
|
+
const {
|
|
244
|
+
rcsImageSrc,
|
|
245
|
+
rcsVideoSrc,
|
|
246
|
+
rcsTitle,
|
|
247
|
+
rcsDesc,
|
|
248
|
+
rcsSuggestions,
|
|
249
|
+
carouselData: rcsCarouselData,
|
|
250
|
+
rcsCarouselData: rcsCarouselDataAlt,
|
|
251
|
+
cardVarMapped: rcsCardVarMapped,
|
|
252
|
+
} = normalizedRcsPreviewContent;
|
|
253
|
+
const resolvedRcsCarouselData =
|
|
254
|
+
Array.isArray(rcsCarouselData) && rcsCarouselData.length > 0
|
|
255
|
+
? rcsCarouselData
|
|
256
|
+
: rcsCarouselDataAlt;
|
|
240
257
|
const {
|
|
241
258
|
videoParams,
|
|
242
259
|
imageURL,
|
|
@@ -317,6 +334,18 @@ export class TemplatePreview extends React.Component { // eslint-disable-line re
|
|
|
317
334
|
'flex-shrink': 0,
|
|
318
335
|
'left': 0,
|
|
319
336
|
};
|
|
337
|
+
|
|
338
|
+
const resolveVarsWithMap = (input, varMap) => {
|
|
339
|
+
if (input === null || input === undefined) return '';
|
|
340
|
+
const str = typeof input === 'string' ? input : String(input);
|
|
341
|
+
return str.replace(TEMPLATE_VAR_REGEX, (token, varName) => {
|
|
342
|
+
const mappedValue = varMap?.[varName];
|
|
343
|
+
if (mappedValue === null || mappedValue === undefined || String(mappedValue) === '') {
|
|
344
|
+
return token;
|
|
345
|
+
}
|
|
346
|
+
return String(mappedValue);
|
|
347
|
+
});
|
|
348
|
+
};
|
|
320
349
|
const getVideoContent = ({
|
|
321
350
|
video,
|
|
322
351
|
actionUrl,
|
|
@@ -473,13 +502,15 @@ export class TemplatePreview extends React.Component { // eslint-disable-line re
|
|
|
473
502
|
const whatsappUpdatedAccountName = whatsappAccountName || templateData?.versions?.base?.content?.whatsapp?.accountName || '';
|
|
474
503
|
const whatsappUpdatedLen = whatsappContentLen !== undefined ? whatsappContentLen : content?.charCount;
|
|
475
504
|
|
|
476
|
-
const renderRcsSuggestionsPreview = () => {
|
|
505
|
+
const renderRcsSuggestionsPreview = (suggestionsArg) => {
|
|
477
506
|
const renderArray = [];
|
|
478
|
-
(rcsSuggestions || [])
|
|
479
|
-
|
|
507
|
+
const suggestions = Array.isArray(suggestionsArg) ? suggestionsArg : (rcsSuggestions || []);
|
|
508
|
+
(suggestions || []).forEach((suggestion, idx) => {
|
|
509
|
+
const suggestionKey = `${suggestion?.type || 'unknown'}-${suggestion?.text || ''}-${idx}`;
|
|
510
|
+
renderArray.push(<CapDivider key={`rcs-divider-${suggestionKey}`} className="whatsapp-divider" />);
|
|
480
511
|
if (suggestion.type === RCS_BUTTON_TYPES.QUICK_REPLY) {
|
|
481
512
|
renderArray.push(
|
|
482
|
-
<CapLabel type="label21" className="rcs-cta-preview">
|
|
513
|
+
<CapLabel key={`rcs-suggestion-${suggestionKey}`} type="label21" className="rcs-cta-preview">
|
|
483
514
|
<CapIcon
|
|
484
515
|
type='small-link'
|
|
485
516
|
size="xs"
|
|
@@ -489,14 +520,14 @@ export class TemplatePreview extends React.Component { // eslint-disable-line re
|
|
|
489
520
|
);
|
|
490
521
|
} else if (suggestion.type === RCS_BUTTON_TYPES.CTA) {
|
|
491
522
|
renderArray.push(
|
|
492
|
-
<CapLabel type="label21" className="rcs-cta-preview">
|
|
523
|
+
<CapLabel key={`rcs-suggestion-${suggestionKey}`} type="label21" className="rcs-cta-preview">
|
|
493
524
|
<CapIcon type="launch" size="xs" />
|
|
494
525
|
{suggestion.text}
|
|
495
526
|
</CapLabel>,
|
|
496
527
|
);
|
|
497
528
|
} else if (suggestion.type === RCS_BUTTON_TYPES.PHONE_NUMBER) {
|
|
498
529
|
renderArray.push(
|
|
499
|
-
<CapLabel type="label21" className="rcs-cta-preview">
|
|
530
|
+
<CapLabel key={`rcs-suggestion-${suggestionKey}`} type="label21" className="rcs-cta-preview">
|
|
500
531
|
<CapIcon type="call" size="xs" />
|
|
501
532
|
{suggestion.text}
|
|
502
533
|
</CapLabel>,
|
|
@@ -509,23 +540,20 @@ export class TemplatePreview extends React.Component { // eslint-disable-line re
|
|
|
509
540
|
const renderTextPreviewContent = () => (
|
|
510
541
|
<>
|
|
511
542
|
{rcsTitle && (
|
|
512
|
-
<>
|
|
513
543
|
<CapLabel
|
|
514
544
|
type="label5"
|
|
515
545
|
className="message-pop-item align-left rcs-content"
|
|
516
546
|
fontWeight="bold"
|
|
517
547
|
>
|
|
518
|
-
{rcsTitle}
|
|
548
|
+
{resolveVarsWithMap(rcsTitle, rcsCardVarMapped)}
|
|
519
549
|
</CapLabel>
|
|
520
|
-
<CapDivider className="whatsapp-divider" />
|
|
521
|
-
</>
|
|
522
550
|
)}
|
|
523
551
|
{rcsDesc && (
|
|
524
552
|
<CapLabel
|
|
525
553
|
type="label5"
|
|
526
554
|
className="message-pop-item align-left rcs-desc rcs-content"
|
|
527
555
|
>
|
|
528
|
-
{rcsDesc}
|
|
556
|
+
{resolveVarsWithMap(rcsDesc, rcsCardVarMapped)}
|
|
529
557
|
</CapLabel>
|
|
530
558
|
)}
|
|
531
559
|
{renderRcsSuggestionsPreview()}
|
|
@@ -542,50 +570,134 @@ export class TemplatePreview extends React.Component { // eslint-disable-line re
|
|
|
542
570
|
/>
|
|
543
571
|
)}
|
|
544
572
|
{rcsVideoSrc && (
|
|
545
|
-
<
|
|
573
|
+
<CapRow className="video-preview">
|
|
546
574
|
<CapImage
|
|
547
575
|
src={rcsVideoSrc}
|
|
548
576
|
className="rcs-image"
|
|
549
577
|
alt={formatMessage(messages.previewGenerated)}
|
|
550
578
|
/>
|
|
551
|
-
<
|
|
579
|
+
<CapRow className="icon-position">
|
|
552
580
|
<CapImage
|
|
553
581
|
className="video-icon"
|
|
554
582
|
src={videoPlay}
|
|
555
583
|
/>
|
|
556
|
-
</
|
|
557
|
-
</
|
|
584
|
+
</CapRow>
|
|
585
|
+
</CapRow>
|
|
558
586
|
)}
|
|
559
587
|
</>
|
|
560
588
|
);
|
|
561
589
|
|
|
562
590
|
const renderRcsPreviewContent = () => {
|
|
591
|
+
const carouselCards = Array.isArray(resolvedRcsCarouselData) ? resolvedRcsCarouselData : [];
|
|
592
|
+
if (carouselCards.length > 0) {
|
|
593
|
+
return (
|
|
594
|
+
<CapRow className="msg-container sms">
|
|
595
|
+
<CapRow className="message-pop sms">
|
|
596
|
+
<CapRow className="msg-container-carousel">
|
|
597
|
+
<CapRow className="scroll-container">
|
|
598
|
+
{carouselCards.map((card, idx) => {
|
|
599
|
+
const key = `rcs-carousel-${idx}-${card?.bodyText || card?.imageSrc || card?.videoPreviewImg || ''}`;
|
|
600
|
+
const isVideo = (card?.mediaType || '').toLowerCase() === 'video';
|
|
601
|
+
const cardSuggestions = Array.isArray(card?.suggestions) ? card.suggestions : [];
|
|
602
|
+
const effectiveCardVarMap = card?.cardVarMapped || rcsCardVarMapped;
|
|
603
|
+
const suggestionsNode = cardSuggestions.length > 0
|
|
604
|
+
? renderRcsSuggestionsPreview(cardSuggestions)
|
|
605
|
+
: null;
|
|
606
|
+
|
|
607
|
+
const resolvedCardTitle = resolveVarsWithMap(card?.title, effectiveCardVarMap);
|
|
608
|
+
const resolvedCardBodyText = resolveVarsWithMap(card?.bodyText, effectiveCardVarMap);
|
|
609
|
+
|
|
610
|
+
return (
|
|
611
|
+
<CapRow
|
|
612
|
+
key={key}
|
|
613
|
+
className="message-pop align-left message-pop-carousel rcs-carousel-card"
|
|
614
|
+
>
|
|
615
|
+
<CapRow className="whatsapp-content">
|
|
616
|
+
{!isVideo && (
|
|
617
|
+
<CapImage
|
|
618
|
+
src={card?.imageSrc ? card.imageSrc : whatsappImageEmptyPreview}
|
|
619
|
+
className="whatsapp-image"
|
|
620
|
+
alt={formatMessage(messages.previewGenerated)}
|
|
621
|
+
/>
|
|
622
|
+
)}
|
|
623
|
+
{isVideo && (
|
|
624
|
+
<CapTooltip title={formatMessage(messages.videoPreviewTooltip)}>
|
|
625
|
+
<CapRow className="video-preview">
|
|
626
|
+
<CapImage
|
|
627
|
+
src={card?.videoPreviewImg ? card.videoPreviewImg : whatsappVideoEmptyPreview}
|
|
628
|
+
className="whatsapp-image"
|
|
629
|
+
alt={formatMessage(messages.previewGenerated)}
|
|
630
|
+
/>
|
|
631
|
+
<CapRow className="icon-position">
|
|
632
|
+
<CapImage className="video-icon" src={videoPlay} alt="Play" />
|
|
633
|
+
</CapRow>
|
|
634
|
+
</CapRow>
|
|
635
|
+
</CapTooltip>
|
|
636
|
+
)}
|
|
637
|
+
|
|
638
|
+
{(resolvedCardTitle || resolvedCardBodyText) && (
|
|
639
|
+
<CapRow className="carousel-content">
|
|
640
|
+
{!!resolvedCardTitle && (
|
|
641
|
+
<CapLabel
|
|
642
|
+
type={card?.titleLabelType || 'label1'}
|
|
643
|
+
className="carousel-title"
|
|
644
|
+
>
|
|
645
|
+
{resolvedCardTitle}
|
|
646
|
+
</CapLabel>
|
|
647
|
+
)}
|
|
648
|
+
{!!resolvedCardBodyText && (
|
|
649
|
+
<CapLabel
|
|
650
|
+
type={card?.bodyLabelType || 'label2'}
|
|
651
|
+
className="carousel-message"
|
|
652
|
+
>
|
|
653
|
+
{resolvedCardBodyText}
|
|
654
|
+
</CapLabel>
|
|
655
|
+
)}
|
|
656
|
+
</CapRow>
|
|
657
|
+
)}
|
|
658
|
+
|
|
659
|
+
{!!suggestionsNode && (
|
|
660
|
+
<>
|
|
661
|
+
{suggestionsNode}
|
|
662
|
+
</>
|
|
663
|
+
)}
|
|
664
|
+
</CapRow>
|
|
665
|
+
</CapRow>
|
|
666
|
+
);
|
|
667
|
+
})}
|
|
668
|
+
</CapRow>
|
|
669
|
+
</CapRow>
|
|
670
|
+
</CapRow>
|
|
671
|
+
</CapRow>
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
|
|
563
675
|
if (rcsOrientation === HORIZONTAL) {
|
|
564
676
|
return rcsType === RIGHT ? (
|
|
565
|
-
<
|
|
566
|
-
<
|
|
677
|
+
<CapRow className="msg-container sms">
|
|
678
|
+
<CapRow className="message-pop sms horizontal">
|
|
567
679
|
<CapColumn className="rcs-preview-text" span={12}>{renderTextPreviewContent()}</CapColumn>
|
|
568
680
|
<CapColumn span={12}>{renderMediaPreviewContent()}</CapColumn>
|
|
569
|
-
</
|
|
570
|
-
</
|
|
681
|
+
</CapRow>
|
|
682
|
+
</CapRow>
|
|
571
683
|
|
|
572
684
|
) : (
|
|
573
|
-
<
|
|
574
|
-
<
|
|
685
|
+
<CapRow className="msg-container sms">
|
|
686
|
+
<CapRow className="message-pop sms horizontal">
|
|
575
687
|
<CapColumn span={12}>{renderMediaPreviewContent()}</CapColumn>
|
|
576
688
|
<CapColumn className="rcs-preview-text" span={12}>{renderTextPreviewContent()}</CapColumn>
|
|
577
|
-
</
|
|
578
|
-
</
|
|
689
|
+
</CapRow>
|
|
690
|
+
</CapRow>
|
|
579
691
|
);
|
|
580
692
|
}
|
|
581
693
|
|
|
582
694
|
return (
|
|
583
|
-
<
|
|
584
|
-
<
|
|
695
|
+
<CapRow className="msg-container sms">
|
|
696
|
+
<CapRow className="message-pop sms">
|
|
585
697
|
{renderMediaPreviewContent()}
|
|
586
698
|
{renderTextPreviewContent()}
|
|
587
|
-
</
|
|
588
|
-
</
|
|
699
|
+
</CapRow>
|
|
700
|
+
</CapRow>
|
|
589
701
|
);
|
|
590
702
|
};
|
|
591
703
|
|
|
@@ -1303,14 +1415,14 @@ export class TemplatePreview extends React.Component { // eslint-disable-line re
|
|
|
1303
1415
|
""
|
|
1304
1416
|
)}
|
|
1305
1417
|
{channel?.toUpperCase() === RCS && (
|
|
1306
|
-
<
|
|
1418
|
+
<CapRow className="shell-v2 align-center rcs-preview">
|
|
1307
1419
|
<CapImage
|
|
1308
1420
|
className="preview-image"
|
|
1309
1421
|
src={rcsIosPreview ? smsMobileIos : smsMobileAndroid}
|
|
1310
1422
|
alt={formatMessage(messages.previewGenerated)}
|
|
1311
1423
|
/>
|
|
1312
1424
|
{renderRcsPreviewContent()}
|
|
1313
|
-
</
|
|
1425
|
+
</CapRow>
|
|
1314
1426
|
|
|
1315
1427
|
)}
|
|
1316
1428
|
{channel?.toUpperCase() === ZALO && (
|
|
@@ -1511,4 +1623,4 @@ TemplatePreview.propTypes = {
|
|
|
1511
1623
|
rcsOrientation: PropTypes.string,
|
|
1512
1624
|
};
|
|
1513
1625
|
|
|
1514
|
-
export default (injectIntl(TemplatePreview));
|
|
1626
|
+
export default (injectIntl(TemplatePreview));
|
|
@@ -2,6 +2,9 @@ import React from 'react';
|
|
|
2
2
|
import { shallowWithIntl } from '../../../helpers/intl-enzym-test-helpers';
|
|
3
3
|
|
|
4
4
|
import { TemplatePreview } from '../index';
|
|
5
|
+
import { RCS } from '../../../v2Containers/CreativesContainer/constants';
|
|
6
|
+
import whatsappImageEmptyPreview from '../assets/images/empty_image_preview.svg';
|
|
7
|
+
import whatsappVideoEmptyPreview from '../assets/images/empty_video_preview.svg';
|
|
5
8
|
|
|
6
9
|
describe('Test Templates container', () => {
|
|
7
10
|
let renderedComponent;
|
|
@@ -69,4 +72,143 @@ describe('Test Templates container', () => {
|
|
|
69
72
|
});
|
|
70
73
|
expect(renderedComponent).toMatchSnapshot();
|
|
71
74
|
});
|
|
75
|
+
|
|
76
|
+
describe('RCS carousel preview branches', () => {
|
|
77
|
+
const buildRcsContent = (cards) => ({
|
|
78
|
+
rcsPreviewContent: {
|
|
79
|
+
carouselData: cards,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const getNodesByClassName = (className) =>
|
|
84
|
+
renderedComponent.findWhere((node) => node.prop('className') === className);
|
|
85
|
+
|
|
86
|
+
it('renders image and video cards with proper media-specific markup', () => {
|
|
87
|
+
renderFunction(
|
|
88
|
+
RCS,
|
|
89
|
+
buildRcsContent([
|
|
90
|
+
{
|
|
91
|
+
mediaType: 'image',
|
|
92
|
+
imageSrc: 'https://example.com/image-card.jpg',
|
|
93
|
+
bodyText: 'image body',
|
|
94
|
+
suggestions: [],
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
mediaType: 'video',
|
|
98
|
+
videoPreviewImg: 'https://example.com/video-thumb.jpg',
|
|
99
|
+
bodyText: 'video body',
|
|
100
|
+
suggestions: [],
|
|
101
|
+
},
|
|
102
|
+
]),
|
|
103
|
+
'',
|
|
104
|
+
0,
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
// Video card should render tooltip/video icon path; image-only card should not.
|
|
108
|
+
expect(renderedComponent.find('CapTooltip')).toHaveLength(1);
|
|
109
|
+
expect(
|
|
110
|
+
renderedComponent.findWhere((node) => node.prop('className') === 'video-icon')
|
|
111
|
+
).toHaveLength(1);
|
|
112
|
+
|
|
113
|
+
// Both cards render media containers.
|
|
114
|
+
expect(
|
|
115
|
+
renderedComponent.findWhere((node) => node.prop('className') === 'whatsapp-image')
|
|
116
|
+
).toHaveLength(2);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('renders per-card suggestions only for cards that provide suggestions', () => {
|
|
120
|
+
renderFunction(
|
|
121
|
+
RCS,
|
|
122
|
+
buildRcsContent([
|
|
123
|
+
{
|
|
124
|
+
mediaType: 'image',
|
|
125
|
+
imageSrc: 'https://example.com/with-suggestions.jpg',
|
|
126
|
+
bodyText: 'has suggestions',
|
|
127
|
+
suggestions: [
|
|
128
|
+
{ type: 'QUICK_REPLY', text: 'Reply 1' },
|
|
129
|
+
{ type: 'CTA', text: 'Visit' },
|
|
130
|
+
],
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
mediaType: 'image',
|
|
134
|
+
imageSrc: 'https://example.com/no-suggestions.jpg',
|
|
135
|
+
bodyText: 'no suggestions',
|
|
136
|
+
suggestions: [],
|
|
137
|
+
},
|
|
138
|
+
]),
|
|
139
|
+
'',
|
|
140
|
+
0,
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
// Suggestion labels/icons should be rendered only from first card.
|
|
144
|
+
expect(getNodesByClassName('rcs-cta-preview')).toHaveLength(2);
|
|
145
|
+
expect(getNodesByClassName('whatsapp-divider')).not.toHaveLength(0);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('falls back to empty preview assets when image/video media src is missing', () => {
|
|
149
|
+
renderFunction(
|
|
150
|
+
RCS,
|
|
151
|
+
buildRcsContent([
|
|
152
|
+
{
|
|
153
|
+
mediaType: 'image',
|
|
154
|
+
bodyText: 'fallback image',
|
|
155
|
+
suggestions: [],
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
mediaType: 'video',
|
|
159
|
+
bodyText: 'fallback video',
|
|
160
|
+
suggestions: [],
|
|
161
|
+
},
|
|
162
|
+
]),
|
|
163
|
+
'',
|
|
164
|
+
0,
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
const mediaImageNodes = renderedComponent.findWhere(
|
|
168
|
+
(node) => node.name() === 'CapImage' && node.prop('className') === 'whatsapp-image'
|
|
169
|
+
);
|
|
170
|
+
const mediaSrcs = mediaImageNodes.map((node) => node.prop('src'));
|
|
171
|
+
|
|
172
|
+
expect(mediaSrcs).toContain(whatsappImageEmptyPreview);
|
|
173
|
+
expect(mediaSrcs).toContain(whatsappVideoEmptyPreview);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('generates unique carousel keys using rcs-carousel-<idx>-<bodyText|imageSrc|videoPreviewImg>', () => {
|
|
177
|
+
renderFunction(
|
|
178
|
+
RCS,
|
|
179
|
+
buildRcsContent([
|
|
180
|
+
{
|
|
181
|
+
mediaType: 'image',
|
|
182
|
+
imageSrc: 'https://example.com/one.jpg',
|
|
183
|
+
bodyText: 'same body',
|
|
184
|
+
suggestions: [],
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
mediaType: 'image',
|
|
188
|
+
imageSrc: 'https://example.com/two.jpg',
|
|
189
|
+
bodyText: 'same body',
|
|
190
|
+
suggestions: [],
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
mediaType: 'video',
|
|
194
|
+
videoPreviewImg: 'https://example.com/three-thumb.jpg',
|
|
195
|
+
bodyText: 'same body',
|
|
196
|
+
suggestions: [],
|
|
197
|
+
},
|
|
198
|
+
]),
|
|
199
|
+
'',
|
|
200
|
+
0,
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
const cardNodes = getNodesByClassName('message-pop align-left message-pop-carousel rcs-carousel-card');
|
|
204
|
+
const keys = cardNodes.map((node) => node.key());
|
|
205
|
+
|
|
206
|
+
expect(keys).toEqual([
|
|
207
|
+
'rcs-carousel-0-same body',
|
|
208
|
+
'rcs-carousel-1-same body',
|
|
209
|
+
'rcs-carousel-2-same body',
|
|
210
|
+
]);
|
|
211
|
+
expect(new Set(keys).size).toBe(keys.length);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
72
214
|
});
|
|
@@ -18,7 +18,7 @@ import injectReducer from '../../utils/injectReducer';
|
|
|
18
18
|
import injectSaga from '../../utils/injectSaga';
|
|
19
19
|
|
|
20
20
|
import CommonTestAndPreview from '../CommonTestAndPreview';
|
|
21
|
-
import { CHANNELS } from '../CommonTestAndPreview/constants';
|
|
21
|
+
import { CHANNELS, RCS_SMS_FALLBACK_VAR_MAPPED_PROP } from '../CommonTestAndPreview/constants';
|
|
22
22
|
import * as commonTestAndPreviewActions from '../CommonTestAndPreview/actions';
|
|
23
23
|
import { commonTestAndPreviewSaga } from '../CommonTestAndPreview/sagas';
|
|
24
24
|
import commonTestAndPreviewReducer from '../CommonTestAndPreview/reducer';
|
|
@@ -69,8 +69,8 @@ const TestAndPreviewSlidebox = (props) => {
|
|
|
69
69
|
|
|
70
70
|
TestAndPreviewSlidebox.propTypes = {
|
|
71
71
|
// Channel prop - supports all channels
|
|
72
|
-
channel: PropTypes.oneOf([CHANNELS.EMAIL, CHANNELS.SMS, CHANNELS.RCS, CHANNELS.WHATSAPP, CHANNELS.INAPP, CHANNELS.MOBILEPUSH
|
|
73
|
-
currentChannel: PropTypes.oneOf([CHANNELS.EMAIL, CHANNELS.SMS, CHANNELS.RCS, CHANNELS.WHATSAPP, CHANNELS.INAPP, CHANNELS.MOBILEPUSH
|
|
72
|
+
channel: PropTypes.oneOf([CHANNELS.EMAIL, CHANNELS.SMS, CHANNELS.RCS, CHANNELS.WHATSAPP, CHANNELS.INAPP, CHANNELS.MOBILEPUSH]),
|
|
73
|
+
currentChannel: PropTypes.oneOf([CHANNELS.EMAIL, CHANNELS.SMS, CHANNELS.RCS, CHANNELS.WHATSAPP, CHANNELS.INAPP, CHANNELS.MOBILEPUSH]), // Alternative prop name for backward compatibility
|
|
74
74
|
// All original props are passed through
|
|
75
75
|
show: PropTypes.bool.isRequired,
|
|
76
76
|
onClose: PropTypes.func.isRequired,
|
|
@@ -78,6 +78,16 @@ TestAndPreviewSlidebox.propTypes = {
|
|
|
78
78
|
content: PropTypes.string,
|
|
79
79
|
beeInstance: PropTypes.object,
|
|
80
80
|
currentTab: PropTypes.number,
|
|
81
|
+
smsFallbackContent: PropTypes.shape({
|
|
82
|
+
templateContent: PropTypes.string,
|
|
83
|
+
senderId: PropTypes.string,
|
|
84
|
+
templateName: PropTypes.string,
|
|
85
|
+
[RCS_SMS_FALLBACK_VAR_MAPPED_PROP]: PropTypes.object,
|
|
86
|
+
}),
|
|
87
|
+
/** Passed to CommonTestAndPreview for RCS test-meta resolution (slot semantics vs full-mode). */
|
|
88
|
+
rcsTestPreviewOptions: PropTypes.shape({
|
|
89
|
+
isLibraryMode: PropTypes.bool,
|
|
90
|
+
}),
|
|
81
91
|
// Redux props are passed through
|
|
82
92
|
actions: PropTypes.object.isRequired,
|
|
83
93
|
extractedTags: PropTypes.array.isRequired,
|
|
@@ -109,10 +119,12 @@ TestAndPreviewSlidebox.defaultProps = {
|
|
|
109
119
|
currentTab: 1,
|
|
110
120
|
messageMetaConfigId: null,
|
|
111
121
|
prefilledValues: {},
|
|
122
|
+
rcsTestPreviewOptions: undefined,
|
|
112
123
|
senderDetailsByChannel: {},
|
|
113
124
|
wecrmAccounts: [],
|
|
114
125
|
isLoadingSenderDetails: false,
|
|
115
126
|
orgUnitId: -1,
|
|
127
|
+
smsFallbackContent: null,
|
|
116
128
|
};
|
|
117
129
|
|
|
118
130
|
const mapStateToProps = createStructuredSelector({
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
GET_PREFILLED_VALUES_SUCCESS,
|
|
35
35
|
GET_PREFILLED_VALUES_FAILURE,
|
|
36
36
|
} from './constants';
|
|
37
|
+
import { extractPreviewFromLiquidResponse } from '../CommonTestAndPreview/previewApiUtils';
|
|
37
38
|
|
|
38
39
|
// Search Customers Saga
|
|
39
40
|
export function* searchCustomersSaga(action) {
|
|
@@ -80,11 +81,12 @@ export function* updatePreviewSaga(action) {
|
|
|
80
81
|
const customValues = action.payload.resolvedTags;
|
|
81
82
|
|
|
82
83
|
const response = yield call(Api.updateEmailPreview, action.payload);
|
|
83
|
-
|
|
84
|
+
const previewPayload = extractPreviewFromLiquidResponse(response);
|
|
85
|
+
if (previewPayload) {
|
|
84
86
|
yield put({
|
|
85
87
|
type: UPDATE_PREVIEW_SUCCESS,
|
|
86
88
|
payload: {
|
|
87
|
-
previewData:
|
|
89
|
+
previewData: previewPayload,
|
|
88
90
|
customValues, // Pass custom values to be preserved
|
|
89
91
|
},
|
|
90
92
|
});
|
|
@@ -221,8 +223,13 @@ export function* createMessageMetaSaga(action) {
|
|
|
221
223
|
export function* getPrefilledValuesSaga(action) {
|
|
222
224
|
try {
|
|
223
225
|
const response = yield call(Api.updateEmailPreview, action.payload);
|
|
224
|
-
|
|
225
|
-
|
|
226
|
+
const body =
|
|
227
|
+
response?.data !== undefined && response?.data !== null
|
|
228
|
+
? response.data
|
|
229
|
+
: response;
|
|
230
|
+
const resolvedTagValues = body?.resolvedTagValues;
|
|
231
|
+
if (resolvedTagValues != null) {
|
|
232
|
+
yield put({ type: GET_PREFILLED_VALUES_SUCCESS, payload: { values: resolvedTagValues } });
|
|
226
233
|
} else {
|
|
227
234
|
yield put({ type: GET_PREFILLED_VALUES_FAILURE, payload: { error: response.error || 'Failed to fetch prefilled values' } });
|
|
228
235
|
}
|
|
@@ -136,7 +136,9 @@ describe('TestAndPreviewSlidebox Sagas', () => {
|
|
|
136
136
|
describe('updatePreviewSaga', () => {
|
|
137
137
|
it('should handle successful preview update', () => {
|
|
138
138
|
const mockResponse = {
|
|
139
|
-
data:
|
|
139
|
+
data: {
|
|
140
|
+
resolvedBody: 'Test Preview Data',
|
|
141
|
+
},
|
|
140
142
|
};
|
|
141
143
|
const customValues = { test: 'value' };
|
|
142
144
|
return expectSaga(sagas.updatePreviewSaga, {
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared message editor that renders template text with {{var}} and/or DLT `{#var#}` segments as
|
|
3
|
+
* variable inputs and static text as headings.
|
|
4
|
+
* Reused by RCS (title/description), SmsTrai Edit (SMS fallback), and WhatsApp (edit message/header).
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import PropTypes from 'prop-types';
|
|
8
|
+
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
9
|
+
import CapHeading from '@capillarytech/cap-ui-library/CapHeading';
|
|
10
|
+
import CapInput from '@capillarytech/cap-ui-library/CapInput';
|
|
11
|
+
import {
|
|
12
|
+
splitTemplateVarString,
|
|
13
|
+
DEFAULT_MUSTACHE_VAR_REGEX,
|
|
14
|
+
isAnyTemplateVarToken,
|
|
15
|
+
} from '../../utils/templateVarUtils';
|
|
16
|
+
|
|
17
|
+
import './index.scss';
|
|
18
|
+
import { VAR_SEGMENT_PLACEHOLDER_PREFIX } from './constants';
|
|
19
|
+
|
|
20
|
+
const { TextArea } = CapInput;
|
|
21
|
+
|
|
22
|
+
export function VarSegmentMessageEditor({
|
|
23
|
+
templateString = '',
|
|
24
|
+
valueMap = {},
|
|
25
|
+
onChange,
|
|
26
|
+
onFocus,
|
|
27
|
+
placeholderPrefix = VAR_SEGMENT_PLACEHOLDER_PREFIX,
|
|
28
|
+
getPlaceholder,
|
|
29
|
+
wrapperClassName = 'rcs_text_area_wrapper',
|
|
30
|
+
rowClassName = 'rcs-edit-template-message-input',
|
|
31
|
+
headingClassName = 'rcs-edit-template-message-split',
|
|
32
|
+
varRegex,
|
|
33
|
+
readOnly = false,
|
|
34
|
+
disabled = false,
|
|
35
|
+
footerContent,
|
|
36
|
+
renderVarFooter,
|
|
37
|
+
}) {
|
|
38
|
+
const segments = splitTemplateVarString(templateString, varRegex || DEFAULT_MUSTACHE_VAR_REGEX);
|
|
39
|
+
if (!segments?.length) return null;
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<div className={wrapperClassName}>
|
|
43
|
+
<CapRow className={rowClassName}>
|
|
44
|
+
{segments.map((segmentToken, segmentIndex) => {
|
|
45
|
+
const isVar =
|
|
46
|
+
typeof segmentToken === 'string' && isAnyTemplateVarToken(segmentToken);
|
|
47
|
+
if (isVar) {
|
|
48
|
+
const varSegmentFieldId = `${segmentToken}_${segmentIndex}`;
|
|
49
|
+
const slotValueFromMap = valueMap?.[varSegmentFieldId];
|
|
50
|
+
// Missing key: show empty (not the raw {{…}} token) so cleared slots and incomplete maps
|
|
51
|
+
// cannot resurrect the token; placeholder still guides the user.
|
|
52
|
+
const value =
|
|
53
|
+
slotValueFromMap !== undefined && slotValueFromMap !== null ? slotValueFromMap : '';
|
|
54
|
+
if (readOnly) {
|
|
55
|
+
return (
|
|
56
|
+
<CapHeading
|
|
57
|
+
key={varSegmentFieldId}
|
|
58
|
+
type="h4"
|
|
59
|
+
className={`${headingClassName} var-segment-message-editor__read-only-value`.trim()}
|
|
60
|
+
>
|
|
61
|
+
{value}
|
|
62
|
+
</CapHeading>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
const fromGet = getPlaceholder && getPlaceholder(segmentToken, segmentIndex);
|
|
66
|
+
const placeholder =
|
|
67
|
+
fromGet !== undefined && fromGet !== null && fromGet !== ''
|
|
68
|
+
? fromGet
|
|
69
|
+
: `${placeholderPrefix}${segmentToken}`;
|
|
70
|
+
return (
|
|
71
|
+
<div key={varSegmentFieldId} className="var-segment-message-editor__var-slot">
|
|
72
|
+
<TextArea
|
|
73
|
+
id={varSegmentFieldId}
|
|
74
|
+
placeholder={placeholder}
|
|
75
|
+
autosize={{ minRows: 1, maxRows: 3 }}
|
|
76
|
+
value={value}
|
|
77
|
+
onFocus={() => onFocus && onFocus(varSegmentFieldId)}
|
|
78
|
+
onChange={(e) =>
|
|
79
|
+
onChange && onChange(varSegmentFieldId, e?.target?.value ?? '')}
|
|
80
|
+
disabled={disabled}
|
|
81
|
+
/>
|
|
82
|
+
{renderVarFooter
|
|
83
|
+
? renderVarFooter(segmentToken, segmentIndex, varSegmentFieldId)
|
|
84
|
+
: null}
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
if (segmentToken) {
|
|
89
|
+
return (
|
|
90
|
+
<CapHeading
|
|
91
|
+
key={`static_${segmentIndex}_${segmentToken}`}
|
|
92
|
+
type="h4"
|
|
93
|
+
className={headingClassName}
|
|
94
|
+
>
|
|
95
|
+
{segmentToken}
|
|
96
|
+
</CapHeading>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
})}
|
|
101
|
+
</CapRow>
|
|
102
|
+
{footerContent}
|
|
103
|
+
</div>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
VarSegmentMessageEditor.propTypes = {
|
|
108
|
+
templateString: PropTypes.string,
|
|
109
|
+
valueMap: PropTypes.object,
|
|
110
|
+
onChange: PropTypes.func,
|
|
111
|
+
onFocus: PropTypes.func,
|
|
112
|
+
placeholderPrefix: PropTypes.string,
|
|
113
|
+
getPlaceholder: PropTypes.func,
|
|
114
|
+
wrapperClassName: PropTypes.string,
|
|
115
|
+
rowClassName: PropTypes.string,
|
|
116
|
+
headingClassName: PropTypes.string,
|
|
117
|
+
varRegex: PropTypes.object,
|
|
118
|
+
readOnly: PropTypes.bool,
|
|
119
|
+
disabled: PropTypes.bool,
|
|
120
|
+
footerContent: PropTypes.node,
|
|
121
|
+
/** Optional hint below a variable field (e.g. DLT `{#var#}` max length). */
|
|
122
|
+
renderVarFooter: PropTypes.func,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export default VarSegmentMessageEditor;
|