@capillarytech/creatives-library 8.0.319 → 8.0.321
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 +14 -0
- package/package.json +1 -1
- package/utils/templateVarUtils.js +172 -0
- package/utils/tests/tagValidations.test.js +34 -0
- package/utils/tests/templateVarUtils.test.js +160 -0
- package/v2Components/CapTagList/index.js +25 -22
- package/v2Components/CapTagList/style.scss +48 -0
- package/v2Components/CapTagListWithInput/__tests__/CapTagListWithInput.test.js +63 -0
- package/v2Components/CapTagListWithInput/index.js +4 -0
- package/v2Components/CapWhatsappCTA/index.js +2 -0
- package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +70 -49
- package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +8 -2
- package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +207 -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 +11 -5
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +20 -1
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +133 -4
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +12 -0
- package/v2Components/CommonTestAndPreview/constants.js +38 -0
- package/v2Components/CommonTestAndPreview/index.js +693 -155
- package/v2Components/CommonTestAndPreview/messages.js +41 -3
- package/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
- package/v2Components/CommonTestAndPreview/sagas.js +15 -6
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +352 -0
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +269 -1
- 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/SendTestMessage.test.js +25 -4
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +199 -1
- package/v2Components/CommonTestAndPreview/tests/index.test.js +132 -4
- package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +2 -2
- package/v2Components/FormBuilder/index.js +14 -1
- package/v2Components/HtmlEditor/HTMLEditor.js +6 -1
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +927 -2
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +3 -0
- package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +87 -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 +107 -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 +197 -0
- package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +261 -0
- package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +422 -0
- package/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
- package/v2Components/TestAndPreviewSlidebox/index.js +8 -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/BeeEditor/index.js +3 -0
- package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +43 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +64 -5
- 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 +67 -0
- package/v2Containers/CreativesContainer/index.js +292 -99
- package/v2Containers/CreativesContainer/index.scss +51 -1
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +104 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +110 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +8 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +363 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +20 -10
- 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/Email/index.js +1 -0
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +7 -1
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +3 -0
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +20 -2
- package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +16 -1
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +3 -0
- package/v2Containers/EmailWrapper/index.js +4 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +1 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +9 -0
- package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +19 -0
- package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +3 -0
- package/v2Containers/InAppWrapper/index.js +3 -0
- package/v2Containers/MobilePush/Create/index.js +2 -0
- package/v2Containers/MobilePush/Edit/index.js +2 -0
- package/v2Containers/MobilepushWrapper/index.js +3 -1
- package/v2Containers/Rcs/constants.js +32 -1
- package/v2Containers/Rcs/index.js +951 -873
- package/v2Containers/Rcs/index.scss +85 -6
- package/v2Containers/Rcs/messages.js +10 -1
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +205 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +40834 -1963
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +0 -5
- package/v2Containers/Rcs/tests/index.test.js +41 -38
- package/v2Containers/Rcs/tests/mockData.js +38 -0
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +251 -0
- package/v2Containers/Rcs/tests/utils.test.js +379 -1
- package/v2Containers/Rcs/utils.js +358 -10
- package/v2Containers/Sms/Create/index.js +83 -36
- package/v2Containers/Sms/Edit/index.js +2 -0
- 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 +611 -128
- package/v2Containers/SmsTrai/Edit/index.scss +121 -0
- package/v2Containers/SmsTrai/Edit/messages.js +9 -4
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4327 -2374
- package/v2Containers/SmsWrapper/index.js +39 -8
- package/v2Containers/TagList/index.js +47 -2
- package/v2Containers/TagList/messages.js +4 -0
- package/v2Containers/TagList/tests/TagList.test.js +122 -20
- package/v2Containers/TagList/tests/mockdata.js +17 -0
- package/v2Containers/Templates/TemplatesActionBar.js +101 -0
- package/v2Containers/Templates/_templates.scss +61 -2
- package/v2Containers/Templates/actions.js +11 -0
- package/v2Containers/Templates/constants.js +2 -0
- package/v2Containers/Templates/index.js +90 -40
- package/v2Containers/Templates/sagas.js +57 -12
- package/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1043 -1079
- package/v2Containers/Templates/tests/sagas.test.js +193 -12
- 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/Viber/index.js +5 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.js +0 -2
- package/v2Containers/WebPush/Create/index.js +9 -1
- package/v2Containers/Whatsapp/index.js +8 -20
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +598 -34
- package/v2Containers/Zalo/index.js +2 -0
|
@@ -468,7 +468,13 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
468
468
|
if (this.props.location.query.type === 'embedded') {
|
|
469
469
|
this.props.actions.resetAccount();
|
|
470
470
|
}
|
|
471
|
-
|
|
471
|
+
// When using local templates (e.g. SMS fallback selector), do not fetch from API or we overwrite global store and break background RCS list
|
|
472
|
+
const useLocalTemplates = get(
|
|
473
|
+
this.props,
|
|
474
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
475
|
+
get(this.props, 'useLocalTemplates', false),
|
|
476
|
+
);
|
|
477
|
+
if (!useLocalTemplates && ['line', VIBER_CHANNEL, FACEBOOK_CHANNEL, 'sms', 'email', 'ebill'].includes((this.state.channel || '').toLowerCase())) {
|
|
472
478
|
const queryParams = {
|
|
473
479
|
// name: this.state.searchText,
|
|
474
480
|
// sortBy: this.state.sortBy,
|
|
@@ -981,8 +987,16 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
981
987
|
|
|
982
988
|
componentWillUnmount() {
|
|
983
989
|
window.removeEventListener("message", this.handleFrameTasks);
|
|
984
|
-
|
|
985
|
-
|
|
990
|
+
// When using local templates (e.g. SMS fallback selector), do not clear global store or background RCS list is wiped
|
|
991
|
+
const useLocalTemplates = get(
|
|
992
|
+
this.props,
|
|
993
|
+
'localTemplatesConfig.useLocalTemplates',
|
|
994
|
+
get(this.props, 'useLocalTemplates', false),
|
|
995
|
+
);
|
|
996
|
+
if (!useLocalTemplates) {
|
|
997
|
+
this.props.actions.resetTemplateStoreData();
|
|
998
|
+
this.props.globalActions.clearMetaEntities();
|
|
999
|
+
}
|
|
986
1000
|
// Clear any pending timeouts to prevent memory leaks
|
|
987
1001
|
if (this._clearEditTimeout) {
|
|
988
1002
|
clearTimeout(this._clearEditTimeout);
|
|
@@ -1947,7 +1961,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
1947
1961
|
style={{ marginRight: "16px" }}
|
|
1948
1962
|
type="eye"
|
|
1949
1963
|
onClick={() => {
|
|
1950
|
-
if (!this.props.isFullMode || this.props.isDltFromRcs) {
|
|
1964
|
+
if (!this.props.isFullMode || this.props.isDltFromRcs || this.props.isSmsFallbackFromRcs) {
|
|
1951
1965
|
if (!get(template, "versions.base.content.zalo.previewUrl", "")) {
|
|
1952
1966
|
this.setState({ zaloPreviewItemId: template?._id });
|
|
1953
1967
|
}
|
|
@@ -3282,6 +3296,13 @@ return (<div>
|
|
|
3282
3296
|
this.setState({modeType});
|
|
3283
3297
|
}
|
|
3284
3298
|
const { _id: id } = template;
|
|
3299
|
+
const {
|
|
3300
|
+
localTemplatesConfig,
|
|
3301
|
+
fbAdManager,
|
|
3302
|
+
isDltFromRcs,
|
|
3303
|
+
isSmsFallbackFromRcs,
|
|
3304
|
+
onSelectTemplate,
|
|
3305
|
+
} = this.props;
|
|
3285
3306
|
const type = this.props.location.query.type;
|
|
3286
3307
|
const module = this.props.location.query.module;
|
|
3287
3308
|
const isLanguageSupport = (this.props.location.query.isLanguageSupport) ? this.props.location.query.isLanguageSupport : false;
|
|
@@ -3367,10 +3388,12 @@ return (<div>
|
|
|
3367
3388
|
}
|
|
3368
3389
|
if (this.isEnabledInLibraryModule("callSelectFromProps")) {
|
|
3369
3390
|
let data = id;
|
|
3370
|
-
if (
|
|
3391
|
+
if (localTemplatesConfig?.useLocalTemplates) {
|
|
3392
|
+
data = template;
|
|
3393
|
+
} else if (fbAdManager || isDltFromRcs || isSmsFallbackFromRcs) {
|
|
3371
3394
|
data = this.selectTemplate(id);
|
|
3372
3395
|
}
|
|
3373
|
-
|
|
3396
|
+
onSelectTemplate(data, fbAdManager);
|
|
3374
3397
|
} else {
|
|
3375
3398
|
timeTracker.startTimer(CHANNEL_EDIT_TRACK_MAPPING[this.state.channel.toLowerCase()]);
|
|
3376
3399
|
if (this.state.channel.toLowerCase() === 'ebill') {
|
|
@@ -4214,17 +4237,23 @@ return (<div>
|
|
|
4214
4237
|
if (([WHATSAPP_LOWERCASE, ZALO_LOWERCASE, RCS_LOWERCASE].includes(this.state?.channel?.toLocaleLowerCase()) && isEmpty(this.state?.hostName))) {
|
|
4215
4238
|
isfilterContentVisisble = false;
|
|
4216
4239
|
}
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4240
|
+
|
|
4241
|
+
const useLocalTemplates = this.props.localTemplatesConfig?.useLocalTemplates;
|
|
4242
|
+
const builtFilterContent = ((isfilterContentVisisble || [WECHAT, MOBILE_PUSH, INAPP].includes(this.state.channel.toUpperCase())) && (
|
|
4243
|
+
<div className="action-container">
|
|
4244
|
+
<div className="action-container__toolbar-row">
|
|
4245
|
+
{isfilterContentVisisble ? (
|
|
4246
|
+
<CapInput.Search
|
|
4247
|
+
className="search-text"
|
|
4248
|
+
placeholder={this.props.intl.formatMessage(messages.searchText)}
|
|
4249
|
+
value={this.state.searchText}
|
|
4250
|
+
onChange={(e) => this.searchTemplate(e.target.value, this.state.channel)}
|
|
4251
|
+
onSearch={() => this.searchTemplate(this.state.searchText, this.state.channel)}
|
|
4252
|
+
onClear={() => this.searchTemplate('', this.state.channel)}
|
|
4253
|
+
onScroll={(e) => e.stopPropagation()}
|
|
4254
|
+
disabled={this.checkSearchDisabled()}
|
|
4255
|
+
/>
|
|
4256
|
+
) : null}
|
|
4228
4257
|
{
|
|
4229
4258
|
channel.toUpperCase() === WECHAT && <CapRadio.CapRadioGroup className="wechat-filters" defaultValue={wechatFilter} onChange={this.setWechatFilter}>
|
|
4230
4259
|
<CapRadio.Button value={WECHAT_FILTERS.ALL}><CapLabel type="label2">
|
|
@@ -4370,20 +4399,27 @@ return (<div>
|
|
|
4370
4399
|
</div>
|
|
4371
4400
|
)
|
|
4372
4401
|
}
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
{
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4402
|
+
</div>
|
|
4403
|
+
<div>
|
|
4404
|
+
<div className="action-container__create-row">
|
|
4405
|
+
{
|
|
4406
|
+
this.state?.channel?.toLowerCase() === WHATSAPP_LOWERCASE && (isWhatsappCountExeeded) ? (
|
|
4407
|
+
<CapTooltip title={whatsappCountExceedText}>
|
|
4408
|
+
<div className="button-disabled-tooltip-wrapper">
|
|
4409
|
+
{createButton}
|
|
4410
|
+
</div>
|
|
4411
|
+
</CapTooltip>
|
|
4412
|
+
)
|
|
4413
|
+
: isfilterContentVisisble && !isWechatEmbedded && !this.props.isDltFromRcs && !this.props.isSmsFallbackFromRcs && createButton
|
|
4414
|
+
}
|
|
4415
|
+
</div>
|
|
4416
|
+
</div>
|
|
4384
4417
|
</div>
|
|
4385
|
-
|
|
4386
|
-
|
|
4418
|
+
));
|
|
4419
|
+
const localTemplatesFilterContent = get(this.props, 'localTemplatesConfig.localTemplatesFilterContent', null);
|
|
4420
|
+
const filterContent = (useLocalTemplates && localTemplatesFilterContent) != null
|
|
4421
|
+
? localTemplatesFilterContent
|
|
4422
|
+
: builtFilterContent;
|
|
4387
4423
|
let htmlPreviewContent = "";
|
|
4388
4424
|
if (this.state.channel.toLowerCase() === 'ebill') {
|
|
4389
4425
|
htmlPreviewContent = this.state.previewTemplate && this.state.previewTemplate.versions && this.state.previewTemplate.versions.base && this.state.previewTemplate.versions.base['ebill-editor'];
|
|
@@ -4393,7 +4429,10 @@ return (<div>
|
|
|
4393
4429
|
|
|
4394
4430
|
|
|
4395
4431
|
const creativesParams = this.getCreativesParams();
|
|
4396
|
-
const templates =
|
|
4432
|
+
const templates = useLocalTemplates
|
|
4433
|
+
? (this.props.localTemplatesConfig?.localTemplates || [])
|
|
4434
|
+
: (this.props.TemplatesList || []);
|
|
4435
|
+
const isLoadingWhenLocal = useLocalTemplates && !!this.props.localTemplatesConfig?.localTemplatesLoading;
|
|
4397
4436
|
const {route} = this.props;
|
|
4398
4437
|
const loadingTipMap = {
|
|
4399
4438
|
sendingFile: 'uploadingFile',
|
|
@@ -4408,9 +4447,11 @@ return (<div>
|
|
|
4408
4447
|
(deleteRcsTemplateInProgress && 'deletingTemplate') ||
|
|
4409
4448
|
(this.props.EmailCreate.duplicateTemplateInProgress && 'duplicatingTemplate');
|
|
4410
4449
|
|
|
4411
|
-
const loadingTip =
|
|
4450
|
+
const loadingTip = useLocalTemplates && this.props.localTemplatesConfig?.localTemplatesLoadingTip
|
|
4451
|
+
? this.props.localTemplatesConfig.localTemplatesLoadingTip
|
|
4452
|
+
: (messages[loadingTipIntl] ? this.props.intl.formatMessage(messages[loadingTipIntl]) : this.props.intl.formatMessage(messages.gettingAllTemplates));
|
|
4412
4453
|
const showNoTemplatesFoundZalo = this.state.channel.toUpperCase() === ZALO && isEmpty(this.state.searchedZaloTemplates) && this.state.searchingZaloTemplate;
|
|
4413
|
-
const showNoTemplatesFoundOther = ![ZALO].includes(this.state.channel.toUpperCase()) && isEmpty(
|
|
4454
|
+
const showNoTemplatesFoundOther = ![ZALO].includes(this.state.channel.toUpperCase()) && isEmpty(templates) && (useLocalTemplates ? !isLoadingWhenLocal : !this.props.Templates.getAllTemplatesInProgress) && (useLocalTemplates || !isEmpty(this.state.searchText));
|
|
4414
4455
|
const showNoTemplatesFound = showNoTemplatesFoundZalo || showNoTemplatesFoundOther;
|
|
4415
4456
|
|
|
4416
4457
|
return (
|
|
@@ -4455,22 +4496,22 @@ return (<div>
|
|
|
4455
4496
|
) : null}
|
|
4456
4497
|
<CapRow>
|
|
4457
4498
|
<Pagination
|
|
4458
|
-
templateInProgress={
|
|
4459
|
-
this.props.Templates.getAllTemplatesInProgress
|
|
4460
|
-
}
|
|
4499
|
+
templateInProgress={useLocalTemplates ? isLoadingWhenLocal : this.props.Templates.getAllTemplatesInProgress}
|
|
4461
4500
|
onPageChange={
|
|
4462
|
-
templates.length
|
|
4501
|
+
templates.length
|
|
4502
|
+
? (useLocalTemplates ? (this.props.localTemplatesConfig?.localTemplatesOnPageChange || (() => {})) : this.onPaginationChange)
|
|
4503
|
+
: () => {}
|
|
4463
4504
|
}
|
|
4464
4505
|
>
|
|
4465
4506
|
{this.getTemplateDataForGrid({
|
|
4466
4507
|
previewTemplateId: this.state.zaloPreviewItemId,
|
|
4467
|
-
isLoading,
|
|
4468
|
-
isInitialLoading,
|
|
4508
|
+
isLoading: useLocalTemplates ? isLoadingWhenLocal : isLoading,
|
|
4509
|
+
isInitialLoading: useLocalTemplates ? isLoadingWhenLocal && templates.length === 0 : isInitialLoading,
|
|
4469
4510
|
loadingTip,
|
|
4470
4511
|
channel: this.state.channel,
|
|
4471
4512
|
templates: this.state.searchingZaloTemplate
|
|
4472
4513
|
? this.state.searchedZaloTemplates
|
|
4473
|
-
:
|
|
4514
|
+
: templates,
|
|
4474
4515
|
filterContent,
|
|
4475
4516
|
handlers: {
|
|
4476
4517
|
handlePreviewClick: this.handlePreviewClick,
|
|
@@ -4653,6 +4694,15 @@ Templates.propTypes = {
|
|
|
4653
4694
|
WebPush: PropTypes.object,
|
|
4654
4695
|
smsRegister: PropTypes.any,
|
|
4655
4696
|
isDltFromRcs: PropTypes.bool,
|
|
4697
|
+
isSmsFallbackFromRcs: PropTypes.bool,
|
|
4698
|
+
localTemplatesConfig: PropTypes.shape({
|
|
4699
|
+
useLocalTemplates: PropTypes.bool,
|
|
4700
|
+
localTemplates: PropTypes.arrayOf(PropTypes.object),
|
|
4701
|
+
localTemplatesLoading: PropTypes.bool,
|
|
4702
|
+
localTemplatesLoadingTip: PropTypes.string,
|
|
4703
|
+
localTemplatesFilterContent: PropTypes.node,
|
|
4704
|
+
localTemplatesOnPageChange: PropTypes.func,
|
|
4705
|
+
}),
|
|
4656
4706
|
};
|
|
4657
4707
|
|
|
4658
4708
|
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 { schema, normalize } from 'normalizr';
|
|
@@ -7,31 +7,69 @@ import * as Api from '../../services/api';
|
|
|
7
7
|
import * as types from './constants';
|
|
8
8
|
import { saveCdnConfigs, removeAllCdnLocalStorageItems } from '../../utils/cdnTransformation';
|
|
9
9
|
import { COPY_OF } from '../../constants/unified';
|
|
10
|
+
import { fetchSmsTemplatesFromQuery } from './utils/smsTemplatesListApi';
|
|
10
11
|
import { ZALO_TEMPLATE_INFO_REQUEST } from '../Zalo/constants';
|
|
11
12
|
import { getTemplateInfoById } from '../Zalo/saga';
|
|
12
|
-
|
|
13
|
-
export function*
|
|
13
|
+
|
|
14
|
+
export function* getLocalSmsTemplates(action) {
|
|
14
15
|
try {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const fetched = yield call(
|
|
17
|
+
fetchSmsTemplatesFromQuery,
|
|
18
|
+
action.queryParams,
|
|
19
|
+
action.intlCopyOf,
|
|
20
|
+
);
|
|
21
|
+
if (typeof action.onSuccess === 'function') {
|
|
22
|
+
yield call(action.onSuccess, fetched);
|
|
23
|
+
}
|
|
24
|
+
} catch (error) {
|
|
25
|
+
if (typeof action.onFailure === 'function') {
|
|
26
|
+
yield call(action.onFailure, error);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function* getAllTemplates(action) {
|
|
32
|
+
try {
|
|
33
|
+
if (action.channel && String(action.channel).toLowerCase() === 'sms') {
|
|
34
|
+
const fetched = yield call(
|
|
35
|
+
fetchSmsTemplatesFromQuery,
|
|
36
|
+
action.queryParams,
|
|
37
|
+
action.intlCopyOf,
|
|
38
|
+
);
|
|
39
|
+
yield put({
|
|
40
|
+
type: types.GET_ALL_TEMPLATES_SUCCESS,
|
|
41
|
+
data: fetched.channelTemplates,
|
|
42
|
+
weCRMTemplate: fetched.weCRMTemplate,
|
|
43
|
+
isReset: get(action, 'queryParams.page') === 1,
|
|
44
|
+
});
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const result = yield call(Api.getAllTemplates, action);
|
|
49
|
+
const channelTemplates = (action.channel === 'wechat')
|
|
50
|
+
? { templates: [...result.response.mapped, ...result.response.richmedia] }
|
|
51
|
+
: result.response;
|
|
52
|
+
if (action.channel === 'wechat' && action.queryParams && action.queryParams.sortBy && action.queryParams.sortBy.toLocaleLowerCase() === ("Most Recent").toLocaleLowerCase()) {
|
|
19
53
|
channelTemplates.templates.sort((a, b) => {
|
|
20
54
|
const dateA = new Date(a.updatedAt);
|
|
21
55
|
const dateB = new Date(b.updatedAt);
|
|
22
56
|
return dateB - dateA;
|
|
23
57
|
});
|
|
24
|
-
} else if (
|
|
58
|
+
} else if (action.channel === 'wechat' && action.queryParams && action.queryParams.sortBy && action.queryParams.sortBy.toLocaleLowerCase() === ("Alphabetically").toLocaleLowerCase()) {
|
|
25
59
|
channelTemplates.templates.sort((a, b) => b.name - a.name);
|
|
26
60
|
}
|
|
27
|
-
|
|
28
|
-
if (channel.intlCopyOf && channelTemplates?.templates) {
|
|
61
|
+
if (action.intlCopyOf && channelTemplates?.templates) {
|
|
29
62
|
channelTemplates.templates = channelTemplates.templates.map((template) => ({
|
|
30
63
|
...template,
|
|
31
|
-
name: template.name.replace(new RegExp(COPY_OF, 'g'),
|
|
64
|
+
name: template.name.replace(new RegExp(COPY_OF, 'g'), action.intlCopyOf),
|
|
32
65
|
}));
|
|
33
66
|
}
|
|
34
|
-
yield put({
|
|
67
|
+
yield put({
|
|
68
|
+
type: types.GET_ALL_TEMPLATES_SUCCESS,
|
|
69
|
+
data: channelTemplates,
|
|
70
|
+
weCRMTemplate: result.response.unMapped,
|
|
71
|
+
isReset: get(action, 'queryParams.page') === 1,
|
|
72
|
+
});
|
|
35
73
|
} catch (error) {
|
|
36
74
|
yield put({ type: types.GET_ALL_TEMPLATES_FAILURE, error });
|
|
37
75
|
}
|
|
@@ -205,6 +243,11 @@ export function* watchGetAllTemplates() {
|
|
|
205
243
|
yield takeLatest(types.GET_ALL_TEMPLATES_REQUEST, getAllTemplates);
|
|
206
244
|
}
|
|
207
245
|
|
|
246
|
+
|
|
247
|
+
export function* watchGetLocalSmsTemplates() {
|
|
248
|
+
yield takeEvery(types.GET_LOCAL_SMS_TEMPLATES_REQUEST, getLocalSmsTemplates);
|
|
249
|
+
}
|
|
250
|
+
|
|
208
251
|
export function* watchDeleteTemplate() {
|
|
209
252
|
yield takeLatest(types.DELETE_TEMPLATE_REQUEST, deleteTemplate);
|
|
210
253
|
}
|
|
@@ -258,6 +301,7 @@ export function* watchForGetTemplateInfoById() {
|
|
|
258
301
|
// All sagas to be loaded
|
|
259
302
|
export default [
|
|
260
303
|
watchGetAllTemplates,
|
|
304
|
+
watchGetLocalSmsTemplates,
|
|
261
305
|
watchDeleteTemplate,
|
|
262
306
|
watchDeleteRcsTemplate,
|
|
263
307
|
watchGetUserList,
|
|
@@ -274,6 +318,7 @@ export default [
|
|
|
274
318
|
export function* v2TemplateSaga() {
|
|
275
319
|
yield all([
|
|
276
320
|
watchGetAllTemplates(),
|
|
321
|
+
watchGetLocalSmsTemplates(),
|
|
277
322
|
watchDeleteTemplate(),
|
|
278
323
|
watchDeleteRcsTemplate(),
|
|
279
324
|
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
|
+
});
|