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
|
@@ -39,7 +39,8 @@ import { v2MobilePushEditSagas } from './sagas';
|
|
|
39
39
|
import v2MobilePushEditReducer from './reducer';
|
|
40
40
|
import * as globalActions from '../../Cap/actions';
|
|
41
41
|
import { MAPP_SDK } from './constants';
|
|
42
|
-
import { isEmbeddedEditOrPreview } from '../../../utils/commonUtils';
|
|
42
|
+
import { checkForPersonalizationTokens, isEmbeddedEditOrPreview, validateMobilePushContent } from '../../../utils/commonUtils';
|
|
43
|
+
import formBuilderMessages from '../../../v2Components/FormBuilder/messages';
|
|
43
44
|
import { EMBEDDED } from '../../Whatsapp/constants';
|
|
44
45
|
import { OUTBOUND } from '../../../v2Components/FormBuilder/constants';
|
|
45
46
|
import TestAndPreviewSlidebox from '../../../v2Components/TestAndPreviewSlidebox';
|
|
@@ -47,6 +48,17 @@ import TestAndPreviewSlidebox from '../../../v2Components/TestAndPreviewSlidebox
|
|
|
47
48
|
const PrefixWrapper = styled.div`
|
|
48
49
|
margin-right: 16px;
|
|
49
50
|
`;
|
|
51
|
+
|
|
52
|
+
const safeParseDeeplinkConfig = (value) => {
|
|
53
|
+
if (!value || typeof value !== 'string') return [];
|
|
54
|
+
try {
|
|
55
|
+
const parsed = JSON.parse(value);
|
|
56
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
57
|
+
} catch {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
50
62
|
export class Edit extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
|
51
63
|
constructor(props) {
|
|
52
64
|
super(props);
|
|
@@ -57,6 +69,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
57
69
|
schema: {},
|
|
58
70
|
currentTab: 1,
|
|
59
71
|
editData: {},
|
|
72
|
+
errorData: [],
|
|
60
73
|
loading: false,
|
|
61
74
|
isFormValid: true,
|
|
62
75
|
injectedTags: {},
|
|
@@ -68,6 +81,10 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
68
81
|
this.getPrimaryCtaFields = getPrimaryCtaFields.bind(this);
|
|
69
82
|
this.getSecondaryCtaFields = getSecondaryCtaFields.bind(this);
|
|
70
83
|
this.getLinkTypeFields = getLinkTypeFields.bind(this);
|
|
84
|
+
// Guard: only one initial meta/TAG fetch (getTags can be invoked from multiple code paths)
|
|
85
|
+
this.hasFetchedInitialTagsRef = false;
|
|
86
|
+
// Guard: avoid duplicate fetch when multiple TagList instances trigger same context
|
|
87
|
+
this.lastFetchedTagContextRef = null;
|
|
71
88
|
}
|
|
72
89
|
componentWillMount() {
|
|
73
90
|
this.props.actions.getWeCrmAccounts("mobilepush");
|
|
@@ -92,11 +109,12 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
92
109
|
if (!_.isEmpty(this.state.schema)) {
|
|
93
110
|
this.injectEvents(this.state.schema);
|
|
94
111
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
112
|
+
const templateId = get(this, "props.params.id");
|
|
113
|
+
const hasTemplateData = !_.isEmpty(this.props.templateData);
|
|
114
|
+
if (this.props.location?.query && (templateId || hasTemplateData)) {
|
|
115
|
+
if (templateId && templateId !== 'temp') {
|
|
98
116
|
this.props.actions.getTemplateDetails(templateId);
|
|
99
|
-
} else {
|
|
117
|
+
} else if (hasTemplateData) {
|
|
100
118
|
this.props.actions.setTemplateDetails(this.props.templateData);
|
|
101
119
|
}
|
|
102
120
|
}
|
|
@@ -109,8 +127,47 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
109
127
|
}
|
|
110
128
|
}
|
|
111
129
|
componentWillReceiveProps(nextProps) {
|
|
112
|
-
if (nextProps.
|
|
113
|
-
|
|
130
|
+
if (nextProps.params?.id !== this.props.params?.id) {
|
|
131
|
+
this.hasFetchedInitialTagsRef = false;
|
|
132
|
+
this.lastFetchedTagContextRef = null;
|
|
133
|
+
}
|
|
134
|
+
// Library mode: on Done click (transition to isGetFormData), run extractTags only when no existing validation errors (braces, personalization, etc.)
|
|
135
|
+
if (nextProps.isGetFormData && !this.props.isGetFormData && !nextProps.isFullMode) {
|
|
136
|
+
// If form already has validation errors (braces, personalization tags, etc.), do not call extractTags; just fail
|
|
137
|
+
if (!this.state.isFormValid) {
|
|
138
|
+
nextProps.onValidationFail?.();
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (nextProps.getLiquidTags && nextProps.showLiquidErrorInFooter) {
|
|
142
|
+
const formDataArr = [this.state.formData?.[0], this.state.formData?.[1]];
|
|
143
|
+
validateMobilePushContent(formDataArr, {
|
|
144
|
+
currentTab: this.state.currentTab,
|
|
145
|
+
getLiquidTags: nextProps.getLiquidTags,
|
|
146
|
+
formatMessage: this.props.intl.formatMessage,
|
|
147
|
+
messages: formBuilderMessages,
|
|
148
|
+
onError: (err) => {
|
|
149
|
+
const { standardErrors = [], liquidErrors = [] } = err;
|
|
150
|
+
// _validatePlatformSpecificContent passes { standardErrors: { ANDROID, IOS, generic }, liquidErrors: { ... } }; footer expects arrays
|
|
151
|
+
const toArray = (v) => (Array.isArray(v) ? v : (v && typeof v === 'object' ? [].concat(...Object.values(v)) : []));
|
|
152
|
+
const STANDARD_ERROR_MSG = toArray(standardErrors);
|
|
153
|
+
const LIQUID_ERROR_MSG = toArray(liquidErrors);
|
|
154
|
+
nextProps.showLiquidErrorInFooter(
|
|
155
|
+
{ STANDARD_ERROR_MSG, LIQUID_ERROR_MSG },
|
|
156
|
+
this.state.currentTab
|
|
157
|
+
);
|
|
158
|
+
// Only treat as validation failure when there are actual errors; skip when helper called onError with empty reset payload
|
|
159
|
+
const hasErrors = STANDARD_ERROR_MSG.length > 0 || LIQUID_ERROR_MSG.length > 0;
|
|
160
|
+
if (hasErrors) {
|
|
161
|
+
nextProps.onValidationFail?.();
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
onSuccess: () => {
|
|
165
|
+
nextProps.getFormLibraryData(this.getFormData());
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
} else {
|
|
169
|
+
nextProps.getFormLibraryData(this.getFormData());
|
|
170
|
+
}
|
|
114
171
|
} else if (nextProps.isGetFormData && this.props.isGetFormData !== nextProps.isGetFormData && this.props.isFullMode && !this.props.Create.createTemplateInProgress) {
|
|
115
172
|
this.startValidation();
|
|
116
173
|
}
|
|
@@ -167,11 +224,15 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
167
224
|
};
|
|
168
225
|
this.props.actions.getMobilepushTemplatesList('mobilepush', params);
|
|
169
226
|
}
|
|
170
|
-
if (nextProps.metaEntities && nextProps.metaEntities.layouts && nextProps.metaEntities.layouts.length > 0 && _.isEmpty(this.state.fullSchema)
|
|
171
|
-
|
|
172
|
-
|
|
227
|
+
if (nextProps.metaEntities && nextProps.metaEntities.layouts && nextProps.metaEntities.layouts.length > 0 && _.isEmpty(this.state.fullSchema)) {
|
|
228
|
+
const definition = nextProps.metaEntities.layouts[0].definition;
|
|
229
|
+
const initialSchema = definition?.textSchema || definition?.imageSchema || {};
|
|
230
|
+
this.setState({fullSchema: definition, schema: initialSchema}, () => {
|
|
231
|
+
// Use this.props (latest) in callback to avoid race: templateDetails may have arrived by now
|
|
232
|
+
const latestSelectedAccount = this.getSelectedWeChatAccountFromProps(this.props);
|
|
233
|
+
this.handleEditSchemaOnPropsChange(this.props, latestSelectedAccount);
|
|
173
234
|
const templateId = get(this, "props.params.id");
|
|
174
|
-
if (
|
|
235
|
+
if (this.props.location.query.module !== 'loyalty' && templateId && templateId !== 'temp') {
|
|
175
236
|
this.props.actions.getTemplateDetails(templateId);
|
|
176
237
|
}
|
|
177
238
|
if (queryType === EMBEDDED && templateId === 'temp' && _.isEmpty(this.state.formData)) { // when his.props.params.id is temp that means mobile push template content will be passed from post message from parent with startTemplateCreation action
|
|
@@ -222,6 +283,15 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
222
283
|
onFormDataChange = (formData, tabCount, currentTab, inputField) => {
|
|
223
284
|
const newFormData = _.cloneDeep(formData);
|
|
224
285
|
const {templateCta} = this.state;
|
|
286
|
+
|
|
287
|
+
// Check for personalization tokens if restriction is enabled and notify parent
|
|
288
|
+
if (this.props.restrictPersonalization) {
|
|
289
|
+
const hasTokens = checkForPersonalizationTokens(newFormData);
|
|
290
|
+
if (this.props.onPersonalizationTokensChange) {
|
|
291
|
+
this.props.onPersonalizationTokensChange(hasTokens);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
225
295
|
if (!_.isEmpty(templateCta) && this.state.currentTab === 2) {
|
|
226
296
|
newFormData[this.state.currentTab - 1][`secondary-cta-${this.state.currentTab - 1}-label`] = get(templateCta, 'name');
|
|
227
297
|
newFormData[this.state.currentTab - 1][`secondary-cta-${this.state.currentTab - 1}-action`] = get(templateCta, 'ctaTemplateDetails[0].buttonText');
|
|
@@ -230,7 +300,10 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
230
300
|
newFormData[this.state.currentTab - 1][`secondary-cta-${this.state.currentTab - 1}-action2`] = get(templateCta, 'ctaTemplateDetails[1].buttonText');
|
|
231
301
|
}
|
|
232
302
|
}
|
|
233
|
-
|
|
303
|
+
const newAccount = newFormData["mobilepush-accounts"];
|
|
304
|
+
const currentAccount = this.state.formData["mobilepush-accounts"];
|
|
305
|
+
const isExplicitAccountChange = newAccount !== undefined && newAccount !== currentAccount;
|
|
306
|
+
if (isExplicitAccountChange) {
|
|
234
307
|
this.setMobilePushAccountOptions(this.props.Edit.weCrmAccounts, newFormData["mobilepush-accounts"]);
|
|
235
308
|
delete newFormData['mobilepush-template'];
|
|
236
309
|
delete newFormData['template-name'];
|
|
@@ -240,6 +313,8 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
240
313
|
if (!_.isEmpty(newFormData[1])) {
|
|
241
314
|
delete newFormData[1];
|
|
242
315
|
}
|
|
316
|
+
} else if (newAccount === undefined && currentAccount !== undefined) {
|
|
317
|
+
newFormData["mobilepush-accounts"] = currentAccount;
|
|
243
318
|
}
|
|
244
319
|
if (this.state.isSchemaChanged) {
|
|
245
320
|
this.setState({isSchemaChanged: false});
|
|
@@ -271,7 +346,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
271
346
|
if (isEmbeddedEditOrPreview(queryType, mode)) {
|
|
272
347
|
selectedWeChatAccount = !_.isEmpty(editSelectedWeChatAccount)
|
|
273
348
|
? editSelectedWeChatAccount
|
|
274
|
-
: templateSelectedWeChatAccount;
|
|
349
|
+
: (templateSelectedWeChatAccount || {});
|
|
275
350
|
} else if (!_.isEmpty(templateSelectedWeChatAccount)) {
|
|
276
351
|
selectedWeChatAccount = templateSelectedWeChatAccount;
|
|
277
352
|
}
|
|
@@ -285,8 +360,8 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
285
360
|
const inputFields = get(schema, `containers[0].panes[${tabIndex - 1}].sections[0].childSections[0].childSections[0].inputFields`);
|
|
286
361
|
const id = field.id;
|
|
287
362
|
const fieldIndex = findIndex(inputFields, {identifier: id});
|
|
288
|
-
const ck = selectedWeChatAccount
|
|
289
|
-
const deepLinkOptions = _.map(
|
|
363
|
+
const ck = selectedWeChatAccount?.configs ? !!selectedWeChatAccount.configs.deeplink : false;
|
|
364
|
+
const deepLinkOptions = _.map(safeParseDeeplinkConfig(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (link) => ({label: link.name, value: link.link, title: link.link }) );
|
|
290
365
|
// let inputId = deeplinkValue && deeplinkValue.toLowerCase() === "deeplink" ? `${id}-select` : `${id}-text`;
|
|
291
366
|
// if (field.id === "cta-deeplink-secondary-cta-1" && (tabIndex > 1 || this.state.currentTab > 1)) {
|
|
292
367
|
// inputId = `${inputId}${tabIndex || this.state.currentTab}`;
|
|
@@ -657,8 +732,8 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
657
732
|
|
|
658
733
|
getLinkName = (link) => {
|
|
659
734
|
const selectedWeChatAccount = this.getWeChatAccount();
|
|
660
|
-
const ck = selectedWeChatAccount
|
|
661
|
-
const deepLinkOptions = _.filter(
|
|
735
|
+
const ck = selectedWeChatAccount?.configs ? !!selectedWeChatAccount.configs.deeplink : false;
|
|
736
|
+
const deepLinkOptions = _.filter(safeParseDeeplinkConfig(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (l) => l.link === link);
|
|
662
737
|
if (deepLinkOptions[0]) {
|
|
663
738
|
return deepLinkOptions[0].name;
|
|
664
739
|
}
|
|
@@ -667,32 +742,22 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
667
742
|
// eslint-disable-next-line react/sort-comp
|
|
668
743
|
showError = () => {
|
|
669
744
|
const {intl} = this.props;
|
|
670
|
-
const {errorData} = this.state;
|
|
745
|
+
const {errorData, schema} = this.state;
|
|
671
746
|
const errorMessage = {key: 'validation-error', message: intl.formatMessage(messages.validationError)};
|
|
672
|
-
let isTagErrorExist = false;
|
|
673
747
|
if (!_.isEmpty(this.state.formData) && !this.state.isFormValid) {
|
|
674
748
|
let tab = this.state.currentTab;
|
|
675
|
-
const isAndroidInvalid = Object.values(errorData[0]).includes(true);
|
|
676
|
-
const isIosInvalid = Object.values(errorData[1]).includes(true);
|
|
749
|
+
const isAndroidInvalid = Object.values(errorData?.[0] || {}).includes(true);
|
|
750
|
+
const isIosInvalid = Object.values(errorData?.[1] || {}).includes(true);
|
|
751
|
+
const isIosTabVisible = get(schema, 'containers[0].panes[1].isSupported', true) !== false;
|
|
677
752
|
if (isAndroidInvalid) {
|
|
678
753
|
tab = 1;
|
|
679
754
|
errorMessage.description = intl.formatMessage(messages.invalidAndroidMessage);
|
|
680
|
-
|
|
681
|
-
if (!_.isEmpty(invalidTags)) {
|
|
682
|
-
isTagErrorExist = true;
|
|
683
|
-
errorMessage.description = `${intl.formatMessage(messages.invalidAndroidMessage)} ${intl.formatMessage(messages.invalidTags)}: ${invalidTags.join(',')} `;
|
|
684
|
-
}
|
|
685
|
-
} else if (isIosInvalid) {
|
|
755
|
+
} else if (isIosInvalid && isIosTabVisible) {
|
|
686
756
|
tab = 2;
|
|
687
757
|
errorMessage.description = intl.formatMessage(messages.invalidIosMessage);
|
|
688
|
-
const invalidTags = errorData[1]['invalid-tags'];
|
|
689
|
-
if (!_.isEmpty(invalidTags)) {
|
|
690
|
-
isTagErrorExist = true;
|
|
691
|
-
errorMessage.description = `${intl.formatMessage(messages.invalidIosMessage)} ${intl.formatMessage(messages.invalidTags)}: ${invalidTags.join(',')} `;
|
|
692
|
-
}
|
|
693
758
|
}
|
|
694
759
|
|
|
695
|
-
if (tab !== this.state.currentTab
|
|
760
|
+
if (tab !== this.state.currentTab) {
|
|
696
761
|
CapNotification.error(errorMessage);
|
|
697
762
|
}
|
|
698
763
|
}
|
|
@@ -719,6 +784,27 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
719
784
|
parent.postMessage(JSON.stringify(response), '*');
|
|
720
785
|
};
|
|
721
786
|
|
|
787
|
+
/**
|
|
788
|
+
* Compute selectedWeChatAccount from props (used so we can call with latest props
|
|
789
|
+
* in setState callback to avoid stale closure and intermittent empty form).
|
|
790
|
+
*/
|
|
791
|
+
getSelectedWeChatAccountFromProps = (props) => {
|
|
792
|
+
const queryType = String(get(props, 'location.query.type', ''))?.toLowerCase();
|
|
793
|
+
const creativesMode = String(get(props, 'creativesMode', ''))?.toLowerCase();
|
|
794
|
+
const { Edit: EditProps, Templates } = props || {};
|
|
795
|
+
const { selectedWeChatAccount: editSelectedWeChatAccount } = EditProps || {};
|
|
796
|
+
const { Templates: nextTemplates } = props || {};
|
|
797
|
+
if (isEmbeddedEditOrPreview(queryType, creativesMode)) {
|
|
798
|
+
return !_.isEmpty(editSelectedWeChatAccount)
|
|
799
|
+
? editSelectedWeChatAccount
|
|
800
|
+
: nextTemplates?.selectedWeChatAccount;
|
|
801
|
+
}
|
|
802
|
+
if (!_.isEmpty(Templates?.selectedWeChatAccount)) {
|
|
803
|
+
return Templates?.selectedWeChatAccount;
|
|
804
|
+
}
|
|
805
|
+
return undefined;
|
|
806
|
+
};
|
|
807
|
+
|
|
722
808
|
getFormData = (e) => {
|
|
723
809
|
const response = {
|
|
724
810
|
action: "getFormData",
|
|
@@ -735,12 +821,16 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
735
821
|
|
|
736
822
|
|
|
737
823
|
setEditState(data, schema) {
|
|
824
|
+
if (!data?.versions?.base || typeof data.versions.base !== 'object') return;
|
|
738
825
|
const tabCount = Object.keys(data.versions.base).length;
|
|
739
826
|
const formData = {};
|
|
740
827
|
if (this.props.location.query.type === 'embedded' && this.props.location.query.module === "loyalty") {
|
|
741
828
|
formData["mobilepush-accounts"] = this.state.formData["mobilepush-accounts"];
|
|
742
829
|
formData['mobilepush-template'] = this.state.formData['mobilepush-template'];
|
|
743
830
|
}
|
|
831
|
+
if (data.definition?.accountId) {
|
|
832
|
+
formData['mobilepush-accounts'] = data.definition.accountId;
|
|
833
|
+
}
|
|
744
834
|
formData['template-name'] = data.name;
|
|
745
835
|
const androidData = data.versions.base.ANDROID;
|
|
746
836
|
const iosData = data.versions.base.IOS;
|
|
@@ -968,15 +1058,19 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
968
1058
|
});
|
|
969
1059
|
};
|
|
970
1060
|
getTags = () => {
|
|
1061
|
+
if (this.hasFetchedInitialTagsRef) {
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
this.hasFetchedInitialTagsRef = true;
|
|
1065
|
+
const context = this.props.getDefaultTags
|
|
1066
|
+
|| (this.props.location.query.type === 'embedded' ? this.props.location.query.module : 'default');
|
|
1067
|
+
this.lastFetchedTagContextRef = typeof context === 'string' ? context.toLowerCase() : context;
|
|
971
1068
|
const query = {
|
|
972
1069
|
layout: 'mobilepush',
|
|
973
1070
|
type: 'TAG',
|
|
974
|
-
context: this.
|
|
1071
|
+
context: this.lastFetchedTagContextRef,
|
|
975
1072
|
embedded: this.props.location.query.type === 'embedded' ? this.props.location.query.type : 'full',
|
|
976
1073
|
};
|
|
977
|
-
if (this.props.getDefaultTags) {
|
|
978
|
-
query.context = this.props.getDefaultTags;
|
|
979
|
-
}
|
|
980
1074
|
this.props.globalActions.fetchSchemaForEntity(query);
|
|
981
1075
|
}
|
|
982
1076
|
setModalContent = (type) => {
|
|
@@ -1076,8 +1170,8 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
1076
1170
|
const currentTab = tab || this.state.currentTab;
|
|
1077
1171
|
const schema = inputSchema ? _.cloneDeep(inputSchema) : _.cloneDeep(this.state.schema);
|
|
1078
1172
|
const selectedWeChatAccount = this.getWeChatAccount();
|
|
1079
|
-
const ck = selectedWeChatAccount
|
|
1080
|
-
const deepLinkOptions = _.map(
|
|
1173
|
+
const ck = selectedWeChatAccount?.configs ? !!selectedWeChatAccount.configs.deeplink : false;
|
|
1174
|
+
const deepLinkOptions = _.map(safeParseDeeplinkConfig(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (link) => ({label: link.name, value: link.link, title: link.link }) );
|
|
1081
1175
|
|
|
1082
1176
|
const inputFields = get(schema, `containers[0].panes[${currentTab - 1}].sections[0].childSections[0].childSections[0].inputFields`);
|
|
1083
1177
|
forEach(inputFields, (inputField, fieldIndex) => {
|
|
@@ -1228,8 +1322,8 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
1228
1322
|
delete formData[self.state.currentTab - 1][`${id.replace('-delete', '')}`];
|
|
1229
1323
|
}
|
|
1230
1324
|
if (child.inputFields[fieldIndex] && child.inputFields[fieldIndex].id === "cta-deeplink-select-section") {
|
|
1231
|
-
const ck = selectedWeChatAccount
|
|
1232
|
-
const configkeys = selectedWeChatAccount ? _.filter(
|
|
1325
|
+
const ck = selectedWeChatAccount?.configs ? !!selectedWeChatAccount.configs.deeplink : false;
|
|
1326
|
+
const configkeys = selectedWeChatAccount ? _.filter(safeParseDeeplinkConfig(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (dl) => dl.link === selectedDeeplink) : [];
|
|
1233
1327
|
if (configkeys.length) {
|
|
1234
1328
|
const options = configkeys[0].keys;
|
|
1235
1329
|
_.forEach(options, (opt) => {
|
|
@@ -1340,8 +1434,8 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
1340
1434
|
delete formData[self.state.currentTab - 1][`cta-deeplink-${id.replace('delete', 'text')}`];
|
|
1341
1435
|
}
|
|
1342
1436
|
if (child.inputFields[fieldIndex] && child.inputFields[fieldIndex].id === "cta-deeplink-select-section") {
|
|
1343
|
-
const ck = selectedWeChatAccount
|
|
1344
|
-
const configkeys = selectedWeChatAccount ? _.filter(
|
|
1437
|
+
const ck = selectedWeChatAccount?.configs ? !!selectedWeChatAccount.configs.deeplink : false;
|
|
1438
|
+
const configkeys = selectedWeChatAccount ? _.filter(safeParseDeeplinkConfig(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (dl) => dl.link === selectedDeeplink) : [];
|
|
1345
1439
|
|
|
1346
1440
|
if (configkeys.length) {
|
|
1347
1441
|
const options = configkeys[0].keys;
|
|
@@ -1629,10 +1723,21 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
1629
1723
|
};
|
|
1630
1724
|
|
|
1631
1725
|
saveFormData = (formData) => {
|
|
1726
|
+
// Check for personalization tokens if restriction is enabled
|
|
1727
|
+
if (this.props.restrictPersonalization) {
|
|
1728
|
+
const hasTokens = checkForPersonalizationTokens(formData);
|
|
1729
|
+
if (hasTokens) {
|
|
1730
|
+
const message = this.props.intl.formatMessage(messages.personalizationTokensErrorMessage);
|
|
1731
|
+
CapNotification.error({message, key: 'personalizationTokensError'});
|
|
1732
|
+
return;
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1632
1736
|
const obj = this.getTransformedData(formData);
|
|
1633
1737
|
|
|
1634
1738
|
this.props.actions.editTemplate(obj, this.onUpdateTemplateComplete);
|
|
1635
1739
|
};
|
|
1740
|
+
|
|
1636
1741
|
handleFrameTasks = (e) => {
|
|
1637
1742
|
//
|
|
1638
1743
|
const type = e.data;
|
|
@@ -1694,8 +1799,8 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
1694
1799
|
const {id} = field;
|
|
1695
1800
|
const fieldIndex = findIndex(inputFields, {identifier: id});
|
|
1696
1801
|
const formDataKey = id.replace("-show-keys", "");
|
|
1697
|
-
const ck = selectedWeChatAccount
|
|
1698
|
-
let keys = selectedWeChatAccount ? _.filter(
|
|
1802
|
+
const ck = selectedWeChatAccount?.configs ? !!selectedWeChatAccount.configs.deeplink : false;
|
|
1803
|
+
let keys = selectedWeChatAccount ? _.filter(safeParseDeeplinkConfig(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (dl) => dl.link === formData[currentTab - 1][formDataKey]) : [];
|
|
1699
1804
|
if (keys[0]) {
|
|
1700
1805
|
keys = keys[0].keys;
|
|
1701
1806
|
}
|
|
@@ -1725,7 +1830,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
1725
1830
|
inputFields.splice(fieldIndex + index + 1, 0, row);
|
|
1726
1831
|
});
|
|
1727
1832
|
if (!tabIndex) { // removes the existing selected options keys so that newly selected options keys can be added.
|
|
1728
|
-
const configkeys = _.filter(
|
|
1833
|
+
const configkeys = _.filter(safeParseDeeplinkConfig(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (dl) => dl.link === this.state.formData[currentTab - 1][field.id]);
|
|
1729
1834
|
if (configkeys.length) {
|
|
1730
1835
|
const options = configkeys[0].keys;
|
|
1731
1836
|
inputFields = inputFields.slice(0, fieldIndex + 1).concat(inputFields.slice(fieldIndex + options.length + 1, inputFields.length));
|
|
@@ -1744,8 +1849,8 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
1744
1849
|
const selectedWeChatAccount = this.getWeChatAccount();
|
|
1745
1850
|
const id = field.id;
|
|
1746
1851
|
const schema = inputSchema ? _.cloneDeep(inputSchema) : _.cloneDeep(this.state.schema);
|
|
1747
|
-
const ck = selectedWeChatAccount
|
|
1748
|
-
const deepLinkOptions = selectedWeChatAccount ? _.map(
|
|
1852
|
+
const ck = selectedWeChatAccount?.configs ? !!selectedWeChatAccount.configs.deeplink : false;
|
|
1853
|
+
const deepLinkOptions = selectedWeChatAccount ? _.map(safeParseDeeplinkConfig(ck ? selectedWeChatAccount?.configs?.deeplink : '[]'), (link) => ({label: link.name, value: link.link, title: link.link }) ) : [];
|
|
1749
1854
|
// const eventsMap = _.cloneDeep(this.state.eventsMap);
|
|
1750
1855
|
const tabIndex = currentTab || this.state.currentTab;
|
|
1751
1856
|
const inputFields = get(schema, `containers[0].panes[${tabIndex - 1}].sections[0].childSections[0].childSections[0].inputFields`);
|
|
@@ -1775,8 +1880,8 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
1775
1880
|
const formDataCopy = cloneDeep(formData);
|
|
1776
1881
|
const schema = inputSchema ? _.cloneDeep(inputSchema) : _.cloneDeep(this.state.schema);
|
|
1777
1882
|
const selectedWeChatAccount = this.getWeChatAccount();
|
|
1778
|
-
const ck = selectedWeChatAccount
|
|
1779
|
-
const deepLinkOptions = selectedWeChatAccount ? _.map(
|
|
1883
|
+
const ck = selectedWeChatAccount?.configs ? !!selectedWeChatAccount.configs.deeplink : false;
|
|
1884
|
+
const deepLinkOptions = selectedWeChatAccount ? _.map(safeParseDeeplinkConfig(ck ? selectedWeChatAccount.configs.deeplink : '[]'), (link) => ({label: link.name, value: link.link, title: link.link }) ) : [];
|
|
1780
1885
|
const inputFields = get(schema, `containers[0].panes[${tabIndex - 1}].sections[0].childSections[0].childSections[0].inputFields`);
|
|
1781
1886
|
const fieldIndex = findIndex(inputFields, {identifier: id});
|
|
1782
1887
|
let newInputFields;
|
|
@@ -1967,10 +2072,15 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
1967
2072
|
this.setState({ schema });
|
|
1968
2073
|
};
|
|
1969
2074
|
handleOnTagsContextChange = (data) => {
|
|
2075
|
+
const context = (data || '').toLowerCase() === 'all' ? 'default' : (data || '').toLowerCase();
|
|
2076
|
+
if (this.lastFetchedTagContextRef === context) {
|
|
2077
|
+
return;
|
|
2078
|
+
}
|
|
2079
|
+
this.lastFetchedTagContextRef = context;
|
|
1970
2080
|
const query = {
|
|
1971
2081
|
layout: 'mobilepush',
|
|
1972
2082
|
type: 'TAG',
|
|
1973
|
-
context
|
|
2083
|
+
context,
|
|
1974
2084
|
embedded: this.props.location.query.type === 'embedded' ? this.props.location.query.type : 'full',
|
|
1975
2085
|
};
|
|
1976
2086
|
this.props.globalActions.fetchSchemaForEntity(query);
|
|
@@ -1987,33 +2097,94 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
1987
2097
|
}
|
|
1988
2098
|
|
|
1989
2099
|
handleEditSchemaOnPropsChange = (nextProps, selectedWeChatAccount) => {
|
|
1990
|
-
|
|
2100
|
+
const templateDetails = nextProps.templateDetails || nextProps.templateData;
|
|
2101
|
+
const queryType = String(get(this.props, 'location.query.type', ''))?.toLowerCase();
|
|
2102
|
+
const isEmbeddedLibrary = queryType === EMBEDDED && !nextProps.isFullMode;
|
|
2103
|
+
const canSetAccountFromTemplate =
|
|
2104
|
+
(_.isEmpty(selectedWeChatAccount) || !selectedWeChatAccount?.configs) &&
|
|
2105
|
+
templateDetails?.definition?.accountId &&
|
|
2106
|
+
nextProps.Edit?.weCrmAccounts?.length > 0;
|
|
2107
|
+
const hasAccountOrEmbedded =
|
|
2108
|
+
!_.isEmpty(selectedWeChatAccount) ||
|
|
2109
|
+
isEmbeddedLibrary ||
|
|
2110
|
+
canSetAccountFromTemplate ||
|
|
2111
|
+
!nextProps.isFullMode ||
|
|
2112
|
+
queryType === EMBEDDED;
|
|
2113
|
+
const hasTemplateDetails = !_.isEmpty(templateDetails);
|
|
2114
|
+
const hasEditData = !_.isEmpty(this.state.editData);
|
|
2115
|
+
const hasFullSchema = !_.isEmpty(this.state.fullSchema);
|
|
2116
|
+
const locationCheck = (this.props.location.query.type !== 'embedded' || this.props.isFullMode === false || queryType === EMBEDDED);
|
|
2117
|
+
const canPopulateForm =
|
|
2118
|
+
hasTemplateDetails &&
|
|
2119
|
+
!hasEditData &&
|
|
2120
|
+
hasFullSchema &&
|
|
2121
|
+
locationCheck &&
|
|
2122
|
+
hasAccountOrEmbedded;
|
|
2123
|
+
if (canPopulateForm) {
|
|
1991
2124
|
this.props = nextProps;
|
|
1992
|
-
|
|
2125
|
+
if (canSetAccountFromTemplate) {
|
|
2126
|
+
this.setMobilePushAccountOptions(nextProps.Edit.weCrmAccounts, templateDetails.definition.accountId);
|
|
2127
|
+
}
|
|
2128
|
+
const mode = templateDetails.definition ? templateDetails.definition.mode : templateDetails.mode;
|
|
1993
2129
|
const schema = mode === "text" ? this.state.fullSchema?.textSchema : this.state.fullSchema?.imageSchema;
|
|
1994
|
-
|
|
1995
|
-
const
|
|
2130
|
+
if (!schema) return;
|
|
2131
|
+
const configs = nextProps.Templates?.selectedWeChatAccount?.configs || {};
|
|
2132
|
+
const hasExplicitConfigs = !_.isEmpty(configs) && ('android' in configs || 'ios' in configs);
|
|
2133
|
+
const isAndroidSupported = hasExplicitConfigs ? configs.android === '1' : true;
|
|
2134
|
+
const isIosSupported = hasExplicitConfigs ? configs.ios === '1' : true;
|
|
1996
2135
|
if (!isAndroidSupported) {
|
|
1997
2136
|
const androidField = get(schema, "containers[0].panes[0]");
|
|
1998
|
-
androidField
|
|
1999
|
-
|
|
2000
|
-
|
|
2137
|
+
if (androidField) {
|
|
2138
|
+
androidField.isSupported = false;
|
|
2139
|
+
this.setState({currentTab: 2});
|
|
2140
|
+
set(schema, "containers[0].panes[0]", androidField);
|
|
2141
|
+
}
|
|
2001
2142
|
}
|
|
2002
2143
|
if (!isIosSupported) {
|
|
2003
2144
|
const iosField = get(schema, "containers[0].panes[1]");
|
|
2004
|
-
iosField
|
|
2005
|
-
|
|
2006
|
-
|
|
2145
|
+
if (iosField) {
|
|
2146
|
+
iosField.isSupported = false;
|
|
2147
|
+
set(schema, "containers[0].panes[1]", iosField);
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
const dataToUse = this.normalizeTemplateDataForEdit(templateDetails);
|
|
2151
|
+
if (dataToUse?.versions?.base) {
|
|
2152
|
+
this.setEditState(dataToUse, schema);
|
|
2153
|
+
this.getTags();
|
|
2154
|
+
} else {
|
|
2155
|
+
console.warn('[MobliPushEdit] Skipped setEditState - dataToUse.versions.base missing', { dataToUse });
|
|
2007
2156
|
}
|
|
2008
|
-
this.setEditState(nextProps.templateDetails, schema);
|
|
2009
|
-
this.getTags();
|
|
2010
2157
|
}
|
|
2158
|
+
};
|
|
2159
|
+
|
|
2160
|
+
normalizeTemplateDataForEdit = (data) => {
|
|
2161
|
+
if (!data) return null;
|
|
2162
|
+
if (data.versions?.base) return data;
|
|
2163
|
+
if (data.content?.versions?.base) {
|
|
2164
|
+
return { ...data, versions: data.content.versions };
|
|
2165
|
+
}
|
|
2166
|
+
const baseContent = data.content || {};
|
|
2167
|
+
if (baseContent.ANDROID || baseContent.IOS) {
|
|
2168
|
+
return {
|
|
2169
|
+
...data,
|
|
2170
|
+
versions: { base: baseContent },
|
|
2171
|
+
name: data.name || data.templateName || '',
|
|
2172
|
+
definition: data.definition || {},
|
|
2173
|
+
mode: data.mode || data.definition?.mode || 'text',
|
|
2174
|
+
};
|
|
2175
|
+
}
|
|
2176
|
+
return data;
|
|
2011
2177
|
}
|
|
2012
2178
|
|
|
2013
2179
|
render() {
|
|
2180
|
+
const queryType = String(get(this.props, 'location.query.type', ''))?.toLowerCase();
|
|
2181
|
+
const isEmbeddedOrLibrary = queryType === 'embedded' || this.props.isFullMode === false;
|
|
2182
|
+
const hasFormContent = !_.isEmpty(this.state.formData) && !_.isEmpty(this.state.schema);
|
|
2183
|
+
const showFormBuilder = !this.props.isLoadingMetaEntities || hasFormContent;
|
|
2014
2184
|
const schema = this.state.schema;
|
|
2015
2185
|
const loadingContentEdit = this.state.loadingContentEdit || (this.props.location.query.module === 'dvs' && _.isEmpty(this.state.schema));
|
|
2016
|
-
const
|
|
2186
|
+
const metaEntitiesBlockSpinner = hasFormContent;
|
|
2187
|
+
const spinning = get(this.props, "Edit.fetchingWeCrmAccounts") || (!metaEntitiesBlockSpinner && this.props.isLoadingMetaEntities) || loadingContentEdit || this.props.Edit.fetchingDefaultTemplates || this.props.Edit.assetUploading || this.state.loading || (this.props.Edit && (("getTemplateDetailsInProgress" in this.props.Edit && this.props.Edit.getTemplateDetailsInProgress) || ("editTemplateInProgress" in this.props.Edit && this.props.Edit.editTemplateInProgress)));
|
|
2017
2188
|
let tags = this.props.metaEntities && this.props.metaEntities.tags ? this.props.metaEntities.tags.standard : [];
|
|
2018
2189
|
if (this.props.supportedTags) {
|
|
2019
2190
|
tags = this.props.supportedTags;
|
|
@@ -2023,8 +2194,11 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
2023
2194
|
<CapSpin spinning={spinning}>
|
|
2024
2195
|
<CapRow>
|
|
2025
2196
|
<CapColumn>
|
|
2026
|
-
|
|
2027
|
-
|
|
2197
|
+
{(() => {
|
|
2198
|
+
if (isEmbeddedOrLibrary && !showFormBuilder && hasFormContent) {
|
|
2199
|
+
console.warn('[MobliPushEdit] FormBuilder HIDDEN (isLoadingMetaEntities=true) but formData+schema exist');
|
|
2200
|
+
}
|
|
2201
|
+
return showFormBuilder && <FormBuilder
|
|
2028
2202
|
channel={MOBILE_PUSH}
|
|
2029
2203
|
schema={schema}
|
|
2030
2204
|
showLiquidErrorInFooter={this.props.showLiquidErrorInFooter}
|
|
@@ -2059,7 +2233,10 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
2059
2233
|
hideTestAndPreviewBtn={this.props.hideTestAndPreviewBtn}
|
|
2060
2234
|
isFullMode={this.props.isFullMode}
|
|
2061
2235
|
eventContextTags={this.props?.eventContextTags}
|
|
2062
|
-
|
|
2236
|
+
waitEventContextTags={this.props?.waitEventContextTags}
|
|
2237
|
+
restrictPersonalization={this.props.restrictPersonalization}
|
|
2238
|
+
/>;
|
|
2239
|
+
})()}
|
|
2063
2240
|
</CapColumn>
|
|
2064
2241
|
{this.props.iosCtasData && this.state.showIosCtaTable &&
|
|
2065
2242
|
<CapSlideBox
|
|
@@ -2158,15 +2335,20 @@ Edit.propTypes = {
|
|
|
2158
2335
|
getFormLibraryData: PropTypes.func,
|
|
2159
2336
|
isGetFormData: PropTypes.bool,
|
|
2160
2337
|
Create: PropTypes.object,
|
|
2161
|
-
onValidationFail: PropTypes.
|
|
2338
|
+
onValidationFail: PropTypes.func,
|
|
2162
2339
|
onPreviewContentClicked: PropTypes.func,
|
|
2163
2340
|
onTestContentClicked: PropTypes.func,
|
|
2164
2341
|
creativesMode: PropTypes.string,
|
|
2165
2342
|
eventContextTags: PropTypes.array,
|
|
2343
|
+
waitEventContextTags: PropTypes.object,
|
|
2344
|
+
getLiquidTags: PropTypes.func,
|
|
2166
2345
|
showLiquidErrorInFooter: PropTypes.func,
|
|
2167
2346
|
showTestAndPreviewSlidebox: PropTypes.bool,
|
|
2168
2347
|
handleTestAndPreview: PropTypes.func,
|
|
2169
2348
|
handleCloseTestAndPreview: PropTypes.func,
|
|
2349
|
+
restrictPersonalization: PropTypes.bool,
|
|
2350
|
+
isAnonymousType: PropTypes.bool,
|
|
2351
|
+
onPersonalizationTokensChange: PropTypes.func,
|
|
2170
2352
|
};
|
|
2171
2353
|
|
|
2172
2354
|
const mapStateToProps = createStructuredSelector({
|
|
@@ -334,4 +334,8 @@ export default defineMessages({
|
|
|
334
334
|
id: 'creatives.containersV2.MobilePush.Edit.thisSectionDisabledHoverText',
|
|
335
335
|
defaultMessage: 'This section is being revamped. Till then it will remain disabled.',
|
|
336
336
|
},
|
|
337
|
+
"personalizationTokensErrorMessage": {
|
|
338
|
+
id: 'creatives.containersV2.MobilePush.Edit.personalizationTokensErrorMessage',
|
|
339
|
+
defaultMessage: 'Personalization tags are not supported for anonymous customers, please remove the tags.',
|
|
340
|
+
},
|
|
337
341
|
});
|