cap-creatives-ui 8.0.280 → 8.0.321
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/.github/workflows/pr-title-check.yml +88 -0
- package/app/constants/unified.js +21 -1
- package/app/containers/App/constants.js +0 -1
- package/app/containers/Login/test/index.test.js +123 -0
- package/app/containers/Login/test/selectors.test.js +165 -0
- package/app/initialState.js +0 -2
- package/app/services/api.js +6 -0
- package/app/services/tests/api.test.js +7 -0
- package/app/services/tests/getSchema.test.js +95 -0
- package/app/utils/common.js +23 -9
- package/app/utils/commonUtils.js +64 -93
- package/app/utils/tagValidations.js +83 -219
- package/app/utils/templateVarUtils.js +172 -0
- package/app/utils/tests/common.test.js +265 -323
- package/app/utils/tests/commonUtil.test.js +461 -118
- package/app/utils/tests/commonUtils.test.js +581 -0
- package/app/utils/tests/messageUtils.test.js +95 -0
- package/app/utils/tests/smsCharCount.test.js +304 -0
- package/app/utils/tests/smsCharCountV2.test.js +213 -10
- package/app/utils/tests/tagValidations.test.js +474 -357
- package/app/utils/tests/templateVarUtils.test.js +160 -0
- package/app/v2Components/CapDeviceContent/index.js +10 -7
- package/app/v2Components/CapTagList/index.js +32 -24
- package/app/v2Components/CapTagList/style.scss +48 -0
- package/app/v2Components/CapTagListWithInput/__tests__/CapTagListWithInput.test.js +63 -0
- package/app/v2Components/CapTagListWithInput/index.js +8 -0
- package/app/v2Components/CapWhatsappCTA/index.js +2 -0
- package/app/v2Components/CapWhatsappCarouselButton/index.js +32 -14
- package/app/v2Components/CapWhatsappCarouselButton/tests/index.test.js +120 -2
- package/app/v2Components/CommonTestAndPreview/CustomValuesEditor.js +70 -49
- package/app/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +39 -0
- package/app/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +606 -0
- package/app/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.scss +36 -0
- package/app/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +79 -0
- package/app/v2Components/CommonTestAndPreview/DeliverySettings/index.js +314 -0
- package/app/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +141 -0
- package/app/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +156 -0
- package/app/v2Components/CommonTestAndPreview/SendTestMessage.js +57 -1
- package/app/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +20 -1
- package/app/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +133 -4
- package/app/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +210 -4
- package/app/v2Components/CommonTestAndPreview/actions.js +20 -0
- package/app/v2Components/CommonTestAndPreview/constants.js +57 -1
- package/app/v2Components/CommonTestAndPreview/index.js +878 -156
- package/app/v2Components/CommonTestAndPreview/messages.js +41 -3
- package/app/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
- package/app/v2Components/CommonTestAndPreview/reducer.js +47 -0
- package/app/v2Components/CommonTestAndPreview/sagas.js +75 -5
- package/app/v2Components/CommonTestAndPreview/selectors.js +51 -0
- package/app/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +352 -0
- package/app/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +1156 -0
- package/app/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +334 -0
- package/app/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +576 -0
- package/app/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +156 -0
- package/app/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +199 -1
- package/app/v2Components/CommonTestAndPreview/tests/actions.test.js +50 -0
- package/app/v2Components/CommonTestAndPreview/tests/constants.test.js +18 -7
- package/app/v2Components/CommonTestAndPreview/tests/index.test.js +914 -5
- package/app/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
- package/app/v2Components/CommonTestAndPreview/tests/reducer.test.js +118 -0
- package/app/v2Components/CommonTestAndPreview/tests/sagas.test.js +146 -378
- package/app/v2Components/CommonTestAndPreview/tests/selectors.test.js +146 -0
- package/app/v2Components/ErrorInfoNote/index.js +24 -26
- package/app/v2Components/FormBuilder/index.js +182 -204
- package/app/v2Components/FormBuilder/messages.js +4 -8
- package/app/v2Components/HtmlEditor/HTMLEditor.js +7 -6
- package/app/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -1
- package/app/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +928 -17
- package/app/v2Components/HtmlEditor/components/CodeEditorPane/index.js +4 -2
- package/app/v2Components/HtmlEditor/hooks/__tests__/useValidation.test.js +452 -3
- package/app/v2Components/HtmlEditor/hooks/useValidation.js +12 -9
- package/app/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +132 -0
- package/app/v2Components/HtmlEditor/utils/htmlValidator.js +4 -2
- package/app/v2Components/SmsFallback/SmsFallbackLocalSelector.js +87 -0
- package/app/v2Components/SmsFallback/constants.js +73 -0
- package/app/v2Components/SmsFallback/index.js +956 -0
- package/app/v2Components/SmsFallback/index.scss +265 -0
- package/app/v2Components/SmsFallback/messages.js +78 -0
- package/app/v2Components/SmsFallback/smsFallbackUtils.js +107 -0
- package/app/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +50 -0
- package/app/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +147 -0
- package/app/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +304 -0
- package/app/v2Components/SmsFallback/tests/smsFallbackUi.test.js +197 -0
- package/app/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +261 -0
- package/app/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +422 -0
- package/app/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
- package/app/v2Components/TestAndPreviewSlidebox/index.js +22 -1
- package/app/v2Components/TestAndPreviewSlidebox/sagas.js +11 -4
- package/app/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +3 -1
- package/app/v2Components/VarSegmentMessageEditor/constants.js +2 -0
- package/app/v2Components/VarSegmentMessageEditor/index.js +125 -0
- package/app/v2Components/VarSegmentMessageEditor/index.scss +46 -0
- package/app/v2Containers/BeeEditor/index.js +3 -0
- package/app/v2Containers/BeePopupEditor/index.js +9 -2
- package/app/v2Containers/Cap/mockData.js +0 -14
- package/app/v2Containers/Cap/reducer.js +3 -55
- package/app/v2Containers/Cap/tests/reducer.test.js +0 -102
- package/app/v2Containers/CommunicationFlow/CommunicationFlow.js +291 -0
- package/app/v2Containers/CommunicationFlow/CommunicationFlow.scss +25 -0
- package/app/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +255 -0
- package/app/v2Containers/CommunicationFlow/constants.js +200 -0
- package/app/v2Containers/CommunicationFlow/index.js +102 -0
- package/app/v2Containers/CommunicationFlow/messages.js +346 -0
- package/app/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.js +522 -0
- package/app/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.scss +170 -0
- package/app/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/Tests/ChannelSelectionStep.test.js +796 -0
- package/app/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/index.js +5 -0
- package/app/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/CommunicationStrategyStep.js +95 -0
- package/app/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/Tests/CommunicationStrategyStep.test.js +133 -0
- package/app/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/index.js +5 -0
- package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.js +289 -0
- package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.scss +70 -0
- package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.js +319 -0
- package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.scss +69 -0
- package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +616 -0
- package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +577 -0
- package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/deliverySettingsConfig.test.js +1111 -0
- package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/deliverySettingsConfig.js +696 -0
- package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/index.js +7 -0
- package/app/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.js +102 -0
- package/app/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.scss +36 -0
- package/app/v2Containers/CommunicationFlow/steps/DynamicControlsStep/Tests/DynamicControlsStep.test.js +91 -0
- package/app/v2Containers/CommunicationFlow/steps/DynamicControlsStep/index.js +5 -0
- package/app/v2Containers/CommunicationFlow/steps/MessageTypeStep/MessageTypeStep.js +86 -0
- package/app/v2Containers/CommunicationFlow/steps/MessageTypeStep/Tests/MessageTypeStep.test.js +100 -0
- package/app/v2Containers/CommunicationFlow/steps/MessageTypeStep/index.js +5 -0
- package/app/v2Containers/CommunicationFlow/utils/getEnabledSteps.js +30 -0
- package/app/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +43 -0
- package/app/v2Containers/CreativesContainer/SlideBoxContent.js +127 -11
- package/app/v2Containers/CreativesContainer/SlideBoxFooter.js +62 -9
- package/app/v2Containers/CreativesContainer/SlideBoxHeader.js +29 -4
- package/app/v2Containers/CreativesContainer/constants.js +24 -0
- package/app/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +67 -0
- package/app/v2Containers/CreativesContainer/index.js +346 -71
- package/app/v2Containers/CreativesContainer/index.scss +51 -1
- package/app/v2Containers/CreativesContainer/messages.js +12 -0
- package/app/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
- package/app/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +69 -1
- package/app/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +443 -0
- package/app/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +110 -0
- package/app/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +147 -4
- package/app/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +363 -0
- package/app/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +57 -10
- package/app/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
- package/app/v2Containers/CreativesContainer/tests/index.test.js +71 -9
- package/app/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +125 -0
- package/app/v2Containers/Email/index.js +2 -5
- package/app/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +58 -77
- package/app/v2Containers/EmailWrapper/components/EmailWrapperView.js +3 -0
- package/app/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +158 -89
- package/app/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +16 -1
- package/app/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +17 -12
- package/app/v2Containers/EmailWrapper/index.js +4 -0
- package/app/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +1 -0
- package/app/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +133 -0
- package/app/v2Containers/FTP/index.js +2 -51
- package/app/v2Containers/FTP/messages.js +0 -4
- package/app/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +110 -155
- package/app/v2Containers/InApp/index.js +297 -118
- package/app/v2Containers/InApp/tests/index.test.js +17 -6
- package/app/v2Containers/InApp/tests/mockData.js +1 -1
- package/app/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +19 -0
- package/app/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +3 -0
- package/app/v2Containers/InAppWrapper/index.js +3 -0
- package/app/v2Containers/InappAdvance/index.js +5 -104
- package/app/v2Containers/InappAdvance/tests/index.test.js +2 -0
- package/app/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +24 -3
- package/app/v2Containers/Line/Container/Text/index.js +0 -1
- package/app/v2Containers/MobilePush/Create/index.js +105 -28
- package/app/v2Containers/MobilePush/Create/messages.js +4 -0
- package/app/v2Containers/MobilePush/Edit/index.js +250 -68
- package/app/v2Containers/MobilePush/Edit/messages.js +4 -0
- package/app/v2Containers/MobilePushNew/components/PlatformContentFields.js +36 -12
- package/app/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +68 -27
- package/app/v2Containers/MobilePushNew/index.js +78 -35
- package/app/v2Containers/MobilePushNew/messages.js +8 -0
- package/app/v2Containers/MobilepushWrapper/index.js +11 -1
- package/app/v2Containers/Rcs/constants.js +32 -1
- package/app/v2Containers/Rcs/index.js +963 -916
- package/app/v2Containers/Rcs/index.scss +85 -6
- package/app/v2Containers/Rcs/messages.js +10 -1
- package/app/v2Containers/Rcs/rcsLibraryHydrationUtils.js +205 -0
- package/app/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +41136 -1566
- package/app/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +0 -5
- package/app/v2Containers/Rcs/tests/index.test.js +41 -38
- package/app/v2Containers/Rcs/tests/mockData.js +38 -0
- package/app/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +251 -0
- package/app/v2Containers/Rcs/tests/utils.test.js +379 -1
- package/app/v2Containers/Rcs/utils.js +358 -10
- package/app/v2Containers/Sms/Create/index.js +122 -39
- package/app/v2Containers/Sms/Create/messages.js +4 -0
- package/app/v2Containers/Sms/Edit/index.js +37 -3
- package/app/v2Containers/Sms/commonMethods.js +3 -6
- package/app/v2Containers/Sms/smsFormDataHelpers.js +67 -0
- package/app/v2Containers/Sms/tests/commonMethods.test.js +122 -0
- package/app/v2Containers/Sms/tests/smsFormDataHelpers.test.js +253 -0
- package/app/v2Containers/SmsTrai/Create/index.js +9 -4
- package/app/v2Containers/SmsTrai/Create/index.scss +1 -1
- package/app/v2Containers/SmsTrai/Edit/constants.js +2 -0
- package/app/v2Containers/SmsTrai/Edit/index.js +667 -160
- package/app/v2Containers/SmsTrai/Edit/index.scss +121 -0
- package/app/v2Containers/SmsTrai/Edit/messages.js +9 -4
- package/app/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4590 -2436
- package/app/v2Containers/SmsWrapper/index.js +41 -8
- package/app/v2Containers/TagList/index.js +63 -2
- package/app/v2Containers/TagList/messages.js +8 -0
- package/app/v2Containers/TagList/tests/TagList.test.js +122 -20
- package/app/v2Containers/TagList/tests/mockdata.js +17 -0
- package/app/v2Containers/Templates/TemplatesActionBar.js +101 -0
- package/app/v2Containers/Templates/_templates.scss +61 -2
- package/app/v2Containers/Templates/actions.js +11 -0
- package/app/v2Containers/Templates/constants.js +2 -0
- package/app/v2Containers/Templates/index.js +90 -40
- package/app/v2Containers/Templates/reducer.js +3 -1
- package/app/v2Containers/Templates/sagas.js +57 -12
- package/app/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
- package/app/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1043 -1079
- package/app/v2Containers/Templates/tests/reducer.test.js +12 -0
- package/app/v2Containers/Templates/tests/sagas.test.js +193 -12
- package/app/v2Containers/Templates/tests/smsTemplatesListApi.test.js +180 -0
- package/app/v2Containers/Templates/utils/smsTemplatesListApi.js +79 -0
- package/app/v2Containers/TemplatesV2/TemplatesV2.style.js +72 -1
- package/app/v2Containers/TemplatesV2/index.js +147 -49
- package/app/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +131 -0
- package/app/v2Containers/Viber/index.js +9 -10
- package/app/v2Containers/Viber/index.scss +1 -1
- package/app/v2Containers/WebPush/Create/components/BrandIconSection.test.js +264 -0
- package/app/v2Containers/WebPush/Create/components/MessageSection.js +78 -19
- package/app/v2Containers/WebPush/Create/components/MessageSection.test.js +82 -0
- package/app/v2Containers/WebPush/Create/components/__snapshots__/BrandIconSection.test.js.snap +187 -0
- package/app/v2Containers/WebPush/Create/components/__snapshots__/MessageSection.test.js.snap +25 -17
- package/app/v2Containers/WebPush/Create/hooks/useAiraTriggerPosition.js +80 -0
- package/app/v2Containers/WebPush/Create/hooks/useAiraTriggerPosition.test.js +210 -0
- package/app/v2Containers/WebPush/Create/hooks/useTagManagement.js +1 -5
- package/app/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +0 -7
- package/app/v2Containers/WebPush/Create/index.js +36 -6
- package/app/v2Containers/WebPush/Create/index.scss +5 -0
- package/app/v2Containers/WebPush/Create/messages.js +8 -1
- package/app/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +269 -0
- package/app/v2Containers/WebPush/Create/utils/validation.js +31 -15
- package/app/v2Containers/WebPush/Create/utils/validation.test.js +72 -24
- package/app/v2Containers/Whatsapp/index.js +28 -53
- package/app/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +26939 -3982
- package/app/v2Containers/Whatsapp/tests/index.test.js +172 -0
- package/app/v2Containers/Zalo/index.js +5 -11
- package/package.json +2 -2
- package/version +9 -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,
|
|
@@ -72,31 +74,21 @@ import { BIG_HTML } from '../InApp/constants';
|
|
|
72
74
|
const classPrefix = 'add-creatives-section';
|
|
73
75
|
const CREATIVES_CONTAINER = 'creativesContainer';
|
|
74
76
|
|
|
75
|
-
const SlideBoxWrapper = styled.div`
|
|
76
|
-
.cap-slide-box-v2-container{
|
|
77
|
-
.slidebox-header, .slidebox-content-container{
|
|
78
|
-
margin-bottom: ${({ slideBoxWrapperMargin }) => `${slideBoxWrapperMargin}`};
|
|
79
|
-
padding: 0 rem;
|
|
80
|
-
&.has-footer{
|
|
81
|
-
overflow-x: hidden;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
.slidebox-footer{
|
|
85
|
-
/* Only apply margin-bottom to footer when ErrorInfoNote is shown in footer (BEE editor) */
|
|
86
|
-
/* For HTML Editor, errors are shown in ValidationErrorDisplay (inside content area), so no footer margin needed */
|
|
87
|
-
margin-bottom: ${({ shouldApplyFooterMargin }) => (shouldApplyFooterMargin ? `${CAP_SPACE_16}` : '0')};
|
|
88
|
-
padding: 0 rem;
|
|
89
|
-
&.has-footer{
|
|
90
|
-
overflow-x: hidden;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
`;
|
|
95
77
|
export class Creatives extends React.Component {
|
|
96
78
|
constructor(props) {
|
|
97
79
|
super(props);
|
|
98
80
|
|
|
99
|
-
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
|
+
});
|
|
100
92
|
|
|
101
93
|
this.state = {
|
|
102
94
|
isLoadingContent: true,
|
|
@@ -130,8 +122,8 @@ export class Creatives extends React.Component {
|
|
|
130
122
|
validationComplete: false, // Flag to track if validation has completed
|
|
131
123
|
errorsAcknowledged: false, // Flag to track if user has acknowledged errors by clicking redirection icon
|
|
132
124
|
},
|
|
125
|
+
hasPersonalizationTokenError: false, // Track personalization token errors in form
|
|
133
126
|
};
|
|
134
|
-
this.liquidFlow = Boolean(commonUtil.hasLiquidSupportFeature());
|
|
135
127
|
this.creativesTemplateSteps = {
|
|
136
128
|
1: 'modeSelection',
|
|
137
129
|
2: 'templateSelection', // only for email in current flows wil be used for mpush, line and wechat as well.
|
|
@@ -143,7 +135,13 @@ export class Creatives extends React.Component {
|
|
|
143
135
|
}
|
|
144
136
|
|
|
145
137
|
componentWillUnmount() {
|
|
146
|
-
|
|
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) {
|
|
147
145
|
this.props.templateActions.resetTemplateStoreData();
|
|
148
146
|
}
|
|
149
147
|
this.props.globalActions.clearMetaEntities();
|
|
@@ -255,12 +253,23 @@ export class Creatives extends React.Component {
|
|
|
255
253
|
};
|
|
256
254
|
|
|
257
255
|
onShowTemplates = () => {
|
|
258
|
-
this.setState({
|
|
256
|
+
this.setState({
|
|
257
|
+
slidBoxContent: 'templates',
|
|
258
|
+
showSlideBox: true,
|
|
259
|
+
isGetFormData: false,
|
|
260
|
+
liquidErrorMessage: { STANDARD_ERROR_MSG: [], LIQUID_ERROR_MSG: [] },
|
|
261
|
+
isLiquidValidationError: false,
|
|
262
|
+
});
|
|
259
263
|
this.resetStep();
|
|
260
264
|
};
|
|
261
265
|
|
|
262
266
|
onChannelChange = (channel) => {
|
|
263
|
-
this.setState({
|
|
267
|
+
this.setState({
|
|
268
|
+
currentChannel: channel,
|
|
269
|
+
templateData: null,
|
|
270
|
+
liquidErrorMessage: { STANDARD_ERROR_MSG: [], LIQUID_ERROR_MSG: [] },
|
|
271
|
+
isLiquidValidationError: false,
|
|
272
|
+
});
|
|
264
273
|
}
|
|
265
274
|
|
|
266
275
|
onCreateNextStep = () => {
|
|
@@ -734,14 +743,41 @@ export class Creatives extends React.Component {
|
|
|
734
743
|
smsFallBackContent = {},
|
|
735
744
|
creativeName = "",
|
|
736
745
|
channel = constants.RCS,
|
|
746
|
+
rcsCardVarMapped,
|
|
737
747
|
} = templateData || {};
|
|
738
|
-
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;
|
|
739
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;
|
|
740
775
|
|
|
741
776
|
creativesTemplateData = {
|
|
742
777
|
type: channel,
|
|
743
778
|
edit: true,
|
|
744
779
|
name: creativeName,
|
|
780
|
+
...(includeRootRcsCardVarMapped ? { rcsCardVarMapped: mergedCardVarMapped } : {}),
|
|
745
781
|
versions: {
|
|
746
782
|
base: {
|
|
747
783
|
content: {
|
|
@@ -751,6 +787,7 @@ export class Creatives extends React.Component {
|
|
|
751
787
|
cardContent: [
|
|
752
788
|
{
|
|
753
789
|
...cardContent,
|
|
790
|
+
...(mergedCardVarMapped ? { cardVarMapped: mergedCardVarMapped } : {}),
|
|
754
791
|
Status,
|
|
755
792
|
},
|
|
756
793
|
],
|
|
@@ -901,7 +938,10 @@ export class Creatives extends React.Component {
|
|
|
901
938
|
return newExpandableDetails;
|
|
902
939
|
}
|
|
903
940
|
|
|
904
|
-
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();
|
|
905
945
|
let templateData = { channel };
|
|
906
946
|
switch (channel) {
|
|
907
947
|
case constants.SMS:
|
|
@@ -1243,26 +1283,101 @@ export class Creatives extends React.Component {
|
|
|
1243
1283
|
break;
|
|
1244
1284
|
case constants.RCS: {
|
|
1245
1285
|
if (template.value) {
|
|
1246
|
-
const {
|
|
1247
|
-
} = template.value || {};
|
|
1248
|
-
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 };
|
|
1249
1327
|
const {
|
|
1250
|
-
cardContent = [],
|
|
1328
|
+
cardContent: cardContentFromSubmit = [],
|
|
1251
1329
|
contentType = "",
|
|
1252
1330
|
cardType = "",
|
|
1253
1331
|
cardSettings = {},
|
|
1254
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
|
+
);
|
|
1255
1342
|
const rcsContent = {
|
|
1256
1343
|
contentType,
|
|
1257
1344
|
cardType,
|
|
1258
1345
|
cardSettings,
|
|
1259
1346
|
cardContent,
|
|
1260
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;
|
|
1261
1357
|
templateData = {
|
|
1262
1358
|
channel,
|
|
1263
1359
|
creativeName: name,
|
|
1264
1360
|
rcsContent,
|
|
1361
|
+
...(includeRootRcsCardVarMappedOnConsumerPayload
|
|
1362
|
+
? { rcsCardVarMapped: cardVarMappedFromFirstRcsCard }
|
|
1363
|
+
: {}),
|
|
1265
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
|
+
}
|
|
1266
1381
|
}
|
|
1267
1382
|
}
|
|
1268
1383
|
break;
|
|
@@ -1382,7 +1497,10 @@ export class Creatives extends React.Component {
|
|
|
1382
1497
|
return templateData;
|
|
1383
1498
|
};
|
|
1384
1499
|
|
|
1385
|
-
getSlideBoxContent({ mode, templateData, isFullMode }) {
|
|
1500
|
+
getSlideBoxContent({ mode, templateData, isFullMode, useLocalTemplates }) {
|
|
1501
|
+
if (useLocalTemplates && mode === 'create' && isEmpty(templateData)) {
|
|
1502
|
+
return 'templates';
|
|
1503
|
+
}
|
|
1386
1504
|
let creativesMode = isFullMode ? 'createTemplate' : 'templates';// for library mode templates page is initial mode and for full mode createTemplates
|
|
1387
1505
|
if (mode === 'create' && isFullMode) {
|
|
1388
1506
|
creativesMode = 'createTemplate';
|
|
@@ -1468,25 +1586,112 @@ export class Creatives extends React.Component {
|
|
|
1468
1586
|
}
|
|
1469
1587
|
|
|
1470
1588
|
getFormData = (template) => {
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
}
|
|
1476
|
-
()
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1589
|
+
// Always reset isGetFormData so the child does not re-send form data on every re-render
|
|
1590
|
+
// (e.g. when user fixes validation error by typing, we must not auto-close the slidebox)
|
|
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,
|
|
1483
1678
|
});
|
|
1484
|
-
}
|
|
1485
|
-
|
|
1486
|
-
|
|
1679
|
+
});
|
|
1680
|
+
},
|
|
1681
|
+
);
|
|
1487
1682
|
}
|
|
1488
1683
|
|
|
1489
|
-
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
|
+
};
|
|
1490
1695
|
// Create the payload for the centralcommnsmetaId API call
|
|
1491
1696
|
const { isLoyaltyModule = false, loyaltyMetaData = {} } = this.props;
|
|
1492
1697
|
const { actionName, setMetaData = () => { } } = loyaltyMetaData;
|
|
@@ -1512,6 +1717,7 @@ export class Creatives extends React.Component {
|
|
|
1512
1717
|
if (result?.status?.code === 200) {
|
|
1513
1718
|
setMetaData(result);
|
|
1514
1719
|
this.props.getCreativesData(creativesData);
|
|
1720
|
+
maybeCloseLibrarySlideBox();
|
|
1515
1721
|
} else {
|
|
1516
1722
|
CapNotification.error({ message: <FormattedMessage {...messages.somethingWentWrong} /> });
|
|
1517
1723
|
}
|
|
@@ -1522,6 +1728,7 @@ export class Creatives extends React.Component {
|
|
|
1522
1728
|
} else {
|
|
1523
1729
|
// If not a loyalty module or different action, should work as usual
|
|
1524
1730
|
this.props.getCreativesData(creativesData);
|
|
1731
|
+
maybeCloseLibrarySlideBox();
|
|
1525
1732
|
}
|
|
1526
1733
|
};
|
|
1527
1734
|
|
|
@@ -1554,8 +1761,12 @@ export class Creatives extends React.Component {
|
|
|
1554
1761
|
}
|
|
1555
1762
|
this.setState((prevState) => ({
|
|
1556
1763
|
...prevState,
|
|
1557
|
-
|
|
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 } : {}),
|
|
1558
1767
|
showSlideBox: false,
|
|
1768
|
+
liquidErrorMessage: { STANDARD_ERROR_MSG: [], LIQUID_ERROR_MSG: [] },
|
|
1769
|
+
isLiquidValidationError: false,
|
|
1559
1770
|
}), () => this.props.handleCloseCreatives(reloadTemplates));
|
|
1560
1771
|
};
|
|
1561
1772
|
|
|
@@ -1763,11 +1974,12 @@ export class Creatives extends React.Component {
|
|
|
1763
1974
|
}
|
|
1764
1975
|
|
|
1765
1976
|
showLiquidErrorInFooter = (errorMessagesFromFormBuilder, currentFormBuilderTab) => {
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
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(),
|
|
1770
1980
|
});
|
|
1981
|
+
if (next == null) return;
|
|
1982
|
+
this.setState(next);
|
|
1771
1983
|
}
|
|
1772
1984
|
|
|
1773
1985
|
// Callback to update HTML Editor validation state (called from EmailWrapper)
|
|
@@ -1777,6 +1989,12 @@ export class Creatives extends React.Component {
|
|
|
1777
1989
|
});
|
|
1778
1990
|
}
|
|
1779
1991
|
|
|
1992
|
+
handlePersonalizationTokensChange = (hasTokens) => {
|
|
1993
|
+
this.setState({
|
|
1994
|
+
hasPersonalizationTokenError: hasTokens,
|
|
1995
|
+
});
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1780
1998
|
shouldShowContinueFooter = () => { // only for email for now, has to be modified according to channel
|
|
1781
1999
|
const {
|
|
1782
2000
|
slidBoxContent, templateStep, currentChannel, emailCreateMode, mobilePushCreateMode, inAppEditorType, weChatTemplateType,
|
|
@@ -1884,6 +2102,11 @@ export class Creatives extends React.Component {
|
|
|
1884
2102
|
inAppEditorType,
|
|
1885
2103
|
htmlEditorValidationState,
|
|
1886
2104
|
} = this.state;
|
|
2105
|
+
const useLocalTemplates = get(
|
|
2106
|
+
this.props,
|
|
2107
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
2108
|
+
get(this.props, 'useLocalTemplates', false),
|
|
2109
|
+
);
|
|
1887
2110
|
const {
|
|
1888
2111
|
isFullMode,
|
|
1889
2112
|
creativesMode,
|
|
@@ -1902,6 +2125,7 @@ export class Creatives extends React.Component {
|
|
|
1902
2125
|
smsRegister,
|
|
1903
2126
|
enableNewChannels,
|
|
1904
2127
|
eventContextTags,
|
|
2128
|
+
waitEventContextTags,
|
|
1905
2129
|
isLoyaltyModule,
|
|
1906
2130
|
loyaltyMetaData = {},
|
|
1907
2131
|
} = this.props;
|
|
@@ -1935,20 +2159,39 @@ export class Creatives extends React.Component {
|
|
|
1935
2159
|
// IMPORTANT: Never show ErrorInfoNote in footer when in HTML Editor mode, even if liquidErrorMessage exists
|
|
1936
2160
|
const shouldShowErrorInfoNoteInFooter = isHTMLEditorMode ? false : hasBEEEditorErrors;
|
|
1937
2161
|
|
|
1938
|
-
|
|
1939
|
-
const slideBoxWrapperMargin = (get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0 && get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0)
|
|
1940
|
-
? CAP_SPACE_64
|
|
1941
|
-
: get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0
|
|
1942
|
-
? CAP_SPACE_56
|
|
1943
|
-
: get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0
|
|
1944
|
-
? CAP_SPACE_32
|
|
1945
|
-
: 0;
|
|
2162
|
+
const slideBoxWrapperMargin = getSlideBoxWrapperMarginFromLiquidErrors(liquidErrorMessage);
|
|
1946
2163
|
/* TODO: Instead of passing down same props separately to each component down, write common function to these props and pass it accordingly */
|
|
2164
|
+
|
|
2165
|
+
// Compute anonymous user type and channel restrictions
|
|
2166
|
+
const { customerType = '' } = this.props;
|
|
2167
|
+
const isAnonymousType = [constants.VISITOR, constants.MIXED].includes(customerType);
|
|
2168
|
+
const restrictPersonalization = isAnonymousType;
|
|
2169
|
+
|
|
2170
|
+
// For anonymous users, only MOBILEPUSH and WEBPUSH channels are allowed
|
|
2171
|
+
let updatedChannelsToHide = [...(channelsToHide || [])];
|
|
2172
|
+
if (isAnonymousType) {
|
|
2173
|
+
const allowedChannels = constants.ALLOWED_CHANNELS_FOR_ANONYMOUS;
|
|
2174
|
+
const allChannels = constants.ALL_CHANNELS_NEW;
|
|
2175
|
+
const channelsToRemove = allChannels.filter((channel) => !allowedChannels.includes(channel));
|
|
2176
|
+
updatedChannelsToHide = [...new Set([...updatedChannelsToHide, ...channelsToRemove])];
|
|
2177
|
+
}
|
|
2178
|
+
// In library mode (journey module), hide mobilepush and wechat channels from engagement blocks
|
|
2179
|
+
// unless the current engagement block itself is that channel (e.g. mobilepush block should show mobilepush tab)
|
|
2180
|
+
const isJourneyModule = (this.props.messageDetails?.type || '').toLowerCase() === constants.JOURNEY;
|
|
2181
|
+
if (!isFullMode && isJourneyModule) {
|
|
2182
|
+
const currentChannelNorm = (currentChannel || '').toLowerCase();
|
|
2183
|
+
const journeyChannelsToHide = ['mobilepush', 'wechat'].filter((ch) => ch !== currentChannelNorm);
|
|
2184
|
+
updatedChannelsToHide = [...new Set([...updatedChannelsToHide, ...journeyChannelsToHide])];
|
|
2185
|
+
}
|
|
2186
|
+
|
|
1947
2187
|
return (
|
|
1948
2188
|
<SlideBoxWrapper
|
|
1949
2189
|
slideBoxWrapperMargin={slideBoxWrapperMargin}
|
|
1950
2190
|
shouldApplyFooterMargin={shouldShowErrorInfoNoteInFooter}
|
|
1951
|
-
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
|
+
)}
|
|
1952
2195
|
>
|
|
1953
2196
|
<CapSlideBox
|
|
1954
2197
|
header={
|
|
@@ -1973,12 +2216,13 @@ export class Creatives extends React.Component {
|
|
|
1973
2216
|
smsRegister={smsRegister}
|
|
1974
2217
|
handleClose={this.handleCloseSlideBox}
|
|
1975
2218
|
moduleType={this.props.messageDetails?.type}
|
|
2219
|
+
useLocalTemplates={useLocalTemplates}
|
|
1976
2220
|
/>
|
|
1977
2221
|
)}
|
|
1978
2222
|
content={(
|
|
1979
2223
|
<SlideBoxContent
|
|
1980
2224
|
key="creatives-container-slidebox-content"
|
|
1981
|
-
onSelectTemplate={this.onSelectTemplate}
|
|
2225
|
+
onSelectTemplate={this.props.onSelectTemplate != null ? this.props.onSelectTemplate : this.onSelectTemplate}
|
|
1982
2226
|
onCreateComplete={getCreativesData}
|
|
1983
2227
|
onPreviewTemplate={this.onPreviewTemplate}
|
|
1984
2228
|
slidBoxContent={slidBoxContent}
|
|
@@ -2014,10 +2258,13 @@ export class Creatives extends React.Component {
|
|
|
2014
2258
|
mobilePushCreateMode={mobilePushCreateMode}
|
|
2015
2259
|
showTemplateName={this.showTemplateName}
|
|
2016
2260
|
onValidationFail={this.onValidationFail}
|
|
2017
|
-
channelsToHide={
|
|
2261
|
+
channelsToHide={updatedChannelsToHide}
|
|
2018
2262
|
forwardedTags={forwardedTags}
|
|
2019
2263
|
selectedOfferDetails={selectedOfferDetails}
|
|
2020
2264
|
channelsToDisable={channelsToDisable}
|
|
2265
|
+
restrictPersonalization={restrictPersonalization}
|
|
2266
|
+
isAnonymousType={isAnonymousType}
|
|
2267
|
+
customerType={customerType}
|
|
2021
2268
|
weChatTemplateType={weChatTemplateType}
|
|
2022
2269
|
onWechatTemplateChange={this.onWechatTemplateChange}
|
|
2023
2270
|
weChatMaptemplateStep={weChatMaptemplateStep}
|
|
@@ -2043,6 +2290,7 @@ export class Creatives extends React.Component {
|
|
|
2043
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.
|
|
2044
2291
|
hostName={this.props?.hostName || ''}
|
|
2045
2292
|
eventContextTags={eventContextTags}
|
|
2293
|
+
waitEventContextTags={waitEventContextTags}
|
|
2046
2294
|
isLoyaltyModule={isLoyaltyModule}
|
|
2047
2295
|
loyaltyMetaData={loyaltyMetaData}
|
|
2048
2296
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
@@ -2050,7 +2298,9 @@ export class Creatives extends React.Component {
|
|
|
2050
2298
|
handleCloseTestAndPreview={this.handleCloseTestAndPreview}
|
|
2051
2299
|
isTestAndPreviewMode={(() => this.state.isTestAndPreviewMode)()}
|
|
2052
2300
|
onHtmlEditorValidationStateChange={this.updateHtmlEditorValidationState}
|
|
2053
|
-
|
|
2301
|
+
onPersonalizationTokensChange={this.handlePersonalizationTokensChange}
|
|
2302
|
+
localTemplatesConfig={pick(this.props.localTemplatesConfig || this.props, constants.LOCAL_TEMPLATE_CONFIG_KEYS)}
|
|
2303
|
+
/>
|
|
2054
2304
|
)}
|
|
2055
2305
|
footer={this.shouldShowFooter() ? (
|
|
2056
2306
|
<SlideBoxFooter
|
|
@@ -2082,6 +2332,10 @@ export class Creatives extends React.Component {
|
|
|
2082
2332
|
})()}
|
|
2083
2333
|
htmlEditorValidationState={htmlEditorValidationState}
|
|
2084
2334
|
isCreatingTemplate={slidBoxContent === 'createTemplate' && currentChannel.toUpperCase() === constants.EMAIL}
|
|
2335
|
+
restrictPersonalization={restrictPersonalization}
|
|
2336
|
+
isAnonymousType={isAnonymousType}
|
|
2337
|
+
templateData={templateData}
|
|
2338
|
+
hasPersonalizationTokenError={this.state.hasPersonalizationTokenError}
|
|
2085
2339
|
/>
|
|
2086
2340
|
) : isLiquidValidationError && (
|
|
2087
2341
|
<CapRow className="template-footer-width">
|
|
@@ -2130,11 +2384,32 @@ Creatives.propTypes = {
|
|
|
2130
2384
|
orgUnitId: PropTypes.number,
|
|
2131
2385
|
hostName: PropTypes.string,
|
|
2132
2386
|
eventContextTags: PropTypes.array,
|
|
2387
|
+
waitEventContextTags: PropTypes.object,
|
|
2133
2388
|
loyaltyTagFetchingDependencies: PropTypes.object,
|
|
2389
|
+
customerType: PropTypes.string,
|
|
2134
2390
|
intl: PropTypes.shape({
|
|
2135
2391
|
formatMessage: PropTypes.func,
|
|
2136
2392
|
}),
|
|
2137
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,
|
|
2138
2413
|
};
|
|
2139
2414
|
const mapStatesToProps = () => createStructuredSelector({
|
|
2140
2415
|
isLoading: isLoadingSelector(),
|