@capillarytech/creatives-library 8.0.316 → 8.0.317-alpha.0
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 +15 -0
- package/package.json +1 -1
- package/services/api.js +6 -0
- package/services/tests/api.test.js +7 -0
- package/utils/common.js +6 -1
- package/utils/templateVarUtils.js +172 -0
- package/utils/tests/tagValidations.test.js +34 -0
- package/utils/tests/templateVarUtils.test.js +160 -0
- package/v2Components/CapTagList/index.js +25 -22
- package/v2Components/CapTagList/style.scss +48 -0
- package/v2Components/CapTagListWithInput/__tests__/CapTagListWithInput.test.js +63 -0
- package/v2Components/CapTagListWithInput/index.js +4 -0
- package/v2Components/CapWhatsappCTA/index.js +2 -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 +11 -5
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +20 -1
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +133 -4
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +12 -0
- package/v2Components/CommonTestAndPreview/constants.js +38 -0
- package/v2Components/CommonTestAndPreview/index.js +693 -155
- package/v2Components/CommonTestAndPreview/messages.js +41 -3
- package/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
- package/v2Components/CommonTestAndPreview/sagas.js +15 -6
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +352 -0
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +269 -1
- 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/SendTestMessage.test.js +25 -4
- 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 +14 -1
- package/v2Components/HtmlEditor/HTMLEditor.js +6 -1
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +927 -2
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +3 -0
- package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +87 -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 +107 -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 +261 -0
- package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +422 -0
- package/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
- package/v2Components/TestAndPreviewSlidebox/index.js +8 -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/BeeEditor/index.js +3 -0
- package/v2Containers/CommunicationFlow/CommunicationFlow.js +291 -0
- package/v2Containers/CommunicationFlow/CommunicationFlow.scss +25 -0
- package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +255 -0
- package/v2Containers/CommunicationFlow/constants.js +200 -0
- package/v2Containers/CommunicationFlow/index.js +102 -0
- package/v2Containers/CommunicationFlow/messages.js +346 -0
- package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.js +522 -0
- package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.scss +170 -0
- package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/Tests/ChannelSelectionStep.test.js +796 -0
- package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/index.js +5 -0
- package/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/CommunicationStrategyStep.js +95 -0
- package/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/Tests/CommunicationStrategyStep.test.js +133 -0
- package/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/index.js +5 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.js +289 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.scss +70 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.js +319 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.scss +69 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +616 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +577 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/deliverySettingsConfig.test.js +1111 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/deliverySettingsConfig.js +696 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/index.js +7 -0
- package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.js +102 -0
- package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.scss +36 -0
- package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/Tests/DynamicControlsStep.test.js +91 -0
- package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/index.js +5 -0
- package/v2Containers/CommunicationFlow/steps/MessageTypeStep/MessageTypeStep.js +86 -0
- package/v2Containers/CommunicationFlow/steps/MessageTypeStep/Tests/MessageTypeStep.test.js +100 -0
- package/v2Containers/CommunicationFlow/steps/MessageTypeStep/index.js +5 -0
- package/v2Containers/CommunicationFlow/utils/getEnabledSteps.js +30 -0
- package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +43 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +64 -5
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +10 -1
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +29 -4
- package/v2Containers/CreativesContainer/constants.js +12 -0
- package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +67 -0
- package/v2Containers/CreativesContainer/index.js +289 -93
- package/v2Containers/CreativesContainer/index.scss +51 -1
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +104 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +110 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +8 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +363 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +20 -10
- package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
- package/v2Containers/CreativesContainer/tests/index.test.js +71 -9
- package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +125 -0
- package/v2Containers/Email/index.js +1 -0
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +7 -1
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +3 -0
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +20 -2
- package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +16 -1
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +3 -0
- package/v2Containers/EmailWrapper/index.js +4 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +1 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +9 -0
- package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +19 -0
- package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +3 -0
- package/v2Containers/InAppWrapper/index.js +3 -0
- package/v2Containers/MobilePush/Create/index.js +2 -0
- package/v2Containers/MobilePush/Edit/index.js +2 -0
- package/v2Containers/MobilepushWrapper/index.js +3 -1
- package/v2Containers/Rcs/constants.js +32 -1
- package/v2Containers/Rcs/index.js +951 -873
- package/v2Containers/Rcs/index.scss +85 -6
- package/v2Containers/Rcs/messages.js +10 -1
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +205 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +40834 -1963
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +0 -5
- package/v2Containers/Rcs/tests/index.test.js +41 -38
- package/v2Containers/Rcs/tests/mockData.js +38 -0
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +251 -0
- package/v2Containers/Rcs/tests/utils.test.js +379 -1
- package/v2Containers/Rcs/utils.js +358 -10
- package/v2Containers/Sms/Create/index.js +83 -36
- package/v2Containers/Sms/Edit/index.js +2 -0
- 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 +611 -128
- package/v2Containers/SmsTrai/Edit/index.scss +121 -0
- package/v2Containers/SmsTrai/Edit/messages.js +9 -4
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4327 -2374
- package/v2Containers/SmsWrapper/index.js +39 -8
- package/v2Containers/TagList/index.js +47 -2
- package/v2Containers/TagList/messages.js +4 -0
- package/v2Containers/TagList/tests/TagList.test.js +122 -20
- package/v2Containers/TagList/tests/mockdata.js +17 -0
- package/v2Containers/Templates/TemplatesActionBar.js +101 -0
- package/v2Containers/Templates/_templates.scss +61 -2
- package/v2Containers/Templates/actions.js +11 -0
- package/v2Containers/Templates/constants.js +2 -0
- package/v2Containers/Templates/index.js +90 -40
- package/v2Containers/Templates/sagas.js +57 -12
- package/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1043 -1079
- package/v2Containers/Templates/tests/sagas.test.js +193 -12
- 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/Viber/index.js +5 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.js +0 -2
- package/v2Containers/WebPush/Create/index.js +9 -1
- package/v2Containers/Whatsapp/index.js +8 -20
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +598 -34
- package/v2Containers/Zalo/index.js +2 -0
|
@@ -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
|
|
|
@@ -47,6 +42,8 @@ import {
|
|
|
47
42
|
import {EXTERNAL_URL, SITE_URL, WEBPUSH_MEDIA_TYPES} from '../WebPush/constants';
|
|
48
43
|
import { IMAGE, VIDEO } from '../Facebook/Advertisement/constant';
|
|
49
44
|
import { RCS_STATUSES } from '../Rcs/constants';
|
|
45
|
+
import { mapRcsCardContentForConsumerWithResolvedTags } from '../Rcs/utils';
|
|
46
|
+
import { RCS_SMS_FALLBACK_VAR_MAPPED_PROP } from '../../v2Components/CommonTestAndPreview/constants';
|
|
50
47
|
import { CREATIVE } from '../Facebook/constants';
|
|
51
48
|
import { LOYALTY } from '../App/constants';
|
|
52
49
|
import {
|
|
@@ -61,6 +58,11 @@ import { capSagaForFetchSchemaForEntity, capSagaLiquidEntity } from '../Cap/saga
|
|
|
61
58
|
import { v2TemplateSagaWatchGetDefaultBeeTemplates } from '../Templates/sagas';
|
|
62
59
|
import { DYNAMIC_URL } from '../../v2Components/CapWhatsappCTA/constants';
|
|
63
60
|
import ErrorInfoNote from '../../v2Components/ErrorInfoNote';
|
|
61
|
+
import SlideBoxWrapper from './CreativesSlideBoxWrapper';
|
|
62
|
+
import {
|
|
63
|
+
computeLiquidFooterUpdateFromFormBuilder,
|
|
64
|
+
getSlideBoxWrapperMarginFromLiquidErrors,
|
|
65
|
+
} from './embeddedSlideboxUtils';
|
|
64
66
|
|
|
65
67
|
import {
|
|
66
68
|
transformChannelPayload,
|
|
@@ -69,51 +71,24 @@ import {
|
|
|
69
71
|
import { MANUAL_CAROUSEL } from '../MobilePushNew/constants';
|
|
70
72
|
import { BIG_HTML } from '../InApp/constants';
|
|
71
73
|
|
|
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
74
|
const classPrefix = 'add-creatives-section';
|
|
90
75
|
const CREATIVES_CONTAINER = 'creativesContainer';
|
|
91
76
|
|
|
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
77
|
export class Creatives extends React.Component {
|
|
113
78
|
constructor(props) {
|
|
114
79
|
super(props);
|
|
115
80
|
|
|
116
|
-
const
|
|
81
|
+
const useLocalTemplates = get(
|
|
82
|
+
props,
|
|
83
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
84
|
+
get(props, 'useLocalTemplates', false),
|
|
85
|
+
);
|
|
86
|
+
const initialSlidBoxContent = this.getSlideBoxContent({
|
|
87
|
+
mode: props.creativesMode,
|
|
88
|
+
templateData: props.templateData,
|
|
89
|
+
isFullMode: props.isFullMode,
|
|
90
|
+
useLocalTemplates,
|
|
91
|
+
});
|
|
117
92
|
|
|
118
93
|
this.state = {
|
|
119
94
|
isLoadingContent: true,
|
|
@@ -160,7 +135,13 @@ export class Creatives extends React.Component {
|
|
|
160
135
|
}
|
|
161
136
|
|
|
162
137
|
componentWillUnmount() {
|
|
163
|
-
|
|
138
|
+
const isEmbedded = get(this.props, 'location.query.type', '') === "embedded";
|
|
139
|
+
const useLocalTemplates = get(
|
|
140
|
+
this.props,
|
|
141
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
142
|
+
get(this.props, 'useLocalTemplates', false),
|
|
143
|
+
);
|
|
144
|
+
if (isEmbedded && !useLocalTemplates) {
|
|
164
145
|
this.props.templateActions.resetTemplateStoreData();
|
|
165
146
|
}
|
|
166
147
|
this.props.globalActions.clearMetaEntities();
|
|
@@ -762,14 +743,41 @@ export class Creatives extends React.Component {
|
|
|
762
743
|
smsFallBackContent = {},
|
|
763
744
|
creativeName = "",
|
|
764
745
|
channel = constants.RCS,
|
|
746
|
+
rcsCardVarMapped,
|
|
765
747
|
} = templateData || {};
|
|
766
|
-
const
|
|
748
|
+
const { isFullMode: isFullModeForRcsPayload } = this.props;
|
|
749
|
+
const firstCardIn = (rcsContent.cardContent && rcsContent.cardContent[0]) || {};
|
|
750
|
+
const {
|
|
751
|
+
cardDisplayTitle: _omitDispTitleIn,
|
|
752
|
+
cardDisplayDescription: _omitDispDescIn,
|
|
753
|
+
...cardContent
|
|
754
|
+
} = firstCardIn;
|
|
767
755
|
const Status = RCS_STATUSES.approved || '';
|
|
756
|
+
const mergedCardVarMapped = (() => {
|
|
757
|
+
const nestedCardVarMapped = cardContent?.cardVarMapped;
|
|
758
|
+
const rootMirrorCardVarMapped = rcsCardVarMapped;
|
|
759
|
+
const nestedRecord =
|
|
760
|
+
nestedCardVarMapped != null && typeof nestedCardVarMapped === 'object'
|
|
761
|
+
? nestedCardVarMapped
|
|
762
|
+
: {};
|
|
763
|
+
const rootRecord =
|
|
764
|
+
rootMirrorCardVarMapped != null && typeof rootMirrorCardVarMapped === 'object'
|
|
765
|
+
? rootMirrorCardVarMapped
|
|
766
|
+
: {};
|
|
767
|
+
const mergedFromRootAndNested = { ...rootRecord, ...nestedRecord };
|
|
768
|
+
return Object.keys(mergedFromRootAndNested).length > 0 ? mergedFromRootAndNested : null;
|
|
769
|
+
})();
|
|
770
|
+
// Campaigns (embedded): do not duplicate `cardVarMapped` as root `rcsCardVarMapped` on send —
|
|
771
|
+
// slot map stays on `versions…cardContent[0].cardVarMapped` only. Library full mode keeps root mirror.
|
|
772
|
+
// Use `=== true` so omitted/undefined `isFullMode` does not behave like library (avoids duplicate on approval payload).
|
|
773
|
+
const includeRootRcsCardVarMapped =
|
|
774
|
+
mergedCardVarMapped && isFullModeForRcsPayload === true;
|
|
768
775
|
|
|
769
776
|
creativesTemplateData = {
|
|
770
777
|
type: channel,
|
|
771
778
|
edit: true,
|
|
772
779
|
name: creativeName,
|
|
780
|
+
...(includeRootRcsCardVarMapped ? { rcsCardVarMapped: mergedCardVarMapped } : {}),
|
|
773
781
|
versions: {
|
|
774
782
|
base: {
|
|
775
783
|
content: {
|
|
@@ -779,6 +787,7 @@ export class Creatives extends React.Component {
|
|
|
779
787
|
cardContent: [
|
|
780
788
|
{
|
|
781
789
|
...cardContent,
|
|
790
|
+
...(mergedCardVarMapped ? { cardVarMapped: mergedCardVarMapped } : {}),
|
|
782
791
|
Status,
|
|
783
792
|
},
|
|
784
793
|
],
|
|
@@ -929,7 +938,10 @@ export class Creatives extends React.Component {
|
|
|
929
938
|
return newExpandableDetails;
|
|
930
939
|
}
|
|
931
940
|
|
|
932
|
-
getCreativesData = async (
|
|
941
|
+
getCreativesData = async (channelParam, template, templateRecords) => { //from creatives to consumers
|
|
942
|
+
const channel = String(
|
|
943
|
+
channelParam || template?.type || get(template, 'value.type') || '',
|
|
944
|
+
).toUpperCase();
|
|
933
945
|
let templateData = { channel };
|
|
934
946
|
switch (channel) {
|
|
935
947
|
case constants.SMS:
|
|
@@ -1271,26 +1283,101 @@ export class Creatives extends React.Component {
|
|
|
1271
1283
|
break;
|
|
1272
1284
|
case constants.RCS: {
|
|
1273
1285
|
if (template.value) {
|
|
1274
|
-
const {
|
|
1275
|
-
} = template.value || {};
|
|
1276
|
-
const
|
|
1286
|
+
const { isFullMode: isFullModeForRcsConsumerPayload } = this.props;
|
|
1287
|
+
const { name = "", versions = {} } = template.value || {};
|
|
1288
|
+
const fromSubmit = get(versions, 'base.content.RCS.smsFallBackContent', {});
|
|
1289
|
+
const fromRecords = {
|
|
1290
|
+
...(templateRecords?.smsFallBackContent || {}),
|
|
1291
|
+
...(get(templateRecords, 'versions.base.content.RCS.smsFallBackContent') || {}),
|
|
1292
|
+
};
|
|
1293
|
+
const hasMeaningfulRcsSmsFallback = (smsFallbackPayload) => {
|
|
1294
|
+
if (
|
|
1295
|
+
!smsFallbackPayload
|
|
1296
|
+
|| typeof smsFallbackPayload !== 'object'
|
|
1297
|
+
|| Object.keys(smsFallbackPayload).length === 0
|
|
1298
|
+
) {
|
|
1299
|
+
return false;
|
|
1300
|
+
}
|
|
1301
|
+
const fallbackBodyText = String(
|
|
1302
|
+
smsFallbackPayload.smsContent
|
|
1303
|
+
?? smsFallbackPayload.smsTemplateContent
|
|
1304
|
+
?? smsFallbackPayload.message
|
|
1305
|
+
?? smsFallbackPayload.content
|
|
1306
|
+
?? '',
|
|
1307
|
+
).trim();
|
|
1308
|
+
const fallbackTemplateName = String(
|
|
1309
|
+
smsFallbackPayload.smsTemplateName ?? smsFallbackPayload.templateName ?? '',
|
|
1310
|
+
).trim();
|
|
1311
|
+
const rcsSmsFallbackVarMapped =
|
|
1312
|
+
smsFallbackPayload?.[RCS_SMS_FALLBACK_VAR_MAPPED_PROP];
|
|
1313
|
+
const hasVarMappedEntries =
|
|
1314
|
+
rcsSmsFallbackVarMapped != null
|
|
1315
|
+
&& typeof rcsSmsFallbackVarMapped === 'object'
|
|
1316
|
+
&& Object.keys(rcsSmsFallbackVarMapped).length > 0;
|
|
1317
|
+
return (
|
|
1318
|
+
fallbackBodyText !== ''
|
|
1319
|
+
|| fallbackTemplateName !== ''
|
|
1320
|
+
|| hasVarMappedEntries
|
|
1321
|
+
);
|
|
1322
|
+
};
|
|
1323
|
+
// If submit has only empty strings, do not let it wipe fallback mirrored on templateRecords (library round-trip).
|
|
1324
|
+
const smsFallBackContent = hasMeaningfulRcsSmsFallback(fromSubmit)
|
|
1325
|
+
? { ...fromRecords, ...fromSubmit }
|
|
1326
|
+
: { ...fromSubmit, ...fromRecords };
|
|
1277
1327
|
const {
|
|
1278
|
-
cardContent = [],
|
|
1328
|
+
cardContent: cardContentFromSubmit = [],
|
|
1279
1329
|
contentType = "",
|
|
1280
1330
|
cardType = "",
|
|
1281
1331
|
cardSettings = {},
|
|
1282
1332
|
} = get(versions, 'base.content.RCS.rcsContent', {});
|
|
1333
|
+
const rootRcsCardVarMappedFromSubmit = get(template, 'value.rcsCardVarMapped');
|
|
1334
|
+
const firstCardFromSubmit = Array.isArray(cardContentFromSubmit)
|
|
1335
|
+
? cardContentFromSubmit[0]
|
|
1336
|
+
: null;
|
|
1337
|
+
const cardContent = mapRcsCardContentForConsumerWithResolvedTags(
|
|
1338
|
+
cardContentFromSubmit,
|
|
1339
|
+
rootRcsCardVarMappedFromSubmit,
|
|
1340
|
+
isFullModeForRcsConsumerPayload,
|
|
1341
|
+
);
|
|
1283
1342
|
const rcsContent = {
|
|
1284
1343
|
contentType,
|
|
1285
1344
|
cardType,
|
|
1286
1345
|
cardSettings,
|
|
1287
1346
|
cardContent,
|
|
1288
1347
|
};
|
|
1348
|
+
const cardVarMappedFromFirstRcsCard =
|
|
1349
|
+
firstCardFromSubmit?.cardVarMapped != null
|
|
1350
|
+
&& typeof firstCardFromSubmit.cardVarMapped === 'object'
|
|
1351
|
+
? firstCardFromSubmit.cardVarMapped
|
|
1352
|
+
: null;
|
|
1353
|
+
const includeRootRcsCardVarMappedOnConsumerPayload =
|
|
1354
|
+
cardVarMappedFromFirstRcsCard
|
|
1355
|
+
&& Object.keys(cardVarMappedFromFirstRcsCard).length > 0
|
|
1356
|
+
&& isFullModeForRcsConsumerPayload === true;
|
|
1289
1357
|
templateData = {
|
|
1290
1358
|
channel,
|
|
1291
1359
|
creativeName: name,
|
|
1292
1360
|
rcsContent,
|
|
1361
|
+
...(includeRootRcsCardVarMappedOnConsumerPayload
|
|
1362
|
+
? { rcsCardVarMapped: cardVarMappedFromFirstRcsCard }
|
|
1363
|
+
: {}),
|
|
1293
1364
|
};
|
|
1365
|
+
// Library / campaign consumers round-trip templateData via getTemplateData; include SMS fallback
|
|
1366
|
+
// so reopening the editor restores fallback text and tag mappings.
|
|
1367
|
+
// cap-campaigns-v2 API expects `smsFallBackContent.message` (see normalizeRcsMessageContentForApi).
|
|
1368
|
+
if (hasMeaningfulRcsSmsFallback(smsFallBackContent)) {
|
|
1369
|
+
const smsText =
|
|
1370
|
+
smsFallBackContent.message
|
|
1371
|
+
?? smsFallBackContent.smsContent
|
|
1372
|
+
?? smsFallBackContent.smsTemplateContent
|
|
1373
|
+
?? '';
|
|
1374
|
+
templateData.smsFallBackContent = {
|
|
1375
|
+
...smsFallBackContent,
|
|
1376
|
+
...(String(smsText).trim() !== ''
|
|
1377
|
+
? { message: String(smsText).trim() }
|
|
1378
|
+
: {}),
|
|
1379
|
+
};
|
|
1380
|
+
}
|
|
1294
1381
|
}
|
|
1295
1382
|
}
|
|
1296
1383
|
break;
|
|
@@ -1410,7 +1497,10 @@ export class Creatives extends React.Component {
|
|
|
1410
1497
|
return templateData;
|
|
1411
1498
|
};
|
|
1412
1499
|
|
|
1413
|
-
getSlideBoxContent({ mode, templateData, isFullMode }) {
|
|
1500
|
+
getSlideBoxContent({ mode, templateData, isFullMode, useLocalTemplates }) {
|
|
1501
|
+
if (useLocalTemplates && mode === 'create' && isEmpty(templateData)) {
|
|
1502
|
+
return 'templates';
|
|
1503
|
+
}
|
|
1414
1504
|
let creativesMode = isFullMode ? 'createTemplate' : 'templates';// for library mode templates page is initial mode and for full mode createTemplates
|
|
1415
1505
|
if (mode === 'create' && isFullMode) {
|
|
1416
1506
|
creativesMode = 'createTemplate';
|
|
@@ -1498,24 +1588,110 @@ export class Creatives extends React.Component {
|
|
|
1498
1588
|
getFormData = (template) => {
|
|
1499
1589
|
// Always reset isGetFormData so the child does not re-send form data on every re-render
|
|
1500
1590
|
// (e.g. when user fixes validation error by typing, we must not auto-close the slidebox)
|
|
1501
|
-
this.setState(
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
{
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1591
|
+
this.setState(
|
|
1592
|
+
(prevState) => {
|
|
1593
|
+
const next = { isGetFormData: false };
|
|
1594
|
+
if (!template.validity) {
|
|
1595
|
+
return next;
|
|
1596
|
+
}
|
|
1597
|
+
const baseTd = prevState.templateData || template;
|
|
1598
|
+
const channel = (
|
|
1599
|
+
baseTd?.type
|
|
1600
|
+
|| template?.type
|
|
1601
|
+
|| get(template, 'value.type')
|
|
1602
|
+
|| ''
|
|
1603
|
+
).toUpperCase();
|
|
1604
|
+
// Library mode: persist last submitted creatives shape so reopening still hydrates the editor
|
|
1605
|
+
// (parent may not merge getCreativesData back into templateData).
|
|
1606
|
+
if (this.props.isFullMode === false && template.value) {
|
|
1607
|
+
if (channel === constants.RCS) {
|
|
1608
|
+
const smsFallBackFromPayload = get(
|
|
1609
|
+
template.value,
|
|
1610
|
+
'versions.base.content.RCS.smsFallBackContent',
|
|
1611
|
+
);
|
|
1612
|
+
const rcsCardVarMappedFromPayload = get(
|
|
1613
|
+
template.value,
|
|
1614
|
+
'versions.base.content.RCS.rcsContent.cardContent[0].cardVarMapped',
|
|
1615
|
+
);
|
|
1616
|
+
next.templateData = {
|
|
1617
|
+
...baseTd,
|
|
1618
|
+
type: constants.RCS,
|
|
1619
|
+
name: template?.value?.name,
|
|
1620
|
+
versions: template?.value?.versions,
|
|
1621
|
+
...(smsFallBackFromPayload != null
|
|
1622
|
+
&& typeof smsFallBackFromPayload === 'object'
|
|
1623
|
+
&& Object.keys(smsFallBackFromPayload).length > 0
|
|
1624
|
+
? { smsFallBackContent: smsFallBackFromPayload }
|
|
1625
|
+
: {}),
|
|
1626
|
+
...(rcsCardVarMappedFromPayload != null
|
|
1627
|
+
&& typeof rcsCardVarMappedFromPayload === 'object'
|
|
1628
|
+
? { rcsCardVarMapped: rcsCardVarMappedFromPayload }
|
|
1629
|
+
: {}),
|
|
1630
|
+
};
|
|
1631
|
+
if (template._id) {
|
|
1632
|
+
next.templateData._id = template._id;
|
|
1633
|
+
}
|
|
1634
|
+
} else if (channel === constants.SMS) {
|
|
1635
|
+
const submittedSmsTemplateValue = template?.value;
|
|
1636
|
+
const smsVersions =
|
|
1637
|
+
submittedSmsTemplateValue?.history != null
|
|
1638
|
+
? submittedSmsTemplateValue
|
|
1639
|
+
: {
|
|
1640
|
+
base: submittedSmsTemplateValue?.base,
|
|
1641
|
+
history: submittedSmsTemplateValue?.base
|
|
1642
|
+
? [submittedSmsTemplateValue.base]
|
|
1643
|
+
: [],
|
|
1644
|
+
};
|
|
1645
|
+
next.templateData = {
|
|
1646
|
+
...baseTd,
|
|
1647
|
+
type: constants.SMS,
|
|
1648
|
+
name: baseTd?.name || 'Campaign message SMS content',
|
|
1649
|
+
versions: smsVersions,
|
|
1650
|
+
};
|
|
1651
|
+
if (template?._id) {
|
|
1652
|
+
next.templateData._id = template._id;
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
return next;
|
|
1657
|
+
},
|
|
1658
|
+
() => {
|
|
1659
|
+
if (!template.validity) {
|
|
1660
|
+
return;
|
|
1661
|
+
}
|
|
1662
|
+
const templateData = this.state.templateData ? this.state.templateData : template; //select existing or create new content
|
|
1663
|
+
const channelForConsumer = String(
|
|
1664
|
+
templateData.type
|
|
1665
|
+
|| template.type
|
|
1666
|
+
|| get(template, 'value.type')
|
|
1667
|
+
|| '',
|
|
1668
|
+
).toUpperCase();
|
|
1669
|
+
const creativesData = this.getCreativesData(
|
|
1670
|
+
channelForConsumer,
|
|
1671
|
+
template,
|
|
1672
|
+
this.state.templateData || template,
|
|
1673
|
+
);// convers data to consumer understandable format
|
|
1674
|
+
creativesData.then((data) => {
|
|
1675
|
+
this.logGTMEvent(channelForConsumer, data);
|
|
1676
|
+
this.processCentralCommsMetaId(channelForConsumer, data, {
|
|
1677
|
+
closeSlideBoxAfterSubmit: template.closeSlideBoxAfterSubmit,
|
|
1512
1678
|
});
|
|
1513
|
-
}
|
|
1514
|
-
|
|
1515
|
-
|
|
1679
|
+
});
|
|
1680
|
+
},
|
|
1681
|
+
);
|
|
1516
1682
|
}
|
|
1517
1683
|
|
|
1518
|
-
processCentralCommsMetaId = (channel, creativesData) => {
|
|
1684
|
+
processCentralCommsMetaId = (channel, creativesData, options = {}) => {
|
|
1685
|
+
const { closeSlideBoxAfterSubmit = false } = options;
|
|
1686
|
+
const maybeCloseLibrarySlideBox = () => {
|
|
1687
|
+
if (
|
|
1688
|
+
closeSlideBoxAfterSubmit
|
|
1689
|
+
&& this.props.isFullMode === false
|
|
1690
|
+
&& typeof this.handleCloseSlideBox === 'function'
|
|
1691
|
+
) {
|
|
1692
|
+
this.handleCloseSlideBox();
|
|
1693
|
+
}
|
|
1694
|
+
};
|
|
1519
1695
|
// Create the payload for the centralcommnsmetaId API call
|
|
1520
1696
|
const { isLoyaltyModule = false, loyaltyMetaData = {} } = this.props;
|
|
1521
1697
|
const { actionName, setMetaData = () => { } } = loyaltyMetaData;
|
|
@@ -1541,6 +1717,7 @@ export class Creatives extends React.Component {
|
|
|
1541
1717
|
if (result?.status?.code === 200) {
|
|
1542
1718
|
setMetaData(result);
|
|
1543
1719
|
this.props.getCreativesData(creativesData);
|
|
1720
|
+
maybeCloseLibrarySlideBox();
|
|
1544
1721
|
} else {
|
|
1545
1722
|
CapNotification.error({ message: <FormattedMessage {...messages.somethingWentWrong} /> });
|
|
1546
1723
|
}
|
|
@@ -1551,6 +1728,7 @@ export class Creatives extends React.Component {
|
|
|
1551
1728
|
} else {
|
|
1552
1729
|
// If not a loyalty module or different action, should work as usual
|
|
1553
1730
|
this.props.getCreativesData(creativesData);
|
|
1731
|
+
maybeCloseLibrarySlideBox();
|
|
1554
1732
|
}
|
|
1555
1733
|
};
|
|
1556
1734
|
|
|
@@ -1583,7 +1761,9 @@ export class Creatives extends React.Component {
|
|
|
1583
1761
|
}
|
|
1584
1762
|
this.setState((prevState) => ({
|
|
1585
1763
|
...prevState,
|
|
1586
|
-
|
|
1764
|
+
// Library mode (isFullMode === false): retain last template so reopening still has RCS payload.
|
|
1765
|
+
// Undefined isFullMode defaults to full-mode close behavior (clear templateData).
|
|
1766
|
+
...(this.props.isFullMode !== false ? { templateData: undefined } : {}),
|
|
1587
1767
|
showSlideBox: false,
|
|
1588
1768
|
liquidErrorMessage: { STANDARD_ERROR_MSG: [], LIQUID_ERROR_MSG: [] },
|
|
1589
1769
|
isLiquidValidationError: false,
|
|
@@ -1794,21 +1974,12 @@ export class Creatives extends React.Component {
|
|
|
1794
1974
|
}
|
|
1795
1975
|
|
|
1796
1976
|
showLiquidErrorInFooter = (errorMessagesFromFormBuilder, currentFormBuilderTab) => {
|
|
1797
|
-
const
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
const hasStandard = !isDeepEmpty(standardMsgs);
|
|
1801
|
-
const isLiquidValidationError = hasLiquid || hasStandard;
|
|
1802
|
-
// Don't overwrite existing liquid error with empty only for Mobile Push OLD (FormBuilder/clear calls empty there); SMS/others clear on input change
|
|
1803
|
-
const isMobilePush = this.state.currentChannel?.toUpperCase() === constants.MOBILE_PUSH;
|
|
1804
|
-
if (!hasLiquid && !hasStandard && this.state.isLiquidValidationError && isMobilePush) {
|
|
1805
|
-
return;
|
|
1806
|
-
}
|
|
1807
|
-
this.setState({
|
|
1808
|
-
isLiquidValidationError,
|
|
1809
|
-
liquidErrorMessage: errorMessagesFromFormBuilder,
|
|
1810
|
-
activeFormBuilderTab: currentFormBuilderTab === 1 ? constants.ANDROID : (currentFormBuilderTab === 2 ? constants.IOS : null), // Update activeFormBuilderTab, default to 1 if undefined
|
|
1977
|
+
const next = computeLiquidFooterUpdateFromFormBuilder(errorMessagesFromFormBuilder, currentFormBuilderTab, {
|
|
1978
|
+
previousIsLiquidValidationError: this.state.isLiquidValidationError,
|
|
1979
|
+
currentChannelUpper: this.state.currentChannel?.toUpperCase(),
|
|
1811
1980
|
});
|
|
1981
|
+
if (next == null) return;
|
|
1982
|
+
this.setState(next);
|
|
1812
1983
|
}
|
|
1813
1984
|
|
|
1814
1985
|
// Callback to update HTML Editor validation state (called from EmailWrapper)
|
|
@@ -1931,6 +2102,11 @@ export class Creatives extends React.Component {
|
|
|
1931
2102
|
inAppEditorType,
|
|
1932
2103
|
htmlEditorValidationState,
|
|
1933
2104
|
} = this.state;
|
|
2105
|
+
const useLocalTemplates = get(
|
|
2106
|
+
this.props,
|
|
2107
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
2108
|
+
get(this.props, 'useLocalTemplates', false),
|
|
2109
|
+
);
|
|
1934
2110
|
const {
|
|
1935
2111
|
isFullMode,
|
|
1936
2112
|
creativesMode,
|
|
@@ -1949,6 +2125,7 @@ export class Creatives extends React.Component {
|
|
|
1949
2125
|
smsRegister,
|
|
1950
2126
|
enableNewChannels,
|
|
1951
2127
|
eventContextTags,
|
|
2128
|
+
waitEventContextTags,
|
|
1952
2129
|
isLoyaltyModule,
|
|
1953
2130
|
loyaltyMetaData = {},
|
|
1954
2131
|
} = this.props;
|
|
@@ -1982,14 +2159,7 @@ export class Creatives extends React.Component {
|
|
|
1982
2159
|
// IMPORTANT: Never show ErrorInfoNote in footer when in HTML Editor mode, even if liquidErrorMessage exists
|
|
1983
2160
|
const shouldShowErrorInfoNoteInFooter = isHTMLEditorMode ? false : hasBEEEditorErrors;
|
|
1984
2161
|
|
|
1985
|
-
|
|
1986
|
-
const slideBoxWrapperMargin = (get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0 && get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0)
|
|
1987
|
-
? CAP_SPACE_64
|
|
1988
|
-
: get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0
|
|
1989
|
-
? CAP_SPACE_56
|
|
1990
|
-
: get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0
|
|
1991
|
-
? CAP_SPACE_32
|
|
1992
|
-
: 0;
|
|
2162
|
+
const slideBoxWrapperMargin = getSlideBoxWrapperMarginFromLiquidErrors(liquidErrorMessage);
|
|
1993
2163
|
/* TODO: Instead of passing down same props separately to each component down, write common function to these props and pass it accordingly */
|
|
1994
2164
|
|
|
1995
2165
|
// Compute anonymous user type and channel restrictions
|
|
@@ -2018,7 +2188,10 @@ export class Creatives extends React.Component {
|
|
|
2018
2188
|
<SlideBoxWrapper
|
|
2019
2189
|
slideBoxWrapperMargin={slideBoxWrapperMargin}
|
|
2020
2190
|
shouldApplyFooterMargin={shouldShowErrorInfoNoteInFooter}
|
|
2021
|
-
className={classnames(
|
|
2191
|
+
className={classnames(
|
|
2192
|
+
`${classPrefix} ${isFullMode ? 'creatives-full-mode' : 'creatives-library-mode'} ${mapTemplateCreate ? 'map-template-create' : ''}`,
|
|
2193
|
+
useLocalTemplates && slidBoxContent === 'templates' && 'creatives-slidebox--local-sms-templates',
|
|
2194
|
+
)}
|
|
2022
2195
|
>
|
|
2023
2196
|
<CapSlideBox
|
|
2024
2197
|
header={
|
|
@@ -2043,12 +2216,13 @@ export class Creatives extends React.Component {
|
|
|
2043
2216
|
smsRegister={smsRegister}
|
|
2044
2217
|
handleClose={this.handleCloseSlideBox}
|
|
2045
2218
|
moduleType={this.props.messageDetails?.type}
|
|
2219
|
+
useLocalTemplates={useLocalTemplates}
|
|
2046
2220
|
/>
|
|
2047
2221
|
)}
|
|
2048
2222
|
content={(
|
|
2049
2223
|
<SlideBoxContent
|
|
2050
2224
|
key="creatives-container-slidebox-content"
|
|
2051
|
-
onSelectTemplate={this.onSelectTemplate}
|
|
2225
|
+
onSelectTemplate={this.props.onSelectTemplate != null ? this.props.onSelectTemplate : this.onSelectTemplate}
|
|
2052
2226
|
onCreateComplete={getCreativesData}
|
|
2053
2227
|
onPreviewTemplate={this.onPreviewTemplate}
|
|
2054
2228
|
slidBoxContent={slidBoxContent}
|
|
@@ -2116,6 +2290,7 @@ export class Creatives extends React.Component {
|
|
|
2116
2290
|
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.
|
|
2117
2291
|
hostName={this.props?.hostName || ''}
|
|
2118
2292
|
eventContextTags={eventContextTags}
|
|
2293
|
+
waitEventContextTags={waitEventContextTags}
|
|
2119
2294
|
isLoyaltyModule={isLoyaltyModule}
|
|
2120
2295
|
loyaltyMetaData={loyaltyMetaData}
|
|
2121
2296
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
@@ -2124,7 +2299,8 @@ export class Creatives extends React.Component {
|
|
|
2124
2299
|
isTestAndPreviewMode={(() => this.state.isTestAndPreviewMode)()}
|
|
2125
2300
|
onHtmlEditorValidationStateChange={this.updateHtmlEditorValidationState}
|
|
2126
2301
|
onPersonalizationTokensChange={this.handlePersonalizationTokensChange}
|
|
2127
|
-
|
|
2302
|
+
localTemplatesConfig={pick(this.props.localTemplatesConfig || this.props, constants.LOCAL_TEMPLATE_CONFIG_KEYS)}
|
|
2303
|
+
/>
|
|
2128
2304
|
)}
|
|
2129
2305
|
footer={this.shouldShowFooter() ? (
|
|
2130
2306
|
<SlideBoxFooter
|
|
@@ -2208,12 +2384,32 @@ Creatives.propTypes = {
|
|
|
2208
2384
|
orgUnitId: PropTypes.number,
|
|
2209
2385
|
hostName: PropTypes.string,
|
|
2210
2386
|
eventContextTags: PropTypes.array,
|
|
2387
|
+
waitEventContextTags: PropTypes.object,
|
|
2211
2388
|
loyaltyTagFetchingDependencies: PropTypes.object,
|
|
2212
2389
|
customerType: PropTypes.string,
|
|
2213
2390
|
intl: PropTypes.shape({
|
|
2214
2391
|
formatMessage: PropTypes.func,
|
|
2215
2392
|
}),
|
|
2216
2393
|
stopValidation: PropTypes.func,
|
|
2394
|
+
// Local template list (e.g. for SMS fallback): when set, TemplatesV2 uses these instead of Redux.
|
|
2395
|
+
// All optional. Pass either localTemplatesConfig (object) or individual props below.
|
|
2396
|
+
localTemplatesConfig: PropTypes.shape({
|
|
2397
|
+
useLocalTemplates: PropTypes.bool,
|
|
2398
|
+
localTemplates: PropTypes.arrayOf(PropTypes.object),
|
|
2399
|
+
localTemplatesLoading: PropTypes.bool,
|
|
2400
|
+
localTemplatesFilterContent: PropTypes.node,
|
|
2401
|
+
localTemplatesSentinelContent: PropTypes.node,
|
|
2402
|
+
localTemplatesScrollContainerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
|
2403
|
+
localTemplatesUseSkeleton: PropTypes.bool,
|
|
2404
|
+
}),
|
|
2405
|
+
useLocalTemplates: PropTypes.bool,
|
|
2406
|
+
localTemplates: PropTypes.arrayOf(PropTypes.object),
|
|
2407
|
+
localTemplatesLoading: PropTypes.bool,
|
|
2408
|
+
localTemplatesFilterContent: PropTypes.node,
|
|
2409
|
+
localTemplatesSentinelContent: PropTypes.node,
|
|
2410
|
+
localTemplatesScrollContainerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
|
2411
|
+
localTemplatesUseSkeleton: PropTypes.bool,
|
|
2412
|
+
onSelectTemplate: PropTypes.func,
|
|
2217
2413
|
};
|
|
2218
2414
|
const mapStatesToProps = () => createStructuredSelector({
|
|
2219
2415
|
isLoading: isLoadingSelector(),
|
|
@@ -2,6 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
$classPrefix: add-creatives-section;
|
|
4
4
|
|
|
5
|
+
/* Local SMS template picker: fill slidebox height; global .v2-pagination-container uses 100vh-20rem and leaves a dead zone inside slideboxes */
|
|
6
|
+
.#{$classPrefix}.creatives-slidebox--local-sms-templates {
|
|
7
|
+
.cap-slide-box-v2-container {
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
min-height: 0;
|
|
11
|
+
max-height: 100vh;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.slidebox-content-container {
|
|
15
|
+
flex: 1;
|
|
16
|
+
min-height: 0;
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: column;
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.slidebox-content-container > div {
|
|
23
|
+
flex: 1;
|
|
24
|
+
min-height: 0;
|
|
25
|
+
display: flex;
|
|
26
|
+
flex-direction: column;
|
|
27
|
+
overflow: hidden;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* TemplatesV2 root: fill slidebox so the template grid can flex instead of using 100vh-based pagination height */
|
|
31
|
+
.slidebox-content-container .creatives-templates-container--local-sms.library-mode {
|
|
32
|
+
flex: 1;
|
|
33
|
+
min-height: 0;
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
overflow: hidden;
|
|
37
|
+
height: auto;
|
|
38
|
+
max-height: 100%;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
5
42
|
.#{$classPrefix} {
|
|
6
43
|
&.creatives-library-mode{
|
|
7
44
|
.sms-create-container, .sms-email-container{
|
|
@@ -80,5 +117,18 @@ $classPrefix: add-creatives-section;
|
|
|
80
117
|
}
|
|
81
118
|
|
|
82
119
|
.template-footer-width {
|
|
83
|
-
width: 100
|
|
120
|
+
width: 100%;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.slidebox-footer-actions {
|
|
124
|
+
display: flex;
|
|
125
|
+
flex-wrap: nowrap;
|
|
126
|
+
align-items: center;
|
|
127
|
+
gap: 0.75rem;
|
|
128
|
+
min-width: 0;
|
|
129
|
+
|
|
130
|
+
.ant-btn,
|
|
131
|
+
button {
|
|
132
|
+
flex-shrink: 0;
|
|
133
|
+
}
|
|
84
134
|
}
|