@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.
Files changed (256) hide show
  1. package/assets/Android.png +0 -0
  2. package/assets/iOS.png +0 -0
  3. package/config/app.js +1 -1
  4. package/constants/unified.js +2 -2
  5. package/initialReducer.js +0 -2
  6. package/package.json +1 -1
  7. package/services/api.js +5 -10
  8. package/services/tests/api.test.js +0 -18
  9. package/translations/en.json +4 -3
  10. package/utils/common.js +6 -5
  11. package/utils/commonUtils.js +1 -14
  12. package/utils/imageUrlUpload.js +141 -0
  13. package/utils/tests/commonUtil.test.js +0 -224
  14. package/utils/transformTemplateConfig.js +10 -0
  15. package/v2Components/CapDeviceContent/index.js +56 -61
  16. package/v2Components/CapImageUpload/constants.js +2 -0
  17. package/v2Components/CapImageUpload/index.js +65 -16
  18. package/v2Components/CapImageUpload/index.scss +4 -1
  19. package/v2Components/CapImageUpload/messages.js +5 -1
  20. package/v2Components/CapImageUrlUpload/constants.js +26 -0
  21. package/v2Components/CapImageUrlUpload/index.js +365 -0
  22. package/v2Components/CapImageUrlUpload/index.scss +35 -0
  23. package/v2Components/CapImageUrlUpload/messages.js +47 -0
  24. package/v2Components/CapTagList/index.js +1 -6
  25. package/v2Components/CapTagListWithInput/index.js +1 -5
  26. package/v2Components/CapTagListWithInput/messages.js +1 -1
  27. package/v2Components/CapWhatsappCTA/tests/index.test.js +0 -5
  28. package/v2Components/ErrorInfoNote/index.js +72 -412
  29. package/v2Components/ErrorInfoNote/messages.js +0 -22
  30. package/v2Components/ErrorInfoNote/style.scss +2 -279
  31. package/v2Components/HtmlEditor/HTMLEditor.js +91 -220
  32. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +133 -1132
  33. package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +12 -17
  34. package/v2Components/HtmlEditor/_htmlEditor.scss +45 -107
  35. package/v2Components/HtmlEditor/_index.lazy.scss +1 -1
  36. package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +101 -13
  37. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +139 -148
  38. package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +1 -2
  39. package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
  40. package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +0 -9
  41. package/v2Components/HtmlEditor/components/EditorToolbar/index.js +1 -1
  42. package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +0 -22
  43. package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +7 -4
  44. package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +45 -35
  45. package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +3 -1
  46. package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
  47. package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +6 -7
  48. package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +6 -3
  49. package/v2Components/HtmlEditor/components/PreviewPane/index.js +11 -10
  50. package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
  51. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +72 -70
  52. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +31 -49
  53. package/v2Components/HtmlEditor/constants.js +20 -29
  54. package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +16 -373
  55. package/v2Components/HtmlEditor/hooks/useEditorContent.js +2 -5
  56. package/v2Components/HtmlEditor/hooks/useInAppContent.js +146 -88
  57. package/v2Components/HtmlEditor/index.js +1 -1
  58. package/v2Components/HtmlEditor/messages.js +85 -95
  59. package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +101 -99
  60. package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +25 -23
  61. package/v2Components/HtmlEditor/utils/validationAdapter.js +41 -34
  62. package/v2Components/MobilePushPreviewV2/index.js +7 -32
  63. package/v2Components/TemplatePreview/_templatePreview.scss +24 -44
  64. package/v2Components/TemplatePreview/index.js +32 -47
  65. package/v2Components/TemplatePreview/messages.js +0 -4
  66. package/v2Components/TestAndPreviewSlidebox/index.js +25 -31
  67. package/v2Containers/App/constants.js +5 -0
  68. package/v2Containers/BeeEditor/index.js +80 -82
  69. package/v2Containers/Cap/tests/__snapshots__/index.test.js.snap +4 -3
  70. package/v2Containers/CreativesContainer/SlideBoxContent.js +118 -148
  71. package/v2Containers/CreativesContainer/SlideBoxFooter.js +3 -9
  72. package/v2Containers/CreativesContainer/SlideBoxHeader.js +2 -2
  73. package/v2Containers/CreativesContainer/constants.js +2 -1
  74. package/v2Containers/CreativesContainer/index.js +41 -173
  75. package/v2Containers/CreativesContainer/messages.js +4 -4
  76. package/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +210 -0
  77. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +354 -38
  78. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +0 -36
  79. package/v2Containers/Email/actions.js +0 -7
  80. package/v2Containers/Email/constants.js +1 -5
  81. package/v2Containers/Email/index.js +0 -13
  82. package/v2Containers/Email/messages.js +0 -32
  83. package/v2Containers/Email/reducer.js +1 -12
  84. package/v2Containers/Email/sagas.js +6 -41
  85. package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +0 -2
  86. package/v2Containers/EmailWrapper/components/EmailWrapperView.js +7 -193
  87. package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +74 -40
  88. package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +67 -2
  89. package/v2Containers/EmailWrapper/constants.js +0 -2
  90. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +67 -436
  91. package/v2Containers/EmailWrapper/index.js +23 -99
  92. package/v2Containers/EmailWrapper/messages.js +1 -61
  93. package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +214 -0
  94. package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +77 -111
  95. package/v2Containers/InApp/actions.js +0 -7
  96. package/v2Containers/InApp/constants.js +4 -20
  97. package/v2Containers/InApp/index.js +357 -801
  98. package/v2Containers/InApp/index.scss +3 -4
  99. package/v2Containers/InApp/messages.js +3 -7
  100. package/v2Containers/InApp/reducer.js +3 -21
  101. package/v2Containers/InApp/sagas.js +9 -29
  102. package/v2Containers/InApp/selectors.js +5 -25
  103. package/v2Containers/InApp/tests/index.test.js +50 -154
  104. package/v2Containers/InApp/tests/reducer.test.js +0 -34
  105. package/v2Containers/InApp/tests/sagas.test.js +9 -61
  106. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +12 -12
  107. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +8 -8
  108. package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +100 -77
  109. package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +72 -63
  110. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +184 -150
  111. package/v2Containers/SmsTrai/Create/tests/__snapshots__/index.test.js.snap +16 -12
  112. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +32 -28
  113. package/v2Containers/TagList/index.js +1 -67
  114. package/v2Containers/Templates/ChannelTypeIllustration.js +13 -1
  115. package/v2Containers/Templates/_templates.scss +202 -56
  116. package/v2Containers/Templates/actions.js +2 -1
  117. package/v2Containers/Templates/constants.js +1 -0
  118. package/v2Containers/Templates/index.js +278 -128
  119. package/v2Containers/Templates/messages.js +24 -4
  120. package/v2Containers/Templates/reducer.js +2 -0
  121. package/v2Containers/Templates/tests/index.test.js +10 -0
  122. package/v2Containers/TemplatesV2/index.js +8 -1
  123. package/v2Containers/TemplatesV2/messages.js +4 -0
  124. package/v2Containers/WebPush/Create/components/BrandIconSection.js +108 -0
  125. package/v2Containers/WebPush/Create/components/ButtonForm.js +172 -0
  126. package/v2Containers/WebPush/Create/components/ButtonItem.js +101 -0
  127. package/v2Containers/WebPush/Create/components/ButtonList.js +145 -0
  128. package/v2Containers/WebPush/Create/components/ButtonsLinksSection.js +164 -0
  129. package/v2Containers/WebPush/Create/components/ButtonsLinksSection.test.js +463 -0
  130. package/v2Containers/WebPush/Create/components/FormActions.js +54 -0
  131. package/v2Containers/WebPush/Create/components/FormActions.test.js +163 -0
  132. package/v2Containers/WebPush/Create/components/MediaSection.js +142 -0
  133. package/v2Containers/WebPush/Create/components/MediaSection.test.js +341 -0
  134. package/v2Containers/WebPush/Create/components/MessageSection.js +103 -0
  135. package/v2Containers/WebPush/Create/components/MessageSection.test.js +268 -0
  136. package/v2Containers/WebPush/Create/components/NotificationTitleSection.js +87 -0
  137. package/v2Containers/WebPush/Create/components/NotificationTitleSection.test.js +210 -0
  138. package/v2Containers/WebPush/Create/components/TemplateNameSection.js +54 -0
  139. package/v2Containers/WebPush/Create/components/TemplateNameSection.test.js +143 -0
  140. package/v2Containers/WebPush/Create/components/__snapshots__/ButtonsLinksSection.test.js.snap +86 -0
  141. package/v2Containers/WebPush/Create/components/__snapshots__/FormActions.test.js.snap +16 -0
  142. package/v2Containers/WebPush/Create/components/__snapshots__/MediaSection.test.js.snap +41 -0
  143. package/v2Containers/WebPush/Create/components/__snapshots__/MessageSection.test.js.snap +54 -0
  144. package/v2Containers/WebPush/Create/components/__snapshots__/NotificationTitleSection.test.js.snap +37 -0
  145. package/v2Containers/WebPush/Create/components/__snapshots__/TemplateNameSection.test.js.snap +21 -0
  146. package/v2Containers/WebPush/Create/components/_buttons.scss +246 -0
  147. package/v2Containers/WebPush/Create/components/tests/ButtonForm.test.js +554 -0
  148. package/v2Containers/WebPush/Create/components/tests/ButtonItem.test.js +607 -0
  149. package/v2Containers/WebPush/Create/components/tests/ButtonList.test.js +633 -0
  150. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonForm.test.js.snap +666 -0
  151. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonItem.test.js.snap +74 -0
  152. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonList.test.js.snap +78 -0
  153. package/v2Containers/WebPush/Create/hooks/useButtonManagement.js +138 -0
  154. package/v2Containers/WebPush/Create/hooks/useButtonManagement.test.js +406 -0
  155. package/v2Containers/WebPush/Create/hooks/useCharacterCount.js +30 -0
  156. package/v2Containers/WebPush/Create/hooks/useCharacterCount.test.js +151 -0
  157. package/v2Containers/WebPush/Create/hooks/useImageUpload.js +104 -0
  158. package/v2Containers/WebPush/Create/hooks/useImageUpload.test.js +538 -0
  159. package/v2Containers/WebPush/Create/hooks/useTagManagement.js +122 -0
  160. package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +633 -0
  161. package/v2Containers/WebPush/Create/index.js +1056 -0
  162. package/v2Containers/WebPush/Create/index.scss +134 -0
  163. package/v2Containers/WebPush/Create/messages.js +203 -0
  164. package/v2Containers/WebPush/Create/preview/DevicePreviewContent.js +228 -0
  165. package/v2Containers/WebPush/Create/preview/NotificationContainer.js +294 -0
  166. package/v2Containers/WebPush/Create/preview/PreviewContent.js +90 -0
  167. package/v2Containers/WebPush/Create/preview/PreviewControls.js +305 -0
  168. package/v2Containers/WebPush/Create/preview/PreviewDisclaimer.js +23 -0
  169. package/v2Containers/WebPush/Create/preview/WebPushPreview.js +150 -0
  170. package/v2Containers/WebPush/Create/preview/assets/Light.svg +53 -0
  171. package/v2Containers/WebPush/Create/preview/assets/Top.svg +5 -0
  172. package/v2Containers/WebPush/Create/preview/assets/android-arrow-down.svg +9 -0
  173. package/v2Containers/WebPush/Create/preview/assets/android-arrow-up.svg +9 -0
  174. package/v2Containers/WebPush/Create/preview/assets/chrome-icon.png +0 -0
  175. package/v2Containers/WebPush/Create/preview/assets/edge-icon.png +0 -0
  176. package/v2Containers/WebPush/Create/preview/assets/firefox-icon.svg +106 -0
  177. package/v2Containers/WebPush/Create/preview/assets/iOS.svg +26 -0
  178. package/v2Containers/WebPush/Create/preview/assets/macos-arrow-down-icon.svg +9 -0
  179. package/v2Containers/WebPush/Create/preview/assets/macos-triple-dot-icon.svg +9 -0
  180. package/v2Containers/WebPush/Create/preview/assets/opera-icon.svg +18 -0
  181. package/v2Containers/WebPush/Create/preview/assets/safari-icon.svg +29 -0
  182. package/v2Containers/WebPush/Create/preview/assets/windows-close-icon.svg +9 -0
  183. package/v2Containers/WebPush/Create/preview/assets/windows-triple-dot-icon.svg +9 -0
  184. package/v2Containers/WebPush/Create/preview/components/AndroidMobileChromeHeader.js +47 -0
  185. package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +141 -0
  186. package/v2Containers/WebPush/Create/preview/components/IOSHeader.js +45 -0
  187. package/v2Containers/WebPush/Create/preview/components/NotificationExpandedContent.js +68 -0
  188. package/v2Containers/WebPush/Create/preview/components/NotificationHeader.js +61 -0
  189. package/v2Containers/WebPush/Create/preview/components/WindowsChromeExpanded.js +99 -0
  190. package/v2Containers/WebPush/Create/preview/components/tests/AndroidMobileExpanded.test.js +733 -0
  191. package/v2Containers/WebPush/Create/preview/components/tests/WindowsChromeExpanded.test.js +571 -0
  192. package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/AndroidMobileExpanded.test.js.snap +81 -0
  193. package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/WindowsChromeExpanded.test.js.snap +81 -0
  194. package/v2Containers/WebPush/Create/preview/config/notificationMappings.js +50 -0
  195. package/v2Containers/WebPush/Create/preview/constants.js +637 -0
  196. package/v2Containers/WebPush/Create/preview/notification-container.scss +79 -0
  197. package/v2Containers/WebPush/Create/preview/preview.scss +351 -0
  198. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-chrome.scss +370 -0
  199. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-edge.scss +12 -0
  200. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-firefox.scss +12 -0
  201. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-opera.scss +12 -0
  202. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-chrome.scss +47 -0
  203. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-edge.scss +11 -0
  204. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-firefox.scss +11 -0
  205. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-opera.scss +11 -0
  206. package/v2Containers/WebPush/Create/preview/styles/_base.scss +207 -0
  207. package/v2Containers/WebPush/Create/preview/styles/_ios.scss +153 -0
  208. package/v2Containers/WebPush/Create/preview/styles/_ipados.scss +107 -0
  209. package/v2Containers/WebPush/Create/preview/styles/_macos-chrome.scss +101 -0
  210. package/v2Containers/WebPush/Create/preview/styles/_windows-chrome.scss +229 -0
  211. package/v2Containers/WebPush/Create/preview/tests/DevicePreviewContent.test.js +909 -0
  212. package/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +1081 -0
  213. package/v2Containers/WebPush/Create/preview/tests/PreviewControls.test.js +723 -0
  214. package/v2Containers/WebPush/Create/preview/tests/WebPushPreview.test.js +943 -0
  215. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/DevicePreviewContent.test.js.snap +131 -0
  216. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/NotificationContainer.test.js.snap +112 -0
  217. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/PreviewControls.test.js.snap +144 -0
  218. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/WebPushPreview.test.js.snap +129 -0
  219. package/v2Containers/WebPush/Create/utils/payloadBuilder.js +94 -0
  220. package/v2Containers/WebPush/Create/utils/payloadBuilder.test.js +390 -0
  221. package/v2Containers/WebPush/Create/utils/previewUtils.js +89 -0
  222. package/v2Containers/WebPush/Create/utils/urlValidation.js +115 -0
  223. package/v2Containers/WebPush/Create/utils/urlValidation.test.js +449 -0
  224. package/v2Containers/WebPush/Create/utils/validation.js +75 -0
  225. package/v2Containers/WebPush/Create/utils/validation.test.js +283 -0
  226. package/v2Containers/WebPush/actions.js +60 -0
  227. package/v2Containers/WebPush/constants.js +128 -0
  228. package/v2Containers/WebPush/index.js +2 -0
  229. package/v2Containers/WebPush/reducer.js +104 -0
  230. package/v2Containers/WebPush/sagas.js +119 -0
  231. package/v2Containers/WebPush/selectors.js +65 -0
  232. package/v2Containers/WebPush/tests/reducer.test.js +863 -0
  233. package/v2Containers/WebPush/tests/sagas.test.js +566 -0
  234. package/v2Containers/WebPush/tests/selectors.test.js +843 -0
  235. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +528 -431
  236. package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +0 -254
  237. package/v2Components/HtmlEditor/components/ValidationTabs/index.js +0 -362
  238. package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +0 -51
  239. package/v2Containers/BeePopupEditor/constants.js +0 -10
  240. package/v2Containers/BeePopupEditor/index.js +0 -193
  241. package/v2Containers/BeePopupEditor/tests/index.test.js +0 -627
  242. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +0 -1046
  243. package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +0 -376
  244. package/v2Containers/InApp/__tests__/sagas.test.js +0 -363
  245. package/v2Containers/InApp/tests/selectors.test.js +0 -612
  246. package/v2Containers/InAppWrapper/components/InAppWrapperView.js +0 -162
  247. package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +0 -267
  248. package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +0 -9
  249. package/v2Containers/InAppWrapper/constants.js +0 -16
  250. package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +0 -473
  251. package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +0 -198
  252. package/v2Containers/InAppWrapper/index.js +0 -148
  253. package/v2Containers/InAppWrapper/messages.js +0 -49
  254. package/v2Containers/InappAdvance/index.js +0 -1099
  255. package/v2Containers/InappAdvance/index.scss +0 -10
  256. 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,2 @@
1
+ export { default } from './Create';
2
+
@@ -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
+ }