@capillarytech/creatives-library 8.0.345-alpha.11 → 8.0.345-alpha.13

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 (27) hide show
  1. package/package.json +1 -1
  2. package/services/api.js +20 -0
  3. package/services/tests/api.test.js +59 -0
  4. package/v2Components/CapCustomSkeleton/index.js +1 -1
  5. package/v2Components/CapCustomSkeleton/tests/__snapshots__/index.test.js.snap +12 -12
  6. package/v2Containers/Assets/images/archive_Empty_Illustration.svg +9 -0
  7. package/v2Containers/CreativesContainer/SlideBoxContent.js +1 -20
  8. package/v2Containers/CreativesContainer/SlideBoxFooter.js +3 -1
  9. package/v2Containers/CreativesContainer/index.js +6 -4
  10. package/v2Containers/CreativesContainer/messages.js +4 -0
  11. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +3 -0
  12. package/v2Containers/Email/index.js +2 -46
  13. package/v2Containers/Templates/ChannelTypeIllustration.js +23 -6
  14. package/v2Containers/Templates/_templates.scss +130 -24
  15. package/v2Containers/Templates/actions.js +36 -0
  16. package/v2Containers/Templates/constants.js +23 -0
  17. package/v2Containers/Templates/index.js +286 -30
  18. package/v2Containers/Templates/messages.js +68 -0
  19. package/v2Containers/Templates/reducer.js +68 -0
  20. package/v2Containers/Templates/sagas.js +89 -1
  21. package/v2Containers/Templates/selectors.js +12 -0
  22. package/v2Containers/Templates/tests/ChannelTypeIllustration.test.js +12 -0
  23. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1300 -1122
  24. package/v2Containers/Templates/tests/index.test.js +6 -0
  25. package/v2Containers/Templates/tests/reducer.test.js +178 -0
  26. package/v2Containers/Templates/tests/sagas.test.js +314 -8
  27. package/v2Containers/Templates/tests/selector.test.js +32 -0
@@ -705,27 +705,8 @@ export function SlideBoxContent(props) {
705
705
  // and getDetails?type=BEE_PLUGIN would never fire. Routing BEE
706
706
  // templates through the direct <Email> path — which is already
707
707
  // battle-tested for the CKEditor flow — sidesteps that entirely.
708
- const vBase = templateData?.versions?.base;
709
- const vBaseActiveTab = vBase?.activeTab || vBase?.selectedLanguages?.[0] || 'en';
710
708
  const isBEETemplate = templateData?.base?.is_drag_drop === true
711
- || templateData?.base?.is_drag_drop === 1
712
- || vBase?.[vBaseActiveTab]?.is_drag_drop === true
713
- || vBase?.[vBaseActiveTab]?.is_drag_drop === 1;
714
- console.log('[SlideBoxContent] BEE routing debug', {
715
- supportCKEditor,
716
- 'templateData._id': templateData?._id,
717
- 'templateData.type': templateData?.type,
718
- 'templateData.base': templateData?.base,
719
- 'templateData.base.is_drag_drop': templateData?.base?.is_drag_drop,
720
- 'templateData.base.drag_drop_id': templateData?.base?.drag_drop_id,
721
- vBase,
722
- vBaseActiveTab,
723
- 'vBase[vBaseActiveTab]': vBase?.[vBaseActiveTab],
724
- 'vBase[vBaseActiveTab].is_drag_drop': vBase?.[vBaseActiveTab]?.is_drag_drop,
725
- 'vBase[vBaseActiveTab].drag_drop_id': vBase?.[vBaseActiveTab]?.drag_drop_id,
726
- isBEETemplate,
727
- routingTo: (supportCKEditor || isBEETemplate) ? 'Email (direct)' : 'EmailWrapper',
728
- });
709
+ || templateData?.base?.is_drag_drop === 1;
729
710
  if (supportCKEditor || isBEETemplate) {
730
711
  return (
731
712
  <Email
@@ -24,6 +24,7 @@ function SlideBoxFooter(props) {
24
24
  slidBoxContent,
25
25
  onSave,
26
26
  onEditTemplate,
27
+ isTemplateArchived,
27
28
  onCreateNextStep,
28
29
  isFullMode,
29
30
  fetchingCmsData,
@@ -214,7 +215,7 @@ function SlideBoxFooter(props) {
214
215
  <FormattedMessage {...(continueButtonLabel || messages.continue)} />
215
216
  </CapButton>
216
217
  )}
217
- {slidBoxContent === PREVIEW && (
218
+ {slidBoxContent === PREVIEW && !isTemplateArchived && (
218
219
  <CapButton onClick={onEditTemplate} type="secondary">
219
220
  <FormattedMessage {...messages.creativesTemplatesEdit} />
220
221
  </CapButton>
@@ -227,6 +228,7 @@ SlideBoxFooter.propTypes = {
227
228
  slidBoxContent: PropTypes.node,
228
229
  onSave: PropTypes.func,
229
230
  onEditTemplate: PropTypes.func,
231
+ isTemplateArchived: PropTypes.bool,
230
232
  onCreateNextStep: PropTypes.func,
231
233
  shouldShowContinueFooter: PropTypes.func,
232
234
  shouldShowDoneFooter: PropTypes.func,
@@ -260,6 +260,10 @@ export class Creatives extends React.Component {
260
260
  };
261
261
 
262
262
  onEditTemplate = () => {
263
+ if (this.props.templateData && this.props.templateData.isArchived) {
264
+ CapNotification.error({ message: this.props.intl.formatMessage(messages.cannotEditArchivedTemplate) });
265
+ return;
266
+ }
263
267
  this.setState({ slidBoxContent: 'editTemplate', showSlideBox: true, templateNameExists: true });
264
268
  };
265
269
 
@@ -966,13 +970,10 @@ export class Creatives extends React.Component {
966
970
  case constants.EMAIL:
967
971
  if (template?.value?.base) {
968
972
  let emailBase = template.value.base;
969
- const { html_content, drag_drop_id: formDragDropId } = emailBase || {};
973
+ const { html_content } = emailBase || {};
970
974
  if (!html_content) {
971
975
  emailBase = templateRecords.base;
972
976
  }
973
- if (!emailBase.drag_drop_id && formDragDropId) {
974
- emailBase = { ...emailBase, drag_drop_id: formDragDropId };
975
- }
976
977
  const newHtmlContent = await updateImagesInHtml(html_content);
977
978
  templateData = {
978
979
  ...templateData, ...emailBase, emailBody: newHtmlContent, emailSubject: (emailBase && emailBase.subject) ? emailBase.subject : '',
@@ -2139,6 +2140,7 @@ export class Creatives extends React.Component {
2139
2140
  onSave={this.saveMessage}
2140
2141
  onDiscard={this.discardMessage}
2141
2142
  onEditTemplate={this.onEditTemplate}
2143
+ isTemplateArchived={!!(this.props.templateData && this.props.templateData.isArchived)}
2142
2144
  slidBoxContent={slidBoxContent}
2143
2145
  onCreateNextStep={this.onCreateNextStep}
2144
2146
  currentChannel={currentChannel.toUpperCase()}
@@ -390,4 +390,8 @@ export default defineMessages({
390
390
  id: `${scope}.personalizationTokensErrorMessage`,
391
391
  defaultMessage: `Personalization tags are not supported for anonymous customers, please remove the tags.`,
392
392
  },
393
+ "cannotEditArchivedTemplate": {
394
+ id: `${scope}.cannotEditArchivedTemplate`,
395
+ defaultMessage: 'Cannot edit an archived template. Please unarchive it first.',
396
+ },
393
397
  });
@@ -295,6 +295,7 @@ exports[`Test SlideBoxContent container campaign message, whatsapp edit all data
295
295
  isEmptyContent={false}
296
296
  isFullMode={false}
297
297
  isLiquidValidationError={false}
298
+ isTemplateArchived={false}
298
299
  isTemplateNameEmpty={false}
299
300
  onCreateNextStep={[Function]}
300
301
  onDiscard={[Function]}
@@ -434,6 +435,7 @@ exports[`Test SlideBoxContent container campaign message, whatsapp edit min data
434
435
  isEmptyContent={false}
435
436
  isFullMode={false}
436
437
  isLiquidValidationError={false}
438
+ isTemplateArchived={false}
437
439
  isTemplateNameEmpty={false}
438
440
  onCreateNextStep={[Function]}
439
441
  onDiscard={[Function]}
@@ -573,6 +575,7 @@ exports[`Test SlideBoxContent container it should clear the url, on channel chan
573
575
  isEmptyContent={false}
574
576
  isFullMode={false}
575
577
  isLiquidValidationError={false}
578
+ isTemplateArchived={false}
576
579
  isTemplateNameEmpty={false}
577
580
  onCreateNextStep={[Function]}
578
581
  onDiscard={[Function]}
@@ -32,7 +32,7 @@ import * as creativesContainerActions from '../CreativesContainer/actions';
32
32
  import withCreatives from '../../hoc/withCreatives';
33
33
  import { EMAIL } from '../CreativesContainer/constants';
34
34
  import { GA } from '@capillarytech/cap-ui-utils';
35
- import { TRACK_CREATE_EMAIL, TRACK_EDIT_EMAIL, BEE_PLUGIN, CREATE, EDIT, LOYALTY } from '../App/constants';
35
+ import { TRACK_CREATE_EMAIL, TRACK_EDIT_EMAIL, BEE_PLUGIN, CREATE, EDIT } from '../App/constants';
36
36
  import { FONT_COLOR_05 } from '@capillarytech/cap-ui-library/styled/variables';
37
37
  import { gtmPush } from '../../utils/gtmTrackers';
38
38
  const {CapCustomCardList} = CapCustomCard;
@@ -98,8 +98,6 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
98
98
  this.edmEvent = undefined;
99
99
  // When schema is set after CmsSettings (e.g. library create BEE), allow BEE init to run once
100
100
  this.schemaJustFilledForBee = false;
101
- // Guard: prevent startTemplateCreation being called twice (componentDidMount + componentWillReceiveProps)
102
- this.templateCreationStarted = false;
103
101
  this.supportedLanguages = this.getSupportedLanguages(props);
104
102
  this.map = {
105
103
  "template-name": {
@@ -226,7 +224,6 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
226
224
  || _.get(this.props.Templates.BEETemplate, 'versions.base.drag_drop_id')
227
225
  || _.get(this.props.Templates.BEETemplate, 'versions.base.id')
228
226
  || this.props.Templates.BEETemplate?._id;
229
- console.log('[Rafeeq manzoor] comes here 1');
230
227
  this.props.actions.getCmsSetting(BEE_PLUGIN, dragDropId, 'open', undefined, isBEESupport, isBEEAppEnable);
231
228
  } else if (this.props.location.query.module !== "library" || (this.props.location.query.module === "library" && !this.props.templateData)) {
232
229
  // Extract drag_drop_id - check multiple possible paths
@@ -237,7 +234,6 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
237
234
  || _.get(this.props.Templates.BEETemplate, 'versions.base.drag_drop_id')
238
235
  || _.get(this.props.Templates.BEETemplate, 'versions.base.id')
239
236
  || this.props.Templates.BEETemplate?._id;
240
- console.log('[Rafeeq manzoor] comes here 2');
241
237
  this.props.actions.getCmsSetting(BEE_PLUGIN, dragDropId, 'create', undefined, isBEESupport, isBEEAppEnable);
242
238
  }
243
239
  }
@@ -290,10 +286,8 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
290
286
 
291
287
  if (this.props.params.id) {
292
288
  const activeTabForLang = beeTemplate.versions?.base?.activeTab || 'en';
293
- console.log('[Rafeeq manzoor] comes here 3');
294
289
  this.props.actions.getCmsSetting(BEE_PLUGIN, dragDropId, 'open', activeTabForLang, isBEESupport, isBEEAppEnable);
295
290
  } else {
296
- console.log('[Rafeeq manzoor] comes here 4');
297
291
  this.props.actions.getCmsSetting(BEE_PLUGIN, dragDropId, 'create', undefined, isBEESupport, isBEEAppEnable);
298
292
  }
299
293
  }
@@ -304,24 +298,6 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
304
298
  if (!this.props.params?.id && this.props.Templates?.selectedEmailLayout) {
305
299
  this.setState((prev) => ({ loadingStatus: Math.max(prev.loadingStatus, 2) }));
306
300
  }
307
-
308
- // For loyalty library mode: componentWillReceiveProps may never fire if Redux state is
309
- // already stable after mount (schema cached, BEETemplate already empty). Call
310
- // startTemplateCreation directly here so the BEE editor always initialises.
311
- if (
312
- !this.templateCreationStarted
313
- && this.state.isEdit
314
- && this.props.moduleType === LOYALTY
315
- && this.props.location.query.module === 'library'
316
- && !_.isEmpty(this.props.templateData)
317
- && !this.props.params.id
318
- && !this.props.isGetFormData
319
- && _.isEmpty(_.get(this, `state.formData['template-subject']`))
320
- ) {
321
- this.templateCreationStarted = true;
322
- console.log('[componentDidMount] loyalty library - calling startTemplateCreation directly', this.props.templateData);
323
- this.startTemplateCreation(this.props.templateData);
324
- }
325
301
  }
326
302
 
327
303
 
@@ -355,7 +331,6 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
355
331
  this.getFormData();
356
332
  }
357
333
  }
358
- console.log('[Rafeeq manzoor] nextProps', nextProps, _.isEmpty(this.state.formData));
359
334
  if (this.state.languageDataSet && nextProps.Templates.selectedEmailLayout && nextProps.Templates.selectedEmailLayout !== '' && !_.isEqual(this.props.Templates.selectedEmailLayout, nextProps.Templates.selectedEmailLayout )) {
360
335
  this.setNewLanguageContent(nextProps.Templates.selectedEmailLayout);
361
336
  }
@@ -384,7 +359,6 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
384
359
  }, 0);
385
360
  }
386
361
  if (nextProps.currentOrgDetails && nextProps.currentOrgDetails.basic_details && !_.isEmpty(nextProps.currentOrgDetails.basic_details) && _.isEmpty(this.state.formData)) {
387
- console.log('[Rafeeq manzoor] if condition');
388
362
  const formData = this.initFormData(nextProps);
389
363
  formData['template-version-options'] = [
390
364
  {
@@ -478,10 +452,8 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
478
452
  // Extract langId from active tab
479
453
  const activeTabForLang = beeTemplate.versions?.base?.activeTab || 'en';
480
454
  if (hasParamsId) {
481
- console.log('[Rafeeq manzoor] comes here 5');
482
455
  this.props.actions.getCmsSetting(BEE_PLUGIN, dragDropId, 'open', activeTabForLang, isBEESupport, isBEEAppEnable);
483
456
  } else if (nextProps.location.query.module !== "library" || (nextProps.location.query.module === "library" && !nextProps.templateData)) {
484
- console.log('[Rafeeq manzoor] comes here 6');
485
457
  this.props.actions.getCmsSetting(BEE_PLUGIN, dragDropId, 'create', undefined, isBEESupport, isBEEAppEnable);
486
458
  }
487
459
  }
@@ -498,12 +470,7 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
498
470
  }
499
471
  });
500
472
  }
501
- console.log('[Rafeeq manzoor] here we have data 1', this.state.isEdit, nextProps.location.query.module);
502
- console.log('[Rafeeq manzoor] here we have data 2', nextProps.templateData, !_.isEmpty(nextProps.templateData), this.props.params.id, nextProps.isGetFormData);
503
- console.log('[Rafeeq manzoor] here we have data 3', _.isEmpty(_.get(this, `state.formData['template-subject']`)));
504
-
505
- if (!this.templateCreationStarted && this.state.isEdit && nextProps.moduleType === LOYALTY && nextProps.location.query.module === "library" && !_.isEmpty(nextProps.templateData) && !this.props.params.id && !nextProps.isGetFormData && _.isEmpty(_.get(this, `state.formData['template-subject']`))) {
506
- this.templateCreationStarted = true;
473
+ if (this.state.isEdit && nextProps.location.query.module === "library" && !_.isEmpty(nextProps.templateData) && !this.props.params.id && !nextProps.isGetFormData && _.isEmpty(_.get(this, `state.formData['template-subject']`))) {
507
474
  this.startTemplateCreation(nextProps.templateData);
508
475
  }
509
476
  if (nextProps.location.query.module === 'library' && nextProps.isGetFormData && (this.props.isGetFormData !== nextProps.isGetFormData)) {
@@ -1271,7 +1238,6 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
1271
1238
  // formData.base.activeTab = language;
1272
1239
  // }
1273
1240
  if (language && editData.versions.base[language].is_drag_drop && isBEEAppEnable) {
1274
- console.log('[Rafeeq manzoor] comes here 7');
1275
1241
  this.props.actions.getCmsSetting(BEE_PLUGIN, editData._id, 'open', language, isBEESupport, isBEEAppEnable);
1276
1242
  }
1277
1243
  });
@@ -1495,7 +1461,6 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
1495
1461
  const currentTab = this.state.currentTab - 1;
1496
1462
  const baseLanguage = this.props.currentOrgDetails.basic_details.base_language ? this.props.currentOrgDetails.basic_details.base_language : 'en';
1497
1463
  if (formData[currentTab][baseLanguage].is_drag_drop && isBEEAppEnable) {
1498
- console.log('[Rafeeq manzoor] comes here 8');
1499
1464
  this.props.actions.getCmsSetting(BEE_PLUGIN, formData[currentTab][baseLanguage].drag_drop_id, 'duplicate', baseLanguage, isEdmSupport, isBEEAppEnable);
1500
1465
  }
1501
1466
  });
@@ -1674,9 +1639,6 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
1674
1639
  if (content.id) {
1675
1640
  tmpData.id = content.id;
1676
1641
  }
1677
- if (content.drag_drop_id) {
1678
- tmpData.drag_drop_id = content.drag_drop_id;
1679
- }
1680
1642
  }
1681
1643
  newFormData.base = _.cloneDeep(tmpData);
1682
1644
  newFormData.secondary_templates.push({template_data: tmpData});
@@ -2553,7 +2515,6 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
2553
2515
  const isBEEAppEnable = this.checkBeeEditorAllowedForLibrary();
2554
2516
  if (templates.drag_drop_id && isBEEAppEnable) {
2555
2517
  tempData.drag_drop_id = templates.drag_drop_id;
2556
- console.log('[Rafeeq manzoor] comes here 9');
2557
2518
  this.props.actions.getCmsSetting(BEE_PLUGIN, tempData._id, 'open', tempData.iso_code, isEdmSupport, isBEEAppEnable);
2558
2519
  }
2559
2520
  // formData.usingTabContainer = true;
@@ -2574,17 +2535,13 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
2574
2535
  });
2575
2536
  this.addLanguage(false, formData, false, additionalLanguages);
2576
2537
  }
2577
- console.log("[Rafeeq manzoor] comes here lib 1", formData[0])
2578
2538
  formData.base = _.cloneDeep(formData[0]);
2579
2539
  if (formData?.['template-subject'] !== '') {
2580
- console.log("[Rafeeq manzoor] comes here lib 1 if", formData)
2581
2540
  this.setState({formData, loading: false, injectedTags: data.tags, tabKey, isDragDrop: (data.base.is_drag_drop !== 0 )}, () => {
2582
2541
  // this.setState({tabKey: ''});
2583
2542
  const isBEEEnable = this.checkBeeEditorAllowedForLibrary();
2584
- console.log("[Rafeeq manzoor] comes here lib 1 isBEEEnable", isBEEEnable)
2585
2543
  _.forEach(formData[0].selectedLanguages, (language) => {
2586
2544
  if (formData[0][language].is_drag_drop && isBEEEnable) {
2587
- console.log('[Rafeeq manzoor] comes here 10');
2588
2545
  this.props.actions.getCmsSetting(BEE_PLUGIN, formData[0][language].drag_drop_id, 'open', language, isEdmSupport, isBEEEnable);
2589
2546
  }
2590
2547
  });
@@ -2927,7 +2884,6 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
2927
2884
  // let getQuery = '';
2928
2885
  const isEdmSupport = (this.props.location.query.isEdmSupport !== "false") || false;
2929
2886
  const isBEEAppEnable = this.checkBeeEditorAllowedForLibrary();
2930
- console.log('[Rafeeq manzoor] comes here 11');
2931
2887
  this.props.actions.getCmsSetting(BEE_PLUGIN, data._id, 'create', this.state.formData[this.state.currentTab - 1].activeTab, isEdmSupport, isBEEAppEnable);
2932
2888
  // this.props.templatesActions.setEdmTemplate(data);
2933
2889
  this.toggleEdmEmailTemplateSelection();
@@ -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,22 @@
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
9
 
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
- }
10
+ // 3 cards per row across all breakpoints
11
+ .creatives-templates-list {
12
+ .v2-pagination-container,
13
+ .v2-pagination-container-half {
14
+ .cap-custom-card-list-row {
15
+ .cap-custom-card-list-col {
16
+ width: calc(33.33% - #{$CAP_SPACE_08});
17
+ margin-right: $CAP_SPACE_12;
18
+ &:nth-child(3n) {
19
+ margin-right: 0;
32
20
  }
33
21
  }
34
22
  }
@@ -674,6 +662,32 @@
674
662
  font-size: 14px;
675
663
  }
676
664
 
665
+ // Archive/Unarchive confirm modal overrides — scoped to avoid affecting other modals
666
+ .archive-confirm-modal {
667
+ // Remove the left margin added when an icon is present
668
+ .ant-modal-confirm-body {
669
+ > .anticon + .ant-modal-confirm-title + .ant-modal-confirm-content {
670
+ margin-left: 0;
671
+ }
672
+ }
673
+
674
+ // Left-align buttons, remove float
675
+ .ant-modal-confirm-btns {
676
+ float: none;
677
+ display: flex;
678
+ align-items: center;
679
+ gap: $CAP_SPACE_08;
680
+ margin-top: $CAP_SPACE_16;
681
+
682
+ // Cancel button styling
683
+ .ant-btn:not(.ant-btn-primary) {
684
+ background-color: $CAP_G08;
685
+ border-color: $CAP_G08;
686
+ color: $CAP_G01;
687
+ }
688
+ }
689
+ }
690
+
677
691
  .popover-action-container {
678
692
  line-height: 24px;
679
693
  }
@@ -1101,4 +1115,96 @@
1101
1115
  .inapp-illustration-parent {
1102
1116
  height: "calc(100vh - 325px)";
1103
1117
  overflow: 'auto';
1104
- }
1118
+ }
1119
+
1120
+ // Archive feature layout classes
1121
+ .illustration-scroll-wrapper {
1122
+ height: calc(100vh - 20.3125rem);
1123
+ overflow: auto;
1124
+ }
1125
+
1126
+ .filter-row {
1127
+ display: flex;
1128
+ align-items: center;
1129
+ justify-content: space-between;
1130
+ width: 100%;
1131
+ }
1132
+
1133
+ .filter-row-content {
1134
+ flex: 1;
1135
+ }
1136
+
1137
+ .bulk-selection-bar {
1138
+ display: flex;
1139
+ align-items: center;
1140
+ gap: $CAP_SPACE_12;
1141
+ flex-shrink: 0;
1142
+ }
1143
+
1144
+ .archived-mode-header {
1145
+ display: flex;
1146
+ align-items: center;
1147
+ gap: $CAP_SPACE_12;
1148
+ margin-bottom: $CAP_SPACE_16;
1149
+
1150
+ .archived-mode-back-icon {
1151
+ cursor: pointer;
1152
+ font-size: 1.428rem;
1153
+ }
1154
+ }
1155
+
1156
+ .archived-tag {
1157
+ margin-left: $CAP_SPACE_08;
1158
+ font-size: 0.786rem;
1159
+ }
1160
+
1161
+ .popover-archive-action {
1162
+ cursor: pointer;
1163
+ padding: $CAP_SPACE_08 0;
1164
+ }
1165
+
1166
+ .archive-menu-item {
1167
+ display: inline-flex;
1168
+ align-items: center;
1169
+ gap: $CAP_SPACE_08;
1170
+ margin-top: 1rem;
1171
+ }
1172
+
1173
+ .archive-btn-label {
1174
+ margin-right: 0.714rem;
1175
+ }
1176
+
1177
+ .bulk-selection-bar .cap-button-v2-prefix {
1178
+ margin-top: 1rem;
1179
+ }
1180
+
1181
+ .bulk-selection-bar .ant-btn.cap-button-v2 > .cap-button-v2-prefix + span {
1182
+ margin-left: -$CAP_SPACE_06;
1183
+ }
1184
+
1185
+ .template-card-top-bar {
1186
+ display: flex;
1187
+ align-items: center;
1188
+ justify-content: space-between;
1189
+ padding: $CAP_SPACE_08 $CAP_SPACE_12 0;
1190
+ }
1191
+
1192
+ .template-listing-header-actions {
1193
+ display: flex;
1194
+ justify-content: space-between;
1195
+ align-items: center;
1196
+ gap: $CAP_SPACE_08;
1197
+ }
1198
+
1199
+ .template-listing-more-btn {
1200
+ padding: 0 $CAP_SPACE_08;
1201
+ min-width: auto;
1202
+ }
1203
+
1204
+ .notification-template-label {
1205
+ color: #5E6C84;
1206
+ }
1207
+
1208
+ .notification-template-name {
1209
+ color: #091E42;
1210
+ }
@@ -167,3 +167,39 @@ export function getCdnTransformationConfig() {
167
167
  type: types.GET_CDN_TRANSFORMATION_CONFIG_REQUEST,
168
168
  };
169
169
  }
170
+
171
+ export function archiveTemplate(channel, id, templateName) {
172
+ return { type: types.ARCHIVE_TEMPLATE_REQUEST, channel, id, templateName };
173
+ }
174
+
175
+ export function unarchiveTemplate(channel, id, templateName) {
176
+ return { type: types.UNARCHIVE_TEMPLATE_REQUEST, channel, id, templateName };
177
+ }
178
+
179
+ export function bulkArchiveTemplates(channel, ids) {
180
+ return { type: types.BULK_ARCHIVE_REQUEST, channel, ids };
181
+ }
182
+
183
+ export function bulkUnarchiveTemplates(channel, ids) {
184
+ return { type: types.BULK_UNARCHIVE_REQUEST, channel, ids };
185
+ }
186
+
187
+ export function setArchiveFilter(filter) {
188
+ return { type: types.SET_ARCHIVE_FILTER, filter };
189
+ }
190
+
191
+ export function toggleTemplateSelection(id) {
192
+ return { type: types.TOGGLE_TEMPLATE_SELECTION, id };
193
+ }
194
+
195
+ export function selectAllTemplates(ids) {
196
+ return { type: types.SELECT_ALL_TEMPLATES, ids };
197
+ }
198
+
199
+ export function clearTemplateSelection() {
200
+ return { type: types.CLEAR_TEMPLATE_SELECTION };
201
+ }
202
+
203
+ export function setArchivedMode(isArchived) {
204
+ return { type: types.SET_ARCHIVED_MODE, isArchived };
205
+ }
@@ -91,3 +91,26 @@ 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';