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