@capillarytech/creatives-library 9.0.14 → 9.0.15-alpha.1
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 +32 -0
- package/global-styles.js +1 -1
- package/package.json +1 -1
- package/services/tests/api.test.js +35 -20
- package/utils/common.js +8 -0
- 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 +168 -109
- package/v2Components/CapActionButton/index.scss +156 -5
- package/v2Components/CapActionButton/messages.js +19 -3
- package/v2Components/CapActionButton/tests/index.test.js +42 -18
- package/v2Components/CapImageUpload/index.js +2 -2
- package/v2Components/CapTagList/index.js +10 -0
- package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +70 -48
- package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +8 -2
- package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +214 -21
- package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +16 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +83 -9
- package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +30 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +60 -11
- package/v2Components/CommonTestAndPreview/SendTestMessage.js +10 -5
- package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +201 -23
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +355 -76
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +155 -8
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +11 -0
- package/v2Components/CommonTestAndPreview/constants.js +38 -2
- package/v2Components/CommonTestAndPreview/index.js +761 -222
- 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/CommonTestAndPreview.addTestCustomer.test.js +1 -0
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +284 -267
- 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/RcsPreviewContent.test.js +281 -283
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +199 -1
- package/v2Components/CommonTestAndPreview/tests/index.test.js +133 -4
- package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +31 -24
- package/v2Components/CommonTestAndPreview/utils.js +84 -0
- package/v2Components/FormBuilder/Classic.js +4487 -0
- package/v2Components/FormBuilder/Functional/FormBuilderShell.js +366 -0
- package/v2Components/FormBuilder/Functional/channels/registry.js +17 -0
- package/v2Components/FormBuilder/Functional/channels/sms/buildSubmitPayload.js +9 -0
- package/v2Components/FormBuilder/Functional/channels/sms/config.js +30 -0
- package/v2Components/FormBuilder/Functional/channels/sms/getEditorErrorDescriptor.js +46 -0
- package/v2Components/FormBuilder/Functional/channels/sms/getLiquidContent.js +13 -0
- package/v2Components/FormBuilder/Functional/channels/sms/index.js +22 -0
- package/v2Components/FormBuilder/Functional/channels/sms/tests/getEditorErrorDescriptor.test.js +52 -0
- package/v2Components/FormBuilder/Functional/channels/sms/tests/getLiquidContent.test.js +25 -0
- package/v2Components/FormBuilder/Functional/channels/sms/tests/validate.test.js +87 -0
- package/v2Components/FormBuilder/Functional/channels/sms/validate.js +89 -0
- package/v2Components/FormBuilder/Functional/constants.js +42 -0
- package/v2Components/FormBuilder/Functional/core/schema/fieldRegistry.js +38 -0
- package/v2Components/FormBuilder/Functional/core/schema/initializeFormState.js +85 -0
- package/v2Components/FormBuilder/Functional/core/store/formReducer.js +81 -0
- package/v2Components/FormBuilder/Functional/core/store/selectors.js +30 -0
- package/v2Components/FormBuilder/Functional/core/store/toLegacyFormData.js +91 -0
- package/v2Components/FormBuilder/Functional/index.js +26 -0
- package/v2Components/FormBuilder/Functional/layout/FieldSlot.js +59 -0
- package/v2Components/FormBuilder/Functional/layout/SchemaForm.js +31 -0
- package/v2Components/FormBuilder/Functional/layout/Section.js +116 -0
- package/v2Components/FormBuilder/Functional/renderers/smsRenderers.js +258 -0
- package/v2Components/FormBuilder/Functional/tests/channelRegistry.test.js +21 -0
- package/v2Components/FormBuilder/Functional/tests/fieldRegistry.test.js +65 -0
- package/v2Components/FormBuilder/Functional/tests/fieldSlot.test.js +97 -0
- package/v2Components/FormBuilder/Functional/tests/fixtures/smsParityCases.js +192 -0
- package/v2Components/FormBuilder/Functional/tests/formReducer.test.js +129 -0
- package/v2Components/FormBuilder/Functional/tests/initializeFormState.test.js +132 -0
- package/v2Components/FormBuilder/Functional/tests/schemaForm.test.js +40 -0
- package/v2Components/FormBuilder/Functional/tests/section.test.js +99 -0
- package/v2Components/FormBuilder/Functional/tests/selectors.test.js +67 -0
- package/v2Components/FormBuilder/Functional/tests/sms.crossFlowParity.test.js +155 -0
- package/v2Components/FormBuilder/Functional/tests/sms.liquid.test.js +172 -0
- package/v2Components/FormBuilder/Functional/tests/sms.rollout.test.js +122 -0
- package/v2Components/FormBuilder/Functional/tests/sms.shell.parity.test.js +329 -0
- package/v2Components/FormBuilder/Functional/tests/smsRenderers.test.js +160 -0
- package/v2Components/FormBuilder/Functional/tests/toLegacyFormData.test.js +95 -0
- package/v2Components/FormBuilder/_formBuilder.scss +5 -0
- package/v2Components/FormBuilder/index.js +41 -4479
- package/v2Components/FormBuilder/tests/__snapshots__/sms.characterization.test.js.snap +114 -0
- package/v2Components/FormBuilder/tests/entryGate.test.js +106 -0
- package/v2Components/FormBuilder/tests/sms.characterization.test.js +336 -0
- package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +91 -0
- package/v2Components/SmsFallback/constants.js +94 -0
- package/v2Components/SmsFallback/index.js +958 -0
- package/v2Components/SmsFallback/index.scss +266 -0
- package/v2Components/SmsFallback/messages.js +78 -0
- package/v2Components/SmsFallback/smsFallbackUtils.js +120 -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 +208 -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 +41 -22
- 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/CustomValuesEditor.js +6 -6
- package/v2Components/TestAndPreviewSlidebox/index.js +13 -1
- 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/CommunicationFlow/Tests/CommunicationFlow.test.js +4 -1
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +4 -0
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +20 -20
- package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +17 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +36 -4
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +14 -5
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +36 -5
- package/v2Containers/CreativesContainer/constants.js +11 -0
- package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +79 -0
- package/v2Containers/CreativesContainer/index.js +323 -104
- package/v2Containers/CreativesContainer/index.scss +83 -1
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +79 -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 +333 -90
- 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 +131 -11
- package/v2Containers/Rcs/index.js +2602 -807
- package/v2Containers/Rcs/index.scss +289 -8
- package/v2Containers/Rcs/messages.js +34 -3
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +227 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +73535 -38537
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +0 -8
- package/v2Containers/Rcs/tests/index.test.js +147 -36
- 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 +115 -48
- 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 +678 -169
- package/v2Containers/SmsTrai/Edit/index.scss +126 -0
- package/v2Containers/SmsTrai/Edit/messages.js +14 -4
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +5615 -3014
- 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 +171 -12
- package/v2Containers/Templates/actions.js +11 -0
- package/v2Containers/Templates/constants.js +2 -0
- package/v2Containers/Templates/index.js +125 -55
- package/v2Containers/Templates/sagas.js +57 -13
- package/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1060 -1015
- 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/Whatsapp/index.js +3 -20
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +578 -34
|
@@ -126,7 +126,7 @@ import { INAPP_LAYOUT_DETAILS, INAPP_MESSAGE_LAYOUT_TYPES } from '../InApp/const
|
|
|
126
126
|
import { ZALO_STATUS_OPTIONS, ZALO_STATUSES } from '../Zalo/constants';
|
|
127
127
|
import { getWhatsappContent, getWhatsappStatus, getWhatsappCategory, getWhatsappCta, getWhatsappQuickReply, getWhatsappAutoFill, getWhatsappCarouselButtonView, getWhatsappDocPreview } from '../Whatsapp/utils';
|
|
128
128
|
import { getRCSContent } from '../Rcs/utils';
|
|
129
|
-
import {RCS_STATUSES} from '../Rcs/constants';
|
|
129
|
+
import { RCS_STATUSES, HOST_INFOBIP } from '../Rcs/constants';
|
|
130
130
|
import zaloMessages from '../Zalo/messages';
|
|
131
131
|
import rcsMessages from '../Rcs/messages';
|
|
132
132
|
import inAppMessages from '../InApp/messages';
|
|
@@ -432,8 +432,13 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
432
432
|
channel = '';
|
|
433
433
|
}
|
|
434
434
|
this.setState({ channel, activeMode });
|
|
435
|
-
// Always reset archive mode and selection when mounting a new channel
|
|
436
|
-
|
|
435
|
+
// Always reset archive mode and selection when mounting a new channel.
|
|
436
|
+
// Skip for local-template instances (e.g. SmsFallback selector) — SET_ARCHIVED_MODE clears
|
|
437
|
+
// Templates.templates in the reducer, which would wipe the background RCS template list.
|
|
438
|
+
const useLocalTemplatesOnMount = get(this.props, 'localTemplatesConfig.useLocalTemplates', false);
|
|
439
|
+
if (!useLocalTemplatesOnMount) {
|
|
440
|
+
this.props.actions.setArchivedMode(false);
|
|
441
|
+
}
|
|
437
442
|
this.props.actions.clearTemplateSelection();
|
|
438
443
|
// Clear templates when entering account selection mode to prevent showing old channel templates
|
|
439
444
|
if (activeMode === ACCOUNT_SELECTION_MODE) {
|
|
@@ -466,7 +471,13 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
466
471
|
if (this.props.location.query.type === 'embedded') {
|
|
467
472
|
this.props.actions.resetAccount();
|
|
468
473
|
}
|
|
469
|
-
|
|
474
|
+
// When using local templates (e.g. SMS fallback selector), do not fetch from API or we overwrite global store and break background RCS list
|
|
475
|
+
const useLocalTemplates = get(
|
|
476
|
+
this.props,
|
|
477
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
478
|
+
get(this.props, 'useLocalTemplates', false),
|
|
479
|
+
);
|
|
480
|
+
if (!useLocalTemplates && [LINE_LOWERCASE, VIBER_CHANNEL, FACEBOOK_CHANNEL, SMS_LOWERCASE, EMAIL_LOWERCASE, EBILL_LOWERCASE].includes((this.state.channel || '').toLowerCase())) {
|
|
470
481
|
const queryParams = {
|
|
471
482
|
// name: this.state.searchText,
|
|
472
483
|
// sortBy: this.state.sortBy,
|
|
@@ -549,7 +560,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
549
560
|
selectedTemplateForPreview: null,
|
|
550
561
|
testAndPreviewContent: null,
|
|
551
562
|
}, () => {
|
|
552
|
-
if ([
|
|
563
|
+
if ([LINE_LOWERCASE, VIBER_CHANNEL, FACEBOOK_CHANNEL, SMS_LOWERCASE, EMAIL_LOWERCASE, EBILL_LOWERCASE, RCS_LOWERCASE].includes(this.state.channel.toLowerCase()) || (this.state.channel.toLowerCase() === 'wechat' && !isEmpty(nextProps.Templates.selectedWeChatAccount))) {
|
|
553
564
|
if (this.state.channel.toLowerCase() === 'wechat' && !isEmpty(nextProps.Templates.selectedWeChatAccount)) {
|
|
554
565
|
params.wecrmId = (nextProps.Templates.selectedWeChatAccount.configs || {}).wecrm_app_id;
|
|
555
566
|
params.wecrmToken = (nextProps.Templates.selectedWeChatAccount.configs || {}).wecrm_token;
|
|
@@ -1012,8 +1023,16 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
1012
1023
|
|
|
1013
1024
|
componentWillUnmount() {
|
|
1014
1025
|
window.removeEventListener("message", this.handleFrameTasks);
|
|
1015
|
-
|
|
1016
|
-
|
|
1026
|
+
// When using local templates (e.g. SMS fallback selector), do not clear global store or background RCS list is wiped
|
|
1027
|
+
const useLocalTemplates = get(
|
|
1028
|
+
this.props,
|
|
1029
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
1030
|
+
get(this.props, 'useLocalTemplates', false),
|
|
1031
|
+
);
|
|
1032
|
+
if (!useLocalTemplates) {
|
|
1033
|
+
this.props.actions.resetTemplateStoreData();
|
|
1034
|
+
this.props.globalActions.clearMetaEntities();
|
|
1035
|
+
}
|
|
1017
1036
|
// Clear any pending timeouts to prevent memory leaks
|
|
1018
1037
|
if (this._clearEditTimeout) {
|
|
1019
1038
|
clearTimeout(this._clearEditTimeout);
|
|
@@ -1870,12 +1889,20 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
1870
1889
|
}
|
|
1871
1890
|
|
|
1872
1891
|
filterRcsTemplates = (templates) => {
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1892
|
+
const selectedRcsAccountName = this.props?.Templates?.selectedRcsAccount?.name || '';
|
|
1893
|
+
const hostName = this.state?.hostName;
|
|
1894
|
+
let nextTemplates = templates || [];
|
|
1895
|
+
if (selectedRcsAccountName) {
|
|
1896
|
+
nextTemplates = nextTemplates.filter(
|
|
1897
|
+
(t) => get(t, 'versions.base.content.RCS.rcsContent.accountName', '') === selectedRcsAccountName
|
|
1898
|
+
);
|
|
1877
1899
|
}
|
|
1878
|
-
|
|
1900
|
+
if (!this.props.isFullMode && hostName !== HOST_INFOBIP) {
|
|
1901
|
+
return nextTemplates.filter(
|
|
1902
|
+
(t) => get(t, 'versions.base.content.RCS.rcsContent.cardContent[0].Status', 'unavailable') === RCS_STATUSES.approved
|
|
1903
|
+
);
|
|
1904
|
+
}
|
|
1905
|
+
return nextTemplates;
|
|
1879
1906
|
}
|
|
1880
1907
|
|
|
1881
1908
|
filterZaloTemplates = (templates) => {
|
|
@@ -2065,7 +2092,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
2065
2092
|
style={{ marginRight: "16px" }}
|
|
2066
2093
|
type="eye"
|
|
2067
2094
|
onClick={() => {
|
|
2068
|
-
if (!this.props.isFullMode || this.props.isDltFromRcs) {
|
|
2095
|
+
if (!this.props.isFullMode || this.props.isDltFromRcs || this.props.isSmsFallbackFromRcs) {
|
|
2069
2096
|
if (!get(template, "versions.base.content.zalo.previewUrl", "")) {
|
|
2070
2097
|
this.setState({ zaloPreviewItemId: template?._id });
|
|
2071
2098
|
}
|
|
@@ -2548,13 +2575,14 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
2548
2575
|
<CapRow type='flex' align="middle" justify="start" gap={12}>
|
|
2549
2576
|
{isCardArchiveEligible && this.renderCardSelectionCheckbox({ templateId: template._id, selectedIds: selectedIdsArrayForCard, isDisabled: isAnyArchiveInProgress })}
|
|
2550
2577
|
<CapLabel className="whatsapp-rcs-template-name">{name}</CapLabel>
|
|
2551
|
-
<CapColumn type="flex" align="middle" className="rcs-status-container zalo-status-color">
|
|
2578
|
+
{this.state.hostName !== HOST_INFOBIP && <CapColumn type="flex" align="middle" className="rcs-status-container zalo-status-color">
|
|
2552
2579
|
<CapStatus
|
|
2553
2580
|
type={statusDisplay}
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2581
|
+
text={statusDisplay && this.props.intl.formatMessage(rcsMessages?.[`${statusDisplay}_STATUS`])}
|
|
2582
|
+
labelType="label3"
|
|
2583
|
+
/>
|
|
2584
|
+
</CapColumn>
|
|
2585
|
+
}
|
|
2558
2586
|
</CapRow>
|
|
2559
2587
|
);
|
|
2560
2588
|
|
|
@@ -3131,6 +3159,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
3131
3159
|
let routeParams = {};
|
|
3132
3160
|
const {fbAdManager} = this.props;
|
|
3133
3161
|
const isLibraryMode = this.isEnabledInLibraryModule("callCreateFromProps");
|
|
3162
|
+
|
|
3134
3163
|
if (!isLibraryMode) {
|
|
3135
3164
|
timeTracker.startTimer(CHANNEL_CREATE_TRACK_MAPPING[channel]);
|
|
3136
3165
|
}
|
|
@@ -3480,6 +3509,13 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
3480
3509
|
this.setState({modeType});
|
|
3481
3510
|
}
|
|
3482
3511
|
const { _id: id } = template;
|
|
3512
|
+
const {
|
|
3513
|
+
localTemplatesConfig,
|
|
3514
|
+
fbAdManager,
|
|
3515
|
+
isDltFromRcs,
|
|
3516
|
+
isSmsFallbackFromRcs,
|
|
3517
|
+
onSelectTemplate,
|
|
3518
|
+
} = this.props;
|
|
3483
3519
|
const type = this.props.location.query.type;
|
|
3484
3520
|
const module = this.props.location.query.module;
|
|
3485
3521
|
const isLanguageSupport = (this.props.location.query.isLanguageSupport) ? this.props.location.query.isLanguageSupport : false;
|
|
@@ -3565,10 +3601,12 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
3565
3601
|
}
|
|
3566
3602
|
if (this.isEnabledInLibraryModule("callSelectFromProps")) {
|
|
3567
3603
|
let data = id;
|
|
3568
|
-
if (
|
|
3604
|
+
if (localTemplatesConfig?.useLocalTemplates) {
|
|
3605
|
+
data = template;
|
|
3606
|
+
} else if (fbAdManager || isDltFromRcs || isSmsFallbackFromRcs) {
|
|
3569
3607
|
data = this.selectTemplate(id);
|
|
3570
3608
|
}
|
|
3571
|
-
|
|
3609
|
+
onSelectTemplate(data, fbAdManager);
|
|
3572
3610
|
} else {
|
|
3573
3611
|
timeTracker.startTimer(CHANNEL_EDIT_TRACK_MAPPING[this.state.channel.toLowerCase()]);
|
|
3574
3612
|
if (this.state.channel.toLowerCase() === 'ebill') {
|
|
@@ -4546,9 +4584,11 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
4546
4584
|
const isWechatEmbedded = !this.props.isFullMode && channel.toUpperCase() === WECHAT;
|
|
4547
4585
|
const channelLowerCase = (channel || '').toLowerCase();
|
|
4548
4586
|
const isTraiDltFeature = this.checkDLTfeatureEnable();
|
|
4549
|
-
|
|
4550
4587
|
const createButton =
|
|
4551
|
-
(
|
|
4588
|
+
(
|
|
4589
|
+
[WHATSAPP_LOWERCASE, RCS_LOWERCASE].includes(channelLowerCase)
|
|
4590
|
+
&& !this.props.isFullMode
|
|
4591
|
+
)
|
|
4552
4592
|
? (
|
|
4553
4593
|
<CapLink
|
|
4554
4594
|
onClick={this.openCreativesFullMode}
|
|
@@ -4580,17 +4620,22 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
4580
4620
|
const _renderSelectedIdsArray = _renderSelectedIds && typeof _renderSelectedIds.toJS === 'function' ? _renderSelectedIds.toJS() : (Array.isArray(_renderSelectedIds) ? _renderSelectedIds : []);
|
|
4581
4621
|
const _renderHasSelection = _isArchivalEnabled && this.props.isFullMode && _renderSelectedIdsArray.length > 0;
|
|
4582
4622
|
|
|
4583
|
-
const
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4623
|
+
const useLocalTemplates = this.props.localTemplatesConfig?.useLocalTemplates;
|
|
4624
|
+
const builtFilterContent = ((isfilterContentVisisble || [WECHAT, MOBILE_PUSH, INAPP].includes(this.state.channel.toUpperCase())) && (
|
|
4625
|
+
<div className="action-container">
|
|
4626
|
+
<div className="action-container__toolbar-row">
|
|
4627
|
+
{isfilterContentVisisble ? (
|
|
4628
|
+
<CapInput.Search
|
|
4629
|
+
className="search-text"
|
|
4630
|
+
placeholder={this.props.intl.formatMessage(messages.searchText)}
|
|
4631
|
+
value={this.state.searchText}
|
|
4632
|
+
onChange={(e) => this.searchTemplate(e.target.value, this.state.channel)}
|
|
4633
|
+
onSearch={() => this.searchTemplate(this.state.searchText, this.state.channel)}
|
|
4634
|
+
onClear={() => this.searchTemplate('', this.state.channel)}
|
|
4635
|
+
onScroll={(e) => e.stopPropagation()}
|
|
4636
|
+
disabled={this.checkSearchDisabled()}
|
|
4637
|
+
/>
|
|
4638
|
+
) : null}
|
|
4594
4639
|
{
|
|
4595
4640
|
channel.toUpperCase() === WECHAT && <CapRadio.CapRadioGroup className="wechat-filters" defaultValue={wechatFilter} onChange={this.setWechatFilter}>
|
|
4596
4641
|
<CapRadio.Button value={WECHAT_FILTERS.ALL}><CapLabel type="label2">
|
|
@@ -4737,16 +4782,6 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
4737
4782
|
)
|
|
4738
4783
|
}
|
|
4739
4784
|
<div className="template-listing-header-actions">
|
|
4740
|
-
{!_isArchivedMode && !_renderHasSelection && (
|
|
4741
|
-
this.state?.channel?.toLowerCase() === WHATSAPP_LOWERCASE && (isWhatsappCountExeeded) ? (
|
|
4742
|
-
<CapTooltip title={whatsappCountExceedText}>
|
|
4743
|
-
<div className="button-disabled-tooltip-wrapper">
|
|
4744
|
-
{createButton}
|
|
4745
|
-
</div>
|
|
4746
|
-
</CapTooltip>
|
|
4747
|
-
)
|
|
4748
|
-
: isfilterContentVisisble && !isWechatEmbedded && !this.props.isDltFromRcs && createButton
|
|
4749
|
-
)}
|
|
4750
4785
|
{/* More (⋯) menu: full mode only, not archived mode, not Zalo (no archive support), not when selection active, archive flag enabled */}
|
|
4751
4786
|
{commonUtil.hasCreativesArchivalEnabled() && !_isArchivedMode && !_renderHasSelection && this.props.isFullMode && this.props.location.query.type !== EMBEDDED && channelLowerCase !== ZALO_LOWERCASE && (
|
|
4752
4787
|
<CapDropdown
|
|
@@ -4769,7 +4804,28 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
4769
4804
|
</CapDropdown>
|
|
4770
4805
|
)}
|
|
4771
4806
|
</div>
|
|
4772
|
-
</div>
|
|
4807
|
+
</div>
|
|
4808
|
+
<div>
|
|
4809
|
+
<div className="action-container__create-row">
|
|
4810
|
+
{
|
|
4811
|
+
isfilterContentVisisble && !isWechatEmbedded && !this.props.isDltFromRcs && !this.props.isSmsFallbackFromRcs && (
|
|
4812
|
+
this.state?.channel?.toLowerCase() === WHATSAPP_LOWERCASE && isWhatsappCountExeeded ? (
|
|
4813
|
+
<CapTooltip title={whatsappCountExceedText}>
|
|
4814
|
+
<div className="button-disabled-tooltip-wrapper">
|
|
4815
|
+
{createButton}
|
|
4816
|
+
</div>
|
|
4817
|
+
</CapTooltip>
|
|
4818
|
+
) : createButton
|
|
4819
|
+
)
|
|
4820
|
+
}
|
|
4821
|
+
</div>
|
|
4822
|
+
</div>
|
|
4823
|
+
</div>
|
|
4824
|
+
));
|
|
4825
|
+
const localTemplatesFilterContent = get(this.props, 'localTemplatesConfig.localTemplatesFilterContent', null);
|
|
4826
|
+
const filterContent = (useLocalTemplates && localTemplatesFilterContent) != null
|
|
4827
|
+
? localTemplatesFilterContent
|
|
4828
|
+
: builtFilterContent;
|
|
4773
4829
|
let htmlPreviewContent = "";
|
|
4774
4830
|
if (this.state.channel.toLowerCase() === 'ebill') {
|
|
4775
4831
|
htmlPreviewContent = this.state.previewTemplate && this.state.previewTemplate.versions && this.state.previewTemplate.versions.base && this.state.previewTemplate.versions.base['ebill-editor'];
|
|
@@ -4779,7 +4835,10 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
4779
4835
|
|
|
4780
4836
|
|
|
4781
4837
|
const creativesParams = this.getCreativesParams();
|
|
4782
|
-
const templates =
|
|
4838
|
+
const templates = useLocalTemplates
|
|
4839
|
+
? (this.props.localTemplatesConfig?.localTemplates || [])
|
|
4840
|
+
: (this.props.TemplatesList || []);
|
|
4841
|
+
const isLoadingWhenLocal = useLocalTemplates && !!this.props.localTemplatesConfig?.localTemplatesLoading;
|
|
4783
4842
|
const {route} = this.props;
|
|
4784
4843
|
const loadingTipMap = {
|
|
4785
4844
|
sendingFile: 'uploadingFile',
|
|
@@ -4794,9 +4853,11 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
4794
4853
|
(deleteRcsTemplateInProgress && 'deletingTemplate') ||
|
|
4795
4854
|
(this.props.EmailCreate.duplicateTemplateInProgress && 'duplicatingTemplate');
|
|
4796
4855
|
|
|
4797
|
-
const loadingTip =
|
|
4856
|
+
const loadingTip = useLocalTemplates && this.props.localTemplatesConfig?.localTemplatesLoadingTip
|
|
4857
|
+
? this.props.localTemplatesConfig.localTemplatesLoadingTip
|
|
4858
|
+
: (messages[loadingTipIntl] ? this.props.intl.formatMessage(messages[loadingTipIntl]) : this.props.intl.formatMessage(messages.gettingAllTemplates));
|
|
4798
4859
|
const showNoTemplatesFoundZalo = this.state.channel.toUpperCase() === ZALO && isEmpty(this.state.searchedZaloTemplates) && this.state.searchingZaloTemplate;
|
|
4799
|
-
const showNoTemplatesFoundOther = ![ZALO].includes(this.state.channel.toUpperCase()) && isEmpty(
|
|
4860
|
+
const showNoTemplatesFoundOther = ![ZALO].includes(this.state.channel.toUpperCase()) && isEmpty(templates) && (useLocalTemplates ? !isLoadingWhenLocal : !this.props.Templates.getAllTemplatesInProgress) && (useLocalTemplates || !isEmpty(this.state.searchText));
|
|
4800
4861
|
const showNoTemplatesFound = showNoTemplatesFoundZalo || showNoTemplatesFoundOther;
|
|
4801
4862
|
|
|
4802
4863
|
return (
|
|
@@ -4840,7 +4901,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
4840
4901
|
/>
|
|
4841
4902
|
) : null}
|
|
4842
4903
|
|
|
4843
|
-
{channel.toLowerCase() === RCS_LOWERCASE && !isFullMode ? (
|
|
4904
|
+
{channel.toLowerCase() === RCS_LOWERCASE && !isFullMode && this.state?.hostName !== HOST_INFOBIP ? (
|
|
4844
4905
|
<CapInfoNote
|
|
4845
4906
|
message={formatMessage(messages.rcsOnlyApprovedTemplates)}
|
|
4846
4907
|
/>
|
|
@@ -4853,22 +4914,22 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
4853
4914
|
) : null}
|
|
4854
4915
|
<CapRow useLegacy>
|
|
4855
4916
|
<Pagination
|
|
4856
|
-
templateInProgress={
|
|
4857
|
-
this.props.Templates.getAllTemplatesInProgress
|
|
4858
|
-
}
|
|
4917
|
+
templateInProgress={useLocalTemplates ? isLoadingWhenLocal : this.props.Templates.getAllTemplatesInProgress}
|
|
4859
4918
|
onPageChange={
|
|
4860
|
-
templates.length
|
|
4919
|
+
templates.length
|
|
4920
|
+
? (useLocalTemplates ? (this.props.localTemplatesConfig?.localTemplatesOnPageChange || (() => {})) : this.onPaginationChange)
|
|
4921
|
+
: () => {}
|
|
4861
4922
|
}
|
|
4862
4923
|
>
|
|
4863
4924
|
{this.getTemplateDataForGrid({
|
|
4864
4925
|
previewTemplateId: this.state.zaloPreviewItemId,
|
|
4865
|
-
isLoading,
|
|
4866
|
-
isInitialLoading,
|
|
4926
|
+
isLoading: useLocalTemplates ? isLoadingWhenLocal : isLoading,
|
|
4927
|
+
isInitialLoading: useLocalTemplates ? isLoadingWhenLocal && templates.length === 0 : isInitialLoading,
|
|
4867
4928
|
loadingTip,
|
|
4868
4929
|
channel: this.state.channel,
|
|
4869
4930
|
templates: this.state.searchingZaloTemplate
|
|
4870
4931
|
? this.state.searchedZaloTemplates
|
|
4871
|
-
:
|
|
4932
|
+
: templates,
|
|
4872
4933
|
filterContent,
|
|
4873
4934
|
handlers: {
|
|
4874
4935
|
handlePreviewClick: this.handlePreviewClick,
|
|
@@ -5052,6 +5113,15 @@ Templates.propTypes = {
|
|
|
5052
5113
|
WebPush: PropTypes.object,
|
|
5053
5114
|
smsRegister: PropTypes.any,
|
|
5054
5115
|
isDltFromRcs: PropTypes.bool,
|
|
5116
|
+
isSmsFallbackFromRcs: PropTypes.bool,
|
|
5117
|
+
localTemplatesConfig: PropTypes.shape({
|
|
5118
|
+
useLocalTemplates: PropTypes.bool,
|
|
5119
|
+
localTemplates: PropTypes.arrayOf(PropTypes.object),
|
|
5120
|
+
localTemplatesLoading: PropTypes.bool,
|
|
5121
|
+
localTemplatesLoadingTip: PropTypes.string,
|
|
5122
|
+
localTemplatesFilterContent: PropTypes.node,
|
|
5123
|
+
localTemplatesOnPageChange: PropTypes.func,
|
|
5124
|
+
}),
|
|
5055
5125
|
};
|
|
5056
5126
|
|
|
5057
5127
|
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';
|
|
@@ -7,33 +7,70 @@ import { CapNotification } from '@capillarytech/cap-ui-library';
|
|
|
7
7
|
import * as Api from '../../services/api';
|
|
8
8
|
import * as types from './constants';
|
|
9
9
|
import { saveCdnConfigs, removeAllCdnLocalStorageItems, initCdnConfigFromEnv } from '../../utils/cdnTransformation';
|
|
10
|
-
import { COPY_OF } from '../../constants/unified';
|
|
10
|
+
import { COPY_OF, SMS as SMS_CHANNEL } 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_CHANNEL) {
|
|
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
|
}
|
|
@@ -270,6 +307,11 @@ export function* watchGetAllTemplates() {
|
|
|
270
307
|
yield takeLatest(types.GET_ALL_TEMPLATES_REQUEST, getAllTemplates);
|
|
271
308
|
}
|
|
272
309
|
|
|
310
|
+
|
|
311
|
+
export function* watchGetLocalSmsTemplates() {
|
|
312
|
+
yield takeEvery(types.GET_LOCAL_SMS_TEMPLATES_REQUEST, getLocalSmsTemplates);
|
|
313
|
+
}
|
|
314
|
+
|
|
273
315
|
export function* watchDeleteTemplate() {
|
|
274
316
|
yield takeLatest(types.DELETE_TEMPLATE_REQUEST, deleteTemplate);
|
|
275
317
|
}
|
|
@@ -323,6 +365,7 @@ export function* watchForGetTemplateInfoById() {
|
|
|
323
365
|
// All sagas to be loaded
|
|
324
366
|
export default [
|
|
325
367
|
watchGetAllTemplates,
|
|
368
|
+
watchGetLocalSmsTemplates,
|
|
326
369
|
watchDeleteTemplate,
|
|
327
370
|
watchDeleteRcsTemplate,
|
|
328
371
|
watchGetUserList,
|
|
@@ -339,6 +382,7 @@ export default [
|
|
|
339
382
|
export function* v2TemplateSaga() {
|
|
340
383
|
yield all([
|
|
341
384
|
watchGetAllTemplates(),
|
|
385
|
+
watchGetLocalSmsTemplates(),
|
|
342
386
|
watchDeleteTemplate(),
|
|
343
387
|
watchDeleteRcsTemplate(),
|
|
344
388
|
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
|
+
});
|