@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
|
@@ -10,8 +10,8 @@ import { connect } from 'react-redux';
|
|
|
10
10
|
import { injectIntl, intlShape, FormattedMessage } from 'react-intl';
|
|
11
11
|
import { createStructuredSelector } from 'reselect';
|
|
12
12
|
import { bindActionCreators, compose } from 'redux';
|
|
13
|
-
import { CapTab, CapCustomCard, CapButton, CapHeader,
|
|
14
|
-
import { find, get } from 'lodash';
|
|
13
|
+
import { CapTab, CapCustomCard, CapButton, CapHeader, CapIcon, CapSpin, CapTooltip } from '@capillarytech/cap-ui-library';
|
|
14
|
+
import { find, get, pick } from 'lodash';
|
|
15
15
|
import Helmet from 'react-helmet';
|
|
16
16
|
|
|
17
17
|
import { UserIsAuthenticated } from '../../utils/authWrapper';
|
|
@@ -36,13 +36,14 @@ import { makeSelectAuthenticated, selectCurrentOrgDetails } from "../../v2Contai
|
|
|
36
36
|
import {
|
|
37
37
|
CALL_TASK,
|
|
38
38
|
COMMON_CHANNELS,
|
|
39
|
+
LOCAL_TEMPLATE_CONFIG_KEYS_FOR_PICK,
|
|
39
40
|
LOYALTY_SUPPORTED_ACTION,
|
|
40
41
|
MOBILE_PUSH,
|
|
41
42
|
NORMALIZED_CHANNEL_ALIASES,
|
|
42
43
|
SMS,
|
|
43
44
|
} from "../CreativesContainer/constants";
|
|
44
45
|
|
|
45
|
-
const {CapCustomCardList} = CapCustomCard;
|
|
46
|
+
const { CapCustomCardList } = CapCustomCard;
|
|
46
47
|
|
|
47
48
|
const StyledCapTab = withStyles(CapTab, CapTabStyle);
|
|
48
49
|
export class TemplatesV2 extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
|
@@ -119,9 +120,9 @@ export class TemplatesV2 extends React.Component { // eslint-disable-line react/
|
|
|
119
120
|
return !normalizedChannelsToHideSet.has(paneKey);
|
|
120
121
|
});
|
|
121
122
|
|
|
122
|
-
if (isFullMode) {
|
|
123
|
-
filteredPanes.push({ content: <div></div>, tab: intl.formatMessage(messages.gallery), key:
|
|
124
|
-
} else {
|
|
123
|
+
if (isFullMode && !normalizedChannelsToHideSet.has(normalizeChannel(ASSETS))) {
|
|
124
|
+
filteredPanes.push({ content: <div></div>, tab: intl.formatMessage(messages.gallery), key: ASSETS });
|
|
125
|
+
} else if (!isFullMode) {
|
|
125
126
|
// Add special-mode panes only when not hidden (use normalized checks)
|
|
126
127
|
if (!normalizedChannelsToHideSet.has(CALL_TASK.toLowerCase())) {
|
|
127
128
|
filteredPanes.push({ content: <div></div>, tab: intl.formatMessage(messages.callTask), key: CALL_TASK.toLowerCase() });
|
|
@@ -222,7 +223,8 @@ export class TemplatesV2 extends React.Component { // eslint-disable-line react/
|
|
|
222
223
|
this.setState({selectedChannel: nextProps.channel, panes });
|
|
223
224
|
}
|
|
224
225
|
}
|
|
225
|
-
|
|
226
|
+
|
|
227
|
+
getTemplateDataForGrid = ({ templates, handlers, filterContent, channel, isLoading, loadingTip }) => {
|
|
226
228
|
const currentChannel = channel.toUpperCase();
|
|
227
229
|
const cardDataList = templates.map((template) => {
|
|
228
230
|
const templateData =
|
|
@@ -248,7 +250,8 @@ export class TemplatesV2 extends React.Component { // eslint-disable-line react/
|
|
|
248
250
|
</CapSpin>
|
|
249
251
|
|
|
250
252
|
</div>);
|
|
251
|
-
}
|
|
253
|
+
};
|
|
254
|
+
|
|
252
255
|
getGalleryComponent = (location) => <Gallery location={location} isFullMode={this.props.isFullMode}/>
|
|
253
256
|
getCallTaskComponent = () => (
|
|
254
257
|
<CallTask
|
|
@@ -312,6 +315,29 @@ export class TemplatesV2 extends React.Component { // eslint-disable-line react/
|
|
|
312
315
|
if (messageStrategy !== "X_ENGAGE" && channel === 'facebook' && !isFullMode) {
|
|
313
316
|
return this.getFacebookComponent();
|
|
314
317
|
}
|
|
318
|
+
const localConfig = this.props.localTemplatesConfig || pick(this.props, LOCAL_TEMPLATE_CONFIG_KEYS_FOR_PICK);
|
|
319
|
+
const useLocalTemplates = localConfig.useLocalTemplates;
|
|
320
|
+
if (useLocalTemplates && channel === (this.props.channel || 'sms')) {
|
|
321
|
+
// Reuse full Templates component (same UI as Redux flow) with local data only
|
|
322
|
+
const location = { pathname: `/${channel}`, search: '', query: !this.props.isFullMode ? { type: 'embedded', module: 'library' } : {} };
|
|
323
|
+
return (
|
|
324
|
+
<Templates
|
|
325
|
+
key={`${channel}-local`}
|
|
326
|
+
location={location}
|
|
327
|
+
route={{ name: channel }}
|
|
328
|
+
router={this.props.router}
|
|
329
|
+
isFullMode={this.props.isFullMode}
|
|
330
|
+
createNew={this.props.createNew}
|
|
331
|
+
onSelectTemplate={this.props.onSelectTemplate}
|
|
332
|
+
handlePeviewTemplate={this.props.handlePeviewTemplate}
|
|
333
|
+
messageStrategy={this.props.messageStrategy}
|
|
334
|
+
smsRegister={this.props.smsRegister}
|
|
335
|
+
hideTestAndPreviewBtn={this.props.hideTestAndPreviewBtn}
|
|
336
|
+
localTemplatesConfig={localConfig}
|
|
337
|
+
/>
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
|
|
315
341
|
const location = {pathname: `/${channel}`, search: '', query};
|
|
316
342
|
switch (channel) {
|
|
317
343
|
case 'call_task':
|
|
@@ -361,29 +387,55 @@ export class TemplatesV2 extends React.Component { // eslint-disable-line react/
|
|
|
361
387
|
}
|
|
362
388
|
render() {
|
|
363
389
|
const { isFullMode, className, cap = {}, Global = {}} = this.props;
|
|
390
|
+
const useLocalTemplates = get(this.props, 'localTemplatesConfig.useLocalTemplates', false);
|
|
364
391
|
const { accessiblePermissions = []} = cap.user || Global.user || {};
|
|
365
392
|
let isCreativeAccessible = true;
|
|
366
393
|
if (!accessiblePermissions.includes(CREATIVES_UI_VIEW)) {
|
|
367
394
|
isCreativeAccessible = false;
|
|
368
395
|
}
|
|
396
|
+
// Recompute active pane content every render so local-list mode updates
|
|
397
|
+
// (templates/loading/search UI) are not stuck with the initial cached pane.
|
|
398
|
+
const panes = this.setChannelContent(this.state.selectedChannel, this.state.panes);
|
|
399
|
+
const hideChannelTabsForLocalSms = useLocalTemplates && panes.length === 1;
|
|
400
|
+
const activeLocalPane = hideChannelTabsForLocalSms
|
|
401
|
+
? (panes.find(
|
|
402
|
+
(p) => String(p.key).toLowerCase() === String(this.state.selectedChannel).toLowerCase(),
|
|
403
|
+
) || panes[0])
|
|
404
|
+
: null;
|
|
369
405
|
return (
|
|
370
406
|
!isCreativeAccessible ? <AccessForbidden /> : (
|
|
371
|
-
<div
|
|
372
|
-
{isFullMode
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
panes={this.state.panes}
|
|
382
|
-
onChange={this.channelChange}
|
|
383
|
-
activeKey={this.state.selectedChannel}
|
|
384
|
-
defaultActiveKey={this.state.selectedChannel}
|
|
385
|
-
isFullMode={isFullMode}
|
|
407
|
+
<div
|
|
408
|
+
className={`${className} creatives-templates-container ${isFullMode ? 'fullmode' : 'library-mode'}${useLocalTemplates ? ' creatives-templates-container--local-sms' : ''}`}
|
|
409
|
+
data-testid="cap-wrapper"
|
|
410
|
+
>
|
|
411
|
+
{isFullMode && !useLocalTemplates && (
|
|
412
|
+
<Helmet
|
|
413
|
+
title={this.props.intl.formatMessage(messages.creatives)}
|
|
414
|
+
meta={[
|
|
415
|
+
{ name: 'description', content: this.props.intl.formatMessage(messages.creativesDesc) },
|
|
416
|
+
]}
|
|
386
417
|
/>
|
|
418
|
+
)}
|
|
419
|
+
<div className="component-wrapper">
|
|
420
|
+
{isFullMode && (
|
|
421
|
+
<CapHeader
|
|
422
|
+
title={<FormattedMessage {...messages.creatives} />}
|
|
423
|
+
{...(!useLocalTemplates && {
|
|
424
|
+
description: <FormattedMessage {...messages.creativesDesc} />,
|
|
425
|
+
})}
|
|
426
|
+
/>
|
|
427
|
+
)}
|
|
428
|
+
{hideChannelTabsForLocalSms ? (
|
|
429
|
+
<div className="templates-v2-local-sms-pane">{activeLocalPane?.content}</div>
|
|
430
|
+
) : (
|
|
431
|
+
<StyledCapTab
|
|
432
|
+
panes={panes}
|
|
433
|
+
onChange={this.channelChange}
|
|
434
|
+
activeKey={this.state.selectedChannel}
|
|
435
|
+
defaultActiveKey={this.state.selectedChannel}
|
|
436
|
+
isFullMode={isFullMode}
|
|
437
|
+
/>
|
|
438
|
+
)}
|
|
387
439
|
</div>
|
|
388
440
|
</div>
|
|
389
441
|
)
|
|
@@ -415,6 +467,17 @@ TemplatesV2.propTypes = {
|
|
|
415
467
|
currentOrgDetails: PropTypes.object,
|
|
416
468
|
restrictPersonalization: PropTypes.bool,
|
|
417
469
|
isAnonymousType: PropTypes.bool,
|
|
470
|
+
// Optional: reuse grid UI with local template list (e.g. SMS fallback). Pass object or same keys as individual props.
|
|
471
|
+
localTemplatesConfig: PropTypes.shape({
|
|
472
|
+
useLocalTemplates: PropTypes.bool,
|
|
473
|
+
localTemplates: PropTypes.arrayOf(PropTypes.object),
|
|
474
|
+
localTemplatesLoading: PropTypes.bool,
|
|
475
|
+
localTemplatesLoadingTip: PropTypes.string,
|
|
476
|
+
localTemplatesFilterContent: PropTypes.node,
|
|
477
|
+
localTemplatesFooterContent: PropTypes.node,
|
|
478
|
+
localTemplatesOnPageChange: PropTypes.func,
|
|
479
|
+
localTemplatesUseSkeleton: PropTypes.bool,
|
|
480
|
+
}),
|
|
418
481
|
};
|
|
419
482
|
|
|
420
483
|
TemplatesV2.defaultProps = {
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedded SMS template list: localTemplatesConfig + SMS-only channel visibility (RCS SMS fallback).
|
|
3
|
+
*/
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { injectIntl } from 'react-intl';
|
|
6
|
+
import '@testing-library/jest-dom';
|
|
7
|
+
import cloneDeep from 'lodash/cloneDeep';
|
|
8
|
+
import { Provider } from 'react-redux';
|
|
9
|
+
import { configureStore } from '@capillarytech/vulcan-react-sdk/utils';
|
|
10
|
+
import history from '../../../utils/history';
|
|
11
|
+
import { initialReducer } from '../../../initialReducer';
|
|
12
|
+
import { render, screen } from '../../../utils/test-utils';
|
|
13
|
+
import { TemplatesV2 } from '../index';
|
|
14
|
+
import { Templates, authData, currentOrgDetails as currentOrgDetailsMock } from './mockData';
|
|
15
|
+
import { CHANNELS_TO_HIDE_FOR_SMS_ONLY } from '../../../v2Components/SmsFallback/constants';
|
|
16
|
+
|
|
17
|
+
const mockTemplates = jest.fn(() => <div data-testid="templates-mock">Templates</div>);
|
|
18
|
+
jest.mock('v2Containers/Templates', () => ({
|
|
19
|
+
__esModule: true,
|
|
20
|
+
default: (props) => mockTemplates(props),
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
jest.mock('../../../utils/authWrapper', () => ({
|
|
24
|
+
UserIsAuthenticated: jest.fn((config) => config),
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
const ComponentToRender = injectIntl(TemplatesV2);
|
|
28
|
+
const renderComponent = (p) => {
|
|
29
|
+
const store = configureStore({}, initialReducer, history);
|
|
30
|
+
return render(
|
|
31
|
+
<Provider store={store}>
|
|
32
|
+
<ComponentToRender {...p} />
|
|
33
|
+
</Provider>,
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
describe('TemplatesV2 local SMS templates (embedded)', () => {
|
|
38
|
+
const templateActions = {
|
|
39
|
+
templateActions: jest.fn(),
|
|
40
|
+
deleteTemplate: jest.fn(),
|
|
41
|
+
getAccountsSettings: jest.fn(),
|
|
42
|
+
getAllTemplates: jest.fn(),
|
|
43
|
+
getCdnTransformationConfig: jest.fn(),
|
|
44
|
+
getDefaultBeeTemplates: jest.fn(),
|
|
45
|
+
getSenderDetails: jest.fn(),
|
|
46
|
+
getTemplateDetails: jest.fn(),
|
|
47
|
+
getUserList: jest.fn(),
|
|
48
|
+
getWeCrmAccounts: jest.fn(),
|
|
49
|
+
handleHtmlUpload: jest.fn(),
|
|
50
|
+
handleZipUpload: jest.fn(),
|
|
51
|
+
resetAccount: jest.fn(),
|
|
52
|
+
resetTemplate: jest.fn(),
|
|
53
|
+
resetTemplateData: jest.fn(),
|
|
54
|
+
resetTemplateStoreData: jest.fn(),
|
|
55
|
+
resetUploadData: jest.fn(),
|
|
56
|
+
setBEETemplate: jest.fn(),
|
|
57
|
+
setChannelAccount: jest.fn(),
|
|
58
|
+
setEdmTemplate: jest.fn(),
|
|
59
|
+
setFacebookAccount: jest.fn(),
|
|
60
|
+
setViberAccount: jest.fn(),
|
|
61
|
+
setWeChatAccount: jest.fn(),
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const baseProps = {
|
|
65
|
+
cap: {
|
|
66
|
+
user: { accessiblePermissions: ['CREATIVES_UI_VIEW'] },
|
|
67
|
+
},
|
|
68
|
+
actions: { defaultAction: jest.fn(), getTemplates: jest.fn() },
|
|
69
|
+
Templates,
|
|
70
|
+
TemplatesList: Templates?.templates,
|
|
71
|
+
authData,
|
|
72
|
+
templateActions,
|
|
73
|
+
isFullMode: false,
|
|
74
|
+
className: 'embed-test',
|
|
75
|
+
channel: 'sms',
|
|
76
|
+
channelsToHide: CHANNELS_TO_HIDE_FOR_SMS_ONLY,
|
|
77
|
+
channelsToDisable: [],
|
|
78
|
+
onChannelChange: jest.fn(),
|
|
79
|
+
enableNewChannels: [],
|
|
80
|
+
/** Without JP_LOCALE_HIDE_FEATURE so SMS panes are not stripped to Email/Line/Gallery only */
|
|
81
|
+
currentOrgDetails: {
|
|
82
|
+
...currentOrgDetailsMock,
|
|
83
|
+
accessibleFeatures: (currentOrgDetailsMock.accessibleFeatures || []).filter(
|
|
84
|
+
(f) => f !== 'JP_LOCALE_HIDE_FEATURE',
|
|
85
|
+
),
|
|
86
|
+
},
|
|
87
|
+
location: {
|
|
88
|
+
pathname: 'v2',
|
|
89
|
+
basename: '/creatives/ui/',
|
|
90
|
+
query: {},
|
|
91
|
+
},
|
|
92
|
+
router: { push: jest.fn() },
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
beforeEach(() => {
|
|
96
|
+
mockTemplates.mockClear();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('adds local-sms container class and single-pane layout when only SMS is visible', () => {
|
|
100
|
+
const p = cloneDeep(baseProps);
|
|
101
|
+
p.localTemplatesConfig = {
|
|
102
|
+
useLocalTemplates: true,
|
|
103
|
+
localTemplates: [],
|
|
104
|
+
localTemplatesLoading: false,
|
|
105
|
+
};
|
|
106
|
+
renderComponent(p);
|
|
107
|
+
|
|
108
|
+
const wrapper = screen.getByTestId('cap-wrapper');
|
|
109
|
+
expect(wrapper).toHaveClass('creatives-templates-container--local-sms');
|
|
110
|
+
expect(document.querySelector('.templates-v2-local-sms-pane')).toBeTruthy();
|
|
111
|
+
expect(mockTemplates).toHaveBeenCalled();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('passes localTemplatesConfig into Templates for the SMS pane', () => {
|
|
115
|
+
const localConfig = {
|
|
116
|
+
useLocalTemplates: true,
|
|
117
|
+
localTemplates: [{ _id: '1', name: 'A' }],
|
|
118
|
+
localTemplatesLoading: false,
|
|
119
|
+
};
|
|
120
|
+
const p = cloneDeep(baseProps);
|
|
121
|
+
p.localTemplatesConfig = localConfig;
|
|
122
|
+
renderComponent(p);
|
|
123
|
+
|
|
124
|
+
expect(mockTemplates).toHaveBeenCalled();
|
|
125
|
+
const passed = mockTemplates.mock.calls.find(
|
|
126
|
+
(call) => call[0] && call[0].localTemplatesConfig && call[0].localTemplatesConfig.useLocalTemplates,
|
|
127
|
+
);
|
|
128
|
+
expect(passed).toBeTruthy();
|
|
129
|
+
expect(passed[0].localTemplatesConfig).toMatchObject(localConfig);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
@@ -82,6 +82,7 @@ export const Viber = (props) => {
|
|
|
82
82
|
viberData = {},
|
|
83
83
|
selectedOfferDetails = [],
|
|
84
84
|
eventContextTags,
|
|
85
|
+
waitEventContextTags,
|
|
85
86
|
// TestAndPreviewSlidebox props
|
|
86
87
|
showTestAndPreviewSlidebox: propsShowTestAndPreviewSlidebox,
|
|
87
88
|
handleTestAndPreview: propsHandleTestAndPreview,
|
|
@@ -232,6 +233,8 @@ export const Viber = (props) => {
|
|
|
232
233
|
tagsParam: tags,
|
|
233
234
|
location,
|
|
234
235
|
tagModule: 'outbound',
|
|
236
|
+
eventContextTags,
|
|
237
|
+
waitEventContextTags,
|
|
235
238
|
isFullMode,
|
|
236
239
|
}) || {};
|
|
237
240
|
if (value.trim() === '') {
|
|
@@ -287,6 +290,7 @@ export const Viber = (props) => {
|
|
|
287
290
|
userLocale={localStorage.getItem("jlocale") || "en"}
|
|
288
291
|
selectedOfferDetails={selectedOfferDetails}
|
|
289
292
|
eventContextTags={eventContextTags}
|
|
293
|
+
waitEventContextTags={waitEventContextTags}
|
|
290
294
|
/>
|
|
291
295
|
</CapColumn>
|
|
292
296
|
<div className="viber-textarea-wrapper">
|
|
@@ -592,6 +596,7 @@ export const Viber = (props) => {
|
|
|
592
596
|
userLocale={localStorage.getItem("jlocale") || "en"}
|
|
593
597
|
selectedOfferDetails={selectedOfferDetails}
|
|
594
598
|
eventContextTags={eventContextTags}
|
|
599
|
+
waitEventContextTags={waitEventContextTags}
|
|
595
600
|
/>
|
|
596
601
|
<CapColumn className="cta-actions">
|
|
597
602
|
<CapButton
|
|
@@ -84,6 +84,7 @@ const MemoizedTagList = memo(({
|
|
|
84
84
|
injectedTags,
|
|
85
85
|
selectedOfferDetails,
|
|
86
86
|
eventContextTags,
|
|
87
|
+
waitEventContextTags,
|
|
87
88
|
forwardedTags,
|
|
88
89
|
onTagSelect,
|
|
89
90
|
restrictPersonalization = false,
|
|
@@ -99,6 +100,7 @@ const MemoizedTagList = memo(({
|
|
|
99
100
|
injectedTags={injectedTags}
|
|
100
101
|
selectedOfferDetails={selectedOfferDetails}
|
|
101
102
|
eventContextTags={eventContextTags}
|
|
103
|
+
waitEventContextTags={waitEventContextTags}
|
|
102
104
|
forwardedTags={forwardedTags}
|
|
103
105
|
onTagSelect={onTagSelect}
|
|
104
106
|
restrictPersonalization={restrictPersonalization}
|
|
@@ -116,6 +118,7 @@ const MemoizedTagList = memo(({
|
|
|
116
118
|
&& prevProps.injectedTags === nextProps.injectedTags
|
|
117
119
|
&& prevProps.selectedOfferDetails === nextProps.selectedOfferDetails
|
|
118
120
|
&& prevProps.eventContextTags === nextProps.eventContextTags
|
|
121
|
+
&& prevProps.waitEventContextTags === nextProps.waitEventContextTags
|
|
119
122
|
&& prevProps.forwardedTags === nextProps.forwardedTags
|
|
120
123
|
&& prevProps.onTagSelect === nextProps.onTagSelect
|
|
121
124
|
&& prevProps.restrictPersonalization === nextProps.restrictPersonalization
|
|
@@ -152,6 +155,7 @@ const WebPushCreate = ({
|
|
|
152
155
|
forwardedTags,
|
|
153
156
|
selectedOfferDetails = [],
|
|
154
157
|
eventContextTags = [],
|
|
158
|
+
waitEventContextTags = {},
|
|
155
159
|
templateActions: templateActionsProps,
|
|
156
160
|
Templates,
|
|
157
161
|
restrictPersonalization = false,
|
|
@@ -232,6 +236,7 @@ const WebPushCreate = ({
|
|
|
232
236
|
supportedTags: memoizedSupportedTags,
|
|
233
237
|
injectedTags,
|
|
234
238
|
eventContextTags,
|
|
239
|
+
waitEventContextTags,
|
|
235
240
|
});
|
|
236
241
|
const { tags, handleOnTagsContextChange, validationConfig } = tagState;
|
|
237
242
|
const { weCrmAccounts } = Templates;
|
|
@@ -837,12 +842,13 @@ const WebPushCreate = ({
|
|
|
837
842
|
injectedTags,
|
|
838
843
|
selectedOfferDetails,
|
|
839
844
|
eventContextTags,
|
|
845
|
+
waitEventContextTags,
|
|
840
846
|
forwardedTags,
|
|
841
847
|
restrictPersonalization,
|
|
842
848
|
disabled: restrictPersonalization,
|
|
843
849
|
disableTooltipMsg: restrictPersonalization ? formatMessage(messages.personalizationNotSupportedAnonymous) : undefined,
|
|
844
850
|
}),
|
|
845
|
-
[tags, injectedTags, selectedOfferDetails, eventContextTags, forwardedTags, restrictPersonalization, formatMessage],
|
|
851
|
+
[tags, injectedTags, selectedOfferDetails, eventContextTags, waitEventContextTags, forwardedTags, restrictPersonalization, formatMessage],
|
|
846
852
|
);
|
|
847
853
|
|
|
848
854
|
// Memoized TagList components with optimized props
|
|
@@ -1083,6 +1089,7 @@ WebPushCreate.propTypes = {
|
|
|
1083
1089
|
forwardedTags: PropTypes.object,
|
|
1084
1090
|
selectedOfferDetails: PropTypes.array,
|
|
1085
1091
|
eventContextTags: PropTypes.array,
|
|
1092
|
+
waitEventContextTags: PropTypes.object,
|
|
1086
1093
|
templateActions: PropTypes.object,
|
|
1087
1094
|
restrictPersonalization: PropTypes.bool,
|
|
1088
1095
|
};
|
|
@@ -1111,6 +1118,7 @@ WebPushCreate.defaultProps = {
|
|
|
1111
1118
|
forwardedTags: {},
|
|
1112
1119
|
selectedOfferDetails: [],
|
|
1113
1120
|
eventContextTags: [],
|
|
1121
|
+
waitEventContextTags: {},
|
|
1114
1122
|
templateActions: {},
|
|
1115
1123
|
Templates: {},
|
|
1116
1124
|
restrictPersonalization: false,
|
|
@@ -118,6 +118,7 @@ import { ANDROID } from '../../v2Components/CommonTestAndPreview/constants';
|
|
|
118
118
|
import CapImageUpload from '../../v2Components/CapImageUpload';
|
|
119
119
|
import TagList from '../TagList';
|
|
120
120
|
import { validateTags } from '../../utils/tagValidations';
|
|
121
|
+
import { splitContentByOrderedVarTokens } from '../../utils/templateVarUtils';
|
|
121
122
|
import { capitalizeString } from '../../utils/Formatter';
|
|
122
123
|
import CapWhatsappCTA from '../../v2Components/CapWhatsappCTA';
|
|
123
124
|
import {
|
|
@@ -180,6 +181,7 @@ export const Whatsapp = (props) => {
|
|
|
180
181
|
getFormData,
|
|
181
182
|
selectedOfferDetails,
|
|
182
183
|
eventContextTags,
|
|
184
|
+
waitEventContextTags = {},
|
|
183
185
|
metaDataStatus = "",
|
|
184
186
|
showTestAndPreviewSlidebox: propsShowTestAndPreviewSlidebox,
|
|
185
187
|
handleTestAndPreview: propsHandleTestAndPreview,
|
|
@@ -482,28 +484,10 @@ export const Whatsapp = (props) => {
|
|
|
482
484
|
);
|
|
483
485
|
};
|
|
484
486
|
|
|
485
|
-
const converStringToVarArr = (validVarArr, content) => {
|
|
486
|
-
const templateVarArray = [];
|
|
487
|
-
while (content?.length !== 0) {
|
|
488
|
-
//converting content string to an array split at var
|
|
489
|
-
const index = content.indexOf(validVarArr?.[0]);
|
|
490
|
-
if (index !== -1) {
|
|
491
|
-
templateVarArray.push(content.substring(0, index)); //push string before var
|
|
492
|
-
templateVarArray.push(validVarArr?.[0]); //push var
|
|
493
|
-
content = content.substring(index + validVarArr?.[0]?.length, content?.length); //remaining str
|
|
494
|
-
validVarArr?.shift(); //remove considered var
|
|
495
|
-
} else {
|
|
496
|
-
templateVarArray.push(content); //remaining str
|
|
497
|
-
break;
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
return templateVarArray;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
487
|
const computeTextMessage = (msg, varMap, regex) => {
|
|
504
488
|
const validVarArr = msg?.match(regex) || [];
|
|
505
489
|
//conerting msg string to variable arr
|
|
506
|
-
const templateHeaderArray =
|
|
490
|
+
const templateHeaderArray = splitContentByOrderedVarTokens(validVarArr, msg);
|
|
507
491
|
if (templateHeaderArray?.length !== 0) {
|
|
508
492
|
let clonedVarMap = {};
|
|
509
493
|
if (!isEmpty(varMap)) {
|
|
@@ -557,7 +541,7 @@ export const Whatsapp = (props) => {
|
|
|
557
541
|
setUnsubscribeRequired(true);
|
|
558
542
|
}
|
|
559
543
|
//converting msg string to variable arr
|
|
560
|
-
const templateMessageArray =
|
|
544
|
+
const templateMessageArray = splitContentByOrderedVarTokens(validVarArr, msg);
|
|
561
545
|
updateTempMsgArray(templateMessageArray.filter((i) => i === 0 || i));
|
|
562
546
|
};
|
|
563
547
|
|
|
@@ -950,6 +934,7 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
|
|
|
950
934
|
injectedTags={injectedTags || {}}
|
|
951
935
|
selectedOfferDetails={selectedOfferDetails}
|
|
952
936
|
eventContextTags={eventContextTags}
|
|
937
|
+
waitEventContextTags={waitEventContextTags}
|
|
953
938
|
/>
|
|
954
939
|
)}
|
|
955
940
|
</>
|
|
@@ -1951,6 +1936,7 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
|
|
|
1951
1936
|
injectedTags={injectedTags || {}}
|
|
1952
1937
|
selectedOfferDetails={selectedOfferDetails}
|
|
1953
1938
|
eventContextTags={eventContextTags}
|
|
1939
|
+
waitEventContextTags={waitEventContextTags}
|
|
1954
1940
|
/>
|
|
1955
1941
|
)
|
|
1956
1942
|
: !isAuthenticationTemplate && (
|
|
@@ -2757,6 +2743,7 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
|
|
|
2757
2743
|
injectedTags={injectedTags || {}}
|
|
2758
2744
|
selectedOfferDetails={selectedOfferDetails}
|
|
2759
2745
|
eventContextTags={eventContextTags}
|
|
2746
|
+
waitEventContextTags={waitEventContextTags}
|
|
2760
2747
|
/>
|
|
2761
2748
|
)
|
|
2762
2749
|
}
|
|
@@ -2875,6 +2862,7 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
|
|
|
2875
2862
|
injectedTags={injectedTags || {}}
|
|
2876
2863
|
selectedOfferDetails={selectedOfferDetails}
|
|
2877
2864
|
eventContextTags={eventContextTags}
|
|
2865
|
+
waitEventContextTags={waitEventContextTags}
|
|
2878
2866
|
/>
|
|
2879
2867
|
)}
|
|
2880
2868
|
{isBtnTypeQuickReply && (
|