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
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
import messages from "../messages";
|
|
25
25
|
import MediaUploaders from "./MediaUploaders";
|
|
26
26
|
import CtaButtons from "./CtaButtons";
|
|
27
|
+
import { hasPersonalizationTags } from "../../../utils/commonUtils";
|
|
27
28
|
|
|
28
29
|
const PlatformContentFields = ({
|
|
29
30
|
deviceType,
|
|
@@ -40,8 +41,17 @@ const PlatformContentFields = ({
|
|
|
40
41
|
tags,
|
|
41
42
|
injectedTags,
|
|
42
43
|
selectedOfferDetails,
|
|
44
|
+
// new prop to disable personalization features for anonymous users
|
|
45
|
+
restrictPersonalization = false,
|
|
43
46
|
}) => {
|
|
44
47
|
const { title: titleError, message: messageError } = errors;
|
|
48
|
+
|
|
49
|
+
const titleErrorToShow = titleError || (restrictPersonalization && hasPersonalizationTags(content.title)
|
|
50
|
+
? formatMessage(messages.personalizationTagsErrorMessage)
|
|
51
|
+
: "");
|
|
52
|
+
const messageErrorToShow = messageError || (restrictPersonalization && hasPersonalizationTags(content.message)
|
|
53
|
+
? formatMessage(messages.personalizationTagsErrorMessage)
|
|
54
|
+
: "");
|
|
45
55
|
const {
|
|
46
56
|
handleTitleChange,
|
|
47
57
|
handleMessageChange,
|
|
@@ -139,14 +149,19 @@ const PlatformContentFields = ({
|
|
|
139
149
|
);
|
|
140
150
|
|
|
141
151
|
const getTagList = useCallback(
|
|
142
|
-
(index) =>
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
152
|
+
(index) => {
|
|
153
|
+
const disableMsg = restrictPersonalization ? formatMessage(messages.personalizationNotSupportedAnonymous) : undefined;
|
|
154
|
+
return (
|
|
155
|
+
<TagList
|
|
156
|
+
{...tagListProps}
|
|
157
|
+
disabled={restrictPersonalization}
|
|
158
|
+
disableTooltipMsg={disableMsg}
|
|
159
|
+
onTagSelect={(value) => onTagSelect(value, index)}
|
|
160
|
+
onContextChange={handleOnTagsContextChange}
|
|
161
|
+
/>
|
|
162
|
+
);
|
|
163
|
+
},
|
|
164
|
+
[tagListProps, onTagSelect, handleOnTagsContextChange, restrictPersonalization, formatMessage]
|
|
150
165
|
);
|
|
151
166
|
|
|
152
167
|
const onButtonTagSelect = useCallback(
|
|
@@ -178,9 +193,9 @@ const PlatformContentFields = ({
|
|
|
178
193
|
size="default"
|
|
179
194
|
isRequired
|
|
180
195
|
errorMessage={
|
|
181
|
-
|
|
196
|
+
titleErrorToShow && (
|
|
182
197
|
<CapError className="mobile-push-template-title-error">
|
|
183
|
-
{
|
|
198
|
+
{titleErrorToShow}
|
|
184
199
|
</CapError>
|
|
185
200
|
)
|
|
186
201
|
}
|
|
@@ -202,9 +217,9 @@ const PlatformContentFields = ({
|
|
|
202
217
|
size="default"
|
|
203
218
|
isRequired
|
|
204
219
|
errorMessage={
|
|
205
|
-
|
|
220
|
+
messageErrorToShow && (
|
|
206
221
|
<CapError className="mobile-push-template-message-error">
|
|
207
|
-
{
|
|
222
|
+
{messageErrorToShow}
|
|
208
223
|
</CapError>
|
|
209
224
|
)
|
|
210
225
|
}
|
|
@@ -314,6 +329,10 @@ const PlatformContentFields = ({
|
|
|
314
329
|
tags={tags}
|
|
315
330
|
injectedTags={injectedTags}
|
|
316
331
|
selectedOfferDetails={selectedOfferDetails}
|
|
332
|
+
disabled={restrictPersonalization}
|
|
333
|
+
disableTooltipMsg={
|
|
334
|
+
restrictPersonalization ? formatMessage(messages.personalizationNotSupportedAnonymous) : undefined
|
|
335
|
+
}
|
|
317
336
|
/>
|
|
318
337
|
</CapRow>
|
|
319
338
|
<CapInput
|
|
@@ -389,6 +408,11 @@ PlatformContentFields.propTypes = {
|
|
|
389
408
|
linkProps: PropTypes.object.isRequired,
|
|
390
409
|
sameContent: PropTypes.bool.isRequired,
|
|
391
410
|
formatMessage: PropTypes.func.isRequired,
|
|
411
|
+
restrictPersonalization: PropTypes.bool,
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
PlatformContentFields.defaultProps = {
|
|
415
|
+
restrictPersonalization: false,
|
|
392
416
|
};
|
|
393
417
|
|
|
394
418
|
export default PlatformContentFields;
|
|
@@ -11,25 +11,29 @@ import {
|
|
|
11
11
|
jest.mock("@capillarytech/cap-ui-library/CapRow", () => ({ children }) => <div>{children}</div>);
|
|
12
12
|
jest.mock("@capillarytech/cap-ui-library/CapColumn", () => ({ children }) => <div>{children}</div>);
|
|
13
13
|
jest.mock("@capillarytech/cap-ui-library/CapInput", () => {
|
|
14
|
-
const MockCapInput = ({
|
|
14
|
+
const MockCapInput = ({
|
|
15
|
+
value, onChange, errorMessage, error, ...props
|
|
16
|
+
}) => (
|
|
15
17
|
<div>
|
|
16
18
|
<input value={value || ""} onChange={onChange} error={error} {...props} />
|
|
17
19
|
{(errorMessage || error) && <div data-testid="error-message">{errorMessage || error}</div>}
|
|
18
20
|
</div>
|
|
19
21
|
);
|
|
20
|
-
|
|
21
|
-
MockCapInput.TextArea = ({
|
|
22
|
+
|
|
23
|
+
MockCapInput.TextArea = ({
|
|
24
|
+
value, onChange, errorMessage, error, ...props
|
|
25
|
+
}) => (
|
|
22
26
|
<div>
|
|
23
|
-
<textarea
|
|
24
|
-
value={value || ""}
|
|
25
|
-
onChange={onChange}
|
|
27
|
+
<textarea
|
|
28
|
+
value={value || ""}
|
|
29
|
+
onChange={onChange}
|
|
26
30
|
data-testid="message-textarea"
|
|
27
31
|
{...props}
|
|
28
32
|
/>
|
|
29
33
|
{(errorMessage || error) && <div data-testid="error-message">{errorMessage || error}</div>}
|
|
30
34
|
</div>
|
|
31
35
|
);
|
|
32
|
-
|
|
36
|
+
|
|
33
37
|
return MockCapInput;
|
|
34
38
|
});
|
|
35
39
|
jest.mock("@capillarytech/cap-ui-library/CapHeading", () => ({ children }) => <div>{children}</div>);
|
|
@@ -56,17 +60,19 @@ jest.mock("@capillarytech/cap-ui-library/CapLabel", () => ({ children }) => <lab
|
|
|
56
60
|
jest.mock("@capillarytech/cap-ui-library/CapInfoNote", () => ({ message }) => <div data-testid="info-note">{message}</div>);
|
|
57
61
|
|
|
58
62
|
// Mock child components
|
|
59
|
-
jest.mock("../../../TagList", () => ({
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
jest.mock("../../../TagList", () => ({
|
|
64
|
+
onTagSelect, onContextChange, label, disabled, disableTooltipMsg, ...props
|
|
65
|
+
}) => (
|
|
66
|
+
<div data-testid="tag-list" data-disabled={disabled || false} data-tooltip={disableTooltipMsg || ''}>
|
|
67
|
+
<button
|
|
68
|
+
type="button"
|
|
63
69
|
onClick={() => onTagSelect && onTagSelect('test_tag')}
|
|
64
70
|
data-testid="tag-select-button"
|
|
65
71
|
>
|
|
66
72
|
Select Tag
|
|
67
73
|
</button>
|
|
68
|
-
<button
|
|
69
|
-
type="button"
|
|
74
|
+
<button
|
|
75
|
+
type="button"
|
|
70
76
|
onClick={() => onContextChange && onContextChange('test_context')}
|
|
71
77
|
data-testid="tag-context-button"
|
|
72
78
|
>
|
|
@@ -99,6 +105,8 @@ jest.mock("../../messages", () => ({
|
|
|
99
105
|
deepLinkKeysPlaceholder: { id: "deepLinkKeysPlaceholder", defaultMessage: "Enter {key}" },
|
|
100
106
|
deepLinkKeysRequired: { id: "deepLinkKeysRequired", defaultMessage: "Deep link keys are required" },
|
|
101
107
|
addLabels: { id: "addLabels", defaultMessage: "Add labels" },
|
|
108
|
+
personalizationTagsErrorMessage: { id: "personalizationTagsErrorMessage", defaultMessage: "Personalization tags are not supported for anonymous customers, please remove the tags." },
|
|
109
|
+
personalizationNotSupportedAnonymous: { id: "personalizationNotSupportedAnonymous", defaultMessage: "Personalization tags are not supported for anonymous customers" },
|
|
102
110
|
}));
|
|
103
111
|
|
|
104
112
|
// Mock constants
|
|
@@ -171,6 +179,7 @@ describe("PlatformContentFields", () => {
|
|
|
171
179
|
tags: ["tag1", "tag2"],
|
|
172
180
|
injectedTags: [],
|
|
173
181
|
selectedOfferDetails: null,
|
|
182
|
+
restrictPersonalization: false,
|
|
174
183
|
};
|
|
175
184
|
|
|
176
185
|
const renderComponent = (props = {}) => render(
|
|
@@ -255,6 +264,38 @@ describe("PlatformContentFields", () => {
|
|
|
255
264
|
|
|
256
265
|
expect(getByTestId("cap-error")).toHaveTextContent("Message is required");
|
|
257
266
|
});
|
|
267
|
+
|
|
268
|
+
it("should show inline personalization error when restricted and tokens present", () => {
|
|
269
|
+
const personalizationErrorMsg = "Personalization tags are not supported for anonymous customers";
|
|
270
|
+
const formatMessageStub = jest.fn((msg) => msg?.defaultMessage ?? "");
|
|
271
|
+
const { container } = renderComponent({
|
|
272
|
+
restrictPersonalization: true,
|
|
273
|
+
content: { ...defaultProps.content, message: "Hello {{user}}" },
|
|
274
|
+
formatMessage: formatMessageStub,
|
|
275
|
+
});
|
|
276
|
+
expect(container.textContent).toContain(personalizationErrorMsg);
|
|
277
|
+
expect(formatMessageStub).toHaveBeenCalledWith(
|
|
278
|
+
expect.objectContaining({ defaultMessage: expect.stringContaining("Personalization tags") })
|
|
279
|
+
);
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
describe("Personalization restriction", () => {
|
|
284
|
+
it("disables tag list and shows tooltip when restrictPersonalization true", () => {
|
|
285
|
+
const formatMessageForTooltip = jest.fn((msg) => msg?.defaultMessage ?? "");
|
|
286
|
+
const { getAllByTestId } = renderComponent({
|
|
287
|
+
restrictPersonalization: true,
|
|
288
|
+
formatMessage: formatMessageForTooltip,
|
|
289
|
+
});
|
|
290
|
+
const tagLists = getAllByTestId("tag-list");
|
|
291
|
+
expect(tagLists.length).toBeGreaterThan(0);
|
|
292
|
+
tagLists.forEach((tag) => {
|
|
293
|
+
expect(tag).toHaveAttribute('data-disabled', 'true');
|
|
294
|
+
});
|
|
295
|
+
expect(formatMessageForTooltip).toHaveBeenCalledWith(
|
|
296
|
+
expect.objectContaining({ defaultMessage: "Personalization tags are not supported for anonymous customers" })
|
|
297
|
+
);
|
|
298
|
+
});
|
|
258
299
|
});
|
|
259
300
|
|
|
260
301
|
describe("Media Type Selection", () => {
|
|
@@ -390,7 +431,7 @@ describe("PlatformContentFields", () => {
|
|
|
390
431
|
// Deep link keys handling - covering lines 109-120, 134, 297-303
|
|
391
432
|
it('should handle deep link keys with array from selection', () => {
|
|
392
433
|
const mockDeepLink = [
|
|
393
|
-
{ value: 'test-deep-link', keys: ['key1', 'key2'] }
|
|
434
|
+
{ value: 'test-deep-link', keys: ['key1', 'key2'] },
|
|
394
435
|
];
|
|
395
436
|
const mockLinkProps = {
|
|
396
437
|
deepLink: mockDeepLink,
|
|
@@ -428,7 +469,7 @@ describe("PlatformContentFields", () => {
|
|
|
428
469
|
|
|
429
470
|
it('should handle deep link keys with single key from selection', () => {
|
|
430
471
|
const mockDeepLink = [
|
|
431
|
-
{ value: 'test-deep-link', keys: 'single-key' }
|
|
472
|
+
{ value: 'test-deep-link', keys: 'single-key' },
|
|
432
473
|
];
|
|
433
474
|
const mockLinkProps = {
|
|
434
475
|
deepLink: mockDeepLink,
|
|
@@ -466,7 +507,7 @@ describe("PlatformContentFields", () => {
|
|
|
466
507
|
|
|
467
508
|
it('should handle deep link keys with no keys from selection but existing keys', () => {
|
|
468
509
|
const mockDeepLink = [
|
|
469
|
-
{ value: 'test-deep-link', keys: [] } // No keys from selection
|
|
510
|
+
{ value: 'test-deep-link', keys: [] }, // No keys from selection
|
|
470
511
|
];
|
|
471
512
|
const mockLinkProps = {
|
|
472
513
|
deepLink: mockDeepLink,
|
|
@@ -503,7 +544,7 @@ describe("PlatformContentFields", () => {
|
|
|
503
544
|
|
|
504
545
|
it('should handle deep link keys with no keys at all', () => {
|
|
505
546
|
const mockDeepLink = [
|
|
506
|
-
{ value: 'test-deep-link', keys: [] } // No keys from selection
|
|
547
|
+
{ value: 'test-deep-link', keys: [] }, // No keys from selection
|
|
507
548
|
];
|
|
508
549
|
const mockLinkProps = {
|
|
509
550
|
deepLink: mockDeepLink,
|
|
@@ -540,7 +581,7 @@ describe("PlatformContentFields", () => {
|
|
|
540
581
|
|
|
541
582
|
it('should handle deep link keys with string value instead of array', () => {
|
|
542
583
|
const mockDeepLink = [
|
|
543
|
-
{ value: 'test-deep-link', keys: 'single-key' }
|
|
584
|
+
{ value: 'test-deep-link', keys: 'single-key' },
|
|
544
585
|
];
|
|
545
586
|
const mockLinkProps = {
|
|
546
587
|
deepLink: mockDeepLink,
|
|
@@ -577,7 +618,7 @@ describe("PlatformContentFields", () => {
|
|
|
577
618
|
|
|
578
619
|
it('should handle deep link keys with undefined deepLinkKeysValue', () => {
|
|
579
620
|
const mockDeepLink = [
|
|
580
|
-
{ value: 'test-deep-link', keys: ['key1', 'key2'] }
|
|
621
|
+
{ value: 'test-deep-link', keys: ['key1', 'key2'] },
|
|
581
622
|
];
|
|
582
623
|
const mockLinkProps = {
|
|
583
624
|
deepLink: mockDeepLink,
|
|
@@ -615,7 +656,7 @@ describe("PlatformContentFields", () => {
|
|
|
615
656
|
|
|
616
657
|
it('should handle deep link keys placeholder with fallback', () => {
|
|
617
658
|
const mockDeepLink = [
|
|
618
|
-
{ value: 'test-deep-link', keys: ['key1', 'key2'] } // Need keys to trigger the section
|
|
659
|
+
{ value: 'test-deep-link', keys: ['key1', 'key2'] }, // Need keys to trigger the section
|
|
619
660
|
];
|
|
620
661
|
const mockLinkProps = {
|
|
621
662
|
deepLink: mockDeepLink,
|
|
@@ -655,7 +696,7 @@ describe("PlatformContentFields", () => {
|
|
|
655
696
|
|
|
656
697
|
it('should handle deep link keys error display', () => {
|
|
657
698
|
const mockDeepLink = [
|
|
658
|
-
{ value: 'test-deep-link', keys: ['key1', 'key2'] }
|
|
699
|
+
{ value: 'test-deep-link', keys: ['key1', 'key2'] },
|
|
659
700
|
];
|
|
660
701
|
const mockLinkProps = {
|
|
661
702
|
deepLink: mockDeepLink,
|
|
@@ -727,7 +768,7 @@ describe("PlatformContentFields", () => {
|
|
|
727
768
|
describe('Deep link query parameter handling', () => {
|
|
728
769
|
it('should match deep link with query parameters', () => {
|
|
729
770
|
const mockDeepLink = [
|
|
730
|
-
{ value: 'myapp://profile', keys: ['userId'] }
|
|
771
|
+
{ value: 'myapp://profile', keys: ['userId'] },
|
|
731
772
|
];
|
|
732
773
|
const mockLinkProps = {
|
|
733
774
|
deepLink: mockDeepLink,
|
|
@@ -766,7 +807,7 @@ describe("PlatformContentFields", () => {
|
|
|
766
807
|
|
|
767
808
|
it('should not match deep link when no base match exists with query parameters', () => {
|
|
768
809
|
const mockDeepLink = [
|
|
769
|
-
{ value: 'myapp://settings', keys: ['theme'] }
|
|
810
|
+
{ value: 'myapp://settings', keys: ['theme'] },
|
|
770
811
|
];
|
|
771
812
|
const mockLinkProps = {
|
|
772
813
|
deepLink: mockDeepLink,
|
|
@@ -805,7 +846,7 @@ describe("PlatformContentFields", () => {
|
|
|
805
846
|
|
|
806
847
|
it('should handle multiple query parameters in deep link value', () => {
|
|
807
848
|
const mockDeepLink = [
|
|
808
|
-
{ value: 'testapp://dashboard', keys: ['category', 'filter'] }
|
|
849
|
+
{ value: 'testapp://dashboard', keys: ['category', 'filter'] },
|
|
809
850
|
];
|
|
810
851
|
const mockLinkProps = {
|
|
811
852
|
deepLink: mockDeepLink,
|
|
@@ -844,7 +885,7 @@ describe("PlatformContentFields", () => {
|
|
|
844
885
|
|
|
845
886
|
it('should handle empty query parameters in deep link value', () => {
|
|
846
887
|
const mockDeepLink = [
|
|
847
|
-
{ value: 'myapp://search', keys: ['query'] }
|
|
888
|
+
{ value: 'myapp://search', keys: ['query'] },
|
|
848
889
|
];
|
|
849
890
|
const mockLinkProps = {
|
|
850
891
|
deepLink: mockDeepLink,
|
|
@@ -860,7 +901,7 @@ describe("PlatformContentFields", () => {
|
|
|
860
901
|
linkType: 'DEEP_LINK',
|
|
861
902
|
};
|
|
862
903
|
|
|
863
|
-
const { getByText } = render(
|
|
904
|
+
const { getByText } = render(
|
|
864
905
|
<IntlProvider locale="en">
|
|
865
906
|
<PlatformContentFields
|
|
866
907
|
deviceType="ANDROID"
|
|
@@ -884,7 +925,7 @@ describe("PlatformContentFields", () => {
|
|
|
884
925
|
|
|
885
926
|
it('should handle tag selection for external link in buttons', () => {
|
|
886
927
|
const mockHandleExternalLinkChange = jest.fn();
|
|
887
|
-
|
|
928
|
+
|
|
888
929
|
// Create a test that actually renders the component and triggers the useCallback
|
|
889
930
|
const { container } = renderComponent({
|
|
890
931
|
content: {
|
|
@@ -77,7 +77,6 @@ import { getContent } from "../MobilePush/commonMethods";
|
|
|
77
77
|
import { getMessageObject } from "../../utils/messageUtils";
|
|
78
78
|
import { gtmPush } from "../../utils/gtmTrackers";
|
|
79
79
|
import mobilePushReducer from "./reducer";
|
|
80
|
-
import { hasLiquidSupportFeature } from "../../utils/common";
|
|
81
80
|
import formBuilderMessages from "../../v2Components/FormBuilder/messages";
|
|
82
81
|
import { validateMobilePushContent } from "../../utils/commonUtils";
|
|
83
82
|
import { getSingleTab } from "../InApp/utils";
|
|
@@ -89,13 +88,14 @@ import { PlatformContentFields } from "./components";
|
|
|
89
88
|
import { CREATE, EDIT, TRACK_CREATE_MPUSH } from "../App/constants";
|
|
90
89
|
import { validateExternalLink, validateDeepLink } from "./utils";
|
|
91
90
|
import messages from "./messages";
|
|
92
|
-
import { EXTERNAL_URL } from "../CreativesContainer/constants";
|
|
91
|
+
import { EXTERNAL_URL, MOBILE_PUSH } from "../CreativesContainer/constants";
|
|
93
92
|
import createMobilePushPayloadWithIntl from "../../utils/createMobilePushPayload";
|
|
94
93
|
import { MOBILEPUSH } from "../../v2Components/CapVideoUpload/constants";
|
|
95
94
|
import { StyledCapTab } from "./style";
|
|
96
95
|
import TestAndPreviewSlidebox from "../../v2Components/TestAndPreviewSlidebox";
|
|
97
|
-
|
|
96
|
+
|
|
98
97
|
import creativesMessages from "../CreativesContainer/messages";
|
|
98
|
+
import { error } from "jquery";
|
|
99
99
|
|
|
100
100
|
// Helper function to extract deep link keys from URL where value equals key
|
|
101
101
|
const extractDeepLinkKeys = (deepLinkValue) => {
|
|
@@ -506,6 +506,9 @@ const MobilePushNew = ({
|
|
|
506
506
|
isGetFormData,
|
|
507
507
|
getTemplateDetailsInProgress,
|
|
508
508
|
onCreateComplete,
|
|
509
|
+
// new flag from parent - when true personalization via tags should be disabled
|
|
510
|
+
restrictPersonalization = false,
|
|
511
|
+
onPersonalizationTokensChange,
|
|
509
512
|
}) => {
|
|
510
513
|
const { formatMessage } = intl;
|
|
511
514
|
|
|
@@ -799,10 +802,9 @@ const MobilePushNew = ({
|
|
|
799
802
|
(value) => {
|
|
800
803
|
let errorTemplateDescMessage = "";
|
|
801
804
|
|
|
802
|
-
const {
|
|
805
|
+
const { isBraceError } = validateTags({
|
|
803
806
|
content: value,
|
|
804
807
|
tagsParam: tags,
|
|
805
|
-
injectedTagsParams: injectedTags,
|
|
806
808
|
location,
|
|
807
809
|
tagModule: getDefaultTags,
|
|
808
810
|
isFullMode,
|
|
@@ -812,14 +814,6 @@ const MobilePushNew = ({
|
|
|
812
814
|
messages.emptyTemplateDescErrorMessage
|
|
813
815
|
);
|
|
814
816
|
}
|
|
815
|
-
if (unsupportedTags?.length > 0) {
|
|
816
|
-
errorTemplateDescMessage = formatMessage(
|
|
817
|
-
globalMessages.unsupportedTagsValidationError,
|
|
818
|
-
{
|
|
819
|
-
unsupportedTags,
|
|
820
|
-
}
|
|
821
|
-
);
|
|
822
|
-
}
|
|
823
817
|
if (isBraceError) {
|
|
824
818
|
errorTemplateDescMessage = formatMessage(
|
|
825
819
|
globalMessages.unbalanacedCurlyBraces
|
|
@@ -836,6 +830,14 @@ const MobilePushNew = ({
|
|
|
836
830
|
if (!value || value.trim() === "") {
|
|
837
831
|
error = formatMessage(messages.emptyTemplateDescErrorMessage);
|
|
838
832
|
}
|
|
833
|
+
// personalization restriction check
|
|
834
|
+
if (
|
|
835
|
+
restrictPersonalization
|
|
836
|
+
&& value
|
|
837
|
+
&& ((value.includes("{{") && value.includes("}}")) || (value.includes("[") && value.includes("]")))
|
|
838
|
+
) {
|
|
839
|
+
error = formatMessage(creativesMessages.personalizationTokensErrorMessage);
|
|
840
|
+
}
|
|
839
841
|
return error || "";
|
|
840
842
|
},
|
|
841
843
|
[templateDescErrorHandler, formatMessage]
|
|
@@ -847,9 +849,17 @@ const MobilePushNew = ({
|
|
|
847
849
|
if (!value || value.trim() === "") {
|
|
848
850
|
error = formatMessage(messages.emptyTemplateDescErrorMessage);
|
|
849
851
|
}
|
|
852
|
+
// personalization restriction check
|
|
853
|
+
if (
|
|
854
|
+
restrictPersonalization
|
|
855
|
+
&& value
|
|
856
|
+
&& ((value.includes("{{") && value.includes("}}")) || (value.includes("[") && value.includes("]")))
|
|
857
|
+
) {
|
|
858
|
+
error = formatMessage(creativesMessages.personalizationTokensErrorMessage);
|
|
859
|
+
}
|
|
850
860
|
return error || "";
|
|
851
861
|
},
|
|
852
|
-
[templateDescErrorHandler, formatMessage]
|
|
862
|
+
[templateDescErrorHandler, formatMessage, restrictPersonalization]
|
|
853
863
|
);
|
|
854
864
|
|
|
855
865
|
const handleOnTagsContextChange = useCallback(
|
|
@@ -1724,6 +1734,29 @@ const MobilePushNew = ({
|
|
|
1724
1734
|
const isAndroidSupported = accountData?.configs?.android === '1';
|
|
1725
1735
|
const isIosSupported = accountData?.configs?.ios === '1';
|
|
1726
1736
|
|
|
1737
|
+
// Notify parent when personalization tokens are added/removed (for anonymous user flow)
|
|
1738
|
+
useEffect(() => {
|
|
1739
|
+
if (!restrictPersonalization || typeof onPersonalizationTokensChange !== 'function') return;
|
|
1740
|
+
const hasToken = (value) => value && (
|
|
1741
|
+
(value.includes('{{') && value.includes('}}'))
|
|
1742
|
+
|| (value.includes('[') && value.includes(']'))
|
|
1743
|
+
);
|
|
1744
|
+
const hasTokens = (
|
|
1745
|
+
(isAndroidSupported && (hasToken(androidContent?.title) || hasToken(androidContent?.message)))
|
|
1746
|
+
|| (isIosSupported && (hasToken(iosContent?.title) || hasToken(iosContent?.message)))
|
|
1747
|
+
);
|
|
1748
|
+
onPersonalizationTokensChange(hasTokens);
|
|
1749
|
+
}, [
|
|
1750
|
+
restrictPersonalization,
|
|
1751
|
+
androidContent?.title,
|
|
1752
|
+
androidContent?.message,
|
|
1753
|
+
iosContent?.title,
|
|
1754
|
+
iosContent?.message,
|
|
1755
|
+
isAndroidSupported,
|
|
1756
|
+
isIosSupported,
|
|
1757
|
+
onPersonalizationTokensChange,
|
|
1758
|
+
]);
|
|
1759
|
+
|
|
1727
1760
|
// Validation logic for template creation/update
|
|
1728
1761
|
const isAndroidFieldsMissing = isAndroidSupported && (!androidContent?.title?.trim() || !androidContent?.message?.trim());
|
|
1729
1762
|
const isIosFieldsMissing = isIosSupported && (!iosContent?.title?.trim() || !iosContent?.message?.trim());
|
|
@@ -2001,6 +2034,11 @@ const MobilePushNew = ({
|
|
|
2001
2034
|
tags: tags || [],
|
|
2002
2035
|
injectedTags: injectedTags || {},
|
|
2003
2036
|
selectedOfferDetails,
|
|
2037
|
+
// disable tag button when personalization is restricted
|
|
2038
|
+
disabled: restrictPersonalization,
|
|
2039
|
+
disableTooltipMsg: restrictPersonalization
|
|
2040
|
+
? formatMessage(creativesMessages.personalizationNotSupportedAnonymous)
|
|
2041
|
+
: undefined,
|
|
2004
2042
|
};
|
|
2005
2043
|
|
|
2006
2044
|
// Fix nested ternary for videoAssetList and gifAssetList
|
|
@@ -2101,6 +2139,7 @@ const MobilePushNew = ({
|
|
|
2101
2139
|
tags={tags}
|
|
2102
2140
|
injectedTags={injectedTags}
|
|
2103
2141
|
selectedOfferDetails={selectedOfferDetails}
|
|
2142
|
+
restrictPersonalization={restrictPersonalization}
|
|
2104
2143
|
/>
|
|
2105
2144
|
);
|
|
2106
2145
|
}, [androidContent, iosContent, androidTitleError, iosTitleError, androidMessageError, iosMessageError, androidExternalLinkError, iosExternalLinkError, androidDeepLinkError, iosDeepLinkError, androidDeepLinkKeysError, iosDeepLinkKeysError, formatMessage, activeTab, imageSrc, isFullMode, imageData, androidAssetList, iosAssetList, videoState, videoData, location, tags, injectedTags, selectedOfferDetails, primaryButtonAndroid, secondaryButtonAndroid, primaryButtonIos, secondaryButtonIos, ctaData, deepLink, mobilePushActions, carouselActiveTabIndex, carouselLinkErrors, handleTitleChange, handleMessageChange, handleMediaTypeChange, handleActionOnClickChange, handleLinkTypeChange, handleDeepLinkChange, handleDeepLinkKeysChange, handleExternalLinkChange, onTagSelect, handleOnTagsContextChange, setUpdateMpushImageSrc, updateOnMpushImageReUpload, setUpdateMpushVideoSrc, updateOnMpushVideoReUpload, clearImageDataByMediaType, handleCarouselDataChange, updateCarouselLinkError, sameContent, updateHandler, deleteHandler]
|
|
@@ -2136,6 +2175,9 @@ const MobilePushNew = ({
|
|
|
2136
2175
|
return panes;
|
|
2137
2176
|
}, [isAndroidSupported, isIosSupported, renderContentFields, formatMessage]);
|
|
2138
2177
|
|
|
2178
|
+
const errorInTitle = activeTab === ANDROID ? androidTitleError : iosTitleError;
|
|
2179
|
+
const errorInMessage = activeTab === ANDROID ? androidMessageError : iosMessageError;
|
|
2180
|
+
|
|
2139
2181
|
// Save button disabled logic: only check enabled platforms
|
|
2140
2182
|
const isSaveDisabled = (
|
|
2141
2183
|
(isAndroidSupported && (!androidContent?.title?.trim() || !androidContent?.message?.trim()))
|
|
@@ -2143,6 +2185,7 @@ const MobilePushNew = ({
|
|
|
2143
2185
|
|| templateNameError
|
|
2144
2186
|
|| Object.values(carouselLinkErrors).some((error) => error !== null && error !== "")
|
|
2145
2187
|
|| !isCarouselDataValid()
|
|
2188
|
+
|| errorInTitle || errorInMessage
|
|
2146
2189
|
);
|
|
2147
2190
|
|
|
2148
2191
|
// Validation in handleSave: only show errors for enabled platforms
|
|
@@ -2599,6 +2642,12 @@ const MobilePushNew = ({
|
|
|
2599
2642
|
};
|
|
2600
2643
|
const onSuccess = () => handleSave();
|
|
2601
2644
|
|
|
2645
|
+
// When liquid is enabled and isFullMode is true, skip liquid validation and proceed directly
|
|
2646
|
+
if (isFullMode) {
|
|
2647
|
+
onSuccess();
|
|
2648
|
+
return;
|
|
2649
|
+
}
|
|
2650
|
+
|
|
2602
2651
|
validateMobilePushContent([androidContent, iosContent], {
|
|
2603
2652
|
currentTab: activeTab === ANDROID ? 1 : 2,
|
|
2604
2653
|
onError,
|
|
@@ -2606,20 +2655,6 @@ const MobilePushNew = ({
|
|
|
2606
2655
|
getLiquidTags: globalActionsProps.getLiquidTags,
|
|
2607
2656
|
formatMessage,
|
|
2608
2657
|
messages: formBuilderMessages,
|
|
2609
|
-
tagLookupMap: metaEntities?.tagLookupMap || {},
|
|
2610
|
-
eventContextTags: metaEntities?.eventContextTags || [],
|
|
2611
|
-
isLiquidFlow: hasLiquidSupportFeature(),
|
|
2612
|
-
forwardedTags: {},
|
|
2613
|
-
skipTags: (tag) => {
|
|
2614
|
-
const skipRegexes = [
|
|
2615
|
-
/dynamic_expiry_date_after_\d+_days\.FORMAT_\d/,
|
|
2616
|
-
/unsubscribe\(#[a-zA-Z\d]{6}\)/,
|
|
2617
|
-
/Link_to_[a-zA-z]/,
|
|
2618
|
-
/SURVEY.*\.TOKEN/,
|
|
2619
|
-
/^[A-Za-z].*\([a-zA-Z\d]*\)/,
|
|
2620
|
-
];
|
|
2621
|
-
return skipRegexes.some((regex) => regex.test(tag));
|
|
2622
|
-
},
|
|
2623
2658
|
singleTab: getSingleTab(accountData),
|
|
2624
2659
|
});
|
|
2625
2660
|
}, [
|
|
@@ -2628,12 +2663,10 @@ const MobilePushNew = ({
|
|
|
2628
2663
|
activeTab,
|
|
2629
2664
|
globalActionsProps,
|
|
2630
2665
|
formatMessage,
|
|
2631
|
-
metaEntities,
|
|
2632
2666
|
accountData,
|
|
2667
|
+
isFullMode,
|
|
2633
2668
|
]);
|
|
2634
2669
|
|
|
2635
|
-
const isLiquidFlow = hasLiquidSupportFeature();
|
|
2636
|
-
|
|
2637
2670
|
useEffect(() => {
|
|
2638
2671
|
// Always map to { label } for both platforms
|
|
2639
2672
|
const newButtons = Array.isArray(ctaData)
|
|
@@ -2880,16 +2913,22 @@ const MobilePushNew = ({
|
|
|
2880
2913
|
setShowTestAndPreviewSlidebox(false);
|
|
2881
2914
|
}, []);
|
|
2882
2915
|
|
|
2883
|
-
// Add useEffect to handle isGetFormData prop changes
|
|
2916
|
+
// Add useEffect to handle isGetFormData prop changes (e.g. Done clicked in footer)
|
|
2917
|
+
// In library mode: run liquid validation (extractTags) first; on success liquidMiddleWare calls handleSave
|
|
2918
|
+
// In full mode: call handleSave directly
|
|
2884
2919
|
useEffect(() => {
|
|
2885
2920
|
if (isGetFormData) {
|
|
2886
|
-
|
|
2921
|
+
if (!isFullMode) {
|
|
2922
|
+
liquidMiddleWare();
|
|
2923
|
+
} else {
|
|
2924
|
+
handleSave();
|
|
2925
|
+
}
|
|
2887
2926
|
// Reset the flag to prevent infinite loop
|
|
2888
2927
|
if (onValidationFail) {
|
|
2889
2928
|
onValidationFail();
|
|
2890
2929
|
}
|
|
2891
2930
|
}
|
|
2892
|
-
}, [isGetFormData, handleSave, onValidationFail]);
|
|
2931
|
+
}, [isGetFormData, handleSave, onValidationFail, isFullMode, liquidMiddleWare]);
|
|
2893
2932
|
|
|
2894
2933
|
// Add message event listener to handle parent communication (like old MobilePush components)
|
|
2895
2934
|
useEffect(() => {
|
|
@@ -3030,7 +3069,8 @@ const MobilePushNew = ({
|
|
|
3030
3069
|
<CapButton
|
|
3031
3070
|
type="primary"
|
|
3032
3071
|
onClick={() => {
|
|
3033
|
-
|
|
3072
|
+
// Liquid validation (extractTags) only in library mode
|
|
3073
|
+
if (!isFullMode) {
|
|
3034
3074
|
liquidMiddleWare();
|
|
3035
3075
|
} else {
|
|
3036
3076
|
handleSave();
|
|
@@ -3046,6 +3086,7 @@ const MobilePushNew = ({
|
|
|
3046
3086
|
className="mobilepush-test-preview-btn"
|
|
3047
3087
|
type="secondary"
|
|
3048
3088
|
style={{ marginLeft: '8px' }}
|
|
3089
|
+
disabled={isSaveDisabled}
|
|
3049
3090
|
>
|
|
3050
3091
|
<FormattedMessage {...creativesMessages.testAndPreview} />
|
|
3051
3092
|
</CapButton>
|
|
@@ -3106,6 +3147,7 @@ MobilePushNew.propTypes = {
|
|
|
3106
3147
|
isGetFormData: PropTypes.bool,
|
|
3107
3148
|
getTemplateDetailsInProgress: PropTypes.bool,
|
|
3108
3149
|
onCreateComplete: PropTypes.func,
|
|
3150
|
+
onPersonalizationTokensChange: PropTypes.func,
|
|
3109
3151
|
};
|
|
3110
3152
|
|
|
3111
3153
|
MobilePushNew.defaultProps = {
|
|
@@ -3136,6 +3178,7 @@ MobilePushNew.defaultProps = {
|
|
|
3136
3178
|
isGetFormData: false,
|
|
3137
3179
|
getTemplateDetailsInProgress: false,
|
|
3138
3180
|
onCreateComplete: () => {},
|
|
3181
|
+
onPersonalizationTokensChange: undefined,
|
|
3139
3182
|
};
|
|
3140
3183
|
|
|
3141
3184
|
const mapStateToProps = createStructuredSelector({
|
|
@@ -269,4 +269,12 @@ export default defineMessages({
|
|
|
269
269
|
id: `${scope}.gifFileTypeError`,
|
|
270
270
|
defaultMessage: 'Only GIF files are allowed',
|
|
271
271
|
},
|
|
272
|
+
personalizationTagsErrorMessage: {
|
|
273
|
+
id: `${scope}.personalizationTagsErrorMessage`,
|
|
274
|
+
defaultMessage: 'Personalization tags are not supported for anonymous customers, please remove the tags.',
|
|
275
|
+
},
|
|
276
|
+
personalizationNotSupportedAnonymous: {
|
|
277
|
+
id: `${scope}.personalizationNotSupportedAnonymous`,
|
|
278
|
+
defaultMessage: `Personalization tags are not supported for anonymous customers`,
|
|
279
|
+
},
|
|
272
280
|
});
|
|
@@ -72,7 +72,7 @@ export class MobilepushWrapper extends React.Component { // eslint-disable-line
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
render() {
|
|
75
|
-
const {mobilePushCreateMode, step, getFormData, setIsLoadingContent, isGetFormData, query, isFullMode, showTemplateName, type, onValidationFail, onPreviewContentClicked, onTestContentClicked, templateData, eventContextTags = [], showTestAndPreviewSlidebox, handleTestAndPreview, handleCloseTestAndPreview} = this.props;
|
|
75
|
+
const {mobilePushCreateMode, step, getFormData, getLiquidTags, setIsLoadingContent, isGetFormData, query, isFullMode, showTemplateName, type, onValidationFail, onPreviewContentClicked, onTestContentClicked, templateData, eventContextTags = [], waitEventContextTags = {},showTestAndPreviewSlidebox, handleTestAndPreview, handleCloseTestAndPreview, restrictPersonalization, isAnonymousType, onPersonalizationTokensChange} = this.props;
|
|
76
76
|
const {templateName} = this.state;
|
|
77
77
|
const isShowMobilepushCreate = !isEmpty(mobilePushCreateMode);
|
|
78
78
|
return (
|
|
@@ -102,6 +102,7 @@ export class MobilepushWrapper extends React.Component { // eslint-disable-line
|
|
|
102
102
|
<div>
|
|
103
103
|
{isShowMobilepushCreate && <MobilepushCreate
|
|
104
104
|
getFormLibraryData={getFormData}
|
|
105
|
+
getLiquidTags={getLiquidTags}
|
|
105
106
|
setIsLoadingContent={setIsLoadingContent}
|
|
106
107
|
defaultData={{"template-name": templateName}}
|
|
107
108
|
location={{
|
|
@@ -120,10 +121,14 @@ export class MobilepushWrapper extends React.Component { // eslint-disable-line
|
|
|
120
121
|
templateData={templateData}
|
|
121
122
|
hideTestAndPreviewBtn={this.props.hideTestAndPreviewBtn}
|
|
122
123
|
eventContextTags={eventContextTags}
|
|
124
|
+
waitEventContextTags={waitEventContextTags}
|
|
123
125
|
showLiquidErrorInFooter={this.props.showLiquidErrorInFooter}
|
|
124
126
|
showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
|
|
125
127
|
handleTestAndPreview={handleTestAndPreview}
|
|
126
128
|
handleCloseTestAndPreview={handleCloseTestAndPreview}
|
|
129
|
+
restrictPersonalization={restrictPersonalization}
|
|
130
|
+
isAnonymousType={isAnonymousType}
|
|
131
|
+
onPersonalizationTokensChange={onPersonalizationTokensChange}
|
|
127
132
|
/>
|
|
128
133
|
|
|
129
134
|
|
|
@@ -140,6 +145,7 @@ MobilepushWrapper.propTypes = {
|
|
|
140
145
|
mobilePushCreateMode: PropTypes.string,
|
|
141
146
|
step: PropTypes.string,
|
|
142
147
|
getFormData: PropTypes.string,
|
|
148
|
+
getLiquidTags: PropTypes.func,
|
|
143
149
|
setIsLoadingContent: PropTypes.func,
|
|
144
150
|
onEnterTemplateName: PropTypes.func,
|
|
145
151
|
onRemoveTemplateName: PropTypes.func,
|
|
@@ -150,10 +156,14 @@ MobilepushWrapper.propTypes = {
|
|
|
150
156
|
type: PropTypes.string,
|
|
151
157
|
onValidationFail: PropTypes.func,
|
|
152
158
|
eventContextTags: PropTypes.array,
|
|
159
|
+
waitEventContextTags: PropTypes.object,
|
|
153
160
|
showLiquidErrorInFooter: PropTypes.func,
|
|
154
161
|
showTestAndPreviewSlidebox: PropTypes.bool,
|
|
155
162
|
handleTestAndPreview: PropTypes.func,
|
|
156
163
|
handleCloseTestAndPreview: PropTypes.func,
|
|
164
|
+
restrictPersonalization: PropTypes.bool,
|
|
165
|
+
isAnonymousType: PropTypes.bool,
|
|
166
|
+
onPersonalizationTokensChange: PropTypes.func,
|
|
157
167
|
};
|
|
158
168
|
|
|
159
169
|
|