@capillarytech/creatives-library 8.0.353-alpha.6 → 8.0.353
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 +0 -29
- package/package.json +1 -1
- package/services/tests/api.test.js +20 -35
- package/utils/commonUtils.js +1 -19
- package/v2Components/CapActionButton/constants.js +0 -7
- package/v2Components/CapActionButton/index.js +108 -166
- package/v2Components/CapActionButton/index.scss +6 -157
- package/v2Components/CapActionButton/messages.js +3 -19
- package/v2Components/CapActionButton/tests/index.test.js +17 -41
- package/v2Components/CapTagList/index.js +0 -10
- package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +49 -72
- package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +2 -8
- package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +21 -213
- package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +0 -16
- package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +10 -85
- package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +0 -30
- package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +11 -79
- package/v2Components/CommonTestAndPreview/SendTestMessage.js +5 -10
- package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +15 -157
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +76 -346
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +4 -133
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +0 -11
- package/v2Components/CommonTestAndPreview/constants.js +2 -38
- package/v2Components/CommonTestAndPreview/index.js +186 -691
- package/v2Components/CommonTestAndPreview/messages.js +3 -45
- package/v2Components/CommonTestAndPreview/sagas.js +6 -25
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +284 -308
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +65 -231
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +5 -118
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +0 -341
- package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +1 -8
- package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +13 -34
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +283 -281
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +1 -199
- package/v2Components/CommonTestAndPreview/tests/index.test.js +4 -132
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +26 -36
- package/v2Components/FormBuilder/index.js +168 -63
- package/v2Components/TemplatePreview/_templatePreview.scss +23 -38
- package/v2Components/TemplatePreview/index.js +31 -143
- package/v2Components/TemplatePreview/tests/index.test.js +0 -142
- package/v2Components/TestAndPreviewSlidebox/index.js +1 -13
- package/v2Components/TestAndPreviewSlidebox/sagas.js +4 -11
- package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +1 -3
- package/v2Containers/CreativesContainer/SlideBoxContent.js +4 -36
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +1 -10
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +4 -29
- package/v2Containers/CreativesContainer/constants.js +0 -9
- package/v2Containers/CreativesContainer/index.js +163 -346
- package/v2Containers/CreativesContainer/index.scss +1 -51
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +34 -78
- package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +16 -79
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -8
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +98 -357
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +15 -20
- package/v2Containers/CreativesContainer/tests/index.test.js +9 -71
- package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
- package/v2Containers/Rcs/constants.js +10 -119
- package/v2Containers/Rcs/index.js +818 -2450
- package/v2Containers/Rcs/index.scss +8 -280
- package/v2Containers/Rcs/messages.js +3 -34
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +70073 -98018
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +5 -0
- package/v2Containers/Rcs/tests/index.test.js +121 -152
- package/v2Containers/Rcs/tests/mockData.js +0 -38
- package/v2Containers/Rcs/tests/utils.test.js +30 -646
- package/v2Containers/Rcs/utils.js +11 -478
- package/v2Containers/Sms/Create/index.js +40 -106
- package/v2Containers/SmsTrai/Create/index.js +4 -9
- package/v2Containers/SmsTrai/Edit/constants.js +0 -2
- package/v2Containers/SmsTrai/Edit/index.js +130 -640
- package/v2Containers/SmsTrai/Edit/messages.js +4 -14
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +2296 -4249
- package/v2Containers/SmsWrapper/index.js +8 -37
- package/v2Containers/TagList/index.js +0 -6
- package/v2Containers/Templates/_templates.scss +9 -166
- package/v2Containers/Templates/actions.js +0 -11
- package/v2Containers/Templates/constants.js +0 -2
- package/v2Containers/Templates/index.js +52 -120
- package/v2Containers/Templates/sagas.js +12 -56
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1017 -1062
- package/v2Containers/Templates/tests/sagas.test.js +16 -199
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +1 -72
- package/v2Containers/TemplatesV2/index.js +23 -86
- package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
- package/v2Containers/Whatsapp/index.js +20 -3
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -578
- package/utils/rcsPayloadUtils.js +0 -92
- package/utils/templateVarUtils.js +0 -201
- package/utils/tests/rcsPayloadUtils.test.js +0 -226
- package/utils/tests/templateVarUtils.test.js +0 -204
- package/v2Components/CommonTestAndPreview/previewApiUtils.js +0 -59
- package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +0 -67
- package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +0 -91
- package/v2Components/SmsFallback/constants.js +0 -73
- package/v2Components/SmsFallback/index.js +0 -956
- package/v2Components/SmsFallback/index.scss +0 -265
- package/v2Components/SmsFallback/messages.js +0 -78
- package/v2Components/SmsFallback/smsFallbackUtils.js +0 -119
- package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +0 -50
- package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +0 -147
- package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +0 -304
- package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +0 -223
- package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +0 -309
- package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +0 -422
- package/v2Components/SmsFallback/useLocalTemplateList.js +0 -92
- package/v2Components/TemplatePreview/constants.js +0 -2
- package/v2Components/VarSegmentMessageEditor/constants.js +0 -2
- package/v2Components/VarSegmentMessageEditor/index.js +0 -125
- package/v2Components/VarSegmentMessageEditor/index.scss +0 -46
- package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +0 -43
- package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +0 -79
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +0 -90
- package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +0 -258
- package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +0 -125
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +0 -225
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -318
- package/v2Containers/Sms/smsFormDataHelpers.js +0 -67
- package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +0 -253
- package/v2Containers/SmsTrai/Edit/index.scss +0 -121
- package/v2Containers/Templates/TemplatesActionBar.js +0 -101
- package/v2Containers/Templates/tests/TemplatesActionBar.test.js +0 -120
- package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +0 -180
- package/v2Containers/Templates/utils/smsTemplatesListApi.js +0 -79
- package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +0 -131
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
|
|
3
|
+
// Isolated input for the email template name field.
|
|
4
|
+
// Manages its own value in local state so keystrokes only re-render this
|
|
5
|
+
// small component, not the entire CreativesContainer → Email → FormBuilder tree.
|
|
6
|
+
class TemplateNameInputField extends React.Component {
|
|
7
|
+
constructor(props) {
|
|
8
|
+
super(props);
|
|
9
|
+
this.state = { localValue: props.initialValue || '' };
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
componentDidUpdate(prevProps) {
|
|
13
|
+
// Sync from props only when the external value changed AND the user hasn't
|
|
14
|
+
// diverged from the previous prop value. This handles async data-load in edit
|
|
15
|
+
// mode without overwriting what the user is actively typing.
|
|
16
|
+
if (
|
|
17
|
+
prevProps.initialValue !== this.props.initialValue &&
|
|
18
|
+
this.state.localValue === (prevProps.initialValue || '')
|
|
19
|
+
) {
|
|
20
|
+
this.setState({ localValue: this.props.initialValue || '' });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
handleChange = (ev) => {
|
|
25
|
+
const { value } = ev.currentTarget;
|
|
26
|
+
this.setState({ localValue: value });
|
|
27
|
+
if (this.props.onChange) this.props.onChange(value);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
handleBlur = () => {
|
|
31
|
+
if (this.props.onBlur) this.props.onBlur(this.state.localValue);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
render() {
|
|
35
|
+
const { onChange: _onChange, initialValue: _initialValue, onBlur: _ob, ...rest } = this.props;
|
|
36
|
+
return (
|
|
37
|
+
<CapInput
|
|
38
|
+
{...rest}
|
|
39
|
+
value={this.state.localValue}
|
|
40
|
+
onChange={this.handleChange}
|
|
41
|
+
onBlur={this.handleBlur}
|
|
42
|
+
/>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
2
46
|
import PropTypes from 'prop-types';
|
|
47
|
+
import {
|
|
48
|
+
CAP_SPACE_16, CAP_SPACE_32, CAP_SPACE_56, CAP_SPACE_64,
|
|
49
|
+
} from '@capillarytech/cap-ui-library/styled/variables';
|
|
50
|
+
|
|
3
51
|
import CapSlideBox from '@capillarytech/cap-ui-library/CapSlideBox';
|
|
4
52
|
import CapHeader from '@capillarytech/cap-ui-library/CapHeader';
|
|
5
53
|
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
@@ -9,11 +57,12 @@ import CapNotification from '@capillarytech/cap-ui-library/CapNotification';
|
|
|
9
57
|
import { injectIntl, FormattedMessage } from 'react-intl';
|
|
10
58
|
import classnames from 'classnames';
|
|
11
59
|
import {
|
|
12
|
-
isEmpty, get, forEach, cloneDeep, debounce,
|
|
60
|
+
isEmpty, get, forEach, cloneDeep, debounce,
|
|
13
61
|
} from 'lodash';
|
|
14
62
|
import { connect } from 'react-redux';
|
|
15
63
|
import { createStructuredSelector } from 'reselect';
|
|
16
64
|
import { bindActionCreators, compose } from 'redux';
|
|
65
|
+
import styled from 'styled-components';
|
|
17
66
|
import { GA } from '@capillarytech/cap-ui-utils';
|
|
18
67
|
import { DAEMON } from '@capillarytech/vulcan-react-sdk/utils/sagaInjectorTypes';
|
|
19
68
|
|
|
@@ -27,7 +76,6 @@ import SlideBoxContent from './SlideBoxContent';
|
|
|
27
76
|
import * as constants from './constants';
|
|
28
77
|
import * as commonUtil from '../../utils/common';
|
|
29
78
|
import { gtmPush } from '../../utils/gtmTrackers';
|
|
30
|
-
import { normalizeRcsMessageContentForApi } from '../../utils/rcsPayloadUtils';
|
|
31
79
|
import './index.scss';
|
|
32
80
|
import * as templateActions from '../Templates/actions';
|
|
33
81
|
import * as globalActions from '../Cap/actions';
|
|
@@ -43,9 +91,6 @@ import {
|
|
|
43
91
|
import {EXTERNAL_URL, SITE_URL, WEBPUSH_MEDIA_TYPES} from '../WebPush/constants';
|
|
44
92
|
import { IMAGE, VIDEO } from '../Facebook/Advertisement/constant';
|
|
45
93
|
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';
|
|
49
94
|
import { CREATIVE } from '../Facebook/constants';
|
|
50
95
|
import { LOYALTY } from '../App/constants';
|
|
51
96
|
import {
|
|
@@ -60,11 +105,6 @@ import { capSagaForFetchSchemaForEntity, capSagaLiquidEntity } from '../Cap/saga
|
|
|
60
105
|
import { v2TemplateSagaWatchGetDefaultBeeTemplates } from '../Templates/sagas';
|
|
61
106
|
import { DYNAMIC_URL } from '../../v2Components/CapWhatsappCTA/constants';
|
|
62
107
|
import ErrorInfoNote from '../../v2Components/ErrorInfoNote';
|
|
63
|
-
import SlideBoxWrapper from './CreativesSlideBoxWrapper';
|
|
64
|
-
import {
|
|
65
|
-
computeLiquidFooterUpdateFromFormBuilder,
|
|
66
|
-
getSlideBoxWrapperMarginFromLiquidErrors,
|
|
67
|
-
} from './embeddedSlideboxUtils';
|
|
68
108
|
|
|
69
109
|
import {
|
|
70
110
|
transformChannelPayload,
|
|
@@ -73,24 +113,51 @@ import {
|
|
|
73
113
|
import { MANUAL_CAROUSEL } from '../MobilePushNew/constants';
|
|
74
114
|
import { BIG_HTML } from '../InApp/constants';
|
|
75
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Returns true if value is "deep empty": no errors present.
|
|
118
|
+
* - null/undefined: empty
|
|
119
|
+
* - string: empty if length === 0
|
|
120
|
+
* - array: empty if length === 0
|
|
121
|
+
* - plain object (e.g. { android: [], ios: [], generic: [] }): empty only if every value is deep-empty
|
|
122
|
+
*/
|
|
123
|
+
function isDeepEmpty(value) {
|
|
124
|
+
if (value == null) return true;
|
|
125
|
+
if (typeof value === 'string') return value.length === 0;
|
|
126
|
+
if (Array.isArray(value)) return value.length === 0;
|
|
127
|
+
if (typeof value === 'object') {
|
|
128
|
+
return Object.values(value).every(isDeepEmpty);
|
|
129
|
+
}
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
|
|
76
133
|
const classPrefix = 'add-creatives-section';
|
|
77
134
|
const CREATIVES_CONTAINER = 'creativesContainer';
|
|
78
135
|
|
|
136
|
+
const SlideBoxWrapper = styled.div`
|
|
137
|
+
.cap-slide-box-v2-container{
|
|
138
|
+
.slidebox-header, .slidebox-content-container{
|
|
139
|
+
margin-bottom: ${({ slideBoxWrapperMargin }) => `${slideBoxWrapperMargin}`};
|
|
140
|
+
padding: 0 rem;
|
|
141
|
+
&.has-footer{
|
|
142
|
+
overflow-x: hidden;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
.slidebox-footer{
|
|
146
|
+
/* Only apply margin-bottom to footer when ErrorInfoNote is shown in footer (BEE editor) */
|
|
147
|
+
/* For HTML Editor, errors are shown in ValidationErrorDisplay (inside content area), so no footer margin needed */
|
|
148
|
+
margin-bottom: ${({ shouldApplyFooterMargin }) => (shouldApplyFooterMargin ? `${CAP_SPACE_16}` : '0')};
|
|
149
|
+
padding: 0 rem;
|
|
150
|
+
&.has-footer{
|
|
151
|
+
overflow-x: hidden;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
`;
|
|
79
156
|
export class Creatives extends React.Component {
|
|
80
157
|
constructor(props) {
|
|
81
158
|
super(props);
|
|
82
159
|
|
|
83
|
-
const
|
|
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
|
-
});
|
|
160
|
+
const initialSlidBoxContent = this.getSlideBoxContent({ mode: props.creativesMode, templateData: props.templateData, isFullMode: props.isFullMode });
|
|
94
161
|
|
|
95
162
|
this.state = {
|
|
96
163
|
isLoadingContent: true,
|
|
@@ -137,13 +204,7 @@ export class Creatives extends React.Component {
|
|
|
137
204
|
}
|
|
138
205
|
|
|
139
206
|
componentWillUnmount() {
|
|
140
|
-
|
|
141
|
-
const useLocalTemplates = get(
|
|
142
|
-
this.props,
|
|
143
|
-
'localTemplatesConfig.useLocalTemplates',
|
|
144
|
-
get(this.props, 'useLocalTemplates', false),
|
|
145
|
-
);
|
|
146
|
-
if (isEmbedded && !useLocalTemplates) {
|
|
207
|
+
if (get(this.props, 'location.query.type', '') === "embedded") {
|
|
147
208
|
this.props.templateActions.resetTemplateStoreData();
|
|
148
209
|
}
|
|
149
210
|
this.props.globalActions.clearMetaEntities();
|
|
@@ -751,69 +812,15 @@ export class Creatives extends React.Component {
|
|
|
751
812
|
smsFallBackContent = {},
|
|
752
813
|
creativeName = "",
|
|
753
814
|
channel = constants.RCS,
|
|
754
|
-
rcsCardVarMapped,
|
|
755
815
|
accountId = "",
|
|
756
816
|
} = templateData || {};
|
|
757
|
-
const
|
|
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;
|
|
817
|
+
const cardContent = (rcsContent.cardContent && rcsContent.cardContent[0]) || {};
|
|
765
818
|
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
|
-
];
|
|
811
819
|
|
|
812
820
|
creativesTemplateData = {
|
|
813
821
|
type: channel,
|
|
814
822
|
edit: true,
|
|
815
823
|
name: creativeName,
|
|
816
|
-
...(includeRootRcsCardVarMapped ? { rcsCardVarMapped: mergedCardVarMapped } : {}),
|
|
817
824
|
versions: {
|
|
818
825
|
base: {
|
|
819
826
|
content: {
|
|
@@ -821,7 +828,12 @@ export class Creatives extends React.Component {
|
|
|
821
828
|
rcsContent: {
|
|
822
829
|
...rcsContent,
|
|
823
830
|
...(accountId && !isFullMode && { accountId }),
|
|
824
|
-
cardContent:
|
|
831
|
+
cardContent: [
|
|
832
|
+
{
|
|
833
|
+
...cardContent,
|
|
834
|
+
Status,
|
|
835
|
+
},
|
|
836
|
+
],
|
|
825
837
|
},
|
|
826
838
|
smsFallBackContent,
|
|
827
839
|
},
|
|
@@ -969,10 +981,7 @@ export class Creatives extends React.Component {
|
|
|
969
981
|
return newExpandableDetails;
|
|
970
982
|
}
|
|
971
983
|
|
|
972
|
-
getCreativesData = async (
|
|
973
|
-
const channel = String(
|
|
974
|
-
channelParam || template?.type || get(template, 'value.type') || '',
|
|
975
|
-
).toUpperCase();
|
|
984
|
+
getCreativesData = async (channel, template, templateRecords) => { //from creatives to consumers
|
|
976
985
|
let templateData = { channel };
|
|
977
986
|
switch (channel) {
|
|
978
987
|
case constants.SMS:
|
|
@@ -1319,104 +1328,28 @@ export class Creatives extends React.Component {
|
|
|
1319
1328
|
break;
|
|
1320
1329
|
case constants.RCS:
|
|
1321
1330
|
if (template.value) {
|
|
1322
|
-
const {
|
|
1323
|
-
|
|
1324
|
-
const
|
|
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 };
|
|
1331
|
+
const { name = "", versions = {} } = {
|
|
1332
|
+
} = template.value || {};
|
|
1333
|
+
const smsFallBackContent = get(versions, 'base.content.RCS.smsFallBackContent', {});
|
|
1363
1334
|
const {
|
|
1364
|
-
cardContent
|
|
1335
|
+
cardContent = [],
|
|
1365
1336
|
contentType = "",
|
|
1366
1337
|
cardType = "",
|
|
1367
1338
|
cardSettings = {},
|
|
1368
1339
|
accountId = "",
|
|
1369
1340
|
} = 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
|
-
);
|
|
1379
1341
|
const rcsContent = {
|
|
1380
1342
|
contentType,
|
|
1381
1343
|
cardType,
|
|
1382
1344
|
cardSettings,
|
|
1383
1345
|
cardContent,
|
|
1384
1346
|
};
|
|
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;
|
|
1394
1347
|
templateData = {
|
|
1395
1348
|
channel,
|
|
1396
1349
|
creativeName: name,
|
|
1397
1350
|
rcsContent,
|
|
1398
1351
|
accountId,
|
|
1399
|
-
...(includeRootRcsCardVarMappedOnConsumerPayload
|
|
1400
|
-
? { rcsCardVarMapped: cardVarMappedFromFirstRcsCard }
|
|
1401
|
-
: {}),
|
|
1402
1352
|
};
|
|
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);
|
|
1420
1353
|
}
|
|
1421
1354
|
break;
|
|
1422
1355
|
case constants.ZALO:
|
|
@@ -1534,10 +1467,7 @@ export class Creatives extends React.Component {
|
|
|
1534
1467
|
return templateData;
|
|
1535
1468
|
};
|
|
1536
1469
|
|
|
1537
|
-
getSlideBoxContent({ mode, templateData, isFullMode
|
|
1538
|
-
if (useLocalTemplates && mode === 'create' && isEmpty(templateData)) {
|
|
1539
|
-
return 'templates';
|
|
1540
|
-
}
|
|
1470
|
+
getSlideBoxContent({ mode, templateData, isFullMode }) {
|
|
1541
1471
|
let creativesMode = isFullMode ? 'createTemplate' : 'templates';// for library mode templates page is initial mode and for full mode createTemplates
|
|
1542
1472
|
if (mode === 'create' && isFullMode) {
|
|
1543
1473
|
creativesMode = 'createTemplate';
|
|
@@ -1625,110 +1555,24 @@ export class Creatives extends React.Component {
|
|
|
1625
1555
|
getFormData = (template) => {
|
|
1626
1556
|
// Always reset isGetFormData so the child does not re-send form data on every re-render
|
|
1627
1557
|
// (e.g. when user fixes validation error by typing, we must not auto-close the slidebox)
|
|
1628
|
-
this.setState(
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
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,
|
|
1558
|
+
this.setState({ isGetFormData: false });
|
|
1559
|
+
if (template.validity) {
|
|
1560
|
+
this.setState(
|
|
1561
|
+
{},
|
|
1562
|
+
() => {
|
|
1563
|
+
const templateData = this.state.templateData ? this.state.templateData : template; //select existing or create new content
|
|
1564
|
+
const channel = templateData.type;
|
|
1565
|
+
const creativesData = this.getCreativesData(channel, template, templateData);// convers data to consumer understandable format
|
|
1566
|
+
creativesData.then((data) => {
|
|
1567
|
+
this.logGTMEvent(channel, data);
|
|
1568
|
+
this.processCentralCommsMetaId(channel, data);
|
|
1715
1569
|
});
|
|
1716
|
-
}
|
|
1717
|
-
|
|
1718
|
-
|
|
1570
|
+
},
|
|
1571
|
+
);
|
|
1572
|
+
}
|
|
1719
1573
|
}
|
|
1720
1574
|
|
|
1721
|
-
processCentralCommsMetaId = (channel, creativesData
|
|
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
|
-
};
|
|
1575
|
+
processCentralCommsMetaId = (channel, creativesData) => {
|
|
1732
1576
|
// Create the payload for the centralcommnsmetaId API call
|
|
1733
1577
|
const { isLoyaltyModule = false, loyaltyMetaData = {} } = this.props;
|
|
1734
1578
|
const { actionName, setMetaData = () => { } } = loyaltyMetaData;
|
|
@@ -1754,7 +1598,6 @@ export class Creatives extends React.Component {
|
|
|
1754
1598
|
if (result?.status?.code === 200) {
|
|
1755
1599
|
setMetaData(result);
|
|
1756
1600
|
this.props.getCreativesData(creativesData);
|
|
1757
|
-
maybeCloseLibrarySlideBox();
|
|
1758
1601
|
} else {
|
|
1759
1602
|
CapNotification.error({ message: <FormattedMessage {...messages.somethingWentWrong} /> });
|
|
1760
1603
|
}
|
|
@@ -1765,7 +1608,6 @@ export class Creatives extends React.Component {
|
|
|
1765
1608
|
} else {
|
|
1766
1609
|
// If not a loyalty module or different action, should work as usual
|
|
1767
1610
|
this.props.getCreativesData(creativesData);
|
|
1768
|
-
maybeCloseLibrarySlideBox();
|
|
1769
1611
|
}
|
|
1770
1612
|
};
|
|
1771
1613
|
|
|
@@ -1798,9 +1640,7 @@ export class Creatives extends React.Component {
|
|
|
1798
1640
|
}
|
|
1799
1641
|
this.setState((prevState) => ({
|
|
1800
1642
|
...prevState,
|
|
1801
|
-
|
|
1802
|
-
// Undefined isFullMode defaults to full-mode close behavior (clear templateData).
|
|
1803
|
-
...(this.props.isFullMode !== false ? { templateData: undefined } : {}),
|
|
1643
|
+
templateData: undefined,
|
|
1804
1644
|
showSlideBox: false,
|
|
1805
1645
|
liquidErrorMessage: { STANDARD_ERROR_MSG: [], LIQUID_ERROR_MSG: [] },
|
|
1806
1646
|
isLiquidValidationError: false,
|
|
@@ -1957,30 +1797,22 @@ export class Creatives extends React.Component {
|
|
|
1957
1797
|
} />
|
|
1958
1798
|
)
|
|
1959
1799
|
|
|
1960
|
-
templateNameComponentInput = ({ formData, onFormDataChange, name }) =>
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
onChange={(ev) => {
|
|
1977
|
-
const { value } = ev.currentTarget;
|
|
1978
|
-
// Use optimized update for better performance
|
|
1979
|
-
this.updateTemplateNameImmediately(value, formData, onFormDataChange);
|
|
1980
|
-
}}
|
|
1981
|
-
/>
|
|
1982
|
-
);
|
|
1983
|
-
}
|
|
1800
|
+
templateNameComponentInput = ({ formData, onFormDataChange, name }) => (
|
|
1801
|
+
<TemplateNameInputField
|
|
1802
|
+
initialValue={name}
|
|
1803
|
+
suffix={<span />}
|
|
1804
|
+
onBlur={(committedValue) => {
|
|
1805
|
+
this.performTemplateNameUpdate(committedValue, formData, onFormDataChange);
|
|
1806
|
+
this.setState({ isEditName: false });
|
|
1807
|
+
}}
|
|
1808
|
+
onChange={(value) => {
|
|
1809
|
+
const isEmptyTemplateName = !value.trim();
|
|
1810
|
+
if (this.state.isTemplateNameEmpty !== isEmptyTemplateName) {
|
|
1811
|
+
this.setState({ isTemplateNameEmpty: isEmptyTemplateName });
|
|
1812
|
+
}
|
|
1813
|
+
}}
|
|
1814
|
+
/>
|
|
1815
|
+
)
|
|
1984
1816
|
|
|
1985
1817
|
showTemplateName = ({ formData, onFormDataChange }) => { //gets called from email/index after template data is fetched
|
|
1986
1818
|
const {
|
|
@@ -2011,17 +1843,21 @@ export class Creatives extends React.Component {
|
|
|
2011
1843
|
}
|
|
2012
1844
|
|
|
2013
1845
|
showLiquidErrorInFooter = (errorMessagesFromFormBuilder, currentFormBuilderTab) => {
|
|
2014
|
-
const
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
this.setState(
|
|
1846
|
+
const liquidMsgs = get(errorMessagesFromFormBuilder, constants.LIQUID_ERROR_MSG, []);
|
|
1847
|
+
const standardMsgs = get(errorMessagesFromFormBuilder, constants.STANDARD_ERROR_MSG, []);
|
|
1848
|
+
const hasLiquid = !isDeepEmpty(liquidMsgs);
|
|
1849
|
+
const hasStandard = !isDeepEmpty(standardMsgs);
|
|
1850
|
+
const isLiquidValidationError = hasLiquid || hasStandard;
|
|
1851
|
+
// Don't overwrite existing liquid error with empty only for Mobile Push OLD (FormBuilder/clear calls empty there); SMS/others clear on input change
|
|
1852
|
+
const isMobilePush = this.state.currentChannel?.toUpperCase() === constants.MOBILE_PUSH;
|
|
1853
|
+
if (!hasLiquid && !hasStandard && this.state.isLiquidValidationError && isMobilePush) {
|
|
1854
|
+
return;
|
|
1855
|
+
}
|
|
1856
|
+
this.setState({
|
|
1857
|
+
isLiquidValidationError,
|
|
1858
|
+
liquidErrorMessage: errorMessagesFromFormBuilder,
|
|
1859
|
+
activeFormBuilderTab: currentFormBuilderTab === 1 ? constants.ANDROID : (currentFormBuilderTab === 2 ? constants.IOS : null), // Update activeFormBuilderTab, default to 1 if undefined
|
|
1860
|
+
});
|
|
2025
1861
|
}
|
|
2026
1862
|
|
|
2027
1863
|
// Callback to update HTML Editor validation state (called from EmailWrapper)
|
|
@@ -2144,11 +1980,6 @@ export class Creatives extends React.Component {
|
|
|
2144
1980
|
inAppEditorType,
|
|
2145
1981
|
htmlEditorValidationState,
|
|
2146
1982
|
} = this.state;
|
|
2147
|
-
const useLocalTemplates = get(
|
|
2148
|
-
this.props,
|
|
2149
|
-
'localTemplatesConfig.useLocalTemplates',
|
|
2150
|
-
get(this.props, 'useLocalTemplates', false),
|
|
2151
|
-
);
|
|
2152
1983
|
const {
|
|
2153
1984
|
isFullMode,
|
|
2154
1985
|
creativesMode,
|
|
@@ -2167,6 +1998,7 @@ export class Creatives extends React.Component {
|
|
|
2167
1998
|
smsRegister,
|
|
2168
1999
|
enableNewChannels,
|
|
2169
2000
|
eventContextTags,
|
|
2001
|
+
waitEventContextTags = {},
|
|
2170
2002
|
isLoyaltyModule,
|
|
2171
2003
|
loyaltyMetaData = {},
|
|
2172
2004
|
} = this.props;
|
|
@@ -2200,7 +2032,14 @@ export class Creatives extends React.Component {
|
|
|
2200
2032
|
// IMPORTANT: Never show ErrorInfoNote in footer when in HTML Editor mode, even if liquidErrorMessage exists
|
|
2201
2033
|
const shouldShowErrorInfoNoteInFooter = isHTMLEditorMode ? false : hasBEEEditorErrors;
|
|
2202
2034
|
|
|
2203
|
-
|
|
2035
|
+
// Calculate margin for header/content (always apply if there are errors, regardless of editor type)
|
|
2036
|
+
const slideBoxWrapperMargin = (get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0 && get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0)
|
|
2037
|
+
? CAP_SPACE_64
|
|
2038
|
+
: get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0
|
|
2039
|
+
? CAP_SPACE_56
|
|
2040
|
+
: get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0
|
|
2041
|
+
? CAP_SPACE_32
|
|
2042
|
+
: 0;
|
|
2204
2043
|
/* TODO: Instead of passing down same props separately to each component down, write common function to these props and pass it accordingly */
|
|
2205
2044
|
|
|
2206
2045
|
// Compute anonymous user type and channel restrictions
|
|
@@ -2229,10 +2068,7 @@ export class Creatives extends React.Component {
|
|
|
2229
2068
|
<SlideBoxWrapper
|
|
2230
2069
|
slideBoxWrapperMargin={slideBoxWrapperMargin}
|
|
2231
2070
|
shouldApplyFooterMargin={shouldShowErrorInfoNoteInFooter}
|
|
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
|
-
)}
|
|
2071
|
+
className={classnames(`${classPrefix} ${isFullMode ? 'creatives-full-mode' : 'creatives-library-mode'} ${mapTemplateCreate ? 'map-template-create' : ''}`)}
|
|
2236
2072
|
>
|
|
2237
2073
|
<CapSlideBox
|
|
2238
2074
|
header={
|
|
@@ -2257,13 +2093,12 @@ export class Creatives extends React.Component {
|
|
|
2257
2093
|
smsRegister={smsRegister}
|
|
2258
2094
|
handleClose={this.handleCloseSlideBox}
|
|
2259
2095
|
moduleType={this.props.messageDetails?.type}
|
|
2260
|
-
useLocalTemplates={useLocalTemplates}
|
|
2261
2096
|
/>
|
|
2262
2097
|
)}
|
|
2263
2098
|
content={(
|
|
2264
2099
|
<SlideBoxContent
|
|
2265
2100
|
key="creatives-container-slidebox-content"
|
|
2266
|
-
onSelectTemplate={this.
|
|
2101
|
+
onSelectTemplate={this.onSelectTemplate}
|
|
2267
2102
|
onCreateComplete={getCreativesData}
|
|
2268
2103
|
onPreviewTemplate={this.onPreviewTemplate}
|
|
2269
2104
|
slidBoxContent={slidBoxContent}
|
|
@@ -2331,6 +2166,7 @@ export class Creatives extends React.Component {
|
|
|
2331
2166
|
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.
|
|
2332
2167
|
hostName={this.props?.hostName || ''}
|
|
2333
2168
|
eventContextTags={eventContextTags}
|
|
2169
|
+
waitEventContextTags={waitEventContextTags}
|
|
2334
2170
|
isLoyaltyModule={isLoyaltyModule}
|
|
2335
2171
|
loyaltyMetaData={loyaltyMetaData}
|
|
2336
2172
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
@@ -2339,8 +2175,7 @@ export class Creatives extends React.Component {
|
|
|
2339
2175
|
isTestAndPreviewMode={(() => this.state.isTestAndPreviewMode)()}
|
|
2340
2176
|
onHtmlEditorValidationStateChange={this.updateHtmlEditorValidationState}
|
|
2341
2177
|
onPersonalizationTokensChange={this.handlePersonalizationTokensChange}
|
|
2342
|
-
|
|
2343
|
-
/>
|
|
2178
|
+
/>
|
|
2344
2179
|
)}
|
|
2345
2180
|
footer={this.shouldShowFooter() ? (
|
|
2346
2181
|
<SlideBoxFooter
|
|
@@ -2425,31 +2260,13 @@ Creatives.propTypes = {
|
|
|
2425
2260
|
orgUnitId: PropTypes.number,
|
|
2426
2261
|
hostName: PropTypes.string,
|
|
2427
2262
|
eventContextTags: PropTypes.array,
|
|
2263
|
+
waitEventContextTags: PropTypes.object,
|
|
2428
2264
|
loyaltyTagFetchingDependencies: PropTypes.object,
|
|
2429
2265
|
customerType: PropTypes.string,
|
|
2430
2266
|
intl: PropTypes.shape({
|
|
2431
2267
|
formatMessage: PropTypes.func,
|
|
2432
2268
|
}),
|
|
2433
2269
|
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,
|
|
2453
2270
|
};
|
|
2454
2271
|
const mapStatesToProps = () => createStructuredSelector({
|
|
2455
2272
|
isLoading: isLoadingSelector(),
|