@capillarytech/creatives-library 8.0.353-alpha.5 → 8.0.353-alpha.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.
- package/constants/unified.js +29 -0
- package/package.json +1 -1
- package/services/tests/api.test.js +35 -20
- package/utils/commonUtils.js +19 -1
- package/utils/rcsPayloadUtils.js +92 -0
- package/utils/templateVarUtils.js +201 -0
- package/utils/tests/rcsPayloadUtils.test.js +226 -0
- package/utils/tests/templateVarUtils.test.js +204 -0
- package/v2Components/CapActionButton/constants.js +7 -0
- package/v2Components/CapActionButton/index.js +166 -108
- package/v2Components/CapActionButton/index.scss +157 -6
- package/v2Components/CapActionButton/messages.js +19 -3
- package/v2Components/CapActionButton/tests/index.test.js +41 -17
- package/v2Components/CapTagList/index.js +10 -0
- package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +72 -49
- package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +8 -2
- package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +213 -21
- package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +16 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +85 -10
- package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +30 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +79 -11
- package/v2Components/CommonTestAndPreview/SendTestMessage.js +10 -5
- package/v2Components/CommonTestAndPreview/UnifiedPreview/PreviewHeader.js +0 -17
- package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +157 -15
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +346 -146
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +138 -48
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +11 -0
- package/v2Components/CommonTestAndPreview/constants.js +38 -4
- package/v2Components/CommonTestAndPreview/index.js +691 -235
- package/v2Components/CommonTestAndPreview/messages.js +45 -3
- package/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
- package/v2Components/CommonTestAndPreview/sagas.js +25 -6
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +308 -284
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +231 -65
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +118 -5
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +341 -0
- package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +8 -1
- package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +34 -13
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/PreviewHeader.test.js +0 -159
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +281 -283
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +199 -256
- package/v2Components/CommonTestAndPreview/tests/constants.test.js +1 -2
- package/v2Components/CommonTestAndPreview/tests/index.test.js +132 -198
- package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +36 -26
- package/v2Components/FormBuilder/index.js +11 -6
- package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +91 -0
- package/v2Components/SmsFallback/constants.js +73 -0
- package/v2Components/SmsFallback/index.js +956 -0
- package/v2Components/SmsFallback/index.scss +265 -0
- package/v2Components/SmsFallback/messages.js +78 -0
- package/v2Components/SmsFallback/smsFallbackUtils.js +119 -0
- package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +50 -0
- package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +147 -0
- package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +304 -0
- package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +223 -0
- package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +309 -0
- package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +422 -0
- package/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
- package/v2Components/TemplatePreview/_templatePreview.scss +38 -23
- package/v2Components/TemplatePreview/constants.js +2 -0
- package/v2Components/TemplatePreview/index.js +143 -31
- package/v2Components/TemplatePreview/tests/index.test.js +142 -0
- package/v2Components/TestAndPreviewSlidebox/index.js +15 -3
- package/v2Components/TestAndPreviewSlidebox/sagas.js +11 -4
- package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +3 -1
- package/v2Components/VarSegmentMessageEditor/constants.js +2 -0
- package/v2Components/VarSegmentMessageEditor/index.js +125 -0
- package/v2Components/VarSegmentMessageEditor/index.scss +46 -0
- package/v2Containers/App/constants.js +0 -3
- package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +43 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +36 -4
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +10 -1
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +29 -4
- package/v2Containers/CreativesContainer/constants.js +9 -0
- package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +79 -0
- package/v2Containers/CreativesContainer/index.js +322 -103
- package/v2Containers/CreativesContainer/index.scss +51 -1
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +78 -34
- package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +79 -16
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +8 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +357 -98
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +20 -15
- package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
- package/v2Containers/CreativesContainer/tests/index.test.js +71 -9
- package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +125 -0
- package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
- package/v2Containers/Rcs/constants.js +119 -10
- package/v2Containers/Rcs/index.js +2445 -813
- package/v2Containers/Rcs/index.scss +280 -8
- package/v2Containers/Rcs/messages.js +34 -3
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +225 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +98018 -70073
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +0 -5
- package/v2Containers/Rcs/tests/index.test.js +152 -121
- package/v2Containers/Rcs/tests/mockData.js +38 -0
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +318 -0
- package/v2Containers/Rcs/tests/utils.test.js +646 -30
- package/v2Containers/Rcs/utils.js +478 -11
- package/v2Containers/Sms/Create/index.js +106 -40
- package/v2Containers/Sms/smsFormDataHelpers.js +67 -0
- package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +253 -0
- package/v2Containers/SmsTrai/Create/index.js +9 -4
- package/v2Containers/SmsTrai/Edit/constants.js +2 -0
- package/v2Containers/SmsTrai/Edit/index.js +640 -130
- package/v2Containers/SmsTrai/Edit/index.scss +121 -0
- package/v2Containers/SmsTrai/Edit/messages.js +14 -4
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4328 -2375
- package/v2Containers/SmsWrapper/index.js +37 -8
- package/v2Containers/TagList/index.js +6 -0
- package/v2Containers/Templates/TemplatesActionBar.js +101 -0
- package/v2Containers/Templates/_templates.scss +166 -9
- package/v2Containers/Templates/actions.js +11 -0
- package/v2Containers/Templates/constants.js +2 -0
- package/v2Containers/Templates/index.js +122 -120
- package/v2Containers/Templates/sagas.js +56 -12
- package/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1062 -1017
- package/v2Containers/Templates/tests/sagas.test.js +199 -16
- package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +180 -0
- package/v2Containers/Templates/utils/smsTemplatesListApi.js +79 -0
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +72 -1
- package/v2Containers/TemplatesV2/index.js +86 -23
- package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +131 -0
- package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
- package/v2Containers/WebPush/Create/index.js +8 -91
- package/v2Containers/WebPush/Create/index.scss +0 -7
- package/v2Containers/Whatsapp/index.js +3 -20
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +578 -34
- package/v2Components/CommonTestAndPreview/UnifiedPreview/WebPushPreviewContent.js +0 -169
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/WebPushPreviewContent.test.js +0 -522
- package/v2Containers/App/tests/constants.test.js +0 -61
- package/v2Containers/Templates/tests/webpush.test.js +0 -375
- package/v2Containers/WebPush/Create/tests/getTemplateContent.test.js +0 -338
- package/v2Containers/WebPush/Create/tests/testAndPreviewIntegration.test.js +0 -325
|
@@ -104,9 +104,6 @@ import {
|
|
|
104
104
|
VIBER as VIBER_CHANNEL,
|
|
105
105
|
FACEBOOK as FACEBOOK_CHANNEL,
|
|
106
106
|
CREATE,
|
|
107
|
-
EXTERNAL_URL,
|
|
108
|
-
URL,
|
|
109
|
-
SITE_URL,
|
|
110
107
|
} from '../App/constants';
|
|
111
108
|
import {MAX_WHATSAPP_TEMPLATES, WARNING_WHATSAPP_TEMPLATES , ACCOUNT_MAPPING_ON_CHANNEL, noFilteredWhatsappZaloTemplatesTitle, noFilteredWhatsappZaloTemplatesDesc, noApprovedWhatsappZaloTemplatesTitle, noApprovedWhatsappTemplatesDesc, zaloDescIllustration, noApprovedRcsTemplatesTitle, noApprovedRcsTemplatesDesc, ARCHIVE_STATUS_ACTIVE, ARCHIVE_STATUS_ARCHIVED, ARCHIVE_REFRESH_TYPE_ARCHIVE, ARCHIVE_REFRESH_TYPE_UNARCHIVE} from './constants';
|
|
112
109
|
import { COPY_OF, EMBEDDED } from '../../constants/unified';
|
|
@@ -125,7 +122,7 @@ import { INAPP_LAYOUT_DETAILS, INAPP_MESSAGE_LAYOUT_TYPES } from '../InApp/const
|
|
|
125
122
|
import { ZALO_STATUS_OPTIONS, ZALO_STATUSES } from '../Zalo/constants';
|
|
126
123
|
import { getWhatsappContent, getWhatsappStatus, getWhatsappCategory, getWhatsappCta, getWhatsappQuickReply, getWhatsappAutoFill, getWhatsappCarouselButtonView } from '../Whatsapp/utils';
|
|
127
124
|
import { getRCSContent } from '../Rcs/utils';
|
|
128
|
-
import {RCS_STATUSES} from '../Rcs/constants';
|
|
125
|
+
import { RCS_STATUSES, HOST_INFOBIP } from '../Rcs/constants';
|
|
129
126
|
import zaloMessages from '../Zalo/messages';
|
|
130
127
|
import rcsMessages from '../Rcs/messages';
|
|
131
128
|
import inAppMessages from '../InApp/messages';
|
|
@@ -463,7 +460,13 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
463
460
|
if (this.props.location.query.type === 'embedded') {
|
|
464
461
|
this.props.actions.resetAccount();
|
|
465
462
|
}
|
|
466
|
-
|
|
463
|
+
// When using local templates (e.g. SMS fallback selector), do not fetch from API or we overwrite global store and break background RCS list
|
|
464
|
+
const useLocalTemplates = get(
|
|
465
|
+
this.props,
|
|
466
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
467
|
+
get(this.props, 'useLocalTemplates', false),
|
|
468
|
+
);
|
|
469
|
+
if (!useLocalTemplates && ['line', VIBER_CHANNEL, FACEBOOK_CHANNEL, 'sms', 'email', 'ebill'].includes((this.state.channel || '').toLowerCase())) {
|
|
467
470
|
const queryParams = {
|
|
468
471
|
// name: this.state.searchText,
|
|
469
472
|
// sortBy: this.state.sortBy,
|
|
@@ -1009,8 +1012,16 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
1009
1012
|
|
|
1010
1013
|
componentWillUnmount() {
|
|
1011
1014
|
window.removeEventListener("message", this.handleFrameTasks);
|
|
1012
|
-
|
|
1013
|
-
|
|
1015
|
+
// When using local templates (e.g. SMS fallback selector), do not clear global store or background RCS list is wiped
|
|
1016
|
+
const useLocalTemplates = get(
|
|
1017
|
+
this.props,
|
|
1018
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
1019
|
+
get(this.props, 'useLocalTemplates', false),
|
|
1020
|
+
);
|
|
1021
|
+
if (!useLocalTemplates) {
|
|
1022
|
+
this.props.actions.resetTemplateStoreData();
|
|
1023
|
+
this.props.globalActions.clearMetaEntities();
|
|
1024
|
+
}
|
|
1014
1025
|
// Clear any pending timeouts to prevent memory leaks
|
|
1015
1026
|
if (this._clearEditTimeout) {
|
|
1016
1027
|
clearTimeout(this._clearEditTimeout);
|
|
@@ -1402,69 +1413,6 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
1402
1413
|
};
|
|
1403
1414
|
}
|
|
1404
1415
|
|
|
1405
|
-
case WEBPUSH: {
|
|
1406
|
-
// WebPush content is stored in creatives format (brandIcon, onClickAction, ctas)
|
|
1407
|
-
// Must be transformed to campaign/test-message format matching getTemplateContent() in WebPush/Create/index.js
|
|
1408
|
-
const webpushContent = get(baseContent, 'content.webpush', {});
|
|
1409
|
-
const title = webpushContent?.title || '';
|
|
1410
|
-
const message = webpushContent?.message || '';
|
|
1411
|
-
const accountId = get(template, 'definition.accountId', null);
|
|
1412
|
-
const templateName = template?.name || '';
|
|
1413
|
-
|
|
1414
|
-
// iconImageUrl stored as brandIcon in creatives format
|
|
1415
|
-
const iconImageUrl = webpushContent?.brandIcon || webpushContent?.iconImageUrl || undefined;
|
|
1416
|
-
|
|
1417
|
-
// cta stored as onClickAction in creatives format (type: URL|SITE_URL, url)
|
|
1418
|
-
// or already as cta in campaign format (type: EXTERNAL_URL|SITE_URL, actionLink)
|
|
1419
|
-
let cta = null;
|
|
1420
|
-
const onClickAction = webpushContent?.onClickAction;
|
|
1421
|
-
const existingCta = webpushContent?.cta;
|
|
1422
|
-
if (onClickAction) {
|
|
1423
|
-
const ctaType = onClickAction.type === URL ? EXTERNAL_URL : (onClickAction.type || SITE_URL);
|
|
1424
|
-
cta = { type: ctaType, actionLink: onClickAction.url || '' };
|
|
1425
|
-
} else if (existingCta) {
|
|
1426
|
-
cta = { type: existingCta.type || EXTERNAL_URL, actionLink: existingCta.actionLink || '' };
|
|
1427
|
-
}
|
|
1428
|
-
|
|
1429
|
-
// expandableDetails: image → media[], ctas[] → mapped ctas
|
|
1430
|
-
const image = webpushContent?.image;
|
|
1431
|
-
const rawCtas = webpushContent?.ctas;
|
|
1432
|
-
const existingExpandable = webpushContent?.expandableDetails;
|
|
1433
|
-
let expandableDetails = null;
|
|
1434
|
-
const hasImage = !!image;
|
|
1435
|
-
const hasCtas = Array.isArray(rawCtas) && rawCtas.length > 0;
|
|
1436
|
-
if (hasImage || hasCtas) {
|
|
1437
|
-
expandableDetails = {
|
|
1438
|
-
media: hasImage ? [{ url: image, type: IMAGE }] : [],
|
|
1439
|
-
ctas: hasCtas ? rawCtas.map((ctaItem) => ({
|
|
1440
|
-
type: ctaItem?.type === URL ? EXTERNAL_URL : (ctaItem?.type || EXTERNAL_URL),
|
|
1441
|
-
action: ctaItem?.action || '',
|
|
1442
|
-
title: ctaItem?.actionText || ctaItem?.title || '',
|
|
1443
|
-
actionLink: ctaItem?.actionLink || '',
|
|
1444
|
-
})) : [],
|
|
1445
|
-
};
|
|
1446
|
-
} else if (existingExpandable) {
|
|
1447
|
-
expandableDetails = {
|
|
1448
|
-
media: existingExpandable?.media || [],
|
|
1449
|
-
ctas: existingExpandable?.ctas || [],
|
|
1450
|
-
};
|
|
1451
|
-
}
|
|
1452
|
-
|
|
1453
|
-
return {
|
|
1454
|
-
channel: WEBPUSH,
|
|
1455
|
-
accountId,
|
|
1456
|
-
content: {
|
|
1457
|
-
title,
|
|
1458
|
-
message,
|
|
1459
|
-
...(iconImageUrl ? { iconImageUrl } : {}),
|
|
1460
|
-
...(cta ? { cta } : {}),
|
|
1461
|
-
...(expandableDetails ? { expandableDetails } : {}),
|
|
1462
|
-
},
|
|
1463
|
-
messageSubject: templateName || title,
|
|
1464
|
-
offers: [],
|
|
1465
|
-
};
|
|
1466
|
-
}
|
|
1467
|
-
|
|
1468
1416
|
default:
|
|
1469
1417
|
console.warn(`Unsupported channel for content extraction: ${channelUpper}`);
|
|
1470
1418
|
return null;
|
|
@@ -1477,7 +1425,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
1477
1425
|
* @returns {Boolean} - True if channel supports Test and Preview
|
|
1478
1426
|
*/
|
|
1479
1427
|
isTestAndPreviewSupported = () => {
|
|
1480
|
-
const supportedChannels = [EMAIL, SMS, INAPP, MOBILE_PUSH, VIBER, ZALO
|
|
1428
|
+
const supportedChannels = [EMAIL, SMS, INAPP, MOBILE_PUSH, VIBER, ZALO];
|
|
1481
1429
|
return supportedChannels.includes(this.state.channel.toUpperCase());
|
|
1482
1430
|
}
|
|
1483
1431
|
|
|
@@ -1863,12 +1811,20 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
1863
1811
|
}
|
|
1864
1812
|
|
|
1865
1813
|
filterRcsTemplates = (templates) => {
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1814
|
+
const selectedRcsAccountName = this.props?.Templates?.selectedRcsAccount?.name || '';
|
|
1815
|
+
const hostName = this.state?.hostName;
|
|
1816
|
+
let nextTemplates = templates || [];
|
|
1817
|
+
if (selectedRcsAccountName) {
|
|
1818
|
+
nextTemplates = nextTemplates.filter(
|
|
1819
|
+
(t) => get(t, 'versions.base.content.RCS.rcsContent.accountName', '') === selectedRcsAccountName
|
|
1820
|
+
);
|
|
1870
1821
|
}
|
|
1871
|
-
|
|
1822
|
+
if (!this.props.isFullMode && hostName !== HOST_INFOBIP) {
|
|
1823
|
+
return nextTemplates.filter(
|
|
1824
|
+
(t) => get(t, 'versions.base.content.RCS.rcsContent.cardContent[0].Status', 'unavailable') === RCS_STATUSES.approved
|
|
1825
|
+
);
|
|
1826
|
+
}
|
|
1827
|
+
return nextTemplates;
|
|
1872
1828
|
}
|
|
1873
1829
|
|
|
1874
1830
|
filterZaloTemplates = (templates) => {
|
|
@@ -2037,7 +1993,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
2037
1993
|
// Show preview icon only for channels that don't support Test and Preview
|
|
2038
1994
|
(() => {
|
|
2039
1995
|
// Channels that have Test and Preview integrated
|
|
2040
|
-
const testAndPreviewChannels = [EMAIL, SMS, WHATSAPP, RCS, INAPP, MOBILE_PUSH, VIBER, ZALO
|
|
1996
|
+
const testAndPreviewChannels = [EMAIL, SMS, WHATSAPP, RCS, INAPP, MOBILE_PUSH, VIBER, ZALO];
|
|
2041
1997
|
const isTestAndPreviewSupported = testAndPreviewChannels.includes(currentChannel.toUpperCase());
|
|
2042
1998
|
|
|
2043
1999
|
// Don't show preview icon if channel supports Test and Preview
|
|
@@ -2058,7 +2014,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
2058
2014
|
style={{ marginRight: "16px" }}
|
|
2059
2015
|
type="eye"
|
|
2060
2016
|
onClick={() => {
|
|
2061
|
-
if (!this.props.isFullMode || this.props.isDltFromRcs) {
|
|
2017
|
+
if (!this.props.isFullMode || this.props.isDltFromRcs || this.props.isSmsFallbackFromRcs) {
|
|
2062
2018
|
if (!get(template, "versions.base.content.zalo.previewUrl", "")) {
|
|
2063
2019
|
this.setState({ zaloPreviewItemId: template?._id });
|
|
2064
2020
|
}
|
|
@@ -2540,13 +2496,14 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
2540
2496
|
<CapRow type="flex" align="middle">
|
|
2541
2497
|
{isCardArchiveEligible && this.renderCardSelectionCheckbox({ templateId: template._id, selectedIds: selectedIdsArrayForCard, isDisabled: isAnyArchiveInProgress })}
|
|
2542
2498
|
<CapLabel className="whatsapp-rcs-template-name">{name}</CapLabel>
|
|
2543
|
-
<CapRow type="flex" align="middle" className="rcs-status-container zalo-status-color">
|
|
2499
|
+
{this.state.hostName !== HOST_INFOBIP && <CapRow type="flex" align="middle" className="rcs-status-container zalo-status-color">
|
|
2544
2500
|
<CapStatus
|
|
2545
2501
|
type={statusDisplay}
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2502
|
+
text={statusDisplay && this.props.intl.formatMessage(rcsMessages?.[`${statusDisplay}_STATUS`])}
|
|
2503
|
+
labelType="label3"
|
|
2504
|
+
/>
|
|
2505
|
+
</CapRow>
|
|
2506
|
+
}
|
|
2550
2507
|
</CapRow>
|
|
2551
2508
|
);
|
|
2552
2509
|
|
|
@@ -3122,6 +3079,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
3122
3079
|
let routeParams = {};
|
|
3123
3080
|
const {fbAdManager} = this.props;
|
|
3124
3081
|
const isLibraryMode = this.isEnabledInLibraryModule("callCreateFromProps");
|
|
3082
|
+
|
|
3125
3083
|
if (!isLibraryMode) {
|
|
3126
3084
|
timeTracker.startTimer(CHANNEL_CREATE_TRACK_MAPPING[channel]);
|
|
3127
3085
|
}
|
|
@@ -3471,6 +3429,13 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
3471
3429
|
this.setState({modeType});
|
|
3472
3430
|
}
|
|
3473
3431
|
const { _id: id } = template;
|
|
3432
|
+
const {
|
|
3433
|
+
localTemplatesConfig,
|
|
3434
|
+
fbAdManager,
|
|
3435
|
+
isDltFromRcs,
|
|
3436
|
+
isSmsFallbackFromRcs,
|
|
3437
|
+
onSelectTemplate,
|
|
3438
|
+
} = this.props;
|
|
3474
3439
|
const type = this.props.location.query.type;
|
|
3475
3440
|
const module = this.props.location.query.module;
|
|
3476
3441
|
const isLanguageSupport = (this.props.location.query.isLanguageSupport) ? this.props.location.query.isLanguageSupport : false;
|
|
@@ -3556,10 +3521,12 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
3556
3521
|
}
|
|
3557
3522
|
if (this.isEnabledInLibraryModule("callSelectFromProps")) {
|
|
3558
3523
|
let data = id;
|
|
3559
|
-
if (
|
|
3524
|
+
if (localTemplatesConfig?.useLocalTemplates) {
|
|
3525
|
+
data = template;
|
|
3526
|
+
} else if (fbAdManager || isDltFromRcs || isSmsFallbackFromRcs) {
|
|
3560
3527
|
data = this.selectTemplate(id);
|
|
3561
3528
|
}
|
|
3562
|
-
|
|
3529
|
+
onSelectTemplate(data, fbAdManager);
|
|
3563
3530
|
} else {
|
|
3564
3531
|
timeTracker.startTimer(CHANNEL_EDIT_TRACK_MAPPING[this.state.channel.toLowerCase()]);
|
|
3565
3532
|
if (this.state.channel.toLowerCase() === 'ebill') {
|
|
@@ -4518,9 +4485,14 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
4518
4485
|
const isWechatEmbedded = !this.props.isFullMode && channel.toUpperCase() === WECHAT;
|
|
4519
4486
|
const channelLowerCase = (channel || '').toLowerCase();
|
|
4520
4487
|
const isTraiDltFeature = this.checkDLTfeatureEnable();
|
|
4521
|
-
|
|
4522
4488
|
const createButton =
|
|
4523
|
-
(
|
|
4489
|
+
(
|
|
4490
|
+
(
|
|
4491
|
+
channelLowerCase === WHATSAPP_LOWERCASE
|
|
4492
|
+
|| channelLowerCase === RCS_LOWERCASE
|
|
4493
|
+
)
|
|
4494
|
+
&& !this.props.isFullMode
|
|
4495
|
+
)
|
|
4524
4496
|
? (
|
|
4525
4497
|
<CapLink
|
|
4526
4498
|
onClick={this.openCreativesFullMode}
|
|
@@ -4552,17 +4524,22 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
4552
4524
|
const _renderSelectedIdsArray = _renderSelectedIds && typeof _renderSelectedIds.toJS === 'function' ? _renderSelectedIds.toJS() : (Array.isArray(_renderSelectedIds) ? _renderSelectedIds : []);
|
|
4553
4525
|
const _renderHasSelection = _isArchivalEnabled && this.props.isFullMode && _renderSelectedIdsArray.length > 0;
|
|
4554
4526
|
|
|
4555
|
-
const
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4527
|
+
const useLocalTemplates = this.props.localTemplatesConfig?.useLocalTemplates;
|
|
4528
|
+
const builtFilterContent = ((isfilterContentVisisble || [WECHAT, MOBILE_PUSH, INAPP].includes(this.state.channel.toUpperCase())) && (
|
|
4529
|
+
<div className="action-container">
|
|
4530
|
+
<div className="action-container__toolbar-row">
|
|
4531
|
+
{isfilterContentVisisble ? (
|
|
4532
|
+
<CapInput.Search
|
|
4533
|
+
className="search-text"
|
|
4534
|
+
placeholder={this.props.intl.formatMessage(messages.searchText)}
|
|
4535
|
+
value={this.state.searchText}
|
|
4536
|
+
onChange={(e) => this.searchTemplate(e.target.value, this.state.channel)}
|
|
4537
|
+
onSearch={() => this.searchTemplate(this.state.searchText, this.state.channel)}
|
|
4538
|
+
onClear={() => this.searchTemplate('', this.state.channel)}
|
|
4539
|
+
onScroll={(e) => e.stopPropagation()}
|
|
4540
|
+
disabled={this.checkSearchDisabled()}
|
|
4541
|
+
/>
|
|
4542
|
+
) : null}
|
|
4566
4543
|
{
|
|
4567
4544
|
channel.toUpperCase() === WECHAT && <CapRadio.CapRadioGroup className="wechat-filters" defaultValue={wechatFilter} onChange={this.setWechatFilter}>
|
|
4568
4545
|
<CapRadio.Button value={WECHAT_FILTERS.ALL}><CapLabel type="label2">
|
|
@@ -4709,16 +4686,6 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
4709
4686
|
)
|
|
4710
4687
|
}
|
|
4711
4688
|
<div className="template-listing-header-actions">
|
|
4712
|
-
{!_isArchivedMode && !_renderHasSelection && (
|
|
4713
|
-
this.state?.channel?.toLowerCase() === WHATSAPP_LOWERCASE && (isWhatsappCountExeeded) ? (
|
|
4714
|
-
<CapTooltip title={whatsappCountExceedText}>
|
|
4715
|
-
<div className="button-disabled-tooltip-wrapper">
|
|
4716
|
-
{createButton}
|
|
4717
|
-
</div>
|
|
4718
|
-
</CapTooltip>
|
|
4719
|
-
)
|
|
4720
|
-
: isfilterContentVisisble && !isWechatEmbedded && !this.props.isDltFromRcs && createButton
|
|
4721
|
-
)}
|
|
4722
4689
|
{/* More (⋯) menu: full mode only, not archived mode, not Zalo (no archive support), not when selection active, archive flag enabled */}
|
|
4723
4690
|
{commonUtil.hasCreativesArchivalEnabled() && !_isArchivedMode && !_renderHasSelection && this.props.isFullMode && this.props.location.query.type !== EMBEDDED && channelLowerCase !== ZALO_LOWERCASE && (
|
|
4724
4691
|
<CapDropdown
|
|
@@ -4741,7 +4708,28 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
4741
4708
|
</CapDropdown>
|
|
4742
4709
|
)}
|
|
4743
4710
|
</div>
|
|
4744
|
-
</div>
|
|
4711
|
+
</div>
|
|
4712
|
+
<div>
|
|
4713
|
+
<div className="action-container__create-row">
|
|
4714
|
+
{
|
|
4715
|
+
isfilterContentVisisble && !isWechatEmbedded && !this.props.isDltFromRcs && !this.props.isSmsFallbackFromRcs && (
|
|
4716
|
+
this.state?.channel?.toLowerCase() === WHATSAPP_LOWERCASE && isWhatsappCountExeeded ? (
|
|
4717
|
+
<CapTooltip title={whatsappCountExceedText}>
|
|
4718
|
+
<div className="button-disabled-tooltip-wrapper">
|
|
4719
|
+
{createButton}
|
|
4720
|
+
</div>
|
|
4721
|
+
</CapTooltip>
|
|
4722
|
+
) : createButton
|
|
4723
|
+
)
|
|
4724
|
+
}
|
|
4725
|
+
</div>
|
|
4726
|
+
</div>
|
|
4727
|
+
</div>
|
|
4728
|
+
));
|
|
4729
|
+
const localTemplatesFilterContent = get(this.props, 'localTemplatesConfig.localTemplatesFilterContent', null);
|
|
4730
|
+
const filterContent = (useLocalTemplates && localTemplatesFilterContent) != null
|
|
4731
|
+
? localTemplatesFilterContent
|
|
4732
|
+
: builtFilterContent;
|
|
4745
4733
|
let htmlPreviewContent = "";
|
|
4746
4734
|
if (this.state.channel.toLowerCase() === 'ebill') {
|
|
4747
4735
|
htmlPreviewContent = this.state.previewTemplate && this.state.previewTemplate.versions && this.state.previewTemplate.versions.base && this.state.previewTemplate.versions.base['ebill-editor'];
|
|
@@ -4751,7 +4739,10 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
4751
4739
|
|
|
4752
4740
|
|
|
4753
4741
|
const creativesParams = this.getCreativesParams();
|
|
4754
|
-
const templates =
|
|
4742
|
+
const templates = useLocalTemplates
|
|
4743
|
+
? (this.props.localTemplatesConfig?.localTemplates || [])
|
|
4744
|
+
: (this.props.TemplatesList || []);
|
|
4745
|
+
const isLoadingWhenLocal = useLocalTemplates && !!this.props.localTemplatesConfig?.localTemplatesLoading;
|
|
4755
4746
|
const {route} = this.props;
|
|
4756
4747
|
const loadingTipMap = {
|
|
4757
4748
|
sendingFile: 'uploadingFile',
|
|
@@ -4766,9 +4757,11 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
4766
4757
|
(deleteRcsTemplateInProgress && 'deletingTemplate') ||
|
|
4767
4758
|
(this.props.EmailCreate.duplicateTemplateInProgress && 'duplicatingTemplate');
|
|
4768
4759
|
|
|
4769
|
-
const loadingTip =
|
|
4760
|
+
const loadingTip = useLocalTemplates && this.props.localTemplatesConfig?.localTemplatesLoadingTip
|
|
4761
|
+
? this.props.localTemplatesConfig.localTemplatesLoadingTip
|
|
4762
|
+
: (messages[loadingTipIntl] ? this.props.intl.formatMessage(messages[loadingTipIntl]) : this.props.intl.formatMessage(messages.gettingAllTemplates));
|
|
4770
4763
|
const showNoTemplatesFoundZalo = this.state.channel.toUpperCase() === ZALO && isEmpty(this.state.searchedZaloTemplates) && this.state.searchingZaloTemplate;
|
|
4771
|
-
const showNoTemplatesFoundOther = ![ZALO].includes(this.state.channel.toUpperCase()) && isEmpty(
|
|
4764
|
+
const showNoTemplatesFoundOther = ![ZALO].includes(this.state.channel.toUpperCase()) && isEmpty(templates) && (useLocalTemplates ? !isLoadingWhenLocal : !this.props.Templates.getAllTemplatesInProgress) && (useLocalTemplates || !isEmpty(this.state.searchText));
|
|
4772
4765
|
const showNoTemplatesFound = showNoTemplatesFoundZalo || showNoTemplatesFoundOther;
|
|
4773
4766
|
|
|
4774
4767
|
return (
|
|
@@ -4812,7 +4805,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
4812
4805
|
/>
|
|
4813
4806
|
) : null}
|
|
4814
4807
|
|
|
4815
|
-
{channel.toLowerCase() === RCS_LOWERCASE && !isFullMode ? (
|
|
4808
|
+
{channel.toLowerCase() === RCS_LOWERCASE && !isFullMode && this.state?.hostName !== HOST_INFOBIP ? (
|
|
4816
4809
|
<CapInfoNote
|
|
4817
4810
|
message={formatMessage(messages.rcsOnlyApprovedTemplates)}
|
|
4818
4811
|
/>
|
|
@@ -4825,22 +4818,22 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
4825
4818
|
) : null}
|
|
4826
4819
|
<CapRow>
|
|
4827
4820
|
<Pagination
|
|
4828
|
-
templateInProgress={
|
|
4829
|
-
this.props.Templates.getAllTemplatesInProgress
|
|
4830
|
-
}
|
|
4821
|
+
templateInProgress={useLocalTemplates ? isLoadingWhenLocal : this.props.Templates.getAllTemplatesInProgress}
|
|
4831
4822
|
onPageChange={
|
|
4832
|
-
templates.length
|
|
4823
|
+
templates.length
|
|
4824
|
+
? (useLocalTemplates ? (this.props.localTemplatesConfig?.localTemplatesOnPageChange || (() => {})) : this.onPaginationChange)
|
|
4825
|
+
: () => {}
|
|
4833
4826
|
}
|
|
4834
4827
|
>
|
|
4835
4828
|
{this.getTemplateDataForGrid({
|
|
4836
4829
|
previewTemplateId: this.state.zaloPreviewItemId,
|
|
4837
|
-
isLoading,
|
|
4838
|
-
isInitialLoading,
|
|
4830
|
+
isLoading: useLocalTemplates ? isLoadingWhenLocal : isLoading,
|
|
4831
|
+
isInitialLoading: useLocalTemplates ? isLoadingWhenLocal && templates.length === 0 : isInitialLoading,
|
|
4839
4832
|
loadingTip,
|
|
4840
4833
|
channel: this.state.channel,
|
|
4841
4834
|
templates: this.state.searchingZaloTemplate
|
|
4842
4835
|
? this.state.searchedZaloTemplates
|
|
4843
|
-
:
|
|
4836
|
+
: templates,
|
|
4844
4837
|
filterContent,
|
|
4845
4838
|
handlers: {
|
|
4846
4839
|
handlePreviewClick: this.handlePreviewClick,
|
|
@@ -5023,6 +5016,15 @@ Templates.propTypes = {
|
|
|
5023
5016
|
WebPush: PropTypes.object,
|
|
5024
5017
|
smsRegister: PropTypes.any,
|
|
5025
5018
|
isDltFromRcs: PropTypes.bool,
|
|
5019
|
+
isSmsFallbackFromRcs: PropTypes.bool,
|
|
5020
|
+
localTemplatesConfig: PropTypes.shape({
|
|
5021
|
+
useLocalTemplates: PropTypes.bool,
|
|
5022
|
+
localTemplates: PropTypes.arrayOf(PropTypes.object),
|
|
5023
|
+
localTemplatesLoading: PropTypes.bool,
|
|
5024
|
+
localTemplatesLoadingTip: PropTypes.string,
|
|
5025
|
+
localTemplatesFilterContent: PropTypes.node,
|
|
5026
|
+
localTemplatesOnPageChange: PropTypes.func,
|
|
5027
|
+
}),
|
|
5026
5028
|
};
|
|
5027
5029
|
|
|
5028
5030
|
const mapStateToProps = createStructuredSelector({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
call, put, takeLatest, all,
|
|
2
|
+
call, put, takeLatest, takeEvery, all,
|
|
3
3
|
} from 'redux-saga/effects';
|
|
4
4
|
import get from 'lodash/get';
|
|
5
5
|
import { CapNotification } from '@capillarytech/cap-ui-library';
|
|
@@ -8,32 +8,69 @@ import * as Api from '../../services/api';
|
|
|
8
8
|
import * as types from './constants';
|
|
9
9
|
import { saveCdnConfigs, removeAllCdnLocalStorageItems } from '../../utils/cdnTransformation';
|
|
10
10
|
import { COPY_OF } from '../../constants/unified';
|
|
11
|
+
import { fetchSmsTemplatesFromQuery } from './utils/smsTemplatesListApi';
|
|
11
12
|
import { ZALO_TEMPLATE_INFO_REQUEST } from '../Zalo/constants';
|
|
12
13
|
import { getTemplateInfoById } from '../Zalo/saga';
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
export function* getAllTemplates(channel, queryParams) {
|
|
15
|
+
export function* getLocalSmsTemplates(action) {
|
|
16
16
|
try {
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
const fetched = yield call(
|
|
18
|
+
fetchSmsTemplatesFromQuery,
|
|
19
|
+
action.queryParams,
|
|
20
|
+
action.intlCopyOf,
|
|
21
|
+
);
|
|
22
|
+
if (typeof action.onSuccess === 'function') {
|
|
23
|
+
yield call(action.onSuccess, fetched);
|
|
24
|
+
}
|
|
25
|
+
} catch (error) {
|
|
26
|
+
if (typeof action.onFailure === 'function') {
|
|
27
|
+
yield call(action.onFailure, error);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function* getAllTemplates(action) {
|
|
33
|
+
try {
|
|
34
|
+
if (action.channel && String(action.channel).toLowerCase() === 'sms') {
|
|
35
|
+
const fetched = yield call(
|
|
36
|
+
fetchSmsTemplatesFromQuery,
|
|
37
|
+
action.queryParams,
|
|
38
|
+
action.intlCopyOf,
|
|
39
|
+
);
|
|
40
|
+
yield put({
|
|
41
|
+
type: types.GET_ALL_TEMPLATES_SUCCESS,
|
|
42
|
+
data: fetched.channelTemplates,
|
|
43
|
+
weCRMTemplate: fetched.weCRMTemplate,
|
|
44
|
+
isReset: get(action, 'queryParams.page') === 1,
|
|
45
|
+
});
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const result = yield call(Api.getAllTemplates, action);
|
|
50
|
+
const channelTemplates = (action.channel === 'wechat')
|
|
51
|
+
? { templates: [...result.response.mapped, ...result.response.richmedia] }
|
|
52
|
+
: result.response;
|
|
53
|
+
if (action.channel === 'wechat' && action.queryParams && action.queryParams.sortBy && action.queryParams.sortBy.toLocaleLowerCase() === ("Most Recent").toLocaleLowerCase()) {
|
|
21
54
|
channelTemplates.templates.sort((a, b) => {
|
|
22
55
|
const dateA = new Date(a.updatedAt);
|
|
23
56
|
const dateB = new Date(b.updatedAt);
|
|
24
57
|
return dateB - dateA;
|
|
25
58
|
});
|
|
26
|
-
} else if (
|
|
59
|
+
} else if (action.channel === 'wechat' && action.queryParams && action.queryParams.sortBy && action.queryParams.sortBy.toLocaleLowerCase() === ("Alphabetically").toLocaleLowerCase()) {
|
|
27
60
|
channelTemplates.templates.sort((a, b) => b.name - a.name);
|
|
28
61
|
}
|
|
29
|
-
|
|
30
|
-
if (channel.intlCopyOf && channelTemplates?.templates) {
|
|
62
|
+
if (action.intlCopyOf && channelTemplates?.templates) {
|
|
31
63
|
channelTemplates.templates = channelTemplates.templates.map((template) => ({
|
|
32
64
|
...template,
|
|
33
|
-
name: template.name.replace(new RegExp(COPY_OF, 'g'),
|
|
65
|
+
name: template.name.replace(new RegExp(COPY_OF, 'g'), action.intlCopyOf),
|
|
34
66
|
}));
|
|
35
67
|
}
|
|
36
|
-
yield put({
|
|
68
|
+
yield put({
|
|
69
|
+
type: types.GET_ALL_TEMPLATES_SUCCESS,
|
|
70
|
+
data: channelTemplates,
|
|
71
|
+
weCRMTemplate: result.response.unMapped,
|
|
72
|
+
isReset: get(action, 'queryParams.page') === 1,
|
|
73
|
+
});
|
|
37
74
|
} catch (error) {
|
|
38
75
|
yield put({ type: types.GET_ALL_TEMPLATES_FAILURE, error });
|
|
39
76
|
}
|
|
@@ -265,6 +302,11 @@ export function* watchGetAllTemplates() {
|
|
|
265
302
|
yield takeLatest(types.GET_ALL_TEMPLATES_REQUEST, getAllTemplates);
|
|
266
303
|
}
|
|
267
304
|
|
|
305
|
+
|
|
306
|
+
export function* watchGetLocalSmsTemplates() {
|
|
307
|
+
yield takeEvery(types.GET_LOCAL_SMS_TEMPLATES_REQUEST, getLocalSmsTemplates);
|
|
308
|
+
}
|
|
309
|
+
|
|
268
310
|
export function* watchDeleteTemplate() {
|
|
269
311
|
yield takeLatest(types.DELETE_TEMPLATE_REQUEST, deleteTemplate);
|
|
270
312
|
}
|
|
@@ -318,6 +360,7 @@ export function* watchForGetTemplateInfoById() {
|
|
|
318
360
|
// All sagas to be loaded
|
|
319
361
|
export default [
|
|
320
362
|
watchGetAllTemplates,
|
|
363
|
+
watchGetLocalSmsTemplates,
|
|
321
364
|
watchDeleteTemplate,
|
|
322
365
|
watchDeleteRcsTemplate,
|
|
323
366
|
watchGetUserList,
|
|
@@ -334,6 +377,7 @@ export default [
|
|
|
334
377
|
export function* v2TemplateSaga() {
|
|
335
378
|
yield all([
|
|
336
379
|
watchGetAllTemplates(),
|
|
380
|
+
watchGetLocalSmsTemplates(),
|
|
337
381
|
watchDeleteTemplate(),
|
|
338
382
|
watchDeleteRcsTemplate(),
|
|
339
383
|
watchGetUserList(),
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jest-environment jsdom
|
|
3
|
+
*/
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
6
|
+
import '@testing-library/jest-dom';
|
|
7
|
+
import TemplatesActionBar from '../TemplatesActionBar';
|
|
8
|
+
|
|
9
|
+
jest.mock('@capillarytech/cap-ui-library/CapInput', () => {
|
|
10
|
+
const React = require('react');
|
|
11
|
+
function Search(props) {
|
|
12
|
+
return React.createElement('input', {
|
|
13
|
+
'data-testid': 'cap-input-search',
|
|
14
|
+
value: props?.value,
|
|
15
|
+
placeholder: props?.placeholder,
|
|
16
|
+
onChange: props?.onChange,
|
|
17
|
+
onKeyDown: (e) => {
|
|
18
|
+
if (e.key === 'Enter' && props.onPressEnter) {
|
|
19
|
+
props.onPressEnter(e);
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function CapInput() {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
CapInput.Search = Search;
|
|
28
|
+
return { __esModule: true, default: CapInput };
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
jest.mock('@capillarytech/cap-ui-library/CapButton', () => {
|
|
32
|
+
const React = require('react');
|
|
33
|
+
return function CapButton(props) {
|
|
34
|
+
return React.createElement('button', {
|
|
35
|
+
type: 'button',
|
|
36
|
+
'data-testid': 'cta',
|
|
37
|
+
onClick: props?.onClick,
|
|
38
|
+
disabled: props?.disabled,
|
|
39
|
+
}, props?.children);
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('TemplatesActionBar', () => {
|
|
44
|
+
it('renders search when searchPlaceholder is set', () => {
|
|
45
|
+
render(
|
|
46
|
+
<TemplatesActionBar
|
|
47
|
+
searchPlaceholder="Find templates"
|
|
48
|
+
searchValue="hi"
|
|
49
|
+
ctaLabel="Create"
|
|
50
|
+
/>,
|
|
51
|
+
);
|
|
52
|
+
expect(screen.getByTestId('cap-input-search')).toHaveAttribute('placeholder', 'Find templates');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('omits search when searchPlaceholder is empty', () => {
|
|
56
|
+
const { container } = render(
|
|
57
|
+
<TemplatesActionBar searchPlaceholder="" ctaLabel="Go" />,
|
|
58
|
+
);
|
|
59
|
+
expect(container.querySelector('[data-testid="cap-input-search"]')).toBeNull();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('fires onSearchChange and onCtaClick', () => {
|
|
63
|
+
const onSearchChange = jest.fn();
|
|
64
|
+
const onCtaClick = jest.fn();
|
|
65
|
+
render(
|
|
66
|
+
<TemplatesActionBar
|
|
67
|
+
searchPlaceholder="S"
|
|
68
|
+
onSearchChange={onSearchChange}
|
|
69
|
+
ctaLabel="New"
|
|
70
|
+
onCtaClick={onCtaClick}
|
|
71
|
+
/>,
|
|
72
|
+
);
|
|
73
|
+
fireEvent.change(screen.getByTestId('cap-input-search'), { target: { value: 'x' } });
|
|
74
|
+
fireEvent.click(screen.getByTestId('cta'));
|
|
75
|
+
expect(onSearchChange).toHaveBeenCalled();
|
|
76
|
+
expect(onCtaClick).toHaveBeenCalled();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('fires onSearch when Enter is pressed (antd Input has no native onSearch)', () => {
|
|
80
|
+
const onSearch = jest.fn();
|
|
81
|
+
render(
|
|
82
|
+
<TemplatesActionBar
|
|
83
|
+
searchPlaceholder="S"
|
|
84
|
+
searchValue="query"
|
|
85
|
+
onSearch={onSearch}
|
|
86
|
+
ctaLabel="New"
|
|
87
|
+
/>,
|
|
88
|
+
);
|
|
89
|
+
const input = screen.getByTestId('cap-input-search');
|
|
90
|
+
fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' });
|
|
91
|
+
expect(onSearch).toHaveBeenCalledWith('query');
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('renders ctaNode instead of default button when provided', () => {
|
|
95
|
+
render(
|
|
96
|
+
<TemplatesActionBar
|
|
97
|
+
searchPlaceholder="S"
|
|
98
|
+
ctaNode={<span data-testid="custom-cta">Custom</span>}
|
|
99
|
+
/>,
|
|
100
|
+
);
|
|
101
|
+
expect(screen.getByTestId('custom-cta')).toBeInTheDocument();
|
|
102
|
+
expect(screen.queryByTestId('cta')).toBeNull();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('hides CTA area when showCta is false', () => {
|
|
106
|
+
const { container } = render(
|
|
107
|
+
<TemplatesActionBar searchPlaceholder="S" showCta={false} ctaLabel="X" />,
|
|
108
|
+
);
|
|
109
|
+
expect(container.querySelector('[data-testid="cta"]')).toBeNull();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('renders children in toolbar row', () => {
|
|
113
|
+
render(
|
|
114
|
+
<TemplatesActionBar searchPlaceholder="S" ctaLabel="C">
|
|
115
|
+
<span data-testid="child">extra</span>
|
|
116
|
+
</TemplatesActionBar>,
|
|
117
|
+
);
|
|
118
|
+
expect(screen.getByTestId('child')).toBeInTheDocument();
|
|
119
|
+
});
|
|
120
|
+
});
|