@capillarytech/creatives-library 9.0.28 → 9.0.29-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/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 +260 -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 +328 -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/Email/index.js +3 -63
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +4 -9
- 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 +1808 -949
- package/v2Containers/Rcs/index.scss +443 -8
- package/v2Containers/Rcs/messages.js +45 -22
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +484 -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 +74176 -39409
- 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 +219 -40
- package/v2Containers/Rcs/tests/mockData.js +38 -0
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +873 -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,10 @@ 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 { mapRcsCardContentForConsumerWithResolvedTags } from '../Rcs/utils';
|
|
94
|
+
import { pickRcsCardVarMappedEntries } from '../Rcs/rcsLibraryHydrationUtils';
|
|
95
|
+
import { RCS_SMS_FALLBACK_VAR_MAPPED_PROP } from '../../v2Components/CommonTestAndPreview/constants';
|
|
94
96
|
import { CREATIVE } from '../Facebook/constants';
|
|
95
97
|
import { LOYALTY } from '../App/constants';
|
|
96
98
|
import {
|
|
@@ -131,6 +133,11 @@ import { capSagaForFetchSchemaForEntity, capSagaLiquidEntity } from '../Cap/saga
|
|
|
131
133
|
import { v2TemplateSagaWatchGetDefaultBeeTemplates } from '../Templates/sagas';
|
|
132
134
|
import { DYNAMIC_URL } from '../../v2Components/CapWhatsappCTA/constants';
|
|
133
135
|
import ErrorInfoNote from '../../v2Components/ErrorInfoNote';
|
|
136
|
+
import SlideBoxWrapper from './CreativesSlideBoxWrapper';
|
|
137
|
+
import {
|
|
138
|
+
computeLiquidFooterUpdateFromFormBuilder,
|
|
139
|
+
getSlideBoxWrapperMarginFromLiquidErrors,
|
|
140
|
+
} from './embeddedSlideboxUtils';
|
|
134
141
|
|
|
135
142
|
import {
|
|
136
143
|
transformChannelPayload,
|
|
@@ -139,51 +146,24 @@ import {
|
|
|
139
146
|
import { MANUAL_CAROUSEL } from '../MobilePushNew/constants';
|
|
140
147
|
import { BIG_HTML } from '../InApp/constants';
|
|
141
148
|
|
|
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
149
|
const classPrefix = 'add-creatives-section';
|
|
160
150
|
const CREATIVES_CONTAINER = 'creativesContainer';
|
|
161
151
|
|
|
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
152
|
export class Creatives extends React.Component {
|
|
183
153
|
constructor(props) {
|
|
184
154
|
super(props);
|
|
185
155
|
|
|
186
|
-
const
|
|
156
|
+
const useLocalTemplates = get(
|
|
157
|
+
props,
|
|
158
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
159
|
+
get(props, 'useLocalTemplates', false),
|
|
160
|
+
);
|
|
161
|
+
const initialSlidBoxContent = this.getSlideBoxContent({
|
|
162
|
+
mode: props.creativesMode,
|
|
163
|
+
templateData: props.templateData,
|
|
164
|
+
isFullMode: props.isFullMode,
|
|
165
|
+
useLocalTemplates,
|
|
166
|
+
});
|
|
187
167
|
|
|
188
168
|
this.state = {
|
|
189
169
|
isLoadingContent: true,
|
|
@@ -230,7 +210,13 @@ export class Creatives extends React.Component {
|
|
|
230
210
|
}
|
|
231
211
|
|
|
232
212
|
componentWillUnmount() {
|
|
233
|
-
|
|
213
|
+
const isEmbedded = get(this.props, 'location.query.type', '') === EMBEDDED;
|
|
214
|
+
const useLocalTemplates = get(
|
|
215
|
+
this.props,
|
|
216
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
217
|
+
get(this.props, 'useLocalTemplates', false),
|
|
218
|
+
);
|
|
219
|
+
if (isEmbedded && !useLocalTemplates) {
|
|
234
220
|
this.props.templateActions.resetTemplateStoreData();
|
|
235
221
|
}
|
|
236
222
|
this.props.globalActions.clearMetaEntities();
|
|
@@ -840,15 +826,69 @@ export class Creatives extends React.Component {
|
|
|
840
826
|
smsFallBackContent = {},
|
|
841
827
|
creativeName = "",
|
|
842
828
|
channel = constants.RCS,
|
|
829
|
+
rcsCardVarMapped,
|
|
843
830
|
accountId = "",
|
|
844
831
|
} = templateData || {};
|
|
845
|
-
const
|
|
832
|
+
const { isFullMode: isFullModeForRcsPayload } = this.props;
|
|
833
|
+
const isCarouselRcs = (rcsContent?.cardType || '').toString().toUpperCase() === RCS_CONTENT_TYPE.carousel;
|
|
834
|
+
const firstCardIn = (rcsContent.cardContent && rcsContent.cardContent[0]) || {};
|
|
835
|
+
const {
|
|
836
|
+
cardDisplayTitle: _omitDispTitleIn,
|
|
837
|
+
cardDisplayDescription: _omitDispDescIn,
|
|
838
|
+
...cardContent
|
|
839
|
+
} = firstCardIn;
|
|
846
840
|
const Status = RCS_STATUSES.approved || '';
|
|
841
|
+
const mergedCardVarMapped = (() => {
|
|
842
|
+
const nestedCardVarMapped = cardContent?.cardVarMapped;
|
|
843
|
+
const rootMirrorCardVarMapped = rcsCardVarMapped;
|
|
844
|
+
const nestedRecord =
|
|
845
|
+
nestedCardVarMapped != null && typeof nestedCardVarMapped === 'object'
|
|
846
|
+
? nestedCardVarMapped
|
|
847
|
+
: {};
|
|
848
|
+
const rootRecord =
|
|
849
|
+
rootMirrorCardVarMapped != null && typeof rootMirrorCardVarMapped === 'object'
|
|
850
|
+
? rootMirrorCardVarMapped
|
|
851
|
+
: {};
|
|
852
|
+
const mergedFromRootAndNested = {
|
|
853
|
+
...pickRcsCardVarMappedEntries(rootRecord),
|
|
854
|
+
...pickRcsCardVarMappedEntries(nestedRecord),
|
|
855
|
+
};
|
|
856
|
+
return Object.keys(mergedFromRootAndNested).length > 0
|
|
857
|
+
? mergedFromRootAndNested
|
|
858
|
+
: null;
|
|
859
|
+
})();
|
|
860
|
+
// Campaigns (embedded): do not duplicate `cardVarMapped` as root `rcsCardVarMapped` on send —
|
|
861
|
+
// slot map stays on `versions…cardContent[0].cardVarMapped` only. Library full mode keeps root mirror.
|
|
862
|
+
// Use `=== true` so omitted/undefined `isFullMode` does not behave like library (avoids duplicate on approval payload).
|
|
863
|
+
const includeRootRcsCardVarMapped =
|
|
864
|
+
mergedCardVarMapped && isFullModeForRcsPayload === true;
|
|
865
|
+
|
|
866
|
+
const builtCardContent = isCarouselRcs
|
|
867
|
+
? (rcsContent.cardContent || []).map((card, idx) => {
|
|
868
|
+
const {
|
|
869
|
+
cardDisplayTitle: _dt,
|
|
870
|
+
cardDisplayDescription: _dd,
|
|
871
|
+
...restCard
|
|
872
|
+
} = card || {};
|
|
873
|
+
return {
|
|
874
|
+
...restCard,
|
|
875
|
+
...(idx === 0 && mergedCardVarMapped ? { cardVarMapped: mergedCardVarMapped } : {}),
|
|
876
|
+
Status,
|
|
877
|
+
};
|
|
878
|
+
})
|
|
879
|
+
: [
|
|
880
|
+
{
|
|
881
|
+
...cardContent,
|
|
882
|
+
...(mergedCardVarMapped ? { cardVarMapped: mergedCardVarMapped } : {}),
|
|
883
|
+
Status,
|
|
884
|
+
},
|
|
885
|
+
];
|
|
847
886
|
|
|
848
887
|
creativesTemplateData = {
|
|
849
888
|
type: channel,
|
|
850
889
|
edit: true,
|
|
851
890
|
name: creativeName,
|
|
891
|
+
...(includeRootRcsCardVarMapped ? { rcsCardVarMapped: mergedCardVarMapped } : {}),
|
|
852
892
|
versions: {
|
|
853
893
|
base: {
|
|
854
894
|
content: {
|
|
@@ -856,12 +896,7 @@ export class Creatives extends React.Component {
|
|
|
856
896
|
rcsContent: {
|
|
857
897
|
...rcsContent,
|
|
858
898
|
...(accountId && !isFullMode && { accountId }),
|
|
859
|
-
cardContent:
|
|
860
|
-
{
|
|
861
|
-
...cardContent,
|
|
862
|
-
Status,
|
|
863
|
-
},
|
|
864
|
-
],
|
|
899
|
+
cardContent: builtCardContent,
|
|
865
900
|
},
|
|
866
901
|
smsFallBackContent,
|
|
867
902
|
},
|
|
@@ -1009,7 +1044,10 @@ export class Creatives extends React.Component {
|
|
|
1009
1044
|
return newExpandableDetails;
|
|
1010
1045
|
}
|
|
1011
1046
|
|
|
1012
|
-
getCreativesData = async (
|
|
1047
|
+
getCreativesData = async (channelParam, template, templateRecords) => { //from creatives to consumers
|
|
1048
|
+
const channel = String(
|
|
1049
|
+
channelParam || template?.type || get(template, 'value.type') || '',
|
|
1050
|
+
).toUpperCase();
|
|
1013
1051
|
let templateData = { channel };
|
|
1014
1052
|
switch (channel) {
|
|
1015
1053
|
case constants.SMS:
|
|
@@ -1356,28 +1394,104 @@ export class Creatives extends React.Component {
|
|
|
1356
1394
|
break;
|
|
1357
1395
|
case constants.RCS:
|
|
1358
1396
|
if (template.value) {
|
|
1359
|
-
const {
|
|
1360
|
-
} = template.value || {};
|
|
1361
|
-
const
|
|
1397
|
+
const { isFullMode: isFullModeForRcsConsumerPayload } = this.props;
|
|
1398
|
+
const { name = "", versions = {} } = template.value || {};
|
|
1399
|
+
const fromSubmit = get(versions, 'base.content.RCS.smsFallBackContent', {});
|
|
1400
|
+
const fromRecords = {
|
|
1401
|
+
...(templateRecords?.smsFallBackContent || {}),
|
|
1402
|
+
...(get(templateRecords, 'versions.base.content.RCS.smsFallBackContent') || {}),
|
|
1403
|
+
};
|
|
1404
|
+
const hasMeaningfulRcsSmsFallback = (smsFallbackPayload) => {
|
|
1405
|
+
if (
|
|
1406
|
+
!smsFallbackPayload
|
|
1407
|
+
|| typeof smsFallbackPayload !== 'object'
|
|
1408
|
+
|| Object.keys(smsFallbackPayload).length === 0
|
|
1409
|
+
) {
|
|
1410
|
+
return false;
|
|
1411
|
+
}
|
|
1412
|
+
const fallbackBodyText = String(
|
|
1413
|
+
smsFallbackPayload.smsContent
|
|
1414
|
+
?? smsFallbackPayload.smsTemplateContent
|
|
1415
|
+
?? smsFallbackPayload.message
|
|
1416
|
+
?? smsFallbackPayload.content
|
|
1417
|
+
?? '',
|
|
1418
|
+
).trim();
|
|
1419
|
+
const fallbackTemplateName = String(
|
|
1420
|
+
smsFallbackPayload.smsTemplateName ?? smsFallbackPayload.templateName ?? '',
|
|
1421
|
+
).trim();
|
|
1422
|
+
const rcsSmsFallbackVarMapped =
|
|
1423
|
+
smsFallbackPayload?.[RCS_SMS_FALLBACK_VAR_MAPPED_PROP];
|
|
1424
|
+
const hasVarMappedEntries =
|
|
1425
|
+
rcsSmsFallbackVarMapped != null
|
|
1426
|
+
&& typeof rcsSmsFallbackVarMapped === 'object'
|
|
1427
|
+
&& Object.keys(rcsSmsFallbackVarMapped).length > 0;
|
|
1428
|
+
return (
|
|
1429
|
+
fallbackBodyText !== ''
|
|
1430
|
+
|| fallbackTemplateName !== ''
|
|
1431
|
+
|| hasVarMappedEntries
|
|
1432
|
+
);
|
|
1433
|
+
};
|
|
1434
|
+
// If submit has only empty strings, do not let it wipe fallback mirrored on templateRecords (library round-trip).
|
|
1435
|
+
const smsFallBackContent = hasMeaningfulRcsSmsFallback(fromSubmit)
|
|
1436
|
+
? { ...fromRecords, ...fromSubmit }
|
|
1437
|
+
: { ...fromSubmit, ...fromRecords };
|
|
1362
1438
|
const {
|
|
1363
|
-
cardContent = [],
|
|
1439
|
+
cardContent: cardContentFromSubmit = [],
|
|
1364
1440
|
contentType = "",
|
|
1365
1441
|
cardType = "",
|
|
1366
1442
|
cardSettings = {},
|
|
1367
1443
|
accountId = "",
|
|
1368
1444
|
} = get(versions, 'base.content.RCS.rcsContent', {});
|
|
1445
|
+
const rootRcsCardVarMappedFromSubmit = get(template, 'value.rcsCardVarMapped');
|
|
1446
|
+
const firstCardFromSubmit = Array.isArray(cardContentFromSubmit)
|
|
1447
|
+
? cardContentFromSubmit[0]
|
|
1448
|
+
: null;
|
|
1449
|
+
const cardContent = mapRcsCardContentForConsumerWithResolvedTags(
|
|
1450
|
+
cardContentFromSubmit,
|
|
1451
|
+
rootRcsCardVarMappedFromSubmit,
|
|
1452
|
+
isFullModeForRcsConsumerPayload,
|
|
1453
|
+
);
|
|
1369
1454
|
const rcsContent = {
|
|
1370
1455
|
contentType,
|
|
1371
1456
|
cardType,
|
|
1372
1457
|
cardSettings,
|
|
1373
1458
|
cardContent,
|
|
1374
1459
|
};
|
|
1460
|
+
const cardVarMappedFromFirstRcsCard =
|
|
1461
|
+
firstCardFromSubmit?.cardVarMapped != null
|
|
1462
|
+
&& typeof firstCardFromSubmit.cardVarMapped === 'object'
|
|
1463
|
+
? pickRcsCardVarMappedEntries(firstCardFromSubmit.cardVarMapped)
|
|
1464
|
+
: null;
|
|
1465
|
+
const includeRootRcsCardVarMappedOnConsumerPayload =
|
|
1466
|
+
cardVarMappedFromFirstRcsCard
|
|
1467
|
+
&& Object.keys(cardVarMappedFromFirstRcsCard).length > 0
|
|
1468
|
+
&& isFullModeForRcsConsumerPayload === true;
|
|
1375
1469
|
templateData = {
|
|
1376
1470
|
channel,
|
|
1377
1471
|
creativeName: name,
|
|
1378
1472
|
rcsContent,
|
|
1379
1473
|
accountId,
|
|
1474
|
+
...(includeRootRcsCardVarMappedOnConsumerPayload
|
|
1475
|
+
? { rcsCardVarMapped: cardVarMappedFromFirstRcsCard }
|
|
1476
|
+
: {}),
|
|
1380
1477
|
};
|
|
1478
|
+
// Library / campaign consumers round-trip templateData via getTemplateData; include SMS fallback
|
|
1479
|
+
// so reopening the editor restores fallback text and tag mappings.
|
|
1480
|
+
// cap-campaigns-v2 API expects `smsFallBackContent.message` (see normalizeRcsMessageContentForApi).
|
|
1481
|
+
if (hasMeaningfulRcsSmsFallback(smsFallBackContent)) {
|
|
1482
|
+
const smsText =
|
|
1483
|
+
smsFallBackContent.message
|
|
1484
|
+
?? smsFallBackContent.smsContent
|
|
1485
|
+
?? smsFallBackContent.smsTemplateContent
|
|
1486
|
+
?? '';
|
|
1487
|
+
templateData.smsFallBackContent = {
|
|
1488
|
+
...smsFallBackContent,
|
|
1489
|
+
...(String(smsText).trim() !== ''
|
|
1490
|
+
? { message: String(smsText).trim() }
|
|
1491
|
+
: {}),
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
normalizeRcsMessageContentForApi(templateData);
|
|
1381
1495
|
}
|
|
1382
1496
|
break;
|
|
1383
1497
|
case constants.ZALO:
|
|
@@ -1495,7 +1609,10 @@ export class Creatives extends React.Component {
|
|
|
1495
1609
|
return templateData;
|
|
1496
1610
|
};
|
|
1497
1611
|
|
|
1498
|
-
getSlideBoxContent({ mode, templateData, isFullMode }) {
|
|
1612
|
+
getSlideBoxContent({ mode, templateData, isFullMode, useLocalTemplates }) {
|
|
1613
|
+
if (useLocalTemplates && mode === 'create' && isEmpty(templateData)) {
|
|
1614
|
+
return 'templates';
|
|
1615
|
+
}
|
|
1499
1616
|
let creativesMode = isFullMode ? 'createTemplate' : 'templates';// for library mode templates page is initial mode and for full mode createTemplates
|
|
1500
1617
|
if (mode === 'create' && isFullMode) {
|
|
1501
1618
|
creativesMode = 'createTemplate';
|
|
@@ -1583,24 +1700,110 @@ export class Creatives extends React.Component {
|
|
|
1583
1700
|
getFormData = (template) => {
|
|
1584
1701
|
// Always reset isGetFormData so the child does not re-send form data on every re-render
|
|
1585
1702
|
// (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
|
-
|
|
1703
|
+
this.setState(
|
|
1704
|
+
(prevState) => {
|
|
1705
|
+
const next = { isGetFormData: false };
|
|
1706
|
+
if (!template.validity) {
|
|
1707
|
+
return next;
|
|
1708
|
+
}
|
|
1709
|
+
const baseTd = prevState.templateData || template;
|
|
1710
|
+
const channel = (
|
|
1711
|
+
baseTd?.type
|
|
1712
|
+
|| template?.type
|
|
1713
|
+
|| get(template, 'value.type')
|
|
1714
|
+
|| ''
|
|
1715
|
+
).toUpperCase();
|
|
1716
|
+
// Library mode: persist last submitted creatives shape so reopening still hydrates the editor
|
|
1717
|
+
// (parent may not merge getCreativesData back into templateData).
|
|
1718
|
+
if (this.props.isFullMode === false && template.value) {
|
|
1719
|
+
if (channel === constants.RCS) {
|
|
1720
|
+
const smsFallBackFromPayload = get(
|
|
1721
|
+
template.value,
|
|
1722
|
+
'versions.base.content.RCS.smsFallBackContent',
|
|
1723
|
+
);
|
|
1724
|
+
const rcsCardVarMappedFromPayload = get(
|
|
1725
|
+
template.value,
|
|
1726
|
+
'versions.base.content.RCS.rcsContent.cardContent[0].cardVarMapped',
|
|
1727
|
+
);
|
|
1728
|
+
next.templateData = {
|
|
1729
|
+
...baseTd,
|
|
1730
|
+
type: constants.RCS,
|
|
1731
|
+
name: template?.value?.name,
|
|
1732
|
+
versions: template?.value?.versions,
|
|
1733
|
+
...(smsFallBackFromPayload != null
|
|
1734
|
+
&& typeof smsFallBackFromPayload === 'object'
|
|
1735
|
+
&& Object.keys(smsFallBackFromPayload).length > 0
|
|
1736
|
+
? { smsFallBackContent: smsFallBackFromPayload }
|
|
1737
|
+
: {}),
|
|
1738
|
+
...(rcsCardVarMappedFromPayload != null
|
|
1739
|
+
&& typeof rcsCardVarMappedFromPayload === 'object'
|
|
1740
|
+
? { rcsCardVarMapped: rcsCardVarMappedFromPayload }
|
|
1741
|
+
: {}),
|
|
1742
|
+
};
|
|
1743
|
+
if (template._id) {
|
|
1744
|
+
next.templateData._id = template._id;
|
|
1745
|
+
}
|
|
1746
|
+
} else if (channel === constants.SMS) {
|
|
1747
|
+
const submittedSmsTemplateValue = template?.value;
|
|
1748
|
+
const smsVersions =
|
|
1749
|
+
submittedSmsTemplateValue?.history != null
|
|
1750
|
+
? submittedSmsTemplateValue
|
|
1751
|
+
: {
|
|
1752
|
+
base: submittedSmsTemplateValue?.base,
|
|
1753
|
+
history: submittedSmsTemplateValue?.base
|
|
1754
|
+
? [submittedSmsTemplateValue.base]
|
|
1755
|
+
: [],
|
|
1756
|
+
};
|
|
1757
|
+
next.templateData = {
|
|
1758
|
+
...baseTd,
|
|
1759
|
+
type: constants.SMS,
|
|
1760
|
+
name: baseTd?.name || constants.DEFAULT_SMS_TEMPLATE_NAME,
|
|
1761
|
+
versions: smsVersions,
|
|
1762
|
+
};
|
|
1763
|
+
if (template?._id) {
|
|
1764
|
+
next.templateData._id = template._id;
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
return next;
|
|
1769
|
+
},
|
|
1770
|
+
() => {
|
|
1771
|
+
if (!template.validity) {
|
|
1772
|
+
return;
|
|
1773
|
+
}
|
|
1774
|
+
const templateData = this.state.templateData ? this.state.templateData : template; //select existing or create new content
|
|
1775
|
+
const channelForConsumer = String(
|
|
1776
|
+
templateData.type
|
|
1777
|
+
|| template.type
|
|
1778
|
+
|| get(template, 'value.type')
|
|
1779
|
+
|| '',
|
|
1780
|
+
).toUpperCase();
|
|
1781
|
+
const creativesData = this.getCreativesData(
|
|
1782
|
+
channelForConsumer,
|
|
1783
|
+
template,
|
|
1784
|
+
this.state.templateData || template,
|
|
1785
|
+
);// convers data to consumer understandable format
|
|
1786
|
+
creativesData.then((data) => {
|
|
1787
|
+
this.logGTMEvent(channelForConsumer, data);
|
|
1788
|
+
this.processCentralCommsMetaId(channelForConsumer, data, {
|
|
1789
|
+
closeSlideBoxAfterSubmit: template.closeSlideBoxAfterSubmit,
|
|
1597
1790
|
});
|
|
1598
|
-
}
|
|
1599
|
-
|
|
1600
|
-
|
|
1791
|
+
});
|
|
1792
|
+
},
|
|
1793
|
+
);
|
|
1601
1794
|
}
|
|
1602
1795
|
|
|
1603
|
-
processCentralCommsMetaId = (channel, creativesData) => {
|
|
1796
|
+
processCentralCommsMetaId = (channel, creativesData, options = {}) => {
|
|
1797
|
+
const { closeSlideBoxAfterSubmit = false } = options;
|
|
1798
|
+
const maybeCloseLibrarySlideBox = () => {
|
|
1799
|
+
if (
|
|
1800
|
+
closeSlideBoxAfterSubmit
|
|
1801
|
+
&& this.props.isFullMode === false
|
|
1802
|
+
&& typeof this.handleCloseSlideBox === 'function'
|
|
1803
|
+
) {
|
|
1804
|
+
this.handleCloseSlideBox();
|
|
1805
|
+
}
|
|
1806
|
+
};
|
|
1604
1807
|
// Create the payload for the centralcommnsmetaId API call
|
|
1605
1808
|
const { isLoyaltyModule = false, loyaltyMetaData = {} } = this.props;
|
|
1606
1809
|
const { actionName, setMetaData = () => { } } = loyaltyMetaData;
|
|
@@ -1626,6 +1829,7 @@ export class Creatives extends React.Component {
|
|
|
1626
1829
|
if (result?.status?.code === 200) {
|
|
1627
1830
|
setMetaData(result);
|
|
1628
1831
|
this.props.getCreativesData(creativesData);
|
|
1832
|
+
maybeCloseLibrarySlideBox();
|
|
1629
1833
|
} else {
|
|
1630
1834
|
CapNotification.error({ message: <FormattedMessage {...messages.somethingWentWrong} /> });
|
|
1631
1835
|
}
|
|
@@ -1636,6 +1840,7 @@ export class Creatives extends React.Component {
|
|
|
1636
1840
|
} else {
|
|
1637
1841
|
// If not a loyalty module or different action, should work as usual
|
|
1638
1842
|
this.props.getCreativesData(creativesData);
|
|
1843
|
+
maybeCloseLibrarySlideBox();
|
|
1639
1844
|
}
|
|
1640
1845
|
};
|
|
1641
1846
|
|
|
@@ -1668,7 +1873,9 @@ export class Creatives extends React.Component {
|
|
|
1668
1873
|
}
|
|
1669
1874
|
this.setState((prevState) => ({
|
|
1670
1875
|
...prevState,
|
|
1671
|
-
|
|
1876
|
+
// Library mode (isFullMode === false): retain last template so reopening still has RCS payload.
|
|
1877
|
+
// Undefined isFullMode defaults to full-mode close behavior (clear templateData).
|
|
1878
|
+
...(this.props.isFullMode !== false ? { templateData: undefined } : {}),
|
|
1672
1879
|
showSlideBox: false,
|
|
1673
1880
|
liquidErrorMessage: { STANDARD_ERROR_MSG: [], LIQUID_ERROR_MSG: [] },
|
|
1674
1881
|
isLiquidValidationError: false,
|
|
@@ -1871,21 +2078,17 @@ export class Creatives extends React.Component {
|
|
|
1871
2078
|
}
|
|
1872
2079
|
|
|
1873
2080
|
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
|
-
});
|
|
2081
|
+
const next = computeLiquidFooterUpdateFromFormBuilder(
|
|
2082
|
+
errorMessagesFromFormBuilder,
|
|
2083
|
+
this.state.liquidErrorMessage,
|
|
2084
|
+
currentFormBuilderTab,
|
|
2085
|
+
{
|
|
2086
|
+
previousIsLiquidValidationError: this.state.isLiquidValidationError,
|
|
2087
|
+
currentChannelUpper: this.state.currentChannel?.toUpperCase(),
|
|
2088
|
+
},
|
|
2089
|
+
);
|
|
2090
|
+
if (next == null) return;
|
|
2091
|
+
this.setState(next);
|
|
1889
2092
|
}
|
|
1890
2093
|
|
|
1891
2094
|
// Callback to update HTML Editor validation state (called from EmailWrapper)
|
|
@@ -2008,6 +2211,11 @@ export class Creatives extends React.Component {
|
|
|
2008
2211
|
inAppEditorType,
|
|
2009
2212
|
htmlEditorValidationState,
|
|
2010
2213
|
} = this.state;
|
|
2214
|
+
const useLocalTemplates = get(
|
|
2215
|
+
this.props,
|
|
2216
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
2217
|
+
get(this.props, 'useLocalTemplates', false),
|
|
2218
|
+
);
|
|
2011
2219
|
const {
|
|
2012
2220
|
isFullMode,
|
|
2013
2221
|
creativesMode,
|
|
@@ -2026,7 +2234,6 @@ export class Creatives extends React.Component {
|
|
|
2026
2234
|
smsRegister,
|
|
2027
2235
|
enableNewChannels,
|
|
2028
2236
|
eventContextTags,
|
|
2029
|
-
waitEventContextTags = {},
|
|
2030
2237
|
isLoyaltyModule,
|
|
2031
2238
|
loyaltyMetaData = {},
|
|
2032
2239
|
} = this.props;
|
|
@@ -2060,14 +2267,7 @@ export class Creatives extends React.Component {
|
|
|
2060
2267
|
// IMPORTANT: Never show ErrorInfoNote in footer when in HTML Editor mode, even if liquidErrorMessage exists
|
|
2061
2268
|
const shouldShowErrorInfoNoteInFooter = isHTMLEditorMode ? false : hasBEEEditorErrors;
|
|
2062
2269
|
|
|
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;
|
|
2270
|
+
const slideBoxWrapperMargin = getSlideBoxWrapperMarginFromLiquidErrors(liquidErrorMessage);
|
|
2071
2271
|
/* TODO: Instead of passing down same props separately to each component down, write common function to these props and pass it accordingly */
|
|
2072
2272
|
|
|
2073
2273
|
// Compute anonymous user type and channel restrictions
|
|
@@ -2096,7 +2296,10 @@ export class Creatives extends React.Component {
|
|
|
2096
2296
|
<SlideBoxWrapper
|
|
2097
2297
|
slideBoxWrapperMargin={slideBoxWrapperMargin}
|
|
2098
2298
|
shouldApplyFooterMargin={shouldShowErrorInfoNoteInFooter}
|
|
2099
|
-
className={classnames(
|
|
2299
|
+
className={classnames(
|
|
2300
|
+
`${classPrefix} ${isFullMode ? 'creatives-full-mode' : 'creatives-library-mode'} ${mapTemplateCreate ? 'map-template-create' : ''}`,
|
|
2301
|
+
useLocalTemplates && slidBoxContent === 'templates' && 'creatives-slidebox--local-sms-templates',
|
|
2302
|
+
)}
|
|
2100
2303
|
>
|
|
2101
2304
|
<CapSlideBox
|
|
2102
2305
|
header={
|
|
@@ -2121,12 +2324,13 @@ export class Creatives extends React.Component {
|
|
|
2121
2324
|
smsRegister={smsRegister}
|
|
2122
2325
|
handleClose={this.handleCloseSlideBox}
|
|
2123
2326
|
moduleType={this.props.messageDetails?.type}
|
|
2327
|
+
useLocalTemplates={useLocalTemplates}
|
|
2124
2328
|
/>
|
|
2125
2329
|
)}
|
|
2126
2330
|
content={(
|
|
2127
2331
|
<SlideBoxContent
|
|
2128
2332
|
key="creatives-container-slidebox-content"
|
|
2129
|
-
onSelectTemplate={this.onSelectTemplate}
|
|
2333
|
+
onSelectTemplate={this.props.onSelectTemplate != null ? this.props.onSelectTemplate : this.onSelectTemplate}
|
|
2130
2334
|
onCreateComplete={getCreativesData}
|
|
2131
2335
|
onPreviewTemplate={this.onPreviewTemplate}
|
|
2132
2336
|
slidBoxContent={slidBoxContent}
|
|
@@ -2194,7 +2398,6 @@ export class Creatives extends React.Component {
|
|
|
2194
2398
|
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
2399
|
hostName={this.props?.hostName || ''}
|
|
2196
2400
|
eventContextTags={eventContextTags}
|
|
2197
|
-
waitEventContextTags={waitEventContextTags}
|
|
2198
2401
|
isLoyaltyModule={isLoyaltyModule}
|
|
2199
2402
|
loyaltyMetaData={loyaltyMetaData}
|
|
2200
2403
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
@@ -2203,7 +2406,8 @@ export class Creatives extends React.Component {
|
|
|
2203
2406
|
isTestAndPreviewMode={(() => this.state.isTestAndPreviewMode)()}
|
|
2204
2407
|
onHtmlEditorValidationStateChange={this.updateHtmlEditorValidationState}
|
|
2205
2408
|
onPersonalizationTokensChange={this.handlePersonalizationTokensChange}
|
|
2206
|
-
|
|
2409
|
+
localTemplatesConfig={pick(this.props.localTemplatesConfig || this.props, constants.LOCAL_TEMPLATE_CONFIG_KEYS)}
|
|
2410
|
+
/>
|
|
2207
2411
|
)}
|
|
2208
2412
|
footer={this.shouldShowFooter() ? (
|
|
2209
2413
|
<SlideBoxFooter
|
|
@@ -2288,13 +2492,31 @@ Creatives.propTypes = {
|
|
|
2288
2492
|
orgUnitId: PropTypes.number,
|
|
2289
2493
|
hostName: PropTypes.string,
|
|
2290
2494
|
eventContextTags: PropTypes.array,
|
|
2291
|
-
waitEventContextTags: PropTypes.object,
|
|
2292
2495
|
loyaltyTagFetchingDependencies: PropTypes.object,
|
|
2293
2496
|
customerType: PropTypes.string,
|
|
2294
2497
|
intl: PropTypes.shape({
|
|
2295
2498
|
formatMessage: PropTypes.func,
|
|
2296
2499
|
}),
|
|
2297
2500
|
stopValidation: PropTypes.func,
|
|
2501
|
+
// Local template list (e.g. for SMS fallback): when set, TemplatesV2 uses these instead of Redux.
|
|
2502
|
+
// All optional. Pass either localTemplatesConfig (object) or individual props below.
|
|
2503
|
+
localTemplatesConfig: PropTypes.shape({
|
|
2504
|
+
useLocalTemplates: PropTypes.bool,
|
|
2505
|
+
localTemplates: PropTypes.arrayOf(PropTypes.object),
|
|
2506
|
+
localTemplatesLoading: PropTypes.bool,
|
|
2507
|
+
localTemplatesFilterContent: PropTypes.node,
|
|
2508
|
+
localTemplatesSentinelContent: PropTypes.node,
|
|
2509
|
+
localTemplatesScrollContainerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
|
2510
|
+
localTemplatesUseSkeleton: PropTypes.bool,
|
|
2511
|
+
}),
|
|
2512
|
+
useLocalTemplates: PropTypes.bool,
|
|
2513
|
+
localTemplates: PropTypes.arrayOf(PropTypes.object),
|
|
2514
|
+
localTemplatesLoading: PropTypes.bool,
|
|
2515
|
+
localTemplatesFilterContent: PropTypes.node,
|
|
2516
|
+
localTemplatesSentinelContent: PropTypes.node,
|
|
2517
|
+
localTemplatesScrollContainerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
|
2518
|
+
localTemplatesUseSkeleton: PropTypes.bool,
|
|
2519
|
+
onSelectTemplate: PropTypes.func,
|
|
2298
2520
|
};
|
|
2299
2521
|
const mapStatesToProps = () => createStructuredSelector({
|
|
2300
2522
|
isLoading: isLoadingSelector(),
|