@capillarytech/creatives-library 8.0.242-alpha.10 → 8.0.242-alpha.11
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/assets/Android.png +0 -0
- package/assets/iOS.png +0 -0
- package/config/app.js +1 -1
- package/constants/unified.js +2 -2
- package/initialReducer.js +0 -2
- package/package.json +1 -1
- package/services/api.js +5 -10
- package/services/tests/api.test.js +0 -18
- package/translations/en.json +4 -3
- package/utils/common.js +6 -5
- package/utils/commonUtils.js +1 -14
- package/utils/imageUrlUpload.js +141 -0
- package/utils/tests/commonUtil.test.js +0 -224
- package/utils/transformTemplateConfig.js +10 -0
- package/v2Components/CapDeviceContent/index.js +56 -61
- package/v2Components/CapImageUpload/constants.js +2 -0
- package/v2Components/CapImageUpload/index.js +65 -16
- package/v2Components/CapImageUpload/index.scss +4 -1
- package/v2Components/CapImageUpload/messages.js +5 -1
- package/v2Components/CapImageUrlUpload/constants.js +26 -0
- package/v2Components/CapImageUrlUpload/index.js +365 -0
- package/v2Components/CapImageUrlUpload/index.scss +35 -0
- package/v2Components/CapImageUrlUpload/messages.js +47 -0
- package/v2Components/CapTagList/index.js +1 -6
- package/v2Components/CapTagListWithInput/index.js +1 -5
- package/v2Components/CapTagListWithInput/messages.js +1 -1
- package/v2Components/CapWhatsappCTA/tests/index.test.js +0 -5
- package/v2Components/ErrorInfoNote/index.js +72 -412
- package/v2Components/ErrorInfoNote/messages.js +0 -22
- package/v2Components/ErrorInfoNote/style.scss +2 -279
- package/v2Components/HtmlEditor/HTMLEditor.js +91 -220
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +133 -1132
- package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +12 -17
- package/v2Components/HtmlEditor/_htmlEditor.scss +45 -107
- package/v2Components/HtmlEditor/_index.lazy.scss +1 -1
- package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +101 -13
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +139 -148
- package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +1 -2
- package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
- package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +0 -9
- package/v2Components/HtmlEditor/components/EditorToolbar/index.js +1 -1
- package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +0 -22
- package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +7 -4
- package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +45 -35
- package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +3 -1
- package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
- package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +6 -7
- package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +6 -3
- package/v2Components/HtmlEditor/components/PreviewPane/index.js +11 -10
- package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +72 -70
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +31 -49
- package/v2Components/HtmlEditor/constants.js +20 -29
- package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +16 -373
- package/v2Components/HtmlEditor/hooks/useEditorContent.js +2 -5
- package/v2Components/HtmlEditor/hooks/useInAppContent.js +146 -88
- package/v2Components/HtmlEditor/index.js +1 -1
- package/v2Components/HtmlEditor/messages.js +85 -95
- package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +101 -99
- package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +25 -23
- package/v2Components/HtmlEditor/utils/validationAdapter.js +41 -34
- package/v2Components/MobilePushPreviewV2/index.js +7 -32
- package/v2Components/TemplatePreview/_templatePreview.scss +24 -44
- package/v2Components/TemplatePreview/index.js +32 -47
- package/v2Components/TemplatePreview/messages.js +0 -4
- package/v2Components/TestAndPreviewSlidebox/index.js +25 -31
- package/v2Containers/App/constants.js +5 -0
- package/v2Containers/BeeEditor/index.js +80 -82
- package/v2Containers/Cap/tests/__snapshots__/index.test.js.snap +4 -3
- package/v2Containers/CreativesContainer/SlideBoxContent.js +118 -148
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +3 -9
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +2 -2
- package/v2Containers/CreativesContainer/constants.js +2 -1
- package/v2Containers/CreativesContainer/index.js +41 -173
- package/v2Containers/CreativesContainer/messages.js +4 -4
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +210 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +354 -38
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +0 -36
- package/v2Containers/Email/actions.js +0 -7
- package/v2Containers/Email/constants.js +1 -5
- package/v2Containers/Email/index.js +0 -13
- package/v2Containers/Email/messages.js +0 -32
- package/v2Containers/Email/reducer.js +1 -12
- package/v2Containers/Email/sagas.js +6 -41
- package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +0 -2
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +7 -193
- package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +74 -40
- package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +67 -2
- package/v2Containers/EmailWrapper/constants.js +0 -2
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +67 -436
- package/v2Containers/EmailWrapper/index.js +23 -99
- package/v2Containers/EmailWrapper/messages.js +1 -61
- package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +214 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +77 -111
- package/v2Containers/InApp/actions.js +0 -7
- package/v2Containers/InApp/constants.js +4 -20
- package/v2Containers/InApp/index.js +357 -801
- package/v2Containers/InApp/index.scss +3 -4
- package/v2Containers/InApp/messages.js +3 -7
- package/v2Containers/InApp/reducer.js +3 -21
- package/v2Containers/InApp/sagas.js +9 -29
- package/v2Containers/InApp/selectors.js +5 -25
- package/v2Containers/InApp/tests/index.test.js +50 -154
- package/v2Containers/InApp/tests/reducer.test.js +0 -34
- package/v2Containers/InApp/tests/sagas.test.js +9 -61
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +12 -12
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +8 -8
- package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +100 -77
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +72 -63
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +184 -150
- package/v2Containers/SmsTrai/Create/tests/__snapshots__/index.test.js.snap +16 -12
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +32 -28
- package/v2Containers/TagList/index.js +1 -67
- package/v2Containers/Templates/ChannelTypeIllustration.js +13 -1
- package/v2Containers/Templates/_templates.scss +202 -56
- package/v2Containers/Templates/actions.js +2 -1
- package/v2Containers/Templates/constants.js +1 -0
- package/v2Containers/Templates/index.js +278 -128
- package/v2Containers/Templates/messages.js +24 -4
- package/v2Containers/Templates/reducer.js +2 -0
- package/v2Containers/Templates/tests/index.test.js +10 -0
- package/v2Containers/TemplatesV2/index.js +8 -1
- package/v2Containers/TemplatesV2/messages.js +4 -0
- package/v2Containers/WebPush/Create/components/BrandIconSection.js +108 -0
- package/v2Containers/WebPush/Create/components/ButtonForm.js +172 -0
- package/v2Containers/WebPush/Create/components/ButtonItem.js +101 -0
- package/v2Containers/WebPush/Create/components/ButtonList.js +145 -0
- package/v2Containers/WebPush/Create/components/ButtonsLinksSection.js +164 -0
- package/v2Containers/WebPush/Create/components/ButtonsLinksSection.test.js +463 -0
- package/v2Containers/WebPush/Create/components/FormActions.js +54 -0
- package/v2Containers/WebPush/Create/components/FormActions.test.js +163 -0
- package/v2Containers/WebPush/Create/components/MediaSection.js +142 -0
- package/v2Containers/WebPush/Create/components/MediaSection.test.js +341 -0
- package/v2Containers/WebPush/Create/components/MessageSection.js +103 -0
- package/v2Containers/WebPush/Create/components/MessageSection.test.js +268 -0
- package/v2Containers/WebPush/Create/components/NotificationTitleSection.js +87 -0
- package/v2Containers/WebPush/Create/components/NotificationTitleSection.test.js +210 -0
- package/v2Containers/WebPush/Create/components/TemplateNameSection.js +54 -0
- package/v2Containers/WebPush/Create/components/TemplateNameSection.test.js +143 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/ButtonsLinksSection.test.js.snap +86 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/FormActions.test.js.snap +16 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/MediaSection.test.js.snap +41 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/MessageSection.test.js.snap +54 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/NotificationTitleSection.test.js.snap +37 -0
- package/v2Containers/WebPush/Create/components/__snapshots__/TemplateNameSection.test.js.snap +21 -0
- package/v2Containers/WebPush/Create/components/_buttons.scss +246 -0
- package/v2Containers/WebPush/Create/components/tests/ButtonForm.test.js +554 -0
- package/v2Containers/WebPush/Create/components/tests/ButtonItem.test.js +607 -0
- package/v2Containers/WebPush/Create/components/tests/ButtonList.test.js +633 -0
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonForm.test.js.snap +666 -0
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonItem.test.js.snap +74 -0
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonList.test.js.snap +78 -0
- package/v2Containers/WebPush/Create/hooks/useButtonManagement.js +138 -0
- package/v2Containers/WebPush/Create/hooks/useButtonManagement.test.js +406 -0
- package/v2Containers/WebPush/Create/hooks/useCharacterCount.js +30 -0
- package/v2Containers/WebPush/Create/hooks/useCharacterCount.test.js +151 -0
- package/v2Containers/WebPush/Create/hooks/useImageUpload.js +104 -0
- package/v2Containers/WebPush/Create/hooks/useImageUpload.test.js +538 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.js +122 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +633 -0
- package/v2Containers/WebPush/Create/index.js +1056 -0
- package/v2Containers/WebPush/Create/index.scss +134 -0
- package/v2Containers/WebPush/Create/messages.js +203 -0
- package/v2Containers/WebPush/Create/preview/DevicePreviewContent.js +228 -0
- package/v2Containers/WebPush/Create/preview/NotificationContainer.js +294 -0
- package/v2Containers/WebPush/Create/preview/PreviewContent.js +90 -0
- package/v2Containers/WebPush/Create/preview/PreviewControls.js +305 -0
- package/v2Containers/WebPush/Create/preview/PreviewDisclaimer.js +23 -0
- package/v2Containers/WebPush/Create/preview/WebPushPreview.js +150 -0
- package/v2Containers/WebPush/Create/preview/assets/Light.svg +53 -0
- package/v2Containers/WebPush/Create/preview/assets/Top.svg +5 -0
- package/v2Containers/WebPush/Create/preview/assets/android-arrow-down.svg +9 -0
- package/v2Containers/WebPush/Create/preview/assets/android-arrow-up.svg +9 -0
- package/v2Containers/WebPush/Create/preview/assets/chrome-icon.png +0 -0
- package/v2Containers/WebPush/Create/preview/assets/edge-icon.png +0 -0
- package/v2Containers/WebPush/Create/preview/assets/firefox-icon.svg +106 -0
- package/v2Containers/WebPush/Create/preview/assets/iOS.svg +26 -0
- package/v2Containers/WebPush/Create/preview/assets/macos-arrow-down-icon.svg +9 -0
- package/v2Containers/WebPush/Create/preview/assets/macos-triple-dot-icon.svg +9 -0
- package/v2Containers/WebPush/Create/preview/assets/opera-icon.svg +18 -0
- package/v2Containers/WebPush/Create/preview/assets/safari-icon.svg +29 -0
- package/v2Containers/WebPush/Create/preview/assets/windows-close-icon.svg +9 -0
- package/v2Containers/WebPush/Create/preview/assets/windows-triple-dot-icon.svg +9 -0
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileChromeHeader.js +47 -0
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +141 -0
- package/v2Containers/WebPush/Create/preview/components/IOSHeader.js +45 -0
- package/v2Containers/WebPush/Create/preview/components/NotificationExpandedContent.js +68 -0
- package/v2Containers/WebPush/Create/preview/components/NotificationHeader.js +61 -0
- package/v2Containers/WebPush/Create/preview/components/WindowsChromeExpanded.js +99 -0
- package/v2Containers/WebPush/Create/preview/components/tests/AndroidMobileExpanded.test.js +733 -0
- package/v2Containers/WebPush/Create/preview/components/tests/WindowsChromeExpanded.test.js +571 -0
- package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/AndroidMobileExpanded.test.js.snap +81 -0
- package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/WindowsChromeExpanded.test.js.snap +81 -0
- package/v2Containers/WebPush/Create/preview/config/notificationMappings.js +50 -0
- package/v2Containers/WebPush/Create/preview/constants.js +637 -0
- package/v2Containers/WebPush/Create/preview/notification-container.scss +79 -0
- package/v2Containers/WebPush/Create/preview/preview.scss +351 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-chrome.scss +370 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-edge.scss +12 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-firefox.scss +12 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-opera.scss +12 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-chrome.scss +47 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-edge.scss +11 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-firefox.scss +11 -0
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-opera.scss +11 -0
- package/v2Containers/WebPush/Create/preview/styles/_base.scss +207 -0
- package/v2Containers/WebPush/Create/preview/styles/_ios.scss +153 -0
- package/v2Containers/WebPush/Create/preview/styles/_ipados.scss +107 -0
- package/v2Containers/WebPush/Create/preview/styles/_macos-chrome.scss +101 -0
- package/v2Containers/WebPush/Create/preview/styles/_windows-chrome.scss +229 -0
- package/v2Containers/WebPush/Create/preview/tests/DevicePreviewContent.test.js +909 -0
- package/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +1081 -0
- package/v2Containers/WebPush/Create/preview/tests/PreviewControls.test.js +723 -0
- package/v2Containers/WebPush/Create/preview/tests/WebPushPreview.test.js +943 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/DevicePreviewContent.test.js.snap +131 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/NotificationContainer.test.js.snap +112 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/PreviewControls.test.js.snap +144 -0
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/WebPushPreview.test.js.snap +129 -0
- package/v2Containers/WebPush/Create/utils/payloadBuilder.js +94 -0
- package/v2Containers/WebPush/Create/utils/payloadBuilder.test.js +390 -0
- package/v2Containers/WebPush/Create/utils/previewUtils.js +89 -0
- package/v2Containers/WebPush/Create/utils/urlValidation.js +115 -0
- package/v2Containers/WebPush/Create/utils/urlValidation.test.js +449 -0
- package/v2Containers/WebPush/Create/utils/validation.js +75 -0
- package/v2Containers/WebPush/Create/utils/validation.test.js +283 -0
- package/v2Containers/WebPush/actions.js +60 -0
- package/v2Containers/WebPush/constants.js +128 -0
- package/v2Containers/WebPush/index.js +2 -0
- package/v2Containers/WebPush/reducer.js +104 -0
- package/v2Containers/WebPush/sagas.js +119 -0
- package/v2Containers/WebPush/selectors.js +65 -0
- package/v2Containers/WebPush/tests/reducer.test.js +863 -0
- package/v2Containers/WebPush/tests/sagas.test.js +566 -0
- package/v2Containers/WebPush/tests/selectors.test.js +843 -0
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +528 -431
- package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +0 -254
- package/v2Components/HtmlEditor/components/ValidationTabs/index.js +0 -362
- package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +0 -51
- package/v2Containers/BeePopupEditor/constants.js +0 -10
- package/v2Containers/BeePopupEditor/index.js +0 -193
- package/v2Containers/BeePopupEditor/tests/index.test.js +0 -627
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +0 -1046
- package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +0 -376
- package/v2Containers/InApp/__tests__/sagas.test.js +0 -363
- package/v2Containers/InApp/tests/selectors.test.js +0 -612
- package/v2Containers/InAppWrapper/components/InAppWrapperView.js +0 -162
- package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +0 -267
- package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +0 -9
- package/v2Containers/InAppWrapper/constants.js +0 -16
- package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +0 -473
- package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +0 -198
- package/v2Containers/InAppWrapper/index.js +0 -148
- package/v2Containers/InAppWrapper/messages.js +0 -49
- package/v2Containers/InappAdvance/index.js +0 -1099
- package/v2Containers/InappAdvance/index.scss +0 -10
- package/v2Containers/InappAdvance/tests/index.test.js +0 -448
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import {
|
|
2
|
+
validateTemplateName,
|
|
3
|
+
validateTitle,
|
|
4
|
+
validateUrl,
|
|
5
|
+
validateMessageContent,
|
|
6
|
+
} from './validation';
|
|
7
|
+
import { isValidHttpUrl } from './urlValidation';
|
|
8
|
+
|
|
9
|
+
// Mock the urlValidation module
|
|
10
|
+
jest.mock('./urlValidation', () => ({
|
|
11
|
+
isValidHttpUrl: jest.fn(),
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
// Mock the tagValidations module
|
|
15
|
+
jest.mock('../../../../utils/tagValidations', () => ({
|
|
16
|
+
validateTags: jest.fn(),
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
// Mock the globalMessages
|
|
20
|
+
jest.mock('../../../Cap/messages', () => ({
|
|
21
|
+
unsupportedTagsValidationError: {
|
|
22
|
+
defaultMessage: 'Unsupported tags: {unsupportedTags}',
|
|
23
|
+
},
|
|
24
|
+
unbalanacedCurlyBraces: {
|
|
25
|
+
defaultMessage: 'Unbalanced curly braces',
|
|
26
|
+
},
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
import { validateTags } from '../../../../utils/tagValidations';
|
|
30
|
+
import globalMessages from '../../../Cap/messages';
|
|
31
|
+
|
|
32
|
+
describe('validation', () => {
|
|
33
|
+
let mockFormatMessage;
|
|
34
|
+
const mockMessages = {
|
|
35
|
+
titleRequired: {
|
|
36
|
+
defaultMessage: 'Title is required',
|
|
37
|
+
},
|
|
38
|
+
urlRequired: {
|
|
39
|
+
defaultMessage: 'URL is required',
|
|
40
|
+
},
|
|
41
|
+
urlInvalid: {
|
|
42
|
+
defaultMessage: 'URL is invalid',
|
|
43
|
+
},
|
|
44
|
+
messageRequired: {
|
|
45
|
+
defaultMessage: 'Message is required',
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
beforeEach(() => {
|
|
50
|
+
jest.clearAllMocks();
|
|
51
|
+
mockFormatMessage = jest.fn((message, values) => {
|
|
52
|
+
if (values) {
|
|
53
|
+
return message.defaultMessage.replace('{unsupportedTags}', values.unsupportedTags);
|
|
54
|
+
}
|
|
55
|
+
return message.defaultMessage || message;
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('validateTemplateName', () => {
|
|
60
|
+
it('should return true for empty string', () => {
|
|
61
|
+
expect(validateTemplateName('')).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should return true for whitespace-only string', () => {
|
|
65
|
+
expect(validateTemplateName(' ')).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should return true for null', () => {
|
|
69
|
+
expect(validateTemplateName(null)).toBe(true);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should return true for undefined', () => {
|
|
73
|
+
expect(validateTemplateName(undefined)).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should return false for valid template name', () => {
|
|
77
|
+
expect(validateTemplateName('Valid Template Name')).toBe(false);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should return false for template name with leading/trailing spaces that has content', () => {
|
|
81
|
+
expect(validateTemplateName(' Valid Template ')).toBe(false);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('validateTitle', () => {
|
|
86
|
+
it('should return error message for empty string', () => {
|
|
87
|
+
const result = validateTitle('', mockFormatMessage, mockMessages);
|
|
88
|
+
expect(result).toBe('Title is required');
|
|
89
|
+
expect(mockFormatMessage).toHaveBeenCalledWith(mockMessages.titleRequired);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should return error message for whitespace-only string', () => {
|
|
93
|
+
const result = validateTitle(' ', mockFormatMessage, mockMessages);
|
|
94
|
+
expect(result).toBe('Title is required');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should return error message for null', () => {
|
|
98
|
+
const result = validateTitle(null, mockFormatMessage, mockMessages);
|
|
99
|
+
expect(result).toBe('Title is required');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should return error message for undefined', () => {
|
|
103
|
+
const result = validateTitle(undefined, mockFormatMessage, mockMessages);
|
|
104
|
+
expect(result).toBe('Title is required');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should return empty string for valid title', () => {
|
|
108
|
+
const result = validateTitle('Valid Title', mockFormatMessage, mockMessages);
|
|
109
|
+
expect(result).toBe('');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should return empty string for title with content after trimming', () => {
|
|
113
|
+
const result = validateTitle(' Valid Title ', mockFormatMessage, mockMessages);
|
|
114
|
+
expect(result).toBe('');
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('validateUrl', () => {
|
|
119
|
+
beforeEach(() => {
|
|
120
|
+
isValidHttpUrl.mockClear();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should return error message for empty string', () => {
|
|
124
|
+
const result = validateUrl('', mockFormatMessage, mockMessages);
|
|
125
|
+
expect(result).toBe('URL is required');
|
|
126
|
+
expect(mockFormatMessage).toHaveBeenCalledWith(mockMessages.urlRequired);
|
|
127
|
+
expect(isValidHttpUrl).not.toHaveBeenCalled();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should return error message for whitespace-only string', () => {
|
|
131
|
+
const result = validateUrl(' ', mockFormatMessage, mockMessages);
|
|
132
|
+
expect(result).toBe('URL is required');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('should return error message for null', () => {
|
|
136
|
+
const result = validateUrl(null, mockFormatMessage, mockMessages);
|
|
137
|
+
expect(result).toBe('URL is required');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should return error message for undefined', () => {
|
|
141
|
+
const result = validateUrl(undefined, mockFormatMessage, mockMessages);
|
|
142
|
+
expect(result).toBe('URL is required');
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should return error message for invalid URL', () => {
|
|
146
|
+
isValidHttpUrl.mockReturnValue(false);
|
|
147
|
+
const result = validateUrl('not-a-url', mockFormatMessage, mockMessages);
|
|
148
|
+
expect(result).toBe('URL is invalid');
|
|
149
|
+
expect(mockFormatMessage).toHaveBeenCalledWith(mockMessages.urlInvalid);
|
|
150
|
+
expect(isValidHttpUrl).toHaveBeenCalledWith('not-a-url');
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should return empty string for valid URL', () => {
|
|
154
|
+
isValidHttpUrl.mockReturnValue(true);
|
|
155
|
+
const result = validateUrl('https://example.com', mockFormatMessage, mockMessages);
|
|
156
|
+
expect(result).toBe('');
|
|
157
|
+
expect(isValidHttpUrl).toHaveBeenCalledWith('https://example.com');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('should pass URL with whitespace to isValidHttpUrl without trimming', () => {
|
|
161
|
+
isValidHttpUrl.mockReturnValue(true);
|
|
162
|
+
const result = validateUrl(' https://example.com ', mockFormatMessage, mockMessages);
|
|
163
|
+
expect(result).toBe('');
|
|
164
|
+
// Contract: validateUrl delegates to isValidHttpUrl with original (untrimmed) value
|
|
165
|
+
expect(isValidHttpUrl).toHaveBeenCalledWith(' https://example.com ');
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe('validateMessageContent', () => {
|
|
170
|
+
const mockValidationConfig = {
|
|
171
|
+
tagsParam: [],
|
|
172
|
+
injectedTagsParams: [],
|
|
173
|
+
location: {},
|
|
174
|
+
tagModule: '',
|
|
175
|
+
eventContextTags: [],
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
beforeEach(() => {
|
|
179
|
+
validateTags.mockClear();
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it('should return error message for empty string', () => {
|
|
183
|
+
const result = validateMessageContent('', mockFormatMessage, mockMessages, mockValidationConfig);
|
|
184
|
+
expect(result).toBe('Message is required');
|
|
185
|
+
expect(mockFormatMessage).toHaveBeenCalledWith(mockMessages.messageRequired);
|
|
186
|
+
expect(validateTags).not.toHaveBeenCalled();
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should return error message for whitespace-only string', () => {
|
|
190
|
+
const result = validateMessageContent(' ', mockFormatMessage, mockMessages, mockValidationConfig);
|
|
191
|
+
expect(result).toBe('Message is required');
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('should return error message for null', () => {
|
|
195
|
+
const result = validateMessageContent(null, mockFormatMessage, mockMessages, mockValidationConfig);
|
|
196
|
+
expect(result).toBe('Message is required');
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('should return error message for undefined', () => {
|
|
200
|
+
const result = validateMessageContent(undefined, mockFormatMessage, mockMessages, mockValidationConfig);
|
|
201
|
+
expect(result).toBe('Message is required');
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should return empty string for valid message without tags', () => {
|
|
205
|
+
validateTags.mockReturnValue({});
|
|
206
|
+
const result = validateMessageContent('Valid message', mockFormatMessage, mockMessages, mockValidationConfig);
|
|
207
|
+
expect(result).toBe('');
|
|
208
|
+
expect(validateTags).toHaveBeenCalledWith({
|
|
209
|
+
content: 'Valid message',
|
|
210
|
+
...mockValidationConfig,
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('should return error message for unsupported tags', () => {
|
|
215
|
+
validateTags.mockReturnValue({
|
|
216
|
+
unsupportedTags: ['tag1', 'tag2'],
|
|
217
|
+
});
|
|
218
|
+
const result = validateMessageContent('Message with {tag1} and {tag2}', mockFormatMessage, mockMessages, mockValidationConfig);
|
|
219
|
+
expect(result).toBe('Unsupported tags: tag1, tag2');
|
|
220
|
+
expect(mockFormatMessage).toHaveBeenCalledWith(globalMessages.unsupportedTagsValidationError, {
|
|
221
|
+
unsupportedTags: 'tag1, tag2',
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should return error message for unbalanced curly braces', () => {
|
|
226
|
+
validateTags.mockReturnValue({
|
|
227
|
+
isBraceError: true,
|
|
228
|
+
});
|
|
229
|
+
const result = validateMessageContent('Message with {unclosed', mockFormatMessage, mockMessages, mockValidationConfig);
|
|
230
|
+
expect(result).toBe('Unbalanced curly braces');
|
|
231
|
+
expect(mockFormatMessage).toHaveBeenCalledWith(globalMessages.unbalanacedCurlyBraces);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('should return error message for both unsupported tags and brace error (unsupported tags takes precedence)', () => {
|
|
235
|
+
validateTags.mockReturnValue({
|
|
236
|
+
unsupportedTags: ['tag1'],
|
|
237
|
+
isBraceError: true,
|
|
238
|
+
});
|
|
239
|
+
const result = validateMessageContent('Message with {tag1}', mockFormatMessage, mockMessages, mockValidationConfig);
|
|
240
|
+
expect(result).toBe('Unsupported tags: tag1');
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it('should pass validation config to validateTags', () => {
|
|
244
|
+
const customConfig = {
|
|
245
|
+
tagsParam: [{ id: 1, name: 'Tag1' }],
|
|
246
|
+
injectedTagsParams: [{ id: 2, name: 'Tag2' }],
|
|
247
|
+
location: { query: { type: 'test' } },
|
|
248
|
+
tagModule: 'custom',
|
|
249
|
+
eventContextTags: [{ id: 3, name: 'Tag3' }],
|
|
250
|
+
};
|
|
251
|
+
validateTags.mockReturnValue({});
|
|
252
|
+
validateMessageContent('Valid message', mockFormatMessage, mockMessages, customConfig);
|
|
253
|
+
expect(validateTags).toHaveBeenCalledWith({
|
|
254
|
+
content: 'Valid message',
|
|
255
|
+
...customConfig,
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('should handle validateTags returning null', () => {
|
|
260
|
+
validateTags.mockReturnValue(null);
|
|
261
|
+
const result = validateMessageContent('Valid message', mockFormatMessage, mockMessages, mockValidationConfig);
|
|
262
|
+
expect(result).toBe('');
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('should handle validateTags returning undefined', () => {
|
|
266
|
+
validateTags.mockReturnValue(undefined);
|
|
267
|
+
const result = validateMessageContent('Valid message', mockFormatMessage, mockMessages, mockValidationConfig);
|
|
268
|
+
expect(result).toBe('');
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('should pass message with whitespace to validateTags without trimming', () => {
|
|
272
|
+
validateTags.mockReturnValue({});
|
|
273
|
+
const result = validateMessageContent(' Valid message ', mockFormatMessage, mockMessages, mockValidationConfig);
|
|
274
|
+
expect(result).toBe('');
|
|
275
|
+
// Contract: validateMessageContent delegates to validateTags with original (untrimmed) value
|
|
276
|
+
expect(validateTags).toHaveBeenCalledWith({
|
|
277
|
+
content: ' Valid message ',
|
|
278
|
+
...mockValidationConfig,
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/*
|
|
2
|
+
*
|
|
3
|
+
* WebPush actions
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as types from './constants';
|
|
8
|
+
|
|
9
|
+
export function createTemplate(template, callback, meta) {
|
|
10
|
+
return {
|
|
11
|
+
type: types.CREATE_TEMPLATE_REQUEST,
|
|
12
|
+
template,
|
|
13
|
+
callback,
|
|
14
|
+
meta,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function clearCreateResponse() {
|
|
19
|
+
return {
|
|
20
|
+
type: types.CLEAR_CREATE_RESPONSE_REQUEST,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function editTemplate(template, callback) {
|
|
25
|
+
return {
|
|
26
|
+
type: types.EDIT_TEMPLATE_REQUEST,
|
|
27
|
+
template,
|
|
28
|
+
callback,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function clearEditResponse() {
|
|
33
|
+
return {
|
|
34
|
+
type: types.CLEAR_EDIT_RESPONSE_REQUEST,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function defaultAction() {
|
|
39
|
+
return {
|
|
40
|
+
type: types.DEFAULT_ACTION,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function uploadWebPushAsset(file, type, fileParams, templateType) {
|
|
45
|
+
return {
|
|
46
|
+
type: types.UPLOAD_WEBPUSH_ASSET_REQUEST,
|
|
47
|
+
file,
|
|
48
|
+
assetType: type,
|
|
49
|
+
fileParams,
|
|
50
|
+
templateType,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function clearWebPushAsset(templateType) {
|
|
55
|
+
return {
|
|
56
|
+
type: types.CLEAR_WEBPUSH_ASSET,
|
|
57
|
+
templateType,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
export const DEFAULT_ACTION = 'app/v2Containers/WebPush/DEFAULT_ACTION';
|
|
2
|
+
|
|
3
|
+
export const CREATE_TEMPLATE_REQUEST = 'app/v2Containers/WebPush/Create/CREATE_TEMPLATE_REQUEST';
|
|
4
|
+
export const CREATE_TEMPLATE_SUCCESS = 'app/v2Containers/WebPush/Create/CREATE_TEMPLATE_SUCCESS';
|
|
5
|
+
export const CREATE_TEMPLATE_FAILURE = 'app/v2Containers/WebPush/Create/CREATE_TEMPLATE_FAILURE';
|
|
6
|
+
|
|
7
|
+
export const CLEAR_CREATE_RESPONSE_REQUEST = 'app/v2Containers/WebPush/Create/CLEAR_CREATE_RESPONSE_REQUEST';
|
|
8
|
+
export const CLEAR_CREATE_RESPONSE_SUCCESS = 'app/v2Containers/WebPush/Create/CLEAR_CREATE_RESPONSE_SUCCESS';
|
|
9
|
+
export const CLEAR_CREATE_RESPONSE_FAILURE = 'app/v2Containers/WebPush/Create/CLEAR_CREATE_RESPONSE_FAILURE';
|
|
10
|
+
|
|
11
|
+
export const EDIT_TEMPLATE_REQUEST = 'app/v2Containers/WebPush/Edit/EDIT_TEMPLATE_REQUEST';
|
|
12
|
+
export const EDIT_TEMPLATE_SUCCESS = 'app/v2Containers/WebPush/Edit/EDIT_TEMPLATE_SUCCESS';
|
|
13
|
+
export const EDIT_TEMPLATE_FAILURE = 'app/v2Containers/WebPush/Edit/EDIT_TEMPLATE_FAILURE';
|
|
14
|
+
|
|
15
|
+
export const CLEAR_EDIT_RESPONSE_REQUEST = 'app/v2Containers/WebPush/Edit/CLEAR_EDIT_RESPONSE_REQUEST';
|
|
16
|
+
export const CLEAR_EDIT_RESPONSE_SUCCESS = 'app/v2Containers/WebPush/Edit/CLEAR_EDIT_RESPONSE_SUCCESS';
|
|
17
|
+
export const CLEAR_EDIT_RESPONSE_FAILURE = 'app/v2Containers/WebPush/Edit/CLEAR_EDIT_RESPONSE_FAILURE';
|
|
18
|
+
|
|
19
|
+
// Media Types
|
|
20
|
+
export const WEBPUSH_MEDIA_TYPES = {
|
|
21
|
+
NONE: "NONE",
|
|
22
|
+
IMAGE: "IMAGE",
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const WEBPUSH_MEDIA_TYPES_OPTIONS = [
|
|
26
|
+
{ label: "None", value: WEBPUSH_MEDIA_TYPES.NONE },
|
|
27
|
+
{ label: "Image", value: WEBPUSH_MEDIA_TYPES.IMAGE },
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
// Image Upload Constants
|
|
31
|
+
export const ALLOWED_IMAGE_EXTENSIONS_REGEX = /\.(jpe?g|png)$/i;
|
|
32
|
+
export const WEBPUSH_IMG_SIZE = 5000000; // 5MB
|
|
33
|
+
|
|
34
|
+
// Note: image width/height validation will be ignored for the web push channel inside CapImageUpload
|
|
35
|
+
export const WEBPUSH_RECOMMENDED_DIMENSIONS = [
|
|
36
|
+
{ width: 1440, height: 720 },
|
|
37
|
+
{ width: 512, height: 256 },
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
// Brand Icon Options
|
|
41
|
+
export const BRAND_ICON_OPTIONS = {
|
|
42
|
+
DONT_SHOW: 'DONT_SHOW',
|
|
43
|
+
UPLOAD_IMAGE: 'UPLOAD_IMAGE',
|
|
44
|
+
ADD_IMAGE_URL: 'ADD_IMAGE_URL',
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Brand Icon Upload Constants
|
|
48
|
+
export const WEBPUSH_BRAND_ICON_SIZE = 1000000; // 1MB
|
|
49
|
+
// Note: image width/height validation will be ignored for the web push channel inside CapImageUpload
|
|
50
|
+
export const WEBPUSH_BRAND_ICON_RECOMMENDED_DIMENSIONS = [
|
|
51
|
+
{ width: 192, height: 192 },
|
|
52
|
+
{ width: 256, height: 256 },
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
// Image Upload Methods
|
|
56
|
+
export const IMAGE_UPLOAD_METHODS = {
|
|
57
|
+
UPLOAD_IMAGE: 'UPLOAD_IMAGE',
|
|
58
|
+
ADD_IMAGE_URL: 'ADD_IMAGE_URL',
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Upload Asset Actions
|
|
62
|
+
const prefix = "app/v2Containers/WebPush";
|
|
63
|
+
export const UPLOAD_WEBPUSH_ASSET_REQUEST = `${prefix}/UPLOAD_WEBPUSH_ASSET_REQUEST`;
|
|
64
|
+
export const UPLOAD_WEBPUSH_ASSET_SUCCESS = `${prefix}/UPLOAD_WEBPUSH_ASSET_SUCCESS`;
|
|
65
|
+
export const UPLOAD_WEBPUSH_ASSET_FAILURE = `${prefix}/UPLOAD_WEBPUSH_ASSET_FAILURE`;
|
|
66
|
+
export const CLEAR_WEBPUSH_ASSET = `${prefix}/CLEAR_WEBPUSH_ASSET`;
|
|
67
|
+
|
|
68
|
+
// Upload Field Identifiers
|
|
69
|
+
export const UPLOAD_FIELD_TYPES = {
|
|
70
|
+
IMAGE: 'image',
|
|
71
|
+
BRAND_ICON: 'brandIcon',
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Button Types
|
|
75
|
+
export const WEBPUSH_BUTTON_TYPES = {
|
|
76
|
+
PRIMARY: 'primary',
|
|
77
|
+
SECONDARY: 'secondary',
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// OnClick Behaviour Options
|
|
81
|
+
export const ON_CLICK_BEHAVIOUR_OPTIONS = {
|
|
82
|
+
OPEN_SITE: 'OPEN_SITE',
|
|
83
|
+
REDIRECT_TO_URL: 'REDIRECT_TO_URL',
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// Action Types
|
|
87
|
+
export const ACTION_TYPES = {
|
|
88
|
+
URL: 'URL',
|
|
89
|
+
OPEN_SITE: 'OPEN_SITE',
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// WebPush Content Field Names
|
|
93
|
+
// Field names used in template data structure (versions.base.content.webpush)
|
|
94
|
+
export const WEBPUSH_CONTENT_FIELDS = {
|
|
95
|
+
TITLE: 'title',
|
|
96
|
+
MESSAGE: 'message',
|
|
97
|
+
IMAGE: 'image',
|
|
98
|
+
BRAND_ICON: 'brandIcon',
|
|
99
|
+
MEDIA_TYPE: 'mediaType',
|
|
100
|
+
ON_CLICK_ACTION: 'onClickAction',
|
|
101
|
+
CTAS: 'ctas',
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// Template Data Path Constants
|
|
105
|
+
export const WEBPUSH_TEMPLATE_PATHS = {
|
|
106
|
+
CONTENT: 'versions.base.content.webpush',
|
|
107
|
+
NAME: 'name',
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// Character Count Configuration
|
|
111
|
+
export const SHOW_CHARACTER_COUNT = true;
|
|
112
|
+
|
|
113
|
+
// Maximum Character Limits for Web Push Fields
|
|
114
|
+
export const NOTIFICATION_TITLE_MAX_LENGTH = 65;
|
|
115
|
+
export const MESSAGE_MAX_LENGTH = 240;
|
|
116
|
+
export const BUTTON_TEXT_MAX_LENGTH = 20;
|
|
117
|
+
|
|
118
|
+
// URL Validation Constants
|
|
119
|
+
export const SUPPORTED_PROTOCOLS = new Set(['http:', 'https:']);
|
|
120
|
+
export const HTTP_URL_PATTERN = /^https?:\/\/.+/i;
|
|
121
|
+
// Pattern to ensure URL has a TLD (Top Level Domain): protocol://domain.tld
|
|
122
|
+
// Requires at least one dot in the domain part, followed by 2+ word characters
|
|
123
|
+
// before path separator (/), query (?), hash (#), port (:), or end of string
|
|
124
|
+
export const TLD_PATTERN = /^https?:\/\/[^/?#:]+\.\w{2,}(?:\/|$|\?|#|:)/i;
|
|
125
|
+
|
|
126
|
+
// Utility Constants
|
|
127
|
+
// Stable empty array to prevent unnecessary re-renders when used as default prop values
|
|
128
|
+
export const EMPTY_ARRAY = [];
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/*
|
|
2
|
+
*
|
|
3
|
+
* WebPush reducer
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { fromJS } from "immutable";
|
|
8
|
+
import * as types from "./constants";
|
|
9
|
+
|
|
10
|
+
const initialState = fromJS({
|
|
11
|
+
createTemplateInProgress: false,
|
|
12
|
+
response: {},
|
|
13
|
+
createTemplateErrorMessage: "",
|
|
14
|
+
editTemplateInProgress: false,
|
|
15
|
+
editResponse: {},
|
|
16
|
+
editTemplateErrorMessage: "",
|
|
17
|
+
uploadedAssetData: {},
|
|
18
|
+
uploadAssetSuccess: false,
|
|
19
|
+
assetUploading: false,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export function webPushReducer(state = initialState, action) {
|
|
23
|
+
// Handle null or undefined action
|
|
24
|
+
if (!action || typeof action !== 'object') {
|
|
25
|
+
return state;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
switch (action.type) {
|
|
29
|
+
case types.DEFAULT_ACTION:
|
|
30
|
+
return state;
|
|
31
|
+
case types.CREATE_TEMPLATE_REQUEST:
|
|
32
|
+
return state
|
|
33
|
+
.set("createTemplateInProgress", true)
|
|
34
|
+
.set("createTemplateError", false)
|
|
35
|
+
.set("createTemplateErrorMessage", fromJS(""));
|
|
36
|
+
case types.CREATE_TEMPLATE_SUCCESS:
|
|
37
|
+
return state
|
|
38
|
+
.set("createTemplateInProgress", false)
|
|
39
|
+
.set("response", action.data)
|
|
40
|
+
.set(
|
|
41
|
+
"createTemplateError",
|
|
42
|
+
action.statusCode !== undefined && action.statusCode > 300
|
|
43
|
+
);
|
|
44
|
+
case types.CREATE_TEMPLATE_FAILURE:
|
|
45
|
+
return state
|
|
46
|
+
.set("createTemplateInProgress", false)
|
|
47
|
+
.set("createTemplateError", true)
|
|
48
|
+
.set("createTemplateErrorMessage", fromJS(action.error));
|
|
49
|
+
case types.CLEAR_CREATE_RESPONSE_REQUEST:
|
|
50
|
+
return state.set("response", {});
|
|
51
|
+
case types.EDIT_TEMPLATE_REQUEST:
|
|
52
|
+
return state
|
|
53
|
+
.set("editTemplateInProgress", true)
|
|
54
|
+
.set("editTemplateError", false)
|
|
55
|
+
.set("editTemplateErrorMessage", fromJS(""));
|
|
56
|
+
case types.EDIT_TEMPLATE_SUCCESS:
|
|
57
|
+
return state
|
|
58
|
+
.set("editTemplateInProgress", false)
|
|
59
|
+
.set("editResponse", action.data)
|
|
60
|
+
.set(
|
|
61
|
+
"editTemplateError",
|
|
62
|
+
action.statusCode !== undefined && action.statusCode > 300
|
|
63
|
+
);
|
|
64
|
+
case types.EDIT_TEMPLATE_FAILURE:
|
|
65
|
+
return state
|
|
66
|
+
.set("editTemplateInProgress", false)
|
|
67
|
+
.set("editTemplateError", true)
|
|
68
|
+
.set("editTemplateErrorMessage", fromJS(action.error || action.errorMsg || ""));
|
|
69
|
+
case types.CLEAR_EDIT_RESPONSE_REQUEST:
|
|
70
|
+
return state.set("editResponse", {});
|
|
71
|
+
case types.UPLOAD_WEBPUSH_ASSET_REQUEST:
|
|
72
|
+
return state.set("uploadAssetSuccess", false).set("assetUploading", true);
|
|
73
|
+
case types.UPLOAD_WEBPUSH_ASSET_SUCCESS:
|
|
74
|
+
return state
|
|
75
|
+
.set(
|
|
76
|
+
"uploadAssetSuccess",
|
|
77
|
+
action.statusCode !== undefined &&
|
|
78
|
+
action.statusCode !== "" &&
|
|
79
|
+
action.statusCode < 300,
|
|
80
|
+
)
|
|
81
|
+
.set("assetUploading", false)
|
|
82
|
+
.set(
|
|
83
|
+
action.templateType !== undefined
|
|
84
|
+
? `uploadedAssetData${action.templateType}`
|
|
85
|
+
: "uploadedAssetData",
|
|
86
|
+
action.data,
|
|
87
|
+
);
|
|
88
|
+
case types.UPLOAD_WEBPUSH_ASSET_FAILURE:
|
|
89
|
+
return state
|
|
90
|
+
.set("uploadAssetSuccess", false)
|
|
91
|
+
.set("assetUploading", false);
|
|
92
|
+
case types.CLEAR_WEBPUSH_ASSET:
|
|
93
|
+
return state.delete(
|
|
94
|
+
action.templateType !== undefined
|
|
95
|
+
? `uploadedAssetData${action.templateType}`
|
|
96
|
+
: "uploadedAssetData",
|
|
97
|
+
);
|
|
98
|
+
default:
|
|
99
|
+
return state;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export default webPushReducer;
|
|
104
|
+
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import {
|
|
2
|
+
call, put, takeLatest, all,
|
|
3
|
+
} from 'redux-saga/effects';
|
|
4
|
+
import * as Api from '../../services/api';
|
|
5
|
+
import * as types from './constants';
|
|
6
|
+
|
|
7
|
+
export function* createTemplate({ template, callback, meta }) {
|
|
8
|
+
let errorMsg;
|
|
9
|
+
try {
|
|
10
|
+
const result = yield call(Api.createWebPushTemplate, template);
|
|
11
|
+
if (result.status && result.status.code >= 400) {
|
|
12
|
+
errorMsg = result.message;
|
|
13
|
+
throw errorMsg;
|
|
14
|
+
}
|
|
15
|
+
if (result.message) {
|
|
16
|
+
errorMsg = result.message;
|
|
17
|
+
}
|
|
18
|
+
// Merge meta into response if provided
|
|
19
|
+
const responseWithMeta = meta ? { ...result.response, meta } : result.response;
|
|
20
|
+
if (callback) {
|
|
21
|
+
yield call(callback, responseWithMeta);
|
|
22
|
+
}
|
|
23
|
+
yield put({
|
|
24
|
+
type: types.CREATE_TEMPLATE_SUCCESS,
|
|
25
|
+
data: responseWithMeta,
|
|
26
|
+
statusCode: result.status ? result.status.code : '',
|
|
27
|
+
errorMsg,
|
|
28
|
+
});
|
|
29
|
+
} catch (error) {
|
|
30
|
+
yield put({ type: types.CREATE_TEMPLATE_FAILURE, error, errorMsg });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function* clearCreateResponse() {
|
|
35
|
+
yield put({ type: types.CLEAR_CREATE_RESPONSE_SUCCESS });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function* editTemplate({ template, callback }) {
|
|
39
|
+
let errorMsg;
|
|
40
|
+
try {
|
|
41
|
+
const result = yield call(Api.createWebPushTemplate, template);
|
|
42
|
+
if (result.status && result.status.code >= 400) {
|
|
43
|
+
errorMsg = result.message;
|
|
44
|
+
throw errorMsg;
|
|
45
|
+
}
|
|
46
|
+
if (result.message) {
|
|
47
|
+
errorMsg = result.message;
|
|
48
|
+
}
|
|
49
|
+
if (callback) {
|
|
50
|
+
callback(result.response, errorMsg);
|
|
51
|
+
}
|
|
52
|
+
yield put({
|
|
53
|
+
type: types.EDIT_TEMPLATE_SUCCESS,
|
|
54
|
+
data: result.response,
|
|
55
|
+
statusCode: result.status ? result.status.code : '',
|
|
56
|
+
errorMsg,
|
|
57
|
+
});
|
|
58
|
+
} catch (error) {
|
|
59
|
+
yield put({ type: types.EDIT_TEMPLATE_FAILURE, error, errorMsg });
|
|
60
|
+
if (callback) {
|
|
61
|
+
callback(null, errorMsg);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function* clearEditResponse() {
|
|
67
|
+
yield put({ type: types.CLEAR_EDIT_RESPONSE_SUCCESS });
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function* uploadWebPushAsset({ file, assetType, fileParams, templateType }) {
|
|
71
|
+
try {
|
|
72
|
+
const result = yield call(Api.uploadFile, {
|
|
73
|
+
file,
|
|
74
|
+
assetType,
|
|
75
|
+
fileParams,
|
|
76
|
+
});
|
|
77
|
+
yield put({
|
|
78
|
+
type: types.UPLOAD_WEBPUSH_ASSET_SUCCESS,
|
|
79
|
+
data: result?.response?.asset,
|
|
80
|
+
statusCode: result?.status?.code || '',
|
|
81
|
+
templateType,
|
|
82
|
+
});
|
|
83
|
+
} catch (error) {
|
|
84
|
+
yield put({ type: types.UPLOAD_WEBPUSH_ASSET_FAILURE, error });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function* watchCreateTemplate() {
|
|
89
|
+
yield takeLatest(types.CREATE_TEMPLATE_REQUEST, createTemplate);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function* watchClearCreateResponse() {
|
|
93
|
+
yield takeLatest(types.CLEAR_CREATE_RESPONSE_REQUEST, clearCreateResponse);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function* watchEditTemplate() {
|
|
97
|
+
yield takeLatest(types.EDIT_TEMPLATE_REQUEST, editTemplate);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function* watchClearEditResponse() {
|
|
101
|
+
yield takeLatest(types.CLEAR_EDIT_RESPONSE_REQUEST, clearEditResponse);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function* watchUploadWebPushAsset() {
|
|
105
|
+
yield takeLatest(
|
|
106
|
+
types.UPLOAD_WEBPUSH_ASSET_REQUEST,
|
|
107
|
+
uploadWebPushAsset,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export default function* webPushSagas() {
|
|
112
|
+
yield all([
|
|
113
|
+
watchCreateTemplate(),
|
|
114
|
+
watchClearCreateResponse(),
|
|
115
|
+
watchEditTemplate(),
|
|
116
|
+
watchClearEditResponse(),
|
|
117
|
+
watchUploadWebPushAsset(),
|
|
118
|
+
]);
|
|
119
|
+
}
|