@capillarytech/creatives-library 8.0.345-alpha.13 → 8.0.345-alpha.15
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/api.js +0 -20
- package/services/tests/api.test.js +13 -59
- 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/CapCustomSkeleton/index.js +1 -1
- package/v2Components/CapCustomSkeleton/tests/__snapshots__/index.test.js.snap +12 -12
- 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 +36 -4
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +11 -4
- 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 +300 -108
- package/v2Containers/CreativesContainer/index.scss +51 -1
- package/v2Containers/CreativesContainer/messages.js +0 -4
- 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 -18
- 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/Rcs/constants.js +119 -8
- package/v2Containers/Rcs/index.js +2379 -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 +98018 -70073
- 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/ChannelTypeIllustration.js +6 -23
- package/v2Containers/Templates/TemplatesActionBar.js +101 -0
- package/v2Containers/Templates/_templates.scss +181 -126
- package/v2Containers/Templates/actions.js +11 -36
- package/v2Containers/Templates/constants.js +2 -23
- package/v2Containers/Templates/index.js +142 -333
- package/v2Containers/Templates/messages.js +0 -68
- package/v2Containers/Templates/reducer.js +0 -68
- package/v2Containers/Templates/sagas.js +55 -98
- package/v2Containers/Templates/selectors.js +0 -12
- package/v2Containers/Templates/tests/ChannelTypeIllustration.test.js +0 -12
- package/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1042 -1256
- package/v2Containers/Templates/tests/index.test.js +0 -6
- package/v2Containers/Templates/tests/reducer.test.js +0 -178
- package/v2Containers/Templates/tests/sagas.test.js +200 -436
- package/v2Containers/Templates/tests/selector.test.js +0 -32
- 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/v2Containers/Assets/images/archive_Empty_Illustration.svg +0 -9
|
@@ -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();
|
|
@@ -260,10 +243,6 @@ export class Creatives extends React.Component {
|
|
|
260
243
|
};
|
|
261
244
|
|
|
262
245
|
onEditTemplate = () => {
|
|
263
|
-
if (this.props.templateData && this.props.templateData.isArchived) {
|
|
264
|
-
CapNotification.error({ message: this.props.intl.formatMessage(messages.cannotEditArchivedTemplate) });
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
246
|
this.setState({ slidBoxContent: 'editTemplate', showSlideBox: true, templateNameExists: true });
|
|
268
247
|
};
|
|
269
248
|
|
|
@@ -766,25 +745,56 @@ export class Creatives extends React.Component {
|
|
|
766
745
|
smsFallBackContent = {},
|
|
767
746
|
creativeName = "",
|
|
768
747
|
channel = constants.RCS,
|
|
769
|
-
|
|
748
|
+
rcsCardVarMapped,
|
|
770
749
|
} = templateData || {};
|
|
771
|
-
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;
|
|
772
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;
|
|
773
782
|
|
|
774
783
|
creativesTemplateData = {
|
|
775
784
|
type: channel,
|
|
776
785
|
edit: true,
|
|
777
786
|
name: creativeName,
|
|
787
|
+
...(includeRootRcsCardVarMapped ? { rcsCardVarMapped: mergedCardVarMapped } : {}),
|
|
778
788
|
versions: {
|
|
779
789
|
base: {
|
|
780
790
|
content: {
|
|
781
791
|
RCS: {
|
|
782
792
|
rcsContent: {
|
|
783
793
|
...rcsContent,
|
|
784
|
-
...(accountId && !isFullMode && { accountId }),
|
|
785
794
|
cardContent: [
|
|
786
795
|
{
|
|
787
796
|
...cardContent,
|
|
797
|
+
...(mergedCardVarMapped ? { cardVarMapped: mergedCardVarMapped } : {}),
|
|
788
798
|
Status,
|
|
789
799
|
},
|
|
790
800
|
],
|
|
@@ -935,7 +945,10 @@ export class Creatives extends React.Component {
|
|
|
935
945
|
return newExpandableDetails;
|
|
936
946
|
}
|
|
937
947
|
|
|
938
|
-
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();
|
|
939
952
|
let templateData = { channel };
|
|
940
953
|
switch (channel) {
|
|
941
954
|
case constants.SMS:
|
|
@@ -1229,7 +1242,7 @@ export class Creatives extends React.Component {
|
|
|
1229
1242
|
};
|
|
1230
1243
|
}
|
|
1231
1244
|
break;
|
|
1232
|
-
case constants.FACEBOOK:
|
|
1245
|
+
case constants.FACEBOOK: {
|
|
1233
1246
|
if (template.value) {
|
|
1234
1247
|
const FacebookAd = template?.value?.versions?.base?.content?.FacebookAd;
|
|
1235
1248
|
const { type } = FacebookAd[0];
|
|
@@ -1273,34 +1286,110 @@ export class Creatives extends React.Component {
|
|
|
1273
1286
|
selectedMarketingObjective: template.value.selectedMarketingObjective,
|
|
1274
1287
|
};
|
|
1275
1288
|
}
|
|
1289
|
+
}
|
|
1276
1290
|
break;
|
|
1277
|
-
case constants.RCS:
|
|
1291
|
+
case constants.RCS: {
|
|
1278
1292
|
if (template.value) {
|
|
1279
|
-
const {
|
|
1280
|
-
} = template.value || {};
|
|
1281
|
-
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 };
|
|
1282
1334
|
const {
|
|
1283
|
-
cardContent = [],
|
|
1335
|
+
cardContent: cardContentFromSubmit = [],
|
|
1284
1336
|
contentType = "",
|
|
1285
1337
|
cardType = "",
|
|
1286
1338
|
cardSettings = {},
|
|
1287
|
-
accountId = "",
|
|
1288
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
|
+
);
|
|
1289
1349
|
const rcsContent = {
|
|
1290
1350
|
contentType,
|
|
1291
1351
|
cardType,
|
|
1292
1352
|
cardSettings,
|
|
1293
1353
|
cardContent,
|
|
1294
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;
|
|
1295
1364
|
templateData = {
|
|
1296
1365
|
channel,
|
|
1297
1366
|
creativeName: name,
|
|
1298
1367
|
rcsContent,
|
|
1299
|
-
|
|
1368
|
+
...(includeRootRcsCardVarMappedOnConsumerPayload
|
|
1369
|
+
? { rcsCardVarMapped: cardVarMappedFromFirstRcsCard }
|
|
1370
|
+
: {}),
|
|
1300
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);
|
|
1301
1389
|
}
|
|
1390
|
+
}
|
|
1302
1391
|
break;
|
|
1303
|
-
case constants.ZALO:
|
|
1392
|
+
case constants.ZALO: {
|
|
1304
1393
|
if (template.value) {
|
|
1305
1394
|
templateData = {
|
|
1306
1395
|
...template.value,
|
|
@@ -1309,6 +1398,7 @@ export class Creatives extends React.Component {
|
|
|
1309
1398
|
delete templateData.type;
|
|
1310
1399
|
}
|
|
1311
1400
|
}
|
|
1401
|
+
}
|
|
1312
1402
|
break;
|
|
1313
1403
|
case constants.WEBPUSH: {
|
|
1314
1404
|
if (template.value) {
|
|
@@ -1415,7 +1505,10 @@ export class Creatives extends React.Component {
|
|
|
1415
1505
|
return templateData;
|
|
1416
1506
|
};
|
|
1417
1507
|
|
|
1418
|
-
getSlideBoxContent({ mode, templateData, isFullMode }) {
|
|
1508
|
+
getSlideBoxContent({ mode, templateData, isFullMode, useLocalTemplates }) {
|
|
1509
|
+
if (useLocalTemplates && mode === 'create' && isEmpty(templateData)) {
|
|
1510
|
+
return 'templates';
|
|
1511
|
+
}
|
|
1419
1512
|
let creativesMode = isFullMode ? 'createTemplate' : 'templates';// for library mode templates page is initial mode and for full mode createTemplates
|
|
1420
1513
|
if (mode === 'create' && isFullMode) {
|
|
1421
1514
|
creativesMode = 'createTemplate';
|
|
@@ -1503,24 +1596,110 @@ export class Creatives extends React.Component {
|
|
|
1503
1596
|
getFormData = (template) => {
|
|
1504
1597
|
// Always reset isGetFormData so the child does not re-send form data on every re-render
|
|
1505
1598
|
// (e.g. when user fixes validation error by typing, we must not auto-close the slidebox)
|
|
1506
|
-
this.setState(
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
{
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
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,
|
|
1517
1686
|
});
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
|
-
|
|
1687
|
+
});
|
|
1688
|
+
},
|
|
1689
|
+
);
|
|
1521
1690
|
}
|
|
1522
1691
|
|
|
1523
|
-
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
|
+
};
|
|
1524
1703
|
// Create the payload for the centralcommnsmetaId API call
|
|
1525
1704
|
const { isLoyaltyModule = false, loyaltyMetaData = {} } = this.props;
|
|
1526
1705
|
const { actionName, setMetaData = () => { } } = loyaltyMetaData;
|
|
@@ -1546,6 +1725,7 @@ export class Creatives extends React.Component {
|
|
|
1546
1725
|
if (result?.status?.code === 200) {
|
|
1547
1726
|
setMetaData(result);
|
|
1548
1727
|
this.props.getCreativesData(creativesData);
|
|
1728
|
+
maybeCloseLibrarySlideBox();
|
|
1549
1729
|
} else {
|
|
1550
1730
|
CapNotification.error({ message: <FormattedMessage {...messages.somethingWentWrong} /> });
|
|
1551
1731
|
}
|
|
@@ -1556,6 +1736,7 @@ export class Creatives extends React.Component {
|
|
|
1556
1736
|
} else {
|
|
1557
1737
|
// If not a loyalty module or different action, should work as usual
|
|
1558
1738
|
this.props.getCreativesData(creativesData);
|
|
1739
|
+
maybeCloseLibrarySlideBox();
|
|
1559
1740
|
}
|
|
1560
1741
|
};
|
|
1561
1742
|
|
|
@@ -1588,7 +1769,9 @@ export class Creatives extends React.Component {
|
|
|
1588
1769
|
}
|
|
1589
1770
|
this.setState((prevState) => ({
|
|
1590
1771
|
...prevState,
|
|
1591
|
-
|
|
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 } : {}),
|
|
1592
1775
|
showSlideBox: false,
|
|
1593
1776
|
liquidErrorMessage: { STANDARD_ERROR_MSG: [], LIQUID_ERROR_MSG: [] },
|
|
1594
1777
|
isLiquidValidationError: false,
|
|
@@ -1799,21 +1982,12 @@ export class Creatives extends React.Component {
|
|
|
1799
1982
|
}
|
|
1800
1983
|
|
|
1801
1984
|
showLiquidErrorInFooter = (errorMessagesFromFormBuilder, currentFormBuilderTab) => {
|
|
1802
|
-
const
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
const hasStandard = !isDeepEmpty(standardMsgs);
|
|
1806
|
-
const isLiquidValidationError = hasLiquid || hasStandard;
|
|
1807
|
-
// Don't overwrite existing liquid error with empty only for Mobile Push OLD (FormBuilder/clear calls empty there); SMS/others clear on input change
|
|
1808
|
-
const isMobilePush = this.state.currentChannel?.toUpperCase() === constants.MOBILE_PUSH;
|
|
1809
|
-
if (!hasLiquid && !hasStandard && this.state.isLiquidValidationError && isMobilePush) {
|
|
1810
|
-
return;
|
|
1811
|
-
}
|
|
1812
|
-
this.setState({
|
|
1813
|
-
isLiquidValidationError,
|
|
1814
|
-
liquidErrorMessage: errorMessagesFromFormBuilder,
|
|
1815
|
-
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(),
|
|
1816
1988
|
});
|
|
1989
|
+
if (next == null) return;
|
|
1990
|
+
this.setState(next);
|
|
1817
1991
|
}
|
|
1818
1992
|
|
|
1819
1993
|
// Callback to update HTML Editor validation state (called from EmailWrapper)
|
|
@@ -1936,6 +2110,11 @@ export class Creatives extends React.Component {
|
|
|
1936
2110
|
inAppEditorType,
|
|
1937
2111
|
htmlEditorValidationState,
|
|
1938
2112
|
} = this.state;
|
|
2113
|
+
const useLocalTemplates = get(
|
|
2114
|
+
this.props,
|
|
2115
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
2116
|
+
get(this.props, 'useLocalTemplates', false),
|
|
2117
|
+
);
|
|
1939
2118
|
const {
|
|
1940
2119
|
isFullMode,
|
|
1941
2120
|
creativesMode,
|
|
@@ -1954,7 +2133,6 @@ export class Creatives extends React.Component {
|
|
|
1954
2133
|
smsRegister,
|
|
1955
2134
|
enableNewChannels,
|
|
1956
2135
|
eventContextTags,
|
|
1957
|
-
waitEventContextTags = {},
|
|
1958
2136
|
isLoyaltyModule,
|
|
1959
2137
|
loyaltyMetaData = {},
|
|
1960
2138
|
} = this.props;
|
|
@@ -1988,14 +2166,7 @@ export class Creatives extends React.Component {
|
|
|
1988
2166
|
// IMPORTANT: Never show ErrorInfoNote in footer when in HTML Editor mode, even if liquidErrorMessage exists
|
|
1989
2167
|
const shouldShowErrorInfoNoteInFooter = isHTMLEditorMode ? false : hasBEEEditorErrors;
|
|
1990
2168
|
|
|
1991
|
-
|
|
1992
|
-
const slideBoxWrapperMargin = (get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0 && get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0)
|
|
1993
|
-
? CAP_SPACE_64
|
|
1994
|
-
: get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0
|
|
1995
|
-
? CAP_SPACE_56
|
|
1996
|
-
: get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0
|
|
1997
|
-
? CAP_SPACE_32
|
|
1998
|
-
: 0;
|
|
2169
|
+
const slideBoxWrapperMargin = getSlideBoxWrapperMarginFromLiquidErrors(liquidErrorMessage);
|
|
1999
2170
|
/* TODO: Instead of passing down same props separately to each component down, write common function to these props and pass it accordingly */
|
|
2000
2171
|
|
|
2001
2172
|
// Compute anonymous user type and channel restrictions
|
|
@@ -2024,7 +2195,10 @@ export class Creatives extends React.Component {
|
|
|
2024
2195
|
<SlideBoxWrapper
|
|
2025
2196
|
slideBoxWrapperMargin={slideBoxWrapperMargin}
|
|
2026
2197
|
shouldApplyFooterMargin={shouldShowErrorInfoNoteInFooter}
|
|
2027
|
-
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
|
+
)}
|
|
2028
2202
|
>
|
|
2029
2203
|
<CapSlideBox
|
|
2030
2204
|
header={
|
|
@@ -2049,12 +2223,13 @@ export class Creatives extends React.Component {
|
|
|
2049
2223
|
smsRegister={smsRegister}
|
|
2050
2224
|
handleClose={this.handleCloseSlideBox}
|
|
2051
2225
|
moduleType={this.props.messageDetails?.type}
|
|
2226
|
+
useLocalTemplates={useLocalTemplates}
|
|
2052
2227
|
/>
|
|
2053
2228
|
)}
|
|
2054
2229
|
content={(
|
|
2055
2230
|
<SlideBoxContent
|
|
2056
2231
|
key="creatives-container-slidebox-content"
|
|
2057
|
-
onSelectTemplate={this.onSelectTemplate}
|
|
2232
|
+
onSelectTemplate={this.props.onSelectTemplate != null ? this.props.onSelectTemplate : this.onSelectTemplate}
|
|
2058
2233
|
onCreateComplete={getCreativesData}
|
|
2059
2234
|
onPreviewTemplate={this.onPreviewTemplate}
|
|
2060
2235
|
slidBoxContent={slidBoxContent}
|
|
@@ -2122,7 +2297,6 @@ export class Creatives extends React.Component {
|
|
|
2122
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.
|
|
2123
2298
|
hostName={this.props?.hostName || ''}
|
|
2124
2299
|
eventContextTags={eventContextTags}
|
|
2125
|
-
waitEventContextTags={waitEventContextTags}
|
|
2126
2300
|
isLoyaltyModule={isLoyaltyModule}
|
|
2127
2301
|
loyaltyMetaData={loyaltyMetaData}
|
|
2128
2302
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
@@ -2131,7 +2305,8 @@ export class Creatives extends React.Component {
|
|
|
2131
2305
|
isTestAndPreviewMode={(() => this.state.isTestAndPreviewMode)()}
|
|
2132
2306
|
onHtmlEditorValidationStateChange={this.updateHtmlEditorValidationState}
|
|
2133
2307
|
onPersonalizationTokensChange={this.handlePersonalizationTokensChange}
|
|
2134
|
-
|
|
2308
|
+
localTemplatesConfig={pick(this.props.localTemplatesConfig || this.props, constants.LOCAL_TEMPLATE_CONFIG_KEYS)}
|
|
2309
|
+
/>
|
|
2135
2310
|
)}
|
|
2136
2311
|
footer={this.shouldShowFooter() ? (
|
|
2137
2312
|
<SlideBoxFooter
|
|
@@ -2140,7 +2315,6 @@ export class Creatives extends React.Component {
|
|
|
2140
2315
|
onSave={this.saveMessage}
|
|
2141
2316
|
onDiscard={this.discardMessage}
|
|
2142
2317
|
onEditTemplate={this.onEditTemplate}
|
|
2143
|
-
isTemplateArchived={!!(this.props.templateData && this.props.templateData.isArchived)}
|
|
2144
2318
|
slidBoxContent={slidBoxContent}
|
|
2145
2319
|
onCreateNextStep={this.onCreateNextStep}
|
|
2146
2320
|
currentChannel={currentChannel.toUpperCase()}
|
|
@@ -2216,13 +2390,31 @@ Creatives.propTypes = {
|
|
|
2216
2390
|
orgUnitId: PropTypes.number,
|
|
2217
2391
|
hostName: PropTypes.string,
|
|
2218
2392
|
eventContextTags: PropTypes.array,
|
|
2219
|
-
waitEventContextTags: PropTypes.object,
|
|
2220
2393
|
loyaltyTagFetchingDependencies: PropTypes.object,
|
|
2221
2394
|
customerType: PropTypes.string,
|
|
2222
2395
|
intl: PropTypes.shape({
|
|
2223
2396
|
formatMessage: PropTypes.func,
|
|
2224
2397
|
}),
|
|
2225
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,
|
|
2226
2418
|
};
|
|
2227
2419
|
const mapStatesToProps = () => createStructuredSelector({
|
|
2228
2420
|
isLoading: isLoadingSelector(),
|