@capillarytech/creatives-library 8.0.345-alpha.10 → 8.0.345-alpha.12
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 +13 -0
- package/utils/commonUtils.js +19 -1
- package/utils/rcsPayloadUtils.js +92 -0
- package/utils/templateVarUtils.js +201 -0
- package/utils/tests/templateVarUtils.test.js +204 -0
- package/v2Components/CapActionButton/constants.js +7 -0
- package/v2Components/CapActionButton/index.js +167 -109
- package/v2Components/CapActionButton/index.scss +157 -6
- package/v2Components/CapActionButton/messages.js +19 -3
- package/v2Components/CapActionButton/tests/index.test.js +41 -17
- package/v2Components/CapTagList/index.js +10 -0
- package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +70 -49
- package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +8 -2
- package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +207 -21
- package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +16 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +85 -10
- package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +30 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +79 -11
- package/v2Components/CommonTestAndPreview/SendTestMessage.js +10 -5
- package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +160 -15
- package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js.rej +18 -0
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +341 -76
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +133 -4
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +11 -0
- package/v2Components/CommonTestAndPreview/constants.js +38 -2
- package/v2Components/CommonTestAndPreview/index.js +676 -186
- package/v2Components/CommonTestAndPreview/messages.js +49 -3
- package/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
- package/v2Components/CommonTestAndPreview/sagas.js +15 -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 +132 -4
- package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +2 -2
- package/v2Components/FormBuilder/index.js +8 -10
- package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +87 -0
- package/v2Components/SmsFallback/constants.js +73 -0
- package/v2Components/SmsFallback/index.js +955 -0
- package/v2Components/SmsFallback/index.scss +265 -0
- package/v2Components/SmsFallback/messages.js +78 -0
- package/v2Components/SmsFallback/smsFallbackUtils.js +118 -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 +197 -0
- package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +277 -0
- package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +422 -0
- package/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
- package/v2Components/TemplatePreview/_templatePreview.scss +33 -23
- package/v2Components/TemplatePreview/constants.js +2 -0
- package/v2Components/TemplatePreview/index.js +143 -28
- 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 +43 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +37 -24
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +10 -1
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +29 -4
- package/v2Containers/CreativesContainer/constants.js +9 -0
- package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +67 -0
- package/v2Containers/CreativesContainer/index.js +301 -107
- package/v2Containers/CreativesContainer/index.scss +51 -1
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +78 -34
- package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +79 -16
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +8 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +357 -98
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +20 -15
- package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
- package/v2Containers/CreativesContainer/tests/index.test.js +71 -9
- package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +125 -0
- package/v2Containers/Email/index.js +0 -23
- package/v2Containers/Rcs/constants.js +119 -8
- package/v2Containers/Rcs/index.js +2370 -807
- package/v2Containers/Rcs/index.js.rej +1336 -0
- package/v2Containers/Rcs/index.scss +276 -6
- package/v2Containers/Rcs/index.scss.rej +74 -0
- package/v2Containers/Rcs/messages.js +38 -3
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +225 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +98302 -70345
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +0 -5
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap.rej +128 -0
- 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 +100 -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 +636 -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 +163 -2
- package/v2Containers/Templates/actions.js +11 -0
- package/v2Containers/Templates/constants.js +2 -0
- package/v2Containers/Templates/index.js +119 -54
- package/v2Containers/Templates/sagas.js +57 -12
- package/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1043 -1079
- package/v2Containers/Templates/tests/sagas.test.js +193 -123
- 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/Whatsapp/index.js +3 -20
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +578 -34
- package/.npmrx +0 -2
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import {
|
|
4
|
-
CAP_SPACE_16, CAP_SPACE_32, CAP_SPACE_56, CAP_SPACE_64,
|
|
5
|
-
} from '@capillarytech/cap-ui-library/styled/variables';
|
|
6
|
-
|
|
7
3
|
import CapSlideBox from '@capillarytech/cap-ui-library/CapSlideBox';
|
|
8
4
|
import CapHeader from '@capillarytech/cap-ui-library/CapHeader';
|
|
9
5
|
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
@@ -13,12 +9,11 @@ import CapNotification from '@capillarytech/cap-ui-library/CapNotification';
|
|
|
13
9
|
import { injectIntl, FormattedMessage } from 'react-intl';
|
|
14
10
|
import classnames from 'classnames';
|
|
15
11
|
import {
|
|
16
|
-
isEmpty, get, forEach, cloneDeep, debounce,
|
|
12
|
+
isEmpty, get, forEach, cloneDeep, debounce, pick,
|
|
17
13
|
} from 'lodash';
|
|
18
14
|
import { connect } from 'react-redux';
|
|
19
15
|
import { createStructuredSelector } from 'reselect';
|
|
20
16
|
import { bindActionCreators, compose } from 'redux';
|
|
21
|
-
import styled from 'styled-components';
|
|
22
17
|
import { GA } from '@capillarytech/cap-ui-utils';
|
|
23
18
|
import { DAEMON } from '@capillarytech/vulcan-react-sdk/utils/sagaInjectorTypes';
|
|
24
19
|
|
|
@@ -32,6 +27,7 @@ import SlideBoxContent from './SlideBoxContent';
|
|
|
32
27
|
import * as constants from './constants';
|
|
33
28
|
import * as commonUtil from '../../utils/common';
|
|
34
29
|
import { gtmPush } from '../../utils/gtmTrackers';
|
|
30
|
+
import { normalizeRcsMessageContentForApi } from '../../utils/rcsPayloadUtils';
|
|
35
31
|
import './index.scss';
|
|
36
32
|
import * as templateActions from '../Templates/actions';
|
|
37
33
|
import * as globalActions from '../Cap/actions';
|
|
@@ -47,6 +43,9 @@ import {
|
|
|
47
43
|
import {EXTERNAL_URL, SITE_URL, WEBPUSH_MEDIA_TYPES} from '../WebPush/constants';
|
|
48
44
|
import { IMAGE, VIDEO } from '../Facebook/Advertisement/constant';
|
|
49
45
|
import { RCS_STATUSES } from '../Rcs/constants';
|
|
46
|
+
import { mapRcsCardContentForConsumerWithResolvedTags } from '../Rcs/utils';
|
|
47
|
+
import { pickRcsCardVarMappedEntries } from '../Rcs/rcsLibraryHydrationUtils';
|
|
48
|
+
import { RCS_SMS_FALLBACK_VAR_MAPPED_PROP } from '../../v2Components/CommonTestAndPreview/constants';
|
|
50
49
|
import { CREATIVE } from '../Facebook/constants';
|
|
51
50
|
import { LOYALTY } from '../App/constants';
|
|
52
51
|
import {
|
|
@@ -61,6 +60,11 @@ import { capSagaForFetchSchemaForEntity, capSagaLiquidEntity } from '../Cap/saga
|
|
|
61
60
|
import { v2TemplateSagaWatchGetDefaultBeeTemplates } from '../Templates/sagas';
|
|
62
61
|
import { DYNAMIC_URL } from '../../v2Components/CapWhatsappCTA/constants';
|
|
63
62
|
import ErrorInfoNote from '../../v2Components/ErrorInfoNote';
|
|
63
|
+
import SlideBoxWrapper from './CreativesSlideBoxWrapper';
|
|
64
|
+
import {
|
|
65
|
+
computeLiquidFooterUpdateFromFormBuilder,
|
|
66
|
+
getSlideBoxWrapperMarginFromLiquidErrors,
|
|
67
|
+
} from './embeddedSlideboxUtils';
|
|
64
68
|
|
|
65
69
|
import {
|
|
66
70
|
transformChannelPayload,
|
|
@@ -69,51 +73,24 @@ import {
|
|
|
69
73
|
import { MANUAL_CAROUSEL } from '../MobilePushNew/constants';
|
|
70
74
|
import { BIG_HTML } from '../InApp/constants';
|
|
71
75
|
|
|
72
|
-
/**
|
|
73
|
-
* Returns true if value is "deep empty": no errors present.
|
|
74
|
-
* - null/undefined: empty
|
|
75
|
-
* - string: empty if length === 0
|
|
76
|
-
* - array: empty if length === 0
|
|
77
|
-
* - plain object (e.g. { android: [], ios: [], generic: [] }): empty only if every value is deep-empty
|
|
78
|
-
*/
|
|
79
|
-
function isDeepEmpty(value) {
|
|
80
|
-
if (value == null) return true;
|
|
81
|
-
if (typeof value === 'string') return value.length === 0;
|
|
82
|
-
if (Array.isArray(value)) return value.length === 0;
|
|
83
|
-
if (typeof value === 'object') {
|
|
84
|
-
return Object.values(value).every(isDeepEmpty);
|
|
85
|
-
}
|
|
86
|
-
return false;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
76
|
const classPrefix = 'add-creatives-section';
|
|
90
77
|
const CREATIVES_CONTAINER = 'creativesContainer';
|
|
91
78
|
|
|
92
|
-
const SlideBoxWrapper = styled.div`
|
|
93
|
-
.cap-slide-box-v2-container{
|
|
94
|
-
.slidebox-header, .slidebox-content-container{
|
|
95
|
-
margin-bottom: ${({ slideBoxWrapperMargin }) => `${slideBoxWrapperMargin}`};
|
|
96
|
-
padding: 0 rem;
|
|
97
|
-
&.has-footer{
|
|
98
|
-
overflow-x: hidden;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
.slidebox-footer{
|
|
102
|
-
/* Only apply margin-bottom to footer when ErrorInfoNote is shown in footer (BEE editor) */
|
|
103
|
-
/* For HTML Editor, errors are shown in ValidationErrorDisplay (inside content area), so no footer margin needed */
|
|
104
|
-
margin-bottom: ${({ shouldApplyFooterMargin }) => (shouldApplyFooterMargin ? `${CAP_SPACE_16}` : '0')};
|
|
105
|
-
padding: 0 rem;
|
|
106
|
-
&.has-footer{
|
|
107
|
-
overflow-x: hidden;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
`;
|
|
112
79
|
export class Creatives extends React.Component {
|
|
113
80
|
constructor(props) {
|
|
114
81
|
super(props);
|
|
115
82
|
|
|
116
|
-
const
|
|
83
|
+
const useLocalTemplates = get(
|
|
84
|
+
props,
|
|
85
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
86
|
+
get(props, 'useLocalTemplates', false),
|
|
87
|
+
);
|
|
88
|
+
const initialSlidBoxContent = this.getSlideBoxContent({
|
|
89
|
+
mode: props.creativesMode,
|
|
90
|
+
templateData: props.templateData,
|
|
91
|
+
isFullMode: props.isFullMode,
|
|
92
|
+
useLocalTemplates,
|
|
93
|
+
});
|
|
117
94
|
|
|
118
95
|
this.state = {
|
|
119
96
|
isLoadingContent: true,
|
|
@@ -160,7 +137,13 @@ export class Creatives extends React.Component {
|
|
|
160
137
|
}
|
|
161
138
|
|
|
162
139
|
componentWillUnmount() {
|
|
163
|
-
|
|
140
|
+
const isEmbedded = get(this.props, 'location.query.type', '') === "embedded";
|
|
141
|
+
const useLocalTemplates = get(
|
|
142
|
+
this.props,
|
|
143
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
144
|
+
get(this.props, 'useLocalTemplates', false),
|
|
145
|
+
);
|
|
146
|
+
if (isEmbedded && !useLocalTemplates) {
|
|
164
147
|
this.props.templateActions.resetTemplateStoreData();
|
|
165
148
|
}
|
|
166
149
|
this.props.globalActions.clearMetaEntities();
|
|
@@ -762,25 +745,56 @@ export class Creatives extends React.Component {
|
|
|
762
745
|
smsFallBackContent = {},
|
|
763
746
|
creativeName = "",
|
|
764
747
|
channel = constants.RCS,
|
|
765
|
-
|
|
748
|
+
rcsCardVarMapped,
|
|
766
749
|
} = templateData || {};
|
|
767
|
-
const
|
|
750
|
+
const { isFullMode: isFullModeForRcsPayload } = this.props;
|
|
751
|
+
const firstCardIn = (rcsContent.cardContent && rcsContent.cardContent[0]) || {};
|
|
752
|
+
const {
|
|
753
|
+
cardDisplayTitle: _omitDispTitleIn,
|
|
754
|
+
cardDisplayDescription: _omitDispDescIn,
|
|
755
|
+
...cardContent
|
|
756
|
+
} = firstCardIn;
|
|
768
757
|
const Status = RCS_STATUSES.approved || '';
|
|
758
|
+
const mergedCardVarMapped = (() => {
|
|
759
|
+
const nestedCardVarMapped = cardContent?.cardVarMapped;
|
|
760
|
+
const rootMirrorCardVarMapped = rcsCardVarMapped;
|
|
761
|
+
const nestedRecord =
|
|
762
|
+
nestedCardVarMapped != null && typeof nestedCardVarMapped === 'object'
|
|
763
|
+
? nestedCardVarMapped
|
|
764
|
+
: {};
|
|
765
|
+
const rootRecord =
|
|
766
|
+
rootMirrorCardVarMapped != null && typeof rootMirrorCardVarMapped === 'object'
|
|
767
|
+
? rootMirrorCardVarMapped
|
|
768
|
+
: {};
|
|
769
|
+
const mergedFromRootAndNested = {
|
|
770
|
+
...pickRcsCardVarMappedEntries(rootRecord),
|
|
771
|
+
...pickRcsCardVarMappedEntries(nestedRecord),
|
|
772
|
+
};
|
|
773
|
+
return Object.keys(mergedFromRootAndNested).length > 0
|
|
774
|
+
? mergedFromRootAndNested
|
|
775
|
+
: null;
|
|
776
|
+
})();
|
|
777
|
+
// Campaigns (embedded): do not duplicate `cardVarMapped` as root `rcsCardVarMapped` on send —
|
|
778
|
+
// slot map stays on `versions…cardContent[0].cardVarMapped` only. Library full mode keeps root mirror.
|
|
779
|
+
// Use `=== true` so omitted/undefined `isFullMode` does not behave like library (avoids duplicate on approval payload).
|
|
780
|
+
const includeRootRcsCardVarMapped =
|
|
781
|
+
mergedCardVarMapped && isFullModeForRcsPayload === true;
|
|
769
782
|
|
|
770
783
|
creativesTemplateData = {
|
|
771
784
|
type: channel,
|
|
772
785
|
edit: true,
|
|
773
786
|
name: creativeName,
|
|
787
|
+
...(includeRootRcsCardVarMapped ? { rcsCardVarMapped: mergedCardVarMapped } : {}),
|
|
774
788
|
versions: {
|
|
775
789
|
base: {
|
|
776
790
|
content: {
|
|
777
791
|
RCS: {
|
|
778
792
|
rcsContent: {
|
|
779
793
|
...rcsContent,
|
|
780
|
-
...(accountId && !isFullMode && { accountId }),
|
|
781
794
|
cardContent: [
|
|
782
795
|
{
|
|
783
796
|
...cardContent,
|
|
797
|
+
...(mergedCardVarMapped ? { cardVarMapped: mergedCardVarMapped } : {}),
|
|
784
798
|
Status,
|
|
785
799
|
},
|
|
786
800
|
],
|
|
@@ -931,7 +945,10 @@ export class Creatives extends React.Component {
|
|
|
931
945
|
return newExpandableDetails;
|
|
932
946
|
}
|
|
933
947
|
|
|
934
|
-
getCreativesData = async (
|
|
948
|
+
getCreativesData = async (channelParam, template, templateRecords) => { //from creatives to consumers
|
|
949
|
+
const channel = String(
|
|
950
|
+
channelParam || template?.type || get(template, 'value.type') || '',
|
|
951
|
+
).toUpperCase();
|
|
935
952
|
let templateData = { channel };
|
|
936
953
|
switch (channel) {
|
|
937
954
|
case constants.SMS:
|
|
@@ -966,13 +983,10 @@ export class Creatives extends React.Component {
|
|
|
966
983
|
case constants.EMAIL:
|
|
967
984
|
if (template?.value?.base) {
|
|
968
985
|
let emailBase = template.value.base;
|
|
969
|
-
const { html_content
|
|
986
|
+
const { html_content } = emailBase || {};
|
|
970
987
|
if (!html_content) {
|
|
971
988
|
emailBase = templateRecords.base;
|
|
972
989
|
}
|
|
973
|
-
if (!emailBase.drag_drop_id && formDragDropId) {
|
|
974
|
-
emailBase = { ...emailBase, drag_drop_id: formDragDropId };
|
|
975
|
-
}
|
|
976
990
|
const newHtmlContent = await updateImagesInHtml(html_content);
|
|
977
991
|
templateData = {
|
|
978
992
|
...templateData, ...emailBase, emailBody: newHtmlContent, emailSubject: (emailBase && emailBase.subject) ? emailBase.subject : '',
|
|
@@ -1228,7 +1242,7 @@ export class Creatives extends React.Component {
|
|
|
1228
1242
|
};
|
|
1229
1243
|
}
|
|
1230
1244
|
break;
|
|
1231
|
-
case constants.FACEBOOK:
|
|
1245
|
+
case constants.FACEBOOK: {
|
|
1232
1246
|
if (template.value) {
|
|
1233
1247
|
const FacebookAd = template?.value?.versions?.base?.content?.FacebookAd;
|
|
1234
1248
|
const { type } = FacebookAd[0];
|
|
@@ -1272,34 +1286,110 @@ export class Creatives extends React.Component {
|
|
|
1272
1286
|
selectedMarketingObjective: template.value.selectedMarketingObjective,
|
|
1273
1287
|
};
|
|
1274
1288
|
}
|
|
1289
|
+
}
|
|
1275
1290
|
break;
|
|
1276
|
-
case constants.RCS:
|
|
1291
|
+
case constants.RCS: {
|
|
1277
1292
|
if (template.value) {
|
|
1278
|
-
const {
|
|
1279
|
-
} = template.value || {};
|
|
1280
|
-
const
|
|
1293
|
+
const { isFullMode: isFullModeForRcsConsumerPayload } = this.props;
|
|
1294
|
+
const { name = "", versions = {} } = template.value || {};
|
|
1295
|
+
const fromSubmit = get(versions, 'base.content.RCS.smsFallBackContent', {});
|
|
1296
|
+
const fromRecords = {
|
|
1297
|
+
...(templateRecords?.smsFallBackContent || {}),
|
|
1298
|
+
...(get(templateRecords, 'versions.base.content.RCS.smsFallBackContent') || {}),
|
|
1299
|
+
};
|
|
1300
|
+
const hasMeaningfulRcsSmsFallback = (smsFallbackPayload) => {
|
|
1301
|
+
if (
|
|
1302
|
+
!smsFallbackPayload
|
|
1303
|
+
|| typeof smsFallbackPayload !== 'object'
|
|
1304
|
+
|| Object.keys(smsFallbackPayload).length === 0
|
|
1305
|
+
) {
|
|
1306
|
+
return false;
|
|
1307
|
+
}
|
|
1308
|
+
const fallbackBodyText = String(
|
|
1309
|
+
smsFallbackPayload.smsContent
|
|
1310
|
+
?? smsFallbackPayload.smsTemplateContent
|
|
1311
|
+
?? smsFallbackPayload.message
|
|
1312
|
+
?? smsFallbackPayload.content
|
|
1313
|
+
?? '',
|
|
1314
|
+
).trim();
|
|
1315
|
+
const fallbackTemplateName = String(
|
|
1316
|
+
smsFallbackPayload.smsTemplateName ?? smsFallbackPayload.templateName ?? '',
|
|
1317
|
+
).trim();
|
|
1318
|
+
const rcsSmsFallbackVarMapped =
|
|
1319
|
+
smsFallbackPayload?.[RCS_SMS_FALLBACK_VAR_MAPPED_PROP];
|
|
1320
|
+
const hasVarMappedEntries =
|
|
1321
|
+
rcsSmsFallbackVarMapped != null
|
|
1322
|
+
&& typeof rcsSmsFallbackVarMapped === 'object'
|
|
1323
|
+
&& Object.keys(rcsSmsFallbackVarMapped).length > 0;
|
|
1324
|
+
return (
|
|
1325
|
+
fallbackBodyText !== ''
|
|
1326
|
+
|| fallbackTemplateName !== ''
|
|
1327
|
+
|| hasVarMappedEntries
|
|
1328
|
+
);
|
|
1329
|
+
};
|
|
1330
|
+
// If submit has only empty strings, do not let it wipe fallback mirrored on templateRecords (library round-trip).
|
|
1331
|
+
const smsFallBackContent = hasMeaningfulRcsSmsFallback(fromSubmit)
|
|
1332
|
+
? { ...fromRecords, ...fromSubmit }
|
|
1333
|
+
: { ...fromSubmit, ...fromRecords };
|
|
1281
1334
|
const {
|
|
1282
|
-
cardContent = [],
|
|
1335
|
+
cardContent: cardContentFromSubmit = [],
|
|
1283
1336
|
contentType = "",
|
|
1284
1337
|
cardType = "",
|
|
1285
1338
|
cardSettings = {},
|
|
1286
|
-
accountId = "",
|
|
1287
1339
|
} = get(versions, 'base.content.RCS.rcsContent', {});
|
|
1340
|
+
const rootRcsCardVarMappedFromSubmit = get(template, 'value.rcsCardVarMapped');
|
|
1341
|
+
const firstCardFromSubmit = Array.isArray(cardContentFromSubmit)
|
|
1342
|
+
? cardContentFromSubmit[0]
|
|
1343
|
+
: null;
|
|
1344
|
+
const cardContent = mapRcsCardContentForConsumerWithResolvedTags(
|
|
1345
|
+
cardContentFromSubmit,
|
|
1346
|
+
rootRcsCardVarMappedFromSubmit,
|
|
1347
|
+
isFullModeForRcsConsumerPayload,
|
|
1348
|
+
);
|
|
1288
1349
|
const rcsContent = {
|
|
1289
1350
|
contentType,
|
|
1290
1351
|
cardType,
|
|
1291
1352
|
cardSettings,
|
|
1292
1353
|
cardContent,
|
|
1293
1354
|
};
|
|
1355
|
+
const cardVarMappedFromFirstRcsCard =
|
|
1356
|
+
firstCardFromSubmit?.cardVarMapped != null
|
|
1357
|
+
&& typeof firstCardFromSubmit.cardVarMapped === 'object'
|
|
1358
|
+
? pickRcsCardVarMappedEntries(firstCardFromSubmit.cardVarMapped)
|
|
1359
|
+
: null;
|
|
1360
|
+
const includeRootRcsCardVarMappedOnConsumerPayload =
|
|
1361
|
+
cardVarMappedFromFirstRcsCard
|
|
1362
|
+
&& Object.keys(cardVarMappedFromFirstRcsCard).length > 0
|
|
1363
|
+
&& isFullModeForRcsConsumerPayload === true;
|
|
1294
1364
|
templateData = {
|
|
1295
1365
|
channel,
|
|
1296
1366
|
creativeName: name,
|
|
1297
1367
|
rcsContent,
|
|
1298
|
-
|
|
1368
|
+
...(includeRootRcsCardVarMappedOnConsumerPayload
|
|
1369
|
+
? { rcsCardVarMapped: cardVarMappedFromFirstRcsCard }
|
|
1370
|
+
: {}),
|
|
1299
1371
|
};
|
|
1372
|
+
// Library / campaign consumers round-trip templateData via getTemplateData; include SMS fallback
|
|
1373
|
+
// so reopening the editor restores fallback text and tag mappings.
|
|
1374
|
+
// cap-campaigns-v2 API expects `smsFallBackContent.message` (see normalizeRcsMessageContentForApi).
|
|
1375
|
+
if (hasMeaningfulRcsSmsFallback(smsFallBackContent)) {
|
|
1376
|
+
const smsText =
|
|
1377
|
+
smsFallBackContent.message
|
|
1378
|
+
?? smsFallBackContent.smsContent
|
|
1379
|
+
?? smsFallBackContent.smsTemplateContent
|
|
1380
|
+
?? '';
|
|
1381
|
+
templateData.smsFallBackContent = {
|
|
1382
|
+
...smsFallBackContent,
|
|
1383
|
+
...(String(smsText).trim() !== ''
|
|
1384
|
+
? { message: String(smsText).trim() }
|
|
1385
|
+
: {}),
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
normalizeRcsMessageContentForApi(templateData);
|
|
1300
1389
|
}
|
|
1390
|
+
}
|
|
1301
1391
|
break;
|
|
1302
|
-
case constants.ZALO:
|
|
1392
|
+
case constants.ZALO: {
|
|
1303
1393
|
if (template.value) {
|
|
1304
1394
|
templateData = {
|
|
1305
1395
|
...template.value,
|
|
@@ -1308,6 +1398,7 @@ export class Creatives extends React.Component {
|
|
|
1308
1398
|
delete templateData.type;
|
|
1309
1399
|
}
|
|
1310
1400
|
}
|
|
1401
|
+
}
|
|
1311
1402
|
break;
|
|
1312
1403
|
case constants.WEBPUSH: {
|
|
1313
1404
|
if (template.value) {
|
|
@@ -1414,7 +1505,10 @@ export class Creatives extends React.Component {
|
|
|
1414
1505
|
return templateData;
|
|
1415
1506
|
};
|
|
1416
1507
|
|
|
1417
|
-
getSlideBoxContent({ mode, templateData, isFullMode }) {
|
|
1508
|
+
getSlideBoxContent({ mode, templateData, isFullMode, useLocalTemplates }) {
|
|
1509
|
+
if (useLocalTemplates && mode === 'create' && isEmpty(templateData)) {
|
|
1510
|
+
return 'templates';
|
|
1511
|
+
}
|
|
1418
1512
|
let creativesMode = isFullMode ? 'createTemplate' : 'templates';// for library mode templates page is initial mode and for full mode createTemplates
|
|
1419
1513
|
if (mode === 'create' && isFullMode) {
|
|
1420
1514
|
creativesMode = 'createTemplate';
|
|
@@ -1502,24 +1596,110 @@ export class Creatives extends React.Component {
|
|
|
1502
1596
|
getFormData = (template) => {
|
|
1503
1597
|
// Always reset isGetFormData so the child does not re-send form data on every re-render
|
|
1504
1598
|
// (e.g. when user fixes validation error by typing, we must not auto-close the slidebox)
|
|
1505
|
-
this.setState(
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
{
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1599
|
+
this.setState(
|
|
1600
|
+
(prevState) => {
|
|
1601
|
+
const next = { isGetFormData: false };
|
|
1602
|
+
if (!template.validity) {
|
|
1603
|
+
return next;
|
|
1604
|
+
}
|
|
1605
|
+
const baseTd = prevState.templateData || template;
|
|
1606
|
+
const channel = (
|
|
1607
|
+
baseTd?.type
|
|
1608
|
+
|| template?.type
|
|
1609
|
+
|| get(template, 'value.type')
|
|
1610
|
+
|| ''
|
|
1611
|
+
).toUpperCase();
|
|
1612
|
+
// Library mode: persist last submitted creatives shape so reopening still hydrates the editor
|
|
1613
|
+
// (parent may not merge getCreativesData back into templateData).
|
|
1614
|
+
if (this.props.isFullMode === false && template.value) {
|
|
1615
|
+
if (channel === constants.RCS) {
|
|
1616
|
+
const smsFallBackFromPayload = get(
|
|
1617
|
+
template.value,
|
|
1618
|
+
'versions.base.content.RCS.smsFallBackContent',
|
|
1619
|
+
);
|
|
1620
|
+
const rcsCardVarMappedFromPayload = get(
|
|
1621
|
+
template.value,
|
|
1622
|
+
'versions.base.content.RCS.rcsContent.cardContent[0].cardVarMapped',
|
|
1623
|
+
);
|
|
1624
|
+
next.templateData = {
|
|
1625
|
+
...baseTd,
|
|
1626
|
+
type: constants.RCS,
|
|
1627
|
+
name: template?.value?.name,
|
|
1628
|
+
versions: template?.value?.versions,
|
|
1629
|
+
...(smsFallBackFromPayload != null
|
|
1630
|
+
&& typeof smsFallBackFromPayload === 'object'
|
|
1631
|
+
&& Object.keys(smsFallBackFromPayload).length > 0
|
|
1632
|
+
? { smsFallBackContent: smsFallBackFromPayload }
|
|
1633
|
+
: {}),
|
|
1634
|
+
...(rcsCardVarMappedFromPayload != null
|
|
1635
|
+
&& typeof rcsCardVarMappedFromPayload === 'object'
|
|
1636
|
+
? { rcsCardVarMapped: rcsCardVarMappedFromPayload }
|
|
1637
|
+
: {}),
|
|
1638
|
+
};
|
|
1639
|
+
if (template._id) {
|
|
1640
|
+
next.templateData._id = template._id;
|
|
1641
|
+
}
|
|
1642
|
+
} else if (channel === constants.SMS) {
|
|
1643
|
+
const submittedSmsTemplateValue = template?.value;
|
|
1644
|
+
const smsVersions =
|
|
1645
|
+
submittedSmsTemplateValue?.history != null
|
|
1646
|
+
? submittedSmsTemplateValue
|
|
1647
|
+
: {
|
|
1648
|
+
base: submittedSmsTemplateValue?.base,
|
|
1649
|
+
history: submittedSmsTemplateValue?.base
|
|
1650
|
+
? [submittedSmsTemplateValue.base]
|
|
1651
|
+
: [],
|
|
1652
|
+
};
|
|
1653
|
+
next.templateData = {
|
|
1654
|
+
...baseTd,
|
|
1655
|
+
type: constants.SMS,
|
|
1656
|
+
name: baseTd?.name || 'Campaign message SMS content',
|
|
1657
|
+
versions: smsVersions,
|
|
1658
|
+
};
|
|
1659
|
+
if (template?._id) {
|
|
1660
|
+
next.templateData._id = template._id;
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
return next;
|
|
1665
|
+
},
|
|
1666
|
+
() => {
|
|
1667
|
+
if (!template.validity) {
|
|
1668
|
+
return;
|
|
1669
|
+
}
|
|
1670
|
+
const templateData = this.state.templateData ? this.state.templateData : template; //select existing or create new content
|
|
1671
|
+
const channelForConsumer = String(
|
|
1672
|
+
templateData.type
|
|
1673
|
+
|| template.type
|
|
1674
|
+
|| get(template, 'value.type')
|
|
1675
|
+
|| '',
|
|
1676
|
+
).toUpperCase();
|
|
1677
|
+
const creativesData = this.getCreativesData(
|
|
1678
|
+
channelForConsumer,
|
|
1679
|
+
template,
|
|
1680
|
+
this.state.templateData || template,
|
|
1681
|
+
);// convers data to consumer understandable format
|
|
1682
|
+
creativesData.then((data) => {
|
|
1683
|
+
this.logGTMEvent(channelForConsumer, data);
|
|
1684
|
+
this.processCentralCommsMetaId(channelForConsumer, data, {
|
|
1685
|
+
closeSlideBoxAfterSubmit: template.closeSlideBoxAfterSubmit,
|
|
1516
1686
|
});
|
|
1517
|
-
}
|
|
1518
|
-
|
|
1519
|
-
|
|
1687
|
+
});
|
|
1688
|
+
},
|
|
1689
|
+
);
|
|
1520
1690
|
}
|
|
1521
1691
|
|
|
1522
|
-
processCentralCommsMetaId = (channel, creativesData) => {
|
|
1692
|
+
processCentralCommsMetaId = (channel, creativesData, options = {}) => {
|
|
1693
|
+
const { closeSlideBoxAfterSubmit = false } = options;
|
|
1694
|
+
const maybeCloseLibrarySlideBox = () => {
|
|
1695
|
+
if (
|
|
1696
|
+
closeSlideBoxAfterSubmit
|
|
1697
|
+
&& this.props.isFullMode === false
|
|
1698
|
+
&& typeof this.handleCloseSlideBox === 'function'
|
|
1699
|
+
) {
|
|
1700
|
+
this.handleCloseSlideBox();
|
|
1701
|
+
}
|
|
1702
|
+
};
|
|
1523
1703
|
// Create the payload for the centralcommnsmetaId API call
|
|
1524
1704
|
const { isLoyaltyModule = false, loyaltyMetaData = {} } = this.props;
|
|
1525
1705
|
const { actionName, setMetaData = () => { } } = loyaltyMetaData;
|
|
@@ -1545,6 +1725,7 @@ export class Creatives extends React.Component {
|
|
|
1545
1725
|
if (result?.status?.code === 200) {
|
|
1546
1726
|
setMetaData(result);
|
|
1547
1727
|
this.props.getCreativesData(creativesData);
|
|
1728
|
+
maybeCloseLibrarySlideBox();
|
|
1548
1729
|
} else {
|
|
1549
1730
|
CapNotification.error({ message: <FormattedMessage {...messages.somethingWentWrong} /> });
|
|
1550
1731
|
}
|
|
@@ -1555,6 +1736,7 @@ export class Creatives extends React.Component {
|
|
|
1555
1736
|
} else {
|
|
1556
1737
|
// If not a loyalty module or different action, should work as usual
|
|
1557
1738
|
this.props.getCreativesData(creativesData);
|
|
1739
|
+
maybeCloseLibrarySlideBox();
|
|
1558
1740
|
}
|
|
1559
1741
|
};
|
|
1560
1742
|
|
|
@@ -1587,7 +1769,9 @@ export class Creatives extends React.Component {
|
|
|
1587
1769
|
}
|
|
1588
1770
|
this.setState((prevState) => ({
|
|
1589
1771
|
...prevState,
|
|
1590
|
-
|
|
1772
|
+
// Library mode (isFullMode === false): retain last template so reopening still has RCS payload.
|
|
1773
|
+
// Undefined isFullMode defaults to full-mode close behavior (clear templateData).
|
|
1774
|
+
...(this.props.isFullMode !== false ? { templateData: undefined } : {}),
|
|
1591
1775
|
showSlideBox: false,
|
|
1592
1776
|
liquidErrorMessage: { STANDARD_ERROR_MSG: [], LIQUID_ERROR_MSG: [] },
|
|
1593
1777
|
isLiquidValidationError: false,
|
|
@@ -1798,21 +1982,12 @@ export class Creatives extends React.Component {
|
|
|
1798
1982
|
}
|
|
1799
1983
|
|
|
1800
1984
|
showLiquidErrorInFooter = (errorMessagesFromFormBuilder, currentFormBuilderTab) => {
|
|
1801
|
-
const
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
const hasStandard = !isDeepEmpty(standardMsgs);
|
|
1805
|
-
const isLiquidValidationError = hasLiquid || hasStandard;
|
|
1806
|
-
// Don't overwrite existing liquid error with empty only for Mobile Push OLD (FormBuilder/clear calls empty there); SMS/others clear on input change
|
|
1807
|
-
const isMobilePush = this.state.currentChannel?.toUpperCase() === constants.MOBILE_PUSH;
|
|
1808
|
-
if (!hasLiquid && !hasStandard && this.state.isLiquidValidationError && isMobilePush) {
|
|
1809
|
-
return;
|
|
1810
|
-
}
|
|
1811
|
-
this.setState({
|
|
1812
|
-
isLiquidValidationError,
|
|
1813
|
-
liquidErrorMessage: errorMessagesFromFormBuilder,
|
|
1814
|
-
activeFormBuilderTab: currentFormBuilderTab === 1 ? constants.ANDROID : (currentFormBuilderTab === 2 ? constants.IOS : null), // Update activeFormBuilderTab, default to 1 if undefined
|
|
1985
|
+
const next = computeLiquidFooterUpdateFromFormBuilder(errorMessagesFromFormBuilder, currentFormBuilderTab, {
|
|
1986
|
+
previousIsLiquidValidationError: this.state.isLiquidValidationError,
|
|
1987
|
+
currentChannelUpper: this.state.currentChannel?.toUpperCase(),
|
|
1815
1988
|
});
|
|
1989
|
+
if (next == null) return;
|
|
1990
|
+
this.setState(next);
|
|
1816
1991
|
}
|
|
1817
1992
|
|
|
1818
1993
|
// Callback to update HTML Editor validation state (called from EmailWrapper)
|
|
@@ -1935,6 +2110,11 @@ export class Creatives extends React.Component {
|
|
|
1935
2110
|
inAppEditorType,
|
|
1936
2111
|
htmlEditorValidationState,
|
|
1937
2112
|
} = this.state;
|
|
2113
|
+
const useLocalTemplates = get(
|
|
2114
|
+
this.props,
|
|
2115
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
2116
|
+
get(this.props, 'useLocalTemplates', false),
|
|
2117
|
+
);
|
|
1938
2118
|
const {
|
|
1939
2119
|
isFullMode,
|
|
1940
2120
|
creativesMode,
|
|
@@ -1953,7 +2133,6 @@ export class Creatives extends React.Component {
|
|
|
1953
2133
|
smsRegister,
|
|
1954
2134
|
enableNewChannels,
|
|
1955
2135
|
eventContextTags,
|
|
1956
|
-
waitEventContextTags = {},
|
|
1957
2136
|
isLoyaltyModule,
|
|
1958
2137
|
loyaltyMetaData = {},
|
|
1959
2138
|
} = this.props;
|
|
@@ -1987,14 +2166,7 @@ export class Creatives extends React.Component {
|
|
|
1987
2166
|
// IMPORTANT: Never show ErrorInfoNote in footer when in HTML Editor mode, even if liquidErrorMessage exists
|
|
1988
2167
|
const shouldShowErrorInfoNoteInFooter = isHTMLEditorMode ? false : hasBEEEditorErrors;
|
|
1989
2168
|
|
|
1990
|
-
|
|
1991
|
-
const slideBoxWrapperMargin = (get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0 && get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0)
|
|
1992
|
-
? CAP_SPACE_64
|
|
1993
|
-
: get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0
|
|
1994
|
-
? CAP_SPACE_56
|
|
1995
|
-
: get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0
|
|
1996
|
-
? CAP_SPACE_32
|
|
1997
|
-
: 0;
|
|
2169
|
+
const slideBoxWrapperMargin = getSlideBoxWrapperMarginFromLiquidErrors(liquidErrorMessage);
|
|
1998
2170
|
/* TODO: Instead of passing down same props separately to each component down, write common function to these props and pass it accordingly */
|
|
1999
2171
|
|
|
2000
2172
|
// Compute anonymous user type and channel restrictions
|
|
@@ -2023,7 +2195,10 @@ export class Creatives extends React.Component {
|
|
|
2023
2195
|
<SlideBoxWrapper
|
|
2024
2196
|
slideBoxWrapperMargin={slideBoxWrapperMargin}
|
|
2025
2197
|
shouldApplyFooterMargin={shouldShowErrorInfoNoteInFooter}
|
|
2026
|
-
className={classnames(
|
|
2198
|
+
className={classnames(
|
|
2199
|
+
`${classPrefix} ${isFullMode ? 'creatives-full-mode' : 'creatives-library-mode'} ${mapTemplateCreate ? 'map-template-create' : ''}`,
|
|
2200
|
+
useLocalTemplates && slidBoxContent === 'templates' && 'creatives-slidebox--local-sms-templates',
|
|
2201
|
+
)}
|
|
2027
2202
|
>
|
|
2028
2203
|
<CapSlideBox
|
|
2029
2204
|
header={
|
|
@@ -2048,12 +2223,13 @@ export class Creatives extends React.Component {
|
|
|
2048
2223
|
smsRegister={smsRegister}
|
|
2049
2224
|
handleClose={this.handleCloseSlideBox}
|
|
2050
2225
|
moduleType={this.props.messageDetails?.type}
|
|
2226
|
+
useLocalTemplates={useLocalTemplates}
|
|
2051
2227
|
/>
|
|
2052
2228
|
)}
|
|
2053
2229
|
content={(
|
|
2054
2230
|
<SlideBoxContent
|
|
2055
2231
|
key="creatives-container-slidebox-content"
|
|
2056
|
-
onSelectTemplate={this.onSelectTemplate}
|
|
2232
|
+
onSelectTemplate={this.props.onSelectTemplate != null ? this.props.onSelectTemplate : this.onSelectTemplate}
|
|
2057
2233
|
onCreateComplete={getCreativesData}
|
|
2058
2234
|
onPreviewTemplate={this.onPreviewTemplate}
|
|
2059
2235
|
slidBoxContent={slidBoxContent}
|
|
@@ -2121,7 +2297,6 @@ export class Creatives extends React.Component {
|
|
|
2121
2297
|
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.
|
|
2122
2298
|
hostName={this.props?.hostName || ''}
|
|
2123
2299
|
eventContextTags={eventContextTags}
|
|
2124
|
-
waitEventContextTags={waitEventContextTags}
|
|
2125
2300
|
isLoyaltyModule={isLoyaltyModule}
|
|
2126
2301
|
loyaltyMetaData={loyaltyMetaData}
|
|
2127
2302
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
@@ -2130,7 +2305,8 @@ export class Creatives extends React.Component {
|
|
|
2130
2305
|
isTestAndPreviewMode={(() => this.state.isTestAndPreviewMode)()}
|
|
2131
2306
|
onHtmlEditorValidationStateChange={this.updateHtmlEditorValidationState}
|
|
2132
2307
|
onPersonalizationTokensChange={this.handlePersonalizationTokensChange}
|
|
2133
|
-
|
|
2308
|
+
localTemplatesConfig={pick(this.props.localTemplatesConfig || this.props, constants.LOCAL_TEMPLATE_CONFIG_KEYS)}
|
|
2309
|
+
/>
|
|
2134
2310
|
)}
|
|
2135
2311
|
footer={this.shouldShowFooter() ? (
|
|
2136
2312
|
<SlideBoxFooter
|
|
@@ -2214,13 +2390,31 @@ Creatives.propTypes = {
|
|
|
2214
2390
|
orgUnitId: PropTypes.number,
|
|
2215
2391
|
hostName: PropTypes.string,
|
|
2216
2392
|
eventContextTags: PropTypes.array,
|
|
2217
|
-
waitEventContextTags: PropTypes.object,
|
|
2218
2393
|
loyaltyTagFetchingDependencies: PropTypes.object,
|
|
2219
2394
|
customerType: PropTypes.string,
|
|
2220
2395
|
intl: PropTypes.shape({
|
|
2221
2396
|
formatMessage: PropTypes.func,
|
|
2222
2397
|
}),
|
|
2223
2398
|
stopValidation: PropTypes.func,
|
|
2399
|
+
// Local template list (e.g. for SMS fallback): when set, TemplatesV2 uses these instead of Redux.
|
|
2400
|
+
// All optional. Pass either localTemplatesConfig (object) or individual props below.
|
|
2401
|
+
localTemplatesConfig: PropTypes.shape({
|
|
2402
|
+
useLocalTemplates: PropTypes.bool,
|
|
2403
|
+
localTemplates: PropTypes.arrayOf(PropTypes.object),
|
|
2404
|
+
localTemplatesLoading: PropTypes.bool,
|
|
2405
|
+
localTemplatesFilterContent: PropTypes.node,
|
|
2406
|
+
localTemplatesSentinelContent: PropTypes.node,
|
|
2407
|
+
localTemplatesScrollContainerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
|
2408
|
+
localTemplatesUseSkeleton: PropTypes.bool,
|
|
2409
|
+
}),
|
|
2410
|
+
useLocalTemplates: PropTypes.bool,
|
|
2411
|
+
localTemplates: PropTypes.arrayOf(PropTypes.object),
|
|
2412
|
+
localTemplatesLoading: PropTypes.bool,
|
|
2413
|
+
localTemplatesFilterContent: PropTypes.node,
|
|
2414
|
+
localTemplatesSentinelContent: PropTypes.node,
|
|
2415
|
+
localTemplatesScrollContainerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
|
2416
|
+
localTemplatesUseSkeleton: PropTypes.bool,
|
|
2417
|
+
onSelectTemplate: PropTypes.func,
|
|
2224
2418
|
};
|
|
2225
2419
|
const mapStatesToProps = () => createStructuredSelector({
|
|
2226
2420
|
isLoading: isLoadingSelector(),
|