cap-creatives-ui 8.0.280 → 8.0.321

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 (247) hide show
  1. package/.github/workflows/pr-title-check.yml +88 -0
  2. package/app/constants/unified.js +21 -1
  3. package/app/containers/App/constants.js +0 -1
  4. package/app/containers/Login/test/index.test.js +123 -0
  5. package/app/containers/Login/test/selectors.test.js +165 -0
  6. package/app/initialState.js +0 -2
  7. package/app/services/api.js +6 -0
  8. package/app/services/tests/api.test.js +7 -0
  9. package/app/services/tests/getSchema.test.js +95 -0
  10. package/app/utils/common.js +23 -9
  11. package/app/utils/commonUtils.js +64 -93
  12. package/app/utils/tagValidations.js +83 -219
  13. package/app/utils/templateVarUtils.js +172 -0
  14. package/app/utils/tests/common.test.js +265 -323
  15. package/app/utils/tests/commonUtil.test.js +461 -118
  16. package/app/utils/tests/commonUtils.test.js +581 -0
  17. package/app/utils/tests/messageUtils.test.js +95 -0
  18. package/app/utils/tests/smsCharCount.test.js +304 -0
  19. package/app/utils/tests/smsCharCountV2.test.js +213 -10
  20. package/app/utils/tests/tagValidations.test.js +474 -357
  21. package/app/utils/tests/templateVarUtils.test.js +160 -0
  22. package/app/v2Components/CapDeviceContent/index.js +10 -7
  23. package/app/v2Components/CapTagList/index.js +32 -24
  24. package/app/v2Components/CapTagList/style.scss +48 -0
  25. package/app/v2Components/CapTagListWithInput/__tests__/CapTagListWithInput.test.js +63 -0
  26. package/app/v2Components/CapTagListWithInput/index.js +8 -0
  27. package/app/v2Components/CapWhatsappCTA/index.js +2 -0
  28. package/app/v2Components/CapWhatsappCarouselButton/index.js +32 -14
  29. package/app/v2Components/CapWhatsappCarouselButton/tests/index.test.js +120 -2
  30. package/app/v2Components/CommonTestAndPreview/CustomValuesEditor.js +70 -49
  31. package/app/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +39 -0
  32. package/app/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +606 -0
  33. package/app/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.scss +36 -0
  34. package/app/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +79 -0
  35. package/app/v2Components/CommonTestAndPreview/DeliverySettings/index.js +314 -0
  36. package/app/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +141 -0
  37. package/app/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +156 -0
  38. package/app/v2Components/CommonTestAndPreview/SendTestMessage.js +57 -1
  39. package/app/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +20 -1
  40. package/app/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +133 -4
  41. package/app/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +210 -4
  42. package/app/v2Components/CommonTestAndPreview/actions.js +20 -0
  43. package/app/v2Components/CommonTestAndPreview/constants.js +57 -1
  44. package/app/v2Components/CommonTestAndPreview/index.js +878 -156
  45. package/app/v2Components/CommonTestAndPreview/messages.js +41 -3
  46. package/app/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
  47. package/app/v2Components/CommonTestAndPreview/reducer.js +47 -0
  48. package/app/v2Components/CommonTestAndPreview/sagas.js +75 -5
  49. package/app/v2Components/CommonTestAndPreview/selectors.js +51 -0
  50. package/app/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +352 -0
  51. package/app/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +1156 -0
  52. package/app/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +334 -0
  53. package/app/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +576 -0
  54. package/app/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +156 -0
  55. package/app/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +199 -1
  56. package/app/v2Components/CommonTestAndPreview/tests/actions.test.js +50 -0
  57. package/app/v2Components/CommonTestAndPreview/tests/constants.test.js +18 -7
  58. package/app/v2Components/CommonTestAndPreview/tests/index.test.js +914 -5
  59. package/app/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
  60. package/app/v2Components/CommonTestAndPreview/tests/reducer.test.js +118 -0
  61. package/app/v2Components/CommonTestAndPreview/tests/sagas.test.js +146 -378
  62. package/app/v2Components/CommonTestAndPreview/tests/selectors.test.js +146 -0
  63. package/app/v2Components/ErrorInfoNote/index.js +24 -26
  64. package/app/v2Components/FormBuilder/index.js +182 -204
  65. package/app/v2Components/FormBuilder/messages.js +4 -8
  66. package/app/v2Components/HtmlEditor/HTMLEditor.js +7 -6
  67. package/app/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -1
  68. package/app/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +928 -17
  69. package/app/v2Components/HtmlEditor/components/CodeEditorPane/index.js +4 -2
  70. package/app/v2Components/HtmlEditor/hooks/__tests__/useValidation.test.js +452 -3
  71. package/app/v2Components/HtmlEditor/hooks/useValidation.js +12 -9
  72. package/app/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +132 -0
  73. package/app/v2Components/HtmlEditor/utils/htmlValidator.js +4 -2
  74. package/app/v2Components/SmsFallback/SmsFallbackLocalSelector.js +87 -0
  75. package/app/v2Components/SmsFallback/constants.js +73 -0
  76. package/app/v2Components/SmsFallback/index.js +956 -0
  77. package/app/v2Components/SmsFallback/index.scss +265 -0
  78. package/app/v2Components/SmsFallback/messages.js +78 -0
  79. package/app/v2Components/SmsFallback/smsFallbackUtils.js +107 -0
  80. package/app/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +50 -0
  81. package/app/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +147 -0
  82. package/app/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +304 -0
  83. package/app/v2Components/SmsFallback/tests/smsFallbackUi.test.js +197 -0
  84. package/app/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +261 -0
  85. package/app/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +422 -0
  86. package/app/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
  87. package/app/v2Components/TestAndPreviewSlidebox/index.js +22 -1
  88. package/app/v2Components/TestAndPreviewSlidebox/sagas.js +11 -4
  89. package/app/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +3 -1
  90. package/app/v2Components/VarSegmentMessageEditor/constants.js +2 -0
  91. package/app/v2Components/VarSegmentMessageEditor/index.js +125 -0
  92. package/app/v2Components/VarSegmentMessageEditor/index.scss +46 -0
  93. package/app/v2Containers/BeeEditor/index.js +3 -0
  94. package/app/v2Containers/BeePopupEditor/index.js +9 -2
  95. package/app/v2Containers/Cap/mockData.js +0 -14
  96. package/app/v2Containers/Cap/reducer.js +3 -55
  97. package/app/v2Containers/Cap/tests/reducer.test.js +0 -102
  98. package/app/v2Containers/CommunicationFlow/CommunicationFlow.js +291 -0
  99. package/app/v2Containers/CommunicationFlow/CommunicationFlow.scss +25 -0
  100. package/app/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +255 -0
  101. package/app/v2Containers/CommunicationFlow/constants.js +200 -0
  102. package/app/v2Containers/CommunicationFlow/index.js +102 -0
  103. package/app/v2Containers/CommunicationFlow/messages.js +346 -0
  104. package/app/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.js +522 -0
  105. package/app/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.scss +170 -0
  106. package/app/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/Tests/ChannelSelectionStep.test.js +796 -0
  107. package/app/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/index.js +5 -0
  108. package/app/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/CommunicationStrategyStep.js +95 -0
  109. package/app/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/Tests/CommunicationStrategyStep.test.js +133 -0
  110. package/app/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/index.js +5 -0
  111. package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.js +289 -0
  112. package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.scss +70 -0
  113. package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.js +319 -0
  114. package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.scss +69 -0
  115. package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +616 -0
  116. package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +577 -0
  117. package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/deliverySettingsConfig.test.js +1111 -0
  118. package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/deliverySettingsConfig.js +696 -0
  119. package/app/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/index.js +7 -0
  120. package/app/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.js +102 -0
  121. package/app/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.scss +36 -0
  122. package/app/v2Containers/CommunicationFlow/steps/DynamicControlsStep/Tests/DynamicControlsStep.test.js +91 -0
  123. package/app/v2Containers/CommunicationFlow/steps/DynamicControlsStep/index.js +5 -0
  124. package/app/v2Containers/CommunicationFlow/steps/MessageTypeStep/MessageTypeStep.js +86 -0
  125. package/app/v2Containers/CommunicationFlow/steps/MessageTypeStep/Tests/MessageTypeStep.test.js +100 -0
  126. package/app/v2Containers/CommunicationFlow/steps/MessageTypeStep/index.js +5 -0
  127. package/app/v2Containers/CommunicationFlow/utils/getEnabledSteps.js +30 -0
  128. package/app/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +43 -0
  129. package/app/v2Containers/CreativesContainer/SlideBoxContent.js +127 -11
  130. package/app/v2Containers/CreativesContainer/SlideBoxFooter.js +62 -9
  131. package/app/v2Containers/CreativesContainer/SlideBoxHeader.js +29 -4
  132. package/app/v2Containers/CreativesContainer/constants.js +24 -0
  133. package/app/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +67 -0
  134. package/app/v2Containers/CreativesContainer/index.js +346 -71
  135. package/app/v2Containers/CreativesContainer/index.scss +51 -1
  136. package/app/v2Containers/CreativesContainer/messages.js +12 -0
  137. package/app/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
  138. package/app/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +69 -1
  139. package/app/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +443 -0
  140. package/app/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +110 -0
  141. package/app/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +147 -4
  142. package/app/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +363 -0
  143. package/app/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +57 -10
  144. package/app/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
  145. package/app/v2Containers/CreativesContainer/tests/index.test.js +71 -9
  146. package/app/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +125 -0
  147. package/app/v2Containers/Email/index.js +2 -5
  148. package/app/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +58 -77
  149. package/app/v2Containers/EmailWrapper/components/EmailWrapperView.js +3 -0
  150. package/app/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +158 -89
  151. package/app/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +16 -1
  152. package/app/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +17 -12
  153. package/app/v2Containers/EmailWrapper/index.js +4 -0
  154. package/app/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +1 -0
  155. package/app/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +133 -0
  156. package/app/v2Containers/FTP/index.js +2 -51
  157. package/app/v2Containers/FTP/messages.js +0 -4
  158. package/app/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +110 -155
  159. package/app/v2Containers/InApp/index.js +297 -118
  160. package/app/v2Containers/InApp/tests/index.test.js +17 -6
  161. package/app/v2Containers/InApp/tests/mockData.js +1 -1
  162. package/app/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +19 -0
  163. package/app/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +3 -0
  164. package/app/v2Containers/InAppWrapper/index.js +3 -0
  165. package/app/v2Containers/InappAdvance/index.js +5 -104
  166. package/app/v2Containers/InappAdvance/tests/index.test.js +2 -0
  167. package/app/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +24 -3
  168. package/app/v2Containers/Line/Container/Text/index.js +0 -1
  169. package/app/v2Containers/MobilePush/Create/index.js +105 -28
  170. package/app/v2Containers/MobilePush/Create/messages.js +4 -0
  171. package/app/v2Containers/MobilePush/Edit/index.js +250 -68
  172. package/app/v2Containers/MobilePush/Edit/messages.js +4 -0
  173. package/app/v2Containers/MobilePushNew/components/PlatformContentFields.js +36 -12
  174. package/app/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +68 -27
  175. package/app/v2Containers/MobilePushNew/index.js +78 -35
  176. package/app/v2Containers/MobilePushNew/messages.js +8 -0
  177. package/app/v2Containers/MobilepushWrapper/index.js +11 -1
  178. package/app/v2Containers/Rcs/constants.js +32 -1
  179. package/app/v2Containers/Rcs/index.js +963 -916
  180. package/app/v2Containers/Rcs/index.scss +85 -6
  181. package/app/v2Containers/Rcs/messages.js +10 -1
  182. package/app/v2Containers/Rcs/rcsLibraryHydrationUtils.js +205 -0
  183. package/app/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +41136 -1566
  184. package/app/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +0 -5
  185. package/app/v2Containers/Rcs/tests/index.test.js +41 -38
  186. package/app/v2Containers/Rcs/tests/mockData.js +38 -0
  187. package/app/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +251 -0
  188. package/app/v2Containers/Rcs/tests/utils.test.js +379 -1
  189. package/app/v2Containers/Rcs/utils.js +358 -10
  190. package/app/v2Containers/Sms/Create/index.js +122 -39
  191. package/app/v2Containers/Sms/Create/messages.js +4 -0
  192. package/app/v2Containers/Sms/Edit/index.js +37 -3
  193. package/app/v2Containers/Sms/commonMethods.js +3 -6
  194. package/app/v2Containers/Sms/smsFormDataHelpers.js +67 -0
  195. package/app/v2Containers/Sms/tests/commonMethods.test.js +122 -0
  196. package/app/v2Containers/Sms/tests/smsFormDataHelpers.test.js +253 -0
  197. package/app/v2Containers/SmsTrai/Create/index.js +9 -4
  198. package/app/v2Containers/SmsTrai/Create/index.scss +1 -1
  199. package/app/v2Containers/SmsTrai/Edit/constants.js +2 -0
  200. package/app/v2Containers/SmsTrai/Edit/index.js +667 -160
  201. package/app/v2Containers/SmsTrai/Edit/index.scss +121 -0
  202. package/app/v2Containers/SmsTrai/Edit/messages.js +9 -4
  203. package/app/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4590 -2436
  204. package/app/v2Containers/SmsWrapper/index.js +41 -8
  205. package/app/v2Containers/TagList/index.js +63 -2
  206. package/app/v2Containers/TagList/messages.js +8 -0
  207. package/app/v2Containers/TagList/tests/TagList.test.js +122 -20
  208. package/app/v2Containers/TagList/tests/mockdata.js +17 -0
  209. package/app/v2Containers/Templates/TemplatesActionBar.js +101 -0
  210. package/app/v2Containers/Templates/_templates.scss +61 -2
  211. package/app/v2Containers/Templates/actions.js +11 -0
  212. package/app/v2Containers/Templates/constants.js +2 -0
  213. package/app/v2Containers/Templates/index.js +90 -40
  214. package/app/v2Containers/Templates/reducer.js +3 -1
  215. package/app/v2Containers/Templates/sagas.js +57 -12
  216. package/app/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
  217. package/app/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1043 -1079
  218. package/app/v2Containers/Templates/tests/reducer.test.js +12 -0
  219. package/app/v2Containers/Templates/tests/sagas.test.js +193 -12
  220. package/app/v2Containers/Templates/tests/smsTemplatesListApi.test.js +180 -0
  221. package/app/v2Containers/Templates/utils/smsTemplatesListApi.js +79 -0
  222. package/app/v2Containers/TemplatesV2/TemplatesV2.style.js +72 -1
  223. package/app/v2Containers/TemplatesV2/index.js +147 -49
  224. package/app/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +131 -0
  225. package/app/v2Containers/Viber/index.js +9 -10
  226. package/app/v2Containers/Viber/index.scss +1 -1
  227. package/app/v2Containers/WebPush/Create/components/BrandIconSection.test.js +264 -0
  228. package/app/v2Containers/WebPush/Create/components/MessageSection.js +78 -19
  229. package/app/v2Containers/WebPush/Create/components/MessageSection.test.js +82 -0
  230. package/app/v2Containers/WebPush/Create/components/__snapshots__/BrandIconSection.test.js.snap +187 -0
  231. package/app/v2Containers/WebPush/Create/components/__snapshots__/MessageSection.test.js.snap +25 -17
  232. package/app/v2Containers/WebPush/Create/hooks/useAiraTriggerPosition.js +80 -0
  233. package/app/v2Containers/WebPush/Create/hooks/useAiraTriggerPosition.test.js +210 -0
  234. package/app/v2Containers/WebPush/Create/hooks/useTagManagement.js +1 -5
  235. package/app/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +0 -7
  236. package/app/v2Containers/WebPush/Create/index.js +36 -6
  237. package/app/v2Containers/WebPush/Create/index.scss +5 -0
  238. package/app/v2Containers/WebPush/Create/messages.js +8 -1
  239. package/app/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +269 -0
  240. package/app/v2Containers/WebPush/Create/utils/validation.js +31 -15
  241. package/app/v2Containers/WebPush/Create/utils/validation.test.js +72 -24
  242. package/app/v2Containers/Whatsapp/index.js +28 -53
  243. package/app/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +26939 -3982
  244. package/app/v2Containers/Whatsapp/tests/index.test.js +172 -0
  245. package/app/v2Containers/Zalo/index.js +5 -11
  246. package/package.json +2 -2
  247. package/version +9 -0
@@ -1,9 +1,5 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import {
4
- CAP_SPACE_16, CAP_SPACE_32, CAP_SPACE_56, CAP_SPACE_64,
5
- } from '@capillarytech/cap-ui-library/styled/variables';
6
-
7
3
  import CapSlideBox from '@capillarytech/cap-ui-library/CapSlideBox';
8
4
  import CapHeader from '@capillarytech/cap-ui-library/CapHeader';
9
5
  import CapRow from '@capillarytech/cap-ui-library/CapRow';
@@ -13,12 +9,11 @@ import CapNotification from '@capillarytech/cap-ui-library/CapNotification';
13
9
  import { injectIntl, FormattedMessage } from 'react-intl';
14
10
  import classnames from 'classnames';
15
11
  import {
16
- isEmpty, get, forEach, cloneDeep, debounce,
12
+ isEmpty, get, forEach, cloneDeep, debounce, pick,
17
13
  } from 'lodash';
18
14
  import { connect } from 'react-redux';
19
15
  import { createStructuredSelector } from 'reselect';
20
16
  import { bindActionCreators, compose } from 'redux';
21
- import styled from 'styled-components';
22
17
  import { GA } from '@capillarytech/cap-ui-utils';
23
18
  import { DAEMON } from '@capillarytech/vulcan-react-sdk/utils/sagaInjectorTypes';
24
19
 
@@ -47,6 +42,8 @@ import {
47
42
  import {EXTERNAL_URL, SITE_URL, WEBPUSH_MEDIA_TYPES} from '../WebPush/constants';
48
43
  import { IMAGE, VIDEO } from '../Facebook/Advertisement/constant';
49
44
  import { RCS_STATUSES } from '../Rcs/constants';
45
+ import { mapRcsCardContentForConsumerWithResolvedTags } from '../Rcs/utils';
46
+ import { RCS_SMS_FALLBACK_VAR_MAPPED_PROP } from '../../v2Components/CommonTestAndPreview/constants';
50
47
  import { CREATIVE } from '../Facebook/constants';
51
48
  import { LOYALTY } from '../App/constants';
52
49
  import {
@@ -61,6 +58,11 @@ import { capSagaForFetchSchemaForEntity, capSagaLiquidEntity } from '../Cap/saga
61
58
  import { v2TemplateSagaWatchGetDefaultBeeTemplates } from '../Templates/sagas';
62
59
  import { DYNAMIC_URL } from '../../v2Components/CapWhatsappCTA/constants';
63
60
  import ErrorInfoNote from '../../v2Components/ErrorInfoNote';
61
+ import SlideBoxWrapper from './CreativesSlideBoxWrapper';
62
+ import {
63
+ computeLiquidFooterUpdateFromFormBuilder,
64
+ getSlideBoxWrapperMarginFromLiquidErrors,
65
+ } from './embeddedSlideboxUtils';
64
66
 
65
67
  import {
66
68
  transformChannelPayload,
@@ -72,31 +74,21 @@ import { BIG_HTML } from '../InApp/constants';
72
74
  const classPrefix = 'add-creatives-section';
73
75
  const CREATIVES_CONTAINER = 'creativesContainer';
74
76
 
75
- const SlideBoxWrapper = styled.div`
76
- .cap-slide-box-v2-container{
77
- .slidebox-header, .slidebox-content-container{
78
- margin-bottom: ${({ slideBoxWrapperMargin }) => `${slideBoxWrapperMargin}`};
79
- padding: 0 rem;
80
- &.has-footer{
81
- overflow-x: hidden;
82
- }
83
- }
84
- .slidebox-footer{
85
- /* Only apply margin-bottom to footer when ErrorInfoNote is shown in footer (BEE editor) */
86
- /* For HTML Editor, errors are shown in ValidationErrorDisplay (inside content area), so no footer margin needed */
87
- margin-bottom: ${({ shouldApplyFooterMargin }) => (shouldApplyFooterMargin ? `${CAP_SPACE_16}` : '0')};
88
- padding: 0 rem;
89
- &.has-footer{
90
- overflow-x: hidden;
91
- }
92
- }
93
- }
94
- `;
95
77
  export class Creatives extends React.Component {
96
78
  constructor(props) {
97
79
  super(props);
98
80
 
99
- const initialSlidBoxContent = this.getSlideBoxContent({ mode: props.creativesMode, templateData: props.templateData, isFullMode: props.isFullMode });
81
+ const useLocalTemplates = get(
82
+ props,
83
+ 'localTemplatesConfig.useLocalTemplates',
84
+ get(props, 'useLocalTemplates', false),
85
+ );
86
+ const initialSlidBoxContent = this.getSlideBoxContent({
87
+ mode: props.creativesMode,
88
+ templateData: props.templateData,
89
+ isFullMode: props.isFullMode,
90
+ useLocalTemplates,
91
+ });
100
92
 
101
93
  this.state = {
102
94
  isLoadingContent: true,
@@ -130,8 +122,8 @@ export class Creatives extends React.Component {
130
122
  validationComplete: false, // Flag to track if validation has completed
131
123
  errorsAcknowledged: false, // Flag to track if user has acknowledged errors by clicking redirection icon
132
124
  },
125
+ hasPersonalizationTokenError: false, // Track personalization token errors in form
133
126
  };
134
- this.liquidFlow = Boolean(commonUtil.hasLiquidSupportFeature());
135
127
  this.creativesTemplateSteps = {
136
128
  1: 'modeSelection',
137
129
  2: 'templateSelection', // only for email in current flows wil be used for mpush, line and wechat as well.
@@ -143,7 +135,13 @@ export class Creatives extends React.Component {
143
135
  }
144
136
 
145
137
  componentWillUnmount() {
146
- if (get(this.props, 'location.query.type', '') === "embedded") {
138
+ const isEmbedded = get(this.props, 'location.query.type', '') === "embedded";
139
+ const useLocalTemplates = get(
140
+ this.props,
141
+ 'localTemplatesConfig.useLocalTemplates',
142
+ get(this.props, 'useLocalTemplates', false),
143
+ );
144
+ if (isEmbedded && !useLocalTemplates) {
147
145
  this.props.templateActions.resetTemplateStoreData();
148
146
  }
149
147
  this.props.globalActions.clearMetaEntities();
@@ -255,12 +253,23 @@ export class Creatives extends React.Component {
255
253
  };
256
254
 
257
255
  onShowTemplates = () => {
258
- this.setState({ slidBoxContent: 'templates', showSlideBox: true, isGetFormData: false });
256
+ this.setState({
257
+ slidBoxContent: 'templates',
258
+ showSlideBox: true,
259
+ isGetFormData: false,
260
+ liquidErrorMessage: { STANDARD_ERROR_MSG: [], LIQUID_ERROR_MSG: [] },
261
+ isLiquidValidationError: false,
262
+ });
259
263
  this.resetStep();
260
264
  };
261
265
 
262
266
  onChannelChange = (channel) => {
263
- this.setState({ currentChannel: channel, templateData: null });
267
+ this.setState({
268
+ currentChannel: channel,
269
+ templateData: null,
270
+ liquidErrorMessage: { STANDARD_ERROR_MSG: [], LIQUID_ERROR_MSG: [] },
271
+ isLiquidValidationError: false,
272
+ });
264
273
  }
265
274
 
266
275
  onCreateNextStep = () => {
@@ -734,14 +743,41 @@ export class Creatives extends React.Component {
734
743
  smsFallBackContent = {},
735
744
  creativeName = "",
736
745
  channel = constants.RCS,
746
+ rcsCardVarMapped,
737
747
  } = templateData || {};
738
- const cardContent = (rcsContent.cardContent && rcsContent.cardContent[0]) || {};
748
+ const { isFullMode: isFullModeForRcsPayload } = this.props;
749
+ const firstCardIn = (rcsContent.cardContent && rcsContent.cardContent[0]) || {};
750
+ const {
751
+ cardDisplayTitle: _omitDispTitleIn,
752
+ cardDisplayDescription: _omitDispDescIn,
753
+ ...cardContent
754
+ } = firstCardIn;
739
755
  const Status = RCS_STATUSES.approved || '';
756
+ const mergedCardVarMapped = (() => {
757
+ const nestedCardVarMapped = cardContent?.cardVarMapped;
758
+ const rootMirrorCardVarMapped = rcsCardVarMapped;
759
+ const nestedRecord =
760
+ nestedCardVarMapped != null && typeof nestedCardVarMapped === 'object'
761
+ ? nestedCardVarMapped
762
+ : {};
763
+ const rootRecord =
764
+ rootMirrorCardVarMapped != null && typeof rootMirrorCardVarMapped === 'object'
765
+ ? rootMirrorCardVarMapped
766
+ : {};
767
+ const mergedFromRootAndNested = { ...rootRecord, ...nestedRecord };
768
+ return Object.keys(mergedFromRootAndNested).length > 0 ? mergedFromRootAndNested : null;
769
+ })();
770
+ // Campaigns (embedded): do not duplicate `cardVarMapped` as root `rcsCardVarMapped` on send —
771
+ // slot map stays on `versions…cardContent[0].cardVarMapped` only. Library full mode keeps root mirror.
772
+ // Use `=== true` so omitted/undefined `isFullMode` does not behave like library (avoids duplicate on approval payload).
773
+ const includeRootRcsCardVarMapped =
774
+ mergedCardVarMapped && isFullModeForRcsPayload === true;
740
775
 
741
776
  creativesTemplateData = {
742
777
  type: channel,
743
778
  edit: true,
744
779
  name: creativeName,
780
+ ...(includeRootRcsCardVarMapped ? { rcsCardVarMapped: mergedCardVarMapped } : {}),
745
781
  versions: {
746
782
  base: {
747
783
  content: {
@@ -751,6 +787,7 @@ export class Creatives extends React.Component {
751
787
  cardContent: [
752
788
  {
753
789
  ...cardContent,
790
+ ...(mergedCardVarMapped ? { cardVarMapped: mergedCardVarMapped } : {}),
754
791
  Status,
755
792
  },
756
793
  ],
@@ -901,7 +938,10 @@ export class Creatives extends React.Component {
901
938
  return newExpandableDetails;
902
939
  }
903
940
 
904
- getCreativesData = async (channel, template, templateRecords) => { //from creatives to consumers
941
+ getCreativesData = async (channelParam, template, templateRecords) => { //from creatives to consumers
942
+ const channel = String(
943
+ channelParam || template?.type || get(template, 'value.type') || '',
944
+ ).toUpperCase();
905
945
  let templateData = { channel };
906
946
  switch (channel) {
907
947
  case constants.SMS:
@@ -1243,26 +1283,101 @@ export class Creatives extends React.Component {
1243
1283
  break;
1244
1284
  case constants.RCS: {
1245
1285
  if (template.value) {
1246
- const { name = "", versions = {} } = {
1247
- } = template.value || {};
1248
- const smsFallBackContent = get(versions, 'base.content.RCS.smsFallBackContent', {});
1286
+ const { isFullMode: isFullModeForRcsConsumerPayload } = this.props;
1287
+ const { name = "", versions = {} } = template.value || {};
1288
+ const fromSubmit = get(versions, 'base.content.RCS.smsFallBackContent', {});
1289
+ const fromRecords = {
1290
+ ...(templateRecords?.smsFallBackContent || {}),
1291
+ ...(get(templateRecords, 'versions.base.content.RCS.smsFallBackContent') || {}),
1292
+ };
1293
+ const hasMeaningfulRcsSmsFallback = (smsFallbackPayload) => {
1294
+ if (
1295
+ !smsFallbackPayload
1296
+ || typeof smsFallbackPayload !== 'object'
1297
+ || Object.keys(smsFallbackPayload).length === 0
1298
+ ) {
1299
+ return false;
1300
+ }
1301
+ const fallbackBodyText = String(
1302
+ smsFallbackPayload.smsContent
1303
+ ?? smsFallbackPayload.smsTemplateContent
1304
+ ?? smsFallbackPayload.message
1305
+ ?? smsFallbackPayload.content
1306
+ ?? '',
1307
+ ).trim();
1308
+ const fallbackTemplateName = String(
1309
+ smsFallbackPayload.smsTemplateName ?? smsFallbackPayload.templateName ?? '',
1310
+ ).trim();
1311
+ const rcsSmsFallbackVarMapped =
1312
+ smsFallbackPayload?.[RCS_SMS_FALLBACK_VAR_MAPPED_PROP];
1313
+ const hasVarMappedEntries =
1314
+ rcsSmsFallbackVarMapped != null
1315
+ && typeof rcsSmsFallbackVarMapped === 'object'
1316
+ && Object.keys(rcsSmsFallbackVarMapped).length > 0;
1317
+ return (
1318
+ fallbackBodyText !== ''
1319
+ || fallbackTemplateName !== ''
1320
+ || hasVarMappedEntries
1321
+ );
1322
+ };
1323
+ // If submit has only empty strings, do not let it wipe fallback mirrored on templateRecords (library round-trip).
1324
+ const smsFallBackContent = hasMeaningfulRcsSmsFallback(fromSubmit)
1325
+ ? { ...fromRecords, ...fromSubmit }
1326
+ : { ...fromSubmit, ...fromRecords };
1249
1327
  const {
1250
- cardContent = [],
1328
+ cardContent: cardContentFromSubmit = [],
1251
1329
  contentType = "",
1252
1330
  cardType = "",
1253
1331
  cardSettings = {},
1254
1332
  } = get(versions, 'base.content.RCS.rcsContent', {});
1333
+ const rootRcsCardVarMappedFromSubmit = get(template, 'value.rcsCardVarMapped');
1334
+ const firstCardFromSubmit = Array.isArray(cardContentFromSubmit)
1335
+ ? cardContentFromSubmit[0]
1336
+ : null;
1337
+ const cardContent = mapRcsCardContentForConsumerWithResolvedTags(
1338
+ cardContentFromSubmit,
1339
+ rootRcsCardVarMappedFromSubmit,
1340
+ isFullModeForRcsConsumerPayload,
1341
+ );
1255
1342
  const rcsContent = {
1256
1343
  contentType,
1257
1344
  cardType,
1258
1345
  cardSettings,
1259
1346
  cardContent,
1260
1347
  };
1348
+ const cardVarMappedFromFirstRcsCard =
1349
+ firstCardFromSubmit?.cardVarMapped != null
1350
+ && typeof firstCardFromSubmit.cardVarMapped === 'object'
1351
+ ? firstCardFromSubmit.cardVarMapped
1352
+ : null;
1353
+ const includeRootRcsCardVarMappedOnConsumerPayload =
1354
+ cardVarMappedFromFirstRcsCard
1355
+ && Object.keys(cardVarMappedFromFirstRcsCard).length > 0
1356
+ && isFullModeForRcsConsumerPayload === true;
1261
1357
  templateData = {
1262
1358
  channel,
1263
1359
  creativeName: name,
1264
1360
  rcsContent,
1361
+ ...(includeRootRcsCardVarMappedOnConsumerPayload
1362
+ ? { rcsCardVarMapped: cardVarMappedFromFirstRcsCard }
1363
+ : {}),
1265
1364
  };
1365
+ // Library / campaign consumers round-trip templateData via getTemplateData; include SMS fallback
1366
+ // so reopening the editor restores fallback text and tag mappings.
1367
+ // cap-campaigns-v2 API expects `smsFallBackContent.message` (see normalizeRcsMessageContentForApi).
1368
+ if (hasMeaningfulRcsSmsFallback(smsFallBackContent)) {
1369
+ const smsText =
1370
+ smsFallBackContent.message
1371
+ ?? smsFallBackContent.smsContent
1372
+ ?? smsFallBackContent.smsTemplateContent
1373
+ ?? '';
1374
+ templateData.smsFallBackContent = {
1375
+ ...smsFallBackContent,
1376
+ ...(String(smsText).trim() !== ''
1377
+ ? { message: String(smsText).trim() }
1378
+ : {}),
1379
+ };
1380
+ }
1266
1381
  }
1267
1382
  }
1268
1383
  break;
@@ -1382,7 +1497,10 @@ export class Creatives extends React.Component {
1382
1497
  return templateData;
1383
1498
  };
1384
1499
 
1385
- getSlideBoxContent({ mode, templateData, isFullMode }) {
1500
+ getSlideBoxContent({ mode, templateData, isFullMode, useLocalTemplates }) {
1501
+ if (useLocalTemplates && mode === 'create' && isEmpty(templateData)) {
1502
+ return 'templates';
1503
+ }
1386
1504
  let creativesMode = isFullMode ? 'createTemplate' : 'templates';// for library mode templates page is initial mode and for full mode createTemplates
1387
1505
  if (mode === 'create' && isFullMode) {
1388
1506
  creativesMode = 'createTemplate';
@@ -1468,25 +1586,112 @@ export class Creatives extends React.Component {
1468
1586
  }
1469
1587
 
1470
1588
  getFormData = (template) => {
1471
- if (template.validity) {
1472
- this.setState(
1473
- {
1474
- isGetFormData: false,
1475
- },
1476
- () => {
1477
- const templateData = this.state.templateData ? this.state.templateData : template; //select existing or create new content
1478
- const channel = templateData.type;
1479
- const creativesData = this.getCreativesData(channel, template, templateData);// convers data to consumer understandable format
1480
- creativesData.then((data) => {
1481
- this.logGTMEvent(channel, data);
1482
- this.processCentralCommsMetaId(channel, data);
1589
+ // Always reset isGetFormData so the child does not re-send form data on every re-render
1590
+ // (e.g. when user fixes validation error by typing, we must not auto-close the slidebox)
1591
+ this.setState(
1592
+ (prevState) => {
1593
+ const next = { isGetFormData: false };
1594
+ if (!template.validity) {
1595
+ return next;
1596
+ }
1597
+ const baseTd = prevState.templateData || template;
1598
+ const channel = (
1599
+ baseTd?.type
1600
+ || template?.type
1601
+ || get(template, 'value.type')
1602
+ || ''
1603
+ ).toUpperCase();
1604
+ // Library mode: persist last submitted creatives shape so reopening still hydrates the editor
1605
+ // (parent may not merge getCreativesData back into templateData).
1606
+ if (this.props.isFullMode === false && template.value) {
1607
+ if (channel === constants.RCS) {
1608
+ const smsFallBackFromPayload = get(
1609
+ template.value,
1610
+ 'versions.base.content.RCS.smsFallBackContent',
1611
+ );
1612
+ const rcsCardVarMappedFromPayload = get(
1613
+ template.value,
1614
+ 'versions.base.content.RCS.rcsContent.cardContent[0].cardVarMapped',
1615
+ );
1616
+ next.templateData = {
1617
+ ...baseTd,
1618
+ type: constants.RCS,
1619
+ name: template?.value?.name,
1620
+ versions: template?.value?.versions,
1621
+ ...(smsFallBackFromPayload != null
1622
+ && typeof smsFallBackFromPayload === 'object'
1623
+ && Object.keys(smsFallBackFromPayload).length > 0
1624
+ ? { smsFallBackContent: smsFallBackFromPayload }
1625
+ : {}),
1626
+ ...(rcsCardVarMappedFromPayload != null
1627
+ && typeof rcsCardVarMappedFromPayload === 'object'
1628
+ ? { rcsCardVarMapped: rcsCardVarMappedFromPayload }
1629
+ : {}),
1630
+ };
1631
+ if (template._id) {
1632
+ next.templateData._id = template._id;
1633
+ }
1634
+ } else if (channel === constants.SMS) {
1635
+ const submittedSmsTemplateValue = template?.value;
1636
+ const smsVersions =
1637
+ submittedSmsTemplateValue?.history != null
1638
+ ? submittedSmsTemplateValue
1639
+ : {
1640
+ base: submittedSmsTemplateValue?.base,
1641
+ history: submittedSmsTemplateValue?.base
1642
+ ? [submittedSmsTemplateValue.base]
1643
+ : [],
1644
+ };
1645
+ next.templateData = {
1646
+ ...baseTd,
1647
+ type: constants.SMS,
1648
+ name: baseTd?.name || 'Campaign message SMS content',
1649
+ versions: smsVersions,
1650
+ };
1651
+ if (template?._id) {
1652
+ next.templateData._id = template._id;
1653
+ }
1654
+ }
1655
+ }
1656
+ return next;
1657
+ },
1658
+ () => {
1659
+ if (!template.validity) {
1660
+ return;
1661
+ }
1662
+ const templateData = this.state.templateData ? this.state.templateData : template; //select existing or create new content
1663
+ const channelForConsumer = String(
1664
+ templateData.type
1665
+ || template.type
1666
+ || get(template, 'value.type')
1667
+ || '',
1668
+ ).toUpperCase();
1669
+ const creativesData = this.getCreativesData(
1670
+ channelForConsumer,
1671
+ template,
1672
+ this.state.templateData || template,
1673
+ );// convers data to consumer understandable format
1674
+ creativesData.then((data) => {
1675
+ this.logGTMEvent(channelForConsumer, data);
1676
+ this.processCentralCommsMetaId(channelForConsumer, data, {
1677
+ closeSlideBoxAfterSubmit: template.closeSlideBoxAfterSubmit,
1483
1678
  });
1484
- },
1485
- );
1486
- }
1679
+ });
1680
+ },
1681
+ );
1487
1682
  }
1488
1683
 
1489
- processCentralCommsMetaId = (channel, creativesData) => {
1684
+ processCentralCommsMetaId = (channel, creativesData, options = {}) => {
1685
+ const { closeSlideBoxAfterSubmit = false } = options;
1686
+ const maybeCloseLibrarySlideBox = () => {
1687
+ if (
1688
+ closeSlideBoxAfterSubmit
1689
+ && this.props.isFullMode === false
1690
+ && typeof this.handleCloseSlideBox === 'function'
1691
+ ) {
1692
+ this.handleCloseSlideBox();
1693
+ }
1694
+ };
1490
1695
  // Create the payload for the centralcommnsmetaId API call
1491
1696
  const { isLoyaltyModule = false, loyaltyMetaData = {} } = this.props;
1492
1697
  const { actionName, setMetaData = () => { } } = loyaltyMetaData;
@@ -1512,6 +1717,7 @@ export class Creatives extends React.Component {
1512
1717
  if (result?.status?.code === 200) {
1513
1718
  setMetaData(result);
1514
1719
  this.props.getCreativesData(creativesData);
1720
+ maybeCloseLibrarySlideBox();
1515
1721
  } else {
1516
1722
  CapNotification.error({ message: <FormattedMessage {...messages.somethingWentWrong} /> });
1517
1723
  }
@@ -1522,6 +1728,7 @@ export class Creatives extends React.Component {
1522
1728
  } else {
1523
1729
  // If not a loyalty module or different action, should work as usual
1524
1730
  this.props.getCreativesData(creativesData);
1731
+ maybeCloseLibrarySlideBox();
1525
1732
  }
1526
1733
  };
1527
1734
 
@@ -1554,8 +1761,12 @@ export class Creatives extends React.Component {
1554
1761
  }
1555
1762
  this.setState((prevState) => ({
1556
1763
  ...prevState,
1557
- templateData: undefined,
1764
+ // Library mode (isFullMode === false): retain last template so reopening still has RCS payload.
1765
+ // Undefined isFullMode defaults to full-mode close behavior (clear templateData).
1766
+ ...(this.props.isFullMode !== false ? { templateData: undefined } : {}),
1558
1767
  showSlideBox: false,
1768
+ liquidErrorMessage: { STANDARD_ERROR_MSG: [], LIQUID_ERROR_MSG: [] },
1769
+ isLiquidValidationError: false,
1559
1770
  }), () => this.props.handleCloseCreatives(reloadTemplates));
1560
1771
  };
1561
1772
 
@@ -1763,11 +1974,12 @@ export class Creatives extends React.Component {
1763
1974
  }
1764
1975
 
1765
1976
  showLiquidErrorInFooter = (errorMessagesFromFormBuilder, currentFormBuilderTab) => {
1766
- this.setState({
1767
- isLiquidValidationError: !isEmpty(get(errorMessagesFromFormBuilder, constants.LIQUID_ERROR_MSG, [])) || !isEmpty(get(errorMessagesFromFormBuilder, constants.STANDARD_ERROR_MSG, [])),
1768
- liquidErrorMessage: errorMessagesFromFormBuilder,
1769
- activeFormBuilderTab: currentFormBuilderTab === 1 ? constants.ANDROID : (currentFormBuilderTab === 2 ? constants.IOS : null), // Update activeFormBuilderTab, default to 1 if undefined
1977
+ const next = computeLiquidFooterUpdateFromFormBuilder(errorMessagesFromFormBuilder, currentFormBuilderTab, {
1978
+ previousIsLiquidValidationError: this.state.isLiquidValidationError,
1979
+ currentChannelUpper: this.state.currentChannel?.toUpperCase(),
1770
1980
  });
1981
+ if (next == null) return;
1982
+ this.setState(next);
1771
1983
  }
1772
1984
 
1773
1985
  // Callback to update HTML Editor validation state (called from EmailWrapper)
@@ -1777,6 +1989,12 @@ export class Creatives extends React.Component {
1777
1989
  });
1778
1990
  }
1779
1991
 
1992
+ handlePersonalizationTokensChange = (hasTokens) => {
1993
+ this.setState({
1994
+ hasPersonalizationTokenError: hasTokens,
1995
+ });
1996
+ }
1997
+
1780
1998
  shouldShowContinueFooter = () => { // only for email for now, has to be modified according to channel
1781
1999
  const {
1782
2000
  slidBoxContent, templateStep, currentChannel, emailCreateMode, mobilePushCreateMode, inAppEditorType, weChatTemplateType,
@@ -1884,6 +2102,11 @@ export class Creatives extends React.Component {
1884
2102
  inAppEditorType,
1885
2103
  htmlEditorValidationState,
1886
2104
  } = this.state;
2105
+ const useLocalTemplates = get(
2106
+ this.props,
2107
+ 'localTemplatesConfig.useLocalTemplates',
2108
+ get(this.props, 'useLocalTemplates', false),
2109
+ );
1887
2110
  const {
1888
2111
  isFullMode,
1889
2112
  creativesMode,
@@ -1902,6 +2125,7 @@ export class Creatives extends React.Component {
1902
2125
  smsRegister,
1903
2126
  enableNewChannels,
1904
2127
  eventContextTags,
2128
+ waitEventContextTags,
1905
2129
  isLoyaltyModule,
1906
2130
  loyaltyMetaData = {},
1907
2131
  } = this.props;
@@ -1935,20 +2159,39 @@ export class Creatives extends React.Component {
1935
2159
  // IMPORTANT: Never show ErrorInfoNote in footer when in HTML Editor mode, even if liquidErrorMessage exists
1936
2160
  const shouldShowErrorInfoNoteInFooter = isHTMLEditorMode ? false : hasBEEEditorErrors;
1937
2161
 
1938
- // Calculate margin for header/content (always apply if there are errors, regardless of editor type)
1939
- const slideBoxWrapperMargin = (get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0 && get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0)
1940
- ? CAP_SPACE_64
1941
- : get(liquidErrorMessage, 'LIQUID_ERROR_MSG.length', 0) > 0
1942
- ? CAP_SPACE_56
1943
- : get(liquidErrorMessage, 'STANDARD_ERROR_MSG.length', 0) > 0
1944
- ? CAP_SPACE_32
1945
- : 0;
2162
+ const slideBoxWrapperMargin = getSlideBoxWrapperMarginFromLiquidErrors(liquidErrorMessage);
1946
2163
  /* TODO: Instead of passing down same props separately to each component down, write common function to these props and pass it accordingly */
2164
+
2165
+ // Compute anonymous user type and channel restrictions
2166
+ const { customerType = '' } = this.props;
2167
+ const isAnonymousType = [constants.VISITOR, constants.MIXED].includes(customerType);
2168
+ const restrictPersonalization = isAnonymousType;
2169
+
2170
+ // For anonymous users, only MOBILEPUSH and WEBPUSH channels are allowed
2171
+ let updatedChannelsToHide = [...(channelsToHide || [])];
2172
+ if (isAnonymousType) {
2173
+ const allowedChannels = constants.ALLOWED_CHANNELS_FOR_ANONYMOUS;
2174
+ const allChannels = constants.ALL_CHANNELS_NEW;
2175
+ const channelsToRemove = allChannels.filter((channel) => !allowedChannels.includes(channel));
2176
+ updatedChannelsToHide = [...new Set([...updatedChannelsToHide, ...channelsToRemove])];
2177
+ }
2178
+ // In library mode (journey module), hide mobilepush and wechat channels from engagement blocks
2179
+ // unless the current engagement block itself is that channel (e.g. mobilepush block should show mobilepush tab)
2180
+ const isJourneyModule = (this.props.messageDetails?.type || '').toLowerCase() === constants.JOURNEY;
2181
+ if (!isFullMode && isJourneyModule) {
2182
+ const currentChannelNorm = (currentChannel || '').toLowerCase();
2183
+ const journeyChannelsToHide = ['mobilepush', 'wechat'].filter((ch) => ch !== currentChannelNorm);
2184
+ updatedChannelsToHide = [...new Set([...updatedChannelsToHide, ...journeyChannelsToHide])];
2185
+ }
2186
+
1947
2187
  return (
1948
2188
  <SlideBoxWrapper
1949
2189
  slideBoxWrapperMargin={slideBoxWrapperMargin}
1950
2190
  shouldApplyFooterMargin={shouldShowErrorInfoNoteInFooter}
1951
- className={classnames(`${classPrefix} ${isFullMode ? 'creatives-full-mode' : 'creatives-library-mode'} ${mapTemplateCreate ? 'map-template-create' : ''}`)}
2191
+ className={classnames(
2192
+ `${classPrefix} ${isFullMode ? 'creatives-full-mode' : 'creatives-library-mode'} ${mapTemplateCreate ? 'map-template-create' : ''}`,
2193
+ useLocalTemplates && slidBoxContent === 'templates' && 'creatives-slidebox--local-sms-templates',
2194
+ )}
1952
2195
  >
1953
2196
  <CapSlideBox
1954
2197
  header={
@@ -1973,12 +2216,13 @@ export class Creatives extends React.Component {
1973
2216
  smsRegister={smsRegister}
1974
2217
  handleClose={this.handleCloseSlideBox}
1975
2218
  moduleType={this.props.messageDetails?.type}
2219
+ useLocalTemplates={useLocalTemplates}
1976
2220
  />
1977
2221
  )}
1978
2222
  content={(
1979
2223
  <SlideBoxContent
1980
2224
  key="creatives-container-slidebox-content"
1981
- onSelectTemplate={this.onSelectTemplate}
2225
+ onSelectTemplate={this.props.onSelectTemplate != null ? this.props.onSelectTemplate : this.onSelectTemplate}
1982
2226
  onCreateComplete={getCreativesData}
1983
2227
  onPreviewTemplate={this.onPreviewTemplate}
1984
2228
  slidBoxContent={slidBoxContent}
@@ -2014,10 +2258,13 @@ export class Creatives extends React.Component {
2014
2258
  mobilePushCreateMode={mobilePushCreateMode}
2015
2259
  showTemplateName={this.showTemplateName}
2016
2260
  onValidationFail={this.onValidationFail}
2017
- channelsToHide={channelsToHide}
2261
+ channelsToHide={updatedChannelsToHide}
2018
2262
  forwardedTags={forwardedTags}
2019
2263
  selectedOfferDetails={selectedOfferDetails}
2020
2264
  channelsToDisable={channelsToDisable}
2265
+ restrictPersonalization={restrictPersonalization}
2266
+ isAnonymousType={isAnonymousType}
2267
+ customerType={customerType}
2021
2268
  weChatTemplateType={weChatTemplateType}
2022
2269
  onWechatTemplateChange={this.onWechatTemplateChange}
2023
2270
  weChatMaptemplateStep={weChatMaptemplateStep}
@@ -2043,6 +2290,7 @@ export class Creatives extends React.Component {
2043
2290
  creativesMode={creativesMode} // An existing prop that we're using here. Required to ensure correct account details in Edit or Preview in case of Embedded mode.
2044
2291
  hostName={this.props?.hostName || ''}
2045
2292
  eventContextTags={eventContextTags}
2293
+ waitEventContextTags={waitEventContextTags}
2046
2294
  isLoyaltyModule={isLoyaltyModule}
2047
2295
  loyaltyMetaData={loyaltyMetaData}
2048
2296
  showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
@@ -2050,7 +2298,9 @@ export class Creatives extends React.Component {
2050
2298
  handleCloseTestAndPreview={this.handleCloseTestAndPreview}
2051
2299
  isTestAndPreviewMode={(() => this.state.isTestAndPreviewMode)()}
2052
2300
  onHtmlEditorValidationStateChange={this.updateHtmlEditorValidationState}
2053
- />
2301
+ onPersonalizationTokensChange={this.handlePersonalizationTokensChange}
2302
+ localTemplatesConfig={pick(this.props.localTemplatesConfig || this.props, constants.LOCAL_TEMPLATE_CONFIG_KEYS)}
2303
+ />
2054
2304
  )}
2055
2305
  footer={this.shouldShowFooter() ? (
2056
2306
  <SlideBoxFooter
@@ -2082,6 +2332,10 @@ export class Creatives extends React.Component {
2082
2332
  })()}
2083
2333
  htmlEditorValidationState={htmlEditorValidationState}
2084
2334
  isCreatingTemplate={slidBoxContent === 'createTemplate' && currentChannel.toUpperCase() === constants.EMAIL}
2335
+ restrictPersonalization={restrictPersonalization}
2336
+ isAnonymousType={isAnonymousType}
2337
+ templateData={templateData}
2338
+ hasPersonalizationTokenError={this.state.hasPersonalizationTokenError}
2085
2339
  />
2086
2340
  ) : isLiquidValidationError && (
2087
2341
  <CapRow className="template-footer-width">
@@ -2130,11 +2384,32 @@ Creatives.propTypes = {
2130
2384
  orgUnitId: PropTypes.number,
2131
2385
  hostName: PropTypes.string,
2132
2386
  eventContextTags: PropTypes.array,
2387
+ waitEventContextTags: PropTypes.object,
2133
2388
  loyaltyTagFetchingDependencies: PropTypes.object,
2389
+ customerType: PropTypes.string,
2134
2390
  intl: PropTypes.shape({
2135
2391
  formatMessage: PropTypes.func,
2136
2392
  }),
2137
2393
  stopValidation: PropTypes.func,
2394
+ // Local template list (e.g. for SMS fallback): when set, TemplatesV2 uses these instead of Redux.
2395
+ // All optional. Pass either localTemplatesConfig (object) or individual props below.
2396
+ localTemplatesConfig: PropTypes.shape({
2397
+ useLocalTemplates: PropTypes.bool,
2398
+ localTemplates: PropTypes.arrayOf(PropTypes.object),
2399
+ localTemplatesLoading: PropTypes.bool,
2400
+ localTemplatesFilterContent: PropTypes.node,
2401
+ localTemplatesSentinelContent: PropTypes.node,
2402
+ localTemplatesScrollContainerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
2403
+ localTemplatesUseSkeleton: PropTypes.bool,
2404
+ }),
2405
+ useLocalTemplates: PropTypes.bool,
2406
+ localTemplates: PropTypes.arrayOf(PropTypes.object),
2407
+ localTemplatesLoading: PropTypes.bool,
2408
+ localTemplatesFilterContent: PropTypes.node,
2409
+ localTemplatesSentinelContent: PropTypes.node,
2410
+ localTemplatesScrollContainerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
2411
+ localTemplatesUseSkeleton: PropTypes.bool,
2412
+ onSelectTemplate: PropTypes.func,
2138
2413
  };
2139
2414
  const mapStatesToProps = () => createStructuredSelector({
2140
2415
  isLoading: isLoadingSelector(),