@capillarytech/creatives-library 8.0.289 → 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
|
@@ -528,26 +528,19 @@ describe('useTagManagement', () => {
|
|
|
528
528
|
|
|
529
529
|
describe('validationConfig', () => {
|
|
530
530
|
it('should return validation config with tags', () => {
|
|
531
|
-
const injectedTags = [{ id: 5, name: 'Injected Tag' }];
|
|
532
|
-
const eventContextTags = [{ id: 6, name: 'Event Tag' }];
|
|
533
|
-
|
|
534
531
|
const { result } = renderHook(() =>
|
|
535
532
|
useTagManagement({
|
|
536
533
|
location: defaultLocation,
|
|
537
534
|
globalActions: mockGlobalActions,
|
|
538
535
|
metaEntities: defaultMetaEntities,
|
|
539
|
-
injectedTags,
|
|
540
|
-
eventContextTags,
|
|
541
536
|
getDefaultTags: 'custom',
|
|
542
537
|
})
|
|
543
538
|
);
|
|
544
539
|
|
|
545
540
|
expect(result.current.validationConfig).toEqual({
|
|
546
541
|
tagsParam: defaultMetaEntities.tags.standard,
|
|
547
|
-
injectedTagsParams: injectedTags,
|
|
548
542
|
location: defaultLocation,
|
|
549
543
|
tagModule: 'custom',
|
|
550
|
-
eventContextTags,
|
|
551
544
|
});
|
|
552
545
|
});
|
|
553
546
|
|
|
@@ -295,8 +295,8 @@ const WebPushCreate = ({
|
|
|
295
295
|
const validateTemplateName = useCallback((value) => validateTemplateNameUtil(value), []);
|
|
296
296
|
|
|
297
297
|
const validateTitle = useCallback(
|
|
298
|
-
(value) => validateTitleUtil(value, formatMessage, messages, restrictPersonalization),
|
|
299
|
-
[formatMessage, restrictPersonalization],
|
|
298
|
+
(value) => validateTitleUtil(value, formatMessage, messages, restrictPersonalization, validationConfig, isFullMode),
|
|
299
|
+
[formatMessage, restrictPersonalization, validationConfig, isFullMode],
|
|
300
300
|
);
|
|
301
301
|
|
|
302
302
|
const validateUrl = useCallback(
|
|
@@ -1016,6 +1016,275 @@ describe('NotificationContainer', () => {
|
|
|
1016
1016
|
});
|
|
1017
1017
|
});
|
|
1018
1018
|
|
|
1019
|
+
describe('platform.browser getter — 2-part vs 3-part class names', () => {
|
|
1020
|
+
it('derives browser from 2-part class name (macos-chrome → parts[1])', () => {
|
|
1021
|
+
// 'macos-chrome'.split('-') = ['macos', 'chrome'] → length=2 → browser = parts[1] = 'chrome'
|
|
1022
|
+
const wrapper = mountWithIntl(
|
|
1023
|
+
<NotificationContainer {...defaultProps} selectedOS={OS_MACOS} selectedBrowser={BROWSER_CHROME} />
|
|
1024
|
+
);
|
|
1025
|
+
expect(wrapper.find('.notification-container').hasClass('macos-chrome')).toBe(true);
|
|
1026
|
+
});
|
|
1027
|
+
|
|
1028
|
+
it('derives browser from 3-part class name (android-mobile-chrome → parts[2])', () => {
|
|
1029
|
+
// 'android-mobile-chrome'.split('-') = ['android', 'mobile', 'chrome'] → length=3 → browser = parts[2] = 'chrome'
|
|
1030
|
+
const wrapper = mountWithIntl(
|
|
1031
|
+
<NotificationContainer {...defaultProps} selectedOS={OS_ANDROID_MOBILE} selectedBrowser={BROWSER_CHROME} />
|
|
1032
|
+
);
|
|
1033
|
+
expect(wrapper.find('.notification-container').hasClass('android-mobile-chrome')).toBe(true);
|
|
1034
|
+
});
|
|
1035
|
+
|
|
1036
|
+
it('derives browser from 3-part class name for Android Tablet (android-tablet-firefox → parts[2])', () => {
|
|
1037
|
+
const wrapper = mountWithIntl(
|
|
1038
|
+
<NotificationContainer {...defaultProps} selectedOS={OS_ANDROID_TABLET} selectedBrowser={BROWSER_FIREFOX} />
|
|
1039
|
+
);
|
|
1040
|
+
expect(wrapper.find('.notification-container').hasClass('android-tablet-firefox')).toBe(true);
|
|
1041
|
+
});
|
|
1042
|
+
});
|
|
1043
|
+
|
|
1044
|
+
describe('platform.isIOS getter (selectedOS === OS_IOS)', () => {
|
|
1045
|
+
it('is true for iOS — renders IOSHeader', () => {
|
|
1046
|
+
const wrapper = mountWithIntl(
|
|
1047
|
+
<NotificationContainer {...defaultProps} selectedOS={OS_IOS} selectedBrowser={BROWSER_CHROME} />
|
|
1048
|
+
);
|
|
1049
|
+
expect(wrapper.find(IOSHeader).exists()).toBe(true);
|
|
1050
|
+
});
|
|
1051
|
+
|
|
1052
|
+
it('is false for macOS — does not render IOSHeader', () => {
|
|
1053
|
+
const wrapper = mountWithIntl(
|
|
1054
|
+
<NotificationContainer {...defaultProps} selectedOS={OS_MACOS} selectedBrowser={BROWSER_CHROME} />
|
|
1055
|
+
);
|
|
1056
|
+
expect(wrapper.find(IOSHeader).exists()).toBe(false);
|
|
1057
|
+
});
|
|
1058
|
+
|
|
1059
|
+
it('is false for Android Mobile — does not render IOSHeader', () => {
|
|
1060
|
+
const wrapper = mountWithIntl(
|
|
1061
|
+
<NotificationContainer {...defaultProps} selectedOS={OS_ANDROID_MOBILE} selectedBrowser={BROWSER_CHROME} />
|
|
1062
|
+
);
|
|
1063
|
+
expect(wrapper.find(IOSHeader).exists()).toBe(false);
|
|
1064
|
+
});
|
|
1065
|
+
|
|
1066
|
+
it('is false for Windows — does not render IOSHeader', () => {
|
|
1067
|
+
const wrapper = mountWithIntl(
|
|
1068
|
+
<NotificationContainer {...defaultProps} selectedOS={OS_WINDOWS} selectedBrowser={BROWSER_CHROME} />
|
|
1069
|
+
);
|
|
1070
|
+
expect(wrapper.find(IOSHeader).exists()).toBe(false);
|
|
1071
|
+
});
|
|
1072
|
+
});
|
|
1073
|
+
|
|
1074
|
+
describe('platform.isIPadOS getter (selectedOS === OS_IPADOS)', () => {
|
|
1075
|
+
it('is true for iPadOS — renders IOSHeader', () => {
|
|
1076
|
+
const wrapper = mountWithIntl(
|
|
1077
|
+
<NotificationContainer {...defaultProps} selectedOS={OS_IPADOS} selectedBrowser={BROWSER_CHROME} />
|
|
1078
|
+
);
|
|
1079
|
+
expect(wrapper.find(IOSHeader).exists()).toBe(true);
|
|
1080
|
+
});
|
|
1081
|
+
|
|
1082
|
+
it('is false for Android Tablet — does not render IOSHeader', () => {
|
|
1083
|
+
const wrapper = mountWithIntl(
|
|
1084
|
+
<NotificationContainer {...defaultProps} selectedOS={OS_ANDROID_TABLET} selectedBrowser={BROWSER_CHROME} />
|
|
1085
|
+
);
|
|
1086
|
+
expect(wrapper.find(IOSHeader).exists()).toBe(false);
|
|
1087
|
+
expect(wrapper.find(AndroidMobileChromeHeader).exists()).toBe(true);
|
|
1088
|
+
});
|
|
1089
|
+
|
|
1090
|
+
it('is false for Windows — does not render IOSHeader', () => {
|
|
1091
|
+
const wrapper = mountWithIntl(
|
|
1092
|
+
<NotificationContainer {...defaultProps} selectedOS={OS_WINDOWS} selectedBrowser={BROWSER_CHROME} />
|
|
1093
|
+
);
|
|
1094
|
+
expect(wrapper.find(IOSHeader).exists()).toBe(false);
|
|
1095
|
+
});
|
|
1096
|
+
|
|
1097
|
+
it('is false for macOS — does not render IOSHeader', () => {
|
|
1098
|
+
const wrapper = mountWithIntl(
|
|
1099
|
+
<NotificationContainer {...defaultProps} selectedOS={OS_MACOS} selectedBrowser={BROWSER_SAFARI} />
|
|
1100
|
+
);
|
|
1101
|
+
expect(wrapper.find(IOSHeader).exists()).toBe(false);
|
|
1102
|
+
});
|
|
1103
|
+
});
|
|
1104
|
+
|
|
1105
|
+
describe('platform.isMacOsBrandIconBrowser getter (isMacOs && supportsBrandIcon)', () => {
|
|
1106
|
+
it('is true for macOS + Chrome (Chrome is in BRAND_ICON_SUPPORTED_BROWSERS) — shows brand icon in expanded', () => {
|
|
1107
|
+
const wrapper = mountWithIntl(
|
|
1108
|
+
<NotificationContainer
|
|
1109
|
+
{...defaultProps}
|
|
1110
|
+
selectedOS={OS_MACOS}
|
|
1111
|
+
selectedBrowser={BROWSER_CHROME}
|
|
1112
|
+
notificationState={NOTIFICATION_STATE_EXPANDED}
|
|
1113
|
+
brandIcon="brand.png"
|
|
1114
|
+
enableBrandIconPreview={true}
|
|
1115
|
+
/>
|
|
1116
|
+
);
|
|
1117
|
+
expect(wrapper.find(NotificationExpandedContent).prop('shouldShowBrandIconInExpandedMac')).toBe(true);
|
|
1118
|
+
});
|
|
1119
|
+
|
|
1120
|
+
it('is true for macOS + Edge (Edge is in BRAND_ICON_SUPPORTED_BROWSERS)', () => {
|
|
1121
|
+
const wrapper = mountWithIntl(
|
|
1122
|
+
<NotificationContainer
|
|
1123
|
+
{...defaultProps}
|
|
1124
|
+
selectedOS={OS_MACOS}
|
|
1125
|
+
selectedBrowser={BROWSER_EDGE}
|
|
1126
|
+
notificationState={NOTIFICATION_STATE_EXPANDED}
|
|
1127
|
+
brandIcon="brand.png"
|
|
1128
|
+
enableBrandIconPreview={true}
|
|
1129
|
+
/>
|
|
1130
|
+
);
|
|
1131
|
+
expect(wrapper.find(NotificationExpandedContent).prop('shouldShowBrandIconInExpandedMac')).toBe(true);
|
|
1132
|
+
});
|
|
1133
|
+
|
|
1134
|
+
it('is true for macOS + Opera (Opera is in BRAND_ICON_SUPPORTED_BROWSERS)', () => {
|
|
1135
|
+
const wrapper = mountWithIntl(
|
|
1136
|
+
<NotificationContainer
|
|
1137
|
+
{...defaultProps}
|
|
1138
|
+
selectedOS={OS_MACOS}
|
|
1139
|
+
selectedBrowser={BROWSER_OPERA}
|
|
1140
|
+
notificationState={NOTIFICATION_STATE_EXPANDED}
|
|
1141
|
+
brandIcon="brand.png"
|
|
1142
|
+
enableBrandIconPreview={true}
|
|
1143
|
+
/>
|
|
1144
|
+
);
|
|
1145
|
+
expect(wrapper.find(NotificationExpandedContent).prop('shouldShowBrandIconInExpandedMac')).toBe(true);
|
|
1146
|
+
});
|
|
1147
|
+
|
|
1148
|
+
it('is false for macOS + Safari (Safari is NOT in BRAND_ICON_SUPPORTED_BROWSERS)', () => {
|
|
1149
|
+
const wrapper = mountWithIntl(
|
|
1150
|
+
<NotificationContainer
|
|
1151
|
+
{...defaultProps}
|
|
1152
|
+
selectedOS={OS_MACOS}
|
|
1153
|
+
selectedBrowser={BROWSER_SAFARI}
|
|
1154
|
+
notificationState={NOTIFICATION_STATE_EXPANDED}
|
|
1155
|
+
brandIcon="brand.png"
|
|
1156
|
+
enableBrandIconPreview={true}
|
|
1157
|
+
/>
|
|
1158
|
+
);
|
|
1159
|
+
expect(wrapper.find(NotificationExpandedContent).prop('shouldShowBrandIconInExpandedMac')).toBe(false);
|
|
1160
|
+
});
|
|
1161
|
+
|
|
1162
|
+
it('is false for Windows + Chrome (not macOS) — renders WindowsChromeExpanded instead', () => {
|
|
1163
|
+
const wrapper = mountWithIntl(
|
|
1164
|
+
<NotificationContainer
|
|
1165
|
+
{...defaultProps}
|
|
1166
|
+
selectedOS={OS_WINDOWS}
|
|
1167
|
+
selectedBrowser={BROWSER_CHROME}
|
|
1168
|
+
notificationState={NOTIFICATION_STATE_EXPANDED}
|
|
1169
|
+
brandIcon="brand.png"
|
|
1170
|
+
enableBrandIconPreview={true}
|
|
1171
|
+
/>
|
|
1172
|
+
);
|
|
1173
|
+
expect(wrapper.find(NotificationExpandedContent).exists()).toBe(false);
|
|
1174
|
+
expect(wrapper.find(WindowsChromeExpanded).exists()).toBe(true);
|
|
1175
|
+
});
|
|
1176
|
+
|
|
1177
|
+
it('is false for macOS + Chrome when brandIcon is empty', () => {
|
|
1178
|
+
const wrapper = mountWithIntl(
|
|
1179
|
+
<NotificationContainer
|
|
1180
|
+
{...defaultProps}
|
|
1181
|
+
selectedOS={OS_MACOS}
|
|
1182
|
+
selectedBrowser={BROWSER_CHROME}
|
|
1183
|
+
notificationState={NOTIFICATION_STATE_EXPANDED}
|
|
1184
|
+
brandIcon=""
|
|
1185
|
+
enableBrandIconPreview={true}
|
|
1186
|
+
/>
|
|
1187
|
+
);
|
|
1188
|
+
expect(wrapper.find(NotificationExpandedContent).prop('shouldShowBrandIconInExpandedMac')).toBe(false);
|
|
1189
|
+
});
|
|
1190
|
+
});
|
|
1191
|
+
|
|
1192
|
+
describe('shouldRenderSeparateIOSCTAs behavior', () => {
|
|
1193
|
+
const iosCollapsedWithCTAs = {
|
|
1194
|
+
...defaultProps,
|
|
1195
|
+
selectedOS: OS_IOS,
|
|
1196
|
+
selectedBrowser: BROWSER_CHROME,
|
|
1197
|
+
notificationState: NOTIFICATION_STATE_COLLAPSED,
|
|
1198
|
+
showSeparateIOSCTAs: true,
|
|
1199
|
+
enableCtas: true,
|
|
1200
|
+
buttons: [{ text: 'Accept' }, { text: 'Dismiss' }],
|
|
1201
|
+
};
|
|
1202
|
+
|
|
1203
|
+
it('renders ios-notification-wrapper when all conditions are satisfied', () => {
|
|
1204
|
+
const wrapper = mountWithIntl(<NotificationContainer {...iosCollapsedWithCTAs} />);
|
|
1205
|
+
expect(wrapper.find('.ios-notification-wrapper').exists()).toBe(true);
|
|
1206
|
+
});
|
|
1207
|
+
|
|
1208
|
+
it('renders ios-cta-container inside the wrapper', () => {
|
|
1209
|
+
const wrapper = mountWithIntl(<NotificationContainer {...iosCollapsedWithCTAs} />);
|
|
1210
|
+
expect(wrapper.find('.ios-cta-container').exists()).toBe(true);
|
|
1211
|
+
});
|
|
1212
|
+
|
|
1213
|
+
it('renders one ios-cta-button per button', () => {
|
|
1214
|
+
const wrapper = mountWithIntl(<NotificationContainer {...iosCollapsedWithCTAs} />);
|
|
1215
|
+
expect(wrapper.find('.ios-cta-button').length).toBe(2);
|
|
1216
|
+
});
|
|
1217
|
+
|
|
1218
|
+
it('renders the correct button label text', () => {
|
|
1219
|
+
const wrapper = mountWithIntl(
|
|
1220
|
+
<NotificationContainer
|
|
1221
|
+
{...iosCollapsedWithCTAs}
|
|
1222
|
+
buttons={[{ text: 'Confirm' }]}
|
|
1223
|
+
/>
|
|
1224
|
+
);
|
|
1225
|
+
expect(wrapper.find('.ios-cta-button').first().text()).toBe('Confirm');
|
|
1226
|
+
});
|
|
1227
|
+
|
|
1228
|
+
it('still renders the notification-container inside the wrapper', () => {
|
|
1229
|
+
const wrapper = mountWithIntl(<NotificationContainer {...iosCollapsedWithCTAs} />);
|
|
1230
|
+
const iosWrapper = wrapper.find('.ios-notification-wrapper');
|
|
1231
|
+
expect(iosWrapper.find('.notification-container').exists()).toBe(true);
|
|
1232
|
+
});
|
|
1233
|
+
|
|
1234
|
+
it('does NOT render ios-notification-wrapper when showSeparateIOSCTAs is false', () => {
|
|
1235
|
+
const wrapper = mountWithIntl(
|
|
1236
|
+
<NotificationContainer {...iosCollapsedWithCTAs} showSeparateIOSCTAs={false} />
|
|
1237
|
+
);
|
|
1238
|
+
expect(wrapper.find('.ios-notification-wrapper').exists()).toBe(false);
|
|
1239
|
+
});
|
|
1240
|
+
|
|
1241
|
+
it('does NOT render ios-notification-wrapper when expanded (isExpanded is true)', () => {
|
|
1242
|
+
const wrapper = mountWithIntl(
|
|
1243
|
+
<NotificationContainer
|
|
1244
|
+
{...iosCollapsedWithCTAs}
|
|
1245
|
+
notificationState={NOTIFICATION_STATE_EXPANDED}
|
|
1246
|
+
supportsExpanded={true}
|
|
1247
|
+
/>
|
|
1248
|
+
);
|
|
1249
|
+
expect(wrapper.find('.ios-notification-wrapper').exists()).toBe(false);
|
|
1250
|
+
});
|
|
1251
|
+
|
|
1252
|
+
it('does NOT render ios-notification-wrapper when enableCtas is false', () => {
|
|
1253
|
+
const wrapper = mountWithIntl(
|
|
1254
|
+
<NotificationContainer {...iosCollapsedWithCTAs} enableCtas={false} />
|
|
1255
|
+
);
|
|
1256
|
+
expect(wrapper.find('.ios-notification-wrapper').exists()).toBe(false);
|
|
1257
|
+
});
|
|
1258
|
+
|
|
1259
|
+
it('does NOT render ios-notification-wrapper when buttons array is empty', () => {
|
|
1260
|
+
const wrapper = mountWithIntl(
|
|
1261
|
+
<NotificationContainer {...iosCollapsedWithCTAs} buttons={[]} />
|
|
1262
|
+
);
|
|
1263
|
+
expect(wrapper.find('.ios-notification-wrapper').exists()).toBe(false);
|
|
1264
|
+
});
|
|
1265
|
+
|
|
1266
|
+
it('does NOT render ios-notification-wrapper for iPadOS (not an iOS browser)', () => {
|
|
1267
|
+
const wrapper = mountWithIntl(
|
|
1268
|
+
<NotificationContainer {...iosCollapsedWithCTAs} selectedOS={OS_IPADOS} />
|
|
1269
|
+
);
|
|
1270
|
+
expect(wrapper.find('.ios-notification-wrapper').exists()).toBe(false);
|
|
1271
|
+
});
|
|
1272
|
+
|
|
1273
|
+
it('does NOT render ios-notification-wrapper for macOS', () => {
|
|
1274
|
+
const wrapper = mountWithIntl(
|
|
1275
|
+
<NotificationContainer {...iosCollapsedWithCTAs} selectedOS={OS_MACOS} />
|
|
1276
|
+
);
|
|
1277
|
+
expect(wrapper.find('.ios-notification-wrapper').exists()).toBe(false);
|
|
1278
|
+
});
|
|
1279
|
+
|
|
1280
|
+
it('does NOT render ios-notification-wrapper for Android Mobile', () => {
|
|
1281
|
+
const wrapper = mountWithIntl(
|
|
1282
|
+
<NotificationContainer {...iosCollapsedWithCTAs} selectedOS={OS_ANDROID_MOBILE} />
|
|
1283
|
+
);
|
|
1284
|
+
expect(wrapper.find('.ios-notification-wrapper').exists()).toBe(false);
|
|
1285
|
+
});
|
|
1286
|
+
});
|
|
1287
|
+
|
|
1019
1288
|
describe('Snapshot Tests', () => {
|
|
1020
1289
|
it('should match snapshot for macOS Chrome collapsed', () => {
|
|
1021
1290
|
const wrapper = shallowWithIntl(
|
|
@@ -11,19 +11,34 @@ import { hasPersonalizationTags } from '../../../../utils/commonUtils';
|
|
|
11
11
|
export const validateTemplateName = (value) => !value || value.trim() === '';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Validates notification title
|
|
14
|
+
* Validates notification title (required and optional tag validation)
|
|
15
15
|
* @param {string} value - The title value
|
|
16
16
|
* @param {Function} formatMessage - i18n format message function
|
|
17
17
|
* @param {Object} messages - Message definitions
|
|
18
|
+
* @param {Object} [validationConfig] - Optional config for tag validation
|
|
19
|
+
* @param {boolean} [isFullMode] - Optional; when set with validationConfig, runs tag validation
|
|
18
20
|
* @returns {string} Error message if invalid, empty string if valid
|
|
19
21
|
*/
|
|
20
|
-
export const validateTitle = (value, formatMessage, messages, restrictPersonalization) => {
|
|
22
|
+
export const validateTitle = (value, formatMessage, messages, restrictPersonalization, validationConfig, isFullMode) => {
|
|
21
23
|
if (!value || value.trim() === '') {
|
|
22
24
|
return formatMessage(messages.titleRequired);
|
|
23
25
|
}
|
|
24
26
|
if (restrictPersonalization && hasPersonalizationTags(value)) {
|
|
25
27
|
return formatMessage(messages.personalizationTokensErrorMessage);
|
|
26
28
|
}
|
|
29
|
+
|
|
30
|
+
if (validationConfig != null) {
|
|
31
|
+
const validationResponse = validateTags({
|
|
32
|
+
content: value,
|
|
33
|
+
...validationConfig,
|
|
34
|
+
isFullMode,
|
|
35
|
+
}) || {};
|
|
36
|
+
|
|
37
|
+
if (validationResponse?.isBraceError) {
|
|
38
|
+
return formatMessage(globalMessages.unbalanacedCurlyBraces);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
27
42
|
return '';
|
|
28
43
|
};
|
|
29
44
|
|
|
@@ -183,10 +183,8 @@ describe('validation', () => {
|
|
|
183
183
|
describe('validateMessageContent', () => {
|
|
184
184
|
const mockValidationConfig = {
|
|
185
185
|
tagsParam: [],
|
|
186
|
-
injectedTagsParams: [],
|
|
187
186
|
location: {},
|
|
188
187
|
tagModule: '',
|
|
189
|
-
eventContextTags: [],
|
|
190
188
|
};
|
|
191
189
|
|
|
192
190
|
beforeEach(() => {
|
|
@@ -225,17 +223,6 @@ describe('validation', () => {
|
|
|
225
223
|
});
|
|
226
224
|
});
|
|
227
225
|
|
|
228
|
-
it('should return error message for unsupported tags', () => {
|
|
229
|
-
validateTags.mockReturnValue({
|
|
230
|
-
unsupportedTags: ['tag1', 'tag2'],
|
|
231
|
-
});
|
|
232
|
-
const result = validateMessageContent('Message with {tag1} and {tag2}', mockFormatMessage, mockMessages, mockValidationConfig);
|
|
233
|
-
expect(result).toBe('Unsupported tags: tag1, tag2');
|
|
234
|
-
expect(mockFormatMessage).toHaveBeenCalledWith(globalMessages.unsupportedTagsValidationError, {
|
|
235
|
-
unsupportedTags: 'tag1, tag2',
|
|
236
|
-
});
|
|
237
|
-
});
|
|
238
|
-
|
|
239
226
|
it('should return error message for unbalanced curly braces', () => {
|
|
240
227
|
validateTags.mockReturnValue({
|
|
241
228
|
isBraceError: true,
|
|
@@ -245,22 +232,11 @@ describe('validation', () => {
|
|
|
245
232
|
expect(mockFormatMessage).toHaveBeenCalledWith(globalMessages.unbalanacedCurlyBraces);
|
|
246
233
|
});
|
|
247
234
|
|
|
248
|
-
it('should return error message for both unsupported tags and brace error (unsupported tags takes precedence)', () => {
|
|
249
|
-
validateTags.mockReturnValue({
|
|
250
|
-
unsupportedTags: ['tag1'],
|
|
251
|
-
isBraceError: true,
|
|
252
|
-
});
|
|
253
|
-
const result = validateMessageContent('Message with {tag1}', mockFormatMessage, mockMessages, mockValidationConfig);
|
|
254
|
-
expect(result).toBe('Unsupported tags: tag1');
|
|
255
|
-
});
|
|
256
|
-
|
|
257
235
|
it('should pass validation config to validateTags', () => {
|
|
258
236
|
const customConfig = {
|
|
259
237
|
tagsParam: [{ id: 1, name: 'Tag1' }],
|
|
260
|
-
injectedTagsParams: [{ id: 2, name: 'Tag2' }],
|
|
261
238
|
location: { query: { type: 'test' } },
|
|
262
239
|
tagModule: 'custom',
|
|
263
|
-
eventContextTags: [{ id: 3, name: 'Tag3' }],
|
|
264
240
|
};
|
|
265
241
|
validateTags.mockReturnValue({});
|
|
266
242
|
validateMessageContent('Valid message', mockFormatMessage, mockMessages, customConfig);
|
|
@@ -637,22 +637,21 @@ export const Whatsapp = (props) => {
|
|
|
637
637
|
validateTags({
|
|
638
638
|
content: contentData.join(""),
|
|
639
639
|
tagsParam: tags,
|
|
640
|
-
injectedTagsParams: injectedTags,
|
|
641
640
|
location,
|
|
642
641
|
tagModule: getDefaultTags,
|
|
643
|
-
eventContextTags,
|
|
644
642
|
isFullMode,
|
|
645
643
|
}) || {};
|
|
646
|
-
const unsupportedTagsLengthCheck =
|
|
647
|
-
validationResponse?.unsupportedTags?.length > 0;
|
|
648
644
|
if (type === HEADER_TEXT) {
|
|
649
645
|
headerTagValidationResponse = validationResponse;
|
|
650
|
-
updateIsHeaderTagValidationError(
|
|
646
|
+
updateIsHeaderTagValidationError(validationResponse.isBraceError);
|
|
651
647
|
} else if (type === CAROUSEL_TEXT) {
|
|
652
|
-
return [
|
|
648
|
+
return [
|
|
649
|
+
{ fieldName: "carouselTagValidationErrMessage", value: validationResponse.isBraceError ? validationResponse : {} },
|
|
650
|
+
{ fieldName: "carouselTagValidationErr", value: validationResponse.isBraceError },
|
|
651
|
+
];
|
|
653
652
|
} else {
|
|
654
653
|
tagValidationResponse = validationResponse;
|
|
655
|
-
updateIsTagValidationError(
|
|
654
|
+
updateIsTagValidationError(validationResponse.isBraceError);
|
|
656
655
|
}
|
|
657
656
|
}
|
|
658
657
|
};
|
|
@@ -2682,18 +2681,11 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
|
|
|
2682
2681
|
} else {
|
|
2683
2682
|
validationResponse = tagValidationResponse;
|
|
2684
2683
|
}
|
|
2685
|
-
const {
|
|
2686
|
-
|
|
2687
|
-
let tagError = "";
|
|
2688
|
-
if (unsupportedTags.length > 0) {
|
|
2689
|
-
tagError = formatMessage(globalMessages.unsupportedTagsValidationError, {
|
|
2690
|
-
unsupportedTags,
|
|
2691
|
-
});
|
|
2692
|
-
}
|
|
2684
|
+
const { isBraceError } = validationResponse || {};
|
|
2693
2685
|
if (isBraceError) {
|
|
2694
|
-
|
|
2686
|
+
return <CapError>{formatMessage(globalMessages.unbalanacedCurlyBraces)}</CapError>;
|
|
2695
2687
|
}
|
|
2696
|
-
return
|
|
2688
|
+
return null;
|
|
2697
2689
|
};
|
|
2698
2690
|
|
|
2699
2691
|
const editModeContent = () => (
|
|
@@ -270,23 +270,15 @@ export const Zalo = (props) => {
|
|
|
270
270
|
validateTags({
|
|
271
271
|
content: message,
|
|
272
272
|
tagsParam: tags,
|
|
273
|
-
injectedTagsParams: injectedTags,
|
|
274
273
|
location,
|
|
275
274
|
tagModule: getDefaultTags,
|
|
276
|
-
eventContextTags,
|
|
277
275
|
isFullMode,
|
|
278
276
|
}) || {};
|
|
279
|
-
const {
|
|
280
|
-
let tagError = '';
|
|
281
|
-
if (unsupportedTags.length > 0) {
|
|
282
|
-
tagError = formatMessage(globalMessages.unsupportedTagsValidationError, {
|
|
283
|
-
unsupportedTags,
|
|
284
|
-
});
|
|
285
|
-
}
|
|
277
|
+
const { isBraceError } = tagValidationResponse;
|
|
286
278
|
if (isBraceError) {
|
|
287
|
-
|
|
279
|
+
return formatMessage(globalMessages.unbalanacedCurlyBraces);
|
|
288
280
|
}
|
|
289
|
-
return
|
|
281
|
+
return '';
|
|
290
282
|
};
|
|
291
283
|
|
|
292
284
|
//this function is used for checking errror validation in this it validate tags error and length error
|