@capillarytech/creatives-library 9.0.29 → 9.0.30
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/global-styles.js +1 -1
- package/package.json +1 -1
- package/services/tests/api.test.js +35 -20
- package/utils/commonUtils.js +22 -1
- package/utils/rcsPayloadUtils.js +102 -0
- package/utils/templateVarUtils.js +198 -0
- package/utils/tests/rcsPayloadUtils.test.js +295 -0
- package/utils/tests/templateVarUtils.test.js +204 -0
- package/v2Components/CapActionButton/constants.js +21 -1
- package/v2Components/CapActionButton/index.js +261 -144
- package/v2Components/CapActionButton/index.scss +245 -14
- package/v2Components/CapActionButton/messages.js +32 -3
- package/v2Components/CapActionButton/tests/index.test.js +74 -19
- package/v2Components/CapImageUpload/index.js +2 -2
- package/v2Components/CapTagList/index.js +9 -0
- package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +70 -48
- 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 +58 -11
- package/v2Components/CommonTestAndPreview/SendTestMessage.js +10 -5
- package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +186 -22
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +381 -80
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +155 -8
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +11 -0
- package/v2Components/CommonTestAndPreview/constants.js +35 -2
- package/v2Components/CommonTestAndPreview/index.js +770 -231
- 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/CommonTestAndPreview.addTestCustomer.test.js +1 -0
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +412 -257
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +337 -63
- 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 +108 -15
- 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/CommonTestAndPreview/tests/utils.test.js +151 -0
- package/v2Components/CommonTestAndPreview/utils.js +84 -0
- package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +91 -0
- package/v2Components/SmsFallback/constants.js +94 -0
- package/v2Components/SmsFallback/index.js +958 -0
- package/v2Components/SmsFallback/index.scss +266 -0
- package/v2Components/SmsFallback/messages.js +78 -0
- package/v2Components/SmsFallback/smsFallbackUtils.js +120 -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 +208 -0
- package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +309 -0
- package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +471 -0
- package/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
- package/v2Components/TemplatePreview/_templatePreview.scss +45 -25
- package/v2Components/TemplatePreview/constants.js +2 -0
- package/v2Components/TemplatePreview/index.js +147 -32
- package/v2Components/TemplatePreview/tests/index.test.js +142 -0
- package/v2Components/TestAndPreviewSlidebox/CustomValuesEditor.js +6 -6
- 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/CommunicationFlow/Tests/CommunicationFlow.test.js +4 -1
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +4 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +20 -20
- package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +27 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +37 -4
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +14 -5
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +36 -5
- package/v2Containers/CreativesContainer/constants.js +11 -0
- package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +77 -0
- package/v2Containers/CreativesContainer/index.js +322 -106
- package/v2Containers/CreativesContainer/index.scss +102 -1
- package/v2Containers/CreativesContainer/tests/CreativesSlideBoxWrapper.test.js +58 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.smsDltPreview.test.js +73 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +37 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +103 -34
- package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +193 -15
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +88 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +549 -57
- 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/carouselUtils.js +224 -0
- package/v2Containers/Rcs/components/CarouselCard.js +317 -0
- package/v2Containers/Rcs/components/CarouselCardButtons.js +113 -0
- package/v2Containers/Rcs/components/CarouselCardMedia.js +136 -0
- package/v2Containers/Rcs/components/CarouselCharacterCount.js +31 -0
- package/v2Containers/Rcs/components/CarouselDimensionSelection.js +80 -0
- package/v2Containers/Rcs/constants.js +132 -16
- package/v2Containers/Rcs/index.js +1822 -946
- package/v2Containers/Rcs/index.scss +443 -8
- package/v2Containers/Rcs/messages.js +45 -22
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +494 -0
- package/v2Containers/Rcs/tests/CarouselCard.test.js +464 -0
- package/v2Containers/Rcs/tests/CarouselCardButtons.test.js +211 -0
- package/v2Containers/Rcs/tests/CarouselCardMedia.test.js +160 -0
- package/v2Containers/Rcs/tests/CarouselCharacterCount.test.js +50 -0
- package/v2Containers/Rcs/tests/CarouselDimensionSelection.test.js +119 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +74440 -39387
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +10 -74
- package/v2Containers/Rcs/tests/carouselUtils.test.js +916 -0
- package/v2Containers/Rcs/tests/index.test.js +275 -40
- package/v2Containers/Rcs/tests/mockData.js +38 -0
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +912 -0
- package/v2Containers/Rcs/tests/utils.test.js +682 -30
- package/v2Containers/Rcs/utils.js +514 -12
- package/v2Containers/Sms/Create/index.js +115 -48
- 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 +678 -169
- package/v2Containers/SmsTrai/Edit/index.scss +126 -0
- package/v2Containers/SmsTrai/Edit/messages.js +14 -4
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +5615 -3014
- package/v2Containers/SmsWrapper/index.js +37 -8
- package/v2Containers/TagList/index.js +5 -0
- package/v2Containers/Templates/TemplatesActionBar.js +101 -0
- package/v2Containers/Templates/_templates.scss +196 -12
- package/v2Containers/Templates/actions.js +11 -0
- package/v2Containers/Templates/constants.js +2 -0
- package/v2Containers/Templates/index.js +131 -59
- package/v2Containers/Templates/sagas.js +57 -13
- package/v2Containers/Templates/tests/TemplatesActionBar.test.js +129 -0
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1060 -1015
- 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 +88 -25
- 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';
|
|
@@ -56,13 +52,15 @@ import CapInput from '@capillarytech/cap-ui-library/CapInput';
|
|
|
56
52
|
import CapNotification from '@capillarytech/cap-ui-library/CapNotification';
|
|
57
53
|
import { injectIntl, FormattedMessage } from 'react-intl';
|
|
58
54
|
import classnames from 'classnames';
|
|
59
|
-
import
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
import isEmpty from 'lodash/isEmpty';
|
|
56
|
+
import get from 'lodash/get';
|
|
57
|
+
import forEach from 'lodash/forEach';
|
|
58
|
+
import cloneDeep from 'lodash/cloneDeep';
|
|
59
|
+
import debounce from 'lodash/debounce';
|
|
60
|
+
import pick from 'lodash/pick';
|
|
62
61
|
import { connect } from 'react-redux';
|
|
63
62
|
import { createStructuredSelector } from 'reselect';
|
|
64
63
|
import { bindActionCreators, compose } from 'redux';
|
|
65
|
-
import styled from 'styled-components';
|
|
66
64
|
import { GA } from '@capillarytech/cap-ui-utils';
|
|
67
65
|
import { DAEMON } from '@capillarytech/vulcan-react-sdk/utils/sagaInjectorTypes';
|
|
68
66
|
|
|
@@ -76,6 +74,7 @@ import SlideBoxContent from './SlideBoxContent';
|
|
|
76
74
|
import * as constants from './constants';
|
|
77
75
|
import * as commonUtil from '../../utils/common';
|
|
78
76
|
import { gtmPush } from '../../utils/gtmTrackers';
|
|
77
|
+
import { normalizeRcsMessageContentForApi } from '../../utils/rcsPayloadUtils';
|
|
79
78
|
import './index.scss';
|
|
80
79
|
import * as templateActions from '../Templates/actions';
|
|
81
80
|
import * as globalActions from '../Cap/actions';
|
|
@@ -90,7 +89,9 @@ import {
|
|
|
90
89
|
} from '../Line/Container/constants';
|
|
91
90
|
import {EXTERNAL_URL, SITE_URL, WEBPUSH_MEDIA_TYPES} from '../WebPush/constants';
|
|
92
91
|
import { IMAGE, VIDEO } from '../Facebook/Advertisement/constant';
|
|
93
|
-
import { RCS_STATUSES } from '../Rcs/constants';
|
|
92
|
+
import { RCS_STATUSES, contentType as RCS_CONTENT_TYPE, EMBEDDED } from '../Rcs/constants';
|
|
93
|
+
import { pickRcsCardVarMappedEntries } from '../Rcs/rcsLibraryHydrationUtils';
|
|
94
|
+
import { RCS_SMS_FALLBACK_VAR_MAPPED_PROP } from '../../v2Components/CommonTestAndPreview/constants';
|
|
94
95
|
import { CREATIVE } from '../Facebook/constants';
|
|
95
96
|
import { LOYALTY } from '../App/constants';
|
|
96
97
|
import {
|
|
@@ -131,6 +132,11 @@ import { capSagaForFetchSchemaForEntity, capSagaLiquidEntity } from '../Cap/saga
|
|
|
131
132
|
import { v2TemplateSagaWatchGetDefaultBeeTemplates } from '../Templates/sagas';
|
|
132
133
|
import { DYNAMIC_URL } from '../../v2Components/CapWhatsappCTA/constants';
|
|
133
134
|
import ErrorInfoNote from '../../v2Components/ErrorInfoNote';
|
|
135
|
+
import SlideBoxWrapper from './CreativesSlideBoxWrapper';
|
|
136
|
+
import {
|
|
137
|
+
computeLiquidFooterUpdateFromFormBuilder,
|
|
138
|
+
getSlideBoxWrapperMarginFromLiquidErrors,
|
|
139
|
+
} from './embeddedSlideboxUtils';
|
|
134
140
|
|
|
135
141
|
import {
|
|
136
142
|
transformChannelPayload,
|
|
@@ -139,51 +145,24 @@ import {
|
|
|
139
145
|
import { MANUAL_CAROUSEL } from '../MobilePushNew/constants';
|
|
140
146
|
import { BIG_HTML } from '../InApp/constants';
|
|
141
147
|
|
|
142
|
-
/**
|
|
143
|
-
* Returns true if value is "deep empty": no errors present.
|
|
144
|
-
* - null/undefined: empty
|
|
145
|
-
* - string: empty if length === 0
|
|
146
|
-
* - array: empty if length === 0
|
|
147
|
-
* - plain object (e.g. { android: [], ios: [], generic: [] }): empty only if every value is deep-empty
|
|
148
|
-
*/
|
|
149
|
-
function isDeepEmpty(value) {
|
|
150
|
-
if (value == null) return true;
|
|
151
|
-
if (typeof value === 'string') return value.length === 0;
|
|
152
|
-
if (Array.isArray(value)) return value.length === 0;
|
|
153
|
-
if (typeof value === 'object') {
|
|
154
|
-
return Object.values(value).every(isDeepEmpty);
|
|
155
|
-
}
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
148
|
const classPrefix = 'add-creatives-section';
|
|
160
149
|
const CREATIVES_CONTAINER = 'creativesContainer';
|
|
161
150
|
|
|
162
|
-
const SlideBoxWrapper = styled.div`
|
|
163
|
-
.cap-slide-box-v2-container{
|
|
164
|
-
.slidebox-header, .slidebox-content-container{
|
|
165
|
-
margin-bottom: ${({ slideBoxWrapperMargin }) => `${slideBoxWrapperMargin}`};
|
|
166
|
-
padding: 0 rem;
|
|
167
|
-
&.has-footer{
|
|
168
|
-
overflow-x: hidden;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
.slidebox-footer{
|
|
172
|
-
/* Only apply margin-bottom to footer when ErrorInfoNote is shown in footer (BEE editor) */
|
|
173
|
-
/* For HTML Editor, errors are shown in ValidationErrorDisplay (inside content area), so no footer margin needed */
|
|
174
|
-
margin-bottom: ${({ shouldApplyFooterMargin }) => (shouldApplyFooterMargin ? `${CAP_SPACE_16}` : '0')};
|
|
175
|
-
padding: 0 rem;
|
|
176
|
-
&.has-footer{
|
|
177
|
-
overflow-x: hidden;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
`;
|
|
182
151
|
export class Creatives extends React.Component {
|
|
183
152
|
constructor(props) {
|
|
184
153
|
super(props);
|
|
185
154
|
|
|
186
|
-
const
|
|
155
|
+
const useLocalTemplates = get(
|
|
156
|
+
props,
|
|
157
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
158
|
+
get(props, 'useLocalTemplates', false),
|
|
159
|
+
);
|
|
160
|
+
const initialSlidBoxContent = this.getSlideBoxContent({
|
|
161
|
+
mode: props.creativesMode,
|
|
162
|
+
templateData: props.templateData,
|
|
163
|
+
isFullMode: props.isFullMode,
|
|
164
|
+
useLocalTemplates,
|
|
165
|
+
});
|
|
187
166
|
|
|
188
167
|
this.state = {
|
|
189
168
|
isLoadingContent: true,
|
|
@@ -230,7 +209,13 @@ export class Creatives extends React.Component {
|
|
|
230
209
|
}
|
|
231
210
|
|
|
232
211
|
componentWillUnmount() {
|
|
233
|
-
|
|
212
|
+
const isEmbedded = get(this.props, 'location.query.type', '') === EMBEDDED;
|
|
213
|
+
const useLocalTemplates = get(
|
|
214
|
+
this.props,
|
|
215
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
216
|
+
get(this.props, 'useLocalTemplates', false),
|
|
217
|
+
);
|
|
218
|
+
if (isEmbedded && !useLocalTemplates) {
|
|
234
219
|
this.props.templateActions.resetTemplateStoreData();
|
|
235
220
|
}
|
|
236
221
|
this.props.globalActions.clearMetaEntities();
|
|
@@ -840,15 +825,69 @@ export class Creatives extends React.Component {
|
|
|
840
825
|
smsFallBackContent = {},
|
|
841
826
|
creativeName = "",
|
|
842
827
|
channel = constants.RCS,
|
|
828
|
+
rcsCardVarMapped,
|
|
843
829
|
accountId = "",
|
|
844
830
|
} = templateData || {};
|
|
845
|
-
const
|
|
831
|
+
const { isFullMode: isFullModeForRcsPayload } = this.props;
|
|
832
|
+
const isCarouselRcs = (rcsContent?.cardType || '').toString().toUpperCase() === RCS_CONTENT_TYPE.carousel;
|
|
833
|
+
const firstCardIn = (rcsContent.cardContent && rcsContent.cardContent[0]) || {};
|
|
834
|
+
const {
|
|
835
|
+
cardDisplayTitle: _omitDispTitleIn,
|
|
836
|
+
cardDisplayDescription: _omitDispDescIn,
|
|
837
|
+
...cardContent
|
|
838
|
+
} = firstCardIn;
|
|
846
839
|
const Status = RCS_STATUSES.approved || '';
|
|
840
|
+
const mergedCardVarMapped = (() => {
|
|
841
|
+
const nestedCardVarMapped = cardContent?.cardVarMapped;
|
|
842
|
+
const rootMirrorCardVarMapped = rcsCardVarMapped;
|
|
843
|
+
const nestedRecord =
|
|
844
|
+
nestedCardVarMapped != null && typeof nestedCardVarMapped === 'object'
|
|
845
|
+
? nestedCardVarMapped
|
|
846
|
+
: {};
|
|
847
|
+
const rootRecord =
|
|
848
|
+
rootMirrorCardVarMapped != null && typeof rootMirrorCardVarMapped === 'object'
|
|
849
|
+
? rootMirrorCardVarMapped
|
|
850
|
+
: {};
|
|
851
|
+
const mergedFromRootAndNested = {
|
|
852
|
+
...pickRcsCardVarMappedEntries(rootRecord),
|
|
853
|
+
...pickRcsCardVarMappedEntries(nestedRecord),
|
|
854
|
+
};
|
|
855
|
+
return Object.keys(mergedFromRootAndNested).length > 0
|
|
856
|
+
? mergedFromRootAndNested
|
|
857
|
+
: null;
|
|
858
|
+
})();
|
|
859
|
+
// Campaigns (embedded): do not duplicate `cardVarMapped` as root `rcsCardVarMapped` on send —
|
|
860
|
+
// slot map stays on `versions…cardContent[0].cardVarMapped` only. Library full mode keeps root mirror.
|
|
861
|
+
// Use `=== true` so omitted/undefined `isFullMode` does not behave like library (avoids duplicate on approval payload).
|
|
862
|
+
const includeRootRcsCardVarMapped =
|
|
863
|
+
mergedCardVarMapped && isFullModeForRcsPayload === true;
|
|
864
|
+
|
|
865
|
+
const builtCardContent = isCarouselRcs
|
|
866
|
+
? (rcsContent.cardContent || []).map((card, idx) => {
|
|
867
|
+
const {
|
|
868
|
+
cardDisplayTitle: _dt,
|
|
869
|
+
cardDisplayDescription: _dd,
|
|
870
|
+
...restCard
|
|
871
|
+
} = card || {};
|
|
872
|
+
return {
|
|
873
|
+
...restCard,
|
|
874
|
+
...(idx === 0 && mergedCardVarMapped ? { cardVarMapped: mergedCardVarMapped } : {}),
|
|
875
|
+
Status,
|
|
876
|
+
};
|
|
877
|
+
})
|
|
878
|
+
: [
|
|
879
|
+
{
|
|
880
|
+
...cardContent,
|
|
881
|
+
...(mergedCardVarMapped ? { cardVarMapped: mergedCardVarMapped } : {}),
|
|
882
|
+
Status,
|
|
883
|
+
},
|
|
884
|
+
];
|
|
847
885
|
|
|
848
886
|
creativesTemplateData = {
|
|
849
887
|
type: channel,
|
|
850
888
|
edit: true,
|
|
851
889
|
name: creativeName,
|
|
890
|
+
...(includeRootRcsCardVarMapped ? { rcsCardVarMapped: mergedCardVarMapped } : {}),
|
|
852
891
|
versions: {
|
|
853
892
|
base: {
|
|
854
893
|
content: {
|
|
@@ -856,12 +895,7 @@ export class Creatives extends React.Component {
|
|
|
856
895
|
rcsContent: {
|
|
857
896
|
...rcsContent,
|
|
858
897
|
...(accountId && !isFullMode && { accountId }),
|
|
859
|
-
cardContent:
|
|
860
|
-
{
|
|
861
|
-
...cardContent,
|
|
862
|
-
Status,
|
|
863
|
-
},
|
|
864
|
-
],
|
|
898
|
+
cardContent: builtCardContent,
|
|
865
899
|
},
|
|
866
900
|
smsFallBackContent,
|
|
867
901
|
},
|
|
@@ -1009,7 +1043,10 @@ export class Creatives extends React.Component {
|
|
|
1009
1043
|
return newExpandableDetails;
|
|
1010
1044
|
}
|
|
1011
1045
|
|
|
1012
|
-
getCreativesData = async (
|
|
1046
|
+
getCreativesData = async (channelParam, template, templateRecords) => { //from creatives to consumers
|
|
1047
|
+
const channel = String(
|
|
1048
|
+
channelParam || template?.type || get(template, 'value.type') || '',
|
|
1049
|
+
).toUpperCase();
|
|
1013
1050
|
let templateData = { channel };
|
|
1014
1051
|
switch (channel) {
|
|
1015
1052
|
case constants.SMS:
|
|
@@ -1356,28 +1393,99 @@ export class Creatives extends React.Component {
|
|
|
1356
1393
|
break;
|
|
1357
1394
|
case constants.RCS:
|
|
1358
1395
|
if (template.value) {
|
|
1359
|
-
const {
|
|
1360
|
-
} = template.value || {};
|
|
1361
|
-
const
|
|
1396
|
+
const { isFullMode: isFullModeForRcsConsumerPayload } = this.props;
|
|
1397
|
+
const { name = "", versions = {} } = template.value || {};
|
|
1398
|
+
const fromSubmit = get(versions, 'base.content.RCS.smsFallBackContent', {});
|
|
1399
|
+
const fromRecords = {
|
|
1400
|
+
...(templateRecords?.smsFallBackContent || {}),
|
|
1401
|
+
...(get(templateRecords, 'versions.base.content.RCS.smsFallBackContent') || {}),
|
|
1402
|
+
};
|
|
1403
|
+
const hasMeaningfulRcsSmsFallback = (smsFallbackPayload) => {
|
|
1404
|
+
if (
|
|
1405
|
+
!smsFallbackPayload
|
|
1406
|
+
|| typeof smsFallbackPayload !== 'object'
|
|
1407
|
+
|| Object.keys(smsFallbackPayload).length === 0
|
|
1408
|
+
) {
|
|
1409
|
+
return false;
|
|
1410
|
+
}
|
|
1411
|
+
const fallbackBodyText = String(
|
|
1412
|
+
smsFallbackPayload.smsContent
|
|
1413
|
+
?? smsFallbackPayload.smsTemplateContent
|
|
1414
|
+
?? smsFallbackPayload.message
|
|
1415
|
+
?? smsFallbackPayload.content
|
|
1416
|
+
?? '',
|
|
1417
|
+
).trim();
|
|
1418
|
+
const fallbackTemplateName = String(
|
|
1419
|
+
smsFallbackPayload.smsTemplateName ?? smsFallbackPayload.templateName ?? '',
|
|
1420
|
+
).trim();
|
|
1421
|
+
const rcsSmsFallbackVarMapped =
|
|
1422
|
+
smsFallbackPayload?.[RCS_SMS_FALLBACK_VAR_MAPPED_PROP];
|
|
1423
|
+
const hasVarMappedEntries =
|
|
1424
|
+
rcsSmsFallbackVarMapped != null
|
|
1425
|
+
&& typeof rcsSmsFallbackVarMapped === 'object'
|
|
1426
|
+
&& Object.keys(rcsSmsFallbackVarMapped).length > 0;
|
|
1427
|
+
return (
|
|
1428
|
+
fallbackBodyText !== ''
|
|
1429
|
+
|| fallbackTemplateName !== ''
|
|
1430
|
+
|| hasVarMappedEntries
|
|
1431
|
+
);
|
|
1432
|
+
};
|
|
1433
|
+
// If submit has only empty strings, do not let it wipe fallback mirrored on templateRecords (library round-trip).
|
|
1434
|
+
const smsFallBackContent = hasMeaningfulRcsSmsFallback(fromSubmit)
|
|
1435
|
+
? { ...fromRecords, ...fromSubmit }
|
|
1436
|
+
: { ...fromSubmit, ...fromRecords };
|
|
1362
1437
|
const {
|
|
1363
|
-
cardContent = [],
|
|
1438
|
+
cardContent: cardContentFromSubmit = [],
|
|
1364
1439
|
contentType = "",
|
|
1365
1440
|
cardType = "",
|
|
1366
1441
|
cardSettings = {},
|
|
1367
1442
|
accountId = "",
|
|
1368
1443
|
} = get(versions, 'base.content.RCS.rcsContent', {});
|
|
1444
|
+
const firstCardFromSubmit = Array.isArray(cardContentFromSubmit)
|
|
1445
|
+
? cardContentFromSubmit[0]
|
|
1446
|
+
: null;
|
|
1447
|
+
const cardContent = cardContentFromSubmit;
|
|
1369
1448
|
const rcsContent = {
|
|
1370
1449
|
contentType,
|
|
1371
1450
|
cardType,
|
|
1372
1451
|
cardSettings,
|
|
1373
1452
|
cardContent,
|
|
1374
1453
|
};
|
|
1454
|
+
const cardVarMappedFromFirstRcsCard =
|
|
1455
|
+
firstCardFromSubmit?.cardVarMapped != null
|
|
1456
|
+
&& typeof firstCardFromSubmit.cardVarMapped === 'object'
|
|
1457
|
+
? pickRcsCardVarMappedEntries(firstCardFromSubmit.cardVarMapped)
|
|
1458
|
+
: null;
|
|
1459
|
+
const includeRootRcsCardVarMappedOnConsumerPayload =
|
|
1460
|
+
cardVarMappedFromFirstRcsCard
|
|
1461
|
+
&& Object.keys(cardVarMappedFromFirstRcsCard).length > 0
|
|
1462
|
+
&& isFullModeForRcsConsumerPayload === true;
|
|
1375
1463
|
templateData = {
|
|
1376
1464
|
channel,
|
|
1377
1465
|
creativeName: name,
|
|
1378
1466
|
rcsContent,
|
|
1379
1467
|
accountId,
|
|
1468
|
+
...(includeRootRcsCardVarMappedOnConsumerPayload
|
|
1469
|
+
? { rcsCardVarMapped: cardVarMappedFromFirstRcsCard }
|
|
1470
|
+
: {}),
|
|
1380
1471
|
};
|
|
1472
|
+
// Library / campaign consumers round-trip templateData via getTemplateData; include SMS fallback
|
|
1473
|
+
// so reopening the editor restores fallback text and tag mappings.
|
|
1474
|
+
// cap-campaigns-v2 API expects `smsFallBackContent.message` (see normalizeRcsMessageContentForApi).
|
|
1475
|
+
if (hasMeaningfulRcsSmsFallback(smsFallBackContent)) {
|
|
1476
|
+
const smsText =
|
|
1477
|
+
smsFallBackContent.message
|
|
1478
|
+
?? smsFallBackContent.smsContent
|
|
1479
|
+
?? smsFallBackContent.smsTemplateContent
|
|
1480
|
+
?? '';
|
|
1481
|
+
templateData.smsFallBackContent = {
|
|
1482
|
+
...smsFallBackContent,
|
|
1483
|
+
...(String(smsText).trim() !== ''
|
|
1484
|
+
? { message: String(smsText).trim() }
|
|
1485
|
+
: {}),
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1488
|
+
normalizeRcsMessageContentForApi(templateData);
|
|
1381
1489
|
}
|
|
1382
1490
|
break;
|
|
1383
1491
|
case constants.ZALO:
|
|
@@ -1495,7 +1603,10 @@ export class Creatives extends React.Component {
|
|
|
1495
1603
|
return templateData;
|
|
1496
1604
|
};
|
|
1497
1605
|
|
|
1498
|
-
getSlideBoxContent({ mode, templateData, isFullMode }) {
|
|
1606
|
+
getSlideBoxContent({ mode, templateData, isFullMode, useLocalTemplates }) {
|
|
1607
|
+
if (useLocalTemplates && mode === 'create' && isEmpty(templateData)) {
|
|
1608
|
+
return 'templates';
|
|
1609
|
+
}
|
|
1499
1610
|
let creativesMode = isFullMode ? 'createTemplate' : 'templates';// for library mode templates page is initial mode and for full mode createTemplates
|
|
1500
1611
|
if (mode === 'create' && isFullMode) {
|
|
1501
1612
|
creativesMode = 'createTemplate';
|
|
@@ -1583,24 +1694,110 @@ export class Creatives extends React.Component {
|
|
|
1583
1694
|
getFormData = (template) => {
|
|
1584
1695
|
// Always reset isGetFormData so the child does not re-send form data on every re-render
|
|
1585
1696
|
// (e.g. when user fixes validation error by typing, we must not auto-close the slidebox)
|
|
1586
|
-
this.setState(
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
{
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1697
|
+
this.setState(
|
|
1698
|
+
(prevState) => {
|
|
1699
|
+
const next = { isGetFormData: false };
|
|
1700
|
+
if (!template.validity) {
|
|
1701
|
+
return next;
|
|
1702
|
+
}
|
|
1703
|
+
const baseTd = prevState.templateData || template;
|
|
1704
|
+
const channel = (
|
|
1705
|
+
baseTd?.type
|
|
1706
|
+
|| template?.type
|
|
1707
|
+
|| get(template, 'value.type')
|
|
1708
|
+
|| ''
|
|
1709
|
+
).toUpperCase();
|
|
1710
|
+
// Library mode: persist last submitted creatives shape so reopening still hydrates the editor
|
|
1711
|
+
// (parent may not merge getCreativesData back into templateData).
|
|
1712
|
+
if (this.props.isFullMode === false && template.value) {
|
|
1713
|
+
if (channel === constants.RCS) {
|
|
1714
|
+
const smsFallBackFromPayload = get(
|
|
1715
|
+
template.value,
|
|
1716
|
+
'versions.base.content.RCS.smsFallBackContent',
|
|
1717
|
+
);
|
|
1718
|
+
const rcsCardVarMappedFromPayload = get(
|
|
1719
|
+
template.value,
|
|
1720
|
+
'versions.base.content.RCS.rcsContent.cardContent[0].cardVarMapped',
|
|
1721
|
+
);
|
|
1722
|
+
next.templateData = {
|
|
1723
|
+
...baseTd,
|
|
1724
|
+
type: constants.RCS,
|
|
1725
|
+
name: template?.value?.name,
|
|
1726
|
+
versions: template?.value?.versions,
|
|
1727
|
+
...(smsFallBackFromPayload != null
|
|
1728
|
+
&& typeof smsFallBackFromPayload === 'object'
|
|
1729
|
+
&& Object.keys(smsFallBackFromPayload).length > 0
|
|
1730
|
+
? { smsFallBackContent: smsFallBackFromPayload }
|
|
1731
|
+
: {}),
|
|
1732
|
+
...(rcsCardVarMappedFromPayload != null
|
|
1733
|
+
&& typeof rcsCardVarMappedFromPayload === 'object'
|
|
1734
|
+
? { rcsCardVarMapped: rcsCardVarMappedFromPayload }
|
|
1735
|
+
: {}),
|
|
1736
|
+
};
|
|
1737
|
+
if (template._id) {
|
|
1738
|
+
next.templateData._id = template._id;
|
|
1739
|
+
}
|
|
1740
|
+
} else if (channel === constants.SMS) {
|
|
1741
|
+
const submittedSmsTemplateValue = template?.value;
|
|
1742
|
+
const smsVersions =
|
|
1743
|
+
submittedSmsTemplateValue?.history != null
|
|
1744
|
+
? submittedSmsTemplateValue
|
|
1745
|
+
: {
|
|
1746
|
+
base: submittedSmsTemplateValue?.base,
|
|
1747
|
+
history: submittedSmsTemplateValue?.base
|
|
1748
|
+
? [submittedSmsTemplateValue.base]
|
|
1749
|
+
: [],
|
|
1750
|
+
};
|
|
1751
|
+
next.templateData = {
|
|
1752
|
+
...baseTd,
|
|
1753
|
+
type: constants.SMS,
|
|
1754
|
+
name: baseTd?.name || constants.DEFAULT_SMS_TEMPLATE_NAME,
|
|
1755
|
+
versions: smsVersions,
|
|
1756
|
+
};
|
|
1757
|
+
if (template?._id) {
|
|
1758
|
+
next.templateData._id = template._id;
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
return next;
|
|
1763
|
+
},
|
|
1764
|
+
() => {
|
|
1765
|
+
if (!template.validity) {
|
|
1766
|
+
return;
|
|
1767
|
+
}
|
|
1768
|
+
const templateData = this.state.templateData ? this.state.templateData : template; //select existing or create new content
|
|
1769
|
+
const channelForConsumer = String(
|
|
1770
|
+
templateData.type
|
|
1771
|
+
|| template.type
|
|
1772
|
+
|| get(template, 'value.type')
|
|
1773
|
+
|| '',
|
|
1774
|
+
).toUpperCase();
|
|
1775
|
+
const creativesData = this.getCreativesData(
|
|
1776
|
+
channelForConsumer,
|
|
1777
|
+
template,
|
|
1778
|
+
this.state.templateData || template,
|
|
1779
|
+
);// convers data to consumer understandable format
|
|
1780
|
+
creativesData.then((data) => {
|
|
1781
|
+
this.logGTMEvent(channelForConsumer, data);
|
|
1782
|
+
this.processCentralCommsMetaId(channelForConsumer, data, {
|
|
1783
|
+
closeSlideBoxAfterSubmit: template.closeSlideBoxAfterSubmit,
|
|
1597
1784
|
});
|
|
1598
|
-
}
|
|
1599
|
-
|
|
1600
|
-
|
|
1785
|
+
});
|
|
1786
|
+
},
|
|
1787
|
+
);
|
|
1601
1788
|
}
|
|
1602
1789
|
|
|
1603
|
-
processCentralCommsMetaId = (channel, creativesData) => {
|
|
1790
|
+
processCentralCommsMetaId = (channel, creativesData, options = {}) => {
|
|
1791
|
+
const { closeSlideBoxAfterSubmit = false } = options;
|
|
1792
|
+
const maybeCloseLibrarySlideBox = () => {
|
|
1793
|
+
if (
|
|
1794
|
+
closeSlideBoxAfterSubmit
|
|
1795
|
+
&& this.props.isFullMode === false
|
|
1796
|
+
&& typeof this.handleCloseSlideBox === 'function'
|
|
1797
|
+
) {
|
|
1798
|
+
this.handleCloseSlideBox();
|
|
1799
|
+
}
|
|
1800
|
+
};
|
|
1604
1801
|
// Create the payload for the centralcommnsmetaId API call
|
|
1605
1802
|
const { isLoyaltyModule = false, loyaltyMetaData = {} } = this.props;
|
|
1606
1803
|
const { actionName, setMetaData = () => { } } = loyaltyMetaData;
|
|
@@ -1626,6 +1823,7 @@ export class Creatives extends React.Component {
|
|
|
1626
1823
|
if (result?.status?.code === 200) {
|
|
1627
1824
|
setMetaData(result);
|
|
1628
1825
|
this.props.getCreativesData(creativesData);
|
|
1826
|
+
maybeCloseLibrarySlideBox();
|
|
1629
1827
|
} else {
|
|
1630
1828
|
CapNotification.error({ message: <FormattedMessage {...messages.somethingWentWrong} /> });
|
|
1631
1829
|
}
|
|
@@ -1636,6 +1834,7 @@ export class Creatives extends React.Component {
|
|
|
1636
1834
|
} else {
|
|
1637
1835
|
// If not a loyalty module or different action, should work as usual
|
|
1638
1836
|
this.props.getCreativesData(creativesData);
|
|
1837
|
+
maybeCloseLibrarySlideBox();
|
|
1639
1838
|
}
|
|
1640
1839
|
};
|
|
1641
1840
|
|
|
@@ -1668,7 +1867,9 @@ export class Creatives extends React.Component {
|
|
|
1668
1867
|
}
|
|
1669
1868
|
this.setState((prevState) => ({
|
|
1670
1869
|
...prevState,
|
|
1671
|
-
|
|
1870
|
+
// Library mode (isFullMode === false): retain last template so reopening still has RCS payload.
|
|
1871
|
+
// Undefined isFullMode defaults to full-mode close behavior (clear templateData).
|
|
1872
|
+
...(this.props.isFullMode !== false ? { templateData: undefined } : {}),
|
|
1672
1873
|
showSlideBox: false,
|
|
1673
1874
|
liquidErrorMessage: { STANDARD_ERROR_MSG: [], LIQUID_ERROR_MSG: [] },
|
|
1674
1875
|
isLiquidValidationError: false,
|
|
@@ -1871,21 +2072,17 @@ export class Creatives extends React.Component {
|
|
|
1871
2072
|
}
|
|
1872
2073
|
|
|
1873
2074
|
showLiquidErrorInFooter = (errorMessagesFromFormBuilder, currentFormBuilderTab) => {
|
|
1874
|
-
const
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
this.setState(
|
|
1885
|
-
isLiquidValidationError,
|
|
1886
|
-
liquidErrorMessage: errorMessagesFromFormBuilder,
|
|
1887
|
-
activeFormBuilderTab: currentFormBuilderTab === 1 ? constants.ANDROID : (currentFormBuilderTab === 2 ? constants.IOS : null), // Update activeFormBuilderTab, default to 1 if undefined
|
|
1888
|
-
});
|
|
2075
|
+
const next = computeLiquidFooterUpdateFromFormBuilder(
|
|
2076
|
+
errorMessagesFromFormBuilder,
|
|
2077
|
+
this.state.liquidErrorMessage,
|
|
2078
|
+
currentFormBuilderTab,
|
|
2079
|
+
{
|
|
2080
|
+
previousIsLiquidValidationError: this.state.isLiquidValidationError,
|
|
2081
|
+
currentChannelUpper: this.state.currentChannel?.toUpperCase(),
|
|
2082
|
+
},
|
|
2083
|
+
);
|
|
2084
|
+
if (next == null) return;
|
|
2085
|
+
this.setState(next);
|
|
1889
2086
|
}
|
|
1890
2087
|
|
|
1891
2088
|
// Callback to update HTML Editor validation state (called from EmailWrapper)
|
|
@@ -2008,6 +2205,11 @@ export class Creatives extends React.Component {
|
|
|
2008
2205
|
inAppEditorType,
|
|
2009
2206
|
htmlEditorValidationState,
|
|
2010
2207
|
} = this.state;
|
|
2208
|
+
const useLocalTemplates = get(
|
|
2209
|
+
this.props,
|
|
2210
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
2211
|
+
get(this.props, 'useLocalTemplates', false),
|
|
2212
|
+
);
|
|
2011
2213
|
const {
|
|
2012
2214
|
isFullMode,
|
|
2013
2215
|
creativesMode,
|
|
@@ -2026,7 +2228,6 @@ export class Creatives extends React.Component {
|
|
|
2026
2228
|
smsRegister,
|
|
2027
2229
|
enableNewChannels,
|
|
2028
2230
|
eventContextTags,
|
|
2029
|
-
waitEventContextTags = {},
|
|
2030
2231
|
isLoyaltyModule,
|
|
2031
2232
|
loyaltyMetaData = {},
|
|
2032
2233
|
} = this.props;
|
|
@@ -2060,14 +2261,7 @@ export class Creatives extends React.Component {
|
|
|
2060
2261
|
// IMPORTANT: Never show ErrorInfoNote in footer when in HTML Editor mode, even if liquidErrorMessage exists
|
|
2061
2262
|
const shouldShowErrorInfoNoteInFooter = isHTMLEditorMode ? false : hasBEEEditorErrors;
|
|
2062
2263
|
|
|
2063
|
-
|
|
2064
|
-
const slideBoxWrapperMargin = (get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0 && get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0)
|
|
2065
|
-
? CAP_SPACE_64
|
|
2066
|
-
: get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0
|
|
2067
|
-
? CAP_SPACE_56
|
|
2068
|
-
: get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0
|
|
2069
|
-
? CAP_SPACE_32
|
|
2070
|
-
: 0;
|
|
2264
|
+
const slideBoxWrapperMargin = getSlideBoxWrapperMarginFromLiquidErrors(liquidErrorMessage);
|
|
2071
2265
|
/* TODO: Instead of passing down same props separately to each component down, write common function to these props and pass it accordingly */
|
|
2072
2266
|
|
|
2073
2267
|
// Compute anonymous user type and channel restrictions
|
|
@@ -2096,7 +2290,10 @@ export class Creatives extends React.Component {
|
|
|
2096
2290
|
<SlideBoxWrapper
|
|
2097
2291
|
slideBoxWrapperMargin={slideBoxWrapperMargin}
|
|
2098
2292
|
shouldApplyFooterMargin={shouldShowErrorInfoNoteInFooter}
|
|
2099
|
-
className={classnames(
|
|
2293
|
+
className={classnames(
|
|
2294
|
+
`${classPrefix} ${isFullMode ? 'creatives-full-mode' : 'creatives-library-mode'} ${mapTemplateCreate ? 'map-template-create' : ''}`,
|
|
2295
|
+
useLocalTemplates && slidBoxContent === 'templates' && 'creatives-slidebox--local-sms-templates',
|
|
2296
|
+
)}
|
|
2100
2297
|
>
|
|
2101
2298
|
<CapSlideBox
|
|
2102
2299
|
header={
|
|
@@ -2121,12 +2318,13 @@ export class Creatives extends React.Component {
|
|
|
2121
2318
|
smsRegister={smsRegister}
|
|
2122
2319
|
handleClose={this.handleCloseSlideBox}
|
|
2123
2320
|
moduleType={this.props.messageDetails?.type}
|
|
2321
|
+
useLocalTemplates={useLocalTemplates}
|
|
2124
2322
|
/>
|
|
2125
2323
|
)}
|
|
2126
2324
|
content={(
|
|
2127
2325
|
<SlideBoxContent
|
|
2128
2326
|
key="creatives-container-slidebox-content"
|
|
2129
|
-
onSelectTemplate={this.onSelectTemplate}
|
|
2327
|
+
onSelectTemplate={this.props.onSelectTemplate != null ? this.props.onSelectTemplate : this.onSelectTemplate}
|
|
2130
2328
|
onCreateComplete={getCreativesData}
|
|
2131
2329
|
onPreviewTemplate={this.onPreviewTemplate}
|
|
2132
2330
|
slidBoxContent={slidBoxContent}
|
|
@@ -2194,7 +2392,6 @@ export class Creatives extends React.Component {
|
|
|
2194
2392
|
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.
|
|
2195
2393
|
hostName={this.props?.hostName || ''}
|
|
2196
2394
|
eventContextTags={eventContextTags}
|
|
2197
|
-
waitEventContextTags={waitEventContextTags}
|
|
2198
2395
|
isLoyaltyModule={isLoyaltyModule}
|
|
2199
2396
|
loyaltyMetaData={loyaltyMetaData}
|
|
2200
2397
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
@@ -2203,7 +2400,8 @@ export class Creatives extends React.Component {
|
|
|
2203
2400
|
isTestAndPreviewMode={(() => this.state.isTestAndPreviewMode)()}
|
|
2204
2401
|
onHtmlEditorValidationStateChange={this.updateHtmlEditorValidationState}
|
|
2205
2402
|
onPersonalizationTokensChange={this.handlePersonalizationTokensChange}
|
|
2206
|
-
|
|
2403
|
+
localTemplatesConfig={pick(this.props.localTemplatesConfig || this.props, constants.LOCAL_TEMPLATE_CONFIG_KEYS)}
|
|
2404
|
+
/>
|
|
2207
2405
|
)}
|
|
2208
2406
|
footer={this.shouldShowFooter() ? (
|
|
2209
2407
|
<SlideBoxFooter
|
|
@@ -2288,13 +2486,31 @@ Creatives.propTypes = {
|
|
|
2288
2486
|
orgUnitId: PropTypes.number,
|
|
2289
2487
|
hostName: PropTypes.string,
|
|
2290
2488
|
eventContextTags: PropTypes.array,
|
|
2291
|
-
waitEventContextTags: PropTypes.object,
|
|
2292
2489
|
loyaltyTagFetchingDependencies: PropTypes.object,
|
|
2293
2490
|
customerType: PropTypes.string,
|
|
2294
2491
|
intl: PropTypes.shape({
|
|
2295
2492
|
formatMessage: PropTypes.func,
|
|
2296
2493
|
}),
|
|
2297
2494
|
stopValidation: PropTypes.func,
|
|
2495
|
+
// Local template list (e.g. for SMS fallback): when set, TemplatesV2 uses these instead of Redux.
|
|
2496
|
+
// All optional. Pass either localTemplatesConfig (object) or individual props below.
|
|
2497
|
+
localTemplatesConfig: PropTypes.shape({
|
|
2498
|
+
useLocalTemplates: PropTypes.bool,
|
|
2499
|
+
localTemplates: PropTypes.arrayOf(PropTypes.object),
|
|
2500
|
+
localTemplatesLoading: PropTypes.bool,
|
|
2501
|
+
localTemplatesFilterContent: PropTypes.node,
|
|
2502
|
+
localTemplatesSentinelContent: PropTypes.node,
|
|
2503
|
+
localTemplatesScrollContainerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
|
2504
|
+
localTemplatesUseSkeleton: PropTypes.bool,
|
|
2505
|
+
}),
|
|
2506
|
+
useLocalTemplates: PropTypes.bool,
|
|
2507
|
+
localTemplates: PropTypes.arrayOf(PropTypes.object),
|
|
2508
|
+
localTemplatesLoading: PropTypes.bool,
|
|
2509
|
+
localTemplatesFilterContent: PropTypes.node,
|
|
2510
|
+
localTemplatesSentinelContent: PropTypes.node,
|
|
2511
|
+
localTemplatesScrollContainerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
|
2512
|
+
localTemplatesUseSkeleton: PropTypes.bool,
|
|
2513
|
+
onSelectTemplate: PropTypes.func,
|
|
2298
2514
|
};
|
|
2299
2515
|
const mapStatesToProps = () => createStructuredSelector({
|
|
2300
2516
|
isLoading: isLoadingSelector(),
|