@capillarytech/creatives-library 8.0.286 → 8.0.287-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.
- 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 +2 -83
- package/utils/tagValidations.js +84 -222
- package/utils/tests/commonUtil.test.js +147 -118
- package/utils/tests/tagValidations.test.js +280 -358
- package/v2Components/ErrorInfoNote/index.js +2 -5
- package/v2Components/FormBuilder/index.js +68 -160
- 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/index.js +4 -4
- 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/ImageCarousel/tests/__snapshots__/content.test.js.snap +3 -24
- package/v2Containers/Line/Container/Text/index.js +0 -1
- package/v2Containers/MobilePushNew/index.js +2 -33
- package/v2Containers/Rcs/index.js +12 -37
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +4 -18
- package/v2Containers/Sms/Create/index.js +30 -2
- package/v2Containers/Sms/Create/messages.js +4 -0
- package/v2Containers/Sms/Edit/index.js +28 -2
- package/v2Containers/Sms/commonMethods.js +7 -2
- package/v2Containers/SmsTrai/Create/index.scss +1 -1
- package/v2Containers/SmsTrai/Edit/index.js +6 -47
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +6 -6
- package/v2Containers/Viber/index.js +0 -1
- package/v2Containers/Viber/index.scss +1 -1
- 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/utils/validation.js +18 -9
- package/v2Containers/WebPush/Create/utils/validation.test.js +0 -24
- package/v2Containers/Whatsapp/index.js +9 -17
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +248 -624
- 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"
|
|
@@ -3117,7 +3117,6 @@ new message content.",
|
|
|
3117
3117
|
},
|
|
3118
3118
|
]
|
|
3119
3119
|
}
|
|
3120
|
-
showTruncatedTooltip={false}
|
|
3121
3120
|
size="large"
|
|
3122
3121
|
style={
|
|
3123
3122
|
Object {
|
|
@@ -3136,7 +3135,6 @@ new message content.",
|
|
|
3136
3135
|
/>
|
|
3137
3136
|
}
|
|
3138
3137
|
onChange={[Function]}
|
|
3139
|
-
onDropdownVisibleChange={[Function]}
|
|
3140
3138
|
removeIcon={
|
|
3141
3139
|
<CapIcon
|
|
3142
3140
|
size="s"
|
|
@@ -3201,7 +3199,6 @@ new message content.",
|
|
|
3201
3199
|
onBlur={[Function]}
|
|
3202
3200
|
onChange={[Function]}
|
|
3203
3201
|
onDeselect={[Function]}
|
|
3204
|
-
onDropdownVisibleChange={[Function]}
|
|
3205
3202
|
onFocus={[Function]}
|
|
3206
3203
|
onInputKeyDown={[Function]}
|
|
3207
3204
|
onSearch={[Function]}
|
|
@@ -3440,11 +3437,7 @@ new message content.",
|
|
|
3440
3437
|
}
|
|
3441
3438
|
}
|
|
3442
3439
|
title=""
|
|
3443
|
-
|
|
3444
|
-
<div
|
|
3445
|
-
className="cap-select-option-tooltip"
|
|
3446
|
-
/>
|
|
3447
|
-
</div>
|
|
3440
|
+
/>
|
|
3448
3441
|
</div>
|
|
3449
3442
|
<span
|
|
3450
3443
|
className="ant-select-arrow"
|
|
@@ -6947,7 +6940,6 @@ new message content.",
|
|
|
6947
6940
|
},
|
|
6948
6941
|
]
|
|
6949
6942
|
}
|
|
6950
|
-
showTruncatedTooltip={false}
|
|
6951
6943
|
size="large"
|
|
6952
6944
|
style={
|
|
6953
6945
|
Object {
|
|
@@ -6966,7 +6958,6 @@ new message content.",
|
|
|
6966
6958
|
/>
|
|
6967
6959
|
}
|
|
6968
6960
|
onChange={[Function]}
|
|
6969
|
-
onDropdownVisibleChange={[Function]}
|
|
6970
6961
|
removeIcon={
|
|
6971
6962
|
<CapIcon
|
|
6972
6963
|
size="s"
|
|
@@ -7031,7 +7022,6 @@ new message content.",
|
|
|
7031
7022
|
onBlur={[Function]}
|
|
7032
7023
|
onChange={[Function]}
|
|
7033
7024
|
onDeselect={[Function]}
|
|
7034
|
-
onDropdownVisibleChange={[Function]}
|
|
7035
7025
|
onFocus={[Function]}
|
|
7036
7026
|
onInputKeyDown={[Function]}
|
|
7037
7027
|
onSearch={[Function]}
|
|
@@ -7270,11 +7260,7 @@ new message content.",
|
|
|
7270
7260
|
}
|
|
7271
7261
|
}
|
|
7272
7262
|
title=""
|
|
7273
|
-
|
|
7274
|
-
<div
|
|
7275
|
-
className="cap-select-option-tooltip"
|
|
7276
|
-
/>
|
|
7277
|
-
</div>
|
|
7263
|
+
/>
|
|
7278
7264
|
</div>
|
|
7279
7265
|
<span
|
|
7280
7266
|
className="ant-select-arrow"
|
|
@@ -10721,7 +10707,6 @@ new message content.",
|
|
|
10721
10707
|
},
|
|
10722
10708
|
]
|
|
10723
10709
|
}
|
|
10724
|
-
showTruncatedTooltip={false}
|
|
10725
10710
|
size="large"
|
|
10726
10711
|
style={
|
|
10727
10712
|
Object {
|
|
@@ -10740,7 +10725,6 @@ new message content.",
|
|
|
10740
10725
|
/>
|
|
10741
10726
|
}
|
|
10742
10727
|
onChange={[Function]}
|
|
10743
|
-
onDropdownVisibleChange={[Function]}
|
|
10744
10728
|
removeIcon={
|
|
10745
10729
|
<CapIcon
|
|
10746
10730
|
size="s"
|
|
@@ -10805,7 +10789,6 @@ new message content.",
|
|
|
10805
10789
|
onBlur={[Function]}
|
|
10806
10790
|
onChange={[Function]}
|
|
10807
10791
|
onDeselect={[Function]}
|
|
10808
|
-
onDropdownVisibleChange={[Function]}
|
|
10809
10792
|
onFocus={[Function]}
|
|
10810
10793
|
onInputKeyDown={[Function]}
|
|
10811
10794
|
onSearch={[Function]}
|
|
@@ -11044,11 +11027,7 @@ new message content.",
|
|
|
11044
11027
|
}
|
|
11045
11028
|
}
|
|
11046
11029
|
title=""
|
|
11047
|
-
|
|
11048
|
-
<div
|
|
11049
|
-
className="cap-select-option-tooltip"
|
|
11050
|
-
/>
|
|
11051
|
-
</div>
|
|
11030
|
+
/>
|
|
11052
11031
|
</div>
|
|
11053
11032
|
<span
|
|
11054
11033
|
className="ant-select-arrow"
|
|
@@ -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";
|
|
@@ -799,10 +798,9 @@ const MobilePushNew = ({
|
|
|
799
798
|
(value) => {
|
|
800
799
|
let errorTemplateDescMessage = "";
|
|
801
800
|
|
|
802
|
-
const {
|
|
801
|
+
const { isBraceError } = validateTags({
|
|
803
802
|
content: value,
|
|
804
803
|
tagsParam: tags,
|
|
805
|
-
injectedTagsParams: injectedTags,
|
|
806
804
|
location,
|
|
807
805
|
tagModule: getDefaultTags,
|
|
808
806
|
isFullMode,
|
|
@@ -812,14 +810,6 @@ const MobilePushNew = ({
|
|
|
812
810
|
messages.emptyTemplateDescErrorMessage
|
|
813
811
|
);
|
|
814
812
|
}
|
|
815
|
-
if (unsupportedTags?.length > 0) {
|
|
816
|
-
errorTemplateDescMessage = formatMessage(
|
|
817
|
-
globalMessages.unsupportedTagsValidationError,
|
|
818
|
-
{
|
|
819
|
-
unsupportedTags,
|
|
820
|
-
}
|
|
821
|
-
);
|
|
822
|
-
}
|
|
823
813
|
if (isBraceError) {
|
|
824
814
|
errorTemplateDescMessage = formatMessage(
|
|
825
815
|
globalMessages.unbalanacedCurlyBraces
|
|
@@ -2606,20 +2596,6 @@ const MobilePushNew = ({
|
|
|
2606
2596
|
getLiquidTags: globalActionsProps.getLiquidTags,
|
|
2607
2597
|
formatMessage,
|
|
2608
2598
|
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
|
-
},
|
|
2623
2599
|
singleTab: getSingleTab(accountData),
|
|
2624
2600
|
});
|
|
2625
2601
|
}, [
|
|
@@ -2628,12 +2604,9 @@ const MobilePushNew = ({
|
|
|
2628
2604
|
activeTab,
|
|
2629
2605
|
globalActionsProps,
|
|
2630
2606
|
formatMessage,
|
|
2631
|
-
metaEntities,
|
|
2632
2607
|
accountData,
|
|
2633
2608
|
]);
|
|
2634
2609
|
|
|
2635
|
-
const isLiquidFlow = hasLiquidSupportFeature();
|
|
2636
|
-
|
|
2637
2610
|
useEffect(() => {
|
|
2638
2611
|
// Always map to { label } for both platforms
|
|
2639
2612
|
const newButtons = Array.isArray(ctaData)
|
|
@@ -3030,11 +3003,7 @@ const MobilePushNew = ({
|
|
|
3030
3003
|
<CapButton
|
|
3031
3004
|
type="primary"
|
|
3032
3005
|
onClick={() => {
|
|
3033
|
-
|
|
3034
|
-
liquidMiddleWare();
|
|
3035
|
-
} else {
|
|
3036
|
-
handleSave();
|
|
3037
|
-
}
|
|
3006
|
+
liquidMiddleWare();
|
|
3038
3007
|
}}
|
|
3039
3008
|
className="save-button"
|
|
3040
3009
|
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 {}
|
|
@@ -86505,7 +86505,6 @@ new message content.",
|
|
|
86505
86505
|
},
|
|
86506
86506
|
]
|
|
86507
86507
|
}
|
|
86508
|
-
showTruncatedTooltip={false}
|
|
86509
86508
|
size="large"
|
|
86510
86509
|
style={
|
|
86511
86510
|
Object {
|
|
@@ -86525,7 +86524,6 @@ new message content.",
|
|
|
86525
86524
|
/>
|
|
86526
86525
|
}
|
|
86527
86526
|
onChange={[Function]}
|
|
86528
|
-
onDropdownVisibleChange={[Function]}
|
|
86529
86527
|
removeIcon={
|
|
86530
86528
|
<_default
|
|
86531
86529
|
size="s"
|
|
@@ -86591,7 +86589,6 @@ new message content.",
|
|
|
86591
86589
|
onBlur={[Function]}
|
|
86592
86590
|
onChange={[Function]}
|
|
86593
86591
|
onDeselect={[Function]}
|
|
86594
|
-
onDropdownVisibleChange={[Function]}
|
|
86595
86592
|
onFocus={[Function]}
|
|
86596
86593
|
onInputKeyDown={[Function]}
|
|
86597
86594
|
onSearch={[Function]}
|
|
@@ -86830,13 +86827,9 @@ new message content.",
|
|
|
86830
86827
|
"opacity": 1,
|
|
86831
86828
|
}
|
|
86832
86829
|
}
|
|
86833
|
-
title=""
|
|
86830
|
+
title="Vertical Medium"
|
|
86834
86831
|
>
|
|
86835
|
-
|
|
86836
|
-
className="cap-select-option-tooltip"
|
|
86837
|
-
>
|
|
86838
|
-
Vertical Medium
|
|
86839
|
-
</div>
|
|
86832
|
+
Vertical Medium
|
|
86840
86833
|
</div>
|
|
86841
86834
|
</div>
|
|
86842
86835
|
<span
|
|
@@ -105854,7 +105847,6 @@ new message content.",
|
|
|
105854
105847
|
},
|
|
105855
105848
|
]
|
|
105856
105849
|
}
|
|
105857
|
-
showTruncatedTooltip={false}
|
|
105858
105850
|
size="large"
|
|
105859
105851
|
style={
|
|
105860
105852
|
Object {
|
|
@@ -105874,7 +105866,6 @@ new message content.",
|
|
|
105874
105866
|
/>
|
|
105875
105867
|
}
|
|
105876
105868
|
onChange={[Function]}
|
|
105877
|
-
onDropdownVisibleChange={[Function]}
|
|
105878
105869
|
removeIcon={
|
|
105879
105870
|
<_default
|
|
105880
105871
|
size="s"
|
|
@@ -105940,7 +105931,6 @@ new message content.",
|
|
|
105940
105931
|
onBlur={[Function]}
|
|
105941
105932
|
onChange={[Function]}
|
|
105942
105933
|
onDeselect={[Function]}
|
|
105943
|
-
onDropdownVisibleChange={[Function]}
|
|
105944
105934
|
onFocus={[Function]}
|
|
105945
105935
|
onInputKeyDown={[Function]}
|
|
105946
105936
|
onSearch={[Function]}
|
|
@@ -106179,13 +106169,9 @@ new message content.",
|
|
|
106179
106169
|
"opacity": 1,
|
|
106180
106170
|
}
|
|
106181
106171
|
}
|
|
106182
|
-
title=""
|
|
106172
|
+
title="Vertical Medium"
|
|
106183
106173
|
>
|
|
106184
|
-
|
|
106185
|
-
className="cap-select-option-tooltip"
|
|
106186
|
-
>
|
|
106187
|
-
Vertical Medium
|
|
106188
|
-
</div>
|
|
106174
|
+
Vertical Medium
|
|
106189
106175
|
</div>
|
|
106190
106176
|
</div>
|
|
106191
106177
|
<span
|
|
@@ -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);
|
|
@@ -141,7 +142,15 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
141
142
|
|
|
142
143
|
componentWillReceiveProps(nextProps) {
|
|
143
144
|
if (nextProps.location.query.module === 'library' && nextProps.isGetFormData) {
|
|
144
|
-
|
|
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);
|
|
@@ -135,7 +136,13 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
135
136
|
|
|
136
137
|
componentWillReceiveProps(nextProps) {
|
|
137
138
|
if (nextProps.location.query.module === 'library' && nextProps.isGetFormData) {
|
|
138
|
-
|
|
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
|
|
|
@@ -6,13 +6,18 @@ export function showError() {
|
|
|
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 =
|
|
13
|
+
const invalidTags = err0['invalid-tags'];
|
|
12
14
|
if (!isEmpty(invalidTags)) {
|
|
13
15
|
errorMessage.description = `${intl.formatMessage(messages.invalidTags)}: ${invalidTags.join(',')} `;
|
|
14
16
|
}
|
|
15
17
|
CapNotification.error(errorMessage);
|
|
18
|
+
} else if (isBraceError) {
|
|
19
|
+
errorMessage.description = intl.formatMessage(messages.unbalancedCurlyBraces);
|
|
20
|
+
CapNotification.error(errorMessage);
|
|
16
21
|
}
|
|
17
22
|
}
|
|
18
23
|
}
|