@capillarytech/creatives-library 8.0.288 → 8.0.290-alpha.0
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 +0 -1
- package/initialState.js +0 -2
- package/package.json +1 -1
- package/utils/common.js +5 -8
- package/utils/commonUtils.js +4 -85
- package/utils/tagValidations.js +84 -222
- package/utils/tests/commonUtil.test.js +461 -118
- package/utils/tests/tagValidations.test.js +280 -358
- package/v2Components/ErrorInfoNote/index.js +2 -5
- package/v2Components/FormBuilder/index.js +78 -161
- package/v2Components/FormBuilder/messages.js +0 -8
- package/v2Components/HtmlEditor/HTMLEditor.js +0 -5
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +0 -1
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +0 -15
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +1 -2
- package/v2Containers/Cap/mockData.js +0 -14
- package/v2Containers/Cap/reducer.js +3 -55
- package/v2Containers/Cap/tests/reducer.test.js +0 -102
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +3 -1
- package/v2Containers/CreativesContainer/index.js +19 -6
- package/v2Containers/Email/index.js +1 -5
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +10 -62
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +12 -115
- package/v2Containers/FTP/index.js +2 -51
- package/v2Containers/FTP/messages.js +0 -4
- package/v2Containers/InApp/index.js +1 -96
- package/v2Containers/InApp/tests/index.test.js +17 -6
- package/v2Containers/InappAdvance/index.js +2 -103
- package/v2Containers/Line/Container/Text/index.js +0 -1
- package/v2Containers/MobilePush/Create/index.js +6 -16
- package/v2Containers/MobilePush/Edit/index.js +6 -16
- package/v2Containers/MobilePushNew/index.js +2 -33
- package/v2Containers/Rcs/index.js +12 -37
- package/v2Containers/Sms/Create/index.js +31 -3
- package/v2Containers/Sms/Create/messages.js +4 -0
- package/v2Containers/Sms/Edit/index.js +29 -3
- package/v2Containers/Sms/commonMethods.js +6 -6
- package/v2Containers/SmsTrai/Edit/index.js +6 -47
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +6 -6
- package/v2Containers/Templates/reducer.js +3 -1
- package/v2Containers/Templates/tests/reducer.test.js +12 -0
- package/v2Containers/Viber/index.js +0 -1
- package/v2Containers/WebPush/Create/components/BrandIconSection.test.js +264 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/BrandIconSection.test.js.snap +187 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.js +1 -3
- package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +0 -7
- package/v2Containers/WebPush/Create/index.js +2 -2
- package/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +269 -0
- package/v2Containers/WebPush/Create/utils/validation.js +17 -2
- package/v2Containers/WebPush/Create/utils/validation.test.js +0 -24
- package/v2Containers/Whatsapp/index.js +9 -17
- package/v2Containers/Zalo/index.js +3 -11
|
@@ -50,9 +50,7 @@ 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";
|
|
54
53
|
import { validateInAppContent } from "../../utils/commonUtils";
|
|
55
|
-
import { hasLiquidSupportFeature } from "../../utils/common";
|
|
56
54
|
import formBuilderMessages from "../../v2Components/FormBuilder/messages";
|
|
57
55
|
import { getSingleTab, hasAnyErrors } from "../InApp/utils";
|
|
58
56
|
import ErrorInfoNote from "../../v2Components/ErrorInfoNote";
|
|
@@ -817,11 +815,9 @@ export const InappAdvanced = (props) => {
|
|
|
817
815
|
const latestHtmlValues = await saveAllBeeInstances();
|
|
818
816
|
const payload = createPayload(latestHtmlValues);
|
|
819
817
|
|
|
820
|
-
// Validate the INAPP content
|
|
821
|
-
const isLiquidFlow = hasLiquidSupportFeature();
|
|
822
818
|
// Skip validation if no tags are available (e.g., in tests or when tags haven't loaded)
|
|
823
819
|
const hasTags = tags && tags.length > 0;
|
|
824
|
-
if (
|
|
820
|
+
if (hasTags) {
|
|
825
821
|
validateInAppContent(payload, {
|
|
826
822
|
currentTab: panes === ANDROID ? 1 : 2, // Convert ANDROID/IOS to tab numbers
|
|
827
823
|
onError,
|
|
@@ -829,10 +825,6 @@ export const InappAdvanced = (props) => {
|
|
|
829
825
|
getLiquidTags: (content, callback) => globalActions.getLiquidTags(content, callback),
|
|
830
826
|
formatMessage,
|
|
831
827
|
messages: formBuilderMessages,
|
|
832
|
-
tagLookupMap: metaEntities?.tagLookupMap || {},
|
|
833
|
-
eventContextTags: metaEntities?.eventContextTags || [],
|
|
834
|
-
isLiquidFlow,
|
|
835
|
-
forwardedTags: {},
|
|
836
828
|
skipTags: (tag) => {
|
|
837
829
|
// Skip certain tags if needed
|
|
838
830
|
const skipRegexes = [
|
|
@@ -847,92 +839,7 @@ export const InappAdvanced = (props) => {
|
|
|
847
839
|
},
|
|
848
840
|
singleTab: getSingleTab(accountData),
|
|
849
841
|
});
|
|
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
|
-
}
|
|
934
842
|
} else {
|
|
935
|
-
// No tags available, skip validation and proceed directly
|
|
936
843
|
onSuccess();
|
|
937
844
|
}
|
|
938
845
|
};
|
|
@@ -1038,15 +945,7 @@ export const InappAdvanced = (props) => {
|
|
|
1038
945
|
)}
|
|
1039
946
|
<CapButton
|
|
1040
947
|
onClick={async () => {
|
|
1041
|
-
|
|
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
|
-
}
|
|
948
|
+
await liquidMiddleWare();
|
|
1050
949
|
}}
|
|
1051
950
|
disabled={isDisableDone()}
|
|
1052
951
|
className="inapp-create-btn"
|
|
@@ -678,31 +678,21 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
678
678
|
}
|
|
679
679
|
showError = () => {
|
|
680
680
|
const {intl} = this.props;
|
|
681
|
-
const {errorData} = this.state;
|
|
681
|
+
const {errorData, schema} = this.state;
|
|
682
682
|
const errorMessage = {key: 'validation-error', message: intl.formatMessage(messages.validationError)};
|
|
683
683
|
if (!isEmpty(this.state.formData) && !this.state.isFormValid) {
|
|
684
684
|
let tab = this.state.currentTab;
|
|
685
|
-
const isAndroidInvalid = Object.values(errorData[0]).includes(true);
|
|
686
|
-
const isIosInvalid = Object.values(errorData[1]).includes(true);
|
|
687
|
-
|
|
685
|
+
const isAndroidInvalid = Object.values(errorData[0] || {}).includes(true);
|
|
686
|
+
const isIosInvalid = Object.values(errorData[1] || {}).includes(true);
|
|
687
|
+
const isIosTabVisible = get(schema, 'containers[0].panes[1].isSupported', true) !== false;
|
|
688
688
|
if (isAndroidInvalid) {
|
|
689
689
|
tab = 1;
|
|
690
690
|
errorMessage.description = intl.formatMessage(messages.invalidAndroidMessage);
|
|
691
|
-
|
|
692
|
-
if (!isEmpty(invalidTags)) {
|
|
693
|
-
isTagErrorExist = true;
|
|
694
|
-
errorMessage.description = `${intl.formatMessage(messages.invalidAndroidMessage)} ${intl.formatMessage(messages.invalidTags)}: ${invalidTags.join(',')} `;
|
|
695
|
-
}
|
|
696
|
-
} else if (isIosInvalid) {
|
|
691
|
+
} else if (isIosInvalid && isIosTabVisible) {
|
|
697
692
|
tab = 2;
|
|
698
693
|
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
|
-
}
|
|
704
694
|
}
|
|
705
|
-
if (tab !== this.state.currentTab
|
|
695
|
+
if (tab !== this.state.currentTab) {
|
|
706
696
|
CapNotification.error(errorMessage);
|
|
707
697
|
}
|
|
708
698
|
}
|
|
@@ -705,32 +705,22 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
705
705
|
// eslint-disable-next-line react/sort-comp
|
|
706
706
|
showError = () => {
|
|
707
707
|
const {intl} = this.props;
|
|
708
|
-
const {errorData} = this.state;
|
|
708
|
+
const {errorData, schema} = this.state;
|
|
709
709
|
const errorMessage = {key: 'validation-error', message: intl.formatMessage(messages.validationError)};
|
|
710
|
-
let isTagErrorExist = false;
|
|
711
710
|
if (!_.isEmpty(this.state.formData) && !this.state.isFormValid) {
|
|
712
711
|
let tab = this.state.currentTab;
|
|
713
|
-
const isAndroidInvalid = Object.values(errorData[0]).includes(true);
|
|
714
|
-
const isIosInvalid = Object.values(errorData[1]).includes(true);
|
|
712
|
+
const isAndroidInvalid = Object.values(errorData[0] || {}).includes(true);
|
|
713
|
+
const isIosInvalid = Object.values(errorData[1] || {}).includes(true);
|
|
714
|
+
const isIosTabVisible = get(schema, 'containers[0].panes[1].isSupported', true) !== false;
|
|
715
715
|
if (isAndroidInvalid) {
|
|
716
716
|
tab = 1;
|
|
717
717
|
errorMessage.description = intl.formatMessage(messages.invalidAndroidMessage);
|
|
718
|
-
|
|
719
|
-
if (!_.isEmpty(invalidTags)) {
|
|
720
|
-
isTagErrorExist = true;
|
|
721
|
-
errorMessage.description = `${intl.formatMessage(messages.invalidAndroidMessage)} ${intl.formatMessage(messages.invalidTags)}: ${invalidTags.join(',')} `;
|
|
722
|
-
}
|
|
723
|
-
} else if (isIosInvalid) {
|
|
718
|
+
} else if (isIosInvalid && isIosTabVisible) {
|
|
724
719
|
tab = 2;
|
|
725
720
|
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
|
-
}
|
|
731
721
|
}
|
|
732
722
|
|
|
733
|
-
if (tab !== this.state.currentTab
|
|
723
|
+
if (tab !== this.state.currentTab) {
|
|
734
724
|
CapNotification.error(errorMessage);
|
|
735
725
|
}
|
|
736
726
|
}
|
|
@@ -77,7 +77,6 @@ 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";
|
|
81
80
|
import formBuilderMessages from "../../v2Components/FormBuilder/messages";
|
|
82
81
|
import { validateMobilePushContent } from "../../utils/commonUtils";
|
|
83
82
|
import { getSingleTab } from "../InApp/utils";
|
|
@@ -803,10 +802,9 @@ const MobilePushNew = ({
|
|
|
803
802
|
(value) => {
|
|
804
803
|
let errorTemplateDescMessage = "";
|
|
805
804
|
|
|
806
|
-
const {
|
|
805
|
+
const { isBraceError } = validateTags({
|
|
807
806
|
content: value,
|
|
808
807
|
tagsParam: tags,
|
|
809
|
-
injectedTagsParams: injectedTags,
|
|
810
808
|
location,
|
|
811
809
|
tagModule: getDefaultTags,
|
|
812
810
|
isFullMode,
|
|
@@ -816,14 +814,6 @@ const MobilePushNew = ({
|
|
|
816
814
|
messages.emptyTemplateDescErrorMessage
|
|
817
815
|
);
|
|
818
816
|
}
|
|
819
|
-
if (unsupportedTags?.length > 0) {
|
|
820
|
-
errorTemplateDescMessage = formatMessage(
|
|
821
|
-
globalMessages.unsupportedTagsValidationError,
|
|
822
|
-
{
|
|
823
|
-
unsupportedTags,
|
|
824
|
-
}
|
|
825
|
-
);
|
|
826
|
-
}
|
|
827
817
|
if (isBraceError) {
|
|
828
818
|
errorTemplateDescMessage = formatMessage(
|
|
829
819
|
globalMessages.unbalanacedCurlyBraces
|
|
@@ -2659,20 +2649,6 @@ const MobilePushNew = ({
|
|
|
2659
2649
|
getLiquidTags: globalActionsProps.getLiquidTags,
|
|
2660
2650
|
formatMessage,
|
|
2661
2651
|
messages: formBuilderMessages,
|
|
2662
|
-
tagLookupMap: metaEntities?.tagLookupMap || {},
|
|
2663
|
-
eventContextTags: metaEntities?.eventContextTags || [],
|
|
2664
|
-
isLiquidFlow: hasLiquidSupportFeature(),
|
|
2665
|
-
forwardedTags: {},
|
|
2666
|
-
skipTags: (tag) => {
|
|
2667
|
-
const skipRegexes = [
|
|
2668
|
-
/dynamic_expiry_date_after_\d+_days\.FORMAT_\d/,
|
|
2669
|
-
/unsubscribe\(#[a-zA-Z\d]{6}\)/,
|
|
2670
|
-
/Link_to_[a-zA-z]/,
|
|
2671
|
-
/SURVEY.*\.TOKEN/,
|
|
2672
|
-
/^[A-Za-z].*\([a-zA-Z\d]*\)/,
|
|
2673
|
-
];
|
|
2674
|
-
return skipRegexes.some((regex) => regex.test(tag));
|
|
2675
|
-
},
|
|
2676
2652
|
singleTab: getSingleTab(accountData),
|
|
2677
2653
|
});
|
|
2678
2654
|
}, [
|
|
@@ -2681,12 +2657,9 @@ const MobilePushNew = ({
|
|
|
2681
2657
|
activeTab,
|
|
2682
2658
|
globalActionsProps,
|
|
2683
2659
|
formatMessage,
|
|
2684
|
-
metaEntities,
|
|
2685
2660
|
accountData,
|
|
2686
2661
|
]);
|
|
2687
2662
|
|
|
2688
|
-
const isLiquidFlow = hasLiquidSupportFeature();
|
|
2689
|
-
|
|
2690
2663
|
useEffect(() => {
|
|
2691
2664
|
// Always map to { label } for both platforms
|
|
2692
2665
|
const newButtons = Array.isArray(ctaData)
|
|
@@ -3083,11 +3056,7 @@ const MobilePushNew = ({
|
|
|
3083
3056
|
<CapButton
|
|
3084
3057
|
type="primary"
|
|
3085
3058
|
onClick={() => {
|
|
3086
|
-
|
|
3087
|
-
liquidMiddleWare();
|
|
3088
|
-
} else {
|
|
3089
|
-
handleSave();
|
|
3090
|
-
}
|
|
3059
|
+
liquidMiddleWare();
|
|
3091
3060
|
}}
|
|
3092
3061
|
className="save-button"
|
|
3093
3062
|
disabled={isSaveDisabled}
|
|
@@ -394,23 +394,15 @@ export const Rcs = (props) => {
|
|
|
394
394
|
const validationResponse =
|
|
395
395
|
validateTags({
|
|
396
396
|
content: contentForValidation,
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
const errorMsg =
|
|
407
|
-
(unsupportedTagsLengthCheck &&
|
|
408
|
-
formatMessage(globalMessages.unsupportedTagsValidationError, {
|
|
409
|
-
unsupportedTags: validationResponse.unsupportedTags,
|
|
410
|
-
})) ||
|
|
411
|
-
(validationResponse.isBraceError &&
|
|
412
|
-
formatMessage(globalMessages.unbalanacedCurlyBraces)) ||
|
|
413
|
-
false;
|
|
397
|
+
tagsParam: tags,
|
|
398
|
+
location,
|
|
399
|
+
tagModule: getDefaultTags,
|
|
400
|
+
isFullMode,
|
|
401
|
+
}) || {};
|
|
402
|
+
const errorMsg =
|
|
403
|
+
(validationResponse?.isBraceError &&
|
|
404
|
+
formatMessage(globalMessages.unbalanacedCurlyBraces)) ||
|
|
405
|
+
false;
|
|
414
406
|
if (type === TITLE_TEXT) setTemplateTitleError(errorMsg);
|
|
415
407
|
if (type === MESSAGE_TEXT) setTemplateDescError(errorMsg);
|
|
416
408
|
};
|
|
@@ -835,10 +827,9 @@ export const Rcs = (props) => {
|
|
|
835
827
|
|
|
836
828
|
const templateDescErrorHandler = (value) => {
|
|
837
829
|
let errorMessage = false;
|
|
838
|
-
const {
|
|
830
|
+
const { isBraceError } = validateTags({
|
|
839
831
|
content: value,
|
|
840
832
|
tagsParam: tags,
|
|
841
|
-
injectedTagsParams: injectedTags,
|
|
842
833
|
location,
|
|
843
834
|
tagModule: getDefaultTags,
|
|
844
835
|
isFullMode,
|
|
@@ -868,26 +859,10 @@ export const Rcs = (props) => {
|
|
|
868
859
|
};
|
|
869
860
|
|
|
870
861
|
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
|
-
}) || {};
|
|
880
862
|
if (value?.length > FALLBACK_MESSAGE_MAX_LENGTH) {
|
|
881
|
-
|
|
882
|
-
} else if (unsupportedTags?.length > 0) {
|
|
883
|
-
errorMessage = formatMessage(
|
|
884
|
-
globalMessages.unsupportedTagsValidationError,
|
|
885
|
-
{
|
|
886
|
-
unsupportedTags,
|
|
887
|
-
},
|
|
888
|
-
);
|
|
863
|
+
return formatMessage(messages.fallbackMsgLenError);
|
|
889
864
|
}
|
|
890
|
-
return
|
|
865
|
+
return false;
|
|
891
866
|
};
|
|
892
867
|
|
|
893
868
|
// Check for forbidden characters: square brackets [] and single curly braces {}
|
|
@@ -51,6 +51,7 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
51
51
|
modalContent: {title: "Alert", body: "Do you really want to delete this version?", type: 'confirm', id: 'sms-version-modal'},
|
|
52
52
|
showTestAndPreviewSlidebox: false,
|
|
53
53
|
isTestAndPreviewMode: false,
|
|
54
|
+
pendingGetFormData: false,
|
|
54
55
|
};
|
|
55
56
|
this.saveFormData = this.saveFormData.bind(this);
|
|
56
57
|
this.onFormDataChange = this.onFormDataChange.bind(this);
|
|
@@ -140,8 +141,16 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
140
141
|
}
|
|
141
142
|
|
|
142
143
|
componentWillReceiveProps(nextProps) {
|
|
143
|
-
if (nextProps.
|
|
144
|
-
|
|
144
|
+
if (!nextProps.isFullMode && nextProps.isGetFormData) {
|
|
145
|
+
// Trigger validation first; response will be sent in setFormValidity callback so pasted content is validated
|
|
146
|
+
this.setState({ startValidation: true, pendingGetFormData: true });
|
|
147
|
+
// Fallback: if FormBuilder never calls onFormValidityChange (e.g. early return), still respond to parent
|
|
148
|
+
this.pendingGetFormDataTimeout = setTimeout(() => {
|
|
149
|
+
if (this.state.pendingGetFormData && this.props.getFormSubscriptionData) {
|
|
150
|
+
this.props.getFormSubscriptionData(this.getFormData());
|
|
151
|
+
this.setState({ pendingGetFormData: false, startValidation: false });
|
|
152
|
+
}
|
|
153
|
+
}, 300);
|
|
145
154
|
} else if (nextProps.isGetFormData && this.props.isFullMode && !this.props.Create.createTemplateInProgress) {
|
|
146
155
|
this.startValidation();
|
|
147
156
|
}
|
|
@@ -171,6 +180,9 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
171
180
|
}
|
|
172
181
|
|
|
173
182
|
componentWillUnmount() {
|
|
183
|
+
if (this.pendingGetFormDataTimeout) {
|
|
184
|
+
clearTimeout(this.pendingGetFormDataTimeout);
|
|
185
|
+
}
|
|
174
186
|
if (this.props.setIsLoadingContent) {
|
|
175
187
|
this.props.setIsLoadingContent(true); // setting isLoading of CreativesContainer so that slidebox foot can be hidden till content is loaded
|
|
176
188
|
}
|
|
@@ -349,7 +361,16 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
349
361
|
}
|
|
350
362
|
|
|
351
363
|
setFormValidity(isFormValid, errorData) {
|
|
352
|
-
this.setState({isFormValid, errorData})
|
|
364
|
+
this.setState({ isFormValid, errorData }, () => {
|
|
365
|
+
if (this.state.pendingGetFormData && this.props.getFormSubscriptionData) {
|
|
366
|
+
if (this.pendingGetFormDataTimeout) {
|
|
367
|
+
clearTimeout(this.pendingGetFormDataTimeout);
|
|
368
|
+
this.pendingGetFormDataTimeout = null;
|
|
369
|
+
}
|
|
370
|
+
this.props.getFormSubscriptionData(this.getFormData());
|
|
371
|
+
this.setState({ pendingGetFormData: false, startValidation: false });
|
|
372
|
+
}
|
|
373
|
+
});
|
|
353
374
|
}
|
|
354
375
|
|
|
355
376
|
injectMessages(elem) {
|
|
@@ -970,6 +991,13 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
970
991
|
}
|
|
971
992
|
|
|
972
993
|
saveFormData() {
|
|
994
|
+
// In library mode the template is submitted via getFormSubscriptionData (triggered by startValidation →
|
|
995
|
+
// onFormValidityChange → setFormValidity). Calling createTemplate API here would set
|
|
996
|
+
// createTemplateInProgress: true in redux and, because the slidebox closes before the API responds,
|
|
997
|
+
// that flag would never be reset – causing the spinner to be stuck on the next open.
|
|
998
|
+
if (!this.props.isFullMode) {
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
973
1001
|
//Logic to save in db etc
|
|
974
1002
|
const formData = _.cloneDeep(this.state.formData);
|
|
975
1003
|
const obj = {};
|
|
@@ -90,6 +90,10 @@ export default defineMessages({
|
|
|
90
90
|
id: 'creatives.containersV2.Create.validationError',
|
|
91
91
|
defaultMessage: 'Validation error',
|
|
92
92
|
},
|
|
93
|
+
"unbalancedCurlyBraces": {
|
|
94
|
+
id: 'creatives.containersV2.Create.unbalancedCurlyBraces',
|
|
95
|
+
defaultMessage: 'Please close all curly braces in the message.',
|
|
96
|
+
},
|
|
93
97
|
"smsTemplateCreatedSuccess": {
|
|
94
98
|
id: 'creatives.containersV2.Create.smsTemplateCreatedSuccess',
|
|
95
99
|
defaultMessage: 'SMS Template Created Successfully',
|
|
@@ -52,6 +52,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
52
52
|
modalContent: {title: "Alert", body: "Do you really want to delete this version?", type: 'confirm', id: 'sms-version-modal'},
|
|
53
53
|
showTestAndPreviewSlidebox: false,
|
|
54
54
|
isTestAndPreviewMode: false,
|
|
55
|
+
pendingGetFormData: false,
|
|
55
56
|
};
|
|
56
57
|
this.saveFormData = this.saveFormData.bind(this);
|
|
57
58
|
this.onFormDataChange = this.onFormDataChange.bind(this);
|
|
@@ -134,8 +135,14 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
134
135
|
}
|
|
135
136
|
|
|
136
137
|
componentWillReceiveProps(nextProps) {
|
|
137
|
-
if (nextProps.
|
|
138
|
-
|
|
138
|
+
if (!nextProps.isFullMode && nextProps.isGetFormData) {
|
|
139
|
+
this.setState({ startValidation: true, pendingGetFormData: true });
|
|
140
|
+
this.pendingGetFormDataTimeout = setTimeout(() => {
|
|
141
|
+
if (this.state.pendingGetFormData && this.props.getFormSubscriptionData) {
|
|
142
|
+
this.props.getFormSubscriptionData(this.getFormData());
|
|
143
|
+
this.setState({ pendingGetFormData: false, startValidation: false });
|
|
144
|
+
}
|
|
145
|
+
}, 300);
|
|
139
146
|
}
|
|
140
147
|
if ( nextProps.location.query.module === 'library' && nextProps.subscriptionTemplateDetails && nextProps.subscriptionTemplateDetails.name && _.isEmpty(this.state.editData) && !_.isEmpty(this.state.schema)) {
|
|
141
148
|
this.setEditState(nextProps.subscriptionTemplateDetails);
|
|
@@ -189,6 +196,9 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
189
196
|
}
|
|
190
197
|
|
|
191
198
|
componentWillUnmount() {
|
|
199
|
+
if (this.pendingGetFormDataTimeout) {
|
|
200
|
+
clearTimeout(this.pendingGetFormDataTimeout);
|
|
201
|
+
}
|
|
192
202
|
if (this.props.setIsLoadingContent) {
|
|
193
203
|
this.props.setIsLoadingContent(true); // setting isLoading of CreativesContainer so that slidebox foot can be hidden till content is loaded
|
|
194
204
|
}
|
|
@@ -317,7 +327,16 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
317
327
|
}
|
|
318
328
|
|
|
319
329
|
setFormValidity(isFormValid, errorData) {
|
|
320
|
-
this.setState({isFormValid, errorData})
|
|
330
|
+
this.setState({ isFormValid, errorData }, () => {
|
|
331
|
+
if (this.state.pendingGetFormData && this.props.getFormSubscriptionData) {
|
|
332
|
+
if (this.pendingGetFormDataTimeout) {
|
|
333
|
+
clearTimeout(this.pendingGetFormDataTimeout);
|
|
334
|
+
this.pendingGetFormDataTimeout = null;
|
|
335
|
+
}
|
|
336
|
+
this.props.getFormSubscriptionData(this.getFormData());
|
|
337
|
+
this.setState({ pendingGetFormData: false, startValidation: false });
|
|
338
|
+
}
|
|
339
|
+
});
|
|
321
340
|
}
|
|
322
341
|
|
|
323
342
|
getFormData(e, value) {
|
|
@@ -923,6 +942,13 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
923
942
|
this.setState({startValidation: false});
|
|
924
943
|
}
|
|
925
944
|
saveFormData() {
|
|
945
|
+
// In library mode the template is submitted via getFormSubscriptionData, not editTemplate API.
|
|
946
|
+
// Calling editTemplate here would set editTemplateInProgress: true in redux and, because the
|
|
947
|
+
// slidebox closes before the API responds, that flag would never be reset – causing the spinner
|
|
948
|
+
// to be stuck on the next open.
|
|
949
|
+
if (!this.props.isFullMode) {
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
926
952
|
//Logic to save in db etc
|
|
927
953
|
//saveFormData gets called only when validation result is true
|
|
928
954
|
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import isEmpty from 'lodash/isEmpty';
|
|
2
|
-
import
|
|
2
|
+
import CapNotification from '@capillarytech/cap-ui-library/CapNotification';
|
|
3
3
|
import messages from './Create/messages';
|
|
4
4
|
export function showError() {
|
|
5
5
|
const {intl} = this.props;
|
|
6
6
|
const {errorData} = this.state;
|
|
7
7
|
const errorMessage = {key: 'validation-error', message: intl.formatMessage(messages.validationError)};
|
|
8
8
|
if (!isEmpty(this.state.formData) && !this.state.isFormValid) {
|
|
9
|
-
const
|
|
9
|
+
const err0 = errorData[0] || {};
|
|
10
|
+
const isSmsInvalid = Object.values(err0).includes(true);
|
|
11
|
+
const isBraceError = Boolean(err0['bracket-error']);
|
|
10
12
|
if (isSmsInvalid) {
|
|
11
|
-
const invalidTags = errorData[0]['invalid-tags'];
|
|
12
|
-
if (!isEmpty(invalidTags)) {
|
|
13
|
-
errorMessage.description = `${intl.formatMessage(messages.invalidTags)}: ${invalidTags.join(',')} `;
|
|
14
|
-
}
|
|
15
13
|
CapNotification.error(errorMessage);
|
|
14
|
+
} else if (isBraceError) {
|
|
15
|
+
// Do not trigger toast for this path; footer error is the reliable UX in SMS library flow.
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
}
|