@capillarytech/creatives-library 8.0.268 → 8.0.270

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 (159) hide show
  1. package/constants/unified.js +1 -0
  2. package/package.json +1 -1
  3. package/services/api.js +5 -0
  4. package/utils/common.js +6 -0
  5. package/utils/imageUrlUpload.js +141 -0
  6. package/utils/tagValidations.js +2 -1
  7. package/utils/tests/transformerUtils.test.js +297 -0
  8. package/utils/transformerUtils.js +40 -0
  9. package/v2Components/CapImageUpload/constants.js +2 -0
  10. package/v2Components/CapImageUpload/index.js +65 -16
  11. package/v2Components/CapImageUpload/index.scss +4 -1
  12. package/v2Components/CapImageUpload/messages.js +5 -1
  13. package/v2Components/CapImageUrlUpload/constants.js +26 -0
  14. package/v2Components/CapImageUrlUpload/index.js +365 -0
  15. package/v2Components/CapImageUrlUpload/index.scss +35 -0
  16. package/v2Components/CapImageUrlUpload/messages.js +47 -0
  17. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +2 -2
  18. package/v2Components/CommonTestAndPreview/index.js +4 -15
  19. package/v2Components/FormBuilder/index.js +8 -8
  20. package/v2Containers/App/constants.js +5 -0
  21. package/v2Containers/CreativesContainer/SlideBoxContent.js +57 -2
  22. package/v2Containers/CreativesContainer/SlideBoxHeader.js +1 -0
  23. package/v2Containers/CreativesContainer/constants.js +3 -0
  24. package/v2Containers/CreativesContainer/index.js +168 -0
  25. package/v2Containers/CreativesContainer/messages.js +4 -0
  26. package/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +210 -0
  27. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +304 -0
  28. package/v2Containers/FTP/index.js +1 -1
  29. package/v2Containers/InApp/index.js +1 -0
  30. package/v2Containers/Line/Container/Text/index.js +1 -0
  31. package/v2Containers/MobilePushNew/index.js +1 -0
  32. package/v2Containers/Rcs/index.js +3 -0
  33. package/v2Containers/SmsTrai/Edit/index.js +2 -12
  34. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +36 -648
  35. package/v2Containers/Templates/ChannelTypeIllustration.js +13 -1
  36. package/v2Containers/Templates/_templates.scss +205 -0
  37. package/v2Containers/Templates/actions.js +2 -1
  38. package/v2Containers/Templates/constants.js +1 -0
  39. package/v2Containers/Templates/index.js +274 -34
  40. package/v2Containers/Templates/messages.js +24 -0
  41. package/v2Containers/Templates/reducer.js +2 -0
  42. package/v2Containers/Templates/tests/index.test.js +10 -0
  43. package/v2Containers/TemplatesV2/index.js +15 -7
  44. package/v2Containers/TemplatesV2/messages.js +4 -0
  45. package/v2Containers/Viber/index.js +1 -0
  46. package/v2Containers/WebPush/Create/components/BrandIconSection.js +108 -0
  47. package/v2Containers/WebPush/Create/components/ButtonForm.js +172 -0
  48. package/v2Containers/WebPush/Create/components/ButtonItem.js +101 -0
  49. package/v2Containers/WebPush/Create/components/ButtonList.js +145 -0
  50. package/v2Containers/WebPush/Create/components/ButtonsLinksSection.js +164 -0
  51. package/v2Containers/WebPush/Create/components/ButtonsLinksSection.test.js +463 -0
  52. package/v2Containers/WebPush/Create/components/FormActions.js +54 -0
  53. package/v2Containers/WebPush/Create/components/FormActions.test.js +163 -0
  54. package/v2Containers/WebPush/Create/components/MediaSection.js +142 -0
  55. package/v2Containers/WebPush/Create/components/MediaSection.test.js +341 -0
  56. package/v2Containers/WebPush/Create/components/MessageSection.js +103 -0
  57. package/v2Containers/WebPush/Create/components/MessageSection.test.js +268 -0
  58. package/v2Containers/WebPush/Create/components/NotificationTitleSection.js +87 -0
  59. package/v2Containers/WebPush/Create/components/NotificationTitleSection.test.js +210 -0
  60. package/v2Containers/WebPush/Create/components/TemplateNameSection.js +54 -0
  61. package/v2Containers/WebPush/Create/components/TemplateNameSection.test.js +143 -0
  62. package/v2Containers/WebPush/Create/components/__snapshots__/ButtonsLinksSection.test.js.snap +86 -0
  63. package/v2Containers/WebPush/Create/components/__snapshots__/FormActions.test.js.snap +16 -0
  64. package/v2Containers/WebPush/Create/components/__snapshots__/MediaSection.test.js.snap +41 -0
  65. package/v2Containers/WebPush/Create/components/__snapshots__/MessageSection.test.js.snap +54 -0
  66. package/v2Containers/WebPush/Create/components/__snapshots__/NotificationTitleSection.test.js.snap +37 -0
  67. package/v2Containers/WebPush/Create/components/__snapshots__/TemplateNameSection.test.js.snap +21 -0
  68. package/v2Containers/WebPush/Create/components/_buttons.scss +246 -0
  69. package/v2Containers/WebPush/Create/components/tests/ButtonForm.test.js +554 -0
  70. package/v2Containers/WebPush/Create/components/tests/ButtonItem.test.js +607 -0
  71. package/v2Containers/WebPush/Create/components/tests/ButtonList.test.js +633 -0
  72. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonForm.test.js.snap +666 -0
  73. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonItem.test.js.snap +74 -0
  74. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonList.test.js.snap +78 -0
  75. package/v2Containers/WebPush/Create/hooks/useButtonManagement.js +138 -0
  76. package/v2Containers/WebPush/Create/hooks/useButtonManagement.test.js +406 -0
  77. package/v2Containers/WebPush/Create/hooks/useCharacterCount.js +30 -0
  78. package/v2Containers/WebPush/Create/hooks/useCharacterCount.test.js +151 -0
  79. package/v2Containers/WebPush/Create/hooks/useImageUpload.js +104 -0
  80. package/v2Containers/WebPush/Create/hooks/useImageUpload.test.js +538 -0
  81. package/v2Containers/WebPush/Create/hooks/useTagManagement.js +122 -0
  82. package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +633 -0
  83. package/v2Containers/WebPush/Create/index.js +1148 -0
  84. package/v2Containers/WebPush/Create/index.scss +134 -0
  85. package/v2Containers/WebPush/Create/messages.js +211 -0
  86. package/v2Containers/WebPush/Create/preview/DevicePreviewContent.js +228 -0
  87. package/v2Containers/WebPush/Create/preview/NotificationContainer.js +294 -0
  88. package/v2Containers/WebPush/Create/preview/PreviewContent.js +90 -0
  89. package/v2Containers/WebPush/Create/preview/PreviewControls.js +305 -0
  90. package/v2Containers/WebPush/Create/preview/PreviewDisclaimer.js +25 -0
  91. package/v2Containers/WebPush/Create/preview/WebPushPreview.js +156 -0
  92. package/v2Containers/WebPush/Create/preview/assets/Light.svg +53 -0
  93. package/v2Containers/WebPush/Create/preview/assets/Top.svg +5 -0
  94. package/v2Containers/WebPush/Create/preview/assets/android-arrow-down.svg +9 -0
  95. package/v2Containers/WebPush/Create/preview/assets/android-arrow-up.svg +9 -0
  96. package/v2Containers/WebPush/Create/preview/assets/chrome-icon.png +0 -0
  97. package/v2Containers/WebPush/Create/preview/assets/edge-icon.png +0 -0
  98. package/v2Containers/WebPush/Create/preview/assets/firefox-icon.svg +106 -0
  99. package/v2Containers/WebPush/Create/preview/assets/iOS.svg +26 -0
  100. package/v2Containers/WebPush/Create/preview/assets/macos-arrow-down-icon.svg +9 -0
  101. package/v2Containers/WebPush/Create/preview/assets/macos-triple-dot-icon.svg +9 -0
  102. package/v2Containers/WebPush/Create/preview/assets/opera-icon.svg +18 -0
  103. package/v2Containers/WebPush/Create/preview/assets/safari-icon.svg +29 -0
  104. package/v2Containers/WebPush/Create/preview/assets/windows-close-icon.svg +9 -0
  105. package/v2Containers/WebPush/Create/preview/assets/windows-triple-dot-icon.svg +9 -0
  106. package/v2Containers/WebPush/Create/preview/components/AndroidMobileChromeHeader.js +51 -0
  107. package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +145 -0
  108. package/v2Containers/WebPush/Create/preview/components/IOSHeader.js +45 -0
  109. package/v2Containers/WebPush/Create/preview/components/NotificationExpandedContent.js +68 -0
  110. package/v2Containers/WebPush/Create/preview/components/NotificationHeader.js +61 -0
  111. package/v2Containers/WebPush/Create/preview/components/WindowsChromeExpanded.js +99 -0
  112. package/v2Containers/WebPush/Create/preview/components/tests/AndroidMobileExpanded.test.js +733 -0
  113. package/v2Containers/WebPush/Create/preview/components/tests/WindowsChromeExpanded.test.js +571 -0
  114. package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/AndroidMobileExpanded.test.js.snap +85 -0
  115. package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/WindowsChromeExpanded.test.js.snap +81 -0
  116. package/v2Containers/WebPush/Create/preview/config/notificationMappings.js +50 -0
  117. package/v2Containers/WebPush/Create/preview/constants.js +637 -0
  118. package/v2Containers/WebPush/Create/preview/notification-container.scss +79 -0
  119. package/v2Containers/WebPush/Create/preview/preview.scss +358 -0
  120. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-chrome.scss +370 -0
  121. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-edge.scss +12 -0
  122. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-firefox.scss +12 -0
  123. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-opera.scss +12 -0
  124. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-chrome.scss +47 -0
  125. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-edge.scss +11 -0
  126. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-firefox.scss +11 -0
  127. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-opera.scss +11 -0
  128. package/v2Containers/WebPush/Create/preview/styles/_base.scss +207 -0
  129. package/v2Containers/WebPush/Create/preview/styles/_ios.scss +153 -0
  130. package/v2Containers/WebPush/Create/preview/styles/_ipados.scss +107 -0
  131. package/v2Containers/WebPush/Create/preview/styles/_macos-chrome.scss +101 -0
  132. package/v2Containers/WebPush/Create/preview/styles/_windows-chrome.scss +229 -0
  133. package/v2Containers/WebPush/Create/preview/tests/DevicePreviewContent.test.js +906 -0
  134. package/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +1081 -0
  135. package/v2Containers/WebPush/Create/preview/tests/PreviewControls.test.js +723 -0
  136. package/v2Containers/WebPush/Create/preview/tests/WebPushPreview.test.js +1327 -0
  137. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/DevicePreviewContent.test.js.snap +131 -0
  138. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/NotificationContainer.test.js.snap +112 -0
  139. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/PreviewControls.test.js.snap +144 -0
  140. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/WebPushPreview.test.js.snap +129 -0
  141. package/v2Containers/WebPush/Create/utils/payloadBuilder.js +96 -0
  142. package/v2Containers/WebPush/Create/utils/payloadBuilder.test.js +396 -0
  143. package/v2Containers/WebPush/Create/utils/previewUtils.js +89 -0
  144. package/v2Containers/WebPush/Create/utils/urlValidation.js +115 -0
  145. package/v2Containers/WebPush/Create/utils/urlValidation.test.js +449 -0
  146. package/v2Containers/WebPush/Create/utils/validation.js +76 -0
  147. package/v2Containers/WebPush/Create/utils/validation.test.js +283 -0
  148. package/v2Containers/WebPush/actions.js +60 -0
  149. package/v2Containers/WebPush/constants.js +132 -0
  150. package/v2Containers/WebPush/index.js +2 -0
  151. package/v2Containers/WebPush/reducer.js +104 -0
  152. package/v2Containers/WebPush/sagas.js +119 -0
  153. package/v2Containers/WebPush/selectors.js +65 -0
  154. package/v2Containers/WebPush/tests/reducer.test.js +863 -0
  155. package/v2Containers/WebPush/tests/sagas.test.js +566 -0
  156. package/v2Containers/WebPush/tests/selectors.test.js +960 -0
  157. package/v2Containers/Whatsapp/index.js +1 -0
  158. package/v2Containers/Zalo/index.js +1 -0
  159. package/v2Containers/Zalo/tests/index.test.js +1 -5
@@ -0,0 +1,47 @@
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 upto: {size}',
41
+ },
42
+ formatTypes: {
43
+ id: `${scope}.formatTypes`,
44
+ defaultMessage: 'Format: {formats}',
45
+ },
46
+ });
47
+
@@ -913,7 +913,7 @@
913
913
  // Colors adjusted to white for preview context (inside .message-pop with blue background)
914
914
  .whatsapp-template-header-preview {
915
915
  // From WhatsApp/index.scss: color: $CAP_G01, but use white for preview
916
- color: $CAP_WHITE;
916
+ color: $CAP_G01;
917
917
  // From WhatsApp/index.scss: font-weight: $FONT_WEIGHT_MEDIUM
918
918
  font-weight: $FONT_WEIGHT_MEDIUM;
919
919
  // From WhatsApp/index.scss: font-size: $FONT_SIZE_VS
@@ -927,7 +927,7 @@
927
927
 
928
928
  .whatsapp-template-footer-preview {
929
929
  // From WhatsApp/index.scss: color: $CAP_G04, but use white for preview
930
- color: $CAP_WHITE;
930
+ color: $CAP_G01;
931
931
  // From WhatsApp/index.scss: font-weight: $FONT_WEIGHT_REGULAR
932
932
  font-weight: $FONT_WEIGHT_REGULAR;
933
933
  // From WhatsApp/index.scss: font-size: 0.5rem
@@ -495,28 +495,19 @@ const CommonTestAndPreview = (props) => {
495
495
 
496
496
  case CHANNELS.SMS: {
497
497
  // Extract SMS message from content
498
- const message = contentStr || formDataObj?.['sms-editor'] || formDataObj?.[0]?.['sms-editor'] || formDataObj?.messageBody || '';
498
+ // For SMS, contentStr should contain the message text
499
+ const message = contentStr || formDataObj?.['sms-editor'] || formDataObj?.[0]?.['sms-editor'] || '';
499
500
 
500
501
  // Resolve tags in message if custom values are provided
501
502
  const resolvedMessage = customValuesObj && Object.keys(customValuesObj).length > 0
502
503
  ? resolveTagsInText(message, customValuesObj)
503
504
  : message;
504
505
 
505
- const baseData = formDataObj?.base || formDataObj?.[0]?.base || formDataObj?.[0] || {};
506
- const templateId = formDataObj?.templateConfigs?.templateId || formDataObj?.template_id || formDataObj?.templateId || baseData?.template_id || '';
507
- const templateRaw = formDataObj?.templateConfigs?.template || baseData?.['sms-editor'] || baseData?.['updated-sms-editor'] || '';
508
- const templateContent = Array.isArray(templateRaw) ? templateRaw.join('') : (templateRaw || '');
509
-
510
- const smsPayload = {
506
+ return {
511
507
  ...basePayload,
512
508
  smsMessageContent: {
513
509
  message: resolvedMessage,
514
- ...(templateId && {
515
- templateConfigs: {
516
- templateId,
517
- ...(templateContent && { template: templateContent }),
518
- },
519
- }),
510
+ templateConfigs: {},
520
511
  },
521
512
  smsDeliverySettings: {
522
513
  channelSettings: {
@@ -530,8 +521,6 @@ const CommonTestAndPreview = (props) => {
530
521
  },
531
522
  },
532
523
  };
533
-
534
- return smsPayload;
535
524
  }
536
525
 
537
526
  case CHANNELS.WHATSAPP: {
@@ -726,7 +726,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
726
726
 
727
727
  let tagValidationResponse = false;
728
728
  if (content) {
729
- tagValidationResponse = this.validateTags(content, tags, injectedTags);
729
+ tagValidationResponse = this.validateTags(content, tags, injectedTags, false, this.props?.isFullMode);
730
730
  }
731
731
 
732
732
  if (tagValidationResponse.valid) {
@@ -764,7 +764,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
764
764
  if (this.state.formData['message-editor'] !== undefined ) {
765
765
  const content = this.state.formData['0']['message-editor'] || '';
766
766
 
767
- const tagValidationResponse = this.validateTags((content), tags, injectedTags);
767
+ const tagValidationResponse = this.validateTags((content), tags, injectedTags, false, this.props?.isFullMode);
768
768
 
769
769
  if (tagValidationResponse.valid) {
770
770
  errorData = {
@@ -847,7 +847,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
847
847
  errorData[index] = true;
848
848
  isValid = false;
849
849
  } else {
850
- const tagValidationResponse = this.validateTags(content, tags, injectedTags);
850
+ const tagValidationResponse = this.validateTags(content, tags, injectedTags, false, this.props?.isFullMode);
851
851
 
852
852
  if (tagValidationResponse.valid) {
853
853
  errorData[index] = false;
@@ -910,7 +910,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
910
910
  isCurrentTabValid = false;
911
911
  } else {
912
912
  errorData[parseInt(index)][`message-editor${selector}`] = false;
913
- const tagValidationResponse = this.validateTags(message, tags, injectedTags);
913
+ const tagValidationResponse = this.validateTags(message, tags, injectedTags, false, this.props?.isFullMode);
914
914
 
915
915
  if (tagValidationResponse.valid) {
916
916
  errorData[parseInt(index)][`message-editor${selector}`] = false;
@@ -939,7 +939,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
939
939
  isCurrentTabValid = false;
940
940
  } else {
941
941
  errorData[parseInt(index)][`message-title${selector}`] = false;
942
- const tagValidationResponse = this.validateTags(title, tags, injectedTags);
942
+ const tagValidationResponse = this.validateTags(title, tags, injectedTags, false, this.props?.isFullMode);
943
943
 
944
944
  if (tagValidationResponse.valid) {
945
945
  errorData[parseInt(index)][`message-title${selector}`] = false;
@@ -1193,7 +1193,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
1193
1193
  if (!content) {
1194
1194
  return false;
1195
1195
  }
1196
- const tagValidationResponse = this.validateTags(content, tags, injectedTags, isEmail);
1196
+ const tagValidationResponse = this.validateTags(content, tags, injectedTags, isEmail, this.props?.isFullMode);
1197
1197
 
1198
1198
  // Check for base64 images in email content
1199
1199
  isEmail && containsBase64Images({content, callback:()=>{
@@ -1500,7 +1500,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
1500
1500
  });
1501
1501
  }
1502
1502
 
1503
- validateTags(content, tagsParam, injectedTagsParams, isEmail = false) {
1503
+ validateTags(content, tagsParam, injectedTagsParams, isEmail = false, isFullMode = this.props?.isFullMode) {
1504
1504
  const type = (this.props.location && this.props.location.query.type) ? this.props.location.query.type : 'full';
1505
1505
  let currentModule = this.props.location.query.module ? this.props.location.query.module : 'default';
1506
1506
  if (this.props.tagModule) {
@@ -1518,7 +1518,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
1518
1518
  response.isBraceError = false;
1519
1519
  response.isContentEmpty = false;
1520
1520
  const contentForValidation = isEmail ? convert(content, GLOBAL_CONVERT_OPTIONS) : content ;
1521
- if(tags && tags.length) {
1521
+ if(tags && tags.length && !isFullMode) {
1522
1522
  _.forEach(tags, (tag) => {
1523
1523
  _.forEach(tag.definition.supportedModules, (module) => {
1524
1524
  if (module.mandatory && (currentModule === module.context)) {
@@ -40,6 +40,7 @@ export const TRACK_CREATE_IMAGE = 'createImage';
40
40
  export const TRACK_CREATE_LINE = 'createLine';
41
41
  export const TRACK_CREATE_VIBER = 'createViber';
42
42
  export const TRACK_CREATE_FACEBOOK = 'createFacebook';
43
+ export const TRACK_CREATE_WEBPUSH = 'createWebPush';
43
44
 
44
45
  export const CREATE = 'create';
45
46
  export const EDIT = 'edit';
@@ -54,6 +55,7 @@ export const EMAIL = 'email';
54
55
  export const ASSETS = 'assets';
55
56
  export const ZALO = 'zalo';
56
57
  export const INAPP = 'inapp';
58
+ export const WEBPUSH = 'webpush';
57
59
 
58
60
  export const JP_LOCALE_HIDE_FEATURE = 'JP_LOCALE_HIDE_FEATURE';
59
61
 
@@ -65,6 +67,7 @@ export const TRACK_EDIT_IMAGE = 'editImage';
65
67
  export const TRACK_EDIT_LINE = 'editLine';
66
68
  export const TRACK_EDIT_VIBER = 'editViber';
67
69
  export const TRACK_EDIT_FACEBOOK = 'editFacebook';
70
+ export const TRACK_EDIT_WEBPUSH = 'editWebPush';
68
71
 
69
72
  export const CHANNEL_CREATE_TRACK_MAPPING = {
70
73
  sms: TRACK_CREATE_SMS,
@@ -75,6 +78,7 @@ export const CHANNEL_CREATE_TRACK_MAPPING = {
75
78
  line: TRACK_CREATE_LINE,
76
79
  viber: TRACK_CREATE_VIBER,
77
80
  facebook: TRACK_CREATE_FACEBOOK,
81
+ webpush: TRACK_CREATE_WEBPUSH,
78
82
  };
79
83
 
80
84
  export const CHANNEL_EDIT_TRACK_MAPPING = {
@@ -86,6 +90,7 @@ export const CHANNEL_EDIT_TRACK_MAPPING = {
86
90
  line: TRACK_EDIT_LINE,
87
91
  viber: TRACK_EDIT_VIBER,
88
92
  facebook: TRACK_EDIT_FACEBOOK,
93
+ webpush: TRACK_EDIT_WEBPUSH,
89
94
  };
90
95
  export const GTM_TRACKING_ID = 'UA-110024621-2';
91
96
  export const BEE_PLUGIN = 'BEE_PLUGIN';
@@ -28,6 +28,10 @@ import { getWhatsappContent } from '../Whatsapp/utils';
28
28
  import * as commonUtil from '../../utils/common';
29
29
  import Zalo from '../Zalo';
30
30
  import MobilePushNew from '../MobilePushNew';
31
+ import WebPush from '../WebPush';
32
+ import DevicePreviewContent from '../WebPush/Create/preview/DevicePreviewContent';
33
+ import { LAYOUT_MODE } from '../WebPush/Create/preview/constants';
34
+ import { WEBPUSH_CONTENT_FIELDS, WEBPUSH_TEMPLATE_PATHS } from '../WebPush/constants';
31
35
  const CreativesWrapper = styled.div`
32
36
  .ant-popover,
33
37
  .ant-notification,
@@ -129,6 +133,7 @@ export function SlideBoxContent(props) {
129
133
  onValidationFail,
130
134
  channelsToHide,
131
135
  forwardedTags,
136
+ supportedTags = [],
132
137
  selectedOfferDetails,
133
138
  channelsToDisable,
134
139
  weChatTemplateType,
@@ -200,6 +205,7 @@ export function SlideBoxContent(props) {
200
205
  const isCreateRcs = isCreate && channel === constants.RCS;
201
206
  const isCreateMPush = isCreate && channel === constants.MOBILE_PUSH;
202
207
  const isCreateCallTask = isCreate && channel === constants.CALL_TASK;
208
+ const isCreateWebPush = isCreate && channel === constants.WEBPUSH;
203
209
  let isEditSms = false;
204
210
  let isEditEmailWithId = false;
205
211
  let isEmailEditWithContent = false;
@@ -207,12 +213,14 @@ export function SlideBoxContent(props) {
207
213
  let isEmailPreview = false;
208
214
  let isMpushPreview = false;
209
215
  let isInappPreview = false;
216
+ let isWebPushPreview = false;
210
217
  let isEditCallTask = false;
211
218
  let isEditMPush = false;
212
219
  let isEditFacebook = false;
213
220
  let isEditFTP = false;
214
221
  let isEditWhatsapp = false;
215
222
  let isEditInApp = false;
223
+ let isEditWebPush = false;
216
224
  let isEditRcs = false;
217
225
  let isEditZalo = false;
218
226
  const isEmailCreate = isCreate && channel === constants.EMAIL;
@@ -226,10 +234,12 @@ export function SlideBoxContent(props) {
226
234
  isEditFacebook = isEdit && channel === constants.FACEBOOK;
227
235
  isEditWhatsapp = isEdit && channel === constants.WHATSAPP;
228
236
  isEditRcs = isEdit && channel === constants.RCS;
237
+ isEditWebPush = isEdit && channel === constants.WEBPUSH;
229
238
  isPreview = slidBoxContent === 'preview' && [constants.SMS, constants.LINE, constants.WHATSAPP, constants.FACEBOOK, constants.VIBER, constants.RCS].includes(channel);
230
239
  isEmailPreview = slidBoxContent === 'preview' && channel === constants.EMAIL;
231
240
  isMpushPreview = slidBoxContent === 'preview' && channel === constants.MOBILE_PUSH;
232
241
  isInappPreview = slidBoxContent === 'preview' && channel === constants.INAPP;
242
+ isWebPushPreview = slidBoxContent === 'preview' && channel === constants.WEBPUSH;
233
243
  isEditFTP = isEdit && [constants.NO_COMMUNICATION, constants.FTP].includes(channel);
234
244
  isEditZalo = isEdit && channel?.toUpperCase() === constants.ZALO;
235
245
  isEditInApp = isEdit && channel === constants.INAPP;
@@ -477,8 +487,30 @@ export function SlideBoxContent(props) {
477
487
  templateData={templateData}
478
488
  channel={channel}
479
489
  forwardedTags={forwardedTags}
480
- />
490
+ />
481
491
  )}
492
+ {isWebPushPreview && (() => {
493
+ const webpushContent = get(templateData, WEBPUSH_TEMPLATE_PATHS.CONTENT, {});
494
+ const notificationTitle = webpushContent?.[WEBPUSH_CONTENT_FIELDS.TITLE] || '';
495
+ const notificationBody = webpushContent?.[WEBPUSH_CONTENT_FIELDS.MESSAGE] || '';
496
+ const imageSrc = webpushContent?.[WEBPUSH_CONTENT_FIELDS.IMAGE] || '';
497
+ const brandIconSrc = webpushContent?.[WEBPUSH_CONTENT_FIELDS.BRAND_ICON] || '';
498
+ // Extract URL from onClickAction or use empty string
499
+ const url = webpushContent?.[WEBPUSH_CONTENT_FIELDS.ON_CLICK_ACTION]?.url || '';
500
+
501
+ return (
502
+ <div className="webpush-preview-container">
503
+ <DevicePreviewContent
504
+ notificationTitle={notificationTitle}
505
+ notificationBody={notificationBody}
506
+ url={url}
507
+ imageSrc={imageSrc}
508
+ brandIconSrc={brandIconSrc}
509
+ layoutMode={LAYOUT_MODE.COMPACT}
510
+ />
511
+ </div>
512
+ );
513
+ })()}
482
514
 
483
515
  {
484
516
  (currentChannel === constants.WECHAT && !!slidBoxContent) && <WechatWrapper
@@ -1014,6 +1046,28 @@ export function SlideBoxContent(props) {
1014
1046
  />
1015
1047
  )}
1016
1048
 
1049
+ {(isCreateWebPush || isEditWebPush) && (
1050
+ <WebPush
1051
+ isFullMode={isFullMode}
1052
+ handleClose={handleClose}
1053
+ onCreateComplete={onCreateComplete}
1054
+ getFormData={getFormData}
1055
+ isGetFormData={isGetFormData}
1056
+ templateData={isEditWebPush ? templateData : undefined}
1057
+ creativesMode={creativesMode}
1058
+ params={isEditWebPush && templateData ? { id: templateData._id } : undefined}
1059
+ location={{
1060
+ pathname: isEditWebPush ? '/webpush/edit' : '/webpush/create',
1061
+ query,
1062
+ search: '',
1063
+ }}
1064
+ getDefaultTags={type}
1065
+ forwardedTags={forwardedTags}
1066
+ supportedTags={supportedTags}
1067
+ selectedOfferDetails={selectedOfferDetails}
1068
+ eventContextTags={eventContextTags}
1069
+ />
1070
+ )}
1017
1071
  {isCreateRcs && (<Rcs
1018
1072
  {...rcsCommonProps}
1019
1073
  showLiquidErrorInFooter={showLiquidErrorInFooter}
@@ -1076,6 +1130,7 @@ SlideBoxContent.propTypes = {
1076
1130
  onValidationFail: PropTypes.func,
1077
1131
  channelsToHide: PropTypes.array,
1078
1132
  forwardedTags: PropTypes.object,
1133
+ supportedTags: PropTypes.array,
1079
1134
  selectedOfferDetails: PropTypes.array,
1080
1135
  channelsToDisable: PropTypes.array,
1081
1136
  weChatTemplateType: PropTypes.string,
@@ -1091,7 +1146,7 @@ SlideBoxContent.propTypes = {
1091
1146
  onFTPSubmit: PropTypes.func,
1092
1147
  messageStrategy: PropTypes.string,
1093
1148
  fbAdManager: PropTypes.string,
1094
- showDisabledFBInfo: PropTypes.boolean,
1149
+ showDisabledFBInfo: PropTypes.bool,
1095
1150
  orgUnitId: PropTypes.any,
1096
1151
  smsRegister: PropTypes.any,
1097
1152
  getCmsTemplatesInProgress: PropTypes.bool,
@@ -71,6 +71,7 @@ export function SlideBoxHeader(props) {
71
71
  rcs: <FormattedMessage {...messages.rcsCreative} />,
72
72
  zalo: <FormattedMessage {...messages.zaloTemplate} />,
73
73
  viber: <FormattedMessage {...messages.viberTemplate} />,
74
+ webpush: <FormattedMessage {...messages.webPushTemplate} />,
74
75
  };
75
76
  return labels[currentChannel.toLowerCase()];
76
77
  };
@@ -21,6 +21,8 @@ export const PUSH = "PUSH";
21
21
  export const RCS = "RCS";
22
22
  export const ZALO = "ZALO";
23
23
  export const INAPP = "INAPP";
24
+ export const WEBPUSH = "WEBPUSH";
25
+ export const WEBPUSH_BRAND_ICON = "WEBPUSH_BRAND_ICON";
24
26
  export const PREVIEW = "preview";
25
27
  export const EDIT_TEMPLATE = "editTemplate";
26
28
  export const JOURNEY = "journey";
@@ -48,3 +50,4 @@ export const BIG_TEXT = "BIG_TEXT";
48
50
  export const GENERIC = "GENERIC";
49
51
  export const LIQUID_ERROR_MSG = "LIQUID_ERROR_MSG";
50
52
  export const STANDARD_ERROR_MSG = "STANDARD_ERROR_MSG";
53
+ export const COMMON_CHANNELS = ['sms', 'email', 'wechat', 'mobilepush', 'webpush', 'line', 'viber', 'facebook', 'call_task', 'ftp', 'assets'];
@@ -42,6 +42,7 @@ import { makeSelectFetchingCmsData } from '../Email/selectors';
42
42
  import {
43
43
  IMAGE as LINE_IMAGE, IMAGE_MAP, IMAGE_CAROUSEL, VIDEO as LINE_VIDEO, TEMPLATE, STICKER,
44
44
  } from '../Line/Container/constants';
45
+ import {EXTERNAL_URL, SITE_URL, WEBPUSH_MEDIA_TYPES} from '../WebPush/constants';
45
46
  import { IMAGE, VIDEO } from '../Facebook/Advertisement/constant';
46
47
  import {RCS_STATUSES} from '../Rcs/constants';
47
48
  import { CREATIVE } from '../Facebook/constants';
@@ -708,6 +709,73 @@ export class Creatives extends React.Component {
708
709
  };
709
710
  break;
710
711
  }
712
+ case constants.WEBPUSH: {
713
+ // Convert from campaign format (messageContent.content.content) to creatives format
714
+ const webpushContent = get(templateData, 'content', {});
715
+ const accountId = get(templateData, 'accountId');
716
+ const {
717
+ title,
718
+ message,
719
+ iconImageUrl: brandIcon = "",
720
+ cta,
721
+ expandableDetails
722
+ } = webpushContent || {};
723
+
724
+ // Map cta to onClickAction
725
+ let onClickAction = null;
726
+ if (cta) {
727
+ if (cta?.type === EXTERNAL_URL) {
728
+ onClickAction = {
729
+ type: URL,
730
+ url: cta?.actionLink || '',
731
+ };
732
+ } else {
733
+ onClickAction = {
734
+ type: cta?.type || SITE_URL,
735
+ };
736
+ }
737
+ }
738
+
739
+ // Map expandableDetails.ctas to ctas array
740
+ let ctas = [];
741
+ if (expandableDetails?.ctas && expandableDetails?.ctas?.length > 0) {
742
+ ctas = expandableDetails?.ctas?.map((ctaItem) => ({
743
+ actionText: ctaItem?.title || ctaItem?.actionText || '',
744
+ type: URL,
745
+ actionLink: ctaItem?.actionLink || '',
746
+ }));
747
+ }
748
+
749
+ // Map expandableDetails.media to image if present
750
+ let image = null;
751
+ if (expandableDetails?.media && expandableDetails?.media?.length > 0) {
752
+ const firstMedia = expandableDetails?.media[0];
753
+ if (firstMedia?.type === WEBPUSH_MEDIA_TYPES.IMAGE && firstMedia?.url) {
754
+ image = firstMedia?.url;
755
+ }
756
+ }
757
+
758
+ creativesTemplateData = {
759
+ type: channel,
760
+ name: templateData?.messageSubject,
761
+ versions: {
762
+ base: {
763
+ content: {
764
+ webpush: {
765
+ title: title || '',
766
+ message: message || '',
767
+ ...(brandIcon && { brandIcon }),
768
+ ...(onClickAction && { onClickAction }),
769
+ ...(ctas.length > 0 && { ctas }),
770
+ ...(image && { image, mediaType: IMAGE }),
771
+ },
772
+ },
773
+ },
774
+ },
775
+ definition: { accountId },
776
+ };
777
+ break;
778
+ }
711
779
  default:
712
780
  break;
713
781
  }
@@ -1122,6 +1190,105 @@ export class Creatives extends React.Component {
1122
1190
  }
1123
1191
  }
1124
1192
  break;
1193
+ case constants.WEBPUSH: {
1194
+ if (template.value) {
1195
+ const channelTemplate = template.value;
1196
+ const accountId = get(channelTemplate, 'definition.accountId');
1197
+ const webpushContent = get(channelTemplate, 'versions.base.content.webpush', {});
1198
+ const {
1199
+ title,
1200
+ message,
1201
+ brandIcon,
1202
+ iconImageUrl: templateImageUrl ,
1203
+ onClickAction,
1204
+ ctas: templateCtas,
1205
+ cta: templateCta,
1206
+ expandableDetails: templateExpandableDetails,
1207
+ image
1208
+ } = webpushContent || {};
1209
+
1210
+ const iconImageUrl = brandIcon || templateImageUrl || '';
1211
+
1212
+ // Map onClickAction to cta
1213
+ let cta = null;
1214
+ if (onClickAction) {
1215
+ if (onClickAction?.type === URL) {
1216
+ cta = {
1217
+ type: EXTERNAL_URL,
1218
+ actionLink: onClickAction?.url || '',
1219
+ };
1220
+ } else {
1221
+ cta = {
1222
+ type: onClickAction?.type || SITE_URL,
1223
+ actionLink: onClickAction?.url || '',
1224
+ };
1225
+ }
1226
+ } else if (templateCta) {
1227
+ // Fallback to cta if onClickAction is not present
1228
+ cta = {
1229
+ type: templateCta?.type || EXTERNAL_URL,
1230
+ actionLink: templateCta?.actionLink || '',
1231
+ };
1232
+ }
1233
+
1234
+ // Map ctas array to expandableDetails.ctas
1235
+ let expandableDetails = null;
1236
+ const hasCtas = templateCtas && templateCtas.length > 0;
1237
+ const hasImage = image;
1238
+
1239
+ if (hasCtas || hasImage) {
1240
+ expandableDetails = {
1241
+ media: [],
1242
+ ctas: [],
1243
+ };
1244
+
1245
+ // Map image to expandableDetails.media
1246
+ if (hasImage) {
1247
+ expandableDetails.media = [{
1248
+ url: image,
1249
+ type: IMAGE,
1250
+ }];
1251
+ }
1252
+
1253
+ // Map ctas array to expandableDetails.ctas
1254
+ if (hasCtas) {
1255
+ expandableDetails.ctas = templateCtas.map((ctaItem) => ({
1256
+ type: ctaItem?.type === URL ? EXTERNAL_URL : ctaItem?.type,
1257
+ action: ctaItem?.action || '',
1258
+ title: ctaItem?.actionText || ctaItem?.title || '',
1259
+ actionLink: ctaItem?.actionLink || '',
1260
+ }));
1261
+ }
1262
+ } else if (templateExpandableDetails) {
1263
+ // If expandableDetails already exists, use it
1264
+ expandableDetails = {
1265
+ media: templateExpandableDetails?.media || [],
1266
+ ctas: templateExpandableDetails?.ctas || [],
1267
+ };
1268
+ }
1269
+
1270
+ // Convert from creatives format to campaign format
1271
+ templateData = {
1272
+ channel,
1273
+ messageContent: {
1274
+ content: {
1275
+ channel: constants.WEBPUSH,
1276
+ accountId,
1277
+ content: {
1278
+ title: title || '',
1279
+ message: message || '',
1280
+ ...(iconImageUrl && { iconImageUrl }),
1281
+ ...(cta && { cta }),
1282
+ ...(expandableDetails && { expandableDetails }),
1283
+ },
1284
+ messageSubject: channelTemplate?.name ? channelTemplate.name : 'messageSubject',
1285
+ offers: [],
1286
+ },
1287
+ },
1288
+ };
1289
+ }
1290
+ break;
1291
+ }
1125
1292
  default:
1126
1293
  break;
1127
1294
  }
@@ -1173,6 +1340,7 @@ export class Creatives extends React.Component {
1173
1340
  case constants.SMS:
1174
1341
  case constants.WECHAT:
1175
1342
  case constants.VIBER:
1343
+ case constants.WEBPUSH:
1176
1344
  break;
1177
1345
  case constants.EMAIL:
1178
1346
  gtmDetails = {
@@ -338,6 +338,10 @@ export default defineMessages({
338
338
  id: `${scope}.rcsCreative`,
339
339
  defaultMessage: `RCS creative`,
340
340
  },
341
+ "webPushTemplate": {
342
+ id: `${scope}.webPushTemplate`,
343
+ defaultMessage: `Web Push Template`,
344
+ },
341
345
  "templateNameEmpty": {
342
346
  id: `${scope}.templateNameEmpty`,
343
347
  defaultMessage: `Template name cannot be empty`