@capillarytech/creatives-library 8.0.287-alpha.3 → 8.0.288
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/constants/unified.js +1 -0
- package/initialState.js +2 -0
- package/package.json +1 -1
- package/utils/common.js +8 -5
- package/utils/commonUtils.js +111 -2
- package/utils/tagValidations.js +222 -84
- package/utils/tests/commonUtil.test.js +118 -147
- package/utils/tests/tagValidations.test.js +358 -280
- package/v2Components/CapTagList/index.js +7 -2
- package/v2Components/CapTagListWithInput/index.js +4 -0
- package/v2Components/ErrorInfoNote/index.js +5 -2
- package/v2Components/FormBuilder/index.js +187 -74
- package/v2Components/FormBuilder/messages.js +12 -0
- package/v2Components/HtmlEditor/HTMLEditor.js +5 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +15 -0
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +2 -1
- package/v2Containers/Cap/mockData.js +14 -0
- package/v2Containers/Cap/reducer.js +55 -3
- package/v2Containers/Cap/tests/reducer.test.js +102 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +20 -0
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +40 -6
- package/v2Containers/CreativesContainer/constants.js +6 -0
- package/v2Containers/CreativesContainer/index.js +36 -5
- package/v2Containers/CreativesContainer/messages.js +12 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +339 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +18 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +37 -0
- package/v2Containers/Email/index.js +5 -1
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +62 -10
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +115 -12
- package/v2Containers/FTP/index.js +51 -2
- package/v2Containers/FTP/messages.js +4 -0
- package/v2Containers/InApp/index.js +96 -1
- package/v2Containers/InApp/tests/index.test.js +6 -17
- package/v2Containers/InappAdvance/index.js +103 -2
- package/v2Containers/Line/Container/Text/index.js +1 -0
- package/v2Containers/MobilePush/Create/index.js +37 -1
- package/v2Containers/MobilePush/Create/messages.js +4 -0
- package/v2Containers/MobilePush/Edit/index.js +37 -2
- package/v2Containers/MobilePush/Edit/messages.js +4 -0
- package/v2Containers/MobilePushNew/components/PlatformContentFields.js +36 -12
- package/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +68 -27
- package/v2Containers/MobilePushNew/index.js +92 -5
- package/v2Containers/MobilePushNew/messages.js +8 -0
- package/v2Containers/MobilepushWrapper/index.js +7 -1
- package/v2Containers/Rcs/index.js +37 -12
- package/v2Containers/Sms/Create/index.js +3 -31
- package/v2Containers/Sms/Create/messages.js +0 -4
- package/v2Containers/Sms/Edit/index.js +3 -29
- package/v2Containers/Sms/commonMethods.js +6 -6
- package/v2Containers/SmsTrai/Edit/index.js +47 -6
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +6 -6
- package/v2Containers/TagList/index.js +17 -1
- package/v2Containers/TagList/messages.js +4 -0
- package/v2Containers/TemplatesV2/index.js +43 -23
- package/v2Containers/Viber/index.js +1 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.js +3 -1
- package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +7 -0
- package/v2Containers/WebPush/Create/index.js +25 -6
- package/v2Containers/WebPush/Create/messages.js +8 -1
- package/v2Containers/WebPush/Create/utils/validation.js +20 -22
- package/v2Containers/WebPush/Create/utils/validation.test.js +52 -0
- package/v2Containers/Whatsapp/index.js +17 -9
- package/v2Containers/Zalo/index.js +11 -3
|
@@ -50,7 +50,9 @@ import injectReducer from '../../utils/injectReducer';
|
|
|
50
50
|
import v2InAppReducer from '../InApp/reducer';
|
|
51
51
|
import { v2InAppSagas } from '../InApp/sagas';
|
|
52
52
|
import injectSaga from '../../utils/injectSaga';
|
|
53
|
+
import { validateTags } from "../../utils/tagValidations";
|
|
53
54
|
import { validateInAppContent } from "../../utils/commonUtils";
|
|
55
|
+
import { hasLiquidSupportFeature } from "../../utils/common";
|
|
54
56
|
import formBuilderMessages from "../../v2Components/FormBuilder/messages";
|
|
55
57
|
import { getSingleTab, hasAnyErrors } from "../InApp/utils";
|
|
56
58
|
import ErrorInfoNote from "../../v2Components/ErrorInfoNote";
|
|
@@ -815,9 +817,11 @@ export const InappAdvanced = (props) => {
|
|
|
815
817
|
const latestHtmlValues = await saveAllBeeInstances();
|
|
816
818
|
const payload = createPayload(latestHtmlValues);
|
|
817
819
|
|
|
820
|
+
// Validate the INAPP content
|
|
821
|
+
const isLiquidFlow = hasLiquidSupportFeature();
|
|
818
822
|
// Skip validation if no tags are available (e.g., in tests or when tags haven't loaded)
|
|
819
823
|
const hasTags = tags && tags.length > 0;
|
|
820
|
-
if (hasTags) {
|
|
824
|
+
if (isLiquidFlow && hasTags) {
|
|
821
825
|
validateInAppContent(payload, {
|
|
822
826
|
currentTab: panes === ANDROID ? 1 : 2, // Convert ANDROID/IOS to tab numbers
|
|
823
827
|
onError,
|
|
@@ -825,6 +829,10 @@ export const InappAdvanced = (props) => {
|
|
|
825
829
|
getLiquidTags: (content, callback) => globalActions.getLiquidTags(content, callback),
|
|
826
830
|
formatMessage,
|
|
827
831
|
messages: formBuilderMessages,
|
|
832
|
+
tagLookupMap: metaEntities?.tagLookupMap || {},
|
|
833
|
+
eventContextTags: metaEntities?.eventContextTags || [],
|
|
834
|
+
isLiquidFlow,
|
|
835
|
+
forwardedTags: {},
|
|
828
836
|
skipTags: (tag) => {
|
|
829
837
|
// Skip certain tags if needed
|
|
830
838
|
const skipRegexes = [
|
|
@@ -839,7 +847,92 @@ export const InappAdvanced = (props) => {
|
|
|
839
847
|
},
|
|
840
848
|
singleTab: getSingleTab(accountData),
|
|
841
849
|
});
|
|
850
|
+
} else if (hasTags) {
|
|
851
|
+
// For non-liquid flow, validate tags using validateTags (only if tags are available)
|
|
852
|
+
const androidContent = latestHtmlValues?.android || (androidBeeHtml?.value || (typeof androidBeeHtml === 'string' ? androidBeeHtml : ''));
|
|
853
|
+
const iosContent = latestHtmlValues?.ios || (iosBeeHtml?.value || (typeof iosBeeHtml === 'string' ? iosBeeHtml : ''));
|
|
854
|
+
|
|
855
|
+
const androidSupported = get(accountData, 'selectedWeChatAccount.configs.android') === DEVICE_SUPPORTED || get(editContent, 'ANDROID.deviceType') === ANDROID;
|
|
856
|
+
const iosSupported = get(accountData, 'selectedWeChatAccount.configs.ios') === DEVICE_SUPPORTED || get(editContent, 'IOS.deviceType') === IOS_CAPITAL;
|
|
857
|
+
|
|
858
|
+
let hasErrors = false;
|
|
859
|
+
const newErrors = {
|
|
860
|
+
STANDARD_ERROR_MSG: {
|
|
861
|
+
ANDROID: [],
|
|
862
|
+
IOS: [],
|
|
863
|
+
GENERIC: [],
|
|
864
|
+
},
|
|
865
|
+
LIQUID_ERROR_MSG: {
|
|
866
|
+
ANDROID: [],
|
|
867
|
+
IOS: [],
|
|
868
|
+
GENERIC: [],
|
|
869
|
+
},
|
|
870
|
+
};
|
|
871
|
+
|
|
872
|
+
// Validate Android content
|
|
873
|
+
if (androidSupported && androidContent && androidContent?.trim() !== '') {
|
|
874
|
+
const validationResponse = validateTags({
|
|
875
|
+
content: androidContent,
|
|
876
|
+
tagsParam: tags,
|
|
877
|
+
injectedTagsParams: injectedTags || {},
|
|
878
|
+
location,
|
|
879
|
+
tagModule: getDefaultTags,
|
|
880
|
+
eventContextTags: metaEntities?.eventContextTags || [],
|
|
881
|
+
isFullMode,
|
|
882
|
+
}) || {};
|
|
883
|
+
|
|
884
|
+
if (validationResponse?.unsupportedTags?.length > 0) {
|
|
885
|
+
hasErrors = true;
|
|
886
|
+
newErrors.LIQUID_ERROR_MSG.ANDROID.push(
|
|
887
|
+
formatMessage(globalMessages.unsupportedTagsValidationError, {
|
|
888
|
+
unsupportedTags: validationResponse.unsupportedTags.join(", "),
|
|
889
|
+
})
|
|
890
|
+
);
|
|
891
|
+
}
|
|
892
|
+
if (validationResponse?.isBraceError) {
|
|
893
|
+
hasErrors = true;
|
|
894
|
+
newErrors.LIQUID_ERROR_MSG.ANDROID.push(
|
|
895
|
+
formatMessage(globalMessages.unbalanacedCurlyBraces)
|
|
896
|
+
);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// Validate iOS content
|
|
901
|
+
if (iosSupported && iosContent && iosContent?.trim() !== '') {
|
|
902
|
+
const validationResponse = validateTags({
|
|
903
|
+
content: iosContent,
|
|
904
|
+
tagsParam: tags,
|
|
905
|
+
injectedTagsParams: injectedTags || {},
|
|
906
|
+
location,
|
|
907
|
+
tagModule: getDefaultTags,
|
|
908
|
+
eventContextTags: metaEntities?.eventContextTags || [],
|
|
909
|
+
isFullMode,
|
|
910
|
+
}) || {};
|
|
911
|
+
|
|
912
|
+
if (validationResponse?.unsupportedTags?.length > 0) {
|
|
913
|
+
hasErrors = true;
|
|
914
|
+
newErrors.LIQUID_ERROR_MSG.IOS.push(
|
|
915
|
+
formatMessage(globalMessages.unsupportedTagsValidationError, {
|
|
916
|
+
unsupportedTags: validationResponse.unsupportedTags.join(", "),
|
|
917
|
+
})
|
|
918
|
+
);
|
|
919
|
+
}
|
|
920
|
+
if (validationResponse?.isBraceError) {
|
|
921
|
+
hasErrors = true;
|
|
922
|
+
newErrors.LIQUID_ERROR_MSG.IOS.push(
|
|
923
|
+
formatMessage(globalMessages.unbalanacedCurlyBraces)
|
|
924
|
+
);
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
if (hasErrors) {
|
|
929
|
+
setErrorMessage(newErrors);
|
|
930
|
+
} else {
|
|
931
|
+
// No errors, proceed with submission
|
|
932
|
+
onSuccess();
|
|
933
|
+
}
|
|
842
934
|
} else {
|
|
935
|
+
// No tags available, skip validation and proceed directly
|
|
843
936
|
onSuccess();
|
|
844
937
|
}
|
|
845
938
|
};
|
|
@@ -945,7 +1038,15 @@ export const InappAdvanced = (props) => {
|
|
|
945
1038
|
)}
|
|
946
1039
|
<CapButton
|
|
947
1040
|
onClick={async () => {
|
|
948
|
-
|
|
1041
|
+
const isLiquidFlow = hasLiquidSupportFeature();
|
|
1042
|
+
const hasTags = tags && tags?.length > 0;
|
|
1043
|
+
if (isLiquidFlow || hasTags) {
|
|
1044
|
+
// Use validation middleware for tag validation
|
|
1045
|
+
await liquidMiddleWare();
|
|
1046
|
+
} else {
|
|
1047
|
+
// No validation needed, proceed directly
|
|
1048
|
+
await onDoneCallback();
|
|
1049
|
+
}
|
|
949
1050
|
}}
|
|
950
1051
|
disabled={isDisableDone()}
|
|
951
1052
|
className="inapp-create-btn"
|
|
@@ -38,6 +38,7 @@ import v2MobilePushCreateReducer from './reducer';
|
|
|
38
38
|
import { v2MobilePushWatchDuplicateTemplateSaga } from './sagas';
|
|
39
39
|
import { EXTERNAL_LINK_LOWERCASE } from './constants';
|
|
40
40
|
import TestAndPreviewSlidebox from '../../../v2Components/TestAndPreviewSlidebox';
|
|
41
|
+
import { checkForPersonalizationTokens } from '../../../utils/commonUtils';
|
|
41
42
|
|
|
42
43
|
const PrefixWrapper = styled.div`
|
|
43
44
|
margin-right: 16px;
|
|
@@ -161,6 +162,15 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
161
162
|
const newFormData = cloneDeep(formData);
|
|
162
163
|
const {templateCta} = this.state;
|
|
163
164
|
const { defaultData = {}, isFullMode, showTemplateName} = this.props;
|
|
165
|
+
|
|
166
|
+
// Check for personalization tokens if restriction is enabled and notify parent
|
|
167
|
+
if (this.props.restrictPersonalization) {
|
|
168
|
+
const hasTokens = checkForPersonalizationTokens(newFormData);
|
|
169
|
+
if (this.props.onPersonalizationTokensChange) {
|
|
170
|
+
this.props.onPersonalizationTokensChange(hasTokens);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
164
174
|
if (!isEmpty(templateCta)) {
|
|
165
175
|
newFormData[this.state.currentTab - 1][`secondary-cta-${this.state.currentTab - 1}-label`] = get(templateCta, 'name');
|
|
166
176
|
newFormData[this.state.currentTab - 1][`secondary-cta-${this.state.currentTab - 1}-action`] = get(templateCta, 'ctaTemplateDetails[0].buttonText');
|
|
@@ -674,14 +684,25 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
674
684
|
let tab = this.state.currentTab;
|
|
675
685
|
const isAndroidInvalid = Object.values(errorData[0]).includes(true);
|
|
676
686
|
const isIosInvalid = Object.values(errorData[1]).includes(true);
|
|
687
|
+
let isTagErrorExist = false;
|
|
677
688
|
if (isAndroidInvalid) {
|
|
678
689
|
tab = 1;
|
|
679
690
|
errorMessage.description = intl.formatMessage(messages.invalidAndroidMessage);
|
|
691
|
+
const invalidTags = errorData[0]['invalid-tags'];
|
|
692
|
+
if (!isEmpty(invalidTags)) {
|
|
693
|
+
isTagErrorExist = true;
|
|
694
|
+
errorMessage.description = `${intl.formatMessage(messages.invalidAndroidMessage)} ${intl.formatMessage(messages.invalidTags)}: ${invalidTags.join(',')} `;
|
|
695
|
+
}
|
|
680
696
|
} else if (isIosInvalid) {
|
|
681
697
|
tab = 2;
|
|
682
698
|
errorMessage.description = intl.formatMessage(messages.invalidIosMessage);
|
|
699
|
+
const invalidTags = errorData[1]['invalid-tags'];
|
|
700
|
+
if (!isEmpty(invalidTags)) {
|
|
701
|
+
isTagErrorExist = true;
|
|
702
|
+
errorMessage.description = `${intl.formatMessage(messages.invalidIosMessage)} ${intl.formatMessage(messages.invalidTags)}: ${invalidTags.join(',')} `;
|
|
703
|
+
}
|
|
683
704
|
}
|
|
684
|
-
if (tab !== this.state.currentTab) {
|
|
705
|
+
if (tab !== this.state.currentTab || isTagErrorExist) {
|
|
685
706
|
CapNotification.error(errorMessage);
|
|
686
707
|
}
|
|
687
708
|
}
|
|
@@ -1493,6 +1514,17 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
1493
1514
|
|
|
1494
1515
|
saveFormData = (formData) => {
|
|
1495
1516
|
//this function gets called from form bulder only when the form data is valid
|
|
1517
|
+
|
|
1518
|
+
// Check for personalization tokens if restriction is enabled
|
|
1519
|
+
if (this.props.restrictPersonalization) {
|
|
1520
|
+
const hasTokens = checkForPersonalizationTokens(formData);
|
|
1521
|
+
if (hasTokens) {
|
|
1522
|
+
const message = this.props.intl.formatMessage(messages.personalizationTokensErrorMessage);
|
|
1523
|
+
CapNotification.error({message, key: 'personalizationTokensError'});
|
|
1524
|
+
return;
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1496
1528
|
const obj = this.getTransformedData(formData);
|
|
1497
1529
|
const content = getContent(obj);
|
|
1498
1530
|
const {
|
|
@@ -1896,6 +1928,7 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
1896
1928
|
isFullMode={this.props.isFullMode}
|
|
1897
1929
|
eventContextTags={this.props?.eventContextTags}
|
|
1898
1930
|
messageDetails={this.props?.messageDetails}
|
|
1931
|
+
restrictPersonalization={this.props.restrictPersonalization}
|
|
1899
1932
|
/>
|
|
1900
1933
|
</CapColumn>
|
|
1901
1934
|
{this.props.iosCtasData && this.state.showIosCtaTable &&
|
|
@@ -2000,6 +2033,9 @@ Create.propTypes = {
|
|
|
2000
2033
|
showTestAndPreviewSlidebox: PropTypes.bool,
|
|
2001
2034
|
handleTestAndPreview: PropTypes.func,
|
|
2002
2035
|
handleCloseTestAndPreview: PropTypes.func,
|
|
2036
|
+
restrictPersonalization: PropTypes.bool,
|
|
2037
|
+
isAnonymousType: PropTypes.bool,
|
|
2038
|
+
onPersonalizationTokensChange: PropTypes.func,
|
|
2003
2039
|
};
|
|
2004
2040
|
|
|
2005
2041
|
const mapStateToProps = createStructuredSelector({
|
|
@@ -342,4 +342,8 @@ export default defineMessages({
|
|
|
342
342
|
id: 'creatives.containersV2.MobilePush.Create.thisSectionDisabledHoverText',
|
|
343
343
|
defaultMessage: 'This section is being revamped. Till then it will remain disabled.',
|
|
344
344
|
},
|
|
345
|
+
"personalizationTokensErrorMessage": {
|
|
346
|
+
id: 'creatives.containersV2.MobilePush.Create.personalizationTokensErrorMessage',
|
|
347
|
+
defaultMessage: 'Personalization tags are not supported for anonymous customers, please remove the tags.',
|
|
348
|
+
},
|
|
345
349
|
});
|
|
@@ -39,7 +39,7 @@ 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 } from '../../../utils/commonUtils';
|
|
43
43
|
import { EMBEDDED } from '../../Whatsapp/constants';
|
|
44
44
|
import { OUTBOUND } from '../../../v2Components/FormBuilder/constants';
|
|
45
45
|
import TestAndPreviewSlidebox from '../../../v2Components/TestAndPreviewSlidebox';
|
|
@@ -246,6 +246,15 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
246
246
|
onFormDataChange = (formData, tabCount, currentTab, inputField) => {
|
|
247
247
|
const newFormData = _.cloneDeep(formData);
|
|
248
248
|
const {templateCta} = this.state;
|
|
249
|
+
|
|
250
|
+
// Check for personalization tokens if restriction is enabled and notify parent
|
|
251
|
+
if (this.props.restrictPersonalization) {
|
|
252
|
+
const hasTokens = checkForPersonalizationTokens(newFormData);
|
|
253
|
+
if (this.props.onPersonalizationTokensChange) {
|
|
254
|
+
this.props.onPersonalizationTokensChange(hasTokens);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
249
258
|
if (!_.isEmpty(templateCta) && this.state.currentTab === 2) {
|
|
250
259
|
newFormData[this.state.currentTab - 1][`secondary-cta-${this.state.currentTab - 1}-label`] = get(templateCta, 'name');
|
|
251
260
|
newFormData[this.state.currentTab - 1][`secondary-cta-${this.state.currentTab - 1}-action`] = get(templateCta, 'ctaTemplateDetails[0].buttonText');
|
|
@@ -698,6 +707,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
698
707
|
const {intl} = this.props;
|
|
699
708
|
const {errorData} = this.state;
|
|
700
709
|
const errorMessage = {key: 'validation-error', message: intl.formatMessage(messages.validationError)};
|
|
710
|
+
let isTagErrorExist = false;
|
|
701
711
|
if (!_.isEmpty(this.state.formData) && !this.state.isFormValid) {
|
|
702
712
|
let tab = this.state.currentTab;
|
|
703
713
|
const isAndroidInvalid = Object.values(errorData[0]).includes(true);
|
|
@@ -705,12 +715,22 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
705
715
|
if (isAndroidInvalid) {
|
|
706
716
|
tab = 1;
|
|
707
717
|
errorMessage.description = intl.formatMessage(messages.invalidAndroidMessage);
|
|
718
|
+
const invalidTags = errorData[0]['invalid-tags'];
|
|
719
|
+
if (!_.isEmpty(invalidTags)) {
|
|
720
|
+
isTagErrorExist = true;
|
|
721
|
+
errorMessage.description = `${intl.formatMessage(messages.invalidAndroidMessage)} ${intl.formatMessage(messages.invalidTags)}: ${invalidTags.join(',')} `;
|
|
722
|
+
}
|
|
708
723
|
} else if (isIosInvalid) {
|
|
709
724
|
tab = 2;
|
|
710
725
|
errorMessage.description = intl.formatMessage(messages.invalidIosMessage);
|
|
726
|
+
const invalidTags = errorData[1]['invalid-tags'];
|
|
727
|
+
if (!_.isEmpty(invalidTags)) {
|
|
728
|
+
isTagErrorExist = true;
|
|
729
|
+
errorMessage.description = `${intl.formatMessage(messages.invalidIosMessage)} ${intl.formatMessage(messages.invalidTags)}: ${invalidTags.join(',')} `;
|
|
730
|
+
}
|
|
711
731
|
}
|
|
712
732
|
|
|
713
|
-
if (tab !== this.state.currentTab) {
|
|
733
|
+
if (tab !== this.state.currentTab || isTagErrorExist) {
|
|
714
734
|
CapNotification.error(errorMessage);
|
|
715
735
|
}
|
|
716
736
|
}
|
|
@@ -1676,10 +1696,21 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
1676
1696
|
};
|
|
1677
1697
|
|
|
1678
1698
|
saveFormData = (formData) => {
|
|
1699
|
+
// Check for personalization tokens if restriction is enabled
|
|
1700
|
+
if (this.props.restrictPersonalization) {
|
|
1701
|
+
const hasTokens = checkForPersonalizationTokens(formData);
|
|
1702
|
+
if (hasTokens) {
|
|
1703
|
+
const message = this.props.intl.formatMessage(messages.personalizationTokensErrorMessage);
|
|
1704
|
+
CapNotification.error({message, key: 'personalizationTokensError'});
|
|
1705
|
+
return;
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1679
1709
|
const obj = this.getTransformedData(formData);
|
|
1680
1710
|
|
|
1681
1711
|
this.props.actions.editTemplate(obj, this.onUpdateTemplateComplete);
|
|
1682
1712
|
};
|
|
1713
|
+
|
|
1683
1714
|
handleFrameTasks = (e) => {
|
|
1684
1715
|
//
|
|
1685
1716
|
const type = e.data;
|
|
@@ -2175,6 +2206,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
2175
2206
|
hideTestAndPreviewBtn={this.props.hideTestAndPreviewBtn}
|
|
2176
2207
|
isFullMode={this.props.isFullMode}
|
|
2177
2208
|
eventContextTags={this.props?.eventContextTags}
|
|
2209
|
+
restrictPersonalization={this.props.restrictPersonalization}
|
|
2178
2210
|
/>;
|
|
2179
2211
|
})()}
|
|
2180
2212
|
</CapColumn>
|
|
@@ -2284,6 +2316,9 @@ Edit.propTypes = {
|
|
|
2284
2316
|
showTestAndPreviewSlidebox: PropTypes.bool,
|
|
2285
2317
|
handleTestAndPreview: PropTypes.func,
|
|
2286
2318
|
handleCloseTestAndPreview: PropTypes.func,
|
|
2319
|
+
restrictPersonalization: PropTypes.bool,
|
|
2320
|
+
isAnonymousType: PropTypes.bool,
|
|
2321
|
+
onPersonalizationTokensChange: PropTypes.func,
|
|
2287
2322
|
};
|
|
2288
2323
|
|
|
2289
2324
|
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
|
});
|
|
@@ -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;
|