@capillarytech/creatives-library 8.0.358 → 8.0.359-alpha.1
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/CapImageUpload/index.js +2 -2
- 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 +214 -21
- package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +16 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +83 -9
- 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/RcsPreviewContent.js +157 -15
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +346 -76
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +150 -4
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +11 -0
- package/v2Components/CommonTestAndPreview/constants.js +38 -2
- package/v2Components/CommonTestAndPreview/index.js +810 -222
- 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/RcsPreviewContent.test.js +281 -283
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +199 -1
- package/v2Components/CommonTestAndPreview/tests/index.test.js +133 -4
- package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +31 -24
- package/v2Components/FormBuilder/index.js +5 -4
- 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 +37 -22
- 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 +13 -1
- 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/CreativesContainer/CreativesSlideBoxWrapper.js +17 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +36 -4
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +14 -5
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +36 -5
- 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 +83 -1
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +79 -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 +120 -11
- package/v2Containers/Rcs/index.js +2577 -812
- package/v2Containers/Rcs/index.scss +281 -8
- package/v2Containers/Rcs/messages.js +34 -3
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +225 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +98036 -70145
- 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 +121 -53
- 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/Whatsapp/index.js +3 -20
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +578 -34
|
@@ -44,10 +44,6 @@ class TemplateNameInputField extends React.Component {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
import PropTypes from 'prop-types';
|
|
47
|
-
import {
|
|
48
|
-
CAP_SPACE_16, CAP_SPACE_32, CAP_SPACE_56, CAP_SPACE_64,
|
|
49
|
-
} from '@capillarytech/cap-ui-library/styled/variables';
|
|
50
|
-
|
|
51
47
|
import CapSlideBox from '@capillarytech/cap-ui-library/CapSlideBox';
|
|
52
48
|
import CapHeader from '@capillarytech/cap-ui-library/CapHeader';
|
|
53
49
|
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
@@ -57,12 +53,11 @@ import CapNotification from '@capillarytech/cap-ui-library/CapNotification';
|
|
|
57
53
|
import { injectIntl, FormattedMessage } from 'react-intl';
|
|
58
54
|
import classnames from 'classnames';
|
|
59
55
|
import {
|
|
60
|
-
isEmpty, get, forEach, cloneDeep, debounce,
|
|
56
|
+
isEmpty, get, forEach, cloneDeep, debounce, pick,
|
|
61
57
|
} from 'lodash';
|
|
62
58
|
import { connect } from 'react-redux';
|
|
63
59
|
import { createStructuredSelector } from 'reselect';
|
|
64
60
|
import { bindActionCreators, compose } from 'redux';
|
|
65
|
-
import styled from 'styled-components';
|
|
66
61
|
import { GA } from '@capillarytech/cap-ui-utils';
|
|
67
62
|
import { DAEMON } from '@capillarytech/vulcan-react-sdk/utils/sagaInjectorTypes';
|
|
68
63
|
|
|
@@ -76,6 +71,7 @@ import SlideBoxContent from './SlideBoxContent';
|
|
|
76
71
|
import * as constants from './constants';
|
|
77
72
|
import * as commonUtil from '../../utils/common';
|
|
78
73
|
import { gtmPush } from '../../utils/gtmTrackers';
|
|
74
|
+
import { normalizeRcsMessageContentForApi } from '../../utils/rcsPayloadUtils';
|
|
79
75
|
import './index.scss';
|
|
80
76
|
import * as templateActions from '../Templates/actions';
|
|
81
77
|
import * as globalActions from '../Cap/actions';
|
|
@@ -91,6 +87,9 @@ import {
|
|
|
91
87
|
import {EXTERNAL_URL, SITE_URL, WEBPUSH_MEDIA_TYPES} from '../WebPush/constants';
|
|
92
88
|
import { IMAGE, VIDEO } from '../Facebook/Advertisement/constant';
|
|
93
89
|
import { RCS_STATUSES } from '../Rcs/constants';
|
|
90
|
+
import { mapRcsCardContentForConsumerWithResolvedTags } from '../Rcs/utils';
|
|
91
|
+
import { pickRcsCardVarMappedEntries } from '../Rcs/rcsLibraryHydrationUtils';
|
|
92
|
+
import { RCS_SMS_FALLBACK_VAR_MAPPED_PROP } from '../../v2Components/CommonTestAndPreview/constants';
|
|
94
93
|
import { CREATIVE } from '../Facebook/constants';
|
|
95
94
|
import { LOYALTY } from '../App/constants';
|
|
96
95
|
import {
|
|
@@ -105,6 +104,11 @@ import { capSagaForFetchSchemaForEntity, capSagaLiquidEntity } from '../Cap/saga
|
|
|
105
104
|
import { v2TemplateSagaWatchGetDefaultBeeTemplates } from '../Templates/sagas';
|
|
106
105
|
import { DYNAMIC_URL } from '../../v2Components/CapWhatsappCTA/constants';
|
|
107
106
|
import ErrorInfoNote from '../../v2Components/ErrorInfoNote';
|
|
107
|
+
import SlideBoxWrapper from './CreativesSlideBoxWrapper';
|
|
108
|
+
import {
|
|
109
|
+
computeLiquidFooterUpdateFromFormBuilder,
|
|
110
|
+
getSlideBoxWrapperMarginFromLiquidErrors,
|
|
111
|
+
} from './embeddedSlideboxUtils';
|
|
108
112
|
|
|
109
113
|
import {
|
|
110
114
|
transformChannelPayload,
|
|
@@ -113,51 +117,24 @@ import {
|
|
|
113
117
|
import { MANUAL_CAROUSEL } from '../MobilePushNew/constants';
|
|
114
118
|
import { BIG_HTML } from '../InApp/constants';
|
|
115
119
|
|
|
116
|
-
/**
|
|
117
|
-
* Returns true if value is "deep empty": no errors present.
|
|
118
|
-
* - null/undefined: empty
|
|
119
|
-
* - string: empty if length === 0
|
|
120
|
-
* - array: empty if length === 0
|
|
121
|
-
* - plain object (e.g. { android: [], ios: [], generic: [] }): empty only if every value is deep-empty
|
|
122
|
-
*/
|
|
123
|
-
function isDeepEmpty(value) {
|
|
124
|
-
if (value == null) return true;
|
|
125
|
-
if (typeof value === 'string') return value.length === 0;
|
|
126
|
-
if (Array.isArray(value)) return value.length === 0;
|
|
127
|
-
if (typeof value === 'object') {
|
|
128
|
-
return Object.values(value).every(isDeepEmpty);
|
|
129
|
-
}
|
|
130
|
-
return false;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
120
|
const classPrefix = 'add-creatives-section';
|
|
134
121
|
const CREATIVES_CONTAINER = 'creativesContainer';
|
|
135
122
|
|
|
136
|
-
const SlideBoxWrapper = styled.div`
|
|
137
|
-
.cap-slide-box-v2-container{
|
|
138
|
-
.slidebox-header, .slidebox-content-container{
|
|
139
|
-
margin-bottom: ${({ slideBoxWrapperMargin }) => `${slideBoxWrapperMargin}`};
|
|
140
|
-
padding: 0 rem;
|
|
141
|
-
&.has-footer{
|
|
142
|
-
overflow-x: hidden;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
.slidebox-footer{
|
|
146
|
-
/* Only apply margin-bottom to footer when ErrorInfoNote is shown in footer (BEE editor) */
|
|
147
|
-
/* For HTML Editor, errors are shown in ValidationErrorDisplay (inside content area), so no footer margin needed */
|
|
148
|
-
margin-bottom: ${({ shouldApplyFooterMargin }) => (shouldApplyFooterMargin ? `${CAP_SPACE_16}` : '0')};
|
|
149
|
-
padding: 0 rem;
|
|
150
|
-
&.has-footer{
|
|
151
|
-
overflow-x: hidden;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
`;
|
|
156
123
|
export class Creatives extends React.Component {
|
|
157
124
|
constructor(props) {
|
|
158
125
|
super(props);
|
|
159
126
|
|
|
160
|
-
const
|
|
127
|
+
const useLocalTemplates = get(
|
|
128
|
+
props,
|
|
129
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
130
|
+
get(props, 'useLocalTemplates', false),
|
|
131
|
+
);
|
|
132
|
+
const initialSlidBoxContent = this.getSlideBoxContent({
|
|
133
|
+
mode: props.creativesMode,
|
|
134
|
+
templateData: props.templateData,
|
|
135
|
+
isFullMode: props.isFullMode,
|
|
136
|
+
useLocalTemplates,
|
|
137
|
+
});
|
|
161
138
|
|
|
162
139
|
this.state = {
|
|
163
140
|
isLoadingContent: true,
|
|
@@ -204,7 +181,13 @@ export class Creatives extends React.Component {
|
|
|
204
181
|
}
|
|
205
182
|
|
|
206
183
|
componentWillUnmount() {
|
|
207
|
-
|
|
184
|
+
const isEmbedded = get(this.props, 'location.query.type', '') === "embedded";
|
|
185
|
+
const useLocalTemplates = get(
|
|
186
|
+
this.props,
|
|
187
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
188
|
+
get(this.props, 'useLocalTemplates', false),
|
|
189
|
+
);
|
|
190
|
+
if (isEmbedded && !useLocalTemplates) {
|
|
208
191
|
this.props.templateActions.resetTemplateStoreData();
|
|
209
192
|
}
|
|
210
193
|
this.props.globalActions.clearMetaEntities();
|
|
@@ -812,15 +795,69 @@ export class Creatives extends React.Component {
|
|
|
812
795
|
smsFallBackContent = {},
|
|
813
796
|
creativeName = "",
|
|
814
797
|
channel = constants.RCS,
|
|
798
|
+
rcsCardVarMapped,
|
|
815
799
|
accountId = "",
|
|
816
800
|
} = templateData || {};
|
|
817
|
-
const
|
|
801
|
+
const { isFullMode: isFullModeForRcsPayload } = this.props;
|
|
802
|
+
const isCarouselRcs = (rcsContent?.cardType || '').toString().toLowerCase() === 'carousel';
|
|
803
|
+
const firstCardIn = (rcsContent.cardContent && rcsContent.cardContent[0]) || {};
|
|
804
|
+
const {
|
|
805
|
+
cardDisplayTitle: _omitDispTitleIn,
|
|
806
|
+
cardDisplayDescription: _omitDispDescIn,
|
|
807
|
+
...cardContent
|
|
808
|
+
} = firstCardIn;
|
|
818
809
|
const Status = RCS_STATUSES.approved || '';
|
|
810
|
+
const mergedCardVarMapped = (() => {
|
|
811
|
+
const nestedCardVarMapped = cardContent?.cardVarMapped;
|
|
812
|
+
const rootMirrorCardVarMapped = rcsCardVarMapped;
|
|
813
|
+
const nestedRecord =
|
|
814
|
+
nestedCardVarMapped != null && typeof nestedCardVarMapped === 'object'
|
|
815
|
+
? nestedCardVarMapped
|
|
816
|
+
: {};
|
|
817
|
+
const rootRecord =
|
|
818
|
+
rootMirrorCardVarMapped != null && typeof rootMirrorCardVarMapped === 'object'
|
|
819
|
+
? rootMirrorCardVarMapped
|
|
820
|
+
: {};
|
|
821
|
+
const mergedFromRootAndNested = {
|
|
822
|
+
...pickRcsCardVarMappedEntries(rootRecord),
|
|
823
|
+
...pickRcsCardVarMappedEntries(nestedRecord),
|
|
824
|
+
};
|
|
825
|
+
return Object.keys(mergedFromRootAndNested).length > 0
|
|
826
|
+
? mergedFromRootAndNested
|
|
827
|
+
: null;
|
|
828
|
+
})();
|
|
829
|
+
// Campaigns (embedded): do not duplicate `cardVarMapped` as root `rcsCardVarMapped` on send —
|
|
830
|
+
// slot map stays on `versions…cardContent[0].cardVarMapped` only. Library full mode keeps root mirror.
|
|
831
|
+
// Use `=== true` so omitted/undefined `isFullMode` does not behave like library (avoids duplicate on approval payload).
|
|
832
|
+
const includeRootRcsCardVarMapped =
|
|
833
|
+
mergedCardVarMapped && isFullModeForRcsPayload === true;
|
|
834
|
+
|
|
835
|
+
const builtCardContent = isCarouselRcs
|
|
836
|
+
? (rcsContent.cardContent || []).map((card, idx) => {
|
|
837
|
+
const {
|
|
838
|
+
cardDisplayTitle: _dt,
|
|
839
|
+
cardDisplayDescription: _dd,
|
|
840
|
+
...restCard
|
|
841
|
+
} = card || {};
|
|
842
|
+
return {
|
|
843
|
+
...restCard,
|
|
844
|
+
...(idx === 0 && mergedCardVarMapped ? { cardVarMapped: mergedCardVarMapped } : {}),
|
|
845
|
+
Status,
|
|
846
|
+
};
|
|
847
|
+
})
|
|
848
|
+
: [
|
|
849
|
+
{
|
|
850
|
+
...cardContent,
|
|
851
|
+
...(mergedCardVarMapped ? { cardVarMapped: mergedCardVarMapped } : {}),
|
|
852
|
+
Status,
|
|
853
|
+
},
|
|
854
|
+
];
|
|
819
855
|
|
|
820
856
|
creativesTemplateData = {
|
|
821
857
|
type: channel,
|
|
822
858
|
edit: true,
|
|
823
859
|
name: creativeName,
|
|
860
|
+
...(includeRootRcsCardVarMapped ? { rcsCardVarMapped: mergedCardVarMapped } : {}),
|
|
824
861
|
versions: {
|
|
825
862
|
base: {
|
|
826
863
|
content: {
|
|
@@ -828,12 +865,7 @@ export class Creatives extends React.Component {
|
|
|
828
865
|
rcsContent: {
|
|
829
866
|
...rcsContent,
|
|
830
867
|
...(accountId && !isFullMode && { accountId }),
|
|
831
|
-
cardContent:
|
|
832
|
-
{
|
|
833
|
-
...cardContent,
|
|
834
|
-
Status,
|
|
835
|
-
},
|
|
836
|
-
],
|
|
868
|
+
cardContent: builtCardContent,
|
|
837
869
|
},
|
|
838
870
|
smsFallBackContent,
|
|
839
871
|
},
|
|
@@ -981,7 +1013,10 @@ export class Creatives extends React.Component {
|
|
|
981
1013
|
return newExpandableDetails;
|
|
982
1014
|
}
|
|
983
1015
|
|
|
984
|
-
getCreativesData = async (
|
|
1016
|
+
getCreativesData = async (channelParam, template, templateRecords) => { //from creatives to consumers
|
|
1017
|
+
const channel = String(
|
|
1018
|
+
channelParam || template?.type || get(template, 'value.type') || '',
|
|
1019
|
+
).toUpperCase();
|
|
985
1020
|
let templateData = { channel };
|
|
986
1021
|
switch (channel) {
|
|
987
1022
|
case constants.SMS:
|
|
@@ -1328,28 +1363,104 @@ export class Creatives extends React.Component {
|
|
|
1328
1363
|
break;
|
|
1329
1364
|
case constants.RCS:
|
|
1330
1365
|
if (template.value) {
|
|
1331
|
-
const {
|
|
1332
|
-
} = template.value || {};
|
|
1333
|
-
const
|
|
1366
|
+
const { isFullMode: isFullModeForRcsConsumerPayload } = this.props;
|
|
1367
|
+
const { name = "", versions = {} } = template.value || {};
|
|
1368
|
+
const fromSubmit = get(versions, 'base.content.RCS.smsFallBackContent', {});
|
|
1369
|
+
const fromRecords = {
|
|
1370
|
+
...(templateRecords?.smsFallBackContent || {}),
|
|
1371
|
+
...(get(templateRecords, 'versions.base.content.RCS.smsFallBackContent') || {}),
|
|
1372
|
+
};
|
|
1373
|
+
const hasMeaningfulRcsSmsFallback = (smsFallbackPayload) => {
|
|
1374
|
+
if (
|
|
1375
|
+
!smsFallbackPayload
|
|
1376
|
+
|| typeof smsFallbackPayload !== 'object'
|
|
1377
|
+
|| Object.keys(smsFallbackPayload).length === 0
|
|
1378
|
+
) {
|
|
1379
|
+
return false;
|
|
1380
|
+
}
|
|
1381
|
+
const fallbackBodyText = String(
|
|
1382
|
+
smsFallbackPayload.smsContent
|
|
1383
|
+
?? smsFallbackPayload.smsTemplateContent
|
|
1384
|
+
?? smsFallbackPayload.message
|
|
1385
|
+
?? smsFallbackPayload.content
|
|
1386
|
+
?? '',
|
|
1387
|
+
).trim();
|
|
1388
|
+
const fallbackTemplateName = String(
|
|
1389
|
+
smsFallbackPayload.smsTemplateName ?? smsFallbackPayload.templateName ?? '',
|
|
1390
|
+
).trim();
|
|
1391
|
+
const rcsSmsFallbackVarMapped =
|
|
1392
|
+
smsFallbackPayload?.[RCS_SMS_FALLBACK_VAR_MAPPED_PROP];
|
|
1393
|
+
const hasVarMappedEntries =
|
|
1394
|
+
rcsSmsFallbackVarMapped != null
|
|
1395
|
+
&& typeof rcsSmsFallbackVarMapped === 'object'
|
|
1396
|
+
&& Object.keys(rcsSmsFallbackVarMapped).length > 0;
|
|
1397
|
+
return (
|
|
1398
|
+
fallbackBodyText !== ''
|
|
1399
|
+
|| fallbackTemplateName !== ''
|
|
1400
|
+
|| hasVarMappedEntries
|
|
1401
|
+
);
|
|
1402
|
+
};
|
|
1403
|
+
// If submit has only empty strings, do not let it wipe fallback mirrored on templateRecords (library round-trip).
|
|
1404
|
+
const smsFallBackContent = hasMeaningfulRcsSmsFallback(fromSubmit)
|
|
1405
|
+
? { ...fromRecords, ...fromSubmit }
|
|
1406
|
+
: { ...fromSubmit, ...fromRecords };
|
|
1334
1407
|
const {
|
|
1335
|
-
cardContent = [],
|
|
1408
|
+
cardContent: cardContentFromSubmit = [],
|
|
1336
1409
|
contentType = "",
|
|
1337
1410
|
cardType = "",
|
|
1338
1411
|
cardSettings = {},
|
|
1339
1412
|
accountId = "",
|
|
1340
1413
|
} = get(versions, 'base.content.RCS.rcsContent', {});
|
|
1414
|
+
const rootRcsCardVarMappedFromSubmit = get(template, 'value.rcsCardVarMapped');
|
|
1415
|
+
const firstCardFromSubmit = Array.isArray(cardContentFromSubmit)
|
|
1416
|
+
? cardContentFromSubmit[0]
|
|
1417
|
+
: null;
|
|
1418
|
+
const cardContent = mapRcsCardContentForConsumerWithResolvedTags(
|
|
1419
|
+
cardContentFromSubmit,
|
|
1420
|
+
rootRcsCardVarMappedFromSubmit,
|
|
1421
|
+
isFullModeForRcsConsumerPayload,
|
|
1422
|
+
);
|
|
1341
1423
|
const rcsContent = {
|
|
1342
1424
|
contentType,
|
|
1343
1425
|
cardType,
|
|
1344
1426
|
cardSettings,
|
|
1345
1427
|
cardContent,
|
|
1346
1428
|
};
|
|
1429
|
+
const cardVarMappedFromFirstRcsCard =
|
|
1430
|
+
firstCardFromSubmit?.cardVarMapped != null
|
|
1431
|
+
&& typeof firstCardFromSubmit.cardVarMapped === 'object'
|
|
1432
|
+
? pickRcsCardVarMappedEntries(firstCardFromSubmit.cardVarMapped)
|
|
1433
|
+
: null;
|
|
1434
|
+
const includeRootRcsCardVarMappedOnConsumerPayload =
|
|
1435
|
+
cardVarMappedFromFirstRcsCard
|
|
1436
|
+
&& Object.keys(cardVarMappedFromFirstRcsCard).length > 0
|
|
1437
|
+
&& isFullModeForRcsConsumerPayload === true;
|
|
1347
1438
|
templateData = {
|
|
1348
1439
|
channel,
|
|
1349
1440
|
creativeName: name,
|
|
1350
1441
|
rcsContent,
|
|
1351
1442
|
accountId,
|
|
1443
|
+
...(includeRootRcsCardVarMappedOnConsumerPayload
|
|
1444
|
+
? { rcsCardVarMapped: cardVarMappedFromFirstRcsCard }
|
|
1445
|
+
: {}),
|
|
1352
1446
|
};
|
|
1447
|
+
// Library / campaign consumers round-trip templateData via getTemplateData; include SMS fallback
|
|
1448
|
+
// so reopening the editor restores fallback text and tag mappings.
|
|
1449
|
+
// cap-campaigns-v2 API expects `smsFallBackContent.message` (see normalizeRcsMessageContentForApi).
|
|
1450
|
+
if (hasMeaningfulRcsSmsFallback(smsFallBackContent)) {
|
|
1451
|
+
const smsText =
|
|
1452
|
+
smsFallBackContent.message
|
|
1453
|
+
?? smsFallBackContent.smsContent
|
|
1454
|
+
?? smsFallBackContent.smsTemplateContent
|
|
1455
|
+
?? '';
|
|
1456
|
+
templateData.smsFallBackContent = {
|
|
1457
|
+
...smsFallBackContent,
|
|
1458
|
+
...(String(smsText).trim() !== ''
|
|
1459
|
+
? { message: String(smsText).trim() }
|
|
1460
|
+
: {}),
|
|
1461
|
+
};
|
|
1462
|
+
}
|
|
1463
|
+
normalizeRcsMessageContentForApi(templateData);
|
|
1353
1464
|
}
|
|
1354
1465
|
break;
|
|
1355
1466
|
case constants.ZALO:
|
|
@@ -1467,7 +1578,10 @@ export class Creatives extends React.Component {
|
|
|
1467
1578
|
return templateData;
|
|
1468
1579
|
};
|
|
1469
1580
|
|
|
1470
|
-
getSlideBoxContent({ mode, templateData, isFullMode }) {
|
|
1581
|
+
getSlideBoxContent({ mode, templateData, isFullMode, useLocalTemplates }) {
|
|
1582
|
+
if (useLocalTemplates && mode === 'create' && isEmpty(templateData)) {
|
|
1583
|
+
return 'templates';
|
|
1584
|
+
}
|
|
1471
1585
|
let creativesMode = isFullMode ? 'createTemplate' : 'templates';// for library mode templates page is initial mode and for full mode createTemplates
|
|
1472
1586
|
if (mode === 'create' && isFullMode) {
|
|
1473
1587
|
creativesMode = 'createTemplate';
|
|
@@ -1555,24 +1669,110 @@ export class Creatives extends React.Component {
|
|
|
1555
1669
|
getFormData = (template) => {
|
|
1556
1670
|
// Always reset isGetFormData so the child does not re-send form data on every re-render
|
|
1557
1671
|
// (e.g. when user fixes validation error by typing, we must not auto-close the slidebox)
|
|
1558
|
-
this.setState(
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
{
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1672
|
+
this.setState(
|
|
1673
|
+
(prevState) => {
|
|
1674
|
+
const next = { isGetFormData: false };
|
|
1675
|
+
if (!template.validity) {
|
|
1676
|
+
return next;
|
|
1677
|
+
}
|
|
1678
|
+
const baseTd = prevState.templateData || template;
|
|
1679
|
+
const channel = (
|
|
1680
|
+
baseTd?.type
|
|
1681
|
+
|| template?.type
|
|
1682
|
+
|| get(template, 'value.type')
|
|
1683
|
+
|| ''
|
|
1684
|
+
).toUpperCase();
|
|
1685
|
+
// Library mode: persist last submitted creatives shape so reopening still hydrates the editor
|
|
1686
|
+
// (parent may not merge getCreativesData back into templateData).
|
|
1687
|
+
if (this.props.isFullMode === false && template.value) {
|
|
1688
|
+
if (channel === constants.RCS) {
|
|
1689
|
+
const smsFallBackFromPayload = get(
|
|
1690
|
+
template.value,
|
|
1691
|
+
'versions.base.content.RCS.smsFallBackContent',
|
|
1692
|
+
);
|
|
1693
|
+
const rcsCardVarMappedFromPayload = get(
|
|
1694
|
+
template.value,
|
|
1695
|
+
'versions.base.content.RCS.rcsContent.cardContent[0].cardVarMapped',
|
|
1696
|
+
);
|
|
1697
|
+
next.templateData = {
|
|
1698
|
+
...baseTd,
|
|
1699
|
+
type: constants.RCS,
|
|
1700
|
+
name: template?.value?.name,
|
|
1701
|
+
versions: template?.value?.versions,
|
|
1702
|
+
...(smsFallBackFromPayload != null
|
|
1703
|
+
&& typeof smsFallBackFromPayload === 'object'
|
|
1704
|
+
&& Object.keys(smsFallBackFromPayload).length > 0
|
|
1705
|
+
? { smsFallBackContent: smsFallBackFromPayload }
|
|
1706
|
+
: {}),
|
|
1707
|
+
...(rcsCardVarMappedFromPayload != null
|
|
1708
|
+
&& typeof rcsCardVarMappedFromPayload === 'object'
|
|
1709
|
+
? { rcsCardVarMapped: rcsCardVarMappedFromPayload }
|
|
1710
|
+
: {}),
|
|
1711
|
+
};
|
|
1712
|
+
if (template._id) {
|
|
1713
|
+
next.templateData._id = template._id;
|
|
1714
|
+
}
|
|
1715
|
+
} else if (channel === constants.SMS) {
|
|
1716
|
+
const submittedSmsTemplateValue = template?.value;
|
|
1717
|
+
const smsVersions =
|
|
1718
|
+
submittedSmsTemplateValue?.history != null
|
|
1719
|
+
? submittedSmsTemplateValue
|
|
1720
|
+
: {
|
|
1721
|
+
base: submittedSmsTemplateValue?.base,
|
|
1722
|
+
history: submittedSmsTemplateValue?.base
|
|
1723
|
+
? [submittedSmsTemplateValue.base]
|
|
1724
|
+
: [],
|
|
1725
|
+
};
|
|
1726
|
+
next.templateData = {
|
|
1727
|
+
...baseTd,
|
|
1728
|
+
type: constants.SMS,
|
|
1729
|
+
name: baseTd?.name || 'Campaign message SMS content',
|
|
1730
|
+
versions: smsVersions,
|
|
1731
|
+
};
|
|
1732
|
+
if (template?._id) {
|
|
1733
|
+
next.templateData._id = template._id;
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
return next;
|
|
1738
|
+
},
|
|
1739
|
+
() => {
|
|
1740
|
+
if (!template.validity) {
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1743
|
+
const templateData = this.state.templateData ? this.state.templateData : template; //select existing or create new content
|
|
1744
|
+
const channelForConsumer = String(
|
|
1745
|
+
templateData.type
|
|
1746
|
+
|| template.type
|
|
1747
|
+
|| get(template, 'value.type')
|
|
1748
|
+
|| '',
|
|
1749
|
+
).toUpperCase();
|
|
1750
|
+
const creativesData = this.getCreativesData(
|
|
1751
|
+
channelForConsumer,
|
|
1752
|
+
template,
|
|
1753
|
+
this.state.templateData || template,
|
|
1754
|
+
);// convers data to consumer understandable format
|
|
1755
|
+
creativesData.then((data) => {
|
|
1756
|
+
this.logGTMEvent(channelForConsumer, data);
|
|
1757
|
+
this.processCentralCommsMetaId(channelForConsumer, data, {
|
|
1758
|
+
closeSlideBoxAfterSubmit: template.closeSlideBoxAfterSubmit,
|
|
1569
1759
|
});
|
|
1570
|
-
}
|
|
1571
|
-
|
|
1572
|
-
|
|
1760
|
+
});
|
|
1761
|
+
},
|
|
1762
|
+
);
|
|
1573
1763
|
}
|
|
1574
1764
|
|
|
1575
|
-
processCentralCommsMetaId = (channel, creativesData) => {
|
|
1765
|
+
processCentralCommsMetaId = (channel, creativesData, options = {}) => {
|
|
1766
|
+
const { closeSlideBoxAfterSubmit = false } = options;
|
|
1767
|
+
const maybeCloseLibrarySlideBox = () => {
|
|
1768
|
+
if (
|
|
1769
|
+
closeSlideBoxAfterSubmit
|
|
1770
|
+
&& this.props.isFullMode === false
|
|
1771
|
+
&& typeof this.handleCloseSlideBox === 'function'
|
|
1772
|
+
) {
|
|
1773
|
+
this.handleCloseSlideBox();
|
|
1774
|
+
}
|
|
1775
|
+
};
|
|
1576
1776
|
// Create the payload for the centralcommnsmetaId API call
|
|
1577
1777
|
const { isLoyaltyModule = false, loyaltyMetaData = {} } = this.props;
|
|
1578
1778
|
const { actionName, setMetaData = () => { } } = loyaltyMetaData;
|
|
@@ -1598,6 +1798,7 @@ export class Creatives extends React.Component {
|
|
|
1598
1798
|
if (result?.status?.code === 200) {
|
|
1599
1799
|
setMetaData(result);
|
|
1600
1800
|
this.props.getCreativesData(creativesData);
|
|
1801
|
+
maybeCloseLibrarySlideBox();
|
|
1601
1802
|
} else {
|
|
1602
1803
|
CapNotification.error({ message: <FormattedMessage {...messages.somethingWentWrong} /> });
|
|
1603
1804
|
}
|
|
@@ -1608,6 +1809,7 @@ export class Creatives extends React.Component {
|
|
|
1608
1809
|
} else {
|
|
1609
1810
|
// If not a loyalty module or different action, should work as usual
|
|
1610
1811
|
this.props.getCreativesData(creativesData);
|
|
1812
|
+
maybeCloseLibrarySlideBox();
|
|
1611
1813
|
}
|
|
1612
1814
|
};
|
|
1613
1815
|
|
|
@@ -1640,7 +1842,9 @@ export class Creatives extends React.Component {
|
|
|
1640
1842
|
}
|
|
1641
1843
|
this.setState((prevState) => ({
|
|
1642
1844
|
...prevState,
|
|
1643
|
-
|
|
1845
|
+
// Library mode (isFullMode === false): retain last template so reopening still has RCS payload.
|
|
1846
|
+
// Undefined isFullMode defaults to full-mode close behavior (clear templateData).
|
|
1847
|
+
...(this.props.isFullMode !== false ? { templateData: undefined } : {}),
|
|
1644
1848
|
showSlideBox: false,
|
|
1645
1849
|
liquidErrorMessage: { STANDARD_ERROR_MSG: [], LIQUID_ERROR_MSG: [] },
|
|
1646
1850
|
isLiquidValidationError: false,
|
|
@@ -1843,21 +2047,17 @@ export class Creatives extends React.Component {
|
|
|
1843
2047
|
}
|
|
1844
2048
|
|
|
1845
2049
|
showLiquidErrorInFooter = (errorMessagesFromFormBuilder, currentFormBuilderTab) => {
|
|
1846
|
-
const
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
this.setState(
|
|
1857
|
-
isLiquidValidationError,
|
|
1858
|
-
liquidErrorMessage: errorMessagesFromFormBuilder,
|
|
1859
|
-
activeFormBuilderTab: currentFormBuilderTab === 1 ? constants.ANDROID : (currentFormBuilderTab === 2 ? constants.IOS : null), // Update activeFormBuilderTab, default to 1 if undefined
|
|
1860
|
-
});
|
|
2050
|
+
const next = computeLiquidFooterUpdateFromFormBuilder(
|
|
2051
|
+
errorMessagesFromFormBuilder,
|
|
2052
|
+
this.state.liquidErrorMessage,
|
|
2053
|
+
currentFormBuilderTab,
|
|
2054
|
+
{
|
|
2055
|
+
previousIsLiquidValidationError: this.state.isLiquidValidationError,
|
|
2056
|
+
currentChannelUpper: this.state.currentChannel?.toUpperCase(),
|
|
2057
|
+
},
|
|
2058
|
+
);
|
|
2059
|
+
if (next == null) return;
|
|
2060
|
+
this.setState(next);
|
|
1861
2061
|
}
|
|
1862
2062
|
|
|
1863
2063
|
// Callback to update HTML Editor validation state (called from EmailWrapper)
|
|
@@ -1980,6 +2180,11 @@ export class Creatives extends React.Component {
|
|
|
1980
2180
|
inAppEditorType,
|
|
1981
2181
|
htmlEditorValidationState,
|
|
1982
2182
|
} = this.state;
|
|
2183
|
+
const useLocalTemplates = get(
|
|
2184
|
+
this.props,
|
|
2185
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
2186
|
+
get(this.props, 'useLocalTemplates', false),
|
|
2187
|
+
);
|
|
1983
2188
|
const {
|
|
1984
2189
|
isFullMode,
|
|
1985
2190
|
creativesMode,
|
|
@@ -1998,7 +2203,6 @@ export class Creatives extends React.Component {
|
|
|
1998
2203
|
smsRegister,
|
|
1999
2204
|
enableNewChannels,
|
|
2000
2205
|
eventContextTags,
|
|
2001
|
-
waitEventContextTags = {},
|
|
2002
2206
|
isLoyaltyModule,
|
|
2003
2207
|
loyaltyMetaData = {},
|
|
2004
2208
|
} = this.props;
|
|
@@ -2032,14 +2236,7 @@ export class Creatives extends React.Component {
|
|
|
2032
2236
|
// IMPORTANT: Never show ErrorInfoNote in footer when in HTML Editor mode, even if liquidErrorMessage exists
|
|
2033
2237
|
const shouldShowErrorInfoNoteInFooter = isHTMLEditorMode ? false : hasBEEEditorErrors;
|
|
2034
2238
|
|
|
2035
|
-
|
|
2036
|
-
const slideBoxWrapperMargin = (get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0 && get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0)
|
|
2037
|
-
? CAP_SPACE_64
|
|
2038
|
-
: get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0
|
|
2039
|
-
? CAP_SPACE_56
|
|
2040
|
-
: get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0
|
|
2041
|
-
? CAP_SPACE_32
|
|
2042
|
-
: 0;
|
|
2239
|
+
const slideBoxWrapperMargin = getSlideBoxWrapperMarginFromLiquidErrors(liquidErrorMessage);
|
|
2043
2240
|
/* TODO: Instead of passing down same props separately to each component down, write common function to these props and pass it accordingly */
|
|
2044
2241
|
|
|
2045
2242
|
// Compute anonymous user type and channel restrictions
|
|
@@ -2068,7 +2265,10 @@ export class Creatives extends React.Component {
|
|
|
2068
2265
|
<SlideBoxWrapper
|
|
2069
2266
|
slideBoxWrapperMargin={slideBoxWrapperMargin}
|
|
2070
2267
|
shouldApplyFooterMargin={shouldShowErrorInfoNoteInFooter}
|
|
2071
|
-
className={classnames(
|
|
2268
|
+
className={classnames(
|
|
2269
|
+
`${classPrefix} ${isFullMode ? 'creatives-full-mode' : 'creatives-library-mode'} ${mapTemplateCreate ? 'map-template-create' : ''}`,
|
|
2270
|
+
useLocalTemplates && slidBoxContent === 'templates' && 'creatives-slidebox--local-sms-templates',
|
|
2271
|
+
)}
|
|
2072
2272
|
>
|
|
2073
2273
|
<CapSlideBox
|
|
2074
2274
|
header={
|
|
@@ -2093,12 +2293,13 @@ export class Creatives extends React.Component {
|
|
|
2093
2293
|
smsRegister={smsRegister}
|
|
2094
2294
|
handleClose={this.handleCloseSlideBox}
|
|
2095
2295
|
moduleType={this.props.messageDetails?.type}
|
|
2296
|
+
useLocalTemplates={useLocalTemplates}
|
|
2096
2297
|
/>
|
|
2097
2298
|
)}
|
|
2098
2299
|
content={(
|
|
2099
2300
|
<SlideBoxContent
|
|
2100
2301
|
key="creatives-container-slidebox-content"
|
|
2101
|
-
onSelectTemplate={this.onSelectTemplate}
|
|
2302
|
+
onSelectTemplate={this.props.onSelectTemplate != null ? this.props.onSelectTemplate : this.onSelectTemplate}
|
|
2102
2303
|
onCreateComplete={getCreativesData}
|
|
2103
2304
|
onPreviewTemplate={this.onPreviewTemplate}
|
|
2104
2305
|
slidBoxContent={slidBoxContent}
|
|
@@ -2166,7 +2367,6 @@ export class Creatives extends React.Component {
|
|
|
2166
2367
|
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.
|
|
2167
2368
|
hostName={this.props?.hostName || ''}
|
|
2168
2369
|
eventContextTags={eventContextTags}
|
|
2169
|
-
waitEventContextTags={waitEventContextTags}
|
|
2170
2370
|
isLoyaltyModule={isLoyaltyModule}
|
|
2171
2371
|
loyaltyMetaData={loyaltyMetaData}
|
|
2172
2372
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
@@ -2175,7 +2375,8 @@ export class Creatives extends React.Component {
|
|
|
2175
2375
|
isTestAndPreviewMode={(() => this.state.isTestAndPreviewMode)()}
|
|
2176
2376
|
onHtmlEditorValidationStateChange={this.updateHtmlEditorValidationState}
|
|
2177
2377
|
onPersonalizationTokensChange={this.handlePersonalizationTokensChange}
|
|
2178
|
-
|
|
2378
|
+
localTemplatesConfig={pick(this.props.localTemplatesConfig || this.props, constants.LOCAL_TEMPLATE_CONFIG_KEYS)}
|
|
2379
|
+
/>
|
|
2179
2380
|
)}
|
|
2180
2381
|
footer={this.shouldShowFooter() ? (
|
|
2181
2382
|
<SlideBoxFooter
|
|
@@ -2260,13 +2461,31 @@ Creatives.propTypes = {
|
|
|
2260
2461
|
orgUnitId: PropTypes.number,
|
|
2261
2462
|
hostName: PropTypes.string,
|
|
2262
2463
|
eventContextTags: PropTypes.array,
|
|
2263
|
-
waitEventContextTags: PropTypes.object,
|
|
2264
2464
|
loyaltyTagFetchingDependencies: PropTypes.object,
|
|
2265
2465
|
customerType: PropTypes.string,
|
|
2266
2466
|
intl: PropTypes.shape({
|
|
2267
2467
|
formatMessage: PropTypes.func,
|
|
2268
2468
|
}),
|
|
2269
2469
|
stopValidation: PropTypes.func,
|
|
2470
|
+
// Local template list (e.g. for SMS fallback): when set, TemplatesV2 uses these instead of Redux.
|
|
2471
|
+
// All optional. Pass either localTemplatesConfig (object) or individual props below.
|
|
2472
|
+
localTemplatesConfig: PropTypes.shape({
|
|
2473
|
+
useLocalTemplates: PropTypes.bool,
|
|
2474
|
+
localTemplates: PropTypes.arrayOf(PropTypes.object),
|
|
2475
|
+
localTemplatesLoading: PropTypes.bool,
|
|
2476
|
+
localTemplatesFilterContent: PropTypes.node,
|
|
2477
|
+
localTemplatesSentinelContent: PropTypes.node,
|
|
2478
|
+
localTemplatesScrollContainerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
|
2479
|
+
localTemplatesUseSkeleton: PropTypes.bool,
|
|
2480
|
+
}),
|
|
2481
|
+
useLocalTemplates: PropTypes.bool,
|
|
2482
|
+
localTemplates: PropTypes.arrayOf(PropTypes.object),
|
|
2483
|
+
localTemplatesLoading: PropTypes.bool,
|
|
2484
|
+
localTemplatesFilterContent: PropTypes.node,
|
|
2485
|
+
localTemplatesSentinelContent: PropTypes.node,
|
|
2486
|
+
localTemplatesScrollContainerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
|
2487
|
+
localTemplatesUseSkeleton: PropTypes.bool,
|
|
2488
|
+
onSelectTemplate: PropTypes.func,
|
|
2270
2489
|
};
|
|
2271
2490
|
const mapStatesToProps = () => createStructuredSelector({
|
|
2272
2491
|
isLoading: isLoadingSelector(),
|