@capillarytech/creatives-library 8.0.340-beta.0.5 → 8.0.340-beta.0.6

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 (61) hide show
  1. package/constants/unified.js +1 -0
  2. package/package.json +1 -1
  3. package/services/api.js +20 -0
  4. package/services/tests/api.test.js +59 -0
  5. package/utils/common.js +6 -0
  6. package/utils/test-utils.js +2 -2
  7. package/utils/tests/v2Common.test.js +46 -1
  8. package/utils/v2common.js +18 -0
  9. package/v2Components/CapTagList/index.js +5 -6
  10. package/v2Components/CommonTestAndPreview/UnifiedPreview/WhatsAppPreviewContent.js +18 -6
  11. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +27 -0
  12. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/WhatsAppPreviewContent.test.js +48 -0
  13. package/v2Components/TemplatePreview/_templatePreview.scss +21 -0
  14. package/v2Components/TemplatePreview/index.js +18 -6
  15. package/v2Components/TemplatePreview/tests/__snapshots__/index.test.js.snap +1 -0
  16. package/v2Containers/Assets/images/archive_Empty_Illustration.svg +9 -0
  17. package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/Tests/ChannelSelectionStep.test.js +28 -20
  18. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +24 -16
  19. package/v2Containers/CreativesContainer/SlideBoxContent.js +16 -5
  20. package/v2Containers/CreativesContainer/SlideBoxFooter.js +3 -1
  21. package/v2Containers/CreativesContainer/index.js +14 -1
  22. package/v2Containers/CreativesContainer/messages.js +4 -0
  23. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +2 -4
  24. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +3 -0
  25. package/v2Containers/Email/reducer.js +12 -3
  26. package/v2Containers/Email/sagas.js +9 -4
  27. package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +4 -0
  28. package/v2Containers/Email/tests/reducer.test.js +47 -0
  29. package/v2Containers/Email/tests/sagas.test.js +146 -6
  30. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +8 -1
  31. package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +1 -0
  32. package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +7 -0
  33. package/v2Containers/Sms/Create/index.js +3 -0
  34. package/v2Containers/Templates/ChannelTypeIllustration.js +23 -6
  35. package/v2Containers/Templates/_templates.scss +155 -24
  36. package/v2Containers/Templates/actions.js +44 -0
  37. package/v2Containers/Templates/constants.js +31 -0
  38. package/v2Containers/Templates/index.js +400 -59
  39. package/v2Containers/Templates/messages.js +96 -0
  40. package/v2Containers/Templates/reducer.js +84 -1
  41. package/v2Containers/Templates/sagas.js +64 -0
  42. package/v2Containers/Templates/selectors.js +12 -0
  43. package/v2Containers/Templates/tests/ChannelTypeIllustration.test.js +12 -0
  44. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1166 -1112
  45. package/v2Containers/Templates/tests/index.test.js +6 -0
  46. package/v2Containers/Templates/tests/reducer.test.js +178 -0
  47. package/v2Containers/Templates/tests/sagas.test.js +390 -8
  48. package/v2Containers/Templates/tests/selector.test.js +32 -0
  49. package/v2Containers/TemplatesV2/TemplatesV2.style.js +1 -1
  50. package/v2Containers/Viber/constants.js +8 -0
  51. package/v2Containers/Viber/index.js +5 -0
  52. package/v2Containers/Viber/messages.js +4 -0
  53. package/v2Containers/Viber/reducer.js +26 -3
  54. package/v2Containers/Viber/sagas.js +50 -8
  55. package/v2Containers/Viber/tests/index.test.js +80 -0
  56. package/v2Containers/Viber/tests/reducer.test.js +297 -0
  57. package/v2Containers/Viber/tests/saga.test.js +412 -40
  58. package/v2Containers/Whatsapp/constants.js +8 -0
  59. package/v2Containers/Whatsapp/index.js +145 -5
  60. package/v2Containers/Whatsapp/index.scss +12 -0
  61. package/v2Containers/Whatsapp/messages.js +16 -0
@@ -3,6 +3,7 @@ import { expectSaga } from 'redux-saga-test-plan';
3
3
  import { takeLatest } from 'redux-saga/effects';
4
4
  import * as matchers from 'redux-saga-test-plan/matchers';
5
5
  import { throwError } from 'redux-saga-test-plan/providers';
6
+ import { fromJS } from 'immutable';
6
7
  import * as types from '../constants';
7
8
  import * as sagas from '../sagas';
8
9
  import { v2EmailDuplicateTemplateSaga, v2EmailSagas } from '../sagas';
@@ -709,10 +710,14 @@ describe('getCmsSetting saga', () => {
709
710
 
710
711
  return expectSaga(sagas.getCmsSetting, basePayload)
711
712
  .provide([
713
+ {
714
+ select(effect, next) {
715
+ return fromJS({ cmsAccountsLoaded: true, isBeeEnabled: true });
716
+ },
717
+ },
712
718
  [matchers.call.fn(Api.getCmsTemplateSettingsV2), fakeResponse],
713
719
  ])
714
- .put({ type: types.GET_CMS_ACCOUNTS_SUCCESS, isBeeEnabled: true })
715
- .put({ type: types.GET_CMS_EDITOR_DETAILS_SUCCESS, settings: fakeResponse.data.response.cmsDetails })
720
+ .put({ type: types.GET_CMS_EDITOR_DETAILS_SUCCESS, settings: fakeResponse.data.response.cmsDetails, isBeeEnabled: true })
716
721
  .run();
717
722
  });
718
723
 
@@ -727,10 +732,14 @@ describe('getCmsSetting saga', () => {
727
732
 
728
733
  return expectSaga(sagas.getCmsSetting, basePayload)
729
734
  .provide([
735
+ {
736
+ select(effect, next) {
737
+ return fromJS({ cmsAccountsLoaded: true, isBeeEnabled: false });
738
+ },
739
+ },
730
740
  [matchers.call.fn(Api.getCmsTemplateSettingsV2), fakeResponse],
731
741
  ])
732
- .put({ type: types.GET_CMS_ACCOUNTS_SUCCESS, isBeeEnabled: false })
733
- .put({ type: types.GET_CMS_EDITOR_DETAILS_SUCCESS, settings: fakeResponse.data.response.cmsDetails })
742
+ .put({ type: types.GET_CMS_EDITOR_DETAILS_SUCCESS, settings: fakeResponse.data.response.cmsDetails, isBeeEnabled: false })
734
743
  .run();
735
744
  });
736
745
 
@@ -743,10 +752,14 @@ describe('getCmsSetting saga', () => {
743
752
 
744
753
  return expectSaga(sagas.getCmsSetting, basePayload)
745
754
  .provide([
755
+ {
756
+ select(effect, next) {
757
+ return fromJS({ cmsAccountsLoaded: true, isBeeEnabled: false });
758
+ },
759
+ },
746
760
  [matchers.call.fn(Api.getCmsTemplateSettingsV2), fakeResponse],
747
761
  ])
748
- .put({ type: types.GET_CMS_ACCOUNTS_SUCCESS, isBeeEnabled: false })
749
- .put({ type: types.GET_CMS_EDITOR_DETAILS_SUCCESS, settings: undefined })
762
+ .put({ type: types.GET_CMS_EDITOR_DETAILS_SUCCESS, settings: {}, isBeeEnabled: false })
750
763
  .run();
751
764
  });
752
765
 
@@ -755,11 +768,138 @@ describe('getCmsSetting saga', () => {
755
768
 
756
769
  return expectSaga(sagas.getCmsSetting, basePayload)
757
770
  .provide([
771
+ {
772
+ select(effect, next) {
773
+ return fromJS({ cmsAccountsLoaded: true, isBeeEnabled: true });
774
+ },
775
+ },
758
776
  [matchers.call.fn(Api.getCmsTemplateSettingsV2), throwError(fakeError)],
759
777
  ])
760
778
  .put({ type: types.GET_CMS_EDITOR_DETAILS_FAILURE, error: fakeError })
761
779
  .run();
762
780
  });
781
+
782
+ it('should wait for accounts when fetchingCmsAccounts is true and cmsAccountsLoaded is false (accounts succeed)', () => {
783
+ const fakeResponse = {
784
+ data: { response: { cmsDetails: { type: 'bee', settings: {} } } },
785
+ };
786
+ let selectCallCount = 0;
787
+
788
+ return expectSaga(sagas.getCmsSetting, basePayload)
789
+ .provide([
790
+ {
791
+ select(effect, next) {
792
+ selectCallCount += 1;
793
+ if (selectCallCount === 1) {
794
+ return fromJS({ cmsAccountsLoaded: false, fetchingCmsAccounts: true, isBeeEnabled: null });
795
+ }
796
+ return fromJS({ cmsAccountsLoaded: true, fetchingCmsAccounts: false, isBeeEnabled: true });
797
+ },
798
+ },
799
+ [matchers.call.fn(Api.getCmsTemplateSettingsV2), fakeResponse],
800
+ ])
801
+ .dispatch({ type: types.GET_CMS_ACCOUNTS_SUCCESS, isBeeEnabled: true })
802
+ .put({ type: types.GET_CMS_EDITOR_DETAILS_SUCCESS, settings: { type: 'bee', settings: {} }, isBeeEnabled: true })
803
+ .run();
804
+ });
805
+
806
+ it('should wait for accounts when fetchingCmsAccounts is true and cmsAccountsLoaded is false (accounts fail)', () => {
807
+ const fakeResponse = {
808
+ data: { response: { cmsDetails: { type: 'ck', settings: {} } } },
809
+ };
810
+ let selectCallCount = 0;
811
+
812
+ return expectSaga(sagas.getCmsSetting, basePayload)
813
+ .provide([
814
+ {
815
+ select(effect, next) {
816
+ selectCallCount += 1;
817
+ if (selectCallCount === 1) {
818
+ return fromJS({ cmsAccountsLoaded: false, fetchingCmsAccounts: true, isBeeEnabled: null });
819
+ }
820
+ return fromJS({ cmsAccountsLoaded: true, fetchingCmsAccounts: false, isBeeEnabled: false });
821
+ },
822
+ },
823
+ [matchers.call.fn(Api.getCmsTemplateSettingsV2), fakeResponse],
824
+ ])
825
+ .dispatch({ type: types.GET_CMS_ACCOUNTS_FAILURE })
826
+ .put({ type: types.GET_CMS_EDITOR_DETAILS_SUCCESS, settings: { type: 'ck', settings: {} }, isBeeEnabled: false })
827
+ .run();
828
+ });
829
+
830
+ it('should skip wait and use isBEEAppEnableFromAction as fallback when cmsAccountsLoaded is false but fetchingCmsAccounts is false', () => {
831
+ const fakeResponse = {
832
+ data: { response: { cmsDetails: { type: 'bee', settings: {} } } },
833
+ };
834
+
835
+ return expectSaga(sagas.getCmsSetting, { ...basePayload, isBEEAppEnable: true })
836
+ .provide([
837
+ {
838
+ select(effect, next) {
839
+ return fromJS({ cmsAccountsLoaded: false, fetchingCmsAccounts: false, isBeeEnabled: null });
840
+ },
841
+ },
842
+ [matchers.call.fn(Api.getCmsTemplateSettingsV2), fakeResponse],
843
+ ])
844
+ .put({ type: types.GET_CMS_EDITOR_DETAILS_SUCCESS, settings: { type: 'bee', settings: {} }, isBeeEnabled: true })
845
+ .run();
846
+ });
847
+
848
+ it('should use state isBeeEnabled (null) and fall back to isBEEAppEnableFromAction via ?? operator', () => {
849
+ const fakeResponse = {
850
+ data: { response: { cmsDetails: { type: 'bee', settings: {} } } },
851
+ };
852
+
853
+ return expectSaga(sagas.getCmsSetting, { ...basePayload, isBEEAppEnable: true })
854
+ .provide([
855
+ {
856
+ select(effect, next) {
857
+ return fromJS({ cmsAccountsLoaded: true, fetchingCmsAccounts: false, isBeeEnabled: null });
858
+ },
859
+ },
860
+ [matchers.call.fn(Api.getCmsTemplateSettingsV2), fakeResponse],
861
+ ])
862
+ .call(Api.getCmsTemplateSettingsV2, basePayload.cmsType, basePayload.projectId, basePayload.cmsMode, basePayload.langId, basePayload.isEdmSupport, true)
863
+ .put({ type: types.GET_CMS_EDITOR_DETAILS_SUCCESS, settings: { type: 'bee', settings: {} }, isBeeEnabled: true })
864
+ .run();
865
+ });
866
+
867
+ it('should use state isBeeEnabled false over isBEEAppEnableFromAction true via ?? operator (false is not null/undefined)', () => {
868
+ const fakeResponse = {
869
+ data: { response: { cmsDetails: { type: 'bee', settings: {} } } },
870
+ };
871
+
872
+ return expectSaga(sagas.getCmsSetting, { ...basePayload, isBEEAppEnable: true })
873
+ .provide([
874
+ {
875
+ select(effect, next) {
876
+ return fromJS({ cmsAccountsLoaded: true, fetchingCmsAccounts: false, isBeeEnabled: false });
877
+ },
878
+ },
879
+ [matchers.call.fn(Api.getCmsTemplateSettingsV2), fakeResponse],
880
+ ])
881
+ .call(Api.getCmsTemplateSettingsV2, basePayload.cmsType, basePayload.projectId, basePayload.cmsMode, basePayload.langId, basePayload.isEdmSupport, false)
882
+ .put({ type: types.GET_CMS_EDITOR_DETAILS_SUCCESS, settings: { type: 'bee', settings: {} }, isBeeEnabled: true })
883
+ .run();
884
+ });
885
+
886
+ it('should derive isBeeEnabled false when cmsDetails type is undefined', () => {
887
+ const fakeResponse = {
888
+ data: { response: { cmsDetails: { settings: {} } } },
889
+ };
890
+
891
+ return expectSaga(sagas.getCmsSetting, basePayload)
892
+ .provide([
893
+ {
894
+ select(effect, next) {
895
+ return fromJS({ cmsAccountsLoaded: true, fetchingCmsAccounts: false, isBeeEnabled: true });
896
+ },
897
+ },
898
+ [matchers.call.fn(Api.getCmsTemplateSettingsV2), fakeResponse],
899
+ ])
900
+ .put({ type: types.GET_CMS_EDITOR_DETAILS_SUCCESS, settings: { settings: {} }, isBeeEnabled: false })
901
+ .run();
902
+ });
763
903
  });
764
904
 
765
905
 
@@ -102,6 +102,10 @@ const useEmailWrapper = ({
102
102
  }
103
103
  }, [onEnterTemplateName, onRemoveTemplateName]);
104
104
 
105
+ useEffect(() => () => {
106
+ emailActions.clearStoreValues();
107
+ }, []);
108
+
105
109
  // Check BEE enabled status from API response
106
110
  // BEE is enabled if isDragDrop is true in the API response
107
111
  // This should work for both full mode and library mode
@@ -708,7 +712,10 @@ const useEmailWrapper = ({
708
712
  } else if (location?.pathname?.includes('/edit/')) {
709
713
  // Extract id from pathname if it's in the format /edit/:id
710
714
  const match = location.pathname.match(/\/edit\/([^/]+)/);
711
- if (match) {
715
+ // Reject sentinel strings that come from unguarded template literals
716
+ // (e.g. `/edit/${maybeUndefined}` → "/edit/undefined"), so they don't
717
+ // get treated as real template ids downstream.
718
+ if (match && match[1] && match[1] !== 'undefined' && match[1] !== 'null') {
712
719
  emailParams.id = match[1];
713
720
  }
714
721
  }
@@ -125,6 +125,7 @@ describe('useEmailWrapper - Edge Cases', () => {
125
125
  getCmsAccounts: jest.fn(),
126
126
  getTemplateDetails: jest.fn(),
127
127
  getCmsSetting: jest.fn(),
128
+ clearStoreValues: jest.fn(),
128
129
  },
129
130
  Email: {
130
131
  isBeeEnabled: undefined,
@@ -79,6 +79,12 @@ describe('useEmailWrapper', () => {
79
79
  setEdmTemplate: jest.fn(),
80
80
  setBEETemplate: jest.fn(),
81
81
  },
82
+ emailActions: {
83
+ getCmsAccounts: jest.fn(),
84
+ getTemplateDetails: jest.fn(),
85
+ getCmsSetting: jest.fn(),
86
+ clearStoreValues: jest.fn(),
87
+ },
82
88
  EmailLayout: null,
83
89
  CmsTemplates: null,
84
90
  SelectedEdmDefaultTemplate: null,
@@ -650,6 +656,7 @@ describe('useEmailWrapper', () => {
650
656
  mockEmailActions = {
651
657
  getTemplateDetails: jest.fn(),
652
658
  getCmsAccounts: jest.fn(),
659
+ clearStoreValues: jest.fn(),
653
660
  };
654
661
 
655
662
  newFlowMockProps = {
@@ -799,6 +799,9 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
799
799
  }
800
800
  const formData = _.cloneDeep(this.state.formData);
801
801
  formData[currentTab - 1][field.id] = myField.value;
802
+ if (formData.base) {
803
+ formData.base[field.id] = myField.value;
804
+ }
802
805
  this.setState({formData}, () => this.onTemplateContentChange());
803
806
  }
804
807
 
@@ -1,5 +1,9 @@
1
1
  import React, { useMemo } from 'react';
2
2
  import PropTypes from 'prop-types';
3
+ import zaloillustration from '@capillarytech/cap-ui-library/assets/images/featureUiNotEnabledIllustration.svg';
4
+ import inAppIllustration from '@capillarytech/cap-ui-library/assets/images/featureUiNotEnabledIllustration.svg';
5
+ import { FormattedMessage } from 'react-intl';
6
+ import { CapIllustration } from "@capillarytech/cap-ui-library";
3
7
  import emailIllustration from '../Assets/images/emailIllustration.svg';
4
8
  import smsIllustration from '../Assets/images/smsIllustration.svg';
5
9
  import pushIllustration from '../Assets/images/pushIllustration.svg';
@@ -8,13 +12,12 @@ import lineIllustration from '../Assets/images/lineIllustration.svg';
8
12
  import facebookIllustration from '../Assets/images/facebookIllustration.svg';
9
13
  import whatsappIllustration from '../Assets/images/whatsappIllustration.png';
10
14
  import whatsappOrZaloAccountIllustration from '../Assets/images/whatsappOrZaloAccountIllustration.svg';
15
+ import archiveEmptyStateIllustration from '../Assets/images/archive_Empty_Illustration.svg';
11
16
  import rcsIllustration from '../Assets/images/rcsIllustration.png';
12
- import zaloillustration from '@capillarytech/cap-ui-library/assets/images/featureUiNotEnabledIllustration.svg';
13
- import inAppIllustration from '@capillarytech/cap-ui-library/assets/images/featureUiNotEnabledIllustration.svg';
14
17
  import messages from './messages';
15
- import { FormattedMessage } from 'react-intl';
16
- import { CapIllustration } from "@capillarytech/cap-ui-library";
17
- import { MOBILE_PUSH, SMS, EMAIL, LINE, VIBER, FACEBOOK, WHATSAPP, RCS, ZALO, INAPP, WEBPUSH } from '../CreativesContainer/constants';
18
+ import {
19
+ MOBILE_PUSH, SMS, EMAIL, LINE, VIBER, FACEBOOK, WHATSAPP, RCS, ZALO, INAPP, WEBPUSH,
20
+ } from '../CreativesContainer/constants';
18
21
 
19
22
 
20
23
  // Configuration object for channel types
@@ -80,7 +83,8 @@ function ChannelTypeIllustration(props) {
80
83
  isFullMode,
81
84
  createTemplate,
82
85
  currentChannel,
83
- hostName
86
+ hostName,
87
+ isArchivedMode,
84
88
  } = props;
85
89
 
86
90
  const templateText = useMemo(() => {
@@ -88,6 +92,18 @@ function ChannelTypeIllustration(props) {
88
92
  return isFullMode ? templateIntlMsg : '';
89
93
  }, [isFullMode]);
90
94
 
95
+ if (isArchivedMode) {
96
+ return (
97
+ <CapIllustration
98
+ illustrationImage={archiveEmptyStateIllustration}
99
+ title={<FormattedMessage {...messages.noArchivedCreatives} />}
100
+ description={<FormattedMessage {...messages.noArchivedCreativesDesc} />}
101
+ descriptionPosition="bottom"
102
+ descriptionClassName="illustration-desc archive-illustration"
103
+ />
104
+ );
105
+ }
106
+
91
107
  const getChannelTypeIllustrationInfo = (type, hostName) => {
92
108
  // Handle special cases with hostName dependency
93
109
  if (type === WHATSAPP) {
@@ -196,5 +212,6 @@ ChannelTypeIllustration.propTypes = {
196
212
  createTemplate: PropTypes.func.isRequired,
197
213
  currentChannel: PropTypes.string,
198
214
  hostName: PropTypes.string,
215
+ isArchivedMode: PropTypes.bool,
199
216
  };
200
217
  export default ChannelTypeIllustration;
@@ -1,34 +1,23 @@
1
1
  @import '~@capillarytech/cap-ui-library/styles/_variables.scss';
2
2
 
3
3
  .ant-tabs-content{
4
- margin-top: 16px;
4
+ margin-top: $CAP_SPACE_16;
5
5
  .ant-tabs-tabpane-active{
6
6
  padding: unset;
7
7
  }
8
8
  }
9
+ //removing current one as not required now in each row we'll have 3 cards for which css has been added
9
10
 
10
- @media screen and (max-width: 1172px) {
11
- .creatives-templates-list.full-mode{
12
- .v2-pagination-container {
13
- .cap-custom-card-list-row {
14
- .cap-custom-card-list-col{
15
- &:nth-child(3n+3) { //every 4th child
16
- margin-right: unset;
17
- }
18
- }
19
- }
20
- }
21
- }
22
- }
23
-
24
- @media screen and (min-width: 1172px) {
25
- .creatives-templates-list.full-mode{
26
- .v2-pagination-container {
27
- .cap-custom-card-list-row {
28
- .cap-custom-card-list-col{
29
- &:nth-child(4n+4) { //every 4th child
30
- margin-right: unset;
31
- }
11
+ // 3 cards per row across all breakpoints
12
+ .creatives-templates-list {
13
+ .v2-pagination-container,
14
+ .v2-pagination-container-half {
15
+ .cap-custom-card-list-row {
16
+ .cap-custom-card-list-col {
17
+ width: calc(33.33% - #{$CAP_SPACE_08});
18
+ margin-right: $CAP_SPACE_12;
19
+ &:nth-child(3n) {
20
+ margin-right: 0;
32
21
  }
33
22
  }
34
23
  }
@@ -36,6 +25,21 @@
36
25
  }
37
26
 
38
27
  .creatives-templates-list {
28
+ position: relative;
29
+
30
+ .archive-listing-spinner {
31
+ position: absolute;
32
+ top: 50%;
33
+ left: 50%;
34
+ transform: translate(-50%, -50%);
35
+ display: flex;
36
+ align-items: center;
37
+ gap: $CAP_SPACE_08;
38
+ background: $CAP_WHITE;
39
+ padding: $CAP_SPACE_08 $CAP_SPACE_16;
40
+ border-radius: $CAP_SPACE_08;
41
+ z-index: 10;
42
+ }
39
43
 
40
44
  .delete-template-confirm {
41
45
  .ant-modal-footer {
@@ -1099,6 +1103,12 @@
1099
1103
  text-overflow: ellipsis;
1100
1104
  }
1101
1105
 
1106
+ .whatsapp-card-head-checkbox-wrapper {
1107
+ .ant-checkbox-wrapper {
1108
+ padding-top: 0.429rem;
1109
+ }
1110
+ }
1111
+
1102
1112
  .zalo-template-name{
1103
1113
  max-width: 170px;
1104
1114
  overflow: hidden;
@@ -1152,4 +1162,125 @@
1152
1162
  .inapp-illustration-parent {
1153
1163
  height: "calc(100vh - 325px)";
1154
1164
  overflow: 'auto';
1155
- }
1165
+ }
1166
+
1167
+ // Archive feature layout classes
1168
+ .illustration-scroll-wrapper {
1169
+ height: calc(100vh - 20.3125rem);
1170
+ overflow: auto;
1171
+ }
1172
+
1173
+ .filter-row {
1174
+ display: flex;
1175
+ align-items: baseline;
1176
+ justify-content: space-between;
1177
+ width: 102%;
1178
+ }
1179
+
1180
+ .filter-row-content {
1181
+ flex: 1;
1182
+ }
1183
+
1184
+ .bulk-selection-bar {
1185
+ display: flex;
1186
+ align-items: center;
1187
+ gap: $CAP_SPACE_12;
1188
+ flex-shrink: 0;
1189
+ margin-right: $CAP_SPACE_32;
1190
+ }
1191
+
1192
+ .archived-mode-header {
1193
+ display: flex;
1194
+ align-items: center;
1195
+ gap: $CAP_SPACE_12;
1196
+ margin-bottom: $CAP_SPACE_16;
1197
+
1198
+ .archived-mode-back-icon {
1199
+ cursor: pointer;
1200
+ font-size: 1.428rem;
1201
+ }
1202
+ }
1203
+
1204
+ .archived-tag {
1205
+ margin-left: $CAP_SPACE_08;
1206
+ font-size: 0.786rem;
1207
+ }
1208
+
1209
+ .popover-archive-action {
1210
+ cursor: pointer;
1211
+ padding: $CAP_SPACE_08 0;
1212
+ }
1213
+
1214
+ .archive-menu-item {
1215
+ display: inline-flex;
1216
+ align-items: center;
1217
+ gap: $CAP_SPACE_08;
1218
+ margin-top: 1rem;
1219
+ }
1220
+
1221
+ .archive-btn-label {
1222
+ margin-right: 0.714rem;
1223
+ }
1224
+
1225
+ .bulk-selection-bar .ant-btn.cap-button-v2 > .cap-button-v2-prefix + span {
1226
+ margin-left: -$CAP_SPACE_06;
1227
+ }
1228
+
1229
+ .template-card-top-bar {
1230
+ display: flex;
1231
+ align-items: center;
1232
+ justify-content: space-between;
1233
+ padding: $CAP_SPACE_08 $CAP_SPACE_12 0;
1234
+ }
1235
+
1236
+ .template-listing-header-actions {
1237
+ display: flex;
1238
+ justify-content: space-between;
1239
+ align-items: center;
1240
+ gap: $CAP_SPACE_08;
1241
+ margin-right: $CAP_SPACE_32;
1242
+ }
1243
+
1244
+ .template-listing-more-btn {
1245
+ padding-inline: $CAP_SPACE_20;
1246
+ min-width: auto;
1247
+ }
1248
+
1249
+ .notification-template-label {
1250
+ color: $CAP_G04;
1251
+ }
1252
+
1253
+ .notification-template-name {
1254
+ color: $CAP_G01;
1255
+ }
1256
+
1257
+ .template-card-title {
1258
+ display: flex;
1259
+ align-items: center;
1260
+ min-width: 0;
1261
+ column-gap: $CAP_SPACE_12;
1262
+
1263
+ .ant-checkbox-wrapper {
1264
+ padding-top: 0.429rem;
1265
+ }
1266
+
1267
+ .cap-checkbox-v2 {
1268
+ flex-shrink: 0;
1269
+ margin-right: $CAP_SPACE_04;
1270
+ // Remove the empty label span's padding that antd Checkbox renders when no children are passed
1271
+ .ant-checkbox + span {
1272
+ padding-left: 0;
1273
+ padding-right: 0;
1274
+ }
1275
+ }
1276
+
1277
+ .template-card-name {
1278
+ font-weight: 500;
1279
+ font-size: $FONT_SIZE_L;
1280
+ color: $CAP_G01;
1281
+ overflow: hidden;
1282
+ text-overflow: ellipsis;
1283
+ white-space: nowrap;
1284
+ min-width: 0;
1285
+ }
1286
+ }
@@ -167,3 +167,47 @@ export function getCdnTransformationConfig() {
167
167
  type: types.GET_CDN_TRANSFORMATION_CONFIG_REQUEST,
168
168
  };
169
169
  }
170
+
171
+ export function archiveTemplate(channel, id, successMessage, description) {
172
+ return {
173
+ type: types.ARCHIVE_TEMPLATE_REQUEST, channel, id, successMessage, description
174
+ };
175
+ }
176
+
177
+ export function unarchiveTemplate(channel, id, successMessage, description) {
178
+ return {
179
+ type: types.UNARCHIVE_TEMPLATE_REQUEST, channel, id, successMessage, description
180
+ };
181
+ }
182
+
183
+ export function bulkArchiveTemplates(channel, ids, successMessage) {
184
+ return {
185
+ type: types.BULK_ARCHIVE_REQUEST, channel, ids, successMessage
186
+ };
187
+ }
188
+
189
+ export function bulkUnarchiveTemplates(channel, ids, successMessage) {
190
+ return {
191
+ type: types.BULK_UNARCHIVE_REQUEST, channel, ids, successMessage
192
+ };
193
+ }
194
+
195
+ export function setArchiveFilter(filter) {
196
+ return { type: types.SET_ARCHIVE_FILTER, filter };
197
+ }
198
+
199
+ export function toggleTemplateSelection(id) {
200
+ return { type: types.TOGGLE_TEMPLATE_SELECTION, id };
201
+ }
202
+
203
+ export function selectAllTemplates(ids) {
204
+ return { type: types.SELECT_ALL_TEMPLATES, ids };
205
+ }
206
+
207
+ export function clearTemplateSelection() {
208
+ return { type: types.CLEAR_TEMPLATE_SELECTION };
209
+ }
210
+
211
+ export function setArchivedMode(isArchived) {
212
+ return { type: types.SET_ARCHIVED_MODE, isArchived };
213
+ }
@@ -91,3 +91,34 @@ export const noApprovedWhatsappTemplatesDesc ='noApprovedWhatsappTemplatesDesc'
91
91
  export const zaloDescIllustration='zaloDescIllustration'
92
92
  export const noApprovedRcsTemplatesTitle='noApprovedRcsTemplatesTitle'
93
93
  export const noApprovedRcsTemplatesDesc='noApprovedRcsTemplatesDesc'
94
+
95
+ // Archive feature
96
+ export const ARCHIVE_TEMPLATE_REQUEST = 'app/v2Containers/Templates/ARCHIVE_TEMPLATE_REQUEST';
97
+ export const ARCHIVE_TEMPLATE_SUCCESS = 'app/v2Containers/Templates/ARCHIVE_TEMPLATE_SUCCESS';
98
+ export const ARCHIVE_TEMPLATE_FAILURE = 'app/v2Containers/Templates/ARCHIVE_TEMPLATE_FAILURE';
99
+
100
+ export const UNARCHIVE_TEMPLATE_REQUEST = 'app/v2Containers/Templates/UNARCHIVE_TEMPLATE_REQUEST';
101
+ export const UNARCHIVE_TEMPLATE_SUCCESS = 'app/v2Containers/Templates/UNARCHIVE_TEMPLATE_SUCCESS';
102
+ export const UNARCHIVE_TEMPLATE_FAILURE = 'app/v2Containers/Templates/UNARCHIVE_TEMPLATE_FAILURE';
103
+
104
+ export const BULK_ARCHIVE_REQUEST = 'app/v2Containers/Templates/BULK_ARCHIVE_REQUEST';
105
+ export const BULK_ARCHIVE_SUCCESS = 'app/v2Containers/Templates/BULK_ARCHIVE_SUCCESS';
106
+ export const BULK_ARCHIVE_FAILURE = 'app/v2Containers/Templates/BULK_ARCHIVE_FAILURE';
107
+
108
+ export const BULK_UNARCHIVE_REQUEST = 'app/v2Containers/Templates/BULK_UNARCHIVE_REQUEST';
109
+ export const BULK_UNARCHIVE_SUCCESS = 'app/v2Containers/Templates/BULK_UNARCHIVE_SUCCESS';
110
+ export const BULK_UNARCHIVE_FAILURE = 'app/v2Containers/Templates/BULK_UNARCHIVE_FAILURE';
111
+
112
+ export const SET_ARCHIVE_FILTER = 'app/v2Containers/Templates/SET_ARCHIVE_FILTER';
113
+ export const TOGGLE_TEMPLATE_SELECTION = 'app/v2Containers/Templates/TOGGLE_TEMPLATE_SELECTION';
114
+ export const SELECT_ALL_TEMPLATES = 'app/v2Containers/Templates/SELECT_ALL_TEMPLATES';
115
+ export const CLEAR_TEMPLATE_SELECTION = 'app/v2Containers/Templates/CLEAR_TEMPLATE_SELECTION';
116
+ export const SET_ARCHIVED_MODE = 'app/v2Containers/Templates/SET_ARCHIVED_MODE';
117
+
118
+ // Archive status values
119
+ export const ARCHIVE_STATUS_ACTIVE = 'active';
120
+ export const ARCHIVE_STATUS_ARCHIVED = 'archived';
121
+
122
+ // Archive listing refresh types
123
+ export const ARCHIVE_REFRESH_TYPE_ARCHIVE = 'ARCHIVE';
124
+ export const ARCHIVE_REFRESH_TYPE_UNARCHIVE = 'UNARCHIVE';