@capillarytech/creatives-library 8.0.318 → 8.0.320

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.
Files changed (139) hide show
  1. package/constants/unified.js +15 -0
  2. package/package.json +1 -1
  3. package/services/api.js +6 -0
  4. package/services/tests/api.test.js +7 -0
  5. package/utils/common.js +6 -1
  6. package/utils/templateVarUtils.js +172 -0
  7. package/utils/tests/templateVarUtils.test.js +160 -0
  8. package/v2Components/CapTagList/index.js +10 -0
  9. package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +70 -49
  10. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +8 -2
  11. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +207 -21
  12. package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +16 -0
  13. package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +85 -10
  14. package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +30 -0
  15. package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +79 -11
  16. package/v2Components/CommonTestAndPreview/SendTestMessage.js +11 -5
  17. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +20 -1
  18. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +133 -4
  19. package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +12 -0
  20. package/v2Components/CommonTestAndPreview/constants.js +38 -0
  21. package/v2Components/CommonTestAndPreview/index.js +693 -155
  22. package/v2Components/CommonTestAndPreview/messages.js +41 -3
  23. package/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
  24. package/v2Components/CommonTestAndPreview/sagas.js +15 -6
  25. package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +352 -0
  26. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +269 -1
  27. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +118 -5
  28. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +341 -0
  29. package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +25 -4
  30. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +199 -1
  31. package/v2Components/CommonTestAndPreview/tests/index.test.js +132 -4
  32. package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
  33. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +2 -2
  34. package/v2Components/FormBuilder/index.js +7 -1
  35. package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +87 -0
  36. package/v2Components/SmsFallback/constants.js +73 -0
  37. package/v2Components/SmsFallback/index.js +956 -0
  38. package/v2Components/SmsFallback/index.scss +265 -0
  39. package/v2Components/SmsFallback/messages.js +78 -0
  40. package/v2Components/SmsFallback/smsFallbackUtils.js +107 -0
  41. package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +50 -0
  42. package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +147 -0
  43. package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +304 -0
  44. package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +197 -0
  45. package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +261 -0
  46. package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +422 -0
  47. package/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
  48. package/v2Components/TestAndPreviewSlidebox/index.js +8 -1
  49. package/v2Components/TestAndPreviewSlidebox/sagas.js +11 -4
  50. package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +3 -1
  51. package/v2Components/VarSegmentMessageEditor/constants.js +2 -0
  52. package/v2Components/VarSegmentMessageEditor/index.js +125 -0
  53. package/v2Components/VarSegmentMessageEditor/index.scss +46 -0
  54. package/v2Containers/CommunicationFlow/CommunicationFlow.js +291 -0
  55. package/v2Containers/CommunicationFlow/CommunicationFlow.scss +25 -0
  56. package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +255 -0
  57. package/v2Containers/CommunicationFlow/constants.js +200 -0
  58. package/v2Containers/CommunicationFlow/index.js +102 -0
  59. package/v2Containers/CommunicationFlow/messages.js +346 -0
  60. package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.js +522 -0
  61. package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.scss +170 -0
  62. package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/Tests/ChannelSelectionStep.test.js +796 -0
  63. package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/index.js +5 -0
  64. package/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/CommunicationStrategyStep.js +95 -0
  65. package/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/Tests/CommunicationStrategyStep.test.js +133 -0
  66. package/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/index.js +5 -0
  67. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.js +289 -0
  68. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.scss +70 -0
  69. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.js +319 -0
  70. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.scss +69 -0
  71. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +616 -0
  72. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +577 -0
  73. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/deliverySettingsConfig.test.js +1111 -0
  74. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/deliverySettingsConfig.js +696 -0
  75. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/index.js +7 -0
  76. package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.js +102 -0
  77. package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.scss +36 -0
  78. package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/Tests/DynamicControlsStep.test.js +91 -0
  79. package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/index.js +5 -0
  80. package/v2Containers/CommunicationFlow/steps/MessageTypeStep/MessageTypeStep.js +86 -0
  81. package/v2Containers/CommunicationFlow/steps/MessageTypeStep/Tests/MessageTypeStep.test.js +100 -0
  82. package/v2Containers/CommunicationFlow/steps/MessageTypeStep/index.js +5 -0
  83. package/v2Containers/CommunicationFlow/utils/getEnabledSteps.js +30 -0
  84. package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +43 -0
  85. package/v2Containers/CreativesContainer/SlideBoxContent.js +36 -4
  86. package/v2Containers/CreativesContainer/SlideBoxFooter.js +10 -1
  87. package/v2Containers/CreativesContainer/SlideBoxHeader.js +29 -4
  88. package/v2Containers/CreativesContainer/constants.js +12 -0
  89. package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +67 -0
  90. package/v2Containers/CreativesContainer/index.js +289 -99
  91. package/v2Containers/CreativesContainer/index.scss +51 -1
  92. package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
  93. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +104 -0
  94. package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +110 -0
  95. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +8 -0
  96. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +363 -0
  97. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +20 -10
  98. package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
  99. package/v2Containers/CreativesContainer/tests/index.test.js +71 -9
  100. package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +125 -0
  101. package/v2Containers/Rcs/constants.js +32 -1
  102. package/v2Containers/Rcs/index.js +950 -873
  103. package/v2Containers/Rcs/index.scss +85 -6
  104. package/v2Containers/Rcs/messages.js +10 -1
  105. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +205 -0
  106. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +40834 -1963
  107. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +0 -5
  108. package/v2Containers/Rcs/tests/index.test.js +41 -38
  109. package/v2Containers/Rcs/tests/mockData.js +38 -0
  110. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +251 -0
  111. package/v2Containers/Rcs/tests/utils.test.js +379 -1
  112. package/v2Containers/Rcs/utils.js +358 -10
  113. package/v2Containers/Sms/Create/index.js +81 -36
  114. package/v2Containers/Sms/smsFormDataHelpers.js +67 -0
  115. package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +253 -0
  116. package/v2Containers/SmsTrai/Create/index.js +9 -4
  117. package/v2Containers/SmsTrai/Edit/constants.js +2 -0
  118. package/v2Containers/SmsTrai/Edit/index.js +609 -128
  119. package/v2Containers/SmsTrai/Edit/index.scss +121 -0
  120. package/v2Containers/SmsTrai/Edit/messages.js +9 -4
  121. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4327 -2374
  122. package/v2Containers/SmsWrapper/index.js +37 -8
  123. package/v2Containers/TagList/index.js +6 -0
  124. package/v2Containers/Templates/TemplatesActionBar.js +101 -0
  125. package/v2Containers/Templates/_templates.scss +61 -2
  126. package/v2Containers/Templates/actions.js +11 -0
  127. package/v2Containers/Templates/constants.js +2 -0
  128. package/v2Containers/Templates/index.js +90 -40
  129. package/v2Containers/Templates/sagas.js +57 -12
  130. package/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
  131. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1043 -1079
  132. package/v2Containers/Templates/tests/sagas.test.js +193 -12
  133. package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +180 -0
  134. package/v2Containers/Templates/utils/smsTemplatesListApi.js +79 -0
  135. package/v2Containers/TemplatesV2/TemplatesV2.style.js +72 -1
  136. package/v2Containers/TemplatesV2/index.js +86 -23
  137. package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +131 -0
  138. package/v2Containers/Whatsapp/index.js +3 -20
  139. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +578 -34
@@ -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, CapSpin, CapIcon, CapTooltip } from '@capillarytech/cap-ui-library';
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: 'assets' });
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
- getTemplateDataForGrid = ({templates, handlers, filterContent, channel, isLoading, loadingTip}) => {
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 className={`${className} creatives-templates-container ${isFullMode ? 'fullmode' : 'library-mode'}`} data-testid="cap-wrapper">
372
- {isFullMode && <Helmet
373
- title={this.props.intl.formatMessage(messages.creatives)}
374
- meta={[
375
- { name: 'description', content: this.props.intl.formatMessage(messages.creativesDesc) },
376
- ]}
377
- />}
378
- <div className="component-wrapper">
379
- {isFullMode && <CapHeader title={<FormattedMessage {...messages.creatives}/>} description={<FormattedMessage {...messages.creativesDesc}/>}/>}
380
- <StyledCapTab
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
+ });
@@ -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 {
@@ -482,28 +483,10 @@ export const Whatsapp = (props) => {
482
483
  );
483
484
  };
484
485
 
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
486
  const computeTextMessage = (msg, varMap, regex) => {
504
487
  const validVarArr = msg?.match(regex) || [];
505
488
  //conerting msg string to variable arr
506
- const templateHeaderArray = converStringToVarArr(validVarArr, msg);
489
+ const templateHeaderArray = splitContentByOrderedVarTokens(validVarArr, msg);
507
490
  if (templateHeaderArray?.length !== 0) {
508
491
  let clonedVarMap = {};
509
492
  if (!isEmpty(varMap)) {
@@ -557,7 +540,7 @@ export const Whatsapp = (props) => {
557
540
  setUnsubscribeRequired(true);
558
541
  }
559
542
  //converting msg string to variable arr
560
- const templateMessageArray = converStringToVarArr(validVarArr, msg);
543
+ const templateMessageArray = splitContentByOrderedVarTokens(validVarArr, msg);
561
544
  updateTempMsgArray(templateMessageArray.filter((i) => i === 0 || i));
562
545
  };
563
546