@capillarytech/creatives-library 8.0.250-alpha.2 → 8.0.251

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 (276) hide show
  1. package/assets/Android.png +0 -0
  2. package/assets/iOS.png +0 -0
  3. package/constants/unified.js +1 -3
  4. package/initialReducer.js +0 -2
  5. package/package.json +1 -1
  6. package/services/api.js +0 -15
  7. package/services/tests/api.test.js +0 -34
  8. package/translations/en.json +3 -4
  9. package/utils/common.js +0 -11
  10. package/utils/commonUtils.js +5 -28
  11. package/utils/tests/commonUtil.test.js +0 -224
  12. package/utils/tests/transformerUtils.test.js +0 -297
  13. package/utils/transformTemplateConfig.js +10 -0
  14. package/utils/transformerUtils.js +0 -40
  15. package/v2Components/CapDeviceContent/index.js +56 -61
  16. package/v2Components/CapImageUpload/constants.js +0 -2
  17. package/v2Components/CapImageUpload/index.js +16 -65
  18. package/v2Components/CapImageUpload/index.scss +1 -4
  19. package/v2Components/CapImageUpload/messages.js +1 -5
  20. package/v2Components/CapTagList/index.js +1 -6
  21. package/v2Components/CapTagListWithInput/index.js +1 -5
  22. package/v2Components/CapTagListWithInput/messages.js +1 -1
  23. package/v2Components/CapWhatsappCTA/tests/index.test.js +0 -5
  24. package/v2Components/ErrorInfoNote/index.js +72 -455
  25. package/v2Components/ErrorInfoNote/messages.js +6 -36
  26. package/v2Components/ErrorInfoNote/style.scss +4 -280
  27. package/v2Components/FormBuilder/tests/index.test.js +4 -13
  28. package/v2Components/HtmlEditor/HTMLEditor.js +94 -547
  29. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +133 -1358
  30. package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +16 -27
  31. package/v2Components/HtmlEditor/_htmlEditor.scss +45 -108
  32. package/v2Components/HtmlEditor/_index.lazy.scss +1 -1
  33. package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +101 -22
  34. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +140 -146
  35. package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +1 -2
  36. package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
  37. package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +0 -9
  38. package/v2Components/HtmlEditor/components/EditorToolbar/index.js +1 -1
  39. package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +0 -22
  40. package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +7 -4
  41. package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +45 -35
  42. package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +3 -1
  43. package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
  44. package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +6 -7
  45. package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +6 -3
  46. package/v2Components/HtmlEditor/components/PreviewPane/index.js +34 -24
  47. package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
  48. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +152 -0
  49. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +31 -49
  50. package/v2Components/HtmlEditor/components/ValidationPanel/_validationPanel.scss +34 -50
  51. package/v2Components/HtmlEditor/components/ValidationPanel/index.js +41 -70
  52. package/v2Components/HtmlEditor/constants.js +20 -42
  53. package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +16 -373
  54. package/v2Components/HtmlEditor/hooks/useEditorContent.js +2 -5
  55. package/v2Components/HtmlEditor/hooks/useInAppContent.js +146 -88
  56. package/v2Components/HtmlEditor/hooks/useValidation.js +53 -189
  57. package/v2Components/HtmlEditor/index.js +1 -1
  58. package/v2Components/HtmlEditor/messages.js +85 -95
  59. package/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +45 -94
  60. package/v2Components/HtmlEditor/utils/__tests__/validationAdapter.test.js +0 -134
  61. package/v2Components/HtmlEditor/utils/contentSanitizer.js +41 -40
  62. package/v2Components/HtmlEditor/utils/htmlValidator.js +72 -71
  63. package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +102 -134
  64. package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +25 -23
  65. package/v2Components/HtmlEditor/utils/validationAdapter.js +41 -66
  66. package/v2Components/MobilePushPreviewV2/index.js +7 -32
  67. package/v2Components/TemplatePreview/_templatePreview.scss +24 -55
  68. package/v2Components/TemplatePreview/index.js +32 -47
  69. package/v2Components/TemplatePreview/messages.js +0 -4
  70. package/v2Components/TestAndPreviewSlidebox/_testAndPreviewSlidebox.scss +0 -1
  71. package/v2Containers/App/constants.js +0 -5
  72. package/v2Containers/BeeEditor/index.js +90 -172
  73. package/v2Containers/Cap/tests/__snapshots__/index.test.js.snap +3 -4
  74. package/v2Containers/CreativesContainer/SlideBoxContent.js +53 -184
  75. package/v2Containers/CreativesContainer/SlideBoxFooter.js +13 -163
  76. package/v2Containers/CreativesContainer/SlideBoxHeader.js +1 -3
  77. package/v2Containers/CreativesContainer/constants.js +0 -4
  78. package/v2Containers/CreativesContainer/index.js +46 -407
  79. package/v2Containers/CreativesContainer/messages.js +0 -12
  80. package/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +0 -210
  81. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +2 -11
  82. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +50 -342
  83. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +0 -106
  84. package/v2Containers/Email/actions.js +0 -7
  85. package/v2Containers/Email/constants.js +1 -5
  86. package/v2Containers/Email/index.js +29 -234
  87. package/v2Containers/Email/messages.js +0 -32
  88. package/v2Containers/Email/reducer.js +1 -12
  89. package/v2Containers/Email/sagas.js +7 -61
  90. package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +0 -2
  91. package/v2Containers/Email/tests/reducer.test.js +0 -46
  92. package/v2Containers/Email/tests/sagas.test.js +29 -320
  93. package/v2Containers/EmailWrapper/components/EmailWrapperView.js +19 -207
  94. package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +74 -40
  95. package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +67 -2
  96. package/v2Containers/EmailWrapper/constants.js +0 -2
  97. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +77 -629
  98. package/v2Containers/EmailWrapper/index.js +23 -103
  99. package/v2Containers/EmailWrapper/messages.js +1 -61
  100. package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +214 -0
  101. package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +77 -594
  102. package/v2Containers/InApp/actions.js +0 -7
  103. package/v2Containers/InApp/constants.js +4 -20
  104. package/v2Containers/InApp/index.js +359 -802
  105. package/v2Containers/InApp/index.scss +3 -4
  106. package/v2Containers/InApp/messages.js +3 -7
  107. package/v2Containers/InApp/reducer.js +3 -21
  108. package/v2Containers/InApp/sagas.js +9 -29
  109. package/v2Containers/InApp/selectors.js +5 -25
  110. package/v2Containers/InApp/tests/index.test.js +50 -154
  111. package/v2Containers/InApp/tests/reducer.test.js +0 -34
  112. package/v2Containers/InApp/tests/sagas.test.js +9 -61
  113. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +9 -15
  114. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +6 -10
  115. package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +75 -102
  116. package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +54 -81
  117. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +174 -244
  118. package/v2Containers/SmsTrai/Create/tests/__snapshots__/index.test.js.snap +12 -16
  119. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +36 -52
  120. package/v2Containers/TagList/index.js +19 -62
  121. package/v2Containers/Templates/ChannelTypeIllustration.js +1 -13
  122. package/v2Containers/Templates/_templates.scss +1 -265
  123. package/v2Containers/Templates/actions.js +1 -2
  124. package/v2Containers/Templates/constants.js +0 -1
  125. package/v2Containers/Templates/index.js +38 -363
  126. package/v2Containers/Templates/messages.js +0 -28
  127. package/v2Containers/Templates/reducer.js +0 -4
  128. package/v2Containers/Templates/tests/index.test.js +0 -10
  129. package/v2Containers/TemplatesV2/index.js +7 -15
  130. package/v2Containers/TemplatesV2/messages.js +0 -4
  131. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +486 -682
  132. package/utils/imageUrlUpload.js +0 -141
  133. package/v2Components/CapImageUrlUpload/constants.js +0 -26
  134. package/v2Components/CapImageUrlUpload/index.js +0 -365
  135. package/v2Components/CapImageUrlUpload/index.scss +0 -35
  136. package/v2Components/CapImageUrlUpload/messages.js +0 -47
  137. package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +0 -874
  138. package/v2Components/HtmlEditor/components/ValidationPanel/constants.js +0 -6
  139. package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +0 -254
  140. package/v2Components/HtmlEditor/components/ValidationTabs/index.js +0 -364
  141. package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +0 -51
  142. package/v2Components/HtmlEditor/hooks/__tests__/useValidation.apiErrors.test.js +0 -795
  143. package/v2Components/HtmlEditor/utils/validationConstants.js +0 -40
  144. package/v2Containers/BeePopupEditor/_beePopupEditor.scss +0 -14
  145. package/v2Containers/BeePopupEditor/constants.js +0 -10
  146. package/v2Containers/BeePopupEditor/index.js +0 -194
  147. package/v2Containers/BeePopupEditor/tests/index.test.js +0 -627
  148. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +0 -1285
  149. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +0 -1870
  150. package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +0 -520
  151. package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +0 -643
  152. package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +0 -376
  153. package/v2Containers/InApp/__tests__/sagas.test.js +0 -363
  154. package/v2Containers/InApp/tests/selectors.test.js +0 -612
  155. package/v2Containers/InAppWrapper/components/InAppWrapperView.js +0 -151
  156. package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +0 -267
  157. package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +0 -23
  158. package/v2Containers/InAppWrapper/constants.js +0 -16
  159. package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +0 -473
  160. package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +0 -198
  161. package/v2Containers/InAppWrapper/index.js +0 -148
  162. package/v2Containers/InAppWrapper/messages.js +0 -49
  163. package/v2Containers/InappAdvance/index.js +0 -1099
  164. package/v2Containers/InappAdvance/index.scss +0 -10
  165. package/v2Containers/InappAdvance/tests/index.test.js +0 -448
  166. package/v2Containers/WebPush/Create/components/BrandIconSection.js +0 -108
  167. package/v2Containers/WebPush/Create/components/ButtonForm.js +0 -172
  168. package/v2Containers/WebPush/Create/components/ButtonItem.js +0 -101
  169. package/v2Containers/WebPush/Create/components/ButtonList.js +0 -107
  170. package/v2Containers/WebPush/Create/components/ButtonsLinksSection.js +0 -160
  171. package/v2Containers/WebPush/Create/components/ButtonsLinksSection.test.js +0 -476
  172. package/v2Containers/WebPush/Create/components/FormActions.js +0 -54
  173. package/v2Containers/WebPush/Create/components/FormActions.test.js +0 -163
  174. package/v2Containers/WebPush/Create/components/MediaSection.js +0 -143
  175. package/v2Containers/WebPush/Create/components/MediaSection.test.js +0 -341
  176. package/v2Containers/WebPush/Create/components/MessageSection.js +0 -103
  177. package/v2Containers/WebPush/Create/components/MessageSection.test.js +0 -268
  178. package/v2Containers/WebPush/Create/components/NotificationTitleSection.js +0 -87
  179. package/v2Containers/WebPush/Create/components/NotificationTitleSection.test.js +0 -210
  180. package/v2Containers/WebPush/Create/components/TemplateNameSection.js +0 -54
  181. package/v2Containers/WebPush/Create/components/TemplateNameSection.test.js +0 -143
  182. package/v2Containers/WebPush/Create/components/__snapshots__/ButtonsLinksSection.test.js.snap +0 -82
  183. package/v2Containers/WebPush/Create/components/__snapshots__/FormActions.test.js.snap +0 -16
  184. package/v2Containers/WebPush/Create/components/__snapshots__/MediaSection.test.js.snap +0 -41
  185. package/v2Containers/WebPush/Create/components/__snapshots__/MessageSection.test.js.snap +0 -54
  186. package/v2Containers/WebPush/Create/components/__snapshots__/NotificationTitleSection.test.js.snap +0 -37
  187. package/v2Containers/WebPush/Create/components/__snapshots__/TemplateNameSection.test.js.snap +0 -21
  188. package/v2Containers/WebPush/Create/components/_buttons.scss +0 -246
  189. package/v2Containers/WebPush/Create/components/tests/ButtonForm.test.js +0 -554
  190. package/v2Containers/WebPush/Create/components/tests/ButtonItem.test.js +0 -607
  191. package/v2Containers/WebPush/Create/components/tests/ButtonList.test.js +0 -515
  192. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonForm.test.js.snap +0 -666
  193. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonItem.test.js.snap +0 -74
  194. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonList.test.js.snap +0 -46
  195. package/v2Containers/WebPush/Create/hooks/useButtonManagement.js +0 -150
  196. package/v2Containers/WebPush/Create/hooks/useButtonManagement.test.js +0 -406
  197. package/v2Containers/WebPush/Create/hooks/useCharacterCount.js +0 -30
  198. package/v2Containers/WebPush/Create/hooks/useCharacterCount.test.js +0 -151
  199. package/v2Containers/WebPush/Create/hooks/useImageUpload.js +0 -104
  200. package/v2Containers/WebPush/Create/hooks/useImageUpload.test.js +0 -538
  201. package/v2Containers/WebPush/Create/hooks/useTagManagement.js +0 -122
  202. package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +0 -633
  203. package/v2Containers/WebPush/Create/index.js +0 -1148
  204. package/v2Containers/WebPush/Create/index.scss +0 -134
  205. package/v2Containers/WebPush/Create/messages.js +0 -203
  206. package/v2Containers/WebPush/Create/preview/DevicePreviewContent.js +0 -228
  207. package/v2Containers/WebPush/Create/preview/NotificationContainer.js +0 -294
  208. package/v2Containers/WebPush/Create/preview/PreviewContent.js +0 -90
  209. package/v2Containers/WebPush/Create/preview/PreviewControls.js +0 -305
  210. package/v2Containers/WebPush/Create/preview/PreviewDisclaimer.js +0 -23
  211. package/v2Containers/WebPush/Create/preview/WebPushPreview.js +0 -155
  212. package/v2Containers/WebPush/Create/preview/assets/Light.svg +0 -53
  213. package/v2Containers/WebPush/Create/preview/assets/Top.svg +0 -5
  214. package/v2Containers/WebPush/Create/preview/assets/android-arrow-down.svg +0 -9
  215. package/v2Containers/WebPush/Create/preview/assets/android-arrow-up.svg +0 -9
  216. package/v2Containers/WebPush/Create/preview/assets/chrome-icon.png +0 -0
  217. package/v2Containers/WebPush/Create/preview/assets/edge-icon.png +0 -0
  218. package/v2Containers/WebPush/Create/preview/assets/firefox-icon.svg +0 -106
  219. package/v2Containers/WebPush/Create/preview/assets/iOS.svg +0 -26
  220. package/v2Containers/WebPush/Create/preview/assets/macos-arrow-down-icon.svg +0 -9
  221. package/v2Containers/WebPush/Create/preview/assets/macos-triple-dot-icon.svg +0 -9
  222. package/v2Containers/WebPush/Create/preview/assets/opera-icon.svg +0 -18
  223. package/v2Containers/WebPush/Create/preview/assets/safari-icon.svg +0 -29
  224. package/v2Containers/WebPush/Create/preview/assets/windows-close-icon.svg +0 -9
  225. package/v2Containers/WebPush/Create/preview/assets/windows-triple-dot-icon.svg +0 -9
  226. package/v2Containers/WebPush/Create/preview/components/AndroidMobileChromeHeader.js +0 -47
  227. package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +0 -141
  228. package/v2Containers/WebPush/Create/preview/components/IOSHeader.js +0 -45
  229. package/v2Containers/WebPush/Create/preview/components/NotificationExpandedContent.js +0 -68
  230. package/v2Containers/WebPush/Create/preview/components/NotificationHeader.js +0 -61
  231. package/v2Containers/WebPush/Create/preview/components/WindowsChromeExpanded.js +0 -99
  232. package/v2Containers/WebPush/Create/preview/components/tests/AndroidMobileExpanded.test.js +0 -733
  233. package/v2Containers/WebPush/Create/preview/components/tests/WindowsChromeExpanded.test.js +0 -571
  234. package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/AndroidMobileExpanded.test.js.snap +0 -81
  235. package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/WindowsChromeExpanded.test.js.snap +0 -81
  236. package/v2Containers/WebPush/Create/preview/config/notificationMappings.js +0 -50
  237. package/v2Containers/WebPush/Create/preview/constants.js +0 -637
  238. package/v2Containers/WebPush/Create/preview/notification-container.scss +0 -79
  239. package/v2Containers/WebPush/Create/preview/preview.scss +0 -351
  240. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-chrome.scss +0 -370
  241. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-edge.scss +0 -12
  242. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-firefox.scss +0 -12
  243. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-opera.scss +0 -12
  244. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-chrome.scss +0 -47
  245. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-edge.scss +0 -11
  246. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-firefox.scss +0 -11
  247. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-opera.scss +0 -11
  248. package/v2Containers/WebPush/Create/preview/styles/_base.scss +0 -207
  249. package/v2Containers/WebPush/Create/preview/styles/_ios.scss +0 -153
  250. package/v2Containers/WebPush/Create/preview/styles/_ipados.scss +0 -107
  251. package/v2Containers/WebPush/Create/preview/styles/_macos-chrome.scss +0 -101
  252. package/v2Containers/WebPush/Create/preview/styles/_windows-chrome.scss +0 -229
  253. package/v2Containers/WebPush/Create/preview/tests/DevicePreviewContent.test.js +0 -909
  254. package/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +0 -1081
  255. package/v2Containers/WebPush/Create/preview/tests/PreviewControls.test.js +0 -723
  256. package/v2Containers/WebPush/Create/preview/tests/WebPushPreview.test.js +0 -1327
  257. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/DevicePreviewContent.test.js.snap +0 -131
  258. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/NotificationContainer.test.js.snap +0 -112
  259. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/PreviewControls.test.js.snap +0 -144
  260. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/WebPushPreview.test.js.snap +0 -129
  261. package/v2Containers/WebPush/Create/utils/payloadBuilder.js +0 -96
  262. package/v2Containers/WebPush/Create/utils/payloadBuilder.test.js +0 -396
  263. package/v2Containers/WebPush/Create/utils/previewUtils.js +0 -89
  264. package/v2Containers/WebPush/Create/utils/urlValidation.js +0 -115
  265. package/v2Containers/WebPush/Create/utils/urlValidation.test.js +0 -449
  266. package/v2Containers/WebPush/Create/utils/validation.js +0 -75
  267. package/v2Containers/WebPush/Create/utils/validation.test.js +0 -283
  268. package/v2Containers/WebPush/actions.js +0 -60
  269. package/v2Containers/WebPush/constants.js +0 -132
  270. package/v2Containers/WebPush/index.js +0 -2
  271. package/v2Containers/WebPush/reducer.js +0 -104
  272. package/v2Containers/WebPush/sagas.js +0 -119
  273. package/v2Containers/WebPush/selectors.js +0 -65
  274. package/v2Containers/WebPush/tests/reducer.test.js +0 -863
  275. package/v2Containers/WebPush/tests/sagas.test.js +0 -566
  276. package/v2Containers/WebPush/tests/selectors.test.js +0 -960
@@ -1,141 +0,0 @@
1
- /**
2
- * Utility functions for uploading images from URLs
3
- *
4
- * NOTE: CORS-limited; will be replaced with backend implementation.
5
- * Flow currently hidden (not removed) from frontend.
6
- */
7
-
8
- import {
9
- DEFAULT_ALLOWED_CONTENT_TYPES,
10
- MIME_TYPE_TO_EXTENSION,
11
- DEFAULT_IMAGE_EXTENSION,
12
- } from '../v2Components/CapImageUrlUpload/constants';
13
-
14
- /**
15
- * Fetches an image from a URL
16
- *
17
- * @param {string} url - The image URL to fetch
18
- * @returns {Promise<Response>} - The fetch response object
19
- * @throws {Error} - If the fetch fails (network/CORS error)
20
- */
21
- export const fetchImageFromUrl = async (url) => {
22
- const trimmedUrl = url?.trim() || '';
23
-
24
- if (!trimmedUrl) {
25
- throw new Error('URL is required');
26
- }
27
-
28
- // CORS-limited: fails for images without proper CORS headers
29
- const response = await fetch(trimmedUrl, {
30
- method: 'GET',
31
- redirect: 'follow',
32
- mode: 'cors',
33
- });
34
-
35
- if (!response.ok) {
36
- throw new Error(`Failed to fetch image: ${response.status} ${response.statusText}`);
37
- }
38
-
39
- return response;
40
- };
41
-
42
- /**
43
- * Helper function to upload image from URL
44
- * Fetches image, validates content type and size, converts to File, and uploads via uploadAsset
45
- *
46
- * @param {string} url - The image URL to upload
47
- * @param {Function} formatMessage - React Intl formatMessage function
48
- * @param {Object} messages - React Intl messages object
49
- * @param {Function} uploadAssetFn - Function to upload the asset (file, type, fileParams)
50
- * @param {string} fileNamePrefix - Prefix for the generated file name
51
- * @param {number} maxSize - Maximum file size in bytes
52
- * @param {string[]} allowedContentTypes - Array of allowed MIME types (defaults to DEFAULT_ALLOWED_CONTENT_TYPES)
53
- * @returns {Promise<{success: boolean, error: string}>} - Result object with success status and error message
54
- *
55
- * @example
56
- * const result = await uploadImageFromUrlHelper(
57
- * 'https://example.com/image.jpg',
58
- * formatMessage,
59
- * messages,
60
- * uploadAsset,
61
- * 'my-image',
62
- * 5000000,
63
- * ['image/jpeg', 'image/png']
64
- * );
65
- */
66
- export const uploadImageFromUrlHelper = async (
67
- url,
68
- formatMessage,
69
- messages,
70
- uploadAssetFn,
71
- fileNamePrefix,
72
- maxSize,
73
- allowedContentTypes = DEFAULT_ALLOWED_CONTENT_TYPES,
74
- ) => {
75
- const trimmedUrl = url?.trim() || '';
76
-
77
- try {
78
- const response = await fetchImageFromUrl(trimmedUrl);
79
-
80
- // Validate Content-Type
81
- const contentType = response.headers?.get('Content-Type') || '';
82
- const normalizedContentType = contentType.split(';')[0].toLowerCase().trim();
83
-
84
- if (!allowedContentTypes.includes(normalizedContentType)) {
85
- return {
86
- success: false,
87
- error: formatMessage(messages.imageTypeInvalid),
88
- };
89
- }
90
-
91
- const blob = await response.blob();
92
-
93
- if (blob.size > maxSize) {
94
- return {
95
- success: false,
96
- error: formatMessage(messages.imageSizeInvalid),
97
- };
98
- }
99
-
100
- // Load image to get dimensions and verify validity
101
- return new Promise((resolve) => {
102
- const img = new Image();
103
- const objectUrl = URL.createObjectURL(blob);
104
-
105
- img.onload = () => {
106
- const extension = MIME_TYPE_TO_EXTENSION[normalizedContentType] || DEFAULT_IMAGE_EXTENSION;
107
- const fileName = `${fileNamePrefix}.${extension}`;
108
- const file = new File([blob], fileName, { type: blob.type });
109
- const fileParams = {
110
- width: img.width,
111
- height: img.height,
112
- error: false,
113
- };
114
-
115
- uploadAssetFn(file, 'image', fileParams);
116
- URL.revokeObjectURL(objectUrl);
117
-
118
- resolve({
119
- success: true,
120
- error: '',
121
- });
122
- };
123
-
124
- img.onerror = () => {
125
- URL.revokeObjectURL(objectUrl);
126
- resolve({
127
- success: false,
128
- error: formatMessage(messages.imageLoadError),
129
- });
130
- };
131
-
132
- img.src = objectUrl;
133
- });
134
- } catch (error) {
135
- return {
136
- success: false,
137
- error: formatMessage(messages.imageLoadError),
138
- };
139
- }
140
- };
141
-
@@ -1,26 +0,0 @@
1
- // Default allowed content types for image URL validation
2
- export const DEFAULT_ALLOWED_CONTENT_TYPES = ['image/jpeg', 'image/jpg', 'image/png'];
3
-
4
- // Default maximum file size (5MB)
5
- export const DEFAULT_MAX_SIZE = 5000000;
6
-
7
- // Default allowed extensions regex
8
- export const DEFAULT_ALLOWED_EXTENSIONS_REGEX = /\.(jpe?g|png)$/i;
9
-
10
- // MIME type to file extension mapping
11
- export const MIME_TYPE_TO_EXTENSION = {
12
- 'image/jpeg': 'jpg',
13
- 'image/jpg': 'jpg',
14
- 'image/png': 'png',
15
- };
16
-
17
- // Default image extension fallback
18
- export const DEFAULT_IMAGE_EXTENSION = 'png';
19
-
20
- // Upload status state machine states
21
- export const UPLOAD_STATUS = {
22
- IDLE: 'idle',
23
- UPLOADING: 'uploading',
24
- WAITING: 'waiting',
25
- };
26
-
@@ -1,365 +0,0 @@
1
- /**
2
- *
3
- * CapImageUrlUpload
4
- *
5
- * A modular component for uploading images from a URL.
6
- * Validates URL format, image type, and size before uploading to gallery.
7
- * Can be used in any form context (creatives, profiles, etc.)
8
- */
9
-
10
- import React, { useState, useCallback, useEffect } from 'react';
11
- import PropTypes from 'prop-types';
12
- import { injectIntl, intlShape, FormattedMessage } from 'react-intl';
13
- import CapInput from '@capillarytech/cap-ui-library/CapInput';
14
- import CapHeading from '@capillarytech/cap-ui-library/CapHeading';
15
- import CapLabel from '@capillarytech/cap-ui-library/CapLabel';
16
- import CapError from '@capillarytech/cap-ui-library/CapError';
17
- import messages from './messages';
18
- import { DEFAULT_ALLOWED_CONTENT_TYPES, DEFAULT_MAX_SIZE, UPLOAD_STATUS } from './constants';
19
- import { fetchImageFromUrl, uploadImageFromUrlHelper } from '../../utils/imageUrlUpload';
20
- import './index.scss';
21
-
22
- function CapImageUrlUpload(props) {
23
- const {
24
- intl,
25
- uploadAsset,
26
- imgSize = DEFAULT_MAX_SIZE,
27
- allowedContentTypes = DEFAULT_ALLOWED_CONTENT_TYPES,
28
- recommendedDimensions = [],
29
- sizeLabel = '',
30
- formatLabel = '',
31
- imageUrl = '',
32
- imageSrc = '', // Secure file path from parent after upload completes
33
- onUrlChange,
34
- onValidationStateChange, // Callback to notify parent of validation state
35
- onUploadStateChange, // Callback to notify parent of upload state
36
- isExternalUploading = false, // Upload state from parent (e.g., redux)
37
- className = '',
38
- placeholder,
39
- disabled = false,
40
- fileNamePrefix = 'image',
41
- } = props;
42
-
43
- const { formatMessage } = intl ?? {};
44
- const { CapHeadingSpan } = CapHeading;
45
-
46
- const [isValidating, setIsValidating] = useState(false);
47
- const [isInternalUploading, setIsInternalUploading] = useState(false);
48
- const [error, setError] = useState('');
49
- // State machine for upload lifecycle
50
- const [uploadStatus, setUploadStatus] = useState(UPLOAD_STATUS.IDLE);
51
-
52
- /**
53
- * Validate image URL
54
- * Checks URL format, fetches as Blob, validates Content-Type, file size, and image validity
55
- */
56
- const validateImageUrl = useCallback(async (url) => {
57
- const trimmedUrl = url?.trim() || '';
58
-
59
- if (!trimmedUrl) {
60
- return { isValid: false, error: '' };
61
- }
62
-
63
- setIsValidating(true);
64
- setError('');
65
-
66
- try {
67
- // Validate URL format
68
- let urlObj;
69
- try {
70
- urlObj = new URL(trimmedUrl);
71
- if (!['http:', 'https:'].includes(urlObj.protocol)) {
72
- setIsValidating(false);
73
- return {
74
- isValid: false,
75
- error: formatMessage(messages.imageUrlInvalid),
76
- };
77
- }
78
- } catch (urlError) {
79
- setIsValidating(false);
80
- return {
81
- isValid: false,
82
- error: formatMessage(messages.imageUrlInvalid),
83
- };
84
- }
85
-
86
- // Fetch image as Blob to check file size
87
- let response;
88
- try {
89
- response = await fetchImageFromUrl(trimmedUrl);
90
- } catch (fetchError) {
91
- setIsValidating(false);
92
- return {
93
- isValid: false,
94
- error: formatMessage(messages.imageLoadError),
95
- };
96
- }
97
-
98
- // Validate Content-Type
99
- const contentType = response.headers?.get('Content-Type') || '';
100
- const normalizedContentType = contentType.split(';')[0].toLowerCase().trim();
101
-
102
- if (!allowedContentTypes.includes(normalizedContentType)) {
103
- setIsValidating(false);
104
- return {
105
- isValid: false,
106
- error: formatMessage(messages.imageTypeInvalid),
107
- };
108
- }
109
-
110
- // Validate file size
111
- const blob = await response.blob();
112
- if (blob.size > imgSize) {
113
- setIsValidating(false);
114
- return {
115
- isValid: false,
116
- error: formatMessage(messages.imageSizeInvalid),
117
- };
118
- }
119
-
120
- // Verify image validity by loading in Image object
121
- return new Promise((resolve) => {
122
- const img = new Image();
123
- const objectUrl = URL.createObjectURL(blob);
124
-
125
- img.onload = () => {
126
- URL.revokeObjectURL(objectUrl);
127
- setIsValidating(false);
128
- resolve({
129
- isValid: true,
130
- error: '',
131
- });
132
- };
133
-
134
- img.onerror = () => {
135
- URL.revokeObjectURL(objectUrl);
136
- setIsValidating(false);
137
- resolve({
138
- isValid: false,
139
- error: formatMessage(messages.imageLoadError),
140
- });
141
- };
142
-
143
- img.src = objectUrl;
144
- });
145
- } catch (err) {
146
- setIsValidating(false);
147
- return {
148
- isValid: false,
149
- error: formatMessage(messages.imageLoadError),
150
- };
151
- }
152
- }, [formatMessage, allowedContentTypes, imgSize]);
153
-
154
- /**
155
- * Upload image from URL to media gallery
156
- * Fetches image, converts to File, uploads via uploadAsset
157
- */
158
- const uploadImageFromUrl = useCallback(async (url) => {
159
- setIsInternalUploading(true);
160
- setUploadStatus(UPLOAD_STATUS.UPLOADING);
161
-
162
- // Notify parent that upload is starting
163
- if (onUploadStateChange) {
164
- onUploadStateChange(true);
165
- }
166
-
167
- const result = await uploadImageFromUrlHelper(
168
- url,
169
- formatMessage,
170
- messages,
171
- uploadAsset,
172
- fileNamePrefix,
173
- imgSize,
174
- allowedContentTypes,
175
- );
176
-
177
- setIsInternalUploading(false);
178
-
179
- // Check if imageSrc is already available (handles React batching/timing issues)
180
- if (result.success && imageSrc && imageSrc !== '') {
181
- // Upload already complete - imageSrc was set before we entered waiting state
182
- setUploadStatus(UPLOAD_STATUS.IDLE);
183
- if (onUploadStateChange) {
184
- onUploadStateChange(false);
185
- }
186
- } else if (result.success) {
187
- // Transition to waiting state - we've triggered the upload, now wait for imageSrc
188
- setUploadStatus(UPLOAD_STATUS.WAITING);
189
- } else {
190
- // Upload failed
191
- setUploadStatus(UPLOAD_STATUS.IDLE);
192
- if (onUploadStateChange) {
193
- onUploadStateChange(false);
194
- }
195
- }
196
-
197
- return result;
198
- }, [formatMessage, uploadAsset, fileNamePrefix, imgSize, allowedContentTypes, onUploadStateChange, imageSrc]);
199
-
200
- /**
201
- * Handle image URL change
202
- * Validates URL and triggers upload on success
203
- */
204
- const handleImageUrlChange = useCallback(async (e) => {
205
- const url = e.target.value;
206
- const trimmedUrl = url?.trim() || '';
207
-
208
- // Reset upload status when URL changes
209
- setUploadStatus(UPLOAD_STATUS.IDLE);
210
-
211
- // Call parent's onUrlChange if provided
212
- if (onUrlChange) {
213
- onUrlChange(url);
214
- }
215
-
216
- if (trimmedUrl !== '') {
217
- // Notify parent that validation is starting
218
- if (onValidationStateChange) {
219
- onValidationStateChange(true);
220
- }
221
-
222
- const validation = await validateImageUrl(trimmedUrl);
223
-
224
- // Notify parent that validation is complete
225
- if (onValidationStateChange) {
226
- onValidationStateChange(false);
227
- }
228
-
229
- if (!validation.isValid) {
230
- setError(validation.error);
231
- if (onUploadStateChange) {
232
- onUploadStateChange(false);
233
- }
234
- } else {
235
- setError('');
236
- // Upload image from URL when validation succeeds
237
- const uploadResult = await uploadImageFromUrl(trimmedUrl);
238
- if (!uploadResult.success) {
239
- setError(uploadResult.error);
240
- if (onUploadStateChange) {
241
- onUploadStateChange(false);
242
- }
243
- }
244
- }
245
- } else {
246
- setError('');
247
- if (onValidationStateChange) {
248
- onValidationStateChange(false);
249
- }
250
- if (onUploadStateChange) {
251
- onUploadStateChange(false);
252
- }
253
- }
254
- }, [validateImageUrl, uploadImageFromUrl, onUrlChange, onValidationStateChange, onUploadStateChange]);
255
-
256
- /**
257
- * Monitor upload status and imageSrc to detect when upload is complete
258
- * Handles React batching and timing issues by checking state transitions
259
- */
260
- useEffect(() => {
261
- if ((uploadStatus === UPLOAD_STATUS.UPLOADING || uploadStatus === UPLOAD_STATUS.WAITING) && imageSrc && imageSrc !== '') {
262
- // Upload is complete - we have the secure file path
263
- setUploadStatus(UPLOAD_STATUS.IDLE);
264
-
265
- // Notify parent that upload is complete
266
- if (onUploadStateChange) {
267
- onUploadStateChange(false);
268
- }
269
- }
270
- }, [uploadStatus, imageSrc, onUploadStateChange]);
271
-
272
- // Determine if we should show "uploading" state
273
- // Show uploading when:
274
- // 1. Internal upload is in progress, OR
275
- // 2. External upload is in progress (from parent's redux), OR
276
- // 3. State machine indicates we're uploading or waiting for completion
277
- const isActuallyUploading = isInternalUploading || isExternalUploading || uploadStatus !== UPLOAD_STATUS.IDLE;
278
-
279
- return (
280
- <div className={`cap-image-url-upload ${className}`}>
281
- <CapInput
282
- className="image-url-input"
283
- placeholder={placeholder || formatMessage(messages.imageUrlPlaceholder)}
284
- value={imageUrl}
285
- onChange={handleImageUrlChange}
286
- size="default"
287
- errorMessage={
288
- error && (
289
- <CapError className="image-url-error">
290
- {error}
291
- </CapError>
292
- )
293
- }
294
- disabled={disabled || isValidating || isActuallyUploading}
295
- />
296
-
297
- {isValidating && (
298
- <CapLabel type="label2" className="validation-label">
299
- <FormattedMessage {...messages.validatingUrl} />
300
- </CapLabel>
301
- )}
302
-
303
- {isActuallyUploading && !isValidating && (
304
- <CapLabel type="label2" className="uploading-label">
305
- <FormattedMessage {...messages.uploadingImage} />
306
- </CapLabel>
307
- )}
308
-
309
- <div className="webpush-image-specs">
310
- {recommendedDimensions?.length > 0 && (
311
- <CapHeadingSpan type="label2" className="image-dimension">
312
- <FormattedMessage
313
- {...messages.recommendedDimensions}
314
- values={{
315
- dimensions: recommendedDimensions
316
- .map((dim) => `${dim.width} x ${dim.height}px`)
317
- .join(', '),
318
- }}
319
- />
320
- </CapHeadingSpan>
321
- )}
322
-
323
- {sizeLabel && (
324
- <CapHeadingSpan type="label2" className="image-size">
325
- {sizeLabel}
326
- </CapHeadingSpan>
327
- )}
328
-
329
- {formatLabel && (
330
- <CapHeadingSpan type="label2" className="image-format">
331
- {formatLabel}
332
- </CapHeadingSpan>
333
- )}
334
- </div>
335
- </div>
336
- );
337
- }
338
-
339
- CapImageUrlUpload.propTypes = {
340
- intl: intlShape.isRequired,
341
- uploadAsset: PropTypes.func.isRequired,
342
- imgSize: PropTypes.number,
343
- allowedContentTypes: PropTypes.arrayOf(PropTypes.string),
344
- recommendedDimensions: PropTypes.arrayOf(
345
- PropTypes.shape({
346
- width: PropTypes.number.isRequired,
347
- height: PropTypes.number.isRequired,
348
- })
349
- ),
350
- sizeLabel: PropTypes.string,
351
- formatLabel: PropTypes.string,
352
- imageUrl: PropTypes.string,
353
- imageSrc: PropTypes.string, // Secure file path from parent after upload completes
354
- onUrlChange: PropTypes.func,
355
- onValidationStateChange: PropTypes.func, // Callback(isValidating: bool)
356
- onUploadStateChange: PropTypes.func, // Callback(isUploading: bool)
357
- isExternalUploading: PropTypes.bool, // Upload state from parent (e.g., redux)
358
- className: PropTypes.string,
359
- placeholder: PropTypes.string,
360
- disabled: PropTypes.bool,
361
- fileNamePrefix: PropTypes.string,
362
- };
363
-
364
- export default injectIntl(CapImageUrlUpload);
365
-
@@ -1,35 +0,0 @@
1
- @import '~@capillarytech/cap-ui-library/styles/_variables.scss';
2
-
3
- @mixin cap-image-url-spec-text {
4
- .image-dimension,
5
- .image-size,
6
- .image-format {
7
- color: $CAP_G01;
8
- }
9
- }
10
-
11
- .cap-image-url-upload {
12
- .image-url-input {
13
- width: 100%;
14
- }
15
-
16
- .validation-label,
17
- .uploading-label {
18
- margin-top: $CAP_SPACE_08;
19
- }
20
-
21
- .image-url-error {
22
- margin-top: $CAP_SPACE_04;
23
- }
24
-
25
- .webpush-image-specs {
26
- @include cap-image-url-spec-text;
27
- }
28
-
29
- .webpush-container & {
30
- .webpush-image-specs {
31
- @include cap-image-url-spec-text;
32
- }
33
- }
34
- }
35
-
@@ -1,47 +0,0 @@
1
- import { defineMessages } from 'react-intl';
2
-
3
- const scope = 'app.v2Components.CapImageUrlUpload';
4
-
5
- export default defineMessages({
6
- imageUrlPlaceholder: {
7
- id: `${scope}.imageUrlPlaceholder`,
8
- defaultMessage: 'Enter image URL',
9
- },
10
- imageUrlInvalid: {
11
- id: `${scope}.imageUrlInvalid`,
12
- defaultMessage: 'Please enter a valid image URL',
13
- },
14
- imageTypeInvalid: {
15
- id: `${scope}.imageTypeInvalid`,
16
- defaultMessage: 'Invalid image type. Only JPEG, JPG, and PNG formats are allowed',
17
- },
18
- imageSizeInvalid: {
19
- id: `${scope}.imageSizeInvalid`,
20
- defaultMessage: 'Image size exceeds the maximum limit',
21
- },
22
- imageLoadError: {
23
- id: `${scope}.imageLoadError`,
24
- defaultMessage: 'Failed to load image. Please check the URL and try again',
25
- },
26
- validatingUrl: {
27
- id: `${scope}.validatingUrl`,
28
- defaultMessage: 'Validating image URL...',
29
- },
30
- uploadingImage: {
31
- id: `${scope}.uploadingImage`,
32
- defaultMessage: 'Uploading image to gallery...',
33
- },
34
- recommendedDimensions: {
35
- id: `${scope}.recommendedDimensions`,
36
- defaultMessage: 'Recommended dimensions: {dimensions}',
37
- },
38
- sizeLimit: {
39
- id: `${scope}.sizeLimit`,
40
- defaultMessage: 'Size up to: {size}',
41
- },
42
- formatTypes: {
43
- id: `${scope}.formatTypes`,
44
- defaultMessage: 'Format: {formats}',
45
- },
46
- });
47
-