@capillarytech/creatives-library 8.0.346 → 8.0.347
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.
- package/package.json +1 -1
- package/services/api.js +20 -0
- package/services/tests/api.test.js +59 -0
- package/utils/tests/v2Common.test.js +46 -1
- package/utils/v2common.js +18 -0
- package/v2Components/CapCustomSkeleton/index.js +1 -1
- package/v2Components/CapCustomSkeleton/tests/__snapshots__/index.test.js.snap +12 -12
- package/v2Containers/Assets/images/archive_Empty_Illustration.svg +9 -0
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +3 -1
- package/v2Containers/CreativesContainer/index.js +5 -0
- package/v2Containers/CreativesContainer/messages.js +4 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +3 -0
- package/v2Containers/Templates/ChannelTypeIllustration.js +23 -6
- package/v2Containers/Templates/_templates.scss +179 -24
- package/v2Containers/Templates/actions.js +44 -0
- package/v2Containers/Templates/constants.js +23 -0
- package/v2Containers/Templates/index.js +378 -58
- package/v2Containers/Templates/messages.js +88 -0
- package/v2Containers/Templates/reducer.js +84 -1
- package/v2Containers/Templates/sagas.js +64 -0
- package/v2Containers/Templates/selectors.js +12 -0
- package/v2Containers/Templates/tests/ChannelTypeIllustration.test.js +12 -0
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1345 -1122
- package/v2Containers/Templates/tests/index.test.js +6 -0
- package/v2Containers/Templates/tests/reducer.test.js +178 -0
- package/v2Containers/Templates/tests/sagas.test.js +390 -8
- package/v2Containers/Templates/tests/selector.test.js +32 -0
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +1 -1
|
@@ -50,9 +50,7 @@ import {
|
|
|
50
50
|
CapStatus,
|
|
51
51
|
CapColoredTag,
|
|
52
52
|
CapSpin,
|
|
53
|
-
|
|
54
|
-
CapColumn,
|
|
55
|
-
CapCarousel
|
|
53
|
+
CapCheckbox,
|
|
56
54
|
} from "@capillarytech/cap-ui-library";
|
|
57
55
|
import { makeSelectTemplates, makeSelectTemplatesResponse } from './selectors';
|
|
58
56
|
import { makeSelectCreate as makeSelectCreateSms } from '../Sms/Create/selectors';
|
|
@@ -83,7 +81,7 @@ import * as webpushActions from '../WebPush/actions';
|
|
|
83
81
|
import * as globalActions from '../Cap/actions';
|
|
84
82
|
import { makeSelectAuthenticated } from '../Cap/selectors';
|
|
85
83
|
import { UserIsAuthenticated } from '../../utils/authWrapper';
|
|
86
|
-
import { getObjFromQueryParams } from '../../utils/v2common';
|
|
84
|
+
import { getObjFromQueryParams, buildTemplateNameDescription } from '../../utils/v2common';
|
|
87
85
|
import messages from './messages';
|
|
88
86
|
import {checkUnicode} from '../../utils/smsCharCountV2';
|
|
89
87
|
import { containsBase64Images } from '../../utils/content';
|
|
@@ -108,7 +106,7 @@ import {
|
|
|
108
106
|
CREATE,
|
|
109
107
|
} from '../App/constants';
|
|
110
108
|
import {MAX_WHATSAPP_TEMPLATES, WARNING_WHATSAPP_TEMPLATES , ACCOUNT_MAPPING_ON_CHANNEL, noFilteredWhatsappZaloTemplatesTitle, noFilteredWhatsappZaloTemplatesDesc, noApprovedWhatsappZaloTemplatesTitle, noApprovedWhatsappTemplatesDesc, zaloDescIllustration, noApprovedRcsTemplatesTitle, noApprovedRcsTemplatesDesc} from './constants';
|
|
111
|
-
import { COPY_OF } from '../../constants/unified';
|
|
109
|
+
import { COPY_OF, EMBEDDED } from '../../constants/unified';
|
|
112
110
|
import {
|
|
113
111
|
STATUS_OPTIONS,
|
|
114
112
|
CATEGORY,
|
|
@@ -116,19 +114,11 @@ import {
|
|
|
116
114
|
STATUS as WHATSAPP_STATUS,
|
|
117
115
|
WHATSAPP_STATUSES,
|
|
118
116
|
HOST_GUPSHUP,
|
|
119
|
-
HOST_HAPTIC,
|
|
120
117
|
CATEGORY_OPTIONS_MAP,
|
|
121
|
-
HOST_TWILIO,
|
|
122
|
-
TWILIO_CATEGORY_OPTIONS,
|
|
123
|
-
KARIX_GUPSHUP_CATEGORY_OPTIONS,
|
|
124
|
-
ICS_CATEGORY_OPTIONS,
|
|
125
|
-
HAPTIC_CATEGORY_OPTIONS,
|
|
126
|
-
HOST_ICS,
|
|
127
118
|
IMAGE,
|
|
128
119
|
VIDEO,
|
|
129
|
-
GIF,
|
|
130
120
|
} from '../Whatsapp/constants';
|
|
131
|
-
import { INAPP_LAYOUT_DETAILS, INAPP_MESSAGE_LAYOUT_TYPES
|
|
121
|
+
import { INAPP_LAYOUT_DETAILS, INAPP_MESSAGE_LAYOUT_TYPES } from '../InApp/constants';
|
|
132
122
|
import { ZALO_STATUS_OPTIONS, ZALO_STATUSES } from '../Zalo/constants';
|
|
133
123
|
import { getWhatsappContent, getWhatsappStatus, getWhatsappCategory, getWhatsappCta, getWhatsappQuickReply, getWhatsappAutoFill, getWhatsappCarouselButtonView } from '../Whatsapp/utils';
|
|
134
124
|
import { getRCSContent } from '../Rcs/utils';
|
|
@@ -145,7 +135,7 @@ import {CREATIVE} from '../Facebook/constants';
|
|
|
145
135
|
import videoPlay from '../../assets/videoPlay.svg';
|
|
146
136
|
import whatsappImageEmptyPreview from '../../v2Components/TemplatePreview/assets/images/empty_image_preview.svg';
|
|
147
137
|
import whatsappVideoEmptyPreview from '../../v2Components/TemplatePreview/assets/images/empty_video_preview.svg';
|
|
148
|
-
import { CAP_SPACE_16 } from '@capillarytech/cap-ui-library/styled/variables';
|
|
138
|
+
import { CAP_SPACE_16, CAP_G08, CAP_G05, CAP_SPACE_08, CAP_SPACE_12 } from '@capillarytech/cap-ui-library/styled/variables';
|
|
149
139
|
import { GA } from '@capillarytech/cap-ui-utils';
|
|
150
140
|
import { MAPP_SDK } from '../InApp/constants';
|
|
151
141
|
import injectReducer from '../../utils/injectReducer';
|
|
@@ -154,7 +144,6 @@ import { compose } from 'redux';
|
|
|
154
144
|
import { v2TemplateSaga } from './sagas';
|
|
155
145
|
import injectSaga from '../../utils/injectSaga';
|
|
156
146
|
import { DAEMON } from '@capillarytech/vulcan-react-sdk/utils/sagaInjectorTypes';
|
|
157
|
-
import { Rcs } from '../Rcs';
|
|
158
147
|
import { makeSelectRcs } from '../Rcs/selectors';
|
|
159
148
|
import { getRcsStatusType } from '../Rcs/utils';
|
|
160
149
|
import { makeSelectWebPush } from '../WebPush/selectors';
|
|
@@ -437,6 +426,9 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
437
426
|
channel = '';
|
|
438
427
|
}
|
|
439
428
|
this.setState({ channel, activeMode });
|
|
429
|
+
// Always reset archive mode and selection when mounting a new channel
|
|
430
|
+
this.props.actions.setArchivedMode(false);
|
|
431
|
+
this.props.actions.clearTemplateSelection();
|
|
440
432
|
// Clear templates when entering account selection mode to prevent showing old channel templates
|
|
441
433
|
if (activeMode === ACCOUNT_SELECTION_MODE) {
|
|
442
434
|
this.props.actions.resetTemplate();
|
|
@@ -827,6 +819,41 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
827
819
|
this.getAllTemplates({params, resetPage: true});
|
|
828
820
|
}
|
|
829
821
|
|
|
822
|
+
// Archive / Unarchive / Bulk Archive / Bulk Unarchive — detect completion and refresh listing
|
|
823
|
+
const wasArchiving = this.props.Templates.archiveInProgress;
|
|
824
|
+
const isArchiveDone = !nextProps.Templates.archiveInProgress && wasArchiving;
|
|
825
|
+
if (isArchiveDone && !nextProps.Templates.archiveError) {
|
|
826
|
+
const { successMessage, description } = nextProps.Templates.archiveSuccessPayload || {};
|
|
827
|
+
if (successMessage) CapNotification.success({ message: successMessage, description });
|
|
828
|
+
this.getAllTemplates({ params, resetPage: true });
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
const wasUnarchiving = this.props.Templates.unarchiveInProgress;
|
|
832
|
+
const isUnarchiveDone = !nextProps.Templates.unarchiveInProgress && wasUnarchiving;
|
|
833
|
+
if (isUnarchiveDone && !nextProps.Templates.unarchiveError) {
|
|
834
|
+
const { successMessage, description } = nextProps.Templates.unarchiveSuccessPayload || {};
|
|
835
|
+
if (successMessage) CapNotification.success({ message: successMessage, description });
|
|
836
|
+
this.getAllTemplates({ params, resetPage: true });
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
const wasBulkArchiving = this.props.Templates.bulkArchiveInProgress;
|
|
840
|
+
const isBulkArchiveDone = !nextProps.Templates.bulkArchiveInProgress && wasBulkArchiving;
|
|
841
|
+
if (isBulkArchiveDone && !nextProps.Templates.bulkArchiveError) {
|
|
842
|
+
const { successMessage, count } = nextProps.Templates.bulkArchiveSuccessPayload || {};
|
|
843
|
+
const msg = successMessage ? successMessage(count) : `${count} templates archived successfully`;
|
|
844
|
+
CapNotification.success({ message: msg });
|
|
845
|
+
this.getAllTemplates({ params, resetPage: true });
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
const wasBulkUnarchiving = this.props.Templates.bulkUnarchiveInProgress;
|
|
849
|
+
const isBulkUnarchiveDone = !nextProps.Templates.bulkUnarchiveInProgress && wasBulkUnarchiving;
|
|
850
|
+
if (isBulkUnarchiveDone && !nextProps.Templates.bulkUnarchiveError) {
|
|
851
|
+
const { successMessage, count } = nextProps.Templates.bulkUnarchiveSuccessPayload || {};
|
|
852
|
+
const msg = successMessage ? successMessage(count) : `${count} templates unarchived successfully`;
|
|
853
|
+
CapNotification.success({ message: msg });
|
|
854
|
+
this.getAllTemplates({ params, resetPage: true });
|
|
855
|
+
}
|
|
856
|
+
|
|
830
857
|
if (!nextProps.Templates.sendingFile && !isEqual(this.props.Templates.sendingFile, nextProps.Templates.sendingFile) && !nextProps.Templates.errorSendingFile) {
|
|
831
858
|
const module = this.props.location.query.module ? this.props.location.query.module : 'default';
|
|
832
859
|
const isLanguageSupport = (this.props.location.query.isLanguageSupport) ? this.props.location.query.isLanguageSupport : true;
|
|
@@ -1595,6 +1622,11 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
1595
1622
|
let queryParams = params || {};
|
|
1596
1623
|
let page = this.state.page;
|
|
1597
1624
|
const { activeMode } = this.state;
|
|
1625
|
+
// Archive filter — use explicit param if provided (props may not have updated yet due to async dispatch)
|
|
1626
|
+
if (!queryParams.archiveStatus) {
|
|
1627
|
+
const archiveFilter = get(this.props, 'Templates.archiveFilter', 'active');
|
|
1628
|
+
queryParams.archiveStatus = archiveFilter;
|
|
1629
|
+
}
|
|
1598
1630
|
if (activeMode === ACCOUNT_SELECTION_MODE) {
|
|
1599
1631
|
this.setTemplatesMode();
|
|
1600
1632
|
}
|
|
@@ -1861,6 +1893,9 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
1861
1893
|
const currentChannel = channel.toUpperCase();
|
|
1862
1894
|
const {channel: stateChannel} = this.state;
|
|
1863
1895
|
const channelLowerCase = stateChannel.toLowerCase();
|
|
1896
|
+
const _selectedIds = get(this.props, 'Templates.selectedTemplateIds', []);
|
|
1897
|
+
const _selectedIdsArray = _selectedIds && typeof _selectedIds.toJS === 'function' ? _selectedIds.toJS() : (Array.isArray(_selectedIds) ? _selectedIds : []);
|
|
1898
|
+
const hasSelection = this.props.isFullMode && _selectedIdsArray.length > 0;
|
|
1864
1899
|
let filteredTemplates = templates;
|
|
1865
1900
|
let isTraiDltFeature = false;
|
|
1866
1901
|
switch (currentChannel) {
|
|
@@ -1900,47 +1935,65 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
1900
1935
|
const iosBodyType = get(template, 'versions.base.content.IOS.bodyType');
|
|
1901
1936
|
const inappBodyType = androidBodyType || iosBodyType;
|
|
1902
1937
|
const isZaloPreviewLoading = previewTemplateId === template?._id;
|
|
1938
|
+
const selectedIdsForCard = get(this.props, 'Templates.selectedTemplateIds', []);
|
|
1939
|
+
const selectedIdsArrayForCard = selectedIdsForCard.toJS ? selectedIdsForCard.toJS() : selectedIdsForCard;
|
|
1940
|
+
// Archive eligibility per template: Zalo never; WhatsApp/RCS not when pending/awaiting
|
|
1941
|
+
const cardWhatsappStatus = get(template, `versions.base.content.${WHATSAPP_LOWERCASE}.status`, '');
|
|
1942
|
+
const cardRcsStatus = get(template, 'versions.base.content.RCS.rcsContent.cardContent[0].Status', '');
|
|
1943
|
+
const isCardArchiveEligible = this.isChannelArchiveEligible(currentChannel, cardWhatsappStatus, cardRcsStatus);
|
|
1944
|
+
const isArchivedMode = get(this.props, 'Templates.isArchivedMode', false);
|
|
1945
|
+
const isAnyArchiveInProgress = !!(get(this.props, 'Templates.archiveInProgress') || get(this.props, 'Templates.unarchiveInProgress') || get(this.props, 'Templates.bulkArchiveInProgress') || get(this.props, 'Templates.bulkUnarchiveInProgress'));
|
|
1903
1946
|
const templateData = {
|
|
1904
1947
|
key: `${currentChannel}-card-${template?.name}`,
|
|
1905
1948
|
title: (
|
|
1906
|
-
<span
|
|
1907
|
-
{
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
}
|
|
1915
|
-
tagHeight="1.25rem"
|
|
1916
|
-
tagFontSize="12px"
|
|
1917
|
-
>
|
|
1918
|
-
{INAPP_LAYOUT_DETAILS[inappBodyType]?.text}
|
|
1919
|
-
</CapColoredTag>
|
|
1920
|
-
</CapRow>
|
|
1949
|
+
<span className="template-card-title">
|
|
1950
|
+
{this.props.isFullMode && this.props.location.query.type !== EMBEDDED && isCardArchiveEligible && (
|
|
1951
|
+
<CapCheckbox
|
|
1952
|
+
checked={selectedIdsArrayForCard.includes(template._id)}
|
|
1953
|
+
onChange={() => !isAnyArchiveInProgress && this.props.actions.toggleTemplateSelection(template._id)}
|
|
1954
|
+
onClick={(e) => e.stopPropagation()}
|
|
1955
|
+
disabled={isAnyArchiveInProgress}
|
|
1956
|
+
/>
|
|
1921
1957
|
)}
|
|
1958
|
+
<CapLabel.CapLabelInline type="label1" title={template?.name} className="template-card-name">
|
|
1959
|
+
{template?.name}
|
|
1960
|
+
{currentChannel === INAPP && (
|
|
1961
|
+
<CapRow>
|
|
1962
|
+
<CapColoredTag
|
|
1963
|
+
tagColor={INAPP_LAYOUT_DETAILS[inappBodyType]?.tagColor}
|
|
1964
|
+
tagTextColor={
|
|
1965
|
+
INAPP_LAYOUT_DETAILS[inappBodyType]?.tagTextColor
|
|
1966
|
+
}
|
|
1967
|
+
tagHeight="1.25rem"
|
|
1968
|
+
tagFontSize="12px"
|
|
1969
|
+
>
|
|
1970
|
+
{INAPP_LAYOUT_DETAILS[inappBodyType]?.text}
|
|
1971
|
+
</CapColoredTag>
|
|
1972
|
+
</CapRow>
|
|
1973
|
+
)}
|
|
1974
|
+
</CapLabel.CapLabelInline>
|
|
1922
1975
|
</span>
|
|
1923
1976
|
),
|
|
1924
|
-
extra: [
|
|
1977
|
+
extra: isArchivedMode ? [] : [
|
|
1925
1978
|
// Hide preview icon for channels that support Test and Preview
|
|
1926
1979
|
// Show preview icon only for channels that don't support Test and Preview
|
|
1927
1980
|
(() => {
|
|
1928
1981
|
// Channels that have Test and Preview integrated
|
|
1929
1982
|
const testAndPreviewChannels = [EMAIL, SMS, WHATSAPP, RCS, INAPP, MOBILE_PUSH, VIBER, ZALO];
|
|
1930
1983
|
const isTestAndPreviewSupported = testAndPreviewChannels.includes(currentChannel.toUpperCase());
|
|
1931
|
-
|
|
1984
|
+
|
|
1932
1985
|
// Don't show preview icon if channel supports Test and Preview
|
|
1933
1986
|
if (isTestAndPreviewSupported) {
|
|
1934
1987
|
return null;
|
|
1935
1988
|
}
|
|
1936
|
-
|
|
1989
|
+
|
|
1937
1990
|
// Show preview icon for other channels (e.g., WeChat, Line, Facebook, Ebill)
|
|
1938
1991
|
if (currentChannel === ZALO && isZaloPreviewLoading) {
|
|
1939
1992
|
return (
|
|
1940
1993
|
<CapSpin style={{ marginRight: "16px", position: "static", display: "inline" }} spinning />
|
|
1941
1994
|
);
|
|
1942
1995
|
}
|
|
1943
|
-
|
|
1996
|
+
|
|
1944
1997
|
return this.getHoverComponent(
|
|
1945
1998
|
<CapIcon
|
|
1946
1999
|
className={`view-${channelLowerCase}`}
|
|
@@ -1960,7 +2013,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
1960
2013
|
);
|
|
1961
2014
|
})()
|
|
1962
2015
|
],
|
|
1963
|
-
hoverOption: (
|
|
2016
|
+
hoverOption: isArchivedMode ? null : (
|
|
1964
2017
|
<CapButton
|
|
1965
2018
|
className={
|
|
1966
2019
|
this.props.isFullMode
|
|
@@ -2000,8 +2053,8 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
2000
2053
|
<CapDropdown
|
|
2001
2054
|
overlay={
|
|
2002
2055
|
<CapMenu>
|
|
2003
|
-
{/* Phase 16: Test and Preview menu item - Show for supported channels */}
|
|
2004
|
-
{(this.isTestAndPreviewSupported() ||
|
|
2056
|
+
{/* Phase 16: Test and Preview menu item - Show for supported channels, hide in archived mode */}
|
|
2057
|
+
{!isArchivedMode && (this.isTestAndPreviewSupported() ||
|
|
2005
2058
|
(this.state.channel.toUpperCase() === WHATSAPP &&
|
|
2006
2059
|
status === WHATSAPP_STATUSES.approved) || (this.state.channel.toUpperCase() === RCS &&
|
|
2007
2060
|
rcsStatus === RCS_STATUSES.approved)) && (
|
|
@@ -2024,7 +2077,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
2024
2077
|
{![WECHAT, WHATSAPP, ZALO].includes(
|
|
2025
2078
|
this.state.channel.toUpperCase()
|
|
2026
2079
|
) &&
|
|
2027
|
-
!isTraiDltFeature && (
|
|
2080
|
+
!isTraiDltFeature && !template.isArchived && (
|
|
2028
2081
|
<CapMenu.Item
|
|
2029
2082
|
className={`duplicate-${channelLowerCase}`}
|
|
2030
2083
|
onClick={() => this.duplicateTemplate(template)}
|
|
@@ -2032,6 +2085,26 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
2032
2085
|
<FormattedMessage {...messages.duplicateButton} />
|
|
2033
2086
|
</CapMenu.Item>
|
|
2034
2087
|
)}
|
|
2088
|
+
{/* Archive/Unarchive menu item (full mode only, not for Zalo, not for WhatsApp/RCS awaiting/pending) */}
|
|
2089
|
+
{(() => {
|
|
2090
|
+
const channelUp = this.state.channel.toUpperCase();
|
|
2091
|
+
if (!this.isChannelArchiveEligible(channelUp, status, rcsStatus)) return null;
|
|
2092
|
+
return !template.isArchived ? (
|
|
2093
|
+
<CapMenu.Item
|
|
2094
|
+
className={`archive-${channelLowerCase}`}
|
|
2095
|
+
onClick={() => this.handleTemplateArchiveAction({ templateId: template._id, templateName: template.name })}
|
|
2096
|
+
>
|
|
2097
|
+
<FormattedMessage {...messages.archiveButton} />
|
|
2098
|
+
</CapMenu.Item>
|
|
2099
|
+
) : (
|
|
2100
|
+
<CapMenu.Item
|
|
2101
|
+
className={`unarchive-${channelLowerCase}`}
|
|
2102
|
+
onClick={() => this.handleTemplateArchiveAction({ templateId: template._id, templateName: template.name, isUnarchive: true })}
|
|
2103
|
+
>
|
|
2104
|
+
<FormattedMessage {...messages.unarchiveButton} />
|
|
2105
|
+
</CapMenu.Item>
|
|
2106
|
+
);
|
|
2107
|
+
})()}
|
|
2035
2108
|
{/* Delete/Unmap menu item */}
|
|
2036
2109
|
{(!(
|
|
2037
2110
|
this.state.channel.toUpperCase() === WHATSAPP &&
|
|
@@ -2312,7 +2385,15 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
2312
2385
|
case WHATSAPP: {
|
|
2313
2386
|
const { whatsappImageSrc = '', templateMsg, docPreview, whatsappVideoPreviewImg = '', templateHeaderPreview, templateFooterPreview, carouselData = [] } = getWhatsappContent(template);
|
|
2314
2387
|
templateData.title = (
|
|
2315
|
-
<CapRow>
|
|
2388
|
+
<CapRow type="flex" align="middle">
|
|
2389
|
+
{this.props.isFullMode && this.props.location.query.type !== EMBEDDED && isCardArchiveEligible && (
|
|
2390
|
+
<CapCheckbox
|
|
2391
|
+
checked={selectedIdsArrayForCard.includes(template._id)}
|
|
2392
|
+
onChange={() => !isAnyArchiveInProgress && this.props.actions.toggleTemplateSelection(template._id)}
|
|
2393
|
+
onClick={(e) => e.stopPropagation()}
|
|
2394
|
+
disabled={isAnyArchiveInProgress}
|
|
2395
|
+
/>
|
|
2396
|
+
)}
|
|
2316
2397
|
<CapLabel className="whatsapp-rcs-template-name">{template?.name}</CapLabel>
|
|
2317
2398
|
<WhatsappStatusContainer template={template} />
|
|
2318
2399
|
</CapRow>
|
|
@@ -2405,7 +2486,15 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
2405
2486
|
const name = get(template, "name", "");
|
|
2406
2487
|
const statusDisplay=getRcsStatusType(status);
|
|
2407
2488
|
templateData.title = (
|
|
2408
|
-
<CapRow>
|
|
2489
|
+
<CapRow type="flex" align="middle">
|
|
2490
|
+
{this.props.isFullMode && this.props.location.query.type !== EMBEDDED && isCardArchiveEligible && (
|
|
2491
|
+
<CapCheckbox
|
|
2492
|
+
checked={selectedIdsArrayForCard.includes(template._id)}
|
|
2493
|
+
onChange={() => !isAnyArchiveInProgress && this.props.actions.toggleTemplateSelection(template._id)}
|
|
2494
|
+
onClick={(e) => e.stopPropagation()}
|
|
2495
|
+
disabled={isAnyArchiveInProgress}
|
|
2496
|
+
/>
|
|
2497
|
+
)}
|
|
2409
2498
|
<CapLabel className="whatsapp-rcs-template-name">{name}</CapLabel>
|
|
2410
2499
|
<CapRow type="flex" align="middle" className="rcs-status-container zalo-status-color">
|
|
2411
2500
|
<CapStatus
|
|
@@ -2529,7 +2618,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
2529
2618
|
|
|
2530
2619
|
//no templates available
|
|
2531
2620
|
const showIllustrationForChannel = (forChannel) => {
|
|
2532
|
-
return forChannel === channelLowerCase && isEmpty(templates) && isEmpty(this.state.searchText) && !isLoading;
|
|
2621
|
+
return forChannel === channelLowerCase && isEmpty(templates) && isEmpty(this.state.searchText) && !isLoading && !get(this.props, 'Templates.isArchivedMode', false);
|
|
2533
2622
|
}
|
|
2534
2623
|
//when filters applied not matching templates
|
|
2535
2624
|
const filteredEmptyAndFullModeAs = (fullModeValue) => {
|
|
@@ -2547,6 +2636,11 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
2547
2636
|
const accountId = get(this.props, 'Templates.selectedWeChatAccount.uuid');
|
|
2548
2637
|
const accounts = get(this.props, 'Templates.weCrmAccounts');
|
|
2549
2638
|
const getAllTemplatesInProgress = get(this.props, 'Templates.getAllTemplatesInProgress');
|
|
2639
|
+
const archiveListingRefreshType = get(this.props, 'Templates.archiveListingRefreshType', null);
|
|
2640
|
+
const isArchiveOperationInProgress = get(this.props, 'Templates.archiveInProgress', false)
|
|
2641
|
+
|| get(this.props, 'Templates.unarchiveInProgress', false)
|
|
2642
|
+
|| get(this.props, 'Templates.bulkArchiveInProgress', false)
|
|
2643
|
+
|| get(this.props, 'Templates.bulkUnarchiveInProgress', false);
|
|
2550
2644
|
|
|
2551
2645
|
const noWhatsappZaloTemplates = this.isFullMode() && isEmpty(templates) || !this.state.hostName;
|
|
2552
2646
|
const noApprovedWhatsappZaloTemplates = filteredEmptyAndFullModeAs(false) && !isEmpty(this.state?.hostName);
|
|
@@ -2555,9 +2649,36 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
2555
2649
|
|
|
2556
2650
|
const noLoaderAndSearchText = isEmpty(this.state.searchText) && !isLoading;
|
|
2557
2651
|
|
|
2558
|
-
|
|
2652
|
+
const isArchivedModeLocal = get(this.props, 'Templates.isArchivedMode', false);
|
|
2653
|
+
const selectedIdsLocal = get(this.props, 'Templates.selectedTemplateIds', []);
|
|
2654
|
+
const selectedIdsArrayLocal = selectedIdsLocal && typeof selectedIdsLocal.toJS === 'function' ? selectedIdsLocal.toJS() : (Array.isArray(selectedIdsLocal) ? selectedIdsLocal : []);
|
|
2655
|
+
const selectedCountLocal = selectedIdsArrayLocal.length;
|
|
2656
|
+
const hasSelectionLocal = this.props.isFullMode && selectedCountLocal > 0;
|
|
2657
|
+
|
|
2658
|
+
return (<div>
|
|
2559
2659
|
{[WECHAT, MOBILE_PUSH, WEBPUSH, INAPP, WHATSAPP, ZALO, RCS].includes(currentChannel) && this.showAccountName()}
|
|
2560
|
-
|
|
2660
|
+
<CapRow type="flex" align="middle" justify="space-between" className="filter-row">
|
|
2661
|
+
<div className="filter-row-content">{filterContent}</div>
|
|
2662
|
+
{hasSelectionLocal && (
|
|
2663
|
+
<CapRow type="flex" align="middle" className="bulk-selection-bar">
|
|
2664
|
+
<CapLabel type="label2">
|
|
2665
|
+
{this.props.intl.formatMessage(messages.templatesSelected, { count: selectedCountLocal })}
|
|
2666
|
+
</CapLabel>
|
|
2667
|
+
<CapButton
|
|
2668
|
+
type="primary"
|
|
2669
|
+
prefix={<CapIcon type="archive" size="l" />}
|
|
2670
|
+
onClick={() => this.handleBulkArchiveAction({ ids: selectedIdsArrayLocal, count: selectedCountLocal, isUnarchive: isArchivedModeLocal })}
|
|
2671
|
+
>
|
|
2672
|
+
<span className="archive-btn-label">
|
|
2673
|
+
<FormattedMessage {...(isArchivedModeLocal ? messages.unarchiveButton : messages.archiveButton)} />
|
|
2674
|
+
</span>
|
|
2675
|
+
</CapButton>
|
|
2676
|
+
<CapButton type="secondary" onClick={() => this.props.actions.clearTemplateSelection()}>
|
|
2677
|
+
<FormattedMessage {...messages.archiveConfirmCancel} />
|
|
2678
|
+
</CapButton>
|
|
2679
|
+
</CapRow>
|
|
2680
|
+
)}
|
|
2681
|
+
</CapRow>
|
|
2561
2682
|
{[WHATSAPP, ZALO, INAPP,RCS].includes(currentChannel) && this.selectedFilters()}
|
|
2562
2683
|
{<div>
|
|
2563
2684
|
{!isEmpty(filteredTemplates) || !isEmpty(this.state.searchText) || !isEmpty(this.props.Templates.templateError) ? (
|
|
@@ -2570,7 +2691,7 @@ return (<div>
|
|
|
2570
2691
|
fbType={"list"}
|
|
2571
2692
|
/>
|
|
2572
2693
|
</div>)
|
|
2573
|
-
: [SMS_LOWERCASE, EMAIL_LOWERCASE].includes(this.state.channel.toLowerCase()) && !isLoading && this.getSmsEmailIllustration()
|
|
2694
|
+
: [SMS_LOWERCASE, EMAIL_LOWERCASE].includes(this.state.channel.toLowerCase()) && !isLoading && !get(this.props, 'Templates.isArchivedMode', false) && this.getSmsEmailIllustration()
|
|
2574
2695
|
}
|
|
2575
2696
|
|
|
2576
2697
|
{(this.state.selectedAccount === '' && isEmpty(this.props.Templates.selectedWeChatAccount)) && ([WECHAT_LOWERCASE, MOBILE_PUSH_LOWERCASE, INAPP_LOWERCASE].includes(this.state.channel.toLowerCase())) &&
|
|
@@ -2594,7 +2715,7 @@ return (<div>
|
|
|
2594
2715
|
</div>
|
|
2595
2716
|
)
|
|
2596
2717
|
}
|
|
2597
|
-
{(showWhatsappIllustration || showZaloIllustration) && (
|
|
2718
|
+
{(showWhatsappIllustration || showZaloIllustration) && !get(this.props, 'Templates.isArchivedMode', false) && (
|
|
2598
2719
|
noLoaderAndSearchText &&
|
|
2599
2720
|
<div style={this.isFullMode() ? { height: "calc(100vh - 325px)", overflow: 'auto' } : {}}>
|
|
2600
2721
|
{noWhatsappZaloTemplates && <ChannelTypeIllustration isFullMode={this.props.isFullMode} createTemplate={this.createTemplate} currentChannel={currentChannel} hostName={this.state?.hostName}/>}
|
|
@@ -2635,8 +2756,27 @@ return (<div>
|
|
|
2635
2756
|
<ChannelTypeIllustration isFullMode={this.props.isFullMode} createTemplate={this.createTemplate} currentChannel={currentChannel} hostName={this.state?.hostName}/>
|
|
2636
2757
|
</div>
|
|
2637
2758
|
}
|
|
2759
|
+
{get(this.props, 'Templates.isArchivedMode', false) && isEmpty(templates) && !isLoading && !getAllTemplatesInProgress && isEmpty(this.state.searchText) && (
|
|
2760
|
+
<CapRow className={this.isFullMode() ? 'illustration-scroll-wrapper' : ''}>
|
|
2761
|
+
<ChannelTypeIllustration
|
|
2762
|
+
isFullMode={this.props.isFullMode}
|
|
2763
|
+
createTemplate={this.createTemplate}
|
|
2764
|
+
currentChannel={currentChannel}
|
|
2765
|
+
isArchivedMode
|
|
2766
|
+
/>
|
|
2767
|
+
</CapRow>
|
|
2768
|
+
)}
|
|
2638
2769
|
{<CapCustomSkeleton loader={isInitialLoading && (isLoading || getAllTemplatesInProgress)} />}
|
|
2639
|
-
{
|
|
2770
|
+
{!isInitialLoading && getAllTemplatesInProgress && archiveListingRefreshType ? (
|
|
2771
|
+
<div className="archive-listing-spinner">
|
|
2772
|
+
<CapSpin spinning />
|
|
2773
|
+
<CapLabel.CapLabelInline type="label1">
|
|
2774
|
+
{archiveListingRefreshType === 'ARCHIVE' ? 'Archival in progress' : 'Unarchival in progress'}
|
|
2775
|
+
</CapLabel.CapLabelInline>
|
|
2776
|
+
</div>
|
|
2777
|
+
) : (
|
|
2778
|
+
<CapPageSpinner spinning={!isInitialLoading && (isLoading || getAllTemplatesInProgress)} />
|
|
2779
|
+
)}
|
|
2640
2780
|
</div>
|
|
2641
2781
|
}
|
|
2642
2782
|
</div>);
|
|
@@ -3278,6 +3418,10 @@ return (<div>
|
|
|
3278
3418
|
};
|
|
3279
3419
|
|
|
3280
3420
|
handleEditClick(e, template, modeType, path, options) {
|
|
3421
|
+
if (template && template.isArchived) {
|
|
3422
|
+
CapNotification.error({ message: this.props.intl.formatMessage(messages.cannotEditArchivedTemplate) });
|
|
3423
|
+
return;
|
|
3424
|
+
}
|
|
3281
3425
|
if (modeType && modeType !== undefined) {
|
|
3282
3426
|
this.setState({modeType});
|
|
3283
3427
|
}
|
|
@@ -3459,6 +3603,75 @@ return (<div>
|
|
|
3459
3603
|
this.setState({showModal: false});
|
|
3460
3604
|
}
|
|
3461
3605
|
|
|
3606
|
+
handleBulkArchiveAction = ({ ids, count, isUnarchive = false }) => {
|
|
3607
|
+
const { intl, actions } = this.props;
|
|
3608
|
+
const { channel } = this.state;
|
|
3609
|
+
const title = isUnarchive
|
|
3610
|
+
? intl.formatMessage(messages.unarchiveTemplates)
|
|
3611
|
+
: intl.formatMessage(messages.archiveTemplates);
|
|
3612
|
+
const action = isUnarchive ? actions.bulkUnarchiveTemplates : actions.bulkArchiveTemplates;
|
|
3613
|
+
const successMessage = (c) => intl.formatMessage(
|
|
3614
|
+
isUnarchive ? messages.bulkUnarchiveSuccess : messages.bulkArchiveSuccess,
|
|
3615
|
+
{ count: c }
|
|
3616
|
+
);
|
|
3617
|
+
this.showArchiveConfirm({
|
|
3618
|
+
title,
|
|
3619
|
+
count,
|
|
3620
|
+
isUnarchive,
|
|
3621
|
+
onConfirm: () => action(channel, ids, successMessage),
|
|
3622
|
+
});
|
|
3623
|
+
};
|
|
3624
|
+
|
|
3625
|
+
handleTemplateArchiveAction = ({ templateId, templateName, isUnarchive = false }) => {
|
|
3626
|
+
const { intl, actions } = this.props;
|
|
3627
|
+
const { channel } = this.state;
|
|
3628
|
+
const title = isUnarchive
|
|
3629
|
+
? intl.formatMessage(messages.unarchiveTemplates)
|
|
3630
|
+
: intl.formatMessage(messages.archiveTemplates);
|
|
3631
|
+
const successMessage = isUnarchive
|
|
3632
|
+
? intl.formatMessage(messages.unarchiveTemplateSuccess)
|
|
3633
|
+
: intl.formatMessage(messages.archiveTemplateSuccess);
|
|
3634
|
+
const action = isUnarchive ? actions.unarchiveTemplate : actions.archiveTemplate;
|
|
3635
|
+
this.showArchiveConfirm({
|
|
3636
|
+
title,
|
|
3637
|
+
count: 1,
|
|
3638
|
+
isUnarchive,
|
|
3639
|
+
onConfirm: () => action(
|
|
3640
|
+
channel,
|
|
3641
|
+
templateId,
|
|
3642
|
+
successMessage,
|
|
3643
|
+
buildTemplateNameDescription(intl.formatMessage(messages.templateNameLabel), templateName)
|
|
3644
|
+
),
|
|
3645
|
+
});
|
|
3646
|
+
};
|
|
3647
|
+
|
|
3648
|
+
// Shared helper for archive/unarchive confirm modals:
|
|
3649
|
+
// - no icon, lighter overlay, Confirm button on left (primary), Cancel on right
|
|
3650
|
+
showArchiveConfirm = ({ title, content, onConfirm, count = 1, isUnarchive = false }) => {
|
|
3651
|
+
const { intl } = this.props;
|
|
3652
|
+
const confirmText = intl.formatMessage(messages.archiveConfirmOk);
|
|
3653
|
+
const cancelText = intl.formatMessage(messages.archiveConfirmCancel);
|
|
3654
|
+
// Derive content from count if not explicitly provided
|
|
3655
|
+
const resolvedContent = content || (isUnarchive
|
|
3656
|
+
? intl.formatMessage(count > 1 ? messages.unarchiveTemplateContent : messages.unarchiveTemplateSingleContent)
|
|
3657
|
+
: intl.formatMessage(count > 1 ? messages.archiveTemplateContent : messages.archiveTemplateSingleContent));
|
|
3658
|
+
// AntD v3 footer order is [cancelButton][okButton]. Swap text+handler so
|
|
3659
|
+
// "Confirm" (primary) appears on the left and "Cancel" (default) on the right.
|
|
3660
|
+
CapModal.confirm({
|
|
3661
|
+
title,
|
|
3662
|
+
content: resolvedContent,
|
|
3663
|
+
icon: ' ',
|
|
3664
|
+
className: 'archive-confirm-modal',
|
|
3665
|
+
maskStyle: { backgroundColor: 'rgba(0, 0, 0, 0.25)' },
|
|
3666
|
+
cancelText: confirmText,
|
|
3667
|
+
okText: cancelText,
|
|
3668
|
+
cancelButtonProps: { type: 'primary' },
|
|
3669
|
+
okButtonProps: { type: 'default' },
|
|
3670
|
+
onCancel: (close) => { onConfirm(); close(); },
|
|
3671
|
+
// onOk (the right "Cancel" button) just closes the modal — default behaviour
|
|
3672
|
+
});
|
|
3673
|
+
}
|
|
3674
|
+
|
|
3462
3675
|
populateTemplatesList = (data, blankTemplateRequired, layoutSelection) => {
|
|
3463
3676
|
if (!data) {
|
|
3464
3677
|
return [];
|
|
@@ -3608,22 +3821,71 @@ return (<div>
|
|
|
3608
3821
|
deleteOption = this.props.intl.formatMessage(messages.unMapButton);
|
|
3609
3822
|
}
|
|
3610
3823
|
if (!layoutSelection) {
|
|
3824
|
+
// Determine archive eligibility for this template:
|
|
3825
|
+
// - Zalo: never eligible
|
|
3826
|
+
// - WhatsApp: not eligible when status is awaitingApproval / pending / unsubmitted
|
|
3827
|
+
// - RCS: not eligible when status is awaitingApproval / pending
|
|
3828
|
+
const templateWhatsappStatus = get(template, `versions.base.content.${WHATSAPP_LOWERCASE}.status`, '');
|
|
3829
|
+
const templateRcsStatus = get(template, 'versions.base.content.RCS.rcsContent.cardContent[0].Status', '');
|
|
3830
|
+
const channelUpCase = this.state.channel.toUpperCase();
|
|
3831
|
+
const isTemplateArchiveEligible = this.isChannelArchiveEligible(channelUpCase, templateWhatsappStatus, templateRcsStatus);
|
|
3832
|
+
|
|
3833
|
+
// Checkbox on card header (full mode only, only for archive-eligible templates)
|
|
3834
|
+
if (this.props.isFullMode && this.props.location.query.type !== EMBEDDED && isTemplateArchiveEligible) {
|
|
3835
|
+
const selectedIds = get(this.props, 'Templates.selectedTemplateIds', []);
|
|
3836
|
+
const selectedIdsArray = selectedIds.toJS ? selectedIds.toJS() : selectedIds;
|
|
3837
|
+
temp.cardTop = (
|
|
3838
|
+
<CapRow type="flex" align="middle" justify="space-between" className="template-card-top-bar">
|
|
3839
|
+
<CapCheckbox
|
|
3840
|
+
checked={selectedIdsArray.includes(template._id)}
|
|
3841
|
+
onChange={() => this.props.actions.toggleTemplateSelection(template._id)}
|
|
3842
|
+
onClick={(e) => e.stopPropagation()}
|
|
3843
|
+
/>
|
|
3844
|
+
</CapRow>
|
|
3845
|
+
);
|
|
3846
|
+
}
|
|
3847
|
+
|
|
3611
3848
|
temp.footer = (
|
|
3612
3849
|
<div className="footer-container">
|
|
3613
3850
|
<div className="card-title">
|
|
3614
3851
|
<span className="template-name" style={{ fontWeight: `${this.state.channel.toLowerCase() === 'wechat' ? '400' : '600'}` }}>
|
|
3615
3852
|
{ template && template.versions && template.versions.history && template.versions.history.length > 1 && this.state.channel.toLowerCase() !== 'mobilepush' && <i style={{fontSize: '16px', margin: '0 8px 0 0', verticalAlign: 'middle'}} className="material-icons">filter_none</i>}
|
|
3616
3853
|
{template?.name}
|
|
3854
|
+
{template.isArchived && <CapColoredTag tagColor={CAP_G08} tagTextColor={CAP_G05} className="archived-tag">{this.props.intl.formatMessage(messages.archivedTag)}</CapColoredTag>}
|
|
3617
3855
|
</span>
|
|
3618
|
-
{this.props.location.query.type !==
|
|
3856
|
+
{this.props.location.query.type !== EMBEDDED && <CapPopover
|
|
3619
3857
|
trigger="click"
|
|
3620
3858
|
content={
|
|
3621
3859
|
<div className="popover-content">
|
|
3622
|
-
{this.state.channel !== 'wechat' && <div className="popover-action-container">
|
|
3623
|
-
<
|
|
3860
|
+
{this.state.channel !== 'wechat' && !template.isArchived && <div className="popover-action-container">
|
|
3861
|
+
<CapButton type="link" onClick={() => this.duplicateTemplate(template)} className="popover-action">
|
|
3862
|
+
{this.props.intl.formatMessage(messages.duplicateButton)}
|
|
3863
|
+
</CapButton>
|
|
3864
|
+
</div>}
|
|
3865
|
+
{this.props.isFullMode && isTemplateArchiveEligible && !template.isArchived && <div className="popover-action-container">
|
|
3866
|
+
<CapButton
|
|
3867
|
+
type="link"
|
|
3868
|
+
onClick={() => this.handleTemplateArchiveAction({ templateId: template._id, templateName: template.name })}
|
|
3869
|
+
className="popover-action popover-archive-action"
|
|
3870
|
+
>
|
|
3871
|
+
<CapIcon type="archive" size="s" />
|
|
3872
|
+
<CapLabel.CapLabelInline type="label1">{this.props.intl.formatMessage(messages.archiveButton)}</CapLabel.CapLabelInline>
|
|
3873
|
+
</CapButton>
|
|
3874
|
+
</div>}
|
|
3875
|
+
{this.props.isFullMode && isTemplateArchiveEligible && template.isArchived && <div className="popover-action-container">
|
|
3876
|
+
<CapButton
|
|
3877
|
+
type="link"
|
|
3878
|
+
onClick={() => this.handleTemplateArchiveAction({ templateId: template._id, templateName: template.name, isUnarchive: true })}
|
|
3879
|
+
className="popover-action popover-archive-action"
|
|
3880
|
+
>
|
|
3881
|
+
<CapIcon type="archive" size="s" />
|
|
3882
|
+
<CapLabel.CapLabelInline type="label1">{this.props.intl.formatMessage(messages.unarchiveButton)}</CapLabel.CapLabelInline>
|
|
3883
|
+
</CapButton>
|
|
3624
3884
|
</div>}
|
|
3625
3885
|
<div className="popover-action-container">
|
|
3626
|
-
<
|
|
3886
|
+
<CapButton type="link" onClick={() => this.toggleDeleteTemplateModal(template)} className="popover-action">
|
|
3887
|
+
{deleteOption}
|
|
3888
|
+
</CapButton>
|
|
3627
3889
|
</div>
|
|
3628
3890
|
</div>
|
|
3629
3891
|
}
|
|
@@ -3676,7 +3938,27 @@ return (<div>
|
|
|
3676
3938
|
return false;
|
|
3677
3939
|
}
|
|
3678
3940
|
}
|
|
3679
|
-
isFullMode = () => this.props.location.query.type !==
|
|
3941
|
+
isFullMode = () => this.props.location.query.type !== EMBEDDED || this.props.isFullMode
|
|
3942
|
+
|
|
3943
|
+
isChannelArchiveEligible = (channel, whatsappStatus, rcsStatus) => (
|
|
3944
|
+
channel !== ZALO &&
|
|
3945
|
+
!(channel === WHATSAPP && [WHATSAPP_STATUSES.awaitingApproval, WHATSAPP_STATUSES.pending, WHATSAPP_STATUSES.unsubmitted].includes(whatsappStatus)) &&
|
|
3946
|
+
!(channel === RCS && [RCS_STATUSES.awaitingApproval, RCS_STATUSES.pending].includes(rcsStatus))
|
|
3947
|
+
)
|
|
3948
|
+
|
|
3949
|
+
enterArchivedMode = () => {
|
|
3950
|
+
this.props.actions.setArchivedMode(true);
|
|
3951
|
+
this.setState({ searchText: '', page: 1 }, () => {
|
|
3952
|
+
this.getAllTemplates({ params: { name: '', sortBy: this.state.sortBy, archiveStatus: 'archived' }, resetPage: true }, true);
|
|
3953
|
+
});
|
|
3954
|
+
}
|
|
3955
|
+
|
|
3956
|
+
exitArchivedMode = () => {
|
|
3957
|
+
this.props.actions.setArchivedMode(false);
|
|
3958
|
+
this.setState({ searchText: '', page: 1 }, () => {
|
|
3959
|
+
this.getAllTemplates({ params: { name: '', sortBy: this.state.sortBy, archiveStatus: 'active' }, resetPage: true }, true);
|
|
3960
|
+
});
|
|
3961
|
+
}
|
|
3680
3962
|
isCreateDisabled = () => {
|
|
3681
3963
|
let isDisabled = this.isLoading();
|
|
3682
3964
|
const channel = this.state.channel.toUpperCase();
|
|
@@ -4214,11 +4496,16 @@ return (<div>
|
|
|
4214
4496
|
if (([WHATSAPP_LOWERCASE, ZALO_LOWERCASE, RCS_LOWERCASE].includes(this.state?.channel?.toLocaleLowerCase()) && isEmpty(this.state?.hostName))) {
|
|
4215
4497
|
isfilterContentVisisble = false;
|
|
4216
4498
|
}
|
|
4499
|
+
const _isArchivedMode = get(this.props, 'Templates.isArchivedMode', false);
|
|
4500
|
+
const _renderSelectedIds = get(this.props, 'Templates.selectedTemplateIds', []);
|
|
4501
|
+
const _renderSelectedIdsArray = _renderSelectedIds && typeof _renderSelectedIds.toJS === 'function' ? _renderSelectedIds.toJS() : (Array.isArray(_renderSelectedIds) ? _renderSelectedIds : []);
|
|
4502
|
+
const _renderHasSelection = this.props.isFullMode && _renderSelectedIdsArray.length > 0;
|
|
4503
|
+
|
|
4217
4504
|
const filterContent = (( isfilterContentVisisble || [WECHAT, MOBILE_PUSH, INAPP].includes(this.state.channel.toUpperCase())) && <div className="action-container">
|
|
4218
4505
|
{isfilterContentVisisble && <CapInput.Search
|
|
4219
4506
|
className="search-text"
|
|
4220
4507
|
style={{width: '210px'}}
|
|
4221
|
-
placeholder={this.props.intl.formatMessage(messages.searchText)}
|
|
4508
|
+
placeholder={_isArchivedMode ? this.props.intl.formatMessage(messages.searchArchivedTemplates) : this.props.intl.formatMessage(messages.searchText)}
|
|
4222
4509
|
value={this.state.searchText}
|
|
4223
4510
|
onChange={(e) => this.searchTemplate(e.target.value, this.state.channel)}
|
|
4224
4511
|
disabled={this.checkSearchDisabled()}
|
|
@@ -4370,9 +4657,9 @@ return (<div>
|
|
|
4370
4657
|
</div>
|
|
4371
4658
|
)
|
|
4372
4659
|
}
|
|
4373
|
-
<div
|
|
4374
|
-
{
|
|
4375
|
-
this.state?.channel?.toLowerCase() === WHATSAPP_LOWERCASE && (isWhatsappCountExeeded)? (
|
|
4660
|
+
<div className="template-listing-header-actions">
|
|
4661
|
+
{!_isArchivedMode && !_renderHasSelection && (
|
|
4662
|
+
this.state?.channel?.toLowerCase() === WHATSAPP_LOWERCASE && (isWhatsappCountExeeded) ? (
|
|
4376
4663
|
<CapTooltip title={whatsappCountExceedText}>
|
|
4377
4664
|
<div className="button-disabled-tooltip-wrapper">
|
|
4378
4665
|
{createButton}
|
|
@@ -4380,9 +4667,29 @@ return (<div>
|
|
|
4380
4667
|
</CapTooltip>
|
|
4381
4668
|
)
|
|
4382
4669
|
: isfilterContentVisisble && !isWechatEmbedded && !this.props.isDltFromRcs && createButton
|
|
4383
|
-
}
|
|
4670
|
+
)}
|
|
4671
|
+
{/* More (⋯) menu: full mode only, not archived mode, not Zalo (no archive support), not when selection active */}
|
|
4672
|
+
{!_isArchivedMode && !_renderHasSelection && this.props.isFullMode && this.props.location.query.type !== EMBEDDED && channelLowerCase !== ZALO_LOWERCASE && (
|
|
4673
|
+
<CapDropdown
|
|
4674
|
+
trigger={['click']}
|
|
4675
|
+
overlay={
|
|
4676
|
+
<CapMenu>
|
|
4677
|
+
<CapMenu.Item
|
|
4678
|
+
key="archived"
|
|
4679
|
+
onClick={this.enterArchivedMode}
|
|
4680
|
+
>
|
|
4681
|
+
<FormattedMessage {...messages.archivedTemplates} />
|
|
4682
|
+
</CapMenu.Item>
|
|
4683
|
+
</CapMenu>
|
|
4684
|
+
}
|
|
4685
|
+
placement="bottomRight"
|
|
4686
|
+
>
|
|
4687
|
+
<CapButton type="flat" className="template-listing-more-btn">
|
|
4688
|
+
<CapIcon type="more" />
|
|
4689
|
+
</CapButton>
|
|
4690
|
+
</CapDropdown>
|
|
4691
|
+
)}
|
|
4384
4692
|
</div>
|
|
4385
|
-
|
|
4386
4693
|
</div>);
|
|
4387
4694
|
let htmlPreviewContent = "";
|
|
4388
4695
|
if (this.state.channel.toLowerCase() === 'ebill') {
|
|
@@ -4420,6 +4727,7 @@ return (<div>
|
|
|
4420
4727
|
className={`creatives-templates-list ${
|
|
4421
4728
|
this.props.isFullMode ? "full-mode" : "library-mode"
|
|
4422
4729
|
}`}
|
|
4730
|
+
style={{ position: 'relative' }}
|
|
4423
4731
|
>
|
|
4424
4732
|
<input
|
|
4425
4733
|
type="file"
|
|
@@ -4431,6 +4739,18 @@ return (<div>
|
|
|
4431
4739
|
}
|
|
4432
4740
|
/>
|
|
4433
4741
|
|
|
4742
|
+
{/* Archived mode header with back arrow (full mode only) */}
|
|
4743
|
+
{this.props.isFullMode && get(this.props, 'Templates.isArchivedMode', false) && (
|
|
4744
|
+
<CapRow type="flex" align="middle" className="archived-mode-header">
|
|
4745
|
+
<CapIcon
|
|
4746
|
+
type="back"
|
|
4747
|
+
className="archived-mode-back-icon"
|
|
4748
|
+
onClick={this.exitArchivedMode}
|
|
4749
|
+
/>
|
|
4750
|
+
<CapHeading type="h3"><FormattedMessage {...messages.archivedTemplates} /></CapHeading>
|
|
4751
|
+
</CapRow>
|
|
4752
|
+
)}
|
|
4753
|
+
|
|
4434
4754
|
{channel.toLowerCase() === WHATSAPP_LOWERCASE &&
|
|
4435
4755
|
showWhatsappCountWarning ? (
|
|
4436
4756
|
<CapAlert message={whatsappCountExceedText} type="info" />
|