@capillarytech/creatives-library 8.0.113 → 8.0.114-alpha.1

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 (108) hide show
  1. package/containers/App/test/saga.test.js +1 -1
  2. package/containers/Assets/Gallery/tests/__snapshots__/reducer.test.js.snap +1 -1
  3. package/containers/Assets/Gallery/tests/actions.test.js +2 -3
  4. package/containers/Assets/Gallery/tests/reducer.test.js +7 -7
  5. package/containers/Assets/Gallery/tests/saga.test.js +9 -9
  6. package/containers/Dashboard/test/saga.test.js +1 -1
  7. package/containers/Ebill/test/saga.test.js +1 -1
  8. package/containers/Email/test/saga.test.js +33 -33
  9. package/containers/LanguageProvider/tests/actions.test.js +1 -1
  10. package/containers/LanguageProvider/tests/reducer.test.js +2 -2
  11. package/containers/LanguageProvider/tests/selectors.test.js +1 -1
  12. package/containers/Line/Create/tests/saga.test.js +2 -9
  13. package/containers/Line/Edit/test/saga.test.js +10 -14
  14. package/containers/MobilePush/Create/test/saga.test.js +2 -2
  15. package/containers/MobilePush/Edit/tests/saga.test.js +14 -14
  16. package/containers/Sms/Create/test/saga.test.js +4 -5
  17. package/containers/Sms/Edit/test/saga.test.js +1 -1
  18. package/containers/Templates/test/saga.test.js +14 -17
  19. package/containers/WeChat/MapTemplates/test/saga.test.js +9 -13
  20. package/containers/WeChat/RichmediaTemplates/Create/test/saga.test.js +1 -1
  21. package/containers/WeChat/RichmediaTemplates/Edit/test/saga.test.js +1 -1
  22. package/package.json +1 -1
  23. package/tests/integration/TemplateCreation/TemplateCreation.integration.test.js +8 -9
  24. package/utils/commonUtils.js +359 -3
  25. package/utils/tagValidations.js +20 -5
  26. package/utils/tests/authWrapper.test.js +2 -2
  27. package/utils/tests/cdnTransformation.test.js +16 -15
  28. package/utils/tests/commonUtil.test.js +474 -171
  29. package/utils/tests/tagValidations.test.js +89 -2
  30. package/v2Components/CapVideoUpload/tests/index.test.js +1 -1
  31. package/v2Components/CapWhatsappCTA/tests/index.test.js +1 -2
  32. package/v2Components/ErrorInfoNote/ErrorTypeRenderer.js +127 -0
  33. package/v2Components/ErrorInfoNote/ErrorTypeRenderer.test.js +147 -0
  34. package/v2Components/ErrorInfoNote/index.js +114 -46
  35. package/v2Components/ErrorInfoNote/messages.js +25 -0
  36. package/v2Components/ErrorInfoNote/style.scss +14 -1
  37. package/v2Components/ErrorInfoNote/utils.js +38 -0
  38. package/v2Components/ErrorInfoNote/utils.test.js +156 -0
  39. package/v2Components/FormBuilder/index.js +204 -127
  40. package/v2Components/FormBuilder/messages.js +1 -1
  41. package/v2Components/MarketingObjective/test/index.test.js +1 -1
  42. package/v2Components/NavigationBar/tests/saga.test.js +2 -3
  43. package/v2Containers/Assets/Gallery/tests/__snapshots__/reducer.test.js.snap +1 -1
  44. package/v2Containers/Assets/Gallery/tests/actions.test.js +2 -3
  45. package/v2Containers/Assets/Gallery/tests/reducer.test.js +7 -7
  46. package/v2Containers/Assets/Gallery/tests/saga.test.js +2 -2
  47. package/v2Containers/BeeEditor/test/saga.test.js +1 -1
  48. package/v2Containers/CallTask/test/saga.test.js +1 -1
  49. package/v2Containers/Cap/reducer.js +4 -4
  50. package/v2Containers/Cap/tests/actions.test.js +1 -1
  51. package/v2Containers/Cap/tests/reducer.test.js +11 -11
  52. package/v2Containers/Cap/tests/saga.test.js +1 -1
  53. package/v2Containers/Cap/tests/selectors.test.js +3 -3
  54. package/v2Containers/CapFacebookPreview/tests/saga.test.js +1 -1
  55. package/v2Containers/CreativesContainer/SlideBoxContent.js +23 -3
  56. package/v2Containers/CreativesContainer/SlideBoxFooter.js +3 -1
  57. package/v2Containers/CreativesContainer/constants.js +4 -1
  58. package/v2Containers/CreativesContainer/index.js +44 -19
  59. package/v2Containers/CreativesContainer/messages.js +4 -0
  60. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +21 -3
  61. package/v2Containers/Ebill/index.js +3 -3
  62. package/v2Containers/Ebill/test/saga.test.js +1 -1
  63. package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +4 -4
  64. package/v2Containers/Email/tests/actions.test.js +1 -1
  65. package/v2Containers/Email/tests/reducer.test.js +2 -2
  66. package/v2Containers/EmailWrapper/components/EmailWrapperView.js +1 -1
  67. package/v2Containers/FTP/test/saga.test.js +1 -1
  68. package/v2Containers/Facebook/test/saga.test.js +7 -7
  69. package/v2Containers/InApp/index.js +123 -50
  70. package/v2Containers/InApp/tests/action.test.js +7 -7
  71. package/v2Containers/InApp/tests/index.test.js +2 -4
  72. package/v2Containers/InApp/tests/reducer.test.js +175 -89
  73. package/v2Containers/InApp/tests/sagas.test.js +1 -1
  74. package/v2Containers/InApp/tests/utils.test.js +41 -0
  75. package/v2Containers/InApp/utils.js +37 -0
  76. package/v2Containers/LanguageProvider/tests/actions.test.js +1 -1
  77. package/v2Containers/LanguageProvider/tests/reducer.test.js +3 -3
  78. package/v2Containers/LanguageProvider/tests/saga.test.js +2 -2
  79. package/v2Containers/LanguageProvider/tests/selectors.test.js +1 -1
  80. package/v2Containers/Line/Container/ImageCarousel/tests/utils.test.js +3 -3
  81. package/v2Containers/Line/Container/Sticker/tests/utils.test.js +6 -6
  82. package/v2Containers/MobilePush/Create/index.js +24 -20
  83. package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
  84. package/v2Containers/MobilePush/Edit/index.js +6 -2
  85. package/v2Containers/MobilePush/Edit/test/saga.test.js +14 -14
  86. package/v2Containers/MobilepushWrapper/index.js +2 -0
  87. package/v2Containers/Rcs/tests/saga.test.js +1 -1
  88. package/v2Containers/Sms/Create/index.js +1 -0
  89. package/v2Containers/Sms/Create/test/saga.test.js +1 -1
  90. package/v2Containers/Sms/Edit/index.js +2 -0
  91. package/v2Containers/Sms/Edit/test/saga.test.js +5 -5
  92. package/v2Containers/SmsTrai/Create/tests/saga.test.js +1 -1
  93. package/v2Containers/SmsTrai/Create/tests/selectors.test.js +1 -1
  94. package/v2Containers/SmsWrapper/index.js +2 -0
  95. package/v2Containers/TagList/tests/TagList.test.js +1 -3
  96. package/v2Containers/TagList/tests/utils.test.js +3 -3
  97. package/v2Containers/Templates/tests/actions.test.js +1 -1
  98. package/v2Containers/Templates/tests/reducer.test.js +8 -8
  99. package/v2Containers/Templates/tests/sagas.test.js +2 -4
  100. package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -13
  101. package/v2Containers/WeChat/RichmediaTemplates/Create/test/saga.test.js +1 -1
  102. package/v2Containers/WeChat/RichmediaTemplates/Edit/test/saga.test.js +1 -1
  103. package/v2Containers/Whatsapp/tests/__snapshots__/utils.test.js.snap +9 -9
  104. package/v2Containers/Whatsapp/tests/actions.test.js +3 -3
  105. package/v2Containers/Whatsapp/tests/reducer.test.js +32 -36
  106. package/v2Containers/Whatsapp/tests/utils.test.js +19 -19
  107. package/v2Containers/Zalo/tests/actions.test.js +3 -3
  108. package/v2Containers/Zalo/tests/reducer.test.js +72 -42
@@ -49,10 +49,10 @@ import * as actions from "../../v2Containers/Cap/actions";
49
49
  import './_formBuilder.scss';
50
50
  import {updateCharCount, checkUnicode} from "../../utils/smsCharCountV2";
51
51
  import { checkSupport, extractNames, preprocessHtml, validateIfTagClosed } from '../../utils/tagValidations';
52
- import { SMS, MOBILE_PUSH, LINE, ENABLE_AI_SUGGESTIONS,AI_CONTENT_BOT_DISABLED, EMAIL, LIQUID_SUPPORTED_CHANNELS } from '../../v2Containers/CreativesContainer/constants';
52
+ import { SMS, MOBILE_PUSH, LINE, ENABLE_AI_SUGGESTIONS,AI_CONTENT_BOT_DISABLED, EMAIL, LIQUID_SUPPORTED_CHANNELS, INAPP } from '../../v2Containers/CreativesContainer/constants';
53
53
  import globalMessages from '../../v2Containers/Cap/messages';
54
54
  import { convert } from 'html-to-text';
55
- import { GLOBAL_CONVERT_OPTIONS, OUTBOUND } from './constants';
55
+ import { OUTBOUND } from './constants';
56
56
  import { GET_TRANSLATION_MAPPED } from '../../containers/TagList/constants';
57
57
  import moment from 'moment';
58
58
  import { CUSTOMER_BARCODE_TAG , COPY_OF, ENTRY_TRIGGER_TAG_REGEX} from '../../containers/App/constants';
@@ -60,7 +60,7 @@ import { REQUEST } from '../../v2Containers/Cap/constants'
60
60
  import { hasLiquidSupportFeature, isEmailUnsubscribeTagMandatory } from '../../utils/common';
61
61
  import { isUrl } from '../../v2Containers/Line/Container/Wrapper/utils';
62
62
  import { bindActionCreators } from 'redux';
63
-
63
+ import { getChannelData, validateLiquidTemplateContent, validateMobilePushContent } from '../../utils/commonUtils';
64
64
  const TabPane = Tabs.TabPane;
65
65
  const {Column} = Table;
66
66
  const {TextArea} = CapInput;
@@ -135,7 +135,12 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
135
135
  this.handleSetRadioValue = this.handleSetRadioValue.bind(this);
136
136
  this.formElements = [];
137
137
  // Check if the liquid flow feature is supported and the channel is in the supported list.
138
- this.liquidFlow = Boolean(LIQUID_SUPPORTED_CHANNELS.includes(props?.schema?.channel?.toUpperCase()) && hasLiquidSupportFeature());
138
+ this.liquidFlow = this.isLiquidFlowSupported.bind(this);
139
+ this.onSubmitWrapper = this.onSubmitWrapper.bind(this);
140
+
141
+ }
142
+ isLiquidFlowSupported = () => {
143
+ return Boolean(LIQUID_SUPPORTED_CHANNELS.includes(this.props?.schema?.channel?.toUpperCase()) && hasLiquidSupportFeature());
139
144
  }
140
145
 
141
146
  componentWillMount() {
@@ -538,6 +543,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
538
543
  } else {
539
544
  errorData['template-name'] = false;
540
545
  }
546
+ isLiquidValid = isValid;
541
547
  }
542
548
 
543
549
  //validation for LINE
@@ -653,20 +659,21 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
653
659
  let isOnlyAndroid = false, isOnlyIos = false;
654
660
  const { TAG_BRACKET_COUNT_MISMATCH_ERROR } = errorMessageForTags;
655
661
  const androidData = {};
656
- for(let data in this.state.formData[0]){
657
- if(!!this.state.formData[0][data] && data !== "tabKey" && data !== "base"){
658
- androidData[data] = this.state.formData[0][data];
662
+ if (this.state.formData && this.state.formData[0]) {
663
+ for(let data in this.state.formData[0]){
664
+ if(!!this.state.formData[0][data] && data !== "tabKey" && data !== "base"){
665
+ androidData[data] = this.state.formData[0][data];
666
+ }
659
667
  }
660
- }
661
668
  if(_.isEmpty(androidData)){
662
669
  isOnlyIos = true;
663
670
  }
664
671
  const iosData = {};
665
- for(let data in this.state.formData[1]){
666
- if(!!this.state.formData[1][data] && data !== "tabKey" && data !== "base"){
667
- iosData[data] = this.state.formData[1][data];
672
+ for(let data in this.state.formData[1]){
673
+ if(!!this.state.formData[1][data] && data !== "tabKey" && data !== "base"){
674
+ iosData[data] = this.state.formData[1][data];
675
+ }
668
676
  }
669
- }
670
677
  if(_.isEmpty(iosData)){
671
678
  isOnlyAndroid = true;
672
679
  }
@@ -701,17 +708,19 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
701
708
  errorData[parseInt(index)]['invalid-tags'] = tagValidationResponse.unsupportedTags;
702
709
  errorData[parseInt(index)][`bracket-error`] = isBraceError && TAG_BRACKET_COUNT_MISMATCH_ERROR;
703
710
  isValid = false;
711
+ isCurrentTabValid = false;
704
712
  }
705
713
  }
706
714
 
707
715
  } else {
708
- errorData[parseInt(index)][`message-editor${selector}`] = true;
709
- isValid = false;
710
- isCurrentTabValid = false;
716
+
717
+ errorData[parseInt(index)][`message-editor${selector}`] = true;
718
+ isValid = false;
719
+ isCurrentTabValid = false;
711
720
  }
712
721
 
713
-
714
722
 
723
+
715
724
  let title = tab[`message-title${selector}`]
716
725
  if(title){
717
726
  title = title.trim();
@@ -730,6 +739,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
730
739
  errorData[parseInt(index)][`message-title${selector}`] = isBraceError ? TAG_BRACKET_COUNT_MISMATCH_ERROR : true;
731
740
  errorData[parseInt(index)][`bracket-error`] = isBraceError && TAG_BRACKET_COUNT_MISMATCH_ERROR;
732
741
  isValid = false;
742
+ isCurrentTabValid = false;
733
743
  }
734
744
  }
735
745
  } else {
@@ -858,9 +868,9 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
858
868
  isCurrentTabValid = false;
859
869
  }else {
860
870
  errorData[parseInt(index)][key] = false;
861
- }
862
- }
863
- });
871
+ }
872
+ }
873
+ });
864
874
  }
865
875
  }
866
876
  if(index == 0){
@@ -873,7 +883,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
873
883
  errorData['template-name'] = true;
874
884
  isValid = false;
875
885
  androidValid = false;
876
- iosValid = false
886
+ iosValid = false;
877
887
  } else {
878
888
  errorData['template-name'] = false;
879
889
  }
@@ -893,7 +903,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
893
903
  // modal.body = "Android template is not configured. Save without Android template";
894
904
  // modal.id = "ios";
895
905
  // modal.type = 'confirm';
896
- return;
906
+ return; //returning from here will not call the liquid middleware
897
907
  }
898
908
  const iosData = {};
899
909
  for(let data in this.state.formData[1]){
@@ -909,7 +919,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
909
919
  // modal.id = 'android';
910
920
  // modal.type = 'confirm';
911
921
  // this.setState({modal, showModal: true, androidValid, iosValid});
912
- return;
922
+ return; //returning from here will not call the liquid middleware
913
923
  }
914
924
  }
915
925
  if (!androidValid || !iosValid) {
@@ -922,7 +932,9 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
922
932
  } else if (!isOnlyIos && !isOnlyAndroid && androidValid && iosValid) {
923
933
  isValid = isValid && true;
924
934
  }
935
+ isLiquidValid = isValid;
925
936
  }
937
+ }
926
938
 
927
939
  // Form Data Validation for Email Channel
928
940
  if (this.props?.schema?.channel?.toUpperCase() === EMAIL) {
@@ -983,7 +995,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
983
995
  errorData[index][currentLang]['template-content'] = true;
984
996
  isValid = false;
985
997
  isLiquidValid = false;
986
- if ((showMessages && !isNaN(index)) || this.liquidFlow) {
998
+ if ((showMessages && !isNaN(index)) || this.liquidFlow()) {
987
999
  if (tagValidationResponse?.missingTags?.length > 0 || tagValidationResponse?.unsupportedTags?.length > 0) {
988
1000
  errorString += `${this.props.intl.formatMessage(messages.contentNotValidLanguage)} ${currentLang}\n`;
989
1001
  }
@@ -999,7 +1011,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
999
1011
  if (tagValidationResponse?.isContentEmpty) {
1000
1012
  errorString += this.props.intl.formatMessage(messages.emailBodyEmptyError);
1001
1013
  // Adds a bypass for cases where content is initially empty in the creation flow.
1002
- if(this.liquidFlow){
1014
+ if(this.liquidFlow()){
1003
1015
  errorString = "";
1004
1016
  isLiquidValid = true;
1005
1017
  }
@@ -1007,8 +1019,8 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
1007
1019
  }
1008
1020
  }
1009
1021
  }
1010
- if (errorString !== "") {
1011
- if (this.liquidFlow) {
1022
+ if (errorString) {
1023
+ if (this.liquidFlow()) {
1012
1024
  this.setState(
1013
1025
  (prevState) => ({
1014
1026
  liquidErrorMessage: {
@@ -1018,7 +1030,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
1018
1030
  }),
1019
1031
  () => {
1020
1032
  // Callback after the state is updated
1021
- this.props.showLiquidErrorInFooter(this.state.liquidErrorMessage);
1033
+ this.props.showLiquidErrorInFooter(this.state.liquidErrorMessage, this.props.channel === SMS? null: this.state.currentTab);
1022
1034
  }
1023
1035
  );
1024
1036
  } else {
@@ -1034,7 +1046,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
1034
1046
  });
1035
1047
  }
1036
1048
 
1037
- const isTemplateValid = this.liquidFlow ? isLiquidValid : isValid;
1049
+ const isTemplateValid = this.liquidFlow() ? isLiquidValid : isValid;
1038
1050
  //Updating the state with the error data
1039
1051
  this.setState((prevState) => ({
1040
1052
  isFormValid: isTemplateValid,
@@ -1046,126 +1058,175 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
1046
1058
  },
1047
1059
  errorData,
1048
1060
  }), () => {
1049
- this.props.showLiquidErrorInFooter(this.state.liquidErrorMessage);
1061
+ this.props.showLiquidErrorInFooter(this.state.liquidErrorMessage, this.props.channel === SMS? null: this.state.currentTab);
1062
+
1050
1063
  if (onValidationComplete) {
1064
+
1051
1065
  onValidationComplete();
1052
1066
  }
1053
1067
  });
1054
1068
 
1069
+
1055
1070
  this.props.onFormValidityChange(isTemplateValid, errorData);
1056
1071
  return isTemplateValid;
1057
- }
1072
+ }
1058
1073
 
1059
1074
  indexOfEnd(targetString, string) {
1060
1075
  var io = targetString.indexOf(string);
1061
1076
  return io == -1 ? -1 : io + string.length;
1062
1077
  }
1063
- continueSaveForm = (id) => {
1064
1078
 
1065
- };
1066
- handleLiquidTemplateSubmit =(templateContent) => {
1067
- if(templateContent){this.setState((prevState) => {
1068
- return {
1069
- formData: {
1070
- ...prevState?.formData,
1071
- base: {
1072
- ...prevState?.formData?.base,
1073
- en: {
1074
- ...prevState?.formData?.base?.en,
1075
- "template-content": preprocessHtml(templateContent)
1079
+ handleLiquidTemplateSubmit = (templateContent) => {
1080
+ const channel = this.props.channel || this.props?.schema?.channel?.toUpperCase();
1081
+
1082
+ if (templateContent && channel === EMAIL) {
1083
+ this.setState((prevState) => {
1084
+ return {
1085
+ formData: {
1086
+ ...prevState?.formData,
1087
+ base: {
1088
+ ...prevState?.formData?.base,
1089
+ [this.props.baseLanguage]: {
1090
+ ...prevState?.formData?.base?.[this.props.baseLanguage],
1091
+ "template-content": preprocessHtml(templateContent)
1092
+ }
1076
1093
  }
1077
1094
  }
1095
+ };
1096
+ }, () => {
1097
+ if (this.props.onSubmit) {
1098
+ this.props.onSubmit(this.state.formData);
1078
1099
  }
1079
- };
1080
- }, () => {
1081
- if (this.props.onSubmit) {
1082
- this.props.onSubmit(this.state.formData);
1100
+ });
1101
+ } else {
1102
+ // For all other channels
1103
+ this.props.onSubmit(this.state.formData);
1104
+ }
1105
+ }
1106
+ onSubmitWrapper = (props) => {
1107
+ const {singleTab = null} = props || {};
1108
+ if (this.liquidFlow()) {
1109
+ // For MPUSH, we need to validate both Android and iOS content separately
1110
+ if (this.props.channel === MOBILE_PUSH || this.props?.schema?.channel?.toUpperCase() === MOBILE_PUSH) {
1111
+ this.validateFormBuilderMPush(this.state.formData, singleTab);
1112
+ return;
1083
1113
  }
1084
- });}
1114
+
1115
+ // For other channels (EMAIL, SMS, INAPP)
1116
+ const content = getChannelData(this.props.schema.channel || this.props.channel, this.state.formData,this.props.baseLanguage);
1117
+
1118
+ // Set up callbacks for error and success handling
1119
+ const onError = ({ standardErrors, liquidErrors }) => {
1120
+ this.setState(
1121
+ (prevState) => ({
1122
+ liquidErrorMessage: {
1123
+ ...prevState.liquidErrorMessage,
1124
+ STANDARD_ERROR_MSG: standardErrors,
1125
+ LIQUID_ERROR_MSG: liquidErrors,
1126
+ },
1127
+ }),
1128
+ () => {
1129
+ this.props.showLiquidErrorInFooter(this.state.liquidErrorMessage);
1130
+ this.props.stopValidation();
1131
+ }
1132
+ );
1133
+ };
1134
+
1135
+ const onSuccess = (contentToSubmit) => {
1136
+ this.handleLiquidTemplateSubmit(contentToSubmit);
1137
+ };
1138
+
1139
+ // Call the common validation function
1140
+ validateLiquidTemplateContent(content, this.props.schema.channel || this.props.channel, {
1141
+ getLiquidTags: this.props.actions.getLiquidTags,
1142
+ formatMessage: this.props.intl.formatMessage,
1143
+ messages,
1144
+ onError,
1145
+ onSuccess,
1146
+ tagLookupMap: this.props?.metaEntities?.tagLookupMap,
1147
+ eventContextTags: this.props?.eventContextTags,
1148
+ isLiquidFlow: this.liquidFlow(),
1149
+ forwardedTags: this.props?.isLoyaltyModule ? this.props?.forwardedTags : {},
1150
+ skipTags: this.skipTags.bind(this)
1151
+ });
1152
+ } else {
1153
+ this.props.onSubmit(this.state.formData);
1154
+ }
1085
1155
  }
1086
-
1156
+
1087
1157
  saveForm(saveForm) {
1088
1158
  if (this.props.isNewVersionFlow && !saveForm) {
1089
1159
  this.props.getValidationData();
1090
1160
  return;
1091
1161
  }
1092
1162
  if ( this.state.isFormValid ) {
1093
- if (this.liquidFlow) {
1094
- const templateContent = this.state.formData?.base?.en?.["template-content"] || "";
1095
- //Converts given HTML content to plain text string.
1096
- const content = convert(
1097
- templateContent, GLOBAL_CONVERT_OPTIONS
1098
- );
1099
- /*
1100
- The `handleResult` function is used as a callback for `getLiquidTags` to handle the results post-processing.
1101
- It checks for errors and unsupported tags in the fetched liquid tags, displays any necessary validation messages,
1102
- and proceeds with form submission if all checks pass.
1103
- */
1104
- const handleResult = (result) => {
1105
- const {formatMessage} = this.props.intl;
1106
- // Checks for errors in the result and displays them if any are found.
1107
- const validString = /\S/.test(content);
1108
- // If the content is empty or there are errors in the result, display the necessary validation messages.
1109
- if (result?.errors?.length > 0 || !validString) {
1110
- this.setState((prevState) => ({
1111
- liquidErrorMessage: {
1112
- ...prevState.liquidErrorMessage,
1113
- STANDARD_ERROR_MSG: !validString ? [...(prevState.liquidErrorMessage?.STANDARD_ERROR_MSG || []), formatMessage(messages.emailBodyEmptyError)] : prevState.liquidErrorMessage?.STANDARD_ERROR_MSG,
1114
- LIQUID_ERROR_MSG: result?.errors?.map(error => error?.message) ?? [formatMessage(messages.somethingWentWrong)],
1115
- }
1116
- }), () => {
1117
- this.props.showLiquidErrorInFooter(this.state.liquidErrorMessage);
1118
- });
1119
- this.props.stopValidation();
1120
- return;
1121
- }
1122
- // Extracts the supported liquid tags from the given content and do the necessary checks.
1123
- else {
1124
- const extractedLiquidTags = extractNames(result?.data || []);
1125
- // Extracts the supported liquid tags from the given content.
1126
- const supportedLiquidTags = checkSupport(
1127
- result,
1128
- this.props?.metaEntities?.tagLookupMap,
1129
- this.props?.eventContextTags,
1130
- this.liquidFlow,
1131
- this.props?.isLoyaltyModule ? this.props?.forwardedTags : {}
1132
- );
1133
- const unsupportedLiquidTags = extractedLiquidTags?.filter(
1134
- (tag) => !supportedLiquidTags?.includes(tag) && !this.skipTags(tag)
1135
- );
1136
- if (
1137
- unsupportedLiquidTags?.length > 0
1138
- ) {
1139
- this.setState(
1140
- (prevState) => ({
1141
- liquidErrorMessage: {
1142
- ...prevState.liquidErrorMessage,
1143
- LIQUID_ERROR_MSG: [formatMessage(messages.unsupportedTagsValidationError, {
1144
- unsupportedTags: unsupportedLiquidTags.join(", ")})],
1145
- },
1146
- }),
1147
- () => {
1148
- this.props.showLiquidErrorInFooter(
1149
- this.state.liquidErrorMessage
1150
- );
1151
- }
1152
- );
1153
- this.props.stopValidation();
1154
- return;
1155
- }
1156
- this.handleLiquidTemplateSubmit(templateContent);
1157
- }
1158
- };
1159
- this.props.actions.getLiquidTags(preprocessHtml(content), handleResult);
1160
- } else {
1161
- this.props.onSubmit(this.state.formData);
1162
- }
1163
+ this.onSubmitWrapper();
1164
+
1163
1165
  } else {
1164
1166
  this.setState({checkValidation: true});
1165
1167
  this.validateForm(null, null, true);
1166
1168
  }
1167
1169
  }
1168
1170
 
1171
+
1172
+ // New function to handle MPUSH content validation for both Android and iOS
1173
+ validateFormBuilderMPush = (formData,singleTab) => {
1174
+ const currentTab = this.state.currentTab;
1175
+
1176
+ // Set up callbacks for error and success handling
1177
+ const onLiquidError = ({ standardErrors, liquidErrors }) => {
1178
+ console.log("onLiquidError.....", standardErrors, liquidErrors);
1179
+ this.setState(
1180
+ (prevState) => ({
1181
+ liquidErrorMessage: {
1182
+ ...prevState.liquidErrorMessage,
1183
+ STANDARD_ERROR_MSG: standardErrors,
1184
+ LIQUID_ERROR_MSG: liquidErrors,
1185
+ },
1186
+ }),
1187
+ () => {
1188
+ this.props.showLiquidErrorInFooter(this.state.liquidErrorMessage, this.state.currentTab);
1189
+ this.props.stopValidation();
1190
+ }
1191
+ );
1192
+ };
1193
+
1194
+ const onSuccess = (contentToSubmit) => {
1195
+ // Clear any previous errors
1196
+ this.setState(
1197
+ (prevState) => ({
1198
+ liquidErrorMessage: {
1199
+ ...prevState.liquidErrorMessage,
1200
+ STANDARD_ERROR_MSG: [],
1201
+ LIQUID_ERROR_MSG: [],
1202
+ },
1203
+ }),
1204
+ () => {
1205
+ // Format depends on the tabType
1206
+ this.handleLiquidTemplateSubmit(contentToSubmit);
1207
+ }
1208
+ );
1209
+ };
1210
+
1211
+ // Call the utility function with our callbacks
1212
+ validateMobilePushContent(formData, {
1213
+ currentTab,
1214
+ onError: onLiquidError,
1215
+ onSuccess,
1216
+ getLiquidTags: this.props.actions.getLiquidTags,
1217
+ formatMessage: this.props.intl.formatMessage,
1218
+ messages: messages,
1219
+ tagLookupMap: this.props?.metaEntities?.tagLookupMap,
1220
+ eventContextTags: this.props?.eventContextTags,
1221
+ isLiquidFlow: this.liquidFlow(), // Use the method instead of props
1222
+ forwardedTags: this.props?.isLoyaltyModule ? this.props?.forwardedTags : {},
1223
+ skipTags: this.skipTags.bind(this),
1224
+ extractNames,
1225
+ checkSupport,
1226
+ singleTab: singleTab?.toUpperCase(),
1227
+ });
1228
+ }
1229
+
1169
1230
  transformInjectedTags(tags) {
1170
1231
  _.forEach(tags, (tag) => {
1171
1232
  const temp = tag;
@@ -1304,7 +1365,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
1304
1365
  });
1305
1366
 
1306
1367
  ifSupported = ifSupported || this.checkIfSupportedTag(tagValue, injectedTags);
1307
- if (!ifSupported && !this.liquidFlow) {
1368
+ if (!ifSupported && !this.liquidFlow()) {
1308
1369
  response.unsupportedTags.push(tagValue);
1309
1370
  response.valid = false;
1310
1371
  }
@@ -2278,12 +2339,11 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2278
2339
  };
2279
2340
  handleOk = (ev) => {
2280
2341
  const id = ev.target.id;
2281
-
2282
2342
  this.setState({showModal: false});
2283
2343
  if (id === "android" && this.state.androidValid) {
2284
- this.props.onSubmit(this.state.formData);
2344
+ this.onSubmitWrapper({singleTab: id});
2285
2345
  } else if (id === "ios" && this.state.iosValid) {
2286
- this.props.onSubmit(this.state.formData);
2346
+ this.onSubmitWrapper({singleTab: id});
2287
2347
  } else if (id === "sms-version-modal") {
2288
2348
  this.state.currentEvent.call(this.props.parent, this.state.currentEventData, this.state.currentTab);
2289
2349
  this.setState({currentEvent: {}, currentEventData: {}});
@@ -2483,6 +2543,19 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2483
2543
  default:
2484
2544
  break;
2485
2545
  }
2546
+ const prevErrorMessage = this.state.liquidErrorMessage?.STANDARD_ERROR_MSG?.[0];
2547
+ if (prevErrorMessage !== errorMessageText && errorMessageText && this.liquidFlow()) {
2548
+ this.setState((prevState) => ({
2549
+ liquidErrorMessage: {
2550
+ ...prevState.liquidErrorMessage,
2551
+ STANDARD_ERROR_MSG: [errorMessageText],
2552
+ }
2553
+ }), () => {
2554
+
2555
+ this.props.showLiquidErrorInFooter(this.state.liquidErrorMessage, this.props.channel === SMS? null: this.state.currentTab);
2556
+ });
2557
+ }
2558
+ else{
2486
2559
  if (styling === 'semantic') {
2487
2560
  columns.push(
2488
2561
  <CapColumn key="input" span={val.width} offset={offset}>
@@ -2490,7 +2563,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2490
2563
  id={val.id}
2491
2564
  placeholder={val.placeholder ? val.placeholder : ''}
2492
2565
  className={`${ifError ? 'error-form-builder' : ''}`}
2493
- errorMessage={errorMessageText}
2566
+ errorMessage={errorMessageText && !this.liquidFlow() ? errorMessageText : ''}
2494
2567
  label={val.label}
2495
2568
  autosize={val.autosize ? val.autosizeParams : false}
2496
2569
  onChange={(e) => this.updateFormData(e.target.value, val)}
@@ -2520,8 +2593,10 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2520
2593
  </CapColumn>
2521
2594
  );
2522
2595
  }
2596
+ }
2523
2597
  };
2524
2598
 
2599
+
2525
2600
  renderColLabelSection(section, childIndex) {
2526
2601
  // const schema = this.props.schema
2527
2602
  const fields = [];
@@ -3465,7 +3540,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
3465
3540
  <CapColumn
3466
3541
  style={val.colStyle ? val.colStyle : {border : ""}}
3467
3542
  span={val.width}
3468
- className={`${(this.state.liquidErrorMessage?.LIQUID_ERROR_MSG?.length || this.state.liquidErrorMessage?.STANDARD_ERROR_MSG?.length) && this.liquidFlow && "error-boundary"} `}
3543
+ className={`${(this.state.liquidErrorMessage?.LIQUID_ERROR_MSG?.length || this.state.liquidErrorMessage?.STANDARD_ERROR_MSG?.length) && this.liquidFlow() && "error-boundary"} `}
3469
3544
  >
3470
3545
  <CKEditor
3471
3546
  id={val.id}
@@ -3509,7 +3584,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
3509
3584
  isModuleFilterEnabled = this.props.isFullMode;
3510
3585
  }
3511
3586
  columns.push(
3512
- <CapColumn style={val.colStyle ? val.colStyle : {}} span={val.width} className={`${(this.state.liquidErrorMessage?.LIQUID_ERROR_MSG?.length || this.state.liquidErrorMessage?.STANDARD_ERROR_MSG?.length) && this.liquidFlow && "error-boundary"}`}>
3587
+ <CapColumn style={val.colStyle ? val.colStyle : {}} span={val.width} className={`${(this.state.liquidErrorMessage?.LIQUID_ERROR_MSG?.length || this.state.liquidErrorMessage?.STANDARD_ERROR_MSG?.length) && this.liquidFlow() && "error-boundary"}`}>
3513
3588
  <BeeEditor
3514
3589
  uid={uuid}
3515
3590
  tokenData={beeToken}
@@ -3795,7 +3870,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
3795
3870
 
3796
3871
 
3797
3872
  return (
3798
- <CapSpin spinning={Boolean((this.liquidFlow && this.props.liquidExtractionInProgress) || this.props.metaDataStatus === REQUEST)} tip={this.props.intl.formatMessage(messages.liquidSpinText)} >
3873
+ <CapSpin spinning={Boolean((this.liquidFlow() && this.props.liquidExtractionInProgress) || this.props.metaDataStatus === REQUEST)} tip={this.props.intl.formatMessage(messages.liquidSpinText)} >
3799
3874
  <CapRow>
3800
3875
  {this.props.schema && this.renderForm()}
3801
3876
  <SlideBox
@@ -3877,7 +3952,8 @@ FormBuilder.propTypes = {
3877
3952
  isFullMode: PropTypes.bool,
3878
3953
  currentOrgDetails: PropTypes.object,
3879
3954
  liquidExtractionInProgress: PropTypes.bool,
3880
- showLiquidErrorInFooter: PropTypes.func
3955
+ showLiquidErrorInFooter: PropTypes.func,
3956
+ channel: PropTypes.string,
3881
3957
  };
3882
3958
 
3883
3959
  const mapStateToProps = createStructuredSelector({
@@ -3894,3 +3970,4 @@ function mapDispatchToProps(dispatch) {
3894
3970
  }
3895
3971
 
3896
3972
  export default connect(mapStateToProps,mapDispatchToProps)(injectIntl(FormBuilder));
3973
+
@@ -94,7 +94,7 @@ export default defineMessages({
94
94
  id: 'creatives.componentsV2.FormBuilder.somethingWentWrong',
95
95
  defaultMessage: 'Something went wrong while validating content, please try again later',
96
96
  },
97
- liquidSpinText:{
97
+ liquidSpinText: {
98
98
  id: 'creatives.componentsV2.FormBuilder.liquidSpinText',
99
99
  defaultMessage: 'Validating the template, it might take a few seconds',
100
100
  },
@@ -26,7 +26,7 @@ const initializeComponent = () => {
26
26
  describe('renders a MarketingObjective', () => {
27
27
  it("Test if MarketingObjective component renders", () => {
28
28
  initializeComponent();
29
- const button = screen.getByRole('button', {name: 'Done'});
29
+ const button = screen.getByText('Done');
30
30
  expect(button).toBeInTheDocument();
31
31
  fireEvent.click(button);
32
32
  });
@@ -5,11 +5,10 @@ import CapCollapsibleLeftNavigationSagas from '@capillarytech/cap-ui-library/Cap
5
5
  import { analyticsBotSaga } from "@capillarytech/cap-ui-library/CapAskAira";
6
6
 
7
7
  describe("analyticsBotSagaFn", () => {
8
- it("should call all analytics bot sagas", () => {
8
+ test.concurrent("should call all analytics bot sagas", () => {
9
9
  const { saga: analyticsBotSagaFn } = rootSagas.find(
10
10
  s => s.key === "analyticsBotSaga"
11
11
  );
12
-
13
12
  return expectSaga(analyticsBotSagaFn)
14
13
  .provide([
15
14
  [matchers.call.fn(analyticsBotSaga[0]), undefined],
@@ -20,7 +19,7 @@ describe("analyticsBotSagaFn", () => {
20
19
  });
21
20
 
22
21
  describe("navigationConfigSaga", () => {
23
- it("should call all analytics bot sagas", () => {
22
+ it.concurrent("should call all analytics bot sagas", () => {
24
23
  const { saga: navigationConfigSaga } = rootSagas.find(
25
24
  s => s.key === "navigation"
26
25
  );
@@ -1,6 +1,6 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`galleryReducer Initial State should match snapshot returns the initial state 1`] = `
3
+ exports[` 1`] = `
4
4
  Immutable.Map {
5
5
  "assetList": Immutable.List [],
6
6
  "assetUploading": false,
@@ -1,10 +1,9 @@
1
-
2
1
  import * as actions from '../actions';
3
2
  import * as types from '../constants';
4
3
 
5
4
  describe('Gallery actions', () => {
6
5
  describe('uploadAsset', () => {
7
- it('has a type of UPLOAD_ASSET_REQUEST', () => {
6
+ test.concurrent('has a type of UPLOAD_ASSET_REQUEST', () => {
8
7
  const expected = {
9
8
  type: types.UPLOAD_ASSET_REQUEST,
10
9
  file: 'test',
@@ -15,7 +14,7 @@ describe('Gallery actions', () => {
15
14
  });
16
15
 
17
16
  describe('getAllAssets', () => {
18
- it('has a type of GET_ALL_ASSETS_REQUEST', () => {
17
+ test.concurrent('has a type of GET_ALL_ASSETS_REQUEST', () => {
19
18
  const expected = {
20
19
  type: types.GET_ALL_ASSETS_REQUEST,
21
20
  assetType: 'IMAGE',