@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
@@ -79,6 +79,7 @@ import * as whatsappActions from '../Whatsapp/actions';
79
79
  import * as rcsActions from '../Rcs/actions';
80
80
  import * as zaloActions from '../Zalo/actions';
81
81
  import * as inAppActions from '../InApp/actions';
82
+ import * as webpushActions from '../WebPush/actions';
82
83
  import * as globalActions from '../Cap/actions';
83
84
  import { makeSelectAuthenticated } from '../Cap/selectors';
84
85
  import { UserIsAuthenticated } from '../../utils/authWrapper';
@@ -137,7 +138,7 @@ import rcsMessages from '../Rcs/messages';
137
138
  import globalMessages from '../../v2Containers/Cap/messages';
138
139
  import { handlePreviewInNewTab } from '../../utils/common';
139
140
 
140
- import { MOBILE_PUSH, WECHAT, SMS, EMAIL, EBILL, LINE, VIBER, FACEBOOK, WHATSAPP, RCS, ZALO, INAPP } from '../CreativesContainer/constants';
141
+ import { MOBILE_PUSH, WECHAT, SMS, EMAIL, EBILL, LINE, VIBER, FACEBOOK, WHATSAPP, RCS, ZALO, INAPP, WEBPUSH } from '../CreativesContainer/constants';
141
142
 
142
143
  import {CREATIVE} from '../Facebook/constants';
143
144
  import videoPlay from '../../assets/videoPlay.svg';
@@ -155,10 +156,13 @@ import { DAEMON } from '@capillarytech/vulcan-react-sdk/utils/sagaInjectorTypes'
155
156
  import { Rcs } from '../Rcs';
156
157
  import { makeSelectRcs } from '../Rcs/selectors';
157
158
  import { getRcsStatusType } from '../Rcs/utils';
159
+ import { makeSelectWebPush } from '../WebPush/selectors';
158
160
  import { v2MobilePushSagas } from '../MobilePushNew/sagas';
159
161
  import { AUTO_CAROUSEL, BIG_PICTURE, FILMSTRIP_CAROUSEL, MANUAL_CAROUSEL } from '../MobilePushNew/constants';
160
162
  import CapPageSpinner from '../../v2Components/CapPageSpinner';
163
+ import webPushSagas from '../WebPush/sagas';
161
164
  const withMobilePushNewSaga = injectSaga({ key: 'mobilePushNew', saga: v2MobilePushSagas, mode: DAEMON });
165
+ const withWebPushSaga = injectSaga({ key: 'webPush', saga: webPushSagas, mode: DAEMON });
162
166
 
163
167
  const { timeTracker } = GA;
164
168
  const {CapCustomCardList} = CapCustomCard;
@@ -212,6 +216,7 @@ const EBILL_LOWERCASE = EBILL.toLowerCase();
212
216
  const LINE_LOWERCASE = LINE.toLowerCase();
213
217
  const ZALO_LOWERCASE = ZALO.toLowerCase();
214
218
  const WECHAT_LOWERCASE = WECHAT.toLowerCase();
219
+ const WEBPUSH_LOWERCASE = WEBPUSH.toLowerCase();
215
220
  const duplicateEnum = {
216
221
  sms: "smsActions",
217
222
  line: "lineActions",
@@ -270,6 +275,9 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
270
275
  // Phase 18: EMAIL API call flag
271
276
  isWaitingForEmailTemplateDetails: false,
272
277
  };
278
+ // Timeout IDs for cleanup
279
+ this._clearEditTimeout = null;
280
+ this._clearCreateTimeout = null;
273
281
  this.getAllTemplates = this.getAllTemplates.bind(this);
274
282
  this.createTemplate = this.createTemplate.bind(this);
275
283
  this.searchTemplate = this.searchTemplate.bind(this);
@@ -395,10 +403,19 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
395
403
  orgUnitId: -1,
396
404
  });
397
405
  break;
406
+ case WEBPUSH:
407
+ channel = 'Webpush';
408
+ activeMode = ACCOUNT_SELECTION_MODE;
409
+ this.props.actions.getWeCrmAccounts('WebPush');
410
+ break;
398
411
  default:
399
412
  channel = '';
400
413
  }
401
414
  this.setState({ channel, activeMode });
415
+ // Clear templates when entering account selection mode to prevent showing old channel templates
416
+ if (activeMode === ACCOUNT_SELECTION_MODE) {
417
+ this.props.actions.resetTemplate();
418
+ }
402
419
  if (isEmpty(this.props.Templates?.userList)) {
403
420
  this.props.actions.getUserList();
404
421
  }
@@ -496,6 +513,10 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
496
513
  channel = 'Facebook';
497
514
  this.setState({defaultAccount: true});
498
515
  nextProps.actions.getAccountsSettings();
516
+ } else if (nextProps.route.name.toLowerCase() === WEBPUSH_LOWERCASE) {
517
+ this.setState({defaultAccount: true});
518
+ channel = 'Webpush';
519
+ nextProps.actions.getWeCrmAccounts('WebPush');
499
520
  }
500
521
 
501
522
  // Phase 14: Reset Test and Preview state on channel change
@@ -647,6 +668,50 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
647
668
  }, 1000);
648
669
  }
649
670
 
671
+ // Check for WebPush edit response - prevent duplicate calls
672
+ if (selectedChannel === WEBPUSH_LOWERCASE && nextProps.WebPush?.editResponse && (nextProps.WebPush.editResponse.templateId || nextProps.WebPush.editResponse._id) && !isEqual(nextProps.WebPush.editResponse, this.props.WebPush?.editResponse)) {
673
+ const channelLabel = this.props.intl.formatMessage(messages.webpushHeader);
674
+ const message = `${channelLabel} ${this.props.intl.formatMessage(messages.templateUpdateSuccess)}`;
675
+ CapNotification.success({
676
+ key: 'webpushEditSuccess',
677
+ message
678
+ });
679
+ // Clear previous state before loading newer templates
680
+ this.props.actions.resetTemplate();
681
+ this.getAllTemplates({params, resetPage: true});
682
+ // Delay clearing to allow drawer to close first
683
+ // Clear any existing timeout before setting a new one
684
+ if (this._clearEditTimeout) {
685
+ clearTimeout(this._clearEditTimeout);
686
+ }
687
+ this._clearEditTimeout = setTimeout(() => {
688
+ this.props.webpushActions.clearEditResponse();
689
+ this._clearEditTimeout = null;
690
+ }, 200);
691
+ }
692
+
693
+ // Check for WebPush create response (for new template creation)
694
+ if (selectedChannel === WEBPUSH_LOWERCASE && nextProps.WebPush?.response && (nextProps.WebPush.response?.templateId || nextProps.WebPush.response?._id) && !isEqual(nextProps.WebPush.response, this.props.WebPush?.response)) {
695
+ // Skip showing generic "created" toast when this is a duplicate operation
696
+ if (!nextProps.WebPush.response.meta?.isDuplicate) {
697
+ const channelLabel = this.props.intl.formatMessage(messages.webpushHeader);
698
+ const message = `${channelLabel} ${this.props.intl.formatMessage(messages.templateCreateSuccess)}`;
699
+ CapNotification.success({key: 'webpushCreateSuccess', message});
700
+ // Clear previous state before loading newer templates
701
+ this.props.actions.resetTemplate();
702
+ this.getAllTemplates({params, resetPage: true});
703
+ // Delay clearing to allow drawer to close first
704
+ // Clear any existing timeout before setting a new one
705
+ if (this._clearCreateTimeout) {
706
+ clearTimeout(this._clearCreateTimeout);
707
+ }
708
+ this._clearCreateTimeout = setTimeout(() => {
709
+ this.props.webpushActions.clearCreateResponse();
710
+ this._clearCreateTimeout = null;
711
+ }, 200);
712
+ }
713
+ }
714
+
650
715
 
651
716
 
652
717
  if (nextProps.Create && this.props.Create && nextProps.Create.createTemplateError && !isEqual(nextProps.Create.createTemplateError, this.props.Create.createTemplateError)) {
@@ -654,7 +719,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
654
719
  if ((this.state.channel || '').toLowerCase() !== "sms") {
655
720
  CapNotification.error({key: 'somethingWrong', message});
656
721
  }
657
- const { smsActions, mobilepushActions, ebillActions, lineActions, viberActions, facebookActions, whatsappActions, inAppActions, rcsActions } = this.props;
722
+ const { smsActions, mobilepushActions, ebillActions, lineActions, viberActions, facebookActions, whatsappActions, inAppActions, rcsActions, webpushActions } = this.props;
658
723
  switch (selectedChannel) {
659
724
  case SMS_LOWERCASE:
660
725
  smsActions.clearCreateResponse();
@@ -683,6 +748,9 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
683
748
  case inAppActions:
684
749
  inAppActions.clearCreateResponse();
685
750
  break;
751
+ case WEBPUSH_LOWERCASE:
752
+ webpushActions.clearCreateResponse();
753
+ break;
686
754
  default:
687
755
  break;
688
756
  }
@@ -695,6 +763,10 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
695
763
  nextProps.Templates.deleteResponse) {
696
764
  const message = `${this.state.channel} ${this.props.intl.formatMessage(messages['Template deleted successfully'])}`;
697
765
  CapNotification.success({key: 'deleteSucess', message});
766
+ // Clear previous state before loading newer templates for web push channel
767
+ if (selectedChannel === WEBPUSH_LOWERCASE) {
768
+ this.props.actions.resetTemplate();
769
+ }
698
770
  this.getAllTemplates({params, resetPage: true});
699
771
  }
700
772
 
@@ -807,7 +879,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
807
879
  this.setState({ previewTemplate: nextProps.Templates.templateDetails });
808
880
  }
809
881
  const { weCrmAccounts: weCrmAccountsList = [], senderDetails = {} } = get(nextProps, 'Templates', {});
810
- const weCrmChannels = [WHATSAPP_LOWERCASE, ZALO_LOWERCASE, RCS_LOWERCASE];
882
+ const weCrmChannels = [WHATSAPP_LOWERCASE, ZALO_LOWERCASE, RCS_LOWERCASE, WEBPUSH_LOWERCASE];
811
883
 
812
884
  // Keeping the wechat flow separate as it has different logic for setting the account. Currently we don't support wechat but still keeping the flow.
813
885
  if (weCrmAccountsList?.length === 1 && this.state?.defaultAccount && selectedChannel === WECHAT_LOWERCASE && !isEmpty(senderDetails?.hostName)) {
@@ -834,9 +906,9 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
834
906
  const isSingleAccount = weCrmAccountsList?.length === 1;
835
907
  const selectedAccount = this.props.Templates[ACCOUNT_MAPPING_ON_CHANNEL[selectedChannel]] || {};
836
908
  const hostName = this.getHostName(isSingleAccount ? weCrmAccountsList[0]?.sourceAccountIdentifier : selectedAccount?.sourceAccountIdentifier, senderDetails?.domainProperties);
837
- if (!isEmpty(hostName)) {
909
+ if (!isEmpty(hostName) || selectedChannel === WEBPUSH_LOWERCASE) {
838
910
  const paramsDefault = {};
839
- const {name, sourceAccountIdentifier, configs } = weCrmAccountsList?.[0] || {};
911
+ const {name, sourceAccountIdentifier, configs, id } = weCrmAccountsList?.[0] || {};
840
912
  if (isSingleAccount) {
841
913
  weCrmAccountsList[0].hostName = hostName;
842
914
  this.setState({ selectedAccount: name });
@@ -861,6 +933,9 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
861
933
  paramsDefault.accessToken = configs?.accessToken;
862
934
  paramsDefault.host = hostName || this.props.Templates?.selectedRcsAccount?.hostName;
863
935
  }
936
+ if (selectedChannel === WEBPUSH_LOWERCASE) {
937
+ paramsDefault.accountId = id;
938
+ }
864
939
  this.setState({ defaultAccount: false });
865
940
  /**
866
941
  * Incase of multiple accounts, getAllTemplates is called on selecting the account. It's handled in onAccountSelect function.
@@ -883,6 +958,15 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
883
958
  window.removeEventListener("message", this.handleFrameTasks);
884
959
  this.props.actions.resetTemplateStoreData();
885
960
  this.props.globalActions.clearMetaEntities();
961
+ // Clear any pending timeouts to prevent memory leaks
962
+ if (this._clearEditTimeout) {
963
+ clearTimeout(this._clearEditTimeout);
964
+ this._clearEditTimeout = null;
965
+ }
966
+ if (this._clearCreateTimeout) {
967
+ clearTimeout(this._clearCreateTimeout);
968
+ this._clearCreateTimeout = null;
969
+ }
886
970
  // this.props.actions.resetAccount();
887
971
  // this.setState({defaultAccount: false});
888
972
  // Phase 14: Cleanup Test and Preview state
@@ -893,8 +977,10 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
893
977
  });
894
978
  }
895
979
 
896
- onAccountSelect(e) {
980
+ onAccountSelect(e) {
897
981
  const value = e.target.value;
982
+ // Clear templates immediately when account is selected to prevent showing old channel templates
983
+ this.props.actions.resetTemplate();
898
984
  this.setState({selectedAccount: value}, () => {
899
985
  const params = {};
900
986
  if (this.state.channel.toLowerCase() !== ZALO_LOWERCASE) {
@@ -922,7 +1008,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
922
1008
  } else {
923
1009
  this.setState({ selectedAccountError: false });
924
1010
  }
925
- } else if ([LINE.toLowerCase(), RCS_LOWERCASE, ZALO_LOWERCASE, WHATSAPP_LOWERCASE].includes(selectedChannel)) {
1011
+ } else if ([LINE.toLowerCase(), RCS_LOWERCASE, ZALO_LOWERCASE, WHATSAPP_LOWERCASE, WEBPUSH_LOWERCASE].includes(selectedChannel)) {
926
1012
  const setAcc = this.props?.Templates?.weCrmAccounts?.find((item) => item?.name === this.state.selectedAccount);
927
1013
  const { domainProperties = [] } = this.props?.Templates?.senderDetails || {};
928
1014
  let hostName = '';
@@ -949,6 +1035,9 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
949
1035
  params.accountId = sourceAccountIdentifier;
950
1036
  params.host = hostName;
951
1037
  }
1038
+ if (selectedChannel === WEBPUSH_LOWERCASE && setAcc) {
1039
+ params.accountId = setAcc.accountId || setAcc.id;
1040
+ }
952
1041
  if (selectedChannel === RCS_LOWERCASE && hostName) {
953
1042
  const { configs: { accessToken = "" } = {} } = setAcc || {};
954
1043
  params.accountId = sourceAccountIdentifier;
@@ -1402,32 +1491,41 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
1402
1491
  let creativesParams = {mode: ''};
1403
1492
  if (!isEmpty(routeParams)) {
1404
1493
  const { pathname } = routeParams;
1405
- if (pathname.includes('create')) {
1406
- creativesParams.mode = 'create';
1407
- } else if (pathname.includes('edit') || pathname.includes('overview')) {
1408
- creativesParams.mode = 'edit';
1409
- if (pathname.includes('richmedia')) {
1410
- creativesParams._id = pathname.split('/')[4];
1411
- creativesParams.definition = {
1412
- msgcontent: "RICH_MEDIA_WECHAT",
1413
- };
1414
- } else {
1415
- creativesParams._id = pathname.split('/')[3];
1416
- creativesParams.modeType = pathname.split('/')[4];
1417
- creativesParams.account = pathname.split('/')[5];
1418
- if (this.state.channel.toLowerCase() === WHATSAPP_LOWERCASE) {
1419
- const whatsappSelectedTemplateData = this.selectTemplate(creativesParams._id) || {};
1420
- const { name = '', versions = {} } = whatsappSelectedTemplateData;
1421
- creativesParams.whatsappTemplateName = name;
1422
- creativesParams.whatsappTemplateCategory = get(versions, `base.content.whatsapp.category`, '');
1423
- creativesParams.whatsappTemplateLanguageCode = get(versions, `base.content.whatsapp.languages[0].language`, '');
1424
- } else if (this.state.channel.toLocaleLowerCase() === ZALO_LOWERCASE) {
1425
- const zaloSelectedTemplateData = this.selectTemplate(parseInt(creativesParams._id, 10)) || {};
1426
- const { name = '' } = zaloSelectedTemplateData;
1427
- creativesParams.name = name
1494
+ if (pathname) {
1495
+ if (pathname.includes('create')) {
1496
+ creativesParams.mode = 'create';
1497
+ } else if (pathname.includes('edit') || pathname.includes('overview')) {
1498
+ creativesParams.mode = 'edit';
1499
+ if (pathname.includes('richmedia')) {
1500
+ creativesParams._id = pathname.split('/')[4];
1501
+ creativesParams.definition = {
1502
+ msgcontent: "RICH_MEDIA_WECHAT",
1503
+ };
1504
+ } else {
1505
+ creativesParams._id = pathname.split('/')[3];
1506
+ creativesParams.modeType = pathname.split('/')[4];
1507
+ creativesParams.account = pathname.split('/')[5];
1508
+ if (this.state.channel.toLowerCase() === WHATSAPP_LOWERCASE) {
1509
+ const whatsappSelectedTemplateData = this.selectTemplate(creativesParams._id) || {};
1510
+ const { name = '', versions = {} } = whatsappSelectedTemplateData;
1511
+ creativesParams.whatsappTemplateName = name;
1512
+ creativesParams.whatsappTemplateCategory = get(versions, `base.content.whatsapp.category`, '');
1513
+ creativesParams.whatsappTemplateLanguageCode = get(versions, `base.content.whatsapp.languages[0].language`, '');
1514
+ } else if (this.state.channel.toLocaleLowerCase() === ZALO_LOWERCASE) {
1515
+ const zaloSelectedTemplateData = this.selectTemplate(parseInt(creativesParams._id, 10)) || {};
1516
+ const { name = '' } = zaloSelectedTemplateData;
1517
+ creativesParams.name = name
1518
+ } else if (this.state.channel.toLowerCase() === WEBPUSH_LOWERCASE) {
1519
+ // For WebPush, extract only the fields the component uses
1520
+ const webpushSelectedTemplateData = this.selectTemplate(creativesParams._id) || {};
1521
+ const { name = '', definition = {}, versions = {} } = webpushSelectedTemplateData;
1522
+ creativesParams.name = name;
1523
+ creativesParams.definition = definition;
1524
+ creativesParams.versions = versions;
1525
+ }
1428
1526
  }
1527
+ creativesParams.type = this.state.channel.toUpperCase();
1429
1528
  }
1430
- creativesParams.type = this.state.channel.toUpperCase();
1431
1529
  }
1432
1530
  }
1433
1531
  if (this.state.previewOpen) {
@@ -1461,6 +1559,13 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
1461
1559
  queryParams.host = params?.host || this.state?.hostName;
1462
1560
  };
1463
1561
 
1562
+ setWebpushQueryParams = (queryParams, params) => {
1563
+ const selectedAccount = this.props.Templates?.selectedWebPushAccount;
1564
+ queryParams.accountId = params?.accountId
1565
+ || selectedAccount?.accountId
1566
+ || selectedAccount?.id;
1567
+ };
1568
+
1464
1569
  getAllTemplates = ({params, getNextPage, resetPage}, resetTemplates) => {
1465
1570
  let queryParams = params || {};
1466
1571
  let page = this.state.page;
@@ -1492,6 +1597,9 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
1492
1597
  if (this.state?.channel?.toLowerCase() === WHATSAPP_LOWERCASE) {
1493
1598
  this.setWhatsappQueryParams(queryParams, params);
1494
1599
  }
1600
+ if (this.state?.channel?.toLowerCase() === WEBPUSH_LOWERCASE) {
1601
+ this.setWebpushQueryParams(queryParams, params);
1602
+ }
1495
1603
  if (this.state?.channel?.toLowerCase() === RCS_LOWERCASE && !isEmpty(this.props.Templates?.selectedRcsAccount)) {
1496
1604
  const { sourceAccountIdentifier = '', configs: { accessToken = '' } = {}, hostName = '' } = this.props.Templates.selectedRcsAccount;
1497
1605
  if (sourceAccountIdentifier) {
@@ -1556,6 +1664,9 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
1556
1664
  if (this.state?.channel?.toLowerCase() === WHATSAPP_LOWERCASE) {
1557
1665
  this.setWhatsappQueryParams(queryParams, params);
1558
1666
  }
1667
+ if (this.state?.channel?.toLowerCase() === WEBPUSH_LOWERCASE) {
1668
+ this.setWebpushQueryParams(queryParams, params);
1669
+ }
1559
1670
  if (this.state?.channel?.toLowerCase() === RCS_LOWERCASE && !isEmpty(this.props.Templates?.selectedRcsAccount)) {
1560
1671
  const { sourceAccountIdentifier = '', configs: { accessToken = '' } = {}, hostName = '' } = this.props.Templates.selectedRcsAccount;
1561
1672
  if (sourceAccountIdentifier) {
@@ -2302,6 +2413,70 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
2302
2413
  templateData.content = <CapLabel type="label19" className="zalo-listing-content desc">{template.name}</CapLabel>;
2303
2414
  break;
2304
2415
  }
2416
+ case WEBPUSH: {
2417
+ const webpushContent = get(template, 'versions.base.content.webpush', {});
2418
+ const notificationTitle = webpushContent?.title || '';
2419
+ const notificationMessage = webpushContent?.message || '';
2420
+ const brandIcon = webpushContent?.brandIcon || '';
2421
+ const mediaImage = webpushContent?.image || '';
2422
+ const ctaButtons = Array.isArray(webpushContent?.ctas)
2423
+ ? webpushContent.ctas.filter(
2424
+ (cta) => typeof cta?.actionText === 'string' && cta.actionText.trim()
2425
+ )
2426
+ : [];
2427
+ const visibleCtas = ctaButtons.slice(0, 2);
2428
+ templateData.content = (
2429
+ <div className="sms-template-content webpush-template-content">
2430
+ <div className="webpush-template-card">
2431
+ <div className="webpush-template-meta">
2432
+ {brandIcon ? (
2433
+ <img
2434
+ src={brandIcon}
2435
+ alt="Brand Icon"
2436
+ className="webpush-brand-icon"
2437
+ />
2438
+ ) : (
2439
+ <span className="webpush-brand-icon-placeholder" />
2440
+ )}
2441
+ <div className="webpush-template-text">
2442
+ <div className="webpush-template-header">
2443
+ <div className="webpush-template-title">
2444
+ {notificationTitle}
2445
+ </div>
2446
+ <div className="webpush-template-time">2:29 PM</div>
2447
+ </div>
2448
+ {notificationMessage ? (
2449
+ <div className="webpush-template-message">
2450
+ {notificationMessage}
2451
+ </div>
2452
+ ) : null}
2453
+ {mediaImage ? (
2454
+ <img
2455
+ src={mediaImage}
2456
+ alt="Media"
2457
+ className="webpush-media-image"
2458
+ />
2459
+ ) : null}
2460
+ </div>
2461
+ </div>
2462
+ {visibleCtas.length ? (
2463
+ <div
2464
+ className={`webpush-template-cta-section${
2465
+ visibleCtas.length === 1 ? ' single-cta' : ''
2466
+ }`}
2467
+ >
2468
+ {visibleCtas.map((cta, index) => (
2469
+ <div className="webpush-template-cta-item" key={`webpush-cta-${index}`}>
2470
+ <span className="webpush-template-cta-text">{cta.actionText}</span>
2471
+ </div>
2472
+ ))}
2473
+ </div>
2474
+ ) : null}
2475
+ </div>
2476
+ </div>
2477
+ );
2478
+ break;
2479
+ }
2305
2480
  default:
2306
2481
  templateData.content = "";
2307
2482
  }
@@ -2337,7 +2512,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
2337
2512
  const noLoaderAndSearchText = isEmpty(this.state.searchText) && !isLoading;
2338
2513
 
2339
2514
  return (<div>
2340
- {[WECHAT, MOBILE_PUSH, INAPP, WHATSAPP, ZALO,RCS].includes(currentChannel) && this.showAccountName()}
2515
+ {[WECHAT, MOBILE_PUSH, WEBPUSH, INAPP, WHATSAPP, ZALO, RCS].includes(currentChannel) && this.showAccountName()}
2341
2516
  {filterContent}
2342
2517
  {[WHATSAPP, ZALO,RCS].includes(currentChannel) && this.selectedFilters()}
2343
2518
  {<div>
@@ -2411,6 +2586,11 @@ return (<div>
2411
2586
  <ChannelTypeIllustration isFullMode={this.props.isFullMode} createTemplate={this.createTemplate} currentChannel={currentChannel}/>
2412
2587
  </div>
2413
2588
  }
2589
+ {showIllustrationForChannel(WEBPUSH_LOWERCASE) &&
2590
+ <div style={this.isFullMode() ? { height: "calc(100vh - 20.3125rem)", overflow: 'auto' } : {}}>
2591
+ <ChannelTypeIllustration isFullMode={this.props.isFullMode} createTemplate={this.createTemplate} currentChannel={currentChannel} hostName={this.state?.hostName}/>
2592
+ </div>
2593
+ }
2414
2594
  {<CapCustomSkeleton loader={isInitialLoading && (isLoading || getAllTemplatesInProgress)} />}
2415
2595
  {<CapPageSpinner spinning={!isInitialLoading && (isLoading || getAllTemplatesInProgress)} />}
2416
2596
  </div>
@@ -2804,6 +2984,10 @@ return (<div>
2804
2984
  params.host = this.state?.hostName;
2805
2985
  }
2806
2986
  this.delay(() => {
2987
+ // Clear previous state before loading newer templates for web push channel
2988
+ if (this.state.channel.toLowerCase() === WEBPUSH_LOWERCASE) {
2989
+ this.props.actions.resetTemplate();
2990
+ }
2807
2991
  this.getAllTemplates({params, resetPage: true});
2808
2992
  }, 500);
2809
2993
  });
@@ -2967,6 +3151,32 @@ return (<div>
2967
3151
  this.getAllTemplates({params: {}}, true);
2968
3152
  this.props.inAppActions.clearCreateResponse();
2969
3153
  });
3154
+ } else if (this.state.channel.toLowerCase() === "webpush") {
3155
+ const params = {
3156
+ name: this.state.searchText,
3157
+ sortBy: this.state.sortBy,
3158
+ };
3159
+
3160
+ // Get the selected WebPush account
3161
+ const selectedAccount = this.props.Templates?.selectedWebPushAccount;
3162
+
3163
+ // Set the accountId in the duplicate object
3164
+ if (duplicateObj.definition) {
3165
+ duplicateObj.definition.accountId = selectedAccount?.accountId || selectedAccount?.id;
3166
+ }
3167
+
3168
+ const channelLabel = this.props.intl.formatMessage(messages.webpushHeader);
3169
+ this.props.webpushActions.createTemplate(duplicateObj, (response) => {
3170
+ if (response && (response.templateId || response._id)) {
3171
+ // Clear response immediately to prevent componentWillReceiveProps from showing "created" notification
3172
+ this.props.webpushActions.clearCreateResponse();
3173
+ // Clear previous state before loading newer templates
3174
+ this.props.actions.resetTemplate();
3175
+ const message = `${channelLabel} ${this.props.intl.formatMessage(messages.templateDuplicateSuccess)}`;
3176
+ CapNotification.success({key: 'duplicateSuccess', message});
3177
+ this.getAllTemplates({params, resetPage: true});
3178
+ }
3179
+ }, { isDuplicate: true });
2970
3180
  } else if (this.state.channel.toLowerCase() === "ebill") {
2971
3181
  this.props.ebillActions.createTemplate(duplicateObj);
2972
3182
  } else if (this.state.channel.toLowerCase() === "email") {
@@ -3101,6 +3311,10 @@ return (<div>
3101
3311
  pathName = `/inapp/edit/${id}/`;
3102
3312
  break;
3103
3313
  }
3314
+ case WEBPUSH: {
3315
+ pathName = `/webpush/edit/${id}`;
3316
+ break;
3317
+ }
3104
3318
  default:
3105
3319
  break;
3106
3320
  }
@@ -3448,6 +3662,14 @@ return (<div>
3448
3662
  fetchingWeCrmAccounts,
3449
3663
  sendingFile,
3450
3664
  } = Templates;
3665
+
3666
+ // Show loading when in account selection or account change mode
3667
+ const isAccountSelectionMode = this.state.activeMode === ACCOUNT_SELECTION_MODE ||
3668
+ this.state.activeMode === ACCOUNT_CHANGE_MODE;
3669
+ if (isAccountSelectionMode) {
3670
+ return false;
3671
+ }
3672
+
3451
3673
  const lineLoader = this.checkLoader('line');
3452
3674
  const smsLoader = this.checkLoader('sms');
3453
3675
  const viberLoader = this.checkLoader(VIBER_CHANNEL);
@@ -3470,6 +3692,10 @@ return (<div>
3470
3692
  fetchingWeCrmAccounts ) &&
3471
3693
  this.state.channel.toLowerCase() === ZALO_LOWERCASE;
3472
3694
  const mobilePushLoader = (((getAllTemplatesInProgress) || (fetchingWeCrmAccounts)) && this.state.channel.toLowerCase() === 'mobilepush');
3695
+ const webpushLoader = (
3696
+ (getAllTemplatesInProgress && this.state.channel.toLowerCase() === WEBPUSH_LOWERCASE) ||
3697
+ (fetchingWeCrmAccounts && this.state.channel.toLowerCase() === WEBPUSH_LOWERCASE)
3698
+ );
3473
3699
  const inAppLoader = (((this.state.selectedAccount !== '' && getAllTemplatesInProgress) || (fetchingWeCrmAccounts)) && this.state.channel.toLowerCase() === INAPP_LOWERCASE);
3474
3700
  const emailLoader = (
3475
3701
  (getAllTemplatesInProgress ||
@@ -3484,6 +3710,7 @@ return (<div>
3484
3710
  (emailLoader !== undefined ? emailLoader : false) ||
3485
3711
  (ebillLoader !== undefined ? ebillLoader : false) ||
3486
3712
  (mobilePushLoader !== undefined ? mobilePushLoader : false) ||
3713
+ (webpushLoader !== undefined ? webpushLoader : false) ||
3487
3714
  (lineLoader !== undefined ? lineLoader : false) ||
3488
3715
  (facebookLoader !== undefined ? facebookLoader : false) ||
3489
3716
  (viberLoader !== undefined ? viberLoader : false) ||
@@ -3554,9 +3781,9 @@ return (<div>
3554
3781
  const isMobilePushChannel = channel === MOBILE_PUSH;
3555
3782
  const isInAppChannel = channel === INAPP;
3556
3783
  const isFacebookChannel = channel === FACEBOOK;
3557
- if ([WECHAT, MOBILE_PUSH, INAPP, LINE, ZALO, WHATSAPP, RCS].includes(channel) && !isEmpty(weCrmAccounts) && !isFacebookChannel) {
3784
+ if ([WECHAT, MOBILE_PUSH, INAPP, LINE, ZALO, WHATSAPP, WEBPUSH, RCS].includes(channel) && !isEmpty(weCrmAccounts) && !isFacebookChannel) {
3558
3785
  forEach(weCrmAccounts, (account) => {
3559
- if ((isWechatChannel && account.configs && account.configs.is_wecrm_enabled) || [MOBILE_PUSH, INAPP, LINE, ZALO, WHATSAPP, RCS].includes(channel)) {
3786
+ if ((isWechatChannel && account.configs && account.configs.is_wecrm_enabled) || [MOBILE_PUSH, INAPP, LINE, ZALO, WHATSAPP, WEBPUSH, RCS].includes(channel)) {
3560
3787
  if (query.type === 'embedded' && (!query.module || (query.module && query.module !== 'library'))) {
3561
3788
  if (query.source_account_id && account.sourceAccountIdentifier === query.source_account_id) {
3562
3789
  accountOptions.push(
@@ -3635,6 +3862,11 @@ return (<div>
3635
3862
  noAccountHeader = messages.noAccountsPresentZalo;
3636
3863
  break;
3637
3864
  }
3865
+ case WEBPUSH: {
3866
+ accountHeader = formatMessage(messages.webpushAccount);
3867
+ noAccountHeader = messages.noAccountsPresentWebpush;
3868
+ break;
3869
+ }
3638
3870
  case RCS: {
3639
3871
  accountHeader = formatMessage(messages.rcsAccount);
3640
3872
  noAccountHeader = messages.noAccountsPresentRcs;
@@ -3691,10 +3923,12 @@ return (<div>
3691
3923
  };
3692
3924
 
3693
3925
  setAccountSelectionMode = () => {
3926
+ this.props.actions.resetTemplate();
3694
3927
  this.setState({activeMode: ACCOUNT_SELECTION_MODE});
3695
3928
  }
3696
3929
 
3697
3930
  setAccountChangeMode = () => {
3931
+ this.props.actions.resetTemplate();
3698
3932
  this.setState({activeMode: ACCOUNT_CHANGE_MODE});
3699
3933
  }
3700
3934
 
@@ -3711,6 +3945,7 @@ return (<div>
3711
3945
 
3712
3946
  const channelObj = {
3713
3947
  [MOBILE_PUSH]: 'mobilepushAccount',
3948
+ [WEBPUSH]: 'webpushAccount',
3714
3949
  [WECHAT]: 'wechatAccount',
3715
3950
  [WHATSAPP]: 'whatsappAccount',
3716
3951
  [INAPP]: 'inappAccount',
@@ -4329,6 +4564,8 @@ Templates.propTypes = {
4329
4564
  rcsActions: PropTypes.object,
4330
4565
  zaloActions: PropTypes.object,
4331
4566
  inAppActions: PropTypes.object,
4567
+ webpushActions: PropTypes.object,
4568
+ WebPush: PropTypes.object,
4332
4569
  smsRegister: PropTypes.any,
4333
4570
  isDltFromRcs: PropTypes.bool,
4334
4571
  };
@@ -4348,6 +4585,7 @@ const mapStateToProps = createStructuredSelector({
4348
4585
  Rcs: makeSelectRcs(),
4349
4586
  Zalo: makeSelectZalo(),
4350
4587
  InApp: makeSelectInApp(),
4588
+ WebPush: makeSelectWebPush(),
4351
4589
  });
4352
4590
 
4353
4591
  function mapDispatchToProps(dispatch) {
@@ -4367,6 +4605,7 @@ function mapDispatchToProps(dispatch) {
4367
4605
  whatsappActions: bindActionCreators(whatsappActions, dispatch),
4368
4606
  rcsActions: bindActionCreators(rcsActions, dispatch),
4369
4607
  zaloActions: bindActionCreators(zaloActions, dispatch),
4608
+ webpushActions: bindActionCreators(webpushActions, dispatch),
4370
4609
  };
4371
4610
  }
4372
4611
 
@@ -4380,6 +4619,7 @@ export default compose(
4380
4619
  UserIsAuthenticated,
4381
4620
  withSaga,
4382
4621
  withMobilePushNewSaga,
4622
+ withWebPushSaga,
4383
4623
  withReducer,
4384
4624
  withConnect,
4385
4625
  )(injectIntl(Templates));
@@ -46,6 +46,10 @@ export default defineMessages({
46
46
  id: `${scope}.mobilepushHeader`,
47
47
  defaultMessage: `Mobile Push`,
48
48
  },
49
+ "webpushHeader": {
50
+ id: `${scope}.webpushHeader`,
51
+ defaultMessage: `Web Push`,
52
+ },
49
53
  "ebillHeader": {
50
54
  id: `${scope}.ebillHeader`,
51
55
  defaultMessage: `Ebill`,
@@ -342,6 +346,10 @@ export default defineMessages({
342
346
  id: `${scope}.newWhatsappTemplate`,
343
347
  defaultMessage: 'Add new Whatsapp {template}',
344
348
  },
349
+ "newWebPushTemplate": {
350
+ id: `${scope}.newWebPushTemplate`,
351
+ defaultMessage: 'Add new Web push {template}',
352
+ },
345
353
  "newInAppMessageTemplate": {
346
354
  id: `${scope}.newInAppMessageTemplate`,
347
355
  defaultMessage: 'Add new In app message {template}',
@@ -378,6 +386,14 @@ export default defineMessages({
378
386
  id: `${scope}.whatsappDescIllustration`,
379
387
  defaultMessage: 'These templates can be reused when creating a\nnew message content.',
380
388
  },
389
+ "webPushTitleIllustration": {
390
+ id: `${scope}.webPushTitleIllustration`,
391
+ defaultMessage: 'Add a new Web push creative {template}',
392
+ },
393
+ "webPushDescIllustration": {
394
+ id: `${scope}.webPushDescIllustration`,
395
+ defaultMessage: 'These templates can be reused when creating a new message content.',
396
+ },
381
397
  "whatsappAccountNotConfiguredTitle": {
382
398
  id: `${scope}.whatsappAccountNotConfiguredTitle`,
383
399
  defaultMessage: 'Whatsapp account is not configured',
@@ -462,6 +478,10 @@ export default defineMessages({
462
478
  id: `${scope}.zaloAccount`,
463
479
  defaultMessage: 'Zalo account',
464
480
  },
481
+ "webpushAccount": {
482
+ id: `${scope}.webpushAccount`,
483
+ defaultMessage: 'Web push account',
484
+ },
465
485
  "rcsAccount": {
466
486
  id: `${scope}.rcsAccount`,
467
487
  defaultMessage: 'RCS account',
@@ -498,6 +518,10 @@ export default defineMessages({
498
518
  id: `${scope}.noAccountsPresentZalo`,
499
519
  defaultMessage: "Zalo accounts are not setup for your brand",
500
520
  },
521
+ "noAccountsPresentWebpush": {
522
+ id: `${scope}.noAccountsPresentWebpush`,
523
+ defaultMessage: "Web push accounts are not setup for your brand",
524
+ },
501
525
  "noAccountsPresentRcs": {
502
526
  id: `${scope}.noAccountsPresentRcs`,
503
527
  defaultMessage: "RCS accounts are not setup for your brand",
@@ -124,6 +124,8 @@ function templatesReducer(state = initialState, action) {
124
124
  return state
125
125
  .set('selectedFacebookAccount', fromJS(action.faceBookAccount))
126
126
  .set('templates', []);
127
+ case types.SET_WEBPUSH_ACCOUNT:
128
+ return state.set('selectedWebPushAccount', fromJS(action.account));
127
129
  case types.RESET_ACCOUNT:
128
130
  return state
129
131
  .remove('selectedWeChatAccount')