@capillarytech/creatives-library 8.0.353-alpha.6 → 8.0.354
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 +0 -29
- package/index.html +1 -0
- package/package.json +1 -1
- package/services/tests/api.test.js +20 -35
- package/utils/cdnTransformation.js +63 -3
- package/utils/commonUtils.js +1 -19
- package/utils/tests/cdnTransformation.test.js +111 -0
- package/v2Components/CapActionButton/constants.js +0 -7
- package/v2Components/CapActionButton/index.js +108 -166
- package/v2Components/CapActionButton/index.scss +6 -157
- package/v2Components/CapActionButton/messages.js +3 -19
- package/v2Components/CapActionButton/tests/index.test.js +17 -41
- package/v2Components/CapTagList/index.js +0 -10
- package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +49 -72
- package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +2 -8
- package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +21 -213
- package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +0 -16
- package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +10 -85
- package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +0 -30
- package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +11 -79
- package/v2Components/CommonTestAndPreview/SendTestMessage.js +5 -10
- package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +15 -157
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +76 -346
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +4 -133
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +0 -11
- package/v2Components/CommonTestAndPreview/constants.js +2 -38
- package/v2Components/CommonTestAndPreview/index.js +186 -691
- package/v2Components/CommonTestAndPreview/messages.js +3 -45
- package/v2Components/CommonTestAndPreview/sagas.js +6 -25
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +284 -308
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +65 -231
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +5 -118
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +0 -341
- package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +1 -8
- package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +13 -34
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +283 -281
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +1 -199
- package/v2Components/CommonTestAndPreview/tests/index.test.js +4 -132
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +26 -36
- package/v2Components/FormBuilder/index.js +6 -11
- package/v2Components/TemplatePreview/_templatePreview.scss +23 -38
- package/v2Components/TemplatePreview/index.js +31 -143
- package/v2Components/TemplatePreview/tests/index.test.js +0 -142
- package/v2Components/TestAndPreviewSlidebox/index.js +1 -13
- package/v2Components/TestAndPreviewSlidebox/sagas.js +4 -11
- package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +1 -3
- package/v2Containers/CreativesContainer/SlideBoxContent.js +4 -36
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +1 -10
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +4 -29
- package/v2Containers/CreativesContainer/constants.js +0 -9
- package/v2Containers/CreativesContainer/index.js +103 -322
- package/v2Containers/CreativesContainer/index.scss +1 -51
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +34 -78
- package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +16 -79
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -8
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +98 -357
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +15 -20
- package/v2Containers/CreativesContainer/tests/index.test.js +9 -71
- package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
- package/v2Containers/Rcs/constants.js +10 -119
- package/v2Containers/Rcs/index.js +818 -2450
- package/v2Containers/Rcs/index.scss +8 -280
- package/v2Containers/Rcs/messages.js +3 -34
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +70073 -98018
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +5 -0
- package/v2Containers/Rcs/tests/index.test.js +121 -152
- package/v2Containers/Rcs/tests/mockData.js +0 -38
- package/v2Containers/Rcs/tests/utils.test.js +30 -646
- package/v2Containers/Rcs/utils.js +11 -478
- package/v2Containers/Sms/Create/index.js +40 -106
- package/v2Containers/SmsTrai/Create/index.js +4 -9
- package/v2Containers/SmsTrai/Edit/constants.js +0 -2
- package/v2Containers/SmsTrai/Edit/index.js +130 -640
- package/v2Containers/SmsTrai/Edit/messages.js +4 -14
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +2296 -4249
- package/v2Containers/SmsWrapper/index.js +8 -37
- package/v2Containers/TagList/index.js +0 -6
- package/v2Containers/Templates/_templates.scss +9 -166
- package/v2Containers/Templates/actions.js +0 -11
- package/v2Containers/Templates/constants.js +0 -2
- package/v2Containers/Templates/index.js +52 -120
- package/v2Containers/Templates/sagas.js +18 -57
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1017 -1062
- package/v2Containers/Templates/tests/sagas.test.js +39 -205
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +1 -72
- package/v2Containers/TemplatesV2/index.js +23 -86
- package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
- package/v2Containers/Whatsapp/index.js +20 -3
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -578
- package/utils/rcsPayloadUtils.js +0 -92
- package/utils/templateVarUtils.js +0 -201
- package/utils/tests/rcsPayloadUtils.test.js +0 -226
- package/utils/tests/templateVarUtils.test.js +0 -204
- package/v2Components/CommonTestAndPreview/previewApiUtils.js +0 -59
- package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +0 -67
- package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +0 -91
- package/v2Components/SmsFallback/constants.js +0 -73
- package/v2Components/SmsFallback/index.js +0 -956
- package/v2Components/SmsFallback/index.scss +0 -265
- package/v2Components/SmsFallback/messages.js +0 -78
- package/v2Components/SmsFallback/smsFallbackUtils.js +0 -119
- package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +0 -50
- package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +0 -147
- package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +0 -304
- package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +0 -223
- package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +0 -309
- package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +0 -422
- package/v2Components/SmsFallback/useLocalTemplateList.js +0 -92
- package/v2Components/TemplatePreview/constants.js +0 -2
- package/v2Components/VarSegmentMessageEditor/constants.js +0 -2
- package/v2Components/VarSegmentMessageEditor/index.js +0 -125
- package/v2Components/VarSegmentMessageEditor/index.scss +0 -46
- package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +0 -43
- package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +0 -79
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +0 -90
- package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +0 -258
- package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +0 -125
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +0 -225
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -318
- package/v2Containers/Sms/smsFormDataHelpers.js +0 -67
- package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +0 -253
- package/v2Containers/SmsTrai/Edit/index.scss +0 -121
- package/v2Containers/Templates/TemplatesActionBar.js +0 -101
- package/v2Containers/Templates/tests/TemplatesActionBar.test.js +0 -120
- package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +0 -180
- package/v2Containers/Templates/utils/smsTemplatesListApi.js +0 -79
- package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +0 -131
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
+
import {
|
|
4
|
+
CAP_SPACE_16, CAP_SPACE_32, CAP_SPACE_56, CAP_SPACE_64,
|
|
5
|
+
} from '@capillarytech/cap-ui-library/styled/variables';
|
|
6
|
+
|
|
3
7
|
import CapSlideBox from '@capillarytech/cap-ui-library/CapSlideBox';
|
|
4
8
|
import CapHeader from '@capillarytech/cap-ui-library/CapHeader';
|
|
5
9
|
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
@@ -9,11 +13,12 @@ import CapNotification from '@capillarytech/cap-ui-library/CapNotification';
|
|
|
9
13
|
import { injectIntl, FormattedMessage } from 'react-intl';
|
|
10
14
|
import classnames from 'classnames';
|
|
11
15
|
import {
|
|
12
|
-
isEmpty, get, forEach, cloneDeep, debounce,
|
|
16
|
+
isEmpty, get, forEach, cloneDeep, debounce,
|
|
13
17
|
} from 'lodash';
|
|
14
18
|
import { connect } from 'react-redux';
|
|
15
19
|
import { createStructuredSelector } from 'reselect';
|
|
16
20
|
import { bindActionCreators, compose } from 'redux';
|
|
21
|
+
import styled from 'styled-components';
|
|
17
22
|
import { GA } from '@capillarytech/cap-ui-utils';
|
|
18
23
|
import { DAEMON } from '@capillarytech/vulcan-react-sdk/utils/sagaInjectorTypes';
|
|
19
24
|
|
|
@@ -27,7 +32,6 @@ import SlideBoxContent from './SlideBoxContent';
|
|
|
27
32
|
import * as constants from './constants';
|
|
28
33
|
import * as commonUtil from '../../utils/common';
|
|
29
34
|
import { gtmPush } from '../../utils/gtmTrackers';
|
|
30
|
-
import { normalizeRcsMessageContentForApi } from '../../utils/rcsPayloadUtils';
|
|
31
35
|
import './index.scss';
|
|
32
36
|
import * as templateActions from '../Templates/actions';
|
|
33
37
|
import * as globalActions from '../Cap/actions';
|
|
@@ -43,9 +47,6 @@ import {
|
|
|
43
47
|
import {EXTERNAL_URL, SITE_URL, WEBPUSH_MEDIA_TYPES} from '../WebPush/constants';
|
|
44
48
|
import { IMAGE, VIDEO } from '../Facebook/Advertisement/constant';
|
|
45
49
|
import { RCS_STATUSES } from '../Rcs/constants';
|
|
46
|
-
import { mapRcsCardContentForConsumerWithResolvedTags } from '../Rcs/utils';
|
|
47
|
-
import { pickRcsCardVarMappedEntries } from '../Rcs/rcsLibraryHydrationUtils';
|
|
48
|
-
import { RCS_SMS_FALLBACK_VAR_MAPPED_PROP } from '../../v2Components/CommonTestAndPreview/constants';
|
|
49
50
|
import { CREATIVE } from '../Facebook/constants';
|
|
50
51
|
import { LOYALTY } from '../App/constants';
|
|
51
52
|
import {
|
|
@@ -60,11 +61,6 @@ import { capSagaForFetchSchemaForEntity, capSagaLiquidEntity } from '../Cap/saga
|
|
|
60
61
|
import { v2TemplateSagaWatchGetDefaultBeeTemplates } from '../Templates/sagas';
|
|
61
62
|
import { DYNAMIC_URL } from '../../v2Components/CapWhatsappCTA/constants';
|
|
62
63
|
import ErrorInfoNote from '../../v2Components/ErrorInfoNote';
|
|
63
|
-
import SlideBoxWrapper from './CreativesSlideBoxWrapper';
|
|
64
|
-
import {
|
|
65
|
-
computeLiquidFooterUpdateFromFormBuilder,
|
|
66
|
-
getSlideBoxWrapperMarginFromLiquidErrors,
|
|
67
|
-
} from './embeddedSlideboxUtils';
|
|
68
64
|
|
|
69
65
|
import {
|
|
70
66
|
transformChannelPayload,
|
|
@@ -73,24 +69,51 @@ import {
|
|
|
73
69
|
import { MANUAL_CAROUSEL } from '../MobilePushNew/constants';
|
|
74
70
|
import { BIG_HTML } from '../InApp/constants';
|
|
75
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Returns true if value is "deep empty": no errors present.
|
|
74
|
+
* - null/undefined: empty
|
|
75
|
+
* - string: empty if length === 0
|
|
76
|
+
* - array: empty if length === 0
|
|
77
|
+
* - plain object (e.g. { android: [], ios: [], generic: [] }): empty only if every value is deep-empty
|
|
78
|
+
*/
|
|
79
|
+
function isDeepEmpty(value) {
|
|
80
|
+
if (value == null) return true;
|
|
81
|
+
if (typeof value === 'string') return value.length === 0;
|
|
82
|
+
if (Array.isArray(value)) return value.length === 0;
|
|
83
|
+
if (typeof value === 'object') {
|
|
84
|
+
return Object.values(value).every(isDeepEmpty);
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
76
89
|
const classPrefix = 'add-creatives-section';
|
|
77
90
|
const CREATIVES_CONTAINER = 'creativesContainer';
|
|
78
91
|
|
|
92
|
+
const SlideBoxWrapper = styled.div`
|
|
93
|
+
.cap-slide-box-v2-container{
|
|
94
|
+
.slidebox-header, .slidebox-content-container{
|
|
95
|
+
margin-bottom: ${({ slideBoxWrapperMargin }) => `${slideBoxWrapperMargin}`};
|
|
96
|
+
padding: 0 rem;
|
|
97
|
+
&.has-footer{
|
|
98
|
+
overflow-x: hidden;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
.slidebox-footer{
|
|
102
|
+
/* Only apply margin-bottom to footer when ErrorInfoNote is shown in footer (BEE editor) */
|
|
103
|
+
/* For HTML Editor, errors are shown in ValidationErrorDisplay (inside content area), so no footer margin needed */
|
|
104
|
+
margin-bottom: ${({ shouldApplyFooterMargin }) => (shouldApplyFooterMargin ? `${CAP_SPACE_16}` : '0')};
|
|
105
|
+
padding: 0 rem;
|
|
106
|
+
&.has-footer{
|
|
107
|
+
overflow-x: hidden;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
`;
|
|
79
112
|
export class Creatives extends React.Component {
|
|
80
113
|
constructor(props) {
|
|
81
114
|
super(props);
|
|
82
115
|
|
|
83
|
-
const
|
|
84
|
-
props,
|
|
85
|
-
'localTemplatesConfig.useLocalTemplates',
|
|
86
|
-
get(props, 'useLocalTemplates', false),
|
|
87
|
-
);
|
|
88
|
-
const initialSlidBoxContent = this.getSlideBoxContent({
|
|
89
|
-
mode: props.creativesMode,
|
|
90
|
-
templateData: props.templateData,
|
|
91
|
-
isFullMode: props.isFullMode,
|
|
92
|
-
useLocalTemplates,
|
|
93
|
-
});
|
|
116
|
+
const initialSlidBoxContent = this.getSlideBoxContent({ mode: props.creativesMode, templateData: props.templateData, isFullMode: props.isFullMode });
|
|
94
117
|
|
|
95
118
|
this.state = {
|
|
96
119
|
isLoadingContent: true,
|
|
@@ -137,13 +160,7 @@ export class Creatives extends React.Component {
|
|
|
137
160
|
}
|
|
138
161
|
|
|
139
162
|
componentWillUnmount() {
|
|
140
|
-
|
|
141
|
-
const useLocalTemplates = get(
|
|
142
|
-
this.props,
|
|
143
|
-
'localTemplatesConfig.useLocalTemplates',
|
|
144
|
-
get(this.props, 'useLocalTemplates', false),
|
|
145
|
-
);
|
|
146
|
-
if (isEmbedded && !useLocalTemplates) {
|
|
163
|
+
if (get(this.props, 'location.query.type', '') === "embedded") {
|
|
147
164
|
this.props.templateActions.resetTemplateStoreData();
|
|
148
165
|
}
|
|
149
166
|
this.props.globalActions.clearMetaEntities();
|
|
@@ -751,69 +768,15 @@ export class Creatives extends React.Component {
|
|
|
751
768
|
smsFallBackContent = {},
|
|
752
769
|
creativeName = "",
|
|
753
770
|
channel = constants.RCS,
|
|
754
|
-
rcsCardVarMapped,
|
|
755
771
|
accountId = "",
|
|
756
772
|
} = templateData || {};
|
|
757
|
-
const
|
|
758
|
-
const isCarouselRcs = (rcsContent?.cardType || '').toString().toLowerCase() === 'carousel';
|
|
759
|
-
const firstCardIn = (rcsContent.cardContent && rcsContent.cardContent[0]) || {};
|
|
760
|
-
const {
|
|
761
|
-
cardDisplayTitle: _omitDispTitleIn,
|
|
762
|
-
cardDisplayDescription: _omitDispDescIn,
|
|
763
|
-
...cardContent
|
|
764
|
-
} = firstCardIn;
|
|
773
|
+
const cardContent = (rcsContent.cardContent && rcsContent.cardContent[0]) || {};
|
|
765
774
|
const Status = RCS_STATUSES.approved || '';
|
|
766
|
-
const mergedCardVarMapped = (() => {
|
|
767
|
-
const nestedCardVarMapped = cardContent?.cardVarMapped;
|
|
768
|
-
const rootMirrorCardVarMapped = rcsCardVarMapped;
|
|
769
|
-
const nestedRecord =
|
|
770
|
-
nestedCardVarMapped != null && typeof nestedCardVarMapped === 'object'
|
|
771
|
-
? nestedCardVarMapped
|
|
772
|
-
: {};
|
|
773
|
-
const rootRecord =
|
|
774
|
-
rootMirrorCardVarMapped != null && typeof rootMirrorCardVarMapped === 'object'
|
|
775
|
-
? rootMirrorCardVarMapped
|
|
776
|
-
: {};
|
|
777
|
-
const mergedFromRootAndNested = {
|
|
778
|
-
...pickRcsCardVarMappedEntries(rootRecord),
|
|
779
|
-
...pickRcsCardVarMappedEntries(nestedRecord),
|
|
780
|
-
};
|
|
781
|
-
return Object.keys(mergedFromRootAndNested).length > 0
|
|
782
|
-
? mergedFromRootAndNested
|
|
783
|
-
: null;
|
|
784
|
-
})();
|
|
785
|
-
// Campaigns (embedded): do not duplicate `cardVarMapped` as root `rcsCardVarMapped` on send —
|
|
786
|
-
// slot map stays on `versions…cardContent[0].cardVarMapped` only. Library full mode keeps root mirror.
|
|
787
|
-
// Use `=== true` so omitted/undefined `isFullMode` does not behave like library (avoids duplicate on approval payload).
|
|
788
|
-
const includeRootRcsCardVarMapped =
|
|
789
|
-
mergedCardVarMapped && isFullModeForRcsPayload === true;
|
|
790
|
-
|
|
791
|
-
const builtCardContent = isCarouselRcs
|
|
792
|
-
? (rcsContent.cardContent || []).map((card, idx) => {
|
|
793
|
-
const {
|
|
794
|
-
cardDisplayTitle: _dt,
|
|
795
|
-
cardDisplayDescription: _dd,
|
|
796
|
-
...restCard
|
|
797
|
-
} = card || {};
|
|
798
|
-
return {
|
|
799
|
-
...restCard,
|
|
800
|
-
...(idx === 0 && mergedCardVarMapped ? { cardVarMapped: mergedCardVarMapped } : {}),
|
|
801
|
-
Status,
|
|
802
|
-
};
|
|
803
|
-
})
|
|
804
|
-
: [
|
|
805
|
-
{
|
|
806
|
-
...cardContent,
|
|
807
|
-
...(mergedCardVarMapped ? { cardVarMapped: mergedCardVarMapped } : {}),
|
|
808
|
-
Status,
|
|
809
|
-
},
|
|
810
|
-
];
|
|
811
775
|
|
|
812
776
|
creativesTemplateData = {
|
|
813
777
|
type: channel,
|
|
814
778
|
edit: true,
|
|
815
779
|
name: creativeName,
|
|
816
|
-
...(includeRootRcsCardVarMapped ? { rcsCardVarMapped: mergedCardVarMapped } : {}),
|
|
817
780
|
versions: {
|
|
818
781
|
base: {
|
|
819
782
|
content: {
|
|
@@ -821,7 +784,12 @@ export class Creatives extends React.Component {
|
|
|
821
784
|
rcsContent: {
|
|
822
785
|
...rcsContent,
|
|
823
786
|
...(accountId && !isFullMode && { accountId }),
|
|
824
|
-
cardContent:
|
|
787
|
+
cardContent: [
|
|
788
|
+
{
|
|
789
|
+
...cardContent,
|
|
790
|
+
Status,
|
|
791
|
+
},
|
|
792
|
+
],
|
|
825
793
|
},
|
|
826
794
|
smsFallBackContent,
|
|
827
795
|
},
|
|
@@ -969,10 +937,7 @@ export class Creatives extends React.Component {
|
|
|
969
937
|
return newExpandableDetails;
|
|
970
938
|
}
|
|
971
939
|
|
|
972
|
-
getCreativesData = async (
|
|
973
|
-
const channel = String(
|
|
974
|
-
channelParam || template?.type || get(template, 'value.type') || '',
|
|
975
|
-
).toUpperCase();
|
|
940
|
+
getCreativesData = async (channel, template, templateRecords) => { //from creatives to consumers
|
|
976
941
|
let templateData = { channel };
|
|
977
942
|
switch (channel) {
|
|
978
943
|
case constants.SMS:
|
|
@@ -1319,104 +1284,28 @@ export class Creatives extends React.Component {
|
|
|
1319
1284
|
break;
|
|
1320
1285
|
case constants.RCS:
|
|
1321
1286
|
if (template.value) {
|
|
1322
|
-
const {
|
|
1323
|
-
|
|
1324
|
-
const
|
|
1325
|
-
const fromRecords = {
|
|
1326
|
-
...(templateRecords?.smsFallBackContent || {}),
|
|
1327
|
-
...(get(templateRecords, 'versions.base.content.RCS.smsFallBackContent') || {}),
|
|
1328
|
-
};
|
|
1329
|
-
const hasMeaningfulRcsSmsFallback = (smsFallbackPayload) => {
|
|
1330
|
-
if (
|
|
1331
|
-
!smsFallbackPayload
|
|
1332
|
-
|| typeof smsFallbackPayload !== 'object'
|
|
1333
|
-
|| Object.keys(smsFallbackPayload).length === 0
|
|
1334
|
-
) {
|
|
1335
|
-
return false;
|
|
1336
|
-
}
|
|
1337
|
-
const fallbackBodyText = String(
|
|
1338
|
-
smsFallbackPayload.smsContent
|
|
1339
|
-
?? smsFallbackPayload.smsTemplateContent
|
|
1340
|
-
?? smsFallbackPayload.message
|
|
1341
|
-
?? smsFallbackPayload.content
|
|
1342
|
-
?? '',
|
|
1343
|
-
).trim();
|
|
1344
|
-
const fallbackTemplateName = String(
|
|
1345
|
-
smsFallbackPayload.smsTemplateName ?? smsFallbackPayload.templateName ?? '',
|
|
1346
|
-
).trim();
|
|
1347
|
-
const rcsSmsFallbackVarMapped =
|
|
1348
|
-
smsFallbackPayload?.[RCS_SMS_FALLBACK_VAR_MAPPED_PROP];
|
|
1349
|
-
const hasVarMappedEntries =
|
|
1350
|
-
rcsSmsFallbackVarMapped != null
|
|
1351
|
-
&& typeof rcsSmsFallbackVarMapped === 'object'
|
|
1352
|
-
&& Object.keys(rcsSmsFallbackVarMapped).length > 0;
|
|
1353
|
-
return (
|
|
1354
|
-
fallbackBodyText !== ''
|
|
1355
|
-
|| fallbackTemplateName !== ''
|
|
1356
|
-
|| hasVarMappedEntries
|
|
1357
|
-
);
|
|
1358
|
-
};
|
|
1359
|
-
// If submit has only empty strings, do not let it wipe fallback mirrored on templateRecords (library round-trip).
|
|
1360
|
-
const smsFallBackContent = hasMeaningfulRcsSmsFallback(fromSubmit)
|
|
1361
|
-
? { ...fromRecords, ...fromSubmit }
|
|
1362
|
-
: { ...fromSubmit, ...fromRecords };
|
|
1287
|
+
const { name = "", versions = {} } = {
|
|
1288
|
+
} = template.value || {};
|
|
1289
|
+
const smsFallBackContent = get(versions, 'base.content.RCS.smsFallBackContent', {});
|
|
1363
1290
|
const {
|
|
1364
|
-
cardContent
|
|
1291
|
+
cardContent = [],
|
|
1365
1292
|
contentType = "",
|
|
1366
1293
|
cardType = "",
|
|
1367
1294
|
cardSettings = {},
|
|
1368
1295
|
accountId = "",
|
|
1369
1296
|
} = get(versions, 'base.content.RCS.rcsContent', {});
|
|
1370
|
-
const rootRcsCardVarMappedFromSubmit = get(template, 'value.rcsCardVarMapped');
|
|
1371
|
-
const firstCardFromSubmit = Array.isArray(cardContentFromSubmit)
|
|
1372
|
-
? cardContentFromSubmit[0]
|
|
1373
|
-
: null;
|
|
1374
|
-
const cardContent = mapRcsCardContentForConsumerWithResolvedTags(
|
|
1375
|
-
cardContentFromSubmit,
|
|
1376
|
-
rootRcsCardVarMappedFromSubmit,
|
|
1377
|
-
isFullModeForRcsConsumerPayload,
|
|
1378
|
-
);
|
|
1379
1297
|
const rcsContent = {
|
|
1380
1298
|
contentType,
|
|
1381
1299
|
cardType,
|
|
1382
1300
|
cardSettings,
|
|
1383
1301
|
cardContent,
|
|
1384
1302
|
};
|
|
1385
|
-
const cardVarMappedFromFirstRcsCard =
|
|
1386
|
-
firstCardFromSubmit?.cardVarMapped != null
|
|
1387
|
-
&& typeof firstCardFromSubmit.cardVarMapped === 'object'
|
|
1388
|
-
? pickRcsCardVarMappedEntries(firstCardFromSubmit.cardVarMapped)
|
|
1389
|
-
: null;
|
|
1390
|
-
const includeRootRcsCardVarMappedOnConsumerPayload =
|
|
1391
|
-
cardVarMappedFromFirstRcsCard
|
|
1392
|
-
&& Object.keys(cardVarMappedFromFirstRcsCard).length > 0
|
|
1393
|
-
&& isFullModeForRcsConsumerPayload === true;
|
|
1394
1303
|
templateData = {
|
|
1395
1304
|
channel,
|
|
1396
1305
|
creativeName: name,
|
|
1397
1306
|
rcsContent,
|
|
1398
1307
|
accountId,
|
|
1399
|
-
...(includeRootRcsCardVarMappedOnConsumerPayload
|
|
1400
|
-
? { rcsCardVarMapped: cardVarMappedFromFirstRcsCard }
|
|
1401
|
-
: {}),
|
|
1402
1308
|
};
|
|
1403
|
-
// Library / campaign consumers round-trip templateData via getTemplateData; include SMS fallback
|
|
1404
|
-
// so reopening the editor restores fallback text and tag mappings.
|
|
1405
|
-
// cap-campaigns-v2 API expects `smsFallBackContent.message` (see normalizeRcsMessageContentForApi).
|
|
1406
|
-
if (hasMeaningfulRcsSmsFallback(smsFallBackContent)) {
|
|
1407
|
-
const smsText =
|
|
1408
|
-
smsFallBackContent.message
|
|
1409
|
-
?? smsFallBackContent.smsContent
|
|
1410
|
-
?? smsFallBackContent.smsTemplateContent
|
|
1411
|
-
?? '';
|
|
1412
|
-
templateData.smsFallBackContent = {
|
|
1413
|
-
...smsFallBackContent,
|
|
1414
|
-
...(String(smsText).trim() !== ''
|
|
1415
|
-
? { message: String(smsText).trim() }
|
|
1416
|
-
: {}),
|
|
1417
|
-
};
|
|
1418
|
-
}
|
|
1419
|
-
normalizeRcsMessageContentForApi(templateData);
|
|
1420
1309
|
}
|
|
1421
1310
|
break;
|
|
1422
1311
|
case constants.ZALO:
|
|
@@ -1534,10 +1423,7 @@ export class Creatives extends React.Component {
|
|
|
1534
1423
|
return templateData;
|
|
1535
1424
|
};
|
|
1536
1425
|
|
|
1537
|
-
getSlideBoxContent({ mode, templateData, isFullMode
|
|
1538
|
-
if (useLocalTemplates && mode === 'create' && isEmpty(templateData)) {
|
|
1539
|
-
return 'templates';
|
|
1540
|
-
}
|
|
1426
|
+
getSlideBoxContent({ mode, templateData, isFullMode }) {
|
|
1541
1427
|
let creativesMode = isFullMode ? 'createTemplate' : 'templates';// for library mode templates page is initial mode and for full mode createTemplates
|
|
1542
1428
|
if (mode === 'create' && isFullMode) {
|
|
1543
1429
|
creativesMode = 'createTemplate';
|
|
@@ -1625,110 +1511,24 @@ export class Creatives extends React.Component {
|
|
|
1625
1511
|
getFormData = (template) => {
|
|
1626
1512
|
// Always reset isGetFormData so the child does not re-send form data on every re-render
|
|
1627
1513
|
// (e.g. when user fixes validation error by typing, we must not auto-close the slidebox)
|
|
1628
|
-
this.setState(
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|| ''
|
|
1640
|
-
).toUpperCase();
|
|
1641
|
-
// Library mode: persist last submitted creatives shape so reopening still hydrates the editor
|
|
1642
|
-
// (parent may not merge getCreativesData back into templateData).
|
|
1643
|
-
if (this.props.isFullMode === false && template.value) {
|
|
1644
|
-
if (channel === constants.RCS) {
|
|
1645
|
-
const smsFallBackFromPayload = get(
|
|
1646
|
-
template.value,
|
|
1647
|
-
'versions.base.content.RCS.smsFallBackContent',
|
|
1648
|
-
);
|
|
1649
|
-
const rcsCardVarMappedFromPayload = get(
|
|
1650
|
-
template.value,
|
|
1651
|
-
'versions.base.content.RCS.rcsContent.cardContent[0].cardVarMapped',
|
|
1652
|
-
);
|
|
1653
|
-
next.templateData = {
|
|
1654
|
-
...baseTd,
|
|
1655
|
-
type: constants.RCS,
|
|
1656
|
-
name: template?.value?.name,
|
|
1657
|
-
versions: template?.value?.versions,
|
|
1658
|
-
...(smsFallBackFromPayload != null
|
|
1659
|
-
&& typeof smsFallBackFromPayload === 'object'
|
|
1660
|
-
&& Object.keys(smsFallBackFromPayload).length > 0
|
|
1661
|
-
? { smsFallBackContent: smsFallBackFromPayload }
|
|
1662
|
-
: {}),
|
|
1663
|
-
...(rcsCardVarMappedFromPayload != null
|
|
1664
|
-
&& typeof rcsCardVarMappedFromPayload === 'object'
|
|
1665
|
-
? { rcsCardVarMapped: rcsCardVarMappedFromPayload }
|
|
1666
|
-
: {}),
|
|
1667
|
-
};
|
|
1668
|
-
if (template._id) {
|
|
1669
|
-
next.templateData._id = template._id;
|
|
1670
|
-
}
|
|
1671
|
-
} else if (channel === constants.SMS) {
|
|
1672
|
-
const submittedSmsTemplateValue = template?.value;
|
|
1673
|
-
const smsVersions =
|
|
1674
|
-
submittedSmsTemplateValue?.history != null
|
|
1675
|
-
? submittedSmsTemplateValue
|
|
1676
|
-
: {
|
|
1677
|
-
base: submittedSmsTemplateValue?.base,
|
|
1678
|
-
history: submittedSmsTemplateValue?.base
|
|
1679
|
-
? [submittedSmsTemplateValue.base]
|
|
1680
|
-
: [],
|
|
1681
|
-
};
|
|
1682
|
-
next.templateData = {
|
|
1683
|
-
...baseTd,
|
|
1684
|
-
type: constants.SMS,
|
|
1685
|
-
name: baseTd?.name || 'Campaign message SMS content',
|
|
1686
|
-
versions: smsVersions,
|
|
1687
|
-
};
|
|
1688
|
-
if (template?._id) {
|
|
1689
|
-
next.templateData._id = template._id;
|
|
1690
|
-
}
|
|
1691
|
-
}
|
|
1692
|
-
}
|
|
1693
|
-
return next;
|
|
1694
|
-
},
|
|
1695
|
-
() => {
|
|
1696
|
-
if (!template.validity) {
|
|
1697
|
-
return;
|
|
1698
|
-
}
|
|
1699
|
-
const templateData = this.state.templateData ? this.state.templateData : template; //select existing or create new content
|
|
1700
|
-
const channelForConsumer = String(
|
|
1701
|
-
templateData.type
|
|
1702
|
-
|| template.type
|
|
1703
|
-
|| get(template, 'value.type')
|
|
1704
|
-
|| '',
|
|
1705
|
-
).toUpperCase();
|
|
1706
|
-
const creativesData = this.getCreativesData(
|
|
1707
|
-
channelForConsumer,
|
|
1708
|
-
template,
|
|
1709
|
-
this.state.templateData || template,
|
|
1710
|
-
);// convers data to consumer understandable format
|
|
1711
|
-
creativesData.then((data) => {
|
|
1712
|
-
this.logGTMEvent(channelForConsumer, data);
|
|
1713
|
-
this.processCentralCommsMetaId(channelForConsumer, data, {
|
|
1714
|
-
closeSlideBoxAfterSubmit: template.closeSlideBoxAfterSubmit,
|
|
1514
|
+
this.setState({ isGetFormData: false });
|
|
1515
|
+
if (template.validity) {
|
|
1516
|
+
this.setState(
|
|
1517
|
+
{},
|
|
1518
|
+
() => {
|
|
1519
|
+
const templateData = this.state.templateData ? this.state.templateData : template; //select existing or create new content
|
|
1520
|
+
const channel = templateData.type;
|
|
1521
|
+
const creativesData = this.getCreativesData(channel, template, templateData);// convers data to consumer understandable format
|
|
1522
|
+
creativesData.then((data) => {
|
|
1523
|
+
this.logGTMEvent(channel, data);
|
|
1524
|
+
this.processCentralCommsMetaId(channel, data);
|
|
1715
1525
|
});
|
|
1716
|
-
}
|
|
1717
|
-
|
|
1718
|
-
|
|
1526
|
+
},
|
|
1527
|
+
);
|
|
1528
|
+
}
|
|
1719
1529
|
}
|
|
1720
1530
|
|
|
1721
|
-
processCentralCommsMetaId = (channel, creativesData
|
|
1722
|
-
const { closeSlideBoxAfterSubmit = false } = options;
|
|
1723
|
-
const maybeCloseLibrarySlideBox = () => {
|
|
1724
|
-
if (
|
|
1725
|
-
closeSlideBoxAfterSubmit
|
|
1726
|
-
&& this.props.isFullMode === false
|
|
1727
|
-
&& typeof this.handleCloseSlideBox === 'function'
|
|
1728
|
-
) {
|
|
1729
|
-
this.handleCloseSlideBox();
|
|
1730
|
-
}
|
|
1731
|
-
};
|
|
1531
|
+
processCentralCommsMetaId = (channel, creativesData) => {
|
|
1732
1532
|
// Create the payload for the centralcommnsmetaId API call
|
|
1733
1533
|
const { isLoyaltyModule = false, loyaltyMetaData = {} } = this.props;
|
|
1734
1534
|
const { actionName, setMetaData = () => { } } = loyaltyMetaData;
|
|
@@ -1754,7 +1554,6 @@ export class Creatives extends React.Component {
|
|
|
1754
1554
|
if (result?.status?.code === 200) {
|
|
1755
1555
|
setMetaData(result);
|
|
1756
1556
|
this.props.getCreativesData(creativesData);
|
|
1757
|
-
maybeCloseLibrarySlideBox();
|
|
1758
1557
|
} else {
|
|
1759
1558
|
CapNotification.error({ message: <FormattedMessage {...messages.somethingWentWrong} /> });
|
|
1760
1559
|
}
|
|
@@ -1765,7 +1564,6 @@ export class Creatives extends React.Component {
|
|
|
1765
1564
|
} else {
|
|
1766
1565
|
// If not a loyalty module or different action, should work as usual
|
|
1767
1566
|
this.props.getCreativesData(creativesData);
|
|
1768
|
-
maybeCloseLibrarySlideBox();
|
|
1769
1567
|
}
|
|
1770
1568
|
};
|
|
1771
1569
|
|
|
@@ -1798,9 +1596,7 @@ export class Creatives extends React.Component {
|
|
|
1798
1596
|
}
|
|
1799
1597
|
this.setState((prevState) => ({
|
|
1800
1598
|
...prevState,
|
|
1801
|
-
|
|
1802
|
-
// Undefined isFullMode defaults to full-mode close behavior (clear templateData).
|
|
1803
|
-
...(this.props.isFullMode !== false ? { templateData: undefined } : {}),
|
|
1599
|
+
templateData: undefined,
|
|
1804
1600
|
showSlideBox: false,
|
|
1805
1601
|
liquidErrorMessage: { STANDARD_ERROR_MSG: [], LIQUID_ERROR_MSG: [] },
|
|
1806
1602
|
isLiquidValidationError: false,
|
|
@@ -2011,17 +1807,21 @@ export class Creatives extends React.Component {
|
|
|
2011
1807
|
}
|
|
2012
1808
|
|
|
2013
1809
|
showLiquidErrorInFooter = (errorMessagesFromFormBuilder, currentFormBuilderTab) => {
|
|
2014
|
-
const
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
this.setState(
|
|
1810
|
+
const liquidMsgs = get(errorMessagesFromFormBuilder, constants.LIQUID_ERROR_MSG, []);
|
|
1811
|
+
const standardMsgs = get(errorMessagesFromFormBuilder, constants.STANDARD_ERROR_MSG, []);
|
|
1812
|
+
const hasLiquid = !isDeepEmpty(liquidMsgs);
|
|
1813
|
+
const hasStandard = !isDeepEmpty(standardMsgs);
|
|
1814
|
+
const isLiquidValidationError = hasLiquid || hasStandard;
|
|
1815
|
+
// Don't overwrite existing liquid error with empty only for Mobile Push OLD (FormBuilder/clear calls empty there); SMS/others clear on input change
|
|
1816
|
+
const isMobilePush = this.state.currentChannel?.toUpperCase() === constants.MOBILE_PUSH;
|
|
1817
|
+
if (!hasLiquid && !hasStandard && this.state.isLiquidValidationError && isMobilePush) {
|
|
1818
|
+
return;
|
|
1819
|
+
}
|
|
1820
|
+
this.setState({
|
|
1821
|
+
isLiquidValidationError,
|
|
1822
|
+
liquidErrorMessage: errorMessagesFromFormBuilder,
|
|
1823
|
+
activeFormBuilderTab: currentFormBuilderTab === 1 ? constants.ANDROID : (currentFormBuilderTab === 2 ? constants.IOS : null), // Update activeFormBuilderTab, default to 1 if undefined
|
|
1824
|
+
});
|
|
2025
1825
|
}
|
|
2026
1826
|
|
|
2027
1827
|
// Callback to update HTML Editor validation state (called from EmailWrapper)
|
|
@@ -2144,11 +1944,6 @@ export class Creatives extends React.Component {
|
|
|
2144
1944
|
inAppEditorType,
|
|
2145
1945
|
htmlEditorValidationState,
|
|
2146
1946
|
} = this.state;
|
|
2147
|
-
const useLocalTemplates = get(
|
|
2148
|
-
this.props,
|
|
2149
|
-
'localTemplatesConfig.useLocalTemplates',
|
|
2150
|
-
get(this.props, 'useLocalTemplates', false),
|
|
2151
|
-
);
|
|
2152
1947
|
const {
|
|
2153
1948
|
isFullMode,
|
|
2154
1949
|
creativesMode,
|
|
@@ -2167,6 +1962,7 @@ export class Creatives extends React.Component {
|
|
|
2167
1962
|
smsRegister,
|
|
2168
1963
|
enableNewChannels,
|
|
2169
1964
|
eventContextTags,
|
|
1965
|
+
waitEventContextTags = {},
|
|
2170
1966
|
isLoyaltyModule,
|
|
2171
1967
|
loyaltyMetaData = {},
|
|
2172
1968
|
} = this.props;
|
|
@@ -2200,7 +1996,14 @@ export class Creatives extends React.Component {
|
|
|
2200
1996
|
// IMPORTANT: Never show ErrorInfoNote in footer when in HTML Editor mode, even if liquidErrorMessage exists
|
|
2201
1997
|
const shouldShowErrorInfoNoteInFooter = isHTMLEditorMode ? false : hasBEEEditorErrors;
|
|
2202
1998
|
|
|
2203
|
-
|
|
1999
|
+
// Calculate margin for header/content (always apply if there are errors, regardless of editor type)
|
|
2000
|
+
const slideBoxWrapperMargin = (get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0 && get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0)
|
|
2001
|
+
? CAP_SPACE_64
|
|
2002
|
+
: get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0
|
|
2003
|
+
? CAP_SPACE_56
|
|
2004
|
+
: get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0
|
|
2005
|
+
? CAP_SPACE_32
|
|
2006
|
+
: 0;
|
|
2204
2007
|
/* TODO: Instead of passing down same props separately to each component down, write common function to these props and pass it accordingly */
|
|
2205
2008
|
|
|
2206
2009
|
// Compute anonymous user type and channel restrictions
|
|
@@ -2229,10 +2032,7 @@ export class Creatives extends React.Component {
|
|
|
2229
2032
|
<SlideBoxWrapper
|
|
2230
2033
|
slideBoxWrapperMargin={slideBoxWrapperMargin}
|
|
2231
2034
|
shouldApplyFooterMargin={shouldShowErrorInfoNoteInFooter}
|
|
2232
|
-
className={classnames(
|
|
2233
|
-
`${classPrefix} ${isFullMode ? 'creatives-full-mode' : 'creatives-library-mode'} ${mapTemplateCreate ? 'map-template-create' : ''}`,
|
|
2234
|
-
useLocalTemplates && slidBoxContent === 'templates' && 'creatives-slidebox--local-sms-templates',
|
|
2235
|
-
)}
|
|
2035
|
+
className={classnames(`${classPrefix} ${isFullMode ? 'creatives-full-mode' : 'creatives-library-mode'} ${mapTemplateCreate ? 'map-template-create' : ''}`)}
|
|
2236
2036
|
>
|
|
2237
2037
|
<CapSlideBox
|
|
2238
2038
|
header={
|
|
@@ -2257,13 +2057,12 @@ export class Creatives extends React.Component {
|
|
|
2257
2057
|
smsRegister={smsRegister}
|
|
2258
2058
|
handleClose={this.handleCloseSlideBox}
|
|
2259
2059
|
moduleType={this.props.messageDetails?.type}
|
|
2260
|
-
useLocalTemplates={useLocalTemplates}
|
|
2261
2060
|
/>
|
|
2262
2061
|
)}
|
|
2263
2062
|
content={(
|
|
2264
2063
|
<SlideBoxContent
|
|
2265
2064
|
key="creatives-container-slidebox-content"
|
|
2266
|
-
onSelectTemplate={this.
|
|
2065
|
+
onSelectTemplate={this.onSelectTemplate}
|
|
2267
2066
|
onCreateComplete={getCreativesData}
|
|
2268
2067
|
onPreviewTemplate={this.onPreviewTemplate}
|
|
2269
2068
|
slidBoxContent={slidBoxContent}
|
|
@@ -2331,6 +2130,7 @@ export class Creatives extends React.Component {
|
|
|
2331
2130
|
creativesMode={creativesMode} // An existing prop that we're using here. Required to ensure correct account details in Edit or Preview in case of Embedded mode.
|
|
2332
2131
|
hostName={this.props?.hostName || ''}
|
|
2333
2132
|
eventContextTags={eventContextTags}
|
|
2133
|
+
waitEventContextTags={waitEventContextTags}
|
|
2334
2134
|
isLoyaltyModule={isLoyaltyModule}
|
|
2335
2135
|
loyaltyMetaData={loyaltyMetaData}
|
|
2336
2136
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
@@ -2339,8 +2139,7 @@ export class Creatives extends React.Component {
|
|
|
2339
2139
|
isTestAndPreviewMode={(() => this.state.isTestAndPreviewMode)()}
|
|
2340
2140
|
onHtmlEditorValidationStateChange={this.updateHtmlEditorValidationState}
|
|
2341
2141
|
onPersonalizationTokensChange={this.handlePersonalizationTokensChange}
|
|
2342
|
-
|
|
2343
|
-
/>
|
|
2142
|
+
/>
|
|
2344
2143
|
)}
|
|
2345
2144
|
footer={this.shouldShowFooter() ? (
|
|
2346
2145
|
<SlideBoxFooter
|
|
@@ -2425,31 +2224,13 @@ Creatives.propTypes = {
|
|
|
2425
2224
|
orgUnitId: PropTypes.number,
|
|
2426
2225
|
hostName: PropTypes.string,
|
|
2427
2226
|
eventContextTags: PropTypes.array,
|
|
2227
|
+
waitEventContextTags: PropTypes.object,
|
|
2428
2228
|
loyaltyTagFetchingDependencies: PropTypes.object,
|
|
2429
2229
|
customerType: PropTypes.string,
|
|
2430
2230
|
intl: PropTypes.shape({
|
|
2431
2231
|
formatMessage: PropTypes.func,
|
|
2432
2232
|
}),
|
|
2433
2233
|
stopValidation: PropTypes.func,
|
|
2434
|
-
// Local template list (e.g. for SMS fallback): when set, TemplatesV2 uses these instead of Redux.
|
|
2435
|
-
// All optional. Pass either localTemplatesConfig (object) or individual props below.
|
|
2436
|
-
localTemplatesConfig: PropTypes.shape({
|
|
2437
|
-
useLocalTemplates: PropTypes.bool,
|
|
2438
|
-
localTemplates: PropTypes.arrayOf(PropTypes.object),
|
|
2439
|
-
localTemplatesLoading: PropTypes.bool,
|
|
2440
|
-
localTemplatesFilterContent: PropTypes.node,
|
|
2441
|
-
localTemplatesSentinelContent: PropTypes.node,
|
|
2442
|
-
localTemplatesScrollContainerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
|
2443
|
-
localTemplatesUseSkeleton: PropTypes.bool,
|
|
2444
|
-
}),
|
|
2445
|
-
useLocalTemplates: PropTypes.bool,
|
|
2446
|
-
localTemplates: PropTypes.arrayOf(PropTypes.object),
|
|
2447
|
-
localTemplatesLoading: PropTypes.bool,
|
|
2448
|
-
localTemplatesFilterContent: PropTypes.node,
|
|
2449
|
-
localTemplatesSentinelContent: PropTypes.node,
|
|
2450
|
-
localTemplatesScrollContainerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
|
2451
|
-
localTemplatesUseSkeleton: PropTypes.bool,
|
|
2452
|
-
onSelectTemplate: PropTypes.func,
|
|
2453
2234
|
};
|
|
2454
2235
|
const mapStatesToProps = () => createStructuredSelector({
|
|
2455
2236
|
isLoading: isLoadingSelector(),
|