@capillarytech/creatives-library 8.0.353-alpha.5 → 8.0.353-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/constants/unified.js +29 -0
- package/package.json +1 -1
- package/services/tests/api.test.js +35 -20
- package/utils/commonUtils.js +19 -1
- package/utils/rcsPayloadUtils.js +92 -0
- package/utils/templateVarUtils.js +201 -0
- package/utils/tests/rcsPayloadUtils.test.js +226 -0
- package/utils/tests/templateVarUtils.test.js +204 -0
- package/v2Components/CapActionButton/constants.js +7 -0
- package/v2Components/CapActionButton/index.js +166 -108
- package/v2Components/CapActionButton/index.scss +157 -6
- package/v2Components/CapActionButton/messages.js +19 -3
- package/v2Components/CapActionButton/tests/index.test.js +41 -17
- package/v2Components/CapTagList/index.js +10 -0
- package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +72 -49
- package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +8 -2
- package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +213 -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/PreviewHeader.js +0 -17
- package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +157 -15
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +346 -146
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +138 -48
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +11 -0
- package/v2Components/CommonTestAndPreview/constants.js +38 -4
- package/v2Components/CommonTestAndPreview/index.js +691 -235
- package/v2Components/CommonTestAndPreview/messages.js +45 -3
- package/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
- package/v2Components/CommonTestAndPreview/sagas.js +25 -6
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +308 -284
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +231 -65
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +118 -5
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +341 -0
- package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +8 -1
- package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +34 -13
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/PreviewHeader.test.js +0 -159
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +281 -283
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +199 -256
- package/v2Components/CommonTestAndPreview/tests/constants.test.js +1 -2
- package/v2Components/CommonTestAndPreview/tests/index.test.js +132 -198
- package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +36 -26
- package/v2Components/FormBuilder/index.js +11 -6
- package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +91 -0
- package/v2Components/SmsFallback/constants.js +73 -0
- package/v2Components/SmsFallback/index.js +956 -0
- package/v2Components/SmsFallback/index.scss +265 -0
- package/v2Components/SmsFallback/messages.js +78 -0
- package/v2Components/SmsFallback/smsFallbackUtils.js +119 -0
- package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +50 -0
- package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +147 -0
- package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +304 -0
- package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +223 -0
- package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +309 -0
- package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +422 -0
- package/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
- package/v2Components/TemplatePreview/_templatePreview.scss +38 -23
- package/v2Components/TemplatePreview/constants.js +2 -0
- package/v2Components/TemplatePreview/index.js +143 -31
- package/v2Components/TemplatePreview/tests/index.test.js +142 -0
- package/v2Components/TestAndPreviewSlidebox/index.js +15 -3
- 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/App/constants.js +0 -3
- package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +43 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +36 -4
- 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 +79 -0
- package/v2Containers/CreativesContainer/index.js +322 -103
- 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/MobilePush/Create/test/saga.test.js +2 -2
- package/v2Containers/Rcs/constants.js +119 -10
- package/v2Containers/Rcs/index.js +2445 -813
- package/v2Containers/Rcs/index.scss +280 -8
- package/v2Containers/Rcs/messages.js +34 -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/index.test.js +152 -121
- package/v2Containers/Rcs/tests/mockData.js +38 -0
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +318 -0
- package/v2Containers/Rcs/tests/utils.test.js +646 -30
- package/v2Containers/Rcs/utils.js +478 -11
- package/v2Containers/Sms/Create/index.js +106 -40
- package/v2Containers/Sms/smsFormDataHelpers.js +67 -0
- package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +253 -0
- package/v2Containers/SmsTrai/Create/index.js +9 -4
- package/v2Containers/SmsTrai/Edit/constants.js +2 -0
- package/v2Containers/SmsTrai/Edit/index.js +640 -130
- package/v2Containers/SmsTrai/Edit/index.scss +121 -0
- package/v2Containers/SmsTrai/Edit/messages.js +14 -4
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4328 -2375
- package/v2Containers/SmsWrapper/index.js +37 -8
- package/v2Containers/TagList/index.js +6 -0
- package/v2Containers/Templates/TemplatesActionBar.js +101 -0
- package/v2Containers/Templates/_templates.scss +166 -9
- package/v2Containers/Templates/actions.js +11 -0
- package/v2Containers/Templates/constants.js +2 -0
- package/v2Containers/Templates/index.js +122 -120
- package/v2Containers/Templates/sagas.js +56 -12
- package/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1062 -1017
- package/v2Containers/Templates/tests/sagas.test.js +199 -16
- package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +180 -0
- package/v2Containers/Templates/utils/smsTemplatesListApi.js +79 -0
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +72 -1
- package/v2Containers/TemplatesV2/index.js +86 -23
- package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +131 -0
- package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
- package/v2Containers/WebPush/Create/index.js +8 -91
- package/v2Containers/WebPush/Create/index.scss +0 -7
- package/v2Containers/Whatsapp/index.js +3 -20
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +578 -34
- package/v2Components/CommonTestAndPreview/UnifiedPreview/WebPushPreviewContent.js +0 -169
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/WebPushPreviewContent.test.js +0 -522
- package/v2Containers/App/tests/constants.test.js +0 -61
- package/v2Containers/Templates/tests/webpush.test.js +0 -375
- package/v2Containers/WebPush/Create/tests/getTemplateContent.test.js +0 -338
- package/v2Containers/WebPush/Create/tests/testAndPreviewIntegration.test.js +0 -325
|
@@ -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();
|
|
@@ -768,15 +751,69 @@ export class Creatives extends React.Component {
|
|
|
768
751
|
smsFallBackContent = {},
|
|
769
752
|
creativeName = "",
|
|
770
753
|
channel = constants.RCS,
|
|
754
|
+
rcsCardVarMapped,
|
|
771
755
|
accountId = "",
|
|
772
756
|
} = templateData || {};
|
|
773
|
-
const
|
|
757
|
+
const { isFullMode: isFullModeForRcsPayload } = this.props;
|
|
758
|
+
const isCarouselRcs = (rcsContent?.cardType || '').toString().toLowerCase() === 'carousel';
|
|
759
|
+
const firstCardIn = (rcsContent.cardContent && rcsContent.cardContent[0]) || {};
|
|
760
|
+
const {
|
|
761
|
+
cardDisplayTitle: _omitDispTitleIn,
|
|
762
|
+
cardDisplayDescription: _omitDispDescIn,
|
|
763
|
+
...cardContent
|
|
764
|
+
} = firstCardIn;
|
|
774
765
|
const Status = RCS_STATUSES.approved || '';
|
|
766
|
+
const mergedCardVarMapped = (() => {
|
|
767
|
+
const nestedCardVarMapped = cardContent?.cardVarMapped;
|
|
768
|
+
const rootMirrorCardVarMapped = rcsCardVarMapped;
|
|
769
|
+
const nestedRecord =
|
|
770
|
+
nestedCardVarMapped != null && typeof nestedCardVarMapped === 'object'
|
|
771
|
+
? nestedCardVarMapped
|
|
772
|
+
: {};
|
|
773
|
+
const rootRecord =
|
|
774
|
+
rootMirrorCardVarMapped != null && typeof rootMirrorCardVarMapped === 'object'
|
|
775
|
+
? rootMirrorCardVarMapped
|
|
776
|
+
: {};
|
|
777
|
+
const mergedFromRootAndNested = {
|
|
778
|
+
...pickRcsCardVarMappedEntries(rootRecord),
|
|
779
|
+
...pickRcsCardVarMappedEntries(nestedRecord),
|
|
780
|
+
};
|
|
781
|
+
return Object.keys(mergedFromRootAndNested).length > 0
|
|
782
|
+
? mergedFromRootAndNested
|
|
783
|
+
: null;
|
|
784
|
+
})();
|
|
785
|
+
// Campaigns (embedded): do not duplicate `cardVarMapped` as root `rcsCardVarMapped` on send —
|
|
786
|
+
// slot map stays on `versions…cardContent[0].cardVarMapped` only. Library full mode keeps root mirror.
|
|
787
|
+
// Use `=== true` so omitted/undefined `isFullMode` does not behave like library (avoids duplicate on approval payload).
|
|
788
|
+
const includeRootRcsCardVarMapped =
|
|
789
|
+
mergedCardVarMapped && isFullModeForRcsPayload === true;
|
|
790
|
+
|
|
791
|
+
const builtCardContent = isCarouselRcs
|
|
792
|
+
? (rcsContent.cardContent || []).map((card, idx) => {
|
|
793
|
+
const {
|
|
794
|
+
cardDisplayTitle: _dt,
|
|
795
|
+
cardDisplayDescription: _dd,
|
|
796
|
+
...restCard
|
|
797
|
+
} = card || {};
|
|
798
|
+
return {
|
|
799
|
+
...restCard,
|
|
800
|
+
...(idx === 0 && mergedCardVarMapped ? { cardVarMapped: mergedCardVarMapped } : {}),
|
|
801
|
+
Status,
|
|
802
|
+
};
|
|
803
|
+
})
|
|
804
|
+
: [
|
|
805
|
+
{
|
|
806
|
+
...cardContent,
|
|
807
|
+
...(mergedCardVarMapped ? { cardVarMapped: mergedCardVarMapped } : {}),
|
|
808
|
+
Status,
|
|
809
|
+
},
|
|
810
|
+
];
|
|
775
811
|
|
|
776
812
|
creativesTemplateData = {
|
|
777
813
|
type: channel,
|
|
778
814
|
edit: true,
|
|
779
815
|
name: creativeName,
|
|
816
|
+
...(includeRootRcsCardVarMapped ? { rcsCardVarMapped: mergedCardVarMapped } : {}),
|
|
780
817
|
versions: {
|
|
781
818
|
base: {
|
|
782
819
|
content: {
|
|
@@ -784,12 +821,7 @@ export class Creatives extends React.Component {
|
|
|
784
821
|
rcsContent: {
|
|
785
822
|
...rcsContent,
|
|
786
823
|
...(accountId && !isFullMode && { accountId }),
|
|
787
|
-
cardContent:
|
|
788
|
-
{
|
|
789
|
-
...cardContent,
|
|
790
|
-
Status,
|
|
791
|
-
},
|
|
792
|
-
],
|
|
824
|
+
cardContent: builtCardContent,
|
|
793
825
|
},
|
|
794
826
|
smsFallBackContent,
|
|
795
827
|
},
|
|
@@ -937,7 +969,10 @@ export class Creatives extends React.Component {
|
|
|
937
969
|
return newExpandableDetails;
|
|
938
970
|
}
|
|
939
971
|
|
|
940
|
-
getCreativesData = async (
|
|
972
|
+
getCreativesData = async (channelParam, template, templateRecords) => { //from creatives to consumers
|
|
973
|
+
const channel = String(
|
|
974
|
+
channelParam || template?.type || get(template, 'value.type') || '',
|
|
975
|
+
).toUpperCase();
|
|
941
976
|
let templateData = { channel };
|
|
942
977
|
switch (channel) {
|
|
943
978
|
case constants.SMS:
|
|
@@ -1284,28 +1319,104 @@ export class Creatives extends React.Component {
|
|
|
1284
1319
|
break;
|
|
1285
1320
|
case constants.RCS:
|
|
1286
1321
|
if (template.value) {
|
|
1287
|
-
const {
|
|
1288
|
-
} = template.value || {};
|
|
1289
|
-
const
|
|
1322
|
+
const { isFullMode: isFullModeForRcsConsumerPayload } = this.props;
|
|
1323
|
+
const { name = "", versions = {} } = template.value || {};
|
|
1324
|
+
const fromSubmit = get(versions, 'base.content.RCS.smsFallBackContent', {});
|
|
1325
|
+
const fromRecords = {
|
|
1326
|
+
...(templateRecords?.smsFallBackContent || {}),
|
|
1327
|
+
...(get(templateRecords, 'versions.base.content.RCS.smsFallBackContent') || {}),
|
|
1328
|
+
};
|
|
1329
|
+
const hasMeaningfulRcsSmsFallback = (smsFallbackPayload) => {
|
|
1330
|
+
if (
|
|
1331
|
+
!smsFallbackPayload
|
|
1332
|
+
|| typeof smsFallbackPayload !== 'object'
|
|
1333
|
+
|| Object.keys(smsFallbackPayload).length === 0
|
|
1334
|
+
) {
|
|
1335
|
+
return false;
|
|
1336
|
+
}
|
|
1337
|
+
const fallbackBodyText = String(
|
|
1338
|
+
smsFallbackPayload.smsContent
|
|
1339
|
+
?? smsFallbackPayload.smsTemplateContent
|
|
1340
|
+
?? smsFallbackPayload.message
|
|
1341
|
+
?? smsFallbackPayload.content
|
|
1342
|
+
?? '',
|
|
1343
|
+
).trim();
|
|
1344
|
+
const fallbackTemplateName = String(
|
|
1345
|
+
smsFallbackPayload.smsTemplateName ?? smsFallbackPayload.templateName ?? '',
|
|
1346
|
+
).trim();
|
|
1347
|
+
const rcsSmsFallbackVarMapped =
|
|
1348
|
+
smsFallbackPayload?.[RCS_SMS_FALLBACK_VAR_MAPPED_PROP];
|
|
1349
|
+
const hasVarMappedEntries =
|
|
1350
|
+
rcsSmsFallbackVarMapped != null
|
|
1351
|
+
&& typeof rcsSmsFallbackVarMapped === 'object'
|
|
1352
|
+
&& Object.keys(rcsSmsFallbackVarMapped).length > 0;
|
|
1353
|
+
return (
|
|
1354
|
+
fallbackBodyText !== ''
|
|
1355
|
+
|| fallbackTemplateName !== ''
|
|
1356
|
+
|| hasVarMappedEntries
|
|
1357
|
+
);
|
|
1358
|
+
};
|
|
1359
|
+
// If submit has only empty strings, do not let it wipe fallback mirrored on templateRecords (library round-trip).
|
|
1360
|
+
const smsFallBackContent = hasMeaningfulRcsSmsFallback(fromSubmit)
|
|
1361
|
+
? { ...fromRecords, ...fromSubmit }
|
|
1362
|
+
: { ...fromSubmit, ...fromRecords };
|
|
1290
1363
|
const {
|
|
1291
|
-
cardContent = [],
|
|
1364
|
+
cardContent: cardContentFromSubmit = [],
|
|
1292
1365
|
contentType = "",
|
|
1293
1366
|
cardType = "",
|
|
1294
1367
|
cardSettings = {},
|
|
1295
1368
|
accountId = "",
|
|
1296
1369
|
} = get(versions, 'base.content.RCS.rcsContent', {});
|
|
1370
|
+
const rootRcsCardVarMappedFromSubmit = get(template, 'value.rcsCardVarMapped');
|
|
1371
|
+
const firstCardFromSubmit = Array.isArray(cardContentFromSubmit)
|
|
1372
|
+
? cardContentFromSubmit[0]
|
|
1373
|
+
: null;
|
|
1374
|
+
const cardContent = mapRcsCardContentForConsumerWithResolvedTags(
|
|
1375
|
+
cardContentFromSubmit,
|
|
1376
|
+
rootRcsCardVarMappedFromSubmit,
|
|
1377
|
+
isFullModeForRcsConsumerPayload,
|
|
1378
|
+
);
|
|
1297
1379
|
const rcsContent = {
|
|
1298
1380
|
contentType,
|
|
1299
1381
|
cardType,
|
|
1300
1382
|
cardSettings,
|
|
1301
1383
|
cardContent,
|
|
1302
1384
|
};
|
|
1385
|
+
const cardVarMappedFromFirstRcsCard =
|
|
1386
|
+
firstCardFromSubmit?.cardVarMapped != null
|
|
1387
|
+
&& typeof firstCardFromSubmit.cardVarMapped === 'object'
|
|
1388
|
+
? pickRcsCardVarMappedEntries(firstCardFromSubmit.cardVarMapped)
|
|
1389
|
+
: null;
|
|
1390
|
+
const includeRootRcsCardVarMappedOnConsumerPayload =
|
|
1391
|
+
cardVarMappedFromFirstRcsCard
|
|
1392
|
+
&& Object.keys(cardVarMappedFromFirstRcsCard).length > 0
|
|
1393
|
+
&& isFullModeForRcsConsumerPayload === true;
|
|
1303
1394
|
templateData = {
|
|
1304
1395
|
channel,
|
|
1305
1396
|
creativeName: name,
|
|
1306
1397
|
rcsContent,
|
|
1307
1398
|
accountId,
|
|
1399
|
+
...(includeRootRcsCardVarMappedOnConsumerPayload
|
|
1400
|
+
? { rcsCardVarMapped: cardVarMappedFromFirstRcsCard }
|
|
1401
|
+
: {}),
|
|
1308
1402
|
};
|
|
1403
|
+
// Library / campaign consumers round-trip templateData via getTemplateData; include SMS fallback
|
|
1404
|
+
// so reopening the editor restores fallback text and tag mappings.
|
|
1405
|
+
// cap-campaigns-v2 API expects `smsFallBackContent.message` (see normalizeRcsMessageContentForApi).
|
|
1406
|
+
if (hasMeaningfulRcsSmsFallback(smsFallBackContent)) {
|
|
1407
|
+
const smsText =
|
|
1408
|
+
smsFallBackContent.message
|
|
1409
|
+
?? smsFallBackContent.smsContent
|
|
1410
|
+
?? smsFallBackContent.smsTemplateContent
|
|
1411
|
+
?? '';
|
|
1412
|
+
templateData.smsFallBackContent = {
|
|
1413
|
+
...smsFallBackContent,
|
|
1414
|
+
...(String(smsText).trim() !== ''
|
|
1415
|
+
? { message: String(smsText).trim() }
|
|
1416
|
+
: {}),
|
|
1417
|
+
};
|
|
1418
|
+
}
|
|
1419
|
+
normalizeRcsMessageContentForApi(templateData);
|
|
1309
1420
|
}
|
|
1310
1421
|
break;
|
|
1311
1422
|
case constants.ZALO:
|
|
@@ -1423,7 +1534,10 @@ export class Creatives extends React.Component {
|
|
|
1423
1534
|
return templateData;
|
|
1424
1535
|
};
|
|
1425
1536
|
|
|
1426
|
-
getSlideBoxContent({ mode, templateData, isFullMode }) {
|
|
1537
|
+
getSlideBoxContent({ mode, templateData, isFullMode, useLocalTemplates }) {
|
|
1538
|
+
if (useLocalTemplates && mode === 'create' && isEmpty(templateData)) {
|
|
1539
|
+
return 'templates';
|
|
1540
|
+
}
|
|
1427
1541
|
let creativesMode = isFullMode ? 'createTemplate' : 'templates';// for library mode templates page is initial mode and for full mode createTemplates
|
|
1428
1542
|
if (mode === 'create' && isFullMode) {
|
|
1429
1543
|
creativesMode = 'createTemplate';
|
|
@@ -1511,24 +1625,110 @@ export class Creatives extends React.Component {
|
|
|
1511
1625
|
getFormData = (template) => {
|
|
1512
1626
|
// Always reset isGetFormData so the child does not re-send form data on every re-render
|
|
1513
1627
|
// (e.g. when user fixes validation error by typing, we must not auto-close the slidebox)
|
|
1514
|
-
this.setState(
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
{
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1628
|
+
this.setState(
|
|
1629
|
+
(prevState) => {
|
|
1630
|
+
const next = { isGetFormData: false };
|
|
1631
|
+
if (!template.validity) {
|
|
1632
|
+
return next;
|
|
1633
|
+
}
|
|
1634
|
+
const baseTd = prevState.templateData || template;
|
|
1635
|
+
const channel = (
|
|
1636
|
+
baseTd?.type
|
|
1637
|
+
|| template?.type
|
|
1638
|
+
|| get(template, 'value.type')
|
|
1639
|
+
|| ''
|
|
1640
|
+
).toUpperCase();
|
|
1641
|
+
// Library mode: persist last submitted creatives shape so reopening still hydrates the editor
|
|
1642
|
+
// (parent may not merge getCreativesData back into templateData).
|
|
1643
|
+
if (this.props.isFullMode === false && template.value) {
|
|
1644
|
+
if (channel === constants.RCS) {
|
|
1645
|
+
const smsFallBackFromPayload = get(
|
|
1646
|
+
template.value,
|
|
1647
|
+
'versions.base.content.RCS.smsFallBackContent',
|
|
1648
|
+
);
|
|
1649
|
+
const rcsCardVarMappedFromPayload = get(
|
|
1650
|
+
template.value,
|
|
1651
|
+
'versions.base.content.RCS.rcsContent.cardContent[0].cardVarMapped',
|
|
1652
|
+
);
|
|
1653
|
+
next.templateData = {
|
|
1654
|
+
...baseTd,
|
|
1655
|
+
type: constants.RCS,
|
|
1656
|
+
name: template?.value?.name,
|
|
1657
|
+
versions: template?.value?.versions,
|
|
1658
|
+
...(smsFallBackFromPayload != null
|
|
1659
|
+
&& typeof smsFallBackFromPayload === 'object'
|
|
1660
|
+
&& Object.keys(smsFallBackFromPayload).length > 0
|
|
1661
|
+
? { smsFallBackContent: smsFallBackFromPayload }
|
|
1662
|
+
: {}),
|
|
1663
|
+
...(rcsCardVarMappedFromPayload != null
|
|
1664
|
+
&& typeof rcsCardVarMappedFromPayload === 'object'
|
|
1665
|
+
? { rcsCardVarMapped: rcsCardVarMappedFromPayload }
|
|
1666
|
+
: {}),
|
|
1667
|
+
};
|
|
1668
|
+
if (template._id) {
|
|
1669
|
+
next.templateData._id = template._id;
|
|
1670
|
+
}
|
|
1671
|
+
} else if (channel === constants.SMS) {
|
|
1672
|
+
const submittedSmsTemplateValue = template?.value;
|
|
1673
|
+
const smsVersions =
|
|
1674
|
+
submittedSmsTemplateValue?.history != null
|
|
1675
|
+
? submittedSmsTemplateValue
|
|
1676
|
+
: {
|
|
1677
|
+
base: submittedSmsTemplateValue?.base,
|
|
1678
|
+
history: submittedSmsTemplateValue?.base
|
|
1679
|
+
? [submittedSmsTemplateValue.base]
|
|
1680
|
+
: [],
|
|
1681
|
+
};
|
|
1682
|
+
next.templateData = {
|
|
1683
|
+
...baseTd,
|
|
1684
|
+
type: constants.SMS,
|
|
1685
|
+
name: baseTd?.name || 'Campaign message SMS content',
|
|
1686
|
+
versions: smsVersions,
|
|
1687
|
+
};
|
|
1688
|
+
if (template?._id) {
|
|
1689
|
+
next.templateData._id = template._id;
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
return next;
|
|
1694
|
+
},
|
|
1695
|
+
() => {
|
|
1696
|
+
if (!template.validity) {
|
|
1697
|
+
return;
|
|
1698
|
+
}
|
|
1699
|
+
const templateData = this.state.templateData ? this.state.templateData : template; //select existing or create new content
|
|
1700
|
+
const channelForConsumer = String(
|
|
1701
|
+
templateData.type
|
|
1702
|
+
|| template.type
|
|
1703
|
+
|| get(template, 'value.type')
|
|
1704
|
+
|| '',
|
|
1705
|
+
).toUpperCase();
|
|
1706
|
+
const creativesData = this.getCreativesData(
|
|
1707
|
+
channelForConsumer,
|
|
1708
|
+
template,
|
|
1709
|
+
this.state.templateData || template,
|
|
1710
|
+
);// convers data to consumer understandable format
|
|
1711
|
+
creativesData.then((data) => {
|
|
1712
|
+
this.logGTMEvent(channelForConsumer, data);
|
|
1713
|
+
this.processCentralCommsMetaId(channelForConsumer, data, {
|
|
1714
|
+
closeSlideBoxAfterSubmit: template.closeSlideBoxAfterSubmit,
|
|
1525
1715
|
});
|
|
1526
|
-
}
|
|
1527
|
-
|
|
1528
|
-
|
|
1716
|
+
});
|
|
1717
|
+
},
|
|
1718
|
+
);
|
|
1529
1719
|
}
|
|
1530
1720
|
|
|
1531
|
-
processCentralCommsMetaId = (channel, creativesData) => {
|
|
1721
|
+
processCentralCommsMetaId = (channel, creativesData, options = {}) => {
|
|
1722
|
+
const { closeSlideBoxAfterSubmit = false } = options;
|
|
1723
|
+
const maybeCloseLibrarySlideBox = () => {
|
|
1724
|
+
if (
|
|
1725
|
+
closeSlideBoxAfterSubmit
|
|
1726
|
+
&& this.props.isFullMode === false
|
|
1727
|
+
&& typeof this.handleCloseSlideBox === 'function'
|
|
1728
|
+
) {
|
|
1729
|
+
this.handleCloseSlideBox();
|
|
1730
|
+
}
|
|
1731
|
+
};
|
|
1532
1732
|
// Create the payload for the centralcommnsmetaId API call
|
|
1533
1733
|
const { isLoyaltyModule = false, loyaltyMetaData = {} } = this.props;
|
|
1534
1734
|
const { actionName, setMetaData = () => { } } = loyaltyMetaData;
|
|
@@ -1554,6 +1754,7 @@ export class Creatives extends React.Component {
|
|
|
1554
1754
|
if (result?.status?.code === 200) {
|
|
1555
1755
|
setMetaData(result);
|
|
1556
1756
|
this.props.getCreativesData(creativesData);
|
|
1757
|
+
maybeCloseLibrarySlideBox();
|
|
1557
1758
|
} else {
|
|
1558
1759
|
CapNotification.error({ message: <FormattedMessage {...messages.somethingWentWrong} /> });
|
|
1559
1760
|
}
|
|
@@ -1564,6 +1765,7 @@ export class Creatives extends React.Component {
|
|
|
1564
1765
|
} else {
|
|
1565
1766
|
// If not a loyalty module or different action, should work as usual
|
|
1566
1767
|
this.props.getCreativesData(creativesData);
|
|
1768
|
+
maybeCloseLibrarySlideBox();
|
|
1567
1769
|
}
|
|
1568
1770
|
};
|
|
1569
1771
|
|
|
@@ -1596,7 +1798,9 @@ export class Creatives extends React.Component {
|
|
|
1596
1798
|
}
|
|
1597
1799
|
this.setState((prevState) => ({
|
|
1598
1800
|
...prevState,
|
|
1599
|
-
|
|
1801
|
+
// Library mode (isFullMode === false): retain last template so reopening still has RCS payload.
|
|
1802
|
+
// Undefined isFullMode defaults to full-mode close behavior (clear templateData).
|
|
1803
|
+
...(this.props.isFullMode !== false ? { templateData: undefined } : {}),
|
|
1600
1804
|
showSlideBox: false,
|
|
1601
1805
|
liquidErrorMessage: { STANDARD_ERROR_MSG: [], LIQUID_ERROR_MSG: [] },
|
|
1602
1806
|
isLiquidValidationError: false,
|
|
@@ -1807,21 +2011,17 @@ export class Creatives extends React.Component {
|
|
|
1807
2011
|
}
|
|
1808
2012
|
|
|
1809
2013
|
showLiquidErrorInFooter = (errorMessagesFromFormBuilder, currentFormBuilderTab) => {
|
|
1810
|
-
const
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
this.setState(
|
|
1821
|
-
isLiquidValidationError,
|
|
1822
|
-
liquidErrorMessage: errorMessagesFromFormBuilder,
|
|
1823
|
-
activeFormBuilderTab: currentFormBuilderTab === 1 ? constants.ANDROID : (currentFormBuilderTab === 2 ? constants.IOS : null), // Update activeFormBuilderTab, default to 1 if undefined
|
|
1824
|
-
});
|
|
2014
|
+
const next = computeLiquidFooterUpdateFromFormBuilder(
|
|
2015
|
+
errorMessagesFromFormBuilder,
|
|
2016
|
+
this.state.liquidErrorMessage,
|
|
2017
|
+
currentFormBuilderTab,
|
|
2018
|
+
{
|
|
2019
|
+
previousIsLiquidValidationError: this.state.isLiquidValidationError,
|
|
2020
|
+
currentChannelUpper: this.state.currentChannel?.toUpperCase(),
|
|
2021
|
+
},
|
|
2022
|
+
);
|
|
2023
|
+
if (next == null) return;
|
|
2024
|
+
this.setState(next);
|
|
1825
2025
|
}
|
|
1826
2026
|
|
|
1827
2027
|
// Callback to update HTML Editor validation state (called from EmailWrapper)
|
|
@@ -1944,6 +2144,11 @@ export class Creatives extends React.Component {
|
|
|
1944
2144
|
inAppEditorType,
|
|
1945
2145
|
htmlEditorValidationState,
|
|
1946
2146
|
} = this.state;
|
|
2147
|
+
const useLocalTemplates = get(
|
|
2148
|
+
this.props,
|
|
2149
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
2150
|
+
get(this.props, 'useLocalTemplates', false),
|
|
2151
|
+
);
|
|
1947
2152
|
const {
|
|
1948
2153
|
isFullMode,
|
|
1949
2154
|
creativesMode,
|
|
@@ -1962,7 +2167,6 @@ export class Creatives extends React.Component {
|
|
|
1962
2167
|
smsRegister,
|
|
1963
2168
|
enableNewChannels,
|
|
1964
2169
|
eventContextTags,
|
|
1965
|
-
waitEventContextTags = {},
|
|
1966
2170
|
isLoyaltyModule,
|
|
1967
2171
|
loyaltyMetaData = {},
|
|
1968
2172
|
} = this.props;
|
|
@@ -1996,14 +2200,7 @@ export class Creatives extends React.Component {
|
|
|
1996
2200
|
// IMPORTANT: Never show ErrorInfoNote in footer when in HTML Editor mode, even if liquidErrorMessage exists
|
|
1997
2201
|
const shouldShowErrorInfoNoteInFooter = isHTMLEditorMode ? false : hasBEEEditorErrors;
|
|
1998
2202
|
|
|
1999
|
-
|
|
2000
|
-
const slideBoxWrapperMargin = (get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0 && get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0)
|
|
2001
|
-
? CAP_SPACE_64
|
|
2002
|
-
: get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0
|
|
2003
|
-
? CAP_SPACE_56
|
|
2004
|
-
: get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0
|
|
2005
|
-
? CAP_SPACE_32
|
|
2006
|
-
: 0;
|
|
2203
|
+
const slideBoxWrapperMargin = getSlideBoxWrapperMarginFromLiquidErrors(liquidErrorMessage);
|
|
2007
2204
|
/* TODO: Instead of passing down same props separately to each component down, write common function to these props and pass it accordingly */
|
|
2008
2205
|
|
|
2009
2206
|
// Compute anonymous user type and channel restrictions
|
|
@@ -2032,7 +2229,10 @@ export class Creatives extends React.Component {
|
|
|
2032
2229
|
<SlideBoxWrapper
|
|
2033
2230
|
slideBoxWrapperMargin={slideBoxWrapperMargin}
|
|
2034
2231
|
shouldApplyFooterMargin={shouldShowErrorInfoNoteInFooter}
|
|
2035
|
-
className={classnames(
|
|
2232
|
+
className={classnames(
|
|
2233
|
+
`${classPrefix} ${isFullMode ? 'creatives-full-mode' : 'creatives-library-mode'} ${mapTemplateCreate ? 'map-template-create' : ''}`,
|
|
2234
|
+
useLocalTemplates && slidBoxContent === 'templates' && 'creatives-slidebox--local-sms-templates',
|
|
2235
|
+
)}
|
|
2036
2236
|
>
|
|
2037
2237
|
<CapSlideBox
|
|
2038
2238
|
header={
|
|
@@ -2057,12 +2257,13 @@ export class Creatives extends React.Component {
|
|
|
2057
2257
|
smsRegister={smsRegister}
|
|
2058
2258
|
handleClose={this.handleCloseSlideBox}
|
|
2059
2259
|
moduleType={this.props.messageDetails?.type}
|
|
2260
|
+
useLocalTemplates={useLocalTemplates}
|
|
2060
2261
|
/>
|
|
2061
2262
|
)}
|
|
2062
2263
|
content={(
|
|
2063
2264
|
<SlideBoxContent
|
|
2064
2265
|
key="creatives-container-slidebox-content"
|
|
2065
|
-
onSelectTemplate={this.onSelectTemplate}
|
|
2266
|
+
onSelectTemplate={this.props.onSelectTemplate != null ? this.props.onSelectTemplate : this.onSelectTemplate}
|
|
2066
2267
|
onCreateComplete={getCreativesData}
|
|
2067
2268
|
onPreviewTemplate={this.onPreviewTemplate}
|
|
2068
2269
|
slidBoxContent={slidBoxContent}
|
|
@@ -2130,7 +2331,6 @@ export class Creatives extends React.Component {
|
|
|
2130
2331
|
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.
|
|
2131
2332
|
hostName={this.props?.hostName || ''}
|
|
2132
2333
|
eventContextTags={eventContextTags}
|
|
2133
|
-
waitEventContextTags={waitEventContextTags}
|
|
2134
2334
|
isLoyaltyModule={isLoyaltyModule}
|
|
2135
2335
|
loyaltyMetaData={loyaltyMetaData}
|
|
2136
2336
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
@@ -2139,7 +2339,8 @@ export class Creatives extends React.Component {
|
|
|
2139
2339
|
isTestAndPreviewMode={(() => this.state.isTestAndPreviewMode)()}
|
|
2140
2340
|
onHtmlEditorValidationStateChange={this.updateHtmlEditorValidationState}
|
|
2141
2341
|
onPersonalizationTokensChange={this.handlePersonalizationTokensChange}
|
|
2142
|
-
|
|
2342
|
+
localTemplatesConfig={pick(this.props.localTemplatesConfig || this.props, constants.LOCAL_TEMPLATE_CONFIG_KEYS)}
|
|
2343
|
+
/>
|
|
2143
2344
|
)}
|
|
2144
2345
|
footer={this.shouldShowFooter() ? (
|
|
2145
2346
|
<SlideBoxFooter
|
|
@@ -2224,13 +2425,31 @@ Creatives.propTypes = {
|
|
|
2224
2425
|
orgUnitId: PropTypes.number,
|
|
2225
2426
|
hostName: PropTypes.string,
|
|
2226
2427
|
eventContextTags: PropTypes.array,
|
|
2227
|
-
waitEventContextTags: PropTypes.object,
|
|
2228
2428
|
loyaltyTagFetchingDependencies: PropTypes.object,
|
|
2229
2429
|
customerType: PropTypes.string,
|
|
2230
2430
|
intl: PropTypes.shape({
|
|
2231
2431
|
formatMessage: PropTypes.func,
|
|
2232
2432
|
}),
|
|
2233
2433
|
stopValidation: PropTypes.func,
|
|
2434
|
+
// Local template list (e.g. for SMS fallback): when set, TemplatesV2 uses these instead of Redux.
|
|
2435
|
+
// All optional. Pass either localTemplatesConfig (object) or individual props below.
|
|
2436
|
+
localTemplatesConfig: PropTypes.shape({
|
|
2437
|
+
useLocalTemplates: PropTypes.bool,
|
|
2438
|
+
localTemplates: PropTypes.arrayOf(PropTypes.object),
|
|
2439
|
+
localTemplatesLoading: PropTypes.bool,
|
|
2440
|
+
localTemplatesFilterContent: PropTypes.node,
|
|
2441
|
+
localTemplatesSentinelContent: PropTypes.node,
|
|
2442
|
+
localTemplatesScrollContainerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
|
2443
|
+
localTemplatesUseSkeleton: PropTypes.bool,
|
|
2444
|
+
}),
|
|
2445
|
+
useLocalTemplates: PropTypes.bool,
|
|
2446
|
+
localTemplates: PropTypes.arrayOf(PropTypes.object),
|
|
2447
|
+
localTemplatesLoading: PropTypes.bool,
|
|
2448
|
+
localTemplatesFilterContent: PropTypes.node,
|
|
2449
|
+
localTemplatesSentinelContent: PropTypes.node,
|
|
2450
|
+
localTemplatesScrollContainerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
|
2451
|
+
localTemplatesUseSkeleton: PropTypes.bool,
|
|
2452
|
+
onSelectTemplate: PropTypes.func,
|
|
2234
2453
|
};
|
|
2235
2454
|
const mapStatesToProps = () => createStructuredSelector({
|
|
2236
2455
|
isLoading: isLoadingSelector(),
|