@capillarytech/creatives-library 8.0.316-alpha.4 → 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 (91) hide show
  1. package/constants/unified.js +1 -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/tests/tagValidations.test.js +34 -0
  7. package/v2Components/CapTagList/index.js +15 -22
  8. package/v2Components/CapTagList/style.scss +48 -0
  9. package/v2Components/CapTagListWithInput/__tests__/CapTagListWithInput.test.js +63 -0
  10. package/v2Components/CapTagListWithInput/index.js +4 -0
  11. package/v2Components/CapWhatsappCTA/index.js +2 -0
  12. package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +180 -0
  13. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +96 -0
  14. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +99 -0
  15. package/v2Components/CommonTestAndPreview/tests/index.test.js +113 -3
  16. package/v2Components/FormBuilder/index.js +7 -0
  17. package/v2Components/HtmlEditor/HTMLEditor.js +6 -1
  18. package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -0
  19. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +927 -2
  20. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +3 -0
  21. package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +95 -0
  22. package/v2Containers/BeeEditor/index.js +3 -0
  23. package/v2Containers/CommunicationFlow/CommunicationFlow.js +291 -0
  24. package/v2Containers/CommunicationFlow/CommunicationFlow.scss +25 -0
  25. package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +255 -0
  26. package/v2Containers/CommunicationFlow/constants.js +200 -0
  27. package/v2Containers/CommunicationFlow/index.js +102 -0
  28. package/v2Containers/CommunicationFlow/messages.js +346 -0
  29. package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.js +522 -0
  30. package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/ChannelSelectionStep.scss +170 -0
  31. package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/Tests/ChannelSelectionStep.test.js +796 -0
  32. package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/index.js +5 -0
  33. package/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/CommunicationStrategyStep.js +95 -0
  34. package/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/Tests/CommunicationStrategyStep.test.js +133 -0
  35. package/v2Containers/CommunicationFlow/steps/CommunicationStrategyStep/index.js +5 -0
  36. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.js +289 -0
  37. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/DeliverySettingsSection.scss +70 -0
  38. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.js +319 -0
  39. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/SenderDetails.scss +69 -0
  40. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +616 -0
  41. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +577 -0
  42. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/deliverySettingsConfig.test.js +1111 -0
  43. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/deliverySettingsConfig.js +696 -0
  44. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/index.js +7 -0
  45. package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.js +102 -0
  46. package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/DynamicControlsStep.scss +36 -0
  47. package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/Tests/DynamicControlsStep.test.js +91 -0
  48. package/v2Containers/CommunicationFlow/steps/DynamicControlsStep/index.js +5 -0
  49. package/v2Containers/CommunicationFlow/steps/MessageTypeStep/MessageTypeStep.js +86 -0
  50. package/v2Containers/CommunicationFlow/steps/MessageTypeStep/Tests/MessageTypeStep.test.js +100 -0
  51. package/v2Containers/CommunicationFlow/steps/MessageTypeStep/index.js +5 -0
  52. package/v2Containers/CommunicationFlow/utils/getEnabledSteps.js +30 -0
  53. package/v2Containers/CreativesContainer/SlideBoxContent.js +28 -1
  54. package/v2Containers/CreativesContainer/constants.js +3 -0
  55. package/v2Containers/CreativesContainer/index.js +3 -0
  56. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +104 -0
  57. package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +110 -0
  58. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +363 -0
  59. package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
  60. package/v2Containers/Email/index.js +1 -0
  61. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +7 -1
  62. package/v2Containers/EmailWrapper/components/EmailWrapperView.js +3 -0
  63. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +20 -2
  64. package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +16 -1
  65. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +3 -0
  66. package/v2Containers/EmailWrapper/index.js +4 -0
  67. package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +1 -0
  68. package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +9 -0
  69. package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +19 -0
  70. package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +3 -0
  71. package/v2Containers/InAppWrapper/index.js +3 -0
  72. package/v2Containers/MobilePush/Create/index.js +2 -0
  73. package/v2Containers/MobilePush/Edit/index.js +2 -0
  74. package/v2Containers/MobilepushWrapper/index.js +3 -1
  75. package/v2Containers/Rcs/index.js +1 -0
  76. package/v2Containers/Sms/Create/index.js +2 -0
  77. package/v2Containers/Sms/Edit/index.js +2 -0
  78. package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +253 -0
  79. package/v2Containers/SmsTrai/Edit/index.js +2 -0
  80. package/v2Containers/SmsWrapper/index.js +2 -0
  81. package/v2Containers/TagList/index.js +41 -2
  82. package/v2Containers/TagList/messages.js +4 -0
  83. package/v2Containers/TagList/tests/TagList.test.js +122 -20
  84. package/v2Containers/TagList/tests/mockdata.js +17 -0
  85. package/v2Containers/Templates/tests/sagas.test.js +83 -0
  86. package/v2Containers/Viber/index.js +5 -0
  87. package/v2Containers/WebPush/Create/hooks/useTagManagement.js +0 -2
  88. package/v2Containers/WebPush/Create/index.js +9 -1
  89. package/v2Containers/Whatsapp/index.js +5 -0
  90. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +20 -0
  91. package/v2Containers/Zalo/index.js +2 -0
@@ -0,0 +1,258 @@
1
+ import {
2
+ CAP_SPACE_32,
3
+ CAP_SPACE_56,
4
+ CAP_SPACE_64,
5
+ } from '@capillarytech/cap-ui-library/styled/variables';
6
+ import {
7
+ isDeepEmpty,
8
+ getSlideBoxWrapperMarginFromLiquidErrors,
9
+ computeLiquidFooterUpdateFromFormBuilder,
10
+ } from '../embeddedSlideboxUtils';
11
+ import { ANDROID, IOS, MOBILE_PUSH, LIQUID_ERROR_MSG, STANDARD_ERROR_MSG } from '../constants';
12
+
13
+ // ---------------------------------------------------------------------------
14
+ // isDeepEmpty
15
+ // ---------------------------------------------------------------------------
16
+
17
+ describe('isDeepEmpty', () => {
18
+ it('returns true for null', () => {
19
+ expect(isDeepEmpty(null)).toBe(true);
20
+ });
21
+
22
+ it('returns true for undefined', () => {
23
+ expect(isDeepEmpty(undefined)).toBe(true);
24
+ });
25
+
26
+ it('returns true for empty string', () => {
27
+ expect(isDeepEmpty('')).toBe(true);
28
+ });
29
+
30
+ it('returns false for non-empty string', () => {
31
+ expect(isDeepEmpty('hello')).toBe(false);
32
+ });
33
+
34
+ it('returns true for empty array', () => {
35
+ expect(isDeepEmpty([])).toBe(true);
36
+ });
37
+
38
+ it('returns false for non-empty array', () => {
39
+ expect(isDeepEmpty(['item'])).toBe(false);
40
+ });
41
+
42
+ it('returns true for empty object', () => {
43
+ expect(isDeepEmpty({})).toBe(true);
44
+ });
45
+
46
+ it('returns true for object where all values are deep-empty', () => {
47
+ expect(isDeepEmpty({ a: null, b: '', c: [] })).toBe(true);
48
+ });
49
+
50
+ it('returns false for object with at least one non-empty value', () => {
51
+ expect(isDeepEmpty({ a: null, b: 'something' })).toBe(false);
52
+ });
53
+
54
+ it('returns true for nested all-empty object', () => {
55
+ expect(isDeepEmpty({ a: { b: null, c: [] } })).toBe(true);
56
+ });
57
+
58
+ it('returns false for nested object with a non-empty leaf', () => {
59
+ expect(isDeepEmpty({ a: { b: 'value' } })).toBe(false);
60
+ });
61
+
62
+ it('returns false for a number (non-null, non-string, non-array, non-object)', () => {
63
+ expect(isDeepEmpty(0)).toBe(false);
64
+ expect(isDeepEmpty(42)).toBe(false);
65
+ });
66
+
67
+ it('returns false for a boolean false', () => {
68
+ expect(isDeepEmpty(false)).toBe(false);
69
+ });
70
+ });
71
+
72
+ // ---------------------------------------------------------------------------
73
+ // getSlideBoxWrapperMarginFromLiquidErrors
74
+ // ---------------------------------------------------------------------------
75
+
76
+ describe('getSlideBoxWrapperMarginFromLiquidErrors', () => {
77
+ it('returns 0 when liquidErrorMessage is null', () => {
78
+ expect(getSlideBoxWrapperMarginFromLiquidErrors(null)).toBe(0);
79
+ });
80
+
81
+ it('returns 0 when liquidErrorMessage is undefined', () => {
82
+ expect(getSlideBoxWrapperMarginFromLiquidErrors(undefined)).toBe(0);
83
+ });
84
+
85
+ it('returns 0 when both error arrays are empty', () => {
86
+ expect(getSlideBoxWrapperMarginFromLiquidErrors({
87
+ STANDARD_ERROR_MSG: [],
88
+ LIQUID_ERROR_MSG: [],
89
+ })).toBe(0);
90
+ });
91
+
92
+ it('returns 0 when neither error array is present', () => {
93
+ expect(getSlideBoxWrapperMarginFromLiquidErrors({})).toBe(0);
94
+ });
95
+
96
+ it('returns CAP_SPACE_64 when both STANDARD and LIQUID errors are present', () => {
97
+ expect(getSlideBoxWrapperMarginFromLiquidErrors({
98
+ STANDARD_ERROR_MSG: ['std error'],
99
+ LIQUID_ERROR_MSG: ['liquid error'],
100
+ })).toBe(CAP_SPACE_64);
101
+ });
102
+
103
+ it('returns CAP_SPACE_56 when only LIQUID errors are present', () => {
104
+ expect(getSlideBoxWrapperMarginFromLiquidErrors({
105
+ STANDARD_ERROR_MSG: [],
106
+ LIQUID_ERROR_MSG: ['liquid error'],
107
+ })).toBe(CAP_SPACE_56);
108
+ });
109
+
110
+ it('returns CAP_SPACE_32 when only STANDARD errors are present', () => {
111
+ expect(getSlideBoxWrapperMarginFromLiquidErrors({
112
+ STANDARD_ERROR_MSG: ['std error'],
113
+ LIQUID_ERROR_MSG: [],
114
+ })).toBe(CAP_SPACE_32);
115
+ });
116
+
117
+ it('returns CAP_SPACE_56 when LIQUID has multiple errors and STANDARD is absent', () => {
118
+ expect(getSlideBoxWrapperMarginFromLiquidErrors({
119
+ LIQUID_ERROR_MSG: ['err1', 'err2'],
120
+ })).toBe(CAP_SPACE_56);
121
+ });
122
+
123
+ it('returns CAP_SPACE_32 when STANDARD has multiple errors and LIQUID is absent', () => {
124
+ expect(getSlideBoxWrapperMarginFromLiquidErrors({
125
+ STANDARD_ERROR_MSG: ['err1', 'err2'],
126
+ })).toBe(CAP_SPACE_32);
127
+ });
128
+ });
129
+
130
+ // ---------------------------------------------------------------------------
131
+ // computeLiquidFooterUpdateFromFormBuilder
132
+ // ---------------------------------------------------------------------------
133
+
134
+ describe('computeLiquidFooterUpdateFromFormBuilder', () => {
135
+ const noErrors = { [LIQUID_ERROR_MSG]: [], [STANDARD_ERROR_MSG]: [] };
136
+ const liquidOnly = { [LIQUID_ERROR_MSG]: ['liquid err'], [STANDARD_ERROR_MSG]: [] };
137
+ const standardOnly = { [LIQUID_ERROR_MSG]: [], [STANDARD_ERROR_MSG]: ['std err'] };
138
+ const bothErrors = { [LIQUID_ERROR_MSG]: ['l'], [STANDARD_ERROR_MSG]: ['s'] };
139
+
140
+ describe('normal (non-null) returns', () => {
141
+ it('returns isLiquidValidationError=false when no errors', () => {
142
+ const result = computeLiquidFooterUpdateFromFormBuilder(noErrors, 1, {
143
+ previousIsLiquidValidationError: false,
144
+ currentChannelUpper: 'SMS',
145
+ });
146
+ expect(result).not.toBeNull();
147
+ expect(result.isLiquidValidationError).toBe(false);
148
+ expect(result.liquidErrorMessage).toEqual(noErrors);
149
+ });
150
+
151
+ it('sets isLiquidValidationError=true when liquid errors present', () => {
152
+ const result = computeLiquidFooterUpdateFromFormBuilder(liquidOnly, 1, {
153
+ previousIsLiquidValidationError: false,
154
+ currentChannelUpper: 'SMS',
155
+ });
156
+ expect(result.isLiquidValidationError).toBe(true);
157
+ });
158
+
159
+ it('sets isLiquidValidationError=true when standard errors present', () => {
160
+ const result = computeLiquidFooterUpdateFromFormBuilder(standardOnly, 1, {
161
+ previousIsLiquidValidationError: false,
162
+ currentChannelUpper: 'SMS',
163
+ });
164
+ expect(result.isLiquidValidationError).toBe(true);
165
+ });
166
+
167
+ it('sets isLiquidValidationError=true when both errors present', () => {
168
+ const result = computeLiquidFooterUpdateFromFormBuilder(bothErrors, 1, {
169
+ previousIsLiquidValidationError: false,
170
+ currentChannelUpper: 'SMS',
171
+ });
172
+ expect(result.isLiquidValidationError).toBe(true);
173
+ });
174
+
175
+ it('maps tab 1 to ANDROID', () => {
176
+ const result = computeLiquidFooterUpdateFromFormBuilder(noErrors, 1, {
177
+ previousIsLiquidValidationError: false,
178
+ currentChannelUpper: 'SMS',
179
+ });
180
+ expect(result.activeFormBuilderTab).toBe(ANDROID);
181
+ });
182
+
183
+ it('maps tab 2 to IOS', () => {
184
+ const result = computeLiquidFooterUpdateFromFormBuilder(noErrors, 2, {
185
+ previousIsLiquidValidationError: false,
186
+ currentChannelUpper: 'SMS',
187
+ });
188
+ expect(result.activeFormBuilderTab).toBe(IOS);
189
+ });
190
+
191
+ it('maps tab 3 (or any other tab) to null', () => {
192
+ const result = computeLiquidFooterUpdateFromFormBuilder(noErrors, 3, {
193
+ previousIsLiquidValidationError: false,
194
+ currentChannelUpper: 'SMS',
195
+ });
196
+ expect(result.activeFormBuilderTab).toBeNull();
197
+ });
198
+
199
+ it('maps undefined tab to null for activeFormBuilderTab', () => {
200
+ const result = computeLiquidFooterUpdateFromFormBuilder(noErrors, undefined, {
201
+ previousIsLiquidValidationError: false,
202
+ currentChannelUpper: 'SMS',
203
+ });
204
+ expect(result.activeFormBuilderTab).toBeNull();
205
+ });
206
+
207
+ it('does NOT return null for Mobile Push when errors ARE present', () => {
208
+ const result = computeLiquidFooterUpdateFromFormBuilder(liquidOnly, 1, {
209
+ previousIsLiquidValidationError: true,
210
+ currentChannelUpper: MOBILE_PUSH,
211
+ });
212
+ expect(result).not.toBeNull();
213
+ expect(result.isLiquidValidationError).toBe(true);
214
+ });
215
+
216
+ it('does NOT return null for non-Mobile Push channel even with previousIsLiquidValidationError', () => {
217
+ const result = computeLiquidFooterUpdateFromFormBuilder(noErrors, 1, {
218
+ previousIsLiquidValidationError: true,
219
+ currentChannelUpper: 'SMS',
220
+ });
221
+ expect(result).not.toBeNull();
222
+ expect(result.isLiquidValidationError).toBe(false);
223
+ });
224
+
225
+ it('works without options argument (uses defaults)', () => {
226
+ const result = computeLiquidFooterUpdateFromFormBuilder(noErrors, 1);
227
+ expect(result).not.toBeNull();
228
+ expect(result.isLiquidValidationError).toBe(false);
229
+ });
230
+ });
231
+
232
+ describe('Mobile Push OLD clear (returns null)', () => {
233
+ it('returns null when no errors and previousIsLiquidValidationError is true for MOBILEPUSH', () => {
234
+ const result = computeLiquidFooterUpdateFromFormBuilder(noErrors, 1, {
235
+ previousIsLiquidValidationError: true,
236
+ currentChannelUpper: MOBILE_PUSH,
237
+ });
238
+ expect(result).toBeNull();
239
+ });
240
+
241
+ it('does NOT return null when previousIsLiquidValidationError is false for MOBILEPUSH', () => {
242
+ const result = computeLiquidFooterUpdateFromFormBuilder(noErrors, 1, {
243
+ previousIsLiquidValidationError: false,
244
+ currentChannelUpper: MOBILE_PUSH,
245
+ });
246
+ expect(result).not.toBeNull();
247
+ });
248
+
249
+ it('does NOT return null when only standard errors cleared but liquid error remains for MOBILEPUSH', () => {
250
+ const result = computeLiquidFooterUpdateFromFormBuilder(liquidOnly, 1, {
251
+ previousIsLiquidValidationError: true,
252
+ currentChannelUpper: MOBILE_PUSH,
253
+ });
254
+ // hasLiquid = true → condition !hasLiquid is false → does not return null
255
+ expect(result).not.toBeNull();
256
+ });
257
+ });
258
+ });
@@ -3134,6 +3134,7 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
3134
3134
  moduleType={moduleType}
3135
3135
  showLiquidErrorInFooter={this.props.showLiquidErrorInFooter}
3136
3136
  eventContextTags={this.props?.eventContextTags}
3137
+ waitEventContextTags={this.props?.waitEventContextTags}
3137
3138
  forwardedTags={this.props?.forwardedTags}
3138
3139
  isLoyaltyModule={this.props?.isLoyaltyModule}
3139
3140
  isTestAndPreviewMode={this.state.isTestAndPreviewMode} // Add flag to prevent validation
@@ -54,6 +54,7 @@ const EmailHTMLEditor = (props) => {
54
54
  globalActions,
55
55
  loadingTags,
56
56
  eventContextTags,
57
+ waitEventContextTags,
57
58
  forwardedTags,
58
59
  selectedOfferDetails,
59
60
  currentOrgDetails,
@@ -502,6 +503,7 @@ const EmailHTMLEditor = (props) => {
502
503
  location,
503
504
  tagModule: getDefaultTags,
504
505
  isFullMode,
506
+ waitEventContextTags,
505
507
  });
506
508
 
507
509
  if (!validationResult.valid) {
@@ -510,7 +512,7 @@ const EmailHTMLEditor = (props) => {
510
512
  setTagValidationError(null);
511
513
  }
512
514
  }
513
- }, [tags, injectedTags, location, getDefaultTags, eventContextTags, showLiquidErrorInFooter]);
515
+ }, [tags, injectedTags, location, getDefaultTags, eventContextTags, waitEventContextTags, showLiquidErrorInFooter]);
514
516
 
515
517
  // Store the last validation state received from HTMLEditor
516
518
  const lastValidationStateRef = useRef(null);
@@ -1100,6 +1102,7 @@ const EmailHTMLEditor = (props) => {
1100
1102
  injectedTags={injectedTags || {}}
1101
1103
  selectedOfferDetails={selectedOfferDetails}
1102
1104
  eventContextTags={eventContextTags}
1105
+ waitEventContextTags={waitEventContextTags}
1103
1106
  showHeading
1104
1107
  showTagList
1105
1108
  showInput
@@ -1124,6 +1127,7 @@ const EmailHTMLEditor = (props) => {
1124
1127
  injectedTags={injectedTags}
1125
1128
  location={location}
1126
1129
  eventContextTags={eventContextTags}
1130
+ waitEventContextTags={waitEventContextTags}
1127
1131
  selectedOfferDetails={selectedOfferDetails}
1128
1132
  channel={EMAIL}
1129
1133
  userLocale={intl.locale || 'en'}
@@ -1151,6 +1155,7 @@ EmailHTMLEditor.propTypes = {
1151
1155
  globalActions: PropTypes.object,
1152
1156
  loadingTags: PropTypes.bool,
1153
1157
  eventContextTags: PropTypes.array,
1158
+ waitEventContextTags: PropTypes.object,
1154
1159
  forwardedTags: PropTypes.object,
1155
1160
  selectedOfferDetails: PropTypes.array,
1156
1161
  currentOrgDetails: PropTypes.object,
@@ -1197,6 +1202,7 @@ EmailHTMLEditor.defaultProps = {
1197
1202
  globalActions: {},
1198
1203
  loadingTags: false,
1199
1204
  eventContextTags: [],
1205
+ waitEventContextTags: {},
1200
1206
  forwardedTags: {},
1201
1207
  selectedOfferDetails: [],
1202
1208
  currentOrgDetails: {},
@@ -173,6 +173,7 @@ const EmailWrapperView = ({
173
173
  forwardedTags,
174
174
  selectedOfferDetails,
175
175
  eventContextTags,
176
+ waitEventContextTags,
176
177
  getFormdata,
177
178
  isGetFormData,
178
179
  getLiquidTags,
@@ -246,6 +247,7 @@ const EmailWrapperView = ({
246
247
  globalActions,
247
248
  loadingTags,
248
249
  eventContextTags,
250
+ waitEventContextTags,
249
251
  forwardedTags,
250
252
  selectedOfferDetails,
251
253
  currentOrgDetails,
@@ -371,6 +373,7 @@ EmailWrapperView.propTypes = {
371
373
  forwardedTags: PropTypes.object,
372
374
  selectedOfferDetails: PropTypes.array,
373
375
  eventContextTags: PropTypes.array,
376
+ waitEventContextTags: PropTypes.object,
374
377
  emailActions: PropTypes.object,
375
378
  Email: PropTypes.object,
376
379
  templateData: PropTypes.object,
@@ -71,7 +71,10 @@ jest.mock('../../../../v2Components/HtmlEditor/index.lazy', () => {
71
71
  }));
72
72
 
73
73
  return (
74
- <div data-testid="html-editor">
74
+ <div
75
+ data-testid="html-editor"
76
+ data-wait-event-context-tags={JSON.stringify(props.waitEventContextTags ?? null)}
77
+ >
75
78
  <button
76
79
  onClick={() => props.onContentChange && props.onContentChange('<p>New content</p>')}
77
80
  data-testid="trigger-content-change"
@@ -130,7 +133,10 @@ jest.mock('../../../../v2Components/HtmlEditor', () => {
130
133
  }));
131
134
 
132
135
  return (
133
- <div data-testid="html-editor">
136
+ <div
137
+ data-testid="html-editor"
138
+ data-wait-event-context-tags={JSON.stringify(props.waitEventContextTags ?? null)}
139
+ >
134
140
  <button
135
141
  onClick={() => props.onContentChange && props.onContentChange('<p>New content</p>')}
136
142
  data-testid="trigger-content-change"
@@ -364,6 +370,7 @@ const defaultProps = {
364
370
  },
365
371
  loadingTags: false,
366
372
  eventContextTags: [],
373
+ waitEventContextTags: {},
367
374
  forwardedTags: {},
368
375
  selectedOfferDetails: [],
369
376
  currentOrgDetails: {
@@ -522,6 +529,17 @@ describe('EmailHTMLEditor', () => {
522
529
  });
523
530
  });
524
531
 
532
+ describe('waitEventContextTags', () => {
533
+ it('forwards waitEventContextTags to HTMLEditor', () => {
534
+ const waitMap = { b1: { eventName: 'E', blockName: 'B', tags: ['t'] } };
535
+ renderWithIntl({ waitEventContextTags: waitMap });
536
+ expect(screen.getByTestId('html-editor')).toHaveAttribute(
537
+ 'data-wait-event-context-tags',
538
+ JSON.stringify(waitMap),
539
+ );
540
+ });
541
+ });
542
+
525
543
  describe('Content Initialization', () => {
526
544
  it('initializes with empty content in create mode', () => {
527
545
  renderWithIntl({ isGetFormData: false });
@@ -37,7 +37,14 @@ jest.mock('../EmailHTMLEditor', () => {
37
37
  getContentForPreview: jest.fn(() => '<p>Test</p>'),
38
38
  }));
39
39
 
40
- return <div data-testid="email-html-editor">HTML Editor</div>;
40
+ return (
41
+ <div
42
+ data-testid="email-html-editor"
43
+ data-wait-event-context-tags={JSON.stringify(props.waitEventContextTags ?? null)}
44
+ >
45
+ HTML Editor
46
+ </div>
47
+ );
41
48
  });
42
49
  });
43
50
 
@@ -137,6 +144,7 @@ const defaultProps = {
137
144
  forwardedTags: {},
138
145
  selectedOfferDetails: [],
139
146
  eventContextTags: [],
147
+ waitEventContextTags: {},
140
148
  getFormdata: jest.fn(),
141
149
  isGetFormData: false,
142
150
  getLiquidTags: jest.fn(),
@@ -171,6 +179,13 @@ describe('EmailWrapperView', () => {
171
179
  jest.clearAllMocks();
172
180
  });
173
181
 
182
+ it('passes waitEventContextTags to EmailHTMLEditor when HTML editor is shown', () => {
183
+ const waitMap = { b1: { eventName: 'E', blockName: 'B', tags: [] } };
184
+ renderWithIntl({ waitEventContextTags: waitMap });
185
+ const el = screen.getByTestId('email-html-editor');
186
+ expect(el).toHaveAttribute('data-wait-event-context-tags', JSON.stringify(waitMap));
187
+ });
188
+
174
189
  describe('Mode Selection UI', () => {
175
190
  it('renders mode selection when step is MODE_SELECTION', () => {
176
191
  renderWithIntl({ step: STEPS.MODE_SELECTION });
@@ -51,6 +51,7 @@ const useEmailWrapper = ({
51
51
  editor,
52
52
  moduleType,
53
53
  eventContextTags,
54
+ waitEventContextTags,
54
55
  isLoyaltyModule,
55
56
  // Props for CmsTemplates component
56
57
  cmsTemplatesLoader,
@@ -737,6 +738,7 @@ const useEmailWrapper = ({
737
738
  selectedEditorMode, // Pass selected mode to Email component (only for HTML_EDITOR)
738
739
  moduleType,
739
740
  eventContextTags,
741
+ waitEventContextTags,
740
742
  isLoyaltyModule,
741
743
  showTestAndPreviewSlidebox,
742
744
  handleTestAndPreview,
@@ -766,6 +768,7 @@ const useEmailWrapper = ({
766
768
  editor,
767
769
  moduleType,
768
770
  eventContextTags,
771
+ waitEventContextTags,
769
772
  isLoyaltyModule,
770
773
  showTestAndPreviewSlidebox,
771
774
  handleTestAndPreview,
@@ -63,6 +63,7 @@ const EmailWrapper = (props) => {
63
63
  onEnterTemplateName,
64
64
  onRemoveTemplateName,
65
65
  eventContextTags,
66
+ waitEventContextTags,
66
67
  isLoyaltyModule,
67
68
  cmsTemplatesLoader,
68
69
  onPreviewContentClicked,
@@ -130,6 +131,7 @@ const EmailWrapper = (props) => {
130
131
  onEnterTemplateName,
131
132
  onRemoveTemplateName,
132
133
  eventContextTags,
134
+ waitEventContextTags,
133
135
  isLoyaltyModule,
134
136
  cmsTemplatesLoader,
135
137
  onPreviewContentClicked,
@@ -184,6 +186,7 @@ const EmailWrapper = (props) => {
184
186
  forwardedTags={forwardedTags}
185
187
  selectedOfferDetails={selectedOfferDetails}
186
188
  eventContextTags={eventContextTags}
189
+ waitEventContextTags={waitEventContextTags}
187
190
  getFormdata={getFormdata}
188
191
  isGetFormData={isGetFormData}
189
192
  getLiquidTags={globalActionsProp?.getLiquidTags}
@@ -241,6 +244,7 @@ EmailWrapper.propTypes = {
241
244
  onEnterTemplateName: PropTypes.func,
242
245
  onRemoveTemplateName: PropTypes.func,
243
246
  eventContextTags: PropTypes.array,
247
+ waitEventContextTags: PropTypes.object,
244
248
  isLoyaltyModule: PropTypes.bool,
245
249
  onPreviewContentClicked: PropTypes.func,
246
250
  onTestContentClicked: PropTypes.func,
@@ -112,6 +112,7 @@ describe('useEmailWrapper - Edge Cases', () => {
112
112
  editor: 'HTML',
113
113
  moduleType: null,
114
114
  eventContextTags: [],
115
+ waitEventContextTags: {},
115
116
  isLoyaltyModule: false,
116
117
  cmsTemplatesLoader: jest.fn(),
117
118
  currentOrgDetails: {},
@@ -102,6 +102,7 @@ describe('useEmailWrapper', () => {
102
102
  editor: null,
103
103
  moduleType: '',
104
104
  eventContextTags: [],
105
+ waitEventContextTags: {},
105
106
  isLoyaltyModule: false,
106
107
  cmsTemplatesLoader: false,
107
108
  currentOrgDetails: { id: 'org1' },
@@ -120,6 +121,14 @@ describe('useEmailWrapper', () => {
120
121
  expect(result.current.onTemplateNameChange).toBeInstanceOf(Function);
121
122
  });
122
123
 
124
+ it('passes waitEventContextTags through emailProps', () => {
125
+ const waitMap = { block1: { eventName: 'E', blockName: 'B', tags: [] } };
126
+ const { result } = renderHook(() =>
127
+ useEmailWrapper({ ...mockProps, waitEventContextTags: waitMap }),
128
+ );
129
+ expect(result.current.emailProps.waitEventContextTags).toEqual(waitMap);
130
+ });
131
+
123
132
  it('handles template name change correctly', () => {
124
133
  const { result } = renderHook(() => useEmailWrapper(mockProps));
125
134
 
@@ -78,6 +78,7 @@ describe('useInAppWrapper', () => {
78
78
  onPreviewContentClicked: jest.fn(),
79
79
  onTestContentClicked: jest.fn(),
80
80
  eventContextTags: {},
81
+ waitEventContextTags: {},
81
82
  onCreateComplete: jest.fn(),
82
83
  handleClose: jest.fn(),
83
84
  templateData: null,
@@ -424,6 +425,24 @@ describe('useInAppWrapper', () => {
424
425
 
425
426
  expect(capturedState.inAppProps.getDefaultTags).toBe('defaultTags');
426
427
  });
428
+
429
+ it('passes waitEventContextTags through to inAppProps', () => {
430
+ const waitMap = { block1: { eventName: 'E', blockName: 'B', tags: [] } };
431
+ let capturedState = null;
432
+ render(
433
+ <TestComponent
434
+ hookProps={{
435
+ ...defaultHookProps,
436
+ waitEventContextTags: waitMap,
437
+ }}
438
+ onStateChange={(state) => {
439
+ capturedState = state;
440
+ }}
441
+ />
442
+ );
443
+
444
+ expect(capturedState.inAppProps.waitEventContextTags).toEqual(waitMap);
445
+ });
427
446
  });
428
447
 
429
448
  describe('isShowInAppCreate', () => {
@@ -33,6 +33,7 @@ const useInAppWrapper = ({
33
33
  onPreviewContentClicked,
34
34
  onTestContentClicked,
35
35
  eventContextTags,
36
+ waitEventContextTags,
36
37
  onCreateComplete,
37
38
  handleClose,
38
39
  templateData,
@@ -149,6 +150,7 @@ const useInAppWrapper = ({
149
150
  onPreviewContentClicked,
150
151
  onTestContentClicked,
151
152
  eventContextTags,
153
+ waitEventContextTags,
152
154
  onCreateComplete,
153
155
  handleClose,
154
156
  };
@@ -173,6 +175,7 @@ const useInAppWrapper = ({
173
175
  onPreviewContentClicked,
174
176
  onTestContentClicked,
175
177
  eventContextTags,
178
+ waitEventContextTags,
176
179
  onCreateComplete,
177
180
  handleClose,
178
181
  ]);
@@ -36,6 +36,7 @@ const InAppWrapper = (props) => {
36
36
  onPreviewContentClicked,
37
37
  onTestContentClicked,
38
38
  eventContextTags,
39
+ waitEventContextTags,
39
40
  onCreateComplete,
40
41
  handleClose,
41
42
  templateData,
@@ -78,6 +79,7 @@ const InAppWrapper = (props) => {
78
79
  onPreviewContentClicked,
79
80
  onTestContentClicked,
80
81
  eventContextTags,
82
+ waitEventContextTags,
81
83
  onCreateComplete,
82
84
  handleClose,
83
85
  templateData,
@@ -124,6 +126,7 @@ InAppWrapper.propTypes = {
124
126
  onPreviewContentClicked: PropTypes.func,
125
127
  onTestContentClicked: PropTypes.func,
126
128
  eventContextTags: PropTypes.array,
129
+ waitEventContextTags: PropTypes.object,
127
130
  onCreateComplete: PropTypes.func,
128
131
  handleClose: PropTypes.func,
129
132
  templateData: PropTypes.object,
@@ -1966,6 +1966,7 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
1966
1966
  hideTestAndPreviewBtn={this.props.hideTestAndPreviewBtn}
1967
1967
  isFullMode={this.props.isFullMode}
1968
1968
  eventContextTags={this.props?.eventContextTags}
1969
+ waitEventContextTags={this.props?.waitEventContextTags}
1969
1970
  messageDetails={this.props?.messageDetails}
1970
1971
  restrictPersonalization={this.props.restrictPersonalization}
1971
1972
  />
@@ -2068,6 +2069,7 @@ Create.propTypes = {
2068
2069
  onPreviewContentClicked: PropTypes.func,
2069
2070
  onTestContentClicked: PropTypes.func,
2070
2071
  eventContextTags: PropTypes.array,
2072
+ waitEventContextTags: PropTypes.object,
2071
2073
  getLiquidTags: PropTypes.func,
2072
2074
  showLiquidErrorInFooter: PropTypes.func,
2073
2075
  showTestAndPreviewSlidebox: PropTypes.bool,
@@ -2233,6 +2233,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
2233
2233
  hideTestAndPreviewBtn={this.props.hideTestAndPreviewBtn}
2234
2234
  isFullMode={this.props.isFullMode}
2235
2235
  eventContextTags={this.props?.eventContextTags}
2236
+ waitEventContextTags={this.props?.waitEventContextTags}
2236
2237
  restrictPersonalization={this.props.restrictPersonalization}
2237
2238
  />;
2238
2239
  })()}
@@ -2339,6 +2340,7 @@ Edit.propTypes = {
2339
2340
  onTestContentClicked: PropTypes.func,
2340
2341
  creativesMode: PropTypes.string,
2341
2342
  eventContextTags: PropTypes.array,
2343
+ waitEventContextTags: PropTypes.object,
2342
2344
  getLiquidTags: PropTypes.func,
2343
2345
  showLiquidErrorInFooter: PropTypes.func,
2344
2346
  showTestAndPreviewSlidebox: PropTypes.bool,
@@ -72,7 +72,7 @@ export class MobilepushWrapper extends React.Component { // eslint-disable-line
72
72
  }
73
73
 
74
74
  render() {
75
- const {mobilePushCreateMode, step, getFormData, getLiquidTags, setIsLoadingContent, isGetFormData, query, isFullMode, showTemplateName, type, onValidationFail, onPreviewContentClicked, onTestContentClicked, templateData, eventContextTags = [], showTestAndPreviewSlidebox, handleTestAndPreview, handleCloseTestAndPreview, restrictPersonalization, isAnonymousType, onPersonalizationTokensChange} = this.props;
75
+ const {mobilePushCreateMode, step, getFormData, getLiquidTags, setIsLoadingContent, isGetFormData, query, isFullMode, showTemplateName, type, onValidationFail, onPreviewContentClicked, onTestContentClicked, templateData, eventContextTags = [], waitEventContextTags = {},showTestAndPreviewSlidebox, handleTestAndPreview, handleCloseTestAndPreview, restrictPersonalization, isAnonymousType, onPersonalizationTokensChange} = this.props;
76
76
  const {templateName} = this.state;
77
77
  const isShowMobilepushCreate = !isEmpty(mobilePushCreateMode);
78
78
  return (
@@ -121,6 +121,7 @@ export class MobilepushWrapper extends React.Component { // eslint-disable-line
121
121
  templateData={templateData}
122
122
  hideTestAndPreviewBtn={this.props.hideTestAndPreviewBtn}
123
123
  eventContextTags={eventContextTags}
124
+ waitEventContextTags={waitEventContextTags}
124
125
  showLiquidErrorInFooter={this.props.showLiquidErrorInFooter}
125
126
  showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
126
127
  handleTestAndPreview={handleTestAndPreview}
@@ -155,6 +156,7 @@ MobilepushWrapper.propTypes = {
155
156
  type: PropTypes.string,
156
157
  onValidationFail: PropTypes.func,
157
158
  eventContextTags: PropTypes.array,
159
+ waitEventContextTags: PropTypes.object,
158
160
  showLiquidErrorInFooter: PropTypes.func,
159
161
  showTestAndPreviewSlidebox: PropTypes.bool,
160
162
  handleTestAndPreview: PropTypes.func,
@@ -144,6 +144,7 @@ export const Rcs = (props) => {
144
144
  orgUnitId,
145
145
  selectedOfferDetails,
146
146
  eventContextTags,
147
+ waitEventContextTags,
147
148
  accountData = {},
148
149
  // TestAndPreviewSlidebox props
149
150
  showTestAndPreviewSlidebox: propsShowTestAndPreviewSlidebox,