@capillarytech/creatives-library 8.0.316 → 8.0.317-alpha.0

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 (172) 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/tagValidations.test.js +34 -0
  8. package/utils/tests/templateVarUtils.test.js +160 -0
  9. package/v2Components/CapTagList/index.js +25 -22
  10. package/v2Components/CapTagList/style.scss +48 -0
  11. package/v2Components/CapTagListWithInput/__tests__/CapTagListWithInput.test.js +63 -0
  12. package/v2Components/CapTagListWithInput/index.js +4 -0
  13. package/v2Components/CapWhatsappCTA/index.js +2 -0
  14. package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +70 -49
  15. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +8 -2
  16. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +207 -21
  17. package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +16 -0
  18. package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +85 -10
  19. package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +30 -0
  20. package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +79 -11
  21. package/v2Components/CommonTestAndPreview/SendTestMessage.js +11 -5
  22. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +20 -1
  23. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +133 -4
  24. package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +12 -0
  25. package/v2Components/CommonTestAndPreview/constants.js +38 -0
  26. package/v2Components/CommonTestAndPreview/index.js +693 -155
  27. package/v2Components/CommonTestAndPreview/messages.js +41 -3
  28. package/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
  29. package/v2Components/CommonTestAndPreview/sagas.js +15 -6
  30. package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +352 -0
  31. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +269 -1
  32. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +118 -5
  33. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +341 -0
  34. package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +25 -4
  35. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +199 -1
  36. package/v2Components/CommonTestAndPreview/tests/index.test.js +132 -4
  37. package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
  38. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +2 -2
  39. package/v2Components/FormBuilder/index.js +14 -1
  40. package/v2Components/HtmlEditor/HTMLEditor.js +6 -1
  41. package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -0
  42. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +927 -2
  43. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +3 -0
  44. package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +87 -0
  45. package/v2Components/SmsFallback/constants.js +73 -0
  46. package/v2Components/SmsFallback/index.js +956 -0
  47. package/v2Components/SmsFallback/index.scss +265 -0
  48. package/v2Components/SmsFallback/messages.js +78 -0
  49. package/v2Components/SmsFallback/smsFallbackUtils.js +107 -0
  50. package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +50 -0
  51. package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +147 -0
  52. package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +304 -0
  53. package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +197 -0
  54. package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +261 -0
  55. package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +422 -0
  56. package/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
  57. package/v2Components/TestAndPreviewSlidebox/index.js +8 -1
  58. package/v2Components/TestAndPreviewSlidebox/sagas.js +11 -4
  59. package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +3 -1
  60. package/v2Components/VarSegmentMessageEditor/constants.js +2 -0
  61. package/v2Components/VarSegmentMessageEditor/index.js +125 -0
  62. package/v2Components/VarSegmentMessageEditor/index.scss +46 -0
  63. package/v2Containers/BeeEditor/index.js +3 -0
  64. package/v2Containers/CommunicationFlow/CommunicationFlow.js +291 -0
  65. package/v2Containers/CommunicationFlow/CommunicationFlow.scss +25 -0
  66. package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +255 -0
  67. package/v2Containers/CommunicationFlow/constants.js +200 -0
  68. package/v2Containers/CommunicationFlow/index.js +102 -0
  69. package/v2Containers/CommunicationFlow/messages.js +346 -0
  70. package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.js +522 -0
  71. package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.scss +170 -0
  72. package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/Tests/ChannelSelectionStep.test.js +796 -0
  73. package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/index.js +5 -0
  74. package/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/CommunicationStrategyStep.js +95 -0
  75. package/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/Tests/CommunicationStrategyStep.test.js +133 -0
  76. package/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/index.js +5 -0
  77. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.js +289 -0
  78. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.scss +70 -0
  79. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.js +319 -0
  80. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.scss +69 -0
  81. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +616 -0
  82. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +577 -0
  83. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/deliverySettingsConfig.test.js +1111 -0
  84. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/deliverySettingsConfig.js +696 -0
  85. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/index.js +7 -0
  86. package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.js +102 -0
  87. package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.scss +36 -0
  88. package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/Tests/DynamicControlsStep.test.js +91 -0
  89. package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/index.js +5 -0
  90. package/v2Containers/CommunicationFlow/steps/MessageTypeStep/MessageTypeStep.js +86 -0
  91. package/v2Containers/CommunicationFlow/steps/MessageTypeStep/Tests/MessageTypeStep.test.js +100 -0
  92. package/v2Containers/CommunicationFlow/steps/MessageTypeStep/index.js +5 -0
  93. package/v2Containers/CommunicationFlow/utils/getEnabledSteps.js +30 -0
  94. package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +43 -0
  95. package/v2Containers/CreativesContainer/SlideBoxContent.js +64 -5
  96. package/v2Containers/CreativesContainer/SlideBoxFooter.js +10 -1
  97. package/v2Containers/CreativesContainer/SlideBoxHeader.js +29 -4
  98. package/v2Containers/CreativesContainer/constants.js +12 -0
  99. package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +67 -0
  100. package/v2Containers/CreativesContainer/index.js +289 -93
  101. package/v2Containers/CreativesContainer/index.scss +51 -1
  102. package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
  103. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +104 -0
  104. package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +110 -0
  105. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +8 -0
  106. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +363 -0
  107. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +20 -10
  108. package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
  109. package/v2Containers/CreativesContainer/tests/index.test.js +71 -9
  110. package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +125 -0
  111. package/v2Containers/Email/index.js +1 -0
  112. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +7 -1
  113. package/v2Containers/EmailWrapper/components/EmailWrapperView.js +3 -0
  114. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +20 -2
  115. package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +16 -1
  116. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +3 -0
  117. package/v2Containers/EmailWrapper/index.js +4 -0
  118. package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +1 -0
  119. package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +9 -0
  120. package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +19 -0
  121. package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +3 -0
  122. package/v2Containers/InAppWrapper/index.js +3 -0
  123. package/v2Containers/MobilePush/Create/index.js +2 -0
  124. package/v2Containers/MobilePush/Edit/index.js +2 -0
  125. package/v2Containers/MobilepushWrapper/index.js +3 -1
  126. package/v2Containers/Rcs/constants.js +32 -1
  127. package/v2Containers/Rcs/index.js +951 -873
  128. package/v2Containers/Rcs/index.scss +85 -6
  129. package/v2Containers/Rcs/messages.js +10 -1
  130. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +205 -0
  131. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +40834 -1963
  132. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +0 -5
  133. package/v2Containers/Rcs/tests/index.test.js +41 -38
  134. package/v2Containers/Rcs/tests/mockData.js +38 -0
  135. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +251 -0
  136. package/v2Containers/Rcs/tests/utils.test.js +379 -1
  137. package/v2Containers/Rcs/utils.js +358 -10
  138. package/v2Containers/Sms/Create/index.js +83 -36
  139. package/v2Containers/Sms/Edit/index.js +2 -0
  140. package/v2Containers/Sms/smsFormDataHelpers.js +67 -0
  141. package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +253 -0
  142. package/v2Containers/SmsTrai/Create/index.js +9 -4
  143. package/v2Containers/SmsTrai/Edit/constants.js +2 -0
  144. package/v2Containers/SmsTrai/Edit/index.js +611 -128
  145. package/v2Containers/SmsTrai/Edit/index.scss +121 -0
  146. package/v2Containers/SmsTrai/Edit/messages.js +9 -4
  147. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4327 -2374
  148. package/v2Containers/SmsWrapper/index.js +39 -8
  149. package/v2Containers/TagList/index.js +47 -2
  150. package/v2Containers/TagList/messages.js +4 -0
  151. package/v2Containers/TagList/tests/TagList.test.js +122 -20
  152. package/v2Containers/TagList/tests/mockdata.js +17 -0
  153. package/v2Containers/Templates/TemplatesActionBar.js +101 -0
  154. package/v2Containers/Templates/_templates.scss +61 -2
  155. package/v2Containers/Templates/actions.js +11 -0
  156. package/v2Containers/Templates/constants.js +2 -0
  157. package/v2Containers/Templates/index.js +90 -40
  158. package/v2Containers/Templates/sagas.js +57 -12
  159. package/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
  160. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1043 -1079
  161. package/v2Containers/Templates/tests/sagas.test.js +193 -12
  162. package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +180 -0
  163. package/v2Containers/Templates/utils/smsTemplatesListApi.js +79 -0
  164. package/v2Containers/TemplatesV2/TemplatesV2.style.js +72 -1
  165. package/v2Containers/TemplatesV2/index.js +86 -23
  166. package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +131 -0
  167. package/v2Containers/Viber/index.js +5 -0
  168. package/v2Containers/WebPush/Create/hooks/useTagManagement.js +0 -2
  169. package/v2Containers/WebPush/Create/index.js +9 -1
  170. package/v2Containers/Whatsapp/index.js +8 -20
  171. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +598 -34
  172. package/v2Containers/Zalo/index.js +2 -0
@@ -30,23 +30,28 @@ jest.mock('@capillarytech/cap-ui-library/CapNotification', () => ({
30
30
  }));
31
31
 
32
32
  // Mock child components - must use React.createElement to avoid hoisting issues
33
+ let lastLeftPanelContentProps = null;
33
34
  jest.mock('../LeftPanelContent', () => {
34
35
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies
35
36
  const ReactLib = require('react');
36
37
  return {
37
38
  __esModule: true,
38
- default: function MockLeftPanelContent() {
39
- return ReactLib.createElement('div', { 'data-testid': 'left-panel' }, 'Left Panel');
39
+ default: function MockLeftPanelContent(props) {
40
+ lastLeftPanelContentProps = props;
41
+ const editorEl = props.renderCustomValuesEditor ? props.renderCustomValuesEditor() : null;
42
+ return ReactLib.createElement('div', { 'data-testid': 'left-panel' }, 'Left Panel', editorEl);
40
43
  },
41
44
  };
42
45
  });
43
46
 
47
+ let lastCustomValuesEditorProps = null;
44
48
  jest.mock('../CustomValuesEditor', () => {
45
49
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies
46
50
  const ReactLib = require('react');
47
51
  return {
48
52
  __esModule: true,
49
- default: function MockCustomValuesEditor() {
53
+ default: function MockCustomValuesEditor(props) {
54
+ lastCustomValuesEditorProps = props;
50
55
  return ReactLib.createElement('div', { 'data-testid': 'custom-values-editor' }, 'Custom Values Editor');
51
56
  },
52
57
  };
@@ -184,6 +189,8 @@ describe('CommonTestAndPreview', () => {
184
189
  beforeEach(() => {
185
190
  jest.clearAllMocks();
186
191
  lastSendTestMessageProps = null;
192
+ lastLeftPanelContentProps = null;
193
+ lastCustomValuesEditorProps = null;
187
194
  // Reset all mock function implementations
188
195
  Object.values(mockActions).forEach((mockFn) => {
189
196
  if (jest.isMockFunction(mockFn)) {
@@ -238,6 +245,24 @@ describe('CommonTestAndPreview', () => {
238
245
  });
239
246
  });
240
247
 
248
+ it('should call getSenderDetailsRequested for RCS and SMS when channel is RCS', async () => {
249
+ render(
250
+ <TestWrapper>
251
+ <CommonTestAndPreview {...defaultProps} channel={CHANNELS.RCS} />
252
+ </TestWrapper>
253
+ );
254
+ await waitFor(() => {
255
+ expect(mockActions.getSenderDetailsRequested).toHaveBeenCalledWith({
256
+ channel: CHANNELS.RCS,
257
+ orgUnitId: -1,
258
+ });
259
+ expect(mockActions.getSenderDetailsRequested).toHaveBeenCalledWith({
260
+ channel: CHANNELS.SMS,
261
+ orgUnitId: -1,
262
+ });
263
+ });
264
+ });
265
+
241
266
  it('should not call getSenderDetailsRequested when channel is INAPP', async () => {
242
267
  render(
243
268
  <TestWrapper>
@@ -296,7 +321,7 @@ describe('CommonTestAndPreview', () => {
296
321
  });
297
322
  expect(lastSendTestMessageProps).toBeDefined();
298
323
  expect(lastSendTestMessageProps.deliverySettings).toBeDefined();
299
- expect(lastSendTestMessageProps.senderDetailsOptions).toEqual(senderDetailsByChannel[CHANNELS.SMS]);
324
+ expect(lastSendTestMessageProps.senderDetailsByChannel).toEqual(senderDetailsByChannel);
300
325
  expect(lastSendTestMessageProps.wecrmAccounts).toEqual([]);
301
326
  expect(typeof lastSendTestMessageProps.onSaveDeliverySettings).toBe('function');
302
327
  expect(lastSendTestMessageProps.isLoadingSenderDetails).toBe(false);
@@ -3245,4 +3270,107 @@ describe('CommonTestAndPreview', () => {
3245
3270
  });
3246
3271
  });
3247
3272
  });
3273
+
3274
+ describe('SMS DLT and mustache tag discrimination (smsTemplateHasMustacheTags / buildSyntheticSmsMustacheTags)', () => {
3275
+ it('should return no tags for SMS content that contains only DLT {#var#} tokens', async () => {
3276
+ render(
3277
+ <TestWrapper>
3278
+ <CommonTestAndPreview
3279
+ {...defaultProps}
3280
+ channel={CHANNELS.SMS}
3281
+ formData={{ 0: { 'sms-editor': 'Order {#orderId#} is confirmed' } }}
3282
+ extractedTags={[]}
3283
+ />
3284
+ </TestWrapper>
3285
+ );
3286
+
3287
+ await waitFor(() => expect(lastLeftPanelContentProps).not.toBeNull());
3288
+
3289
+ // smsTemplateHasMustacheTags returns false for DLT-only → extractedTags is []
3290
+ expect(lastLeftPanelContentProps.extractedTags).toEqual([]);
3291
+ });
3292
+
3293
+ it('should build synthetic tags from {{mustache}} tokens, excluding DLT {#var#} tokens', async () => {
3294
+ render(
3295
+ <TestWrapper>
3296
+ <CommonTestAndPreview
3297
+ {...defaultProps}
3298
+ channel={CHANNELS.SMS}
3299
+ formData={{ 0: { 'sms-editor': 'Hi {{name}}, order {#orderId#} shipped' } }}
3300
+ extractedTags={[]}
3301
+ />
3302
+ </TestWrapper>
3303
+ );
3304
+
3305
+ await waitFor(() => expect(lastLeftPanelContentProps).not.toBeNull());
3306
+
3307
+ const tags = lastLeftPanelContentProps.extractedTags;
3308
+ // Only {{name}} should become a tag — {#orderId#} must be excluded
3309
+ expect(tags).toHaveLength(1);
3310
+ expect(tags[0].name).toBe('name');
3311
+ });
3312
+
3313
+ it('should use API-extracted tags when present instead of building synthetic ones', async () => {
3314
+ const apiTags = [{ name: 'firstName', metaData: { userDriven: true }, children: [] }];
3315
+ render(
3316
+ <TestWrapper>
3317
+ <CommonTestAndPreview
3318
+ {...defaultProps}
3319
+ channel={CHANNELS.SMS}
3320
+ formData={{ 0: { 'sms-editor': 'Hi {{firstName}}' } }}
3321
+ extractedTags={apiTags}
3322
+ />
3323
+ </TestWrapper>
3324
+ );
3325
+
3326
+ await waitFor(() => expect(lastLeftPanelContentProps).not.toBeNull());
3327
+
3328
+ // API tags take priority over buildSyntheticSmsMustacheTags
3329
+ expect(lastLeftPanelContentProps.extractedTags).toEqual(apiTags);
3330
+ });
3331
+ });
3332
+
3333
+ describe('handleDiscardCustomValues — preview reset', () => {
3334
+ it('should call updatePreviewRequested when handleDiscardCustomValues is invoked', async () => {
3335
+ render(
3336
+ <TestWrapper>
3337
+ <CommonTestAndPreview
3338
+ {...defaultProps}
3339
+ channel={CHANNELS.SMS}
3340
+ formData={{ 0: { 'sms-editor': 'Hi {{name}}' } }}
3341
+ />
3342
+ </TestWrapper>
3343
+ );
3344
+
3345
+ await waitFor(() => expect(lastCustomValuesEditorProps).not.toBeNull());
3346
+
3347
+ lastCustomValuesEditorProps.handleDiscardCustomValues();
3348
+
3349
+ expect(mockActions.updatePreviewRequested).toHaveBeenCalledTimes(1);
3350
+ });
3351
+
3352
+ it('should call updatePreviewRequested with RCS channel when handleDiscardCustomValues is invoked for RCS with fallback', async () => {
3353
+ render(
3354
+ <TestWrapper>
3355
+ <CommonTestAndPreview
3356
+ {...defaultProps}
3357
+ channel={CHANNELS.RCS}
3358
+ smsFallbackContent={{
3359
+ templateContent: 'Fallback {{name}}',
3360
+ content: 'Fallback {{name}}',
3361
+ }}
3362
+ formData={{}}
3363
+ />
3364
+ </TestWrapper>
3365
+ );
3366
+
3367
+ await waitFor(() => expect(lastCustomValuesEditorProps).not.toBeNull());
3368
+
3369
+ lastCustomValuesEditorProps.handleDiscardCustomValues();
3370
+
3371
+ // updatePreviewRequested is called; syncSmsFallbackPreview (which hits Api directly) is NOT called
3372
+ expect(mockActions.updatePreviewRequested).toHaveBeenCalledTimes(1);
3373
+ });
3374
+ });
3248
3375
  });
3376
+
@@ -0,0 +1,67 @@
1
+ import {
2
+ normalizePreviewApiPayload,
3
+ extractPreviewFromLiquidResponse,
4
+ getSmsFallbackTextForTagExtraction,
5
+ } from '../previewApiUtils';
6
+ import { RCS_SMS_FALLBACK_VAR_MAPPED_PROP } from '../constants';
7
+
8
+ describe('previewApiUtils', () => {
9
+ describe('normalizePreviewApiPayload', () => {
10
+ it('maps messageBody to resolvedBody when resolvedBody is missing', () => {
11
+ expect(normalizePreviewApiPayload({ messageBody: 'Hello' }).resolvedBody).toBe('Hello');
12
+ });
13
+ });
14
+
15
+ describe('extractPreviewFromLiquidResponse', () => {
16
+ it('accepts nested data shape', () => {
17
+ const r = { data: { resolvedBody: 'ok' } };
18
+ expect(extractPreviewFromLiquidResponse(r)).toEqual({ resolvedBody: 'ok' });
19
+ });
20
+
21
+ it('accepts top-level preview (typical SMS)', () => {
22
+ const r = { messageBody: 'sms text' };
23
+ expect(extractPreviewFromLiquidResponse(r)).toMatchObject({
24
+ messageBody: 'sms text',
25
+ resolvedBody: 'sms text',
26
+ });
27
+ });
28
+
29
+ it('returns null when errors array is non-empty', () => {
30
+ expect(extractPreviewFromLiquidResponse({ errors: [{ code: 1 }] })).toBeNull();
31
+ });
32
+ });
33
+
34
+ describe('getSmsFallbackTextForTagExtraction', () => {
35
+ it('returns empty string when context is missing or has no template body', () => {
36
+ expect(getSmsFallbackTextForTagExtraction(null)).toBe('');
37
+ expect(getSmsFallbackTextForTagExtraction({})).toBe('');
38
+ expect(getSmsFallbackTextForTagExtraction({ templateContent: '', content: '' })).toBe('');
39
+ });
40
+
41
+ it('returns raw template when rcsSmsFallbackVarMapped is absent or empty', () => {
42
+ const raw = '{{optout}} {{fullname}} test SMS';
43
+ expect(getSmsFallbackTextForTagExtraction({ templateContent: raw })).toBe(raw);
44
+ expect(getSmsFallbackTextForTagExtraction({
45
+ content: raw,
46
+ [RCS_SMS_FALLBACK_VAR_MAPPED_PROP]: {},
47
+ })).toBe(raw);
48
+ });
49
+
50
+ it('prefers templateContent over content when both are set', () => {
51
+ expect(getSmsFallbackTextForTagExtraction({
52
+ templateContent: 'A',
53
+ content: 'B',
54
+ })).toBe('A');
55
+ });
56
+
57
+ it('applies VarSegment slot map so preview / meta payloads are not stale vs raw template', () => {
58
+ const rawTemplateWithSlots = '{{optout}} tail';
59
+ const rcsSmsFallbackVarMappedSlots = { '{{optout}}_0': 'STOP' };
60
+ const resolvedFallbackText = getSmsFallbackTextForTagExtraction({
61
+ templateContent: rawTemplateWithSlots,
62
+ [RCS_SMS_FALLBACK_VAR_MAPPED_PROP]: rcsSmsFallbackVarMappedSlots,
63
+ });
64
+ expect(resolvedFallbackText).toBe('STOP tail');
65
+ });
66
+ });
67
+ });
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import {
8
- call, put, takeLatest, all,
8
+ call, put, takeLatest, takeEvery, all,
9
9
  } from 'redux-saga/effects';
10
10
  import {
11
11
  searchCustomersSaga,
@@ -1333,7 +1333,7 @@ describe('CommonTestAndPreview Sagas', () => {
1333
1333
  it('should watch for GET_SENDER_DETAILS_REQUESTED', () => {
1334
1334
  const generator = watchGetSenderDetails();
1335
1335
  expect(generator.next().value).toEqual(
1336
- takeLatest('app/CommonTestAndPreview/GET_SENDER_DETAILS_REQUESTED', getSenderDetailsSaga)
1336
+ takeEvery('app/CommonTestAndPreview/GET_SENDER_DETAILS_REQUESTED', getSenderDetailsSaga)
1337
1337
  );
1338
1338
  expect(generator.next().done).toBe(true);
1339
1339
  });
@@ -2990,6 +2990,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2990
2990
  selectedOfferDetails={this.props.selectedOfferDetails}
2991
2991
  eventContextTags={this.props?.eventContextTags}
2992
2992
  restrictPersonalization={this.props.restrictPersonalization}
2993
+ waitEventContextTags={this.props?.waitEventContextTags}
2993
2994
  />
2994
2995
  </CapColumn>
2995
2996
  );
@@ -3019,6 +3020,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
3019
3020
  userLocale={this.props.userLocale}
3020
3021
  selectedOfferDetails={this.props.selectedOfferDetails}
3021
3022
  eventContextTags={this.props?.eventContextTags}
3023
+ waitEventContextTags={this.props?.waitEventContextTags}
3022
3024
  moduleFilterEnabled={this.props.location && this.props.location.query && this.props.location.query.type !== 'embedded'}
3023
3025
  containerStyle={val.style || {}}
3024
3026
  inputProps={val.inputProps || {}}
@@ -3658,6 +3660,10 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
3658
3660
  channel={channel}
3659
3661
  eventContextTags={this.props?.eventContextTags}
3660
3662
  restrictPersonalization={this.props.restrictPersonalization}
3663
+ waitEventContextTags={this.props?.waitEventContextTags}
3664
+ getPopupContainer={this.props.tagListGetPopupContainer}
3665
+ popoverOverlayStyle={this.props.tagListPopoverOverlayStyle}
3666
+ popoverOverlayClassName={this.props.tagListPopoverOverlayClassName}
3661
3667
  />
3662
3668
  </CapColumn>
3663
3669
  );
@@ -3704,6 +3710,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
3704
3710
  userLocale={this.state.translationLang}
3705
3711
  selectedOfferDetails={this.props.selectedOfferDetails}
3706
3712
  eventContextTags={this.props?.eventContextTags}
3713
+ waitEventContextTags={this.props?.waitEventContextTags}
3707
3714
  moduleFilterEnabled={moduleFilterEnabledForCapTagList}
3708
3715
  containerStyle={val.style || {}}
3709
3716
  inputProps={val.inputProps || {}}
@@ -3998,6 +4005,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
3998
4005
  onContextChange={this.props.onContextChange}
3999
4006
  moduleFilterEnabled={isModuleFilterEnabled}
4000
4007
  eventContextTags={this.props?.eventContextTags}
4008
+ waitEventContextTags={this.props?.waitEventContextTags}
4001
4009
  />
4002
4010
  </CapColumn>
4003
4011
  );
@@ -4300,6 +4308,7 @@ FormBuilder.defaultProps = {
4300
4308
  userLocale: localStorage.getItem('jlocale') || 'en',
4301
4309
  showLiquidErrorInFooter: () => {},
4302
4310
  metaDataStatus: "",
4311
+ waitEventContextTags: {},
4303
4312
  isTestAndPreviewMode: false, // Default to false to maintain existing behavior
4304
4313
  };
4305
4314
 
@@ -4348,12 +4357,16 @@ FormBuilder.propTypes = {
4348
4357
  type: PropTypes.string.isRequired,
4349
4358
  isEmailLoading: PropTypes.bool.isRequired,
4350
4359
  moduleType: PropTypes.string.isRequired,
4351
- showLiquidErrorInFooter: PropTypes.bool.isRequired,
4360
+ showLiquidErrorInFooter: PropTypes.func.isRequired,
4352
4361
  eventContextTags: PropTypes.array.isRequired,
4362
+ waitEventContextTags: PropTypes.object,
4353
4363
  forwardedTags: PropTypes.object.isRequired,
4354
4364
  isLoyaltyModule: PropTypes.bool.isRequired,
4355
4365
  isTestAndPreviewMode: PropTypes.bool, // Add new prop type
4356
4366
  restrictPersonalization: PropTypes.bool,
4367
+ tagListGetPopupContainer: PropTypes.func,
4368
+ tagListPopoverOverlayStyle: PropTypes.object,
4369
+ tagListPopoverOverlayClassName: PropTypes.string,
4357
4370
  };
4358
4371
 
4359
4372
  const mapStateToProps = createStructuredSelector({
@@ -94,6 +94,7 @@ const HTMLEditor = forwardRef(({
94
94
  injectedTags = {},
95
95
  location,
96
96
  eventContextTags = [],
97
+ waitEventContextTags,
97
98
  selectedOfferDetails = [],
98
99
  channel,
99
100
  userLocale = 'en',
@@ -361,7 +362,7 @@ const HTMLEditor = forwardRef(({
361
362
  const issueCounts = calculateIssueCounts();
362
363
  const isContentEmpty = !currentContent || currentContent.trim() === '';
363
364
 
364
- // hasErrors = only Rule Group #1 (Input & Sanitization) gates Done/Update/Preview/Test
365
+ // hasErrors = only Rule Group #1 (Input & Sanitization) - gates Done/Update/Preview/Test
365
366
  const newState = {
366
367
  isContentEmpty,
367
368
  issueCounts,
@@ -663,6 +664,7 @@ const HTMLEditor = forwardRef(({
663
664
  injectedTags={injectedTags}
664
665
  location={location}
665
666
  eventContextTags={eventContextTags}
667
+ waitEventContextTags={waitEventContextTags}
666
668
  selectedOfferDetails={selectedOfferDetails}
667
669
  channel={channel}
668
670
  userLocale={userLocale}
@@ -734,6 +736,7 @@ const HTMLEditor = forwardRef(({
734
736
  injectedTags={injectedTags}
735
737
  location={location}
736
738
  eventContextTags={eventContextTags}
739
+ waitEventContextTags={waitEventContextTags}
737
740
  selectedOfferDetails={selectedOfferDetails}
738
741
  channel={channel}
739
742
  userLocale={userLocale}
@@ -772,6 +775,7 @@ HTMLEditor.propTypes = {
772
775
  injectedTags: PropTypes.object,
773
776
  location: PropTypes.object,
774
777
  eventContextTags: PropTypes.array,
778
+ waitEventContextTags: PropTypes.object,
775
779
  selectedOfferDetails: PropTypes.array,
776
780
  channel: PropTypes.string,
777
781
  userLocale: PropTypes.string,
@@ -805,6 +809,7 @@ HTMLEditor.defaultProps = {
805
809
  injectedTags: {},
806
810
  location: null,
807
811
  eventContextTags: [],
812
+ waitEventContextTags: {},
808
813
  selectedOfferDetails: [],
809
814
  channel: null,
810
815
  userLocale: 'en',
@@ -225,6 +225,7 @@ const defaultProps = {
225
225
  injectedTags: {},
226
226
  location: { query: {} },
227
227
  eventContextTags: [],
228
+ waitEventContextTags: {},
228
229
  selectedOfferDetails: [],
229
230
  channel: 'EMAIL',
230
231
  userLocale: 'en',