@capillarytech/creatives-library 8.0.286 → 8.0.287

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.
Files changed (32) hide show
  1. package/package.json +1 -1
  2. package/utils/commonUtils.js +3 -0
  3. package/v2Components/CapTagList/index.js +6 -2
  4. package/v2Components/CapTagListWithInput/index.js +4 -0
  5. package/v2Components/FormBuilder/index.js +26 -3
  6. package/v2Components/FormBuilder/messages.js +4 -0
  7. package/v2Containers/CreativesContainer/SlideBoxContent.js +20 -0
  8. package/v2Containers/CreativesContainer/SlideBoxFooter.js +39 -3
  9. package/v2Containers/CreativesContainer/constants.js +6 -0
  10. package/v2Containers/CreativesContainer/index.js +32 -1
  11. package/v2Containers/CreativesContainer/messages.js +12 -0
  12. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +339 -0
  13. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +18 -0
  14. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +37 -0
  15. package/v2Containers/MobilePush/Create/index.js +45 -0
  16. package/v2Containers/MobilePush/Create/messages.js +4 -0
  17. package/v2Containers/MobilePush/Edit/index.js +45 -0
  18. package/v2Containers/MobilePush/Edit/messages.js +4 -0
  19. package/v2Containers/MobilePushNew/components/PlatformContentFields.js +36 -12
  20. package/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +68 -27
  21. package/v2Containers/MobilePushNew/index.js +32 -3
  22. package/v2Containers/MobilePushNew/messages.js +8 -0
  23. package/v2Containers/MobilepushWrapper/index.js +7 -1
  24. package/v2Containers/SmsTrai/Create/index.scss +1 -1
  25. package/v2Containers/TagList/index.js +17 -1
  26. package/v2Containers/TagList/messages.js +4 -0
  27. package/v2Containers/TemplatesV2/index.js +43 -23
  28. package/v2Containers/Viber/index.scss +1 -1
  29. package/v2Containers/WebPush/Create/index.js +25 -6
  30. package/v2Containers/WebPush/Create/messages.js +8 -1
  31. package/v2Containers/WebPush/Create/utils/validation.js +16 -9
  32. package/v2Containers/WebPush/Create/utils/validation.test.js +28 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "8.0.286",
4
+ "version": "8.0.287",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -559,3 +559,6 @@ export const validateCarouselCards = (
559
559
  reasons,
560
560
  };
561
561
  };
562
+
563
+ export const hasPersonalizationTags = (text = '') =>
564
+ (text && ((text.includes('{{') && text.includes('}}')) || (text.includes('[') && text.includes(']'))));
@@ -476,7 +476,9 @@ class CapTagList extends React.Component { // eslint-disable-line react/prefer-s
476
476
  >
477
477
  <CapTooltip
478
478
  title={
479
- fetchingSchemaError && (
479
+ this?.props?.disableTooltipMsg && this?.props?.disabled ? (
480
+ this?.props?.disableTooltipMsg
481
+ ) : fetchingSchemaError ? (
480
482
  <CapRow className="tooltip-text-container">
481
483
  <CapLabel className="tooltip-text1">
482
484
  {formatMessage(messages.somethingWentWrong)}
@@ -485,7 +487,7 @@ class CapTagList extends React.Component { // eslint-disable-line react/prefer-s
485
487
  {formatMessage(messages.labelFetchErrorMsg)}
486
488
  </CapLabel>
487
489
  </CapRow>
488
- )
490
+ ) : null
489
491
  }
490
492
  placement="right"
491
493
  >
@@ -538,6 +540,8 @@ CapTagList.propTypes = {
538
540
  currentOrgDetails: PropTypes.object,
539
541
  channel: PropTypes.string,
540
542
  disabled: PropTypes.bool,
543
+ // Optional custom tooltip message when disabled (used for personalization restriction)
544
+ disableTooltipMsg: PropTypes.string,
541
545
  fetchingSchemaError: PropTypes.bool,
542
546
  popoverPlacement: PropTypes.string,
543
547
  };
@@ -26,6 +26,7 @@ export const CapTagListWithInput = (props) => {
26
26
  className = '',
27
27
  userLocale = 'en',
28
28
  eventContextTags = [],
29
+ restrictPersonalization = false,
29
30
  // CapInput props
30
31
  inputId,
31
32
  inputValue = '',
@@ -78,6 +79,7 @@ export const CapTagListWithInput = (props) => {
78
79
  eventContextTags={eventContextTags}
79
80
  style={tagListStyle}
80
81
  popoverPlacement={popoverPlacement}
82
+ restrictPersonalization={restrictPersonalization}
81
83
  />
82
84
  )}
83
85
  </CapRow>
@@ -113,6 +115,7 @@ CapTagListWithInput.propTypes = {
113
115
  className: PropTypes.string,
114
116
  userLocale: PropTypes.string,
115
117
  eventContextTags: PropTypes.array,
118
+ restrictPersonalization: PropTypes.bool,
116
119
 
117
120
  // CapInput props
118
121
  inputId: PropTypes.string.isRequired,
@@ -150,6 +153,7 @@ CapTagListWithInput.defaultProps = {
150
153
  className: '',
151
154
  userLocale: 'en',
152
155
  eventContextTags: [],
156
+ restrictPersonalization: false,
153
157
  inputValue: '',
154
158
  inputSize: 'default',
155
159
  inputRequired: false,
@@ -63,7 +63,7 @@ import { REQUEST } from '../../v2Containers/Cap/constants'
63
63
  import { hasLiquidSupportFeature, isEmailUnsubscribeTagMandatory } from '../../utils/common';
64
64
  import { isUrl } from '../../v2Containers/Line/Container/Wrapper/utils';
65
65
  import { bindActionCreators } from 'redux';
66
- import { getChannelData, validateLiquidTemplateContent, validateMobilePushContent } from '../../utils/commonUtils';
66
+ import { getChannelData, hasPersonalizationTags, validateLiquidTemplateContent, validateMobilePushContent } from '../../utils/commonUtils';
67
67
  const TabPane = Tabs.TabPane;
68
68
  const {Column} = Table;
69
69
  const {TextArea} = CapInput;
@@ -903,11 +903,14 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
903
903
  if (errorData[parseInt(index)]) {
904
904
  if (message) {
905
905
  message = message.trim();
906
-
907
906
  if (message === "") {
908
907
  errorData[parseInt(index)][`message-editor${selector}`] = true;
909
908
  isValid = false;
910
909
  isCurrentTabValid = false;
910
+ } else if (this.props.restrictPersonalization && hasPersonalizationTags(message)) {
911
+ errorData[parseInt(index)][`message-editor${selector}`] = true;
912
+ isValid = false;
913
+ isCurrentTabValid = false;
911
914
  } else {
912
915
  errorData[parseInt(index)][`message-editor${selector}`] = false;
913
916
  const tagValidationResponse = this.validateTags(message, tags, injectedTags, false, this.props?.isFullMode);
@@ -937,6 +940,10 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
937
940
  errorData[parseInt(index)][`message-title${selector}`] = true;
938
941
  isValid = false;
939
942
  isCurrentTabValid = false;
943
+ } else if (this.props.restrictPersonalization && hasPersonalizationTags(title)) {
944
+ errorData[parseInt(index)][`message-title${selector}`] = true;
945
+ isValid = false;
946
+ isCurrentTabValid = false;
940
947
  } else {
941
948
  errorData[parseInt(index)][`message-title${selector}`] = false;
942
949
  const tagValidationResponse = this.validateTags(title, tags, injectedTags, false, this.props?.isFullMode);
@@ -2882,6 +2889,10 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2882
2889
  default:
2883
2890
  break;
2884
2891
  }
2892
+
2893
+ if (this.props.restrictPersonalization && hasPersonalizationTags(messageContent)) {
2894
+ errorMessageText = formatMessage(messages.personalizationTagsErrorMessage);
2895
+ }
2885
2896
  const prevErrorMessage = this.state.liquidErrorMessage?.STANDARD_ERROR_MSG?.[0];
2886
2897
  if (prevErrorMessage !== errorMessageText && errorMessageText && this.liquidFlow()) {
2887
2898
  this.setState((prevState) => ({
@@ -3047,6 +3058,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
3047
3058
  userLocale={this.props.userLocale}
3048
3059
  selectedOfferDetails={this.props.selectedOfferDetails}
3049
3060
  eventContextTags={this.props?.eventContextTags}
3061
+ restrictPersonalization={this.props.restrictPersonalization}
3050
3062
  />
3051
3063
  </CapColumn>
3052
3064
  );
@@ -3081,6 +3093,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
3081
3093
  inputProps={val.inputProps || {}}
3082
3094
  showInput={val.showInput !== false}
3083
3095
  showTagList={val.showTagList !== false}
3096
+ restrictPersonalization={this.props.restrictPersonalization}
3084
3097
  />
3085
3098
  </CapColumn>
3086
3099
  );
@@ -3457,8 +3470,15 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
3457
3470
  ifError = this.state.checkValidation && (isVersionEnable ? this.state.errorData[`${this.state.currentTab - 1}`][val.id] : this.state.errorData[val.id]);
3458
3471
  const { TAG_BRACKET_COUNT_MISMATCH_ERROR } = errorMessageForTags;
3459
3472
  const { formatMessage } = this.props.intl;
3460
- let errorMessageText = errorType === TAG_BRACKET_COUNT_MISMATCH_ERROR ? formatMessage(globalMessages.unbalanacedCurlyBraces) :(val.errorMessage && ifError ? val.errorMessage : '');
3461
3473
  const value = isVersionEnable ? this.state.formData[`${this.state.currentTab - 1}`][val.id] : this.state.formData[val.id];
3474
+ // Show personalization error for title field inline (same as message textarea) when restrictPersonalization is true
3475
+ const hasPersonalizationError = this.props.restrictPersonalization && hasPersonalizationTags(value);
3476
+ if (hasPersonalizationError) {
3477
+ ifError = true;
3478
+ }
3479
+ let errorMessageText = hasPersonalizationError
3480
+ ? formatMessage(messages.personalizationTagsErrorMessage)
3481
+ : (errorType === TAG_BRACKET_COUNT_MISMATCH_ERROR ? formatMessage(globalMessages.unbalanacedCurlyBraces) : (val.errorMessage && ifError ? val.errorMessage : ''));
3462
3482
  if (styling === 'semantic') {
3463
3483
  columns.push(
3464
3484
  <CapColumn key={val.id} span={val.width} offset={val.offset} style={val.style || {}}>
@@ -3709,6 +3729,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
3709
3729
  selectedOfferDetails={this.props.selectedOfferDetails}
3710
3730
  channel={channel}
3711
3731
  eventContextTags={this.props?.eventContextTags}
3732
+ restrictPersonalization={this.props.restrictPersonalization}
3712
3733
  />
3713
3734
  </CapColumn>
3714
3735
  );
@@ -3760,6 +3781,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
3760
3781
  inputProps={val.inputProps || {}}
3761
3782
  showInput={val.showInput !== false}
3762
3783
  showTagList={val.showTagList !== false}
3784
+ restrictPersonalization={this.props.restrictPersonalization}
3763
3785
  />
3764
3786
  </CapColumn>
3765
3787
  );
@@ -4403,6 +4425,7 @@ FormBuilder.propTypes = {
4403
4425
  forwardedTags: PropTypes.object.isRequired,
4404
4426
  isLoyaltyModule: PropTypes.bool.isRequired,
4405
4427
  isTestAndPreviewMode: PropTypes.bool, // Add new prop type
4428
+ restrictPersonalization: PropTypes.bool,
4406
4429
  };
4407
4430
 
4408
4431
  const mapStateToProps = createStructuredSelector({
@@ -102,4 +102,8 @@ export default defineMessages({
102
102
  id: 'creatives.componentsV2.FormBuilder.base64ImageError',
103
103
  defaultMessage: 'Base64 images are not allowed. Please upload your image to a gallery and use it, or add the image URL instead.',
104
104
  },
105
+ personalizationTagsErrorMessage: {
106
+ id: `creatives.componentsV2.FormBuilder.personalizationTagsErrorMessage`,
107
+ defaultMessage: 'Personalization tags are not supported for anonymous customers, please remove the tags.',
108
+ },
105
109
  });
@@ -173,6 +173,9 @@ export function SlideBoxContent(props) {
173
173
  showTestAndPreviewSlidebox,
174
174
  handleTestAndPreview,
175
175
  handleCloseTestAndPreview,
176
+ restrictPersonalization = false,
177
+ isAnonymousType = false,
178
+ onPersonalizationTokensChange,
176
179
  isTestAndPreviewMode,
177
180
  onHtmlEditorValidationStateChange,
178
181
  } = props;
@@ -637,6 +640,8 @@ export function SlideBoxContent(props) {
637
640
  smsRegister={smsRegister}
638
641
  onShowTemplates={onShowTemplates}
639
642
  eventContextTags={eventContextTags}
643
+ restrictPersonalization={restrictPersonalization}
644
+ isAnonymousType={isAnonymousType}
640
645
  />
641
646
  )}
642
647
 
@@ -677,6 +682,8 @@ export function SlideBoxContent(props) {
677
682
  isTestAndPreviewMode={isTestAndPreviewMode}
678
683
  location={location}
679
684
  onHtmlEditorValidationStateChange={onHtmlEditorValidationStateChange}
685
+ restrictPersonalization={restrictPersonalization}
686
+ isAnonymousType={isAnonymousType}
680
687
  />
681
688
  )}
682
689
  {(isEditEmailWithId || isEmailEditWithContent) && (
@@ -797,6 +804,9 @@ export function SlideBoxContent(props) {
797
804
  showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
798
805
  handleTestAndPreview={handleTestAndPreview}
799
806
  handleCloseTestAndPreview={handleCloseTestAndPreview}
807
+ restrictPersonalization={restrictPersonalization}
808
+ isAnonymousType={isAnonymousType}
809
+ onPersonalizationTokensChange={onPersonalizationTokensChange}
800
810
  />
801
811
  ) : (
802
812
  <MobilePushNew
@@ -824,6 +834,9 @@ export function SlideBoxContent(props) {
824
834
  eventContextTags={eventContextTags}
825
835
  showLiquidErrorInFooter={showLiquidErrorInFooter}
826
836
  handleClose={handleClose}
837
+ restrictPersonalization={restrictPersonalization}
838
+ isAnonymousType={isAnonymousType}
839
+ onPersonalizationTokensChange={onPersonalizationTokensChange}
827
840
  />
828
841
  )
829
842
  )}
@@ -861,6 +874,9 @@ export function SlideBoxContent(props) {
861
874
  showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
862
875
  handleTestAndPreview={handleTestAndPreview}
863
876
  handleCloseTestAndPreview={handleCloseTestAndPreview}
877
+ restrictPersonalization={restrictPersonalization}
878
+ isAnonymousType={isAnonymousType}
879
+ onPersonalizationTokensChange={onPersonalizationTokensChange}
864
880
  />
865
881
  ) : (
866
882
  <MobilePushNew
@@ -895,6 +911,8 @@ export function SlideBoxContent(props) {
895
911
  showLiquidErrorInFooter={showLiquidErrorInFooter}
896
912
  onCreateComplete={onCreateComplete}
897
913
  creativesMode={creativesMode}
914
+ restrictPersonalization={restrictPersonalization}
915
+ isAnonymousType={isAnonymousType}
898
916
  />
899
917
  )
900
918
  )}
@@ -1143,6 +1161,8 @@ export function SlideBoxContent(props) {
1143
1161
  supportedTags={supportedTags}
1144
1162
  selectedOfferDetails={selectedOfferDetails}
1145
1163
  eventContextTags={eventContextTags}
1164
+ restrictPersonalization={restrictPersonalization}
1165
+ isAnonymousType={isAnonymousType}
1146
1166
  />
1147
1167
  )}
1148
1168
  {isCreateRcs && (<Rcs
@@ -43,8 +43,11 @@ function SlideBoxFooter(props) {
43
43
  currentChannel,
44
44
  emailCreateMode,
45
45
  selectedEmailCreateMode,
46
+ restrictPersonalization = false,
47
+ isAnonymousType = false,
48
+ templateData = {},
49
+ hasPersonalizationTokenError: hasPersonalizationTokenErrorProp = false,
46
50
  } = props;
47
-
48
51
  // Calculate if buttons should be disabled
49
52
  // Only apply validation state checks for EMAIL channel in HTML Editor mode (not BEE/DragDrop)
50
53
  // For other channels, BEE editor, or when htmlEditorValidationState is not provided, don't disable based on validation
@@ -127,6 +130,32 @@ function SlideBoxFooter(props) {
127
130
  const hasBEEEditorErrors = isEmailChannel && isBEEEditorMode && (hasStandardErrors || hasLiquidErrors) && (!htmlEditorValidationState || !htmlEditorHasErrors);
128
131
 
129
132
  const shouldShowErrorInfoNote = hasBEEEditorErrors || isSupportCKEditor;
133
+
134
+ // Check for personalization tokens in title/message when anonymous user tries to save
135
+ const hasPersonalizationTokens = () => {
136
+ if (!isAnonymousType || !templateData) return false;
137
+
138
+ const androidTitle = templateData?.versions?.ANDROID?.base?.title || '';
139
+ const iosTitle = templateData?.versions?.IOS?.base?.title || '';
140
+ const androidMessageBody = templateData?.versions?.ANDROID?.base?.expandibleDetails?.message
141
+ || templateData?.versions?.ANDROID?.base?.expandableDetails?.message || '';
142
+ const iosMessageBody = templateData?.versions?.IOS?.base?.expandibleDetails?.message
143
+ || templateData?.versions?.IOS?.base?.expandableDetails?.message || '';
144
+ const contentToCheck = `${androidTitle} ${iosTitle} ${androidMessageBody} ${iosMessageBody}`;
145
+ // Check for liquid tags {{ }}
146
+ if (contentToCheck.includes('{{') && contentToCheck.includes('}}')) {
147
+ return true;
148
+ }
149
+ // Check for event context tags [
150
+ if (contentToCheck.includes('[') && contentToCheck.includes(']')) {
151
+ return true;
152
+ }
153
+ return false;
154
+ };
155
+
156
+ // Use prop from parent (FormBuilder flow) when available; else fall back to templateData check
157
+ const hasPersonalizationTokenError = hasPersonalizationTokenErrorProp === true || (restrictPersonalization && hasPersonalizationTokens());
158
+
130
159
  return (
131
160
  <div className="template-footer-width">
132
161
  {shouldShowErrorInfoNote && (
@@ -147,7 +176,7 @@ function SlideBoxFooter(props) {
147
176
  <CapRow>
148
177
  <CapButton
149
178
  onClick={onSave}
150
- disabled={isTemplateNameEmpty || fetchingCmsData || shouldDisableButtons}
179
+ disabled={isTemplateNameEmpty || fetchingCmsData || shouldDisableButtons || hasPersonalizationTokenError}
151
180
  >
152
181
  {isFullMode ? (
153
182
  getFullModeSaveBtn(slidBoxContent, isCreatingTemplate)
@@ -159,7 +188,7 @@ function SlideBoxFooter(props) {
159
188
  <CapButton
160
189
  type="secondary"
161
190
  onClick={onTestAndPreview}
162
- disabled={shouldDisableButtons}
191
+ disabled={shouldDisableButtons || hasPersonalizationTokenError}
163
192
  style={{ marginLeft: '8px' }}
164
193
  >
165
194
  <FormattedMessage {...messages.testAndPreview} />
@@ -220,6 +249,11 @@ SlideBoxFooter.propTypes = {
220
249
  currentChannel: PropTypes.string,
221
250
  emailCreateMode: PropTypes.string,
222
251
  selectedEmailCreateMode: PropTypes.string,
252
+ restrictPersonalization: PropTypes.bool,
253
+ isAnonymousType: PropTypes.bool,
254
+ templateData: PropTypes.object,
255
+ formData: PropTypes.array,
256
+ hasPersonalizationTokenError: PropTypes.bool,
223
257
  };
224
258
 
225
259
  SlideBoxFooter.defaultProps = {
@@ -245,5 +279,7 @@ SlideBoxFooter.defaultProps = {
245
279
  currentChannel: '',
246
280
  emailCreateMode: '',
247
281
  selectedEmailCreateMode: '',
282
+ formData: [],
283
+ hasPersonalizationTokenError: false,
248
284
  };
249
285
  export default SlideBoxFooter;
@@ -52,3 +52,9 @@ export const GENERIC = "GENERIC";
52
52
  export const LIQUID_ERROR_MSG = "LIQUID_ERROR_MSG";
53
53
  export const STANDARD_ERROR_MSG = "STANDARD_ERROR_MSG";
54
54
  export const COMMON_CHANNELS = ['sms', 'email', 'wechat', 'mobilepush', 'webpush', 'line', 'viber', 'facebook', 'call_task', 'ftp', 'assets'];
55
+ export const MIXED = "MIXED";
56
+ export const VISITOR = "VISITOR";
57
+ export const ALLOWED_CHANNELS_FOR_ANONYMOUS = ['mobilepush', 'webpush'];
58
+ export const ALL_CHANNELS_NEW = [
59
+ 'sms', 'email', 'whatsapp', 'facebook', 'line', 'viber', 'rcs', 'zalo', 'inapp', 'call_task', 'ftp',
60
+ ];
@@ -130,6 +130,7 @@ export class Creatives extends React.Component {
130
130
  validationComplete: false, // Flag to track if validation has completed
131
131
  errorsAcknowledged: false, // Flag to track if user has acknowledged errors by clicking redirection icon
132
132
  },
133
+ hasPersonalizationTokenError: false, // Track personalization token errors in form
133
134
  };
134
135
  this.liquidFlow = Boolean(commonUtil.hasLiquidSupportFeature());
135
136
  this.creativesTemplateSteps = {
@@ -1777,6 +1778,12 @@ export class Creatives extends React.Component {
1777
1778
  });
1778
1779
  }
1779
1780
 
1781
+ handlePersonalizationTokensChange = (hasTokens) => {
1782
+ this.setState({
1783
+ hasPersonalizationTokenError: hasTokens,
1784
+ });
1785
+ }
1786
+
1780
1787
  shouldShowContinueFooter = () => { // only for email for now, has to be modified according to channel
1781
1788
  const {
1782
1789
  slidBoxContent, templateStep, currentChannel, emailCreateMode, mobilePushCreateMode, inAppEditorType, weChatTemplateType,
@@ -1944,6 +1951,21 @@ export class Creatives extends React.Component {
1944
1951
  ? CAP_SPACE_32
1945
1952
  : 0;
1946
1953
  /* TODO: Instead of passing down same props separately to each component down, write common function to these props and pass it accordingly */
1954
+
1955
+ // Compute anonymous user type and channel restrictions
1956
+ const { customerType = '' } = this.props;
1957
+ const isAnonymousType = customerType === constants.VISITOR || customerType === constants.MIXED;
1958
+ const restrictPersonalization = isAnonymousType;
1959
+
1960
+ // For anonymous users, only MOBILEPUSH and WEBPUSH channels are allowed
1961
+ let updatedChannelsToHide = [...(channelsToHide || [])];
1962
+ if (isAnonymousType) {
1963
+ const allowedChannels = constants.ALLOWED_CHANNELS_FOR_ANONYMOUS;
1964
+ const allChannels = constants.ALL_CHANNELS_NEW;
1965
+ const channelsToRemove = allChannels.filter((channel) => !allowedChannels.includes(channel));
1966
+ updatedChannelsToHide = [...new Set([...updatedChannelsToHide, ...channelsToRemove])];
1967
+ }
1968
+
1947
1969
  return (
1948
1970
  <SlideBoxWrapper
1949
1971
  slideBoxWrapperMargin={slideBoxWrapperMargin}
@@ -2014,10 +2036,13 @@ export class Creatives extends React.Component {
2014
2036
  mobilePushCreateMode={mobilePushCreateMode}
2015
2037
  showTemplateName={this.showTemplateName}
2016
2038
  onValidationFail={this.onValidationFail}
2017
- channelsToHide={channelsToHide}
2039
+ channelsToHide={updatedChannelsToHide}
2018
2040
  forwardedTags={forwardedTags}
2019
2041
  selectedOfferDetails={selectedOfferDetails}
2020
2042
  channelsToDisable={channelsToDisable}
2043
+ restrictPersonalization={restrictPersonalization}
2044
+ isAnonymousType={isAnonymousType}
2045
+ customerType={customerType}
2021
2046
  weChatTemplateType={weChatTemplateType}
2022
2047
  onWechatTemplateChange={this.onWechatTemplateChange}
2023
2048
  weChatMaptemplateStep={weChatMaptemplateStep}
@@ -2050,6 +2075,7 @@ export class Creatives extends React.Component {
2050
2075
  handleCloseTestAndPreview={this.handleCloseTestAndPreview}
2051
2076
  isTestAndPreviewMode={(() => this.state.isTestAndPreviewMode)()}
2052
2077
  onHtmlEditorValidationStateChange={this.updateHtmlEditorValidationState}
2078
+ onPersonalizationTokensChange={this.handlePersonalizationTokensChange}
2053
2079
  />
2054
2080
  )}
2055
2081
  footer={this.shouldShowFooter() ? (
@@ -2082,6 +2108,10 @@ export class Creatives extends React.Component {
2082
2108
  })()}
2083
2109
  htmlEditorValidationState={htmlEditorValidationState}
2084
2110
  isCreatingTemplate={slidBoxContent === 'createTemplate' && currentChannel.toUpperCase() === constants.EMAIL}
2111
+ restrictPersonalization={restrictPersonalization}
2112
+ isAnonymousType={isAnonymousType}
2113
+ templateData={templateData}
2114
+ hasPersonalizationTokenError={this.state.hasPersonalizationTokenError}
2085
2115
  />
2086
2116
  ) : isLiquidValidationError && (
2087
2117
  <CapRow className="template-footer-width">
@@ -2131,6 +2161,7 @@ Creatives.propTypes = {
2131
2161
  hostName: PropTypes.string,
2132
2162
  eventContextTags: PropTypes.array,
2133
2163
  loyaltyTagFetchingDependencies: PropTypes.object,
2164
+ customerType: PropTypes.string,
2134
2165
  intl: PropTypes.shape({
2135
2166
  formatMessage: PropTypes.func,
2136
2167
  }),
@@ -378,4 +378,16 @@ export default defineMessages({
378
378
  id: `${scope}.next`,
379
379
  defaultMessage: `Next`,
380
380
  },
381
+ "channelNotSupportedAnonymous": {
382
+ id: `${scope}.channelNotSupportedAnonymous`,
383
+ defaultMessage: `This channel is not supported for anonymous customers`,
384
+ },
385
+ "personalizationNotSupportedAnonymous": {
386
+ id: `${scope}.personalizationNotSupportedAnonymous`,
387
+ defaultMessage: `Personalization tags are not supported for anonymous customers`,
388
+ },
389
+ "personalizationTokensErrorMessage": {
390
+ id: `${scope}.personalizationTokensErrorMessage`,
391
+ defaultMessage: `Personalization tags are not supported for anonymous customers. Please remove the tags.`,
392
+ },
381
393
  });