@capillarytech/creatives-library 8.0.285-alpha.1 → 8.0.286

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 (45) hide show
  1. package/constants/unified.js +1 -0
  2. package/initialState.js +2 -0
  3. package/package.json +1 -1
  4. package/utils/common.js +8 -5
  5. package/utils/commonUtils.js +83 -2
  6. package/utils/tagValidations.js +222 -84
  7. package/utils/tests/commonUtil.test.js +118 -147
  8. package/utils/tests/tagValidations.test.js +358 -280
  9. package/v2Components/ErrorInfoNote/index.js +5 -2
  10. package/v2Components/FormBuilder/index.js +158 -64
  11. package/v2Components/FormBuilder/messages.js +8 -0
  12. package/v2Components/HtmlEditor/HTMLEditor.js +5 -0
  13. package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -0
  14. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +15 -0
  15. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +2 -1
  16. package/v2Containers/Cap/mockData.js +14 -0
  17. package/v2Containers/Cap/reducer.js +55 -3
  18. package/v2Containers/Cap/tests/reducer.test.js +102 -0
  19. package/v2Containers/CreativesContainer/index.js +1 -0
  20. package/v2Containers/Email/index.js +5 -1
  21. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +62 -10
  22. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +115 -12
  23. package/v2Containers/FTP/index.js +51 -2
  24. package/v2Containers/FTP/messages.js +4 -0
  25. package/v2Containers/InApp/index.js +96 -1
  26. package/v2Containers/InApp/tests/index.test.js +6 -17
  27. package/v2Containers/InappAdvance/index.js +103 -2
  28. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +24 -3
  29. package/v2Containers/Line/Container/Text/index.js +1 -0
  30. package/v2Containers/MobilePushNew/index.js +33 -2
  31. package/v2Containers/Rcs/index.js +37 -12
  32. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +18 -4
  33. package/v2Containers/SmsTrai/Create/index.scss +1 -1
  34. package/v2Containers/SmsTrai/Edit/index.js +47 -6
  35. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +6 -6
  36. package/v2Containers/Viber/index.js +1 -0
  37. package/v2Containers/Viber/index.scss +1 -1
  38. package/v2Containers/WebPush/Create/hooks/useTagManagement.js +3 -1
  39. package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +7 -0
  40. package/v2Containers/WebPush/Create/index.js +2 -2
  41. package/v2Containers/WebPush/Create/utils/validation.js +9 -18
  42. package/v2Containers/WebPush/Create/utils/validation.test.js +24 -0
  43. package/v2Containers/Whatsapp/index.js +17 -9
  44. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +624 -248
  45. 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
- await liquidMiddleWare();
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"
@@ -3117,6 +3117,7 @@ new message content.",
3117
3117
  },
3118
3118
  ]
3119
3119
  }
3120
+ showTruncatedTooltip={false}
3120
3121
  size="large"
3121
3122
  style={
3122
3123
  Object {
@@ -3135,6 +3136,7 @@ new message content.",
3135
3136
  />
3136
3137
  }
3137
3138
  onChange={[Function]}
3139
+ onDropdownVisibleChange={[Function]}
3138
3140
  removeIcon={
3139
3141
  <CapIcon
3140
3142
  size="s"
@@ -3199,6 +3201,7 @@ new message content.",
3199
3201
  onBlur={[Function]}
3200
3202
  onChange={[Function]}
3201
3203
  onDeselect={[Function]}
3204
+ onDropdownVisibleChange={[Function]}
3202
3205
  onFocus={[Function]}
3203
3206
  onInputKeyDown={[Function]}
3204
3207
  onSearch={[Function]}
@@ -3437,7 +3440,11 @@ new message content.",
3437
3440
  }
3438
3441
  }
3439
3442
  title=""
3440
- />
3443
+ >
3444
+ <div
3445
+ className="cap-select-option-tooltip"
3446
+ />
3447
+ </div>
3441
3448
  </div>
3442
3449
  <span
3443
3450
  className="ant-select-arrow"
@@ -6940,6 +6947,7 @@ new message content.",
6940
6947
  },
6941
6948
  ]
6942
6949
  }
6950
+ showTruncatedTooltip={false}
6943
6951
  size="large"
6944
6952
  style={
6945
6953
  Object {
@@ -6958,6 +6966,7 @@ new message content.",
6958
6966
  />
6959
6967
  }
6960
6968
  onChange={[Function]}
6969
+ onDropdownVisibleChange={[Function]}
6961
6970
  removeIcon={
6962
6971
  <CapIcon
6963
6972
  size="s"
@@ -7022,6 +7031,7 @@ new message content.",
7022
7031
  onBlur={[Function]}
7023
7032
  onChange={[Function]}
7024
7033
  onDeselect={[Function]}
7034
+ onDropdownVisibleChange={[Function]}
7025
7035
  onFocus={[Function]}
7026
7036
  onInputKeyDown={[Function]}
7027
7037
  onSearch={[Function]}
@@ -7260,7 +7270,11 @@ new message content.",
7260
7270
  }
7261
7271
  }
7262
7272
  title=""
7263
- />
7273
+ >
7274
+ <div
7275
+ className="cap-select-option-tooltip"
7276
+ />
7277
+ </div>
7264
7278
  </div>
7265
7279
  <span
7266
7280
  className="ant-select-arrow"
@@ -10707,6 +10721,7 @@ new message content.",
10707
10721
  },
10708
10722
  ]
10709
10723
  }
10724
+ showTruncatedTooltip={false}
10710
10725
  size="large"
10711
10726
  style={
10712
10727
  Object {
@@ -10725,6 +10740,7 @@ new message content.",
10725
10740
  />
10726
10741
  }
10727
10742
  onChange={[Function]}
10743
+ onDropdownVisibleChange={[Function]}
10728
10744
  removeIcon={
10729
10745
  <CapIcon
10730
10746
  size="s"
@@ -10789,6 +10805,7 @@ new message content.",
10789
10805
  onBlur={[Function]}
10790
10806
  onChange={[Function]}
10791
10807
  onDeselect={[Function]}
10808
+ onDropdownVisibleChange={[Function]}
10792
10809
  onFocus={[Function]}
10793
10810
  onInputKeyDown={[Function]}
10794
10811
  onSearch={[Function]}
@@ -11027,7 +11044,11 @@ new message content.",
11027
11044
  }
11028
11045
  }
11029
11046
  title=""
11030
- />
11047
+ >
11048
+ <div
11049
+ className="cap-select-option-tooltip"
11050
+ />
11051
+ </div>
11031
11052
  </div>
11032
11053
  <span
11033
11054
  className="ant-select-arrow"
@@ -137,6 +137,7 @@ export const LineText = ({
137
137
  const { valid, isBraceError } = validateTags({
138
138
  content: value,
139
139
  tagsParam: tags,
140
+ injectedTagsParams: injectedTags,
140
141
  location,
141
142
  tagModule: 'outbound',
142
143
  isFullMode,
@@ -77,6 +77,7 @@ import { getContent } from "../MobilePush/commonMethods";
77
77
  import { getMessageObject } from "../../utils/messageUtils";
78
78
  import { gtmPush } from "../../utils/gtmTrackers";
79
79
  import mobilePushReducer from "./reducer";
80
+ import { hasLiquidSupportFeature } from "../../utils/common";
80
81
  import formBuilderMessages from "../../v2Components/FormBuilder/messages";
81
82
  import { validateMobilePushContent } from "../../utils/commonUtils";
82
83
  import { getSingleTab } from "../InApp/utils";
@@ -798,9 +799,10 @@ const MobilePushNew = ({
798
799
  (value) => {
799
800
  let errorTemplateDescMessage = "";
800
801
 
801
- const { isBraceError } = validateTags({
802
+ const { unsupportedTags, isBraceError } = validateTags({
802
803
  content: value,
803
804
  tagsParam: tags,
805
+ injectedTagsParams: injectedTags,
804
806
  location,
805
807
  tagModule: getDefaultTags,
806
808
  isFullMode,
@@ -810,6 +812,14 @@ const MobilePushNew = ({
810
812
  messages.emptyTemplateDescErrorMessage
811
813
  );
812
814
  }
815
+ if (unsupportedTags?.length > 0) {
816
+ errorTemplateDescMessage = formatMessage(
817
+ globalMessages.unsupportedTagsValidationError,
818
+ {
819
+ unsupportedTags,
820
+ }
821
+ );
822
+ }
813
823
  if (isBraceError) {
814
824
  errorTemplateDescMessage = formatMessage(
815
825
  globalMessages.unbalanacedCurlyBraces
@@ -2596,6 +2606,20 @@ const MobilePushNew = ({
2596
2606
  getLiquidTags: globalActionsProps.getLiquidTags,
2597
2607
  formatMessage,
2598
2608
  messages: formBuilderMessages,
2609
+ tagLookupMap: metaEntities?.tagLookupMap || {},
2610
+ eventContextTags: metaEntities?.eventContextTags || [],
2611
+ isLiquidFlow: hasLiquidSupportFeature(),
2612
+ forwardedTags: {},
2613
+ skipTags: (tag) => {
2614
+ const skipRegexes = [
2615
+ /dynamic_expiry_date_after_\d+_days\.FORMAT_\d/,
2616
+ /unsubscribe\(#[a-zA-Z\d]{6}\)/,
2617
+ /Link_to_[a-zA-z]/,
2618
+ /SURVEY.*\.TOKEN/,
2619
+ /^[A-Za-z].*\([a-zA-Z\d]*\)/,
2620
+ ];
2621
+ return skipRegexes.some((regex) => regex.test(tag));
2622
+ },
2599
2623
  singleTab: getSingleTab(accountData),
2600
2624
  });
2601
2625
  }, [
@@ -2604,9 +2628,12 @@ const MobilePushNew = ({
2604
2628
  activeTab,
2605
2629
  globalActionsProps,
2606
2630
  formatMessage,
2631
+ metaEntities,
2607
2632
  accountData,
2608
2633
  ]);
2609
2634
 
2635
+ const isLiquidFlow = hasLiquidSupportFeature();
2636
+
2610
2637
  useEffect(() => {
2611
2638
  // Always map to { label } for both platforms
2612
2639
  const newButtons = Array.isArray(ctaData)
@@ -3003,7 +3030,11 @@ const MobilePushNew = ({
3003
3030
  <CapButton
3004
3031
  type="primary"
3005
3032
  onClick={() => {
3006
- liquidMiddleWare();
3033
+ if (isLiquidFlow) {
3034
+ liquidMiddleWare();
3035
+ } else {
3036
+ handleSave();
3037
+ }
3007
3038
  }}
3008
3039
  className="save-button"
3009
3040
  disabled={isSaveDisabled}
@@ -394,15 +394,23 @@ export const Rcs = (props) => {
394
394
  const validationResponse =
395
395
  validateTags({
396
396
  content: contentForValidation,
397
- tagsParam: tags,
398
- location,
399
- tagModule: getDefaultTags,
400
- isFullMode,
401
- }) || {};
402
- const errorMsg =
403
- (validationResponse?.isBraceError &&
404
- formatMessage(globalMessages.unbalanacedCurlyBraces)) ||
405
- false;
397
+ tagsParam: tags,
398
+ injectedTagsParams: injectedTags,
399
+ location,
400
+ tagModule: getDefaultTags,
401
+ eventContextTags,
402
+ isFullMode,
403
+ }) || {};
404
+ const unsupportedTagsLengthCheck =
405
+ validationResponse?.unsupportedTags?.length > 0;
406
+ const errorMsg =
407
+ (unsupportedTagsLengthCheck &&
408
+ formatMessage(globalMessages.unsupportedTagsValidationError, {
409
+ unsupportedTags: validationResponse.unsupportedTags,
410
+ })) ||
411
+ (validationResponse.isBraceError &&
412
+ formatMessage(globalMessages.unbalanacedCurlyBraces)) ||
413
+ false;
406
414
  if (type === TITLE_TEXT) setTemplateTitleError(errorMsg);
407
415
  if (type === MESSAGE_TEXT) setTemplateDescError(errorMsg);
408
416
  };
@@ -827,9 +835,10 @@ export const Rcs = (props) => {
827
835
 
828
836
  const templateDescErrorHandler = (value) => {
829
837
  let errorMessage = false;
830
- const { isBraceError } = validateTags({
838
+ const { unsupportedTags, isBraceError } = validateTags({
831
839
  content: value,
832
840
  tagsParam: tags,
841
+ injectedTagsParams: injectedTags,
833
842
  location,
834
843
  tagModule: getDefaultTags,
835
844
  isFullMode,
@@ -859,10 +868,26 @@ export const Rcs = (props) => {
859
868
  };
860
869
 
861
870
  const fallbackMessageErrorHandler = (value) => {
871
+ let errorMessage = false;
872
+ const { unsupportedTags } = validateTags({
873
+ content: value,
874
+ tagsParam: tags,
875
+ injectedTagsParams: injectedTags,
876
+ location,
877
+ tagModule: getDefaultTags,
878
+ isFullMode,
879
+ }) || {};
862
880
  if (value?.length > FALLBACK_MESSAGE_MAX_LENGTH) {
863
- return formatMessage(messages.fallbackMsgLenError);
881
+ errorMessage = formatMessage(messages.fallbackMsgLenError);
882
+ } else if (unsupportedTags?.length > 0) {
883
+ errorMessage = formatMessage(
884
+ globalMessages.unsupportedTagsValidationError,
885
+ {
886
+ unsupportedTags,
887
+ },
888
+ );
864
889
  }
865
- return false;
890
+ return errorMessage;
866
891
  };
867
892
 
868
893
  // Check for forbidden characters: square brackets [] and single curly braces {}
@@ -86505,6 +86505,7 @@ new message content.",
86505
86505
  },
86506
86506
  ]
86507
86507
  }
86508
+ showTruncatedTooltip={false}
86508
86509
  size="large"
86509
86510
  style={
86510
86511
  Object {
@@ -86524,6 +86525,7 @@ new message content.",
86524
86525
  />
86525
86526
  }
86526
86527
  onChange={[Function]}
86528
+ onDropdownVisibleChange={[Function]}
86527
86529
  removeIcon={
86528
86530
  <_default
86529
86531
  size="s"
@@ -86589,6 +86591,7 @@ new message content.",
86589
86591
  onBlur={[Function]}
86590
86592
  onChange={[Function]}
86591
86593
  onDeselect={[Function]}
86594
+ onDropdownVisibleChange={[Function]}
86592
86595
  onFocus={[Function]}
86593
86596
  onInputKeyDown={[Function]}
86594
86597
  onSearch={[Function]}
@@ -86827,9 +86830,13 @@ new message content.",
86827
86830
  "opacity": 1,
86828
86831
  }
86829
86832
  }
86830
- title="Vertical Medium"
86833
+ title=""
86831
86834
  >
86832
- Vertical Medium
86835
+ <div
86836
+ className="cap-select-option-tooltip"
86837
+ >
86838
+ Vertical Medium
86839
+ </div>
86833
86840
  </div>
86834
86841
  </div>
86835
86842
  <span
@@ -105847,6 +105854,7 @@ new message content.",
105847
105854
  },
105848
105855
  ]
105849
105856
  }
105857
+ showTruncatedTooltip={false}
105850
105858
  size="large"
105851
105859
  style={
105852
105860
  Object {
@@ -105866,6 +105874,7 @@ new message content.",
105866
105874
  />
105867
105875
  }
105868
105876
  onChange={[Function]}
105877
+ onDropdownVisibleChange={[Function]}
105869
105878
  removeIcon={
105870
105879
  <_default
105871
105880
  size="s"
@@ -105931,6 +105940,7 @@ new message content.",
105931
105940
  onBlur={[Function]}
105932
105941
  onChange={[Function]}
105933
105942
  onDeselect={[Function]}
105943
+ onDropdownVisibleChange={[Function]}
105934
105944
  onFocus={[Function]}
105935
105945
  onInputKeyDown={[Function]}
105936
105946
  onSearch={[Function]}
@@ -106169,9 +106179,13 @@ new message content.",
106169
106179
  "opacity": 1,
106170
106180
  }
106171
106181
  }
106172
- title="Vertical Medium"
106182
+ title=""
106173
106183
  >
106174
- Vertical Medium
106184
+ <div
106185
+ className="cap-select-option-tooltip"
106186
+ >
106187
+ Vertical Medium
106188
+ </div>
106175
106189
  </div>
106176
106190
  </div>
106177
106191
  <span
@@ -98,5 +98,5 @@
98
98
  }
99
99
 
100
100
  .create-dlt-msg {
101
- margin-left: 120px;
101
+ margin-left: 100px;
102
102
  }
@@ -39,8 +39,10 @@ import formBuilderMessages from '../../../v2Components/FormBuilder/messages';
39
39
  import UnifiedPreview from '../../../v2Components/CommonTestAndPreview/UnifiedPreview';
40
40
  import TestAndPreviewSlidebox from '../../../v2Components/TestAndPreviewSlidebox';
41
41
  import withCreatives from '../../../hoc/withCreatives';
42
+ import { validateTags } from '../../../utils/tagValidations';
42
43
  import {
43
44
  CHARLIMIT,
45
+ SMS,
44
46
  SMS_TRAI_VAR,
45
47
  TAG,
46
48
  EMBEDDED,
@@ -49,15 +51,16 @@ import {
49
51
  ALL,
50
52
  LIBRARY,
51
53
  } from './constants';
52
- import { SMS } from '../../CreativesContainer/constants';
53
54
  import v2EditSmsReducer from '../../Sms/Edit/reducer';
54
55
  import { v2SmsEditSagas } from '../../Sms/Edit/sagas';
55
56
  import ErrorInfoNote from '../../../v2Components/ErrorInfoNote';
56
57
  import { validateLiquidTemplateContent } from '../../../utils/commonUtils';
58
+ import { hasLiquidSupportFeature } from '../../../utils/common';
57
59
  import { ANDROID } from '../../../v2Components/CommonTestAndPreview/constants';
58
60
 
59
61
  let varMap = {};
60
62
  let traiData = {};
63
+ let tagValidationResponse = {};
61
64
  const { TextArea } = CapInput;
62
65
  const { CapLabelInline } = CapLabel;
63
66
 
@@ -91,6 +94,7 @@ export const SmsTraiEdit = (props) => {
91
94
  const [tags, updateTags] = useState([]);
92
95
  const [textAreaId, updateTextAreaId] = useState();
93
96
  const [isValidationError, updateIsValidationError] = useState(false);
97
+ const [isTagValidationError, updateIsTagValidationError] = useState(false);
94
98
  const [totalMessageLength, setTotalMessageLength] = useState(0);
95
99
  const [isUnicodeAllowed, updateIsUnicodeAllowed] = useState(true);
96
100
  const [showMsgLengthNote, updateshowMsgLengthNote] = useState(false);
@@ -225,6 +229,29 @@ export const SmsTraiEdit = (props) => {
225
229
  }
226
230
  }, []);
227
231
 
232
+ //performs tag validation
233
+ useEffect(() => {
234
+ if (
235
+ !isFullMode &&
236
+ updatedSmsEditor?.length > 0 &&
237
+ !updatedSmsEditor.includes(SMS_TRAI_VAR)
238
+ ) {
239
+ tagValidationResponse =
240
+ validateTags({
241
+ content: updatedSmsEditor.join(''),
242
+ tagsParam: tags,
243
+ injectedTagsParams: injectedTags,
244
+ location,
245
+ tagModule: getDefaultTags,
246
+ eventContextTags,
247
+ isFullMode,
248
+ }) || {};
249
+ updateIsTagValidationError(
250
+ tagValidationResponse.unsupportedTags.length > 0,
251
+ );
252
+ }
253
+ }, [updatedSmsEditor, tags]);
254
+
228
255
  const computeUpdatedSmsEditor = () => {
229
256
  const arr = [...tempMsgArray];
230
257
  const varMapKeys = Object.keys(varMap)?.map((key) => Number(key.slice(8)))?.sort((a, b) => a - b) || [];
@@ -261,8 +288,6 @@ export const SmsTraiEdit = (props) => {
261
288
  };
262
289
 
263
290
  const onSubmitWrapper = () => {
264
- setIsLiquidValidationError(false);
265
- setLiquidErrorMessages({});
266
291
  const content = updatedSmsEditor.join('');
267
292
  const onError = ({ standardErrors, liquidErrors }) => {
268
293
  setLiquidErrorMessages({
@@ -273,8 +298,6 @@ export const SmsTraiEdit = (props) => {
273
298
  };
274
299
 
275
300
  const onSuccess = () => {
276
- setIsLiquidValidationError(false);
277
- setLiquidErrorMessages({});
278
301
  onDoneCallback();
279
302
  };
280
303
  validateLiquidTemplateContent(content, {
@@ -283,6 +306,10 @@ export const SmsTraiEdit = (props) => {
283
306
  messages: formBuilderMessages,
284
307
  onError,
285
308
  onSuccess,
309
+ tagLookupMap: metaEntities?.tagLookupMap,
310
+ eventContextTags,
311
+ isLiquidFlow: true,
312
+ forwardedTags: {},
286
313
  });
287
314
  };
288
315
 
@@ -521,6 +548,17 @@ export const SmsTraiEdit = (props) => {
521
548
  return countVarChar;
522
549
  };
523
550
 
551
+ const tagValidationErrorMessage = () => {
552
+ const { unsupportedTags = [] } = tagValidationResponse;
553
+ let tagError = '';
554
+ if (unsupportedTags.length > 0) {
555
+ tagError = formatMessage(messages.unsupportedTagsValidationError, {
556
+ unsupportedTags,
557
+ });
558
+ }
559
+ return <CapError>{tagError}</CapError>;
560
+ };
561
+
524
562
  const disablehandler = () => {
525
563
  if (traiData && !isEmpty(traiData)) {
526
564
  const msg = get(traiData, `versions.base.sms-editor`, '');
@@ -566,6 +604,7 @@ export const SmsTraiEdit = (props) => {
566
604
  setShowTestAndPreviewSlidebox(false);
567
605
  };
568
606
 
607
+ const isLiquidSupportFeatureEnabled = hasLiquidSupportFeature();
569
608
  return (
570
609
  <>
571
610
  <CapSpin spinning={loading || fetchingLiquidTags} tip={fetchingLiquidTags && formatMessage(formBuilderMessages.liquidSpinText)}>
@@ -623,6 +662,7 @@ export const SmsTraiEdit = (props) => {
623
662
  <CapRow>
624
663
  {smsLengthForVar()}
625
664
  </CapRow>
665
+ {isTagValidationError && tagValidationErrorMessage()}
626
666
  <CapCheckbox onChange={unicodeHandler} checked={isUnicodeAllowed} disabled={disablehandler()}>
627
667
  {formatMessage(messages.unicodeLabel)}
628
668
  </CapCheckbox>
@@ -653,8 +693,9 @@ export const SmsTraiEdit = (props) => {
653
693
  <FormattedMessage {...messages.testAndPreviewButtonLabel} />
654
694
  </CapButton>
655
695
  <CapButton
656
- onClick={onSubmitWrapper}
696
+ onClick={isLiquidSupportFeatureEnabled ? onSubmitWrapper : onDoneCallback}
657
697
  className="create-msg"
698
+ disabled={isTagValidationError || (isLiquidSupportFeatureEnabled && !isObject(metaEntities?.tagLookupMap))}
658
699
  >
659
700
  <FormattedMessage {...messages.saveButtonLabel} />
660
701
  </CapButton>