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
@@ -10,12 +10,14 @@ import { isTraiDLTEnable } from '../../utils/common';
10
10
  import SmsEdit from '../Sms/Edit';
11
11
  import SmsTraiCreate from '../SmsTrai/Create';
12
12
  import SmsTraiEdit from '../SmsTrai/Edit';
13
+
13
14
  const SmsWrapper = (props) => {
14
15
  const {
15
16
  isCreateSms,
16
17
  isEditSms,
17
18
  setIsLoadingContent,
18
19
  location,
20
+ route: routeFromProps,
19
21
  isGetFormData,
20
22
  getFormSubscriptionData,
21
23
  isFullMode,
@@ -30,21 +32,41 @@ const SmsWrapper = (props) => {
30
32
  smsRegister,
31
33
  onShowTemplates,
32
34
  eventContextTags,
35
+ waitEventContextTags,
33
36
  showLiquidErrorInFooter,
34
37
  getLiquidTags,
35
38
  showTestAndPreviewSlidebox,
36
39
  handleTestAndPreview,
37
40
  handleCloseTestAndPreview,
38
41
  isTestAndPreviewMode,
42
+ onValidationFail,
43
+ embeddedSmsFallback = false,
44
+ onEmbeddedSmsFooterValidity,
45
+ forceFullTagContext = false,
39
46
  } = props;
40
47
 
48
+ /** FormBuilder / SMS Create assume `location.query`; connected-router shapes may omit it. */
49
+ const smsLocation = (() => {
50
+ const loc = location || {};
51
+ const q = loc.query;
52
+ if (q && typeof q === 'object') {
53
+ return { ...loc, query: { ...q } };
54
+ }
55
+ return {
56
+ pathname: loc.pathname || '/sms/create',
57
+ search: loc.search || '',
58
+ query: { type: 'embedded', module: 'library' },
59
+ };
60
+ })();
61
+
41
62
  const smsProps = {
42
63
  onCreateComplete,
43
64
  setIsLoadingContent,
44
- location,
45
- route: { name: 'sms' },
65
+ location: smsLocation,
66
+ route: routeFromProps || { name: 'sms' },
46
67
  isGetFormData,
47
68
  getFormSubscriptionData,
69
+ templateData,
48
70
  getDefaultTags,
49
71
  isFullMode,
50
72
  forwardedTags,
@@ -52,30 +74,41 @@ const SmsWrapper = (props) => {
52
74
  onPreviewContentClicked,
53
75
  onTestContentClicked,
54
76
  eventContextTags,
77
+ waitEventContextTags,
55
78
  showLiquidErrorInFooter,
56
79
  getLiquidTags,
57
80
  showTestAndPreviewSlidebox,
58
81
  handleTestAndPreview,
59
82
  handleCloseTestAndPreview,
60
83
  isTestAndPreviewMode,
84
+ onValidationFail,
85
+ forceFullTagContext,
86
+ embeddedSmsFallback,
87
+ onEmbeddedSmsFooterValidity,
88
+ ...(embeddedSmsFallback
89
+ ? {
90
+ tagListGetPopupContainer: () => document.body,
91
+ tagListPopoverOverlayStyle: { zIndex: 10020 },
92
+ tagListPopoverOverlayClassName: 'sms-fallback-taglist-popover rcs-sms-fallback-taglist-popover',
93
+ }
94
+ : {}),
61
95
  };
62
- const isTraiDlt = isTraiDLTEnable(isFullMode, smsRegister);
96
+ const useTraiSmsFlow = isTraiDLTEnable(isFullMode, smsRegister);
63
97
  return <>
64
98
  {
65
- isCreateSms && (isTraiDlt ?
99
+ isCreateSms && (useTraiSmsFlow ?
66
100
  <SmsTraiCreate
67
101
  isComponent
68
102
  {...smsProps}
69
103
  onShowTemplates={onShowTemplates}
70
104
  /> :
71
105
  <SmsCreate
72
- isComponent {
73
- ...smsProps
74
- }
106
+ isComponent
107
+ {...smsProps}
75
108
  />
76
109
  )
77
110
  }
78
- {isEditSms && (isTraiDlt ?
111
+ {isEditSms && (useTraiSmsFlow ?
79
112
  <SmsTraiEdit
80
113
  {...smsProps}
81
114
  params={{id: templateData._id}}
@@ -167,7 +167,7 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
167
167
  let injectedTags = {};
168
168
  const eventContextTagsObj = {};
169
169
 
170
- const {selectedOfferDetails, eventContextTags } = props;
170
+ const {selectedOfferDetails, eventContextTags, waitEventContextTags } = props;
171
171
  if (props.injectedTags && !_.isEmpty(props.injectedTags)) {
172
172
  const formattedInjectedTags = handleInjectedData(
173
173
  props.injectedTags,
@@ -219,6 +219,43 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
219
219
  };
220
220
  });
221
221
  }
222
+ // Wait event context tags should be displayed in the Add Labels when node is next to Event based wait node.
223
+ if (waitEventContextTags && Object.keys(waitEventContextTags)?.length) {
224
+
225
+ Object.keys(waitEventContextTags).forEach((blockId) => {
226
+ const WAIT_EVENT_HEADER_MSG_LABEL = `${waitEventContextTags[blockId].eventName} (${waitEventContextTags[blockId].blockName})`;
227
+ eventContextTagsObj[blockId] = {
228
+ "name": WAIT_EVENT_HEADER_MSG_LABEL,
229
+ "desc": WAIT_EVENT_HEADER_MSG_LABEL,
230
+ "resolved": true,
231
+ 'tag-header': true,
232
+ "subtags": {},
233
+ };
234
+
235
+ waitEventContextTags?.[blockId]?.tags?.forEach((tag) => {
236
+ const {
237
+ tagName, label, profileId, profileName, blockName, eventName
238
+ } = tag || {};
239
+ if (!profileId || !tagName || !label || !profileName) return;
240
+ // Initializing the tags profile if it doesn't exist
241
+ if (!eventContextTagsObj?.[blockId]?.subtags?.[profileId]) {
242
+ eventContextTagsObj[blockId].subtags[profileId] = {
243
+ "name": profileName,
244
+ "desc": profileName,
245
+ "resolved": true,
246
+ 'tag-header': true,
247
+ "subtags": {},
248
+ };
249
+ }
250
+ // Adding the current tag to the profile group
251
+ eventContextTagsObj[blockId].subtags[profileId].subtags[tagName] = {
252
+ name: label,
253
+ desc: label,
254
+ resolved: true,
255
+ };
256
+ });
257
+ });
258
+ }
222
259
  this.setState({tags: _.merge( {}, tags, injectedTags, eventContextTagsObj )});
223
260
  }
224
261
 
@@ -396,6 +433,17 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
396
433
  }
397
434
 
398
435
  render() {
436
+ const { restrictPersonalization, disabled, disableTooltipMsg, intl } = this.props;
437
+
438
+ // Compute disabled state and tooltip message
439
+ let isDisabled = disabled || false;
440
+ let tooltipMsg = disableTooltipMsg;
441
+
442
+ if (restrictPersonalization && !disabled) {
443
+ isDisabled = true;
444
+ tooltipMsg = intl.formatMessage(messages.personalizationNotSupportedAnonymous);
445
+ }
446
+
399
447
  return (
400
448
  <div className={this.props.className ? this.props.className : ''}>
401
449
  <CapTagList
@@ -411,9 +459,14 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
411
459
  modalProps={this.props.modalProps}
412
460
  currentOrgDetails={this.props.currentOrgDetails}
413
461
  channel={this.props.channel}
414
- disabled={this.props.disabled}
462
+ disabled={isDisabled}
463
+ // custom tooltip message to show when disabled
464
+ disableTooltipMsg={tooltipMsg}
415
465
  fetchingSchemaError={this?.state?.tagsError}
416
466
  popoverPlacement={this.props.popoverPlacement}
467
+ overlayStyle={this.props.popoverOverlayStyle}
468
+ overlayClassName={this.props.popoverOverlayClassName}
469
+ getPopupContainer={this.props.getPopupContainer}
417
470
  />
418
471
  </div>
419
472
  );
@@ -424,6 +477,7 @@ TagList.defaultProps = {
424
477
  isNewVersionFlow: false,
425
478
  userLocale: 'en',
426
479
  eventContextTags: [],
480
+ waitEventContextTags: {},
427
481
  };
428
482
 
429
483
  TagList.propTypes = {
@@ -444,7 +498,14 @@ TagList.propTypes = {
444
498
  disabled: PropTypes.bool,
445
499
  fetchingSchemaError: PropTypes.bool,
446
500
  eventContextTags: PropTypes.array,
501
+ waitEventContextTags: PropTypes.object,
447
502
  popoverPlacement: PropTypes.string,
503
+ // message to show when Add Label button is disabled (e.g. personalization restriction)
504
+ disableTooltipMsg: PropTypes.string,
505
+ restrictPersonalization: PropTypes.bool,
506
+ popoverOverlayStyle: PropTypes.object,
507
+ popoverOverlayClassName: PropTypes.string,
508
+ getPopupContainer: PropTypes.func,
448
509
  intl: PropTypes.shape({
449
510
  formatMessage: PropTypes.func.isRequired,
450
511
  locale: PropTypes.string,
@@ -15,4 +15,12 @@ export default defineMessages({
15
15
  id: `${scope}.entryEvent`,
16
16
  defaultMessage: 'Entry event',
17
17
  },
18
+ personalizationNotSupportedAnonymous: {
19
+ id: `${scope}.personalizationNotSupportedAnonymous`,
20
+ defaultMessage: 'Personalization tags are not supported for anonymous customers',
21
+ },
22
+ waitEvent: {
23
+ id: `${scope}.waitEvent`,
24
+ defaultMessage: 'Wait Event',
25
+ },
18
26
  });
@@ -5,28 +5,34 @@ import { initialReducer } from '../../../initialReducer';
5
5
  import { injectIntl } from "react-intl";
6
6
  import { fireEvent } from "@testing-library/react";
7
7
  import { TagList } from '../index';
8
- import { TagListData, eventContextTags } from './mockdata';
8
+ import { TagListData, eventContextTags, waitEventContextTags } from './mockdata';
9
+ import { OfferTag, badgesTags, offer } from '../../../utils/tests/common.mockdata';
10
+ import * as commonUtils from "../../../utils/common";
9
11
  import { Provider } from 'react-redux';
10
12
  import { screen, render } from '../../../utils/test-utils';
11
13
  import history from '../../../utils/history';
12
14
  const { getByText, queryByText } = screen;
13
15
 
16
+ const buildProps = (props = {}) => ({
17
+ ...TagListData,
18
+ onTagSelect: jest.fn(),
19
+ ...props,
20
+ });
14
21
 
15
- const initializeTagList = (props) => {
22
+ const initializeTagList = (props = {}) => {
16
23
  const store = configureStore({}, initialReducer, history);
17
24
  const Component = injectIntl(TagList);
18
-
19
- const propsObj = {
20
- ...TagListData,
21
- onTagSelect: jest.fn(),
22
- ...props,
25
+ const propsObj = buildProps(props);
26
+ return {
27
+ ...render(
28
+ <Provider store={store}>
29
+ <Component {...propsObj} />
30
+ </Provider>
31
+ ),
32
+ store,
33
+ Component,
34
+ propsObj,
23
35
  };
24
-
25
- return render(
26
- <Provider store={store}>
27
- <Component {...propsObj} />
28
- </Provider>
29
- );
30
36
  };
31
37
 
32
38
  const addLabelBtnAssertion = () => {
@@ -41,19 +47,115 @@ describe("TagList test : UNIT", () => {
41
47
  addLabelBtnAssertion();
42
48
  });
43
49
 
44
- it('should render event context tags correctly from generateTags and show tags under profile', () => {
45
- initializeTagList({eventContextTags});
50
+ it('should render event context tag section from generateTags', () => {
51
+ initializeTagList({ eventContextTags, moduleFilterEnabled: false });
46
52
  addLabelBtnAssertion();
47
53
  const EVENT_CONTEXT_TAG_HEADER = getByText(/Entry event/i);
48
54
  expect(EVENT_CONTEXT_TAG_HEADER).toBeInTheDocument();
49
- fireEvent.click(EVENT_CONTEXT_TAG_HEADER);
50
- // Customer profile tags
51
- const CUSTOMER_PROFILE = getByText(/Current Customer/i);
52
- fireEvent.click(CUSTOMER_PROFILE);
53
- expect(getByText(/lifetimePurchases/i)).toBeInTheDocument();
54
55
 
55
56
  // Behavioural event profile tags should not be visible as label and profile name is not present
56
57
  const BEHAVIOURAL_EVENT_PROFILE = queryByText(/Behavioural event/i);
57
58
  expect(BEHAVIOURAL_EVENT_PROFILE).not.toBeInTheDocument();
58
59
  });
60
+
61
+ it('should render wait event context section when waitEventContextTags is provided', () => {
62
+ initializeTagList({ waitEventContextTags, moduleFilterEnabled: false });
63
+ addLabelBtnAssertion();
64
+ const WAIT_EVENT_HEADER = getByText(/Order Placed \(Wait Block\)/i);
65
+ expect(WAIT_EVENT_HEADER).toBeInTheDocument();
66
+ });
67
+
68
+ it('should merge empty waitEventContextTags with entry event tags', () => {
69
+ initializeTagList({ eventContextTags, waitEventContextTags: {}, moduleFilterEnabled: false });
70
+ addLabelBtnAssertion();
71
+ expect(getByText(/Entry event/i)).toBeInTheDocument();
72
+ });
73
+
74
+ it('calls parent onContextChange with Outbound when tags and injectedTags are empty on mount', () => {
75
+ const onContextChange = jest.fn();
76
+ initializeTagList({
77
+ tags: [],
78
+ injectedTags: {},
79
+ onContextChange,
80
+ onTagSelect: jest.fn(),
81
+ });
82
+ expect(onContextChange).toHaveBeenCalledWith('Outbound');
83
+ });
84
+
85
+ it('applies fetchingSchemaError from props via componentWillReceiveProps', () => {
86
+ const { rerender, Component, propsObj, store } = initializeTagList({ fetchingSchemaError: false });
87
+ addLabelBtnAssertion();
88
+ rerender(
89
+ <Provider store={store}>
90
+ <Component {...propsObj} fetchingSchemaError />
91
+ </Provider>
92
+ );
93
+ expect(screen.getByText(/add label/i)).toBeInTheDocument();
94
+ });
95
+
96
+ it('disables Add label when restrictPersonalization is true', () => {
97
+ initializeTagList({
98
+ restrictPersonalization: true,
99
+ disabled: false,
100
+ moduleFilterEnabled: false,
101
+ });
102
+ const btn = screen.getByText(/add label/i).closest('button');
103
+ expect(btn).toBeDisabled();
104
+ });
105
+
106
+ it('calls transformCouponTags when selectedOfferDetails and coupon tags are present', () => {
107
+ const spy = jest.spyOn(TagList.prototype, 'transformCouponTags');
108
+ initializeTagList({
109
+ tags: OfferTag,
110
+ injectedTags: {},
111
+ selectedOfferDetails: [{ id: 'c1', couponName: 'Promo Coupon', couponSeriesId: 'c1' }],
112
+ moduleFilterEnabled: false,
113
+ });
114
+ expect(spy).toHaveBeenCalled();
115
+ spy.mockRestore();
116
+ });
117
+
118
+ it('calls transformBadgeTags from common when badge offer and Badge tags are present', () => {
119
+ const spy = jest.spyOn(commonUtils, 'transformBadgeTags');
120
+ initializeTagList({
121
+ tags: badgesTags,
122
+ injectedTags: {},
123
+ selectedOfferDetails: offer,
124
+ moduleFilterEnabled: false,
125
+ });
126
+ expect(spy).toHaveBeenCalled();
127
+ spy.mockRestore();
128
+ });
129
+
130
+ it('unmounts without throwing', () => {
131
+ const { unmount } = initializeTagList();
132
+ expect(() => unmount()).not.toThrow();
133
+ });
134
+
135
+ it('regenerates tags when props.tags change (componentDidUpdate)', () => {
136
+ const { rerender, Component, store } = initializeTagList({ tags: TagListData.tags });
137
+ const extra = [
138
+ ...TagListData.tags,
139
+ {
140
+ _id: 'extra-tag',
141
+ type: 'TAG',
142
+ definition: {
143
+ label: { en: 'Extra' },
144
+ value: 'extra_value',
145
+ subtags: [],
146
+ 'tag-header': false,
147
+ supportedModules: [{ context: 'default', layout: 'sms', mandatory: false }],
148
+ },
149
+ scope: { tag: 'STANDARD', orgId: -1, verticals: [] },
150
+ isActive: true,
151
+ },
152
+ ];
153
+ rerender(
154
+ <Provider store={store}>
155
+ <Component {...buildProps({ tags: extra })} />
156
+ </Provider>
157
+ );
158
+ addLabelBtnAssertion();
159
+ expect(screen.getByText(/add label/i)).toBeInTheDocument();
160
+ });
59
161
  });
@@ -149,3 +149,20 @@ export const eventContextTags = [
149
149
  "isDynamicFact": false
150
150
  }
151
151
  ];
152
+
153
+ export const waitEventContextTags = {
154
+ block1: {
155
+ eventName: 'Order Placed',
156
+ blockName: 'Wait Block',
157
+ tags: [
158
+ {
159
+ tagName: 'waitEvent.orderId',
160
+ label: 'Order ID',
161
+ profileId: 'ORDER_PROFILE',
162
+ profileName: 'Order Profile',
163
+ blockName: 'Wait Block',
164
+ eventName: 'Order Placed',
165
+ },
166
+ ],
167
+ },
168
+ };
@@ -0,0 +1,101 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import CapInput from '@capillarytech/cap-ui-library/CapInput';
4
+ import CapButton from '@capillarytech/cap-ui-library/CapButton';
5
+
6
+ /**
7
+ * Reusable action bar for template pickers.
8
+ * Layout and spacing live in `_templates.scss` (`.action-container`, `.action-container__toolbar-row`).
9
+ * Default search field width: `.action-container__toolbar-row .search-text` (13.125rem).
10
+ * Pass `searchInputClassName` / `searchInputStyle` to override (defaults match Templates list: 210px per master).
11
+ */
12
+ const TemplatesActionBar = ({
13
+ searchValue,
14
+ onSearchChange,
15
+ onSearch,
16
+ onClear,
17
+ searchPlaceholder,
18
+ searchInputClassName,
19
+ searchInputStyle,
20
+ ctaLabel,
21
+ onCtaClick,
22
+ ctaDisabled,
23
+ ctaClassName,
24
+ ctaNode,
25
+ children,
26
+ showCta = true,
27
+ }) => (
28
+ <div className="action-container">
29
+ <div className="action-container__toolbar-row">
30
+ {searchPlaceholder && (
31
+ <CapInput.Search
32
+ className={['search-text', searchInputClassName].filter(Boolean).join(' ')}
33
+ placeholder={searchPlaceholder}
34
+ value={searchValue}
35
+ onChange={onSearchChange}
36
+ /* antd `Input` (used by CapInput.Search) has no `onSearch`; only `Input.Search` does. */
37
+ onPressEnter={(e) => {
38
+ if (onSearch) {
39
+ const v = e?.target && 'value' in e.target ? e.target.value : searchValue;
40
+ onSearch(v);
41
+ }
42
+ }}
43
+ onSearch={onSearch}
44
+ onClear={onClear}
45
+ onScroll={(e) => e.stopPropagation()}
46
+ />
47
+ )}
48
+ {children}
49
+ </div>
50
+ {showCta && (
51
+ <div>
52
+ {ctaNode || (
53
+ <CapButton
54
+ className={ctaClassName}
55
+ type="primary"
56
+ disabled={ctaDisabled}
57
+ onClick={onCtaClick}
58
+ >
59
+ {ctaLabel}
60
+ </CapButton>
61
+ )}
62
+ </div>
63
+ )}
64
+ </div>
65
+ );
66
+
67
+ TemplatesActionBar.propTypes = {
68
+ searchValue: PropTypes.string,
69
+ onSearchChange: PropTypes.func,
70
+ onSearch: PropTypes.func,
71
+ onClear: PropTypes.func,
72
+ searchPlaceholder: PropTypes.string,
73
+ searchInputClassName: PropTypes.string,
74
+ searchInputStyle: PropTypes.object,
75
+ ctaLabel: PropTypes.node,
76
+ onCtaClick: PropTypes.func,
77
+ ctaDisabled: PropTypes.bool,
78
+ ctaClassName: PropTypes.string,
79
+ ctaNode: PropTypes.node,
80
+ children: PropTypes.node,
81
+ showCta: PropTypes.bool,
82
+ };
83
+
84
+ TemplatesActionBar.defaultProps = {
85
+ searchValue: '',
86
+ onSearchChange: () => {},
87
+ onSearch: () => {},
88
+ onClear: () => {},
89
+ searchPlaceholder: '',
90
+ searchInputClassName: '',
91
+ searchInputStyle: { width: '210px' },
92
+ ctaLabel: null,
93
+ onCtaClick: () => {},
94
+ ctaDisabled: false,
95
+ ctaClassName: '',
96
+ ctaNode: null,
97
+ children: null,
98
+ };
99
+
100
+ export default TemplatesActionBar;
101
+
@@ -659,11 +659,27 @@
659
659
  }
660
660
 
661
661
  .action-container{
662
- margin-top: 8px;
663
- margin-bottom: 16px;
662
+ margin-top: $CAP_SPACE_08;
663
+ margin-bottom: $CAP_SPACE_16;
664
664
  display: flex;
665
665
  justify-content: space-between;
666
666
  align-items: center;
667
+
668
+ &__toolbar-row {
669
+ display: flex;
670
+ align-items: center;
671
+ gap: 0.75rem;
672
+ }
673
+
674
+ &__toolbar-row .search-text {
675
+ width: 13.125rem;
676
+ }
677
+
678
+ &__create-row {
679
+ display: flex;
680
+ justify-content: space-between;
681
+ align-items: center;
682
+ }
667
683
  }
668
684
 
669
685
  .popover-action-container:hover{
@@ -1101,4 +1117,47 @@
1101
1117
  .inapp-illustration-parent {
1102
1118
  height: "calc(100vh - 325px)";
1103
1119
  overflow: 'auto';
1120
+ }
1121
+
1122
+ /* Local SMS / slidebox: viewport-based .v2-pagination-container-half height leaves empty space below and clips cards */
1123
+ .creatives-templates-container--local-sms.library-mode {
1124
+ .creatives-templates-list.library-mode > .cap-row:first-of-type > div {
1125
+ display: flex;
1126
+ flex-direction: column;
1127
+ flex: 1 1 auto;
1128
+ min-height: 0;
1129
+ overflow: hidden;
1130
+ }
1131
+
1132
+ .creatives-templates-list.library-mode > .cap-row:first-of-type > div > div:first-child {
1133
+ display: flex;
1134
+ flex-direction: column;
1135
+ flex: 1 1 auto;
1136
+ min-height: 0;
1137
+ overflow: hidden;
1138
+ }
1139
+
1140
+ /* Block below search/filter: grid + skeletons — must grow to use space above footer */
1141
+ .creatives-templates-list.library-mode > .cap-row:first-of-type > div > div:first-child > div:nth-child(2) {
1142
+ flex: 1 1 auto;
1143
+ min-height: 0;
1144
+ display: flex;
1145
+ flex-direction: column;
1146
+ overflow: hidden;
1147
+ }
1148
+
1149
+ /*
1150
+ * Scroll needs a definite height. Pure flex + height:auto + max-height:100% often won’t bound (no % base), so no scrollbar.
1151
+ * Use a taller slice than global 100vh-20rem so the grid uses space under search; still overflow-y:auto for long lists.
1152
+ */
1153
+ .v2-pagination-container,
1154
+ .v2-pagination-container-half {
1155
+ flex: 0 1 auto;
1156
+ min-height: 0;
1157
+ height: calc(100vh - 12rem);
1158
+ max-height: calc(100vh - 12rem);
1159
+ overflow-y: auto;
1160
+ overflow-x: hidden;
1161
+ -webkit-overflow-scrolling: touch;
1162
+ }
1104
1163
  }
@@ -15,6 +15,17 @@ export function getAllTemplates(channel, queryParams, intlCopyOf = '') {
15
15
  };
16
16
  }
17
17
 
18
+
19
+ export function getLocalSmsTemplates(queryParams, intlCopyOf = '', onSuccess, onFailure) {
20
+ return {
21
+ type: types.GET_LOCAL_SMS_TEMPLATES_REQUEST,
22
+ queryParams,
23
+ intlCopyOf,
24
+ onSuccess,
25
+ onFailure,
26
+ };
27
+ }
28
+
18
29
  export function resetTemplate() {
19
30
  return {
20
31
  type: types.RESET_TEMPLATE,
@@ -10,6 +10,8 @@ export const GET_ALL_TEMPLATES_REQUEST = 'app/v2Containers/Templates/GET_ALL_TEM
10
10
  export const GET_ALL_TEMPLATES_SUCCESS = 'app/v2Containers/Templates/GET_ALL_TEMPLATES_SUCCESS';
11
11
  export const GET_ALL_TEMPLATES_FAILURE = 'app/v2Containers/Templates/GET_ALL_TEMPLATES_FAILURE';
12
12
 
13
+ export const GET_LOCAL_SMS_TEMPLATES_REQUEST = 'app/v2Containers/Templates/GET_LOCAL_SMS_TEMPLATES_REQUEST';
14
+
13
15
  export const DELETE_TEMPLATE_REQUEST = 'app/v2Containers/Templates/DELETE_TEMPLATE_REQUEST';
14
16
  export const DELETE_RCS_TEMPLATE_REQUEST = 'app/v2Containers/Templates/DELETE_RCS_TEMPLATE_REQUEST';
15
17
  export const DELETE_TEMPLATE_SUCCESS = 'app/v2Containers/Templates/DELETE_TEMPLATE_SUCCESS';