@capillarytech/creatives-library 8.0.329 → 8.0.330

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 (122) hide show
  1. package/constants/unified.js +0 -14
  2. package/package.json +1 -1
  3. package/services/api.js +0 -17
  4. package/services/tests/api.test.js +0 -85
  5. package/utils/commonUtils.js +0 -10
  6. package/utils/tests/commonUtil.test.js +0 -169
  7. package/v2Components/CapTagList/index.js +0 -10
  8. package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +49 -70
  9. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +2 -8
  10. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +21 -207
  11. package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +0 -16
  12. package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +10 -85
  13. package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +0 -30
  14. package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +11 -79
  15. package/v2Components/CommonTestAndPreview/SendTestMessage.js +53 -87
  16. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +1 -20
  17. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +4 -133
  18. package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +34 -145
  19. package/v2Components/CommonTestAndPreview/actions.js +0 -10
  20. package/v2Components/CommonTestAndPreview/constants.js +1 -53
  21. package/v2Components/CommonTestAndPreview/index.js +168 -1006
  22. package/v2Components/CommonTestAndPreview/messages.js +3 -147
  23. package/v2Components/CommonTestAndPreview/reducer.js +0 -10
  24. package/v2Components/CommonTestAndPreview/sagas.js +6 -15
  25. package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +286 -328
  26. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +65 -231
  27. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +5 -118
  28. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +0 -341
  29. package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +24 -65
  30. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +1 -199
  31. package/v2Components/CommonTestAndPreview/tests/constants.test.js +1 -31
  32. package/v2Components/CommonTestAndPreview/tests/index.test.js +4 -168
  33. package/v2Components/CommonTestAndPreview/tests/reducer.test.js +0 -71
  34. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +2 -2
  35. package/v2Components/CommonTestAndPreview/tests/selectors.test.js +0 -17
  36. package/v2Components/FormBuilder/index.js +1 -7
  37. package/v2Components/TestAndPreviewSlidebox/index.js +1 -8
  38. package/v2Components/TestAndPreviewSlidebox/sagas.js +4 -11
  39. package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +1 -3
  40. package/v2Containers/CreativesContainer/SlideBoxContent.js +4 -36
  41. package/v2Containers/CreativesContainer/SlideBoxFooter.js +1 -10
  42. package/v2Containers/CreativesContainer/SlideBoxHeader.js +4 -29
  43. package/v2Containers/CreativesContainer/constants.js +0 -9
  44. package/v2Containers/CreativesContainer/index.js +93 -286
  45. package/v2Containers/CreativesContainer/index.scss +1 -51
  46. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +34 -78
  47. package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +16 -79
  48. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -8
  49. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +98 -357
  50. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +10 -20
  51. package/v2Containers/CreativesContainer/tests/index.test.js +9 -71
  52. package/v2Containers/Rcs/constants.js +1 -34
  53. package/v2Containers/Rcs/index.js +884 -999
  54. package/v2Containers/Rcs/index.scss +6 -85
  55. package/v2Containers/Rcs/messages.js +1 -10
  56. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +2453 -41456
  57. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +5 -0
  58. package/v2Containers/Rcs/tests/index.test.js +38 -41
  59. package/v2Containers/Rcs/tests/mockData.js +0 -38
  60. package/v2Containers/Rcs/tests/utils.test.js +1 -379
  61. package/v2Containers/Rcs/utils.js +10 -358
  62. package/v2Containers/Sms/Create/index.js +38 -100
  63. package/v2Containers/SmsTrai/Create/index.js +4 -9
  64. package/v2Containers/SmsTrai/Edit/constants.js +0 -2
  65. package/v2Containers/SmsTrai/Edit/index.js +128 -609
  66. package/v2Containers/SmsTrai/Edit/messages.js +4 -9
  67. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +2600 -4586
  68. package/v2Containers/SmsWrapper/index.js +8 -37
  69. package/v2Containers/TagList/index.js +0 -6
  70. package/v2Containers/Templates/_templates.scss +2 -63
  71. package/v2Containers/Templates/actions.js +0 -11
  72. package/v2Containers/Templates/constants.js +0 -2
  73. package/v2Containers/Templates/index.js +40 -90
  74. package/v2Containers/Templates/sagas.js +12 -57
  75. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1079 -1043
  76. package/v2Containers/Templates/tests/sagas.test.js +123 -193
  77. package/v2Containers/TemplatesV2/TemplatesV2.style.js +1 -72
  78. package/v2Containers/TemplatesV2/index.js +23 -86
  79. package/v2Containers/Whatsapp/index.js +20 -3
  80. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +4872 -5790
  81. package/utils/templateVarUtils.js +0 -172
  82. package/utils/tests/templateVarUtils.test.js +0 -160
  83. package/v2Components/CommonTestAndPreview/AddTestCustomer.js +0 -42
  84. package/v2Components/CommonTestAndPreview/CustomerCreationModal.js +0 -155
  85. package/v2Components/CommonTestAndPreview/ExistingCustomerModal.js +0 -93
  86. package/v2Components/CommonTestAndPreview/previewApiUtils.js +0 -59
  87. package/v2Components/CommonTestAndPreview/tests/AddTestCustomer.test.js +0 -66
  88. package/v2Components/CommonTestAndPreview/tests/CommonTestAndPreview.addTestCustomer.test.js +0 -648
  89. package/v2Components/CommonTestAndPreview/tests/CustomerCreationModal.test.js +0 -174
  90. package/v2Components/CommonTestAndPreview/tests/ExistingCustomerModal.test.js +0 -114
  91. package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +0 -67
  92. package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +0 -87
  93. package/v2Components/SmsFallback/constants.js +0 -73
  94. package/v2Components/SmsFallback/index.js +0 -955
  95. package/v2Components/SmsFallback/index.scss +0 -265
  96. package/v2Components/SmsFallback/messages.js +0 -78
  97. package/v2Components/SmsFallback/smsFallbackUtils.js +0 -107
  98. package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +0 -50
  99. package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +0 -147
  100. package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +0 -304
  101. package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +0 -197
  102. package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +0 -261
  103. package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +0 -422
  104. package/v2Components/SmsFallback/useLocalTemplateList.js +0 -92
  105. package/v2Components/VarSegmentMessageEditor/constants.js +0 -2
  106. package/v2Components/VarSegmentMessageEditor/index.js +0 -125
  107. package/v2Components/VarSegmentMessageEditor/index.scss +0 -46
  108. package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +0 -43
  109. package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +0 -67
  110. package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +0 -90
  111. package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +0 -258
  112. package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +0 -125
  113. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +0 -205
  114. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -251
  115. package/v2Containers/Sms/smsFormDataHelpers.js +0 -67
  116. package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +0 -253
  117. package/v2Containers/SmsTrai/Edit/index.scss +0 -121
  118. package/v2Containers/Templates/TemplatesActionBar.js +0 -101
  119. package/v2Containers/Templates/tests/TemplatesActionBar.test.js +0 -120
  120. package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +0 -180
  121. package/v2Containers/Templates/utils/smsTemplatesListApi.js +0 -79
  122. package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +0 -131
@@ -1,258 +0,0 @@
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
- });
@@ -1,125 +0,0 @@
1
- /**
2
- * Covers local-templates flag resolution: nested `localTemplatesConfig.useLocalTemplates`
3
- * vs top-level `useLocalTemplates` (embedded consumers / SlideBoxContent).
4
- */
5
- import React from 'react';
6
- import { shallowWithIntl } from '../../../helpers/intl-enzym-test-helpers';
7
- import { Creatives } from '../index';
8
- import mockdata from '../../mockdata';
9
-
10
- const { smsTemplates, loyaltyMetaData } = mockdata;
11
-
12
- jest.mock('../../../v2Components/FormBuilder', () => ({
13
- __esModule: true,
14
- default: (props) => (
15
- <div className="FormBuilder-mock" {...props}>
16
- FormBuilder
17
- </div>
18
- ),
19
- }));
20
-
21
- const baseProps = {
22
- loyaltyMetaData,
23
- Templates: smsTemplates,
24
- channel: 'SMS',
25
- creativesMode: 'create',
26
- templateData: null,
27
- isFullMode: true,
28
- handleCloseCreatives: jest.fn(),
29
- getCreativesData: jest.fn(),
30
- templateActions: {
31
- getCdnTransformationConfig: jest.fn(),
32
- resetTemplateStoreData: jest.fn(),
33
- },
34
- globalActions: {
35
- clearMetaEntities: jest.fn(),
36
- },
37
- };
38
-
39
- describe('CreativesContainer useLocalTemplates prop resolution', () => {
40
- beforeEach(() => {
41
- jest.clearAllMocks();
42
- });
43
-
44
- it('initial slidebox is templates when only top-level useLocalTemplates is true', () => {
45
- const wrapper = shallowWithIntl(
46
- <Creatives
47
- {...baseProps}
48
- useLocalTemplates
49
- />,
50
- );
51
- expect(wrapper.instance().state.slidBoxContent).toBe('templates');
52
- });
53
-
54
- it('initial slidebox is templates when localTemplatesConfig.useLocalTemplates is true', () => {
55
- const wrapper = shallowWithIntl(
56
- <Creatives
57
- {...baseProps}
58
- localTemplatesConfig={{ useLocalTemplates: true }}
59
- />,
60
- );
61
- expect(wrapper.instance().state.slidBoxContent).toBe('templates');
62
- });
63
-
64
- it('does not reset template store on unmount when embedded and top-level useLocalTemplates is true', () => {
65
- const wrapper = shallowWithIntl(
66
- <Creatives
67
- {...baseProps}
68
- location={{ query: { type: 'embedded' } }}
69
- useLocalTemplates
70
- />,
71
- );
72
- wrapper.unmount();
73
- expect(baseProps.templateActions.resetTemplateStoreData).not.toHaveBeenCalled();
74
- expect(baseProps.globalActions.clearMetaEntities).toHaveBeenCalled();
75
- });
76
-
77
- it('resets template store on unmount when embedded and local templates are not used', () => {
78
- const wrapper = shallowWithIntl(
79
- <Creatives
80
- {...baseProps}
81
- location={{ query: { type: 'embedded' } }}
82
- useLocalTemplates={false}
83
- />,
84
- );
85
- wrapper.unmount();
86
- expect(baseProps.templateActions.resetTemplateStoreData).toHaveBeenCalled();
87
- expect(baseProps.globalActions.clearMetaEntities).toHaveBeenCalled();
88
- });
89
-
90
- it('prefers nested localTemplatesConfig.useLocalTemplates=false over top-level true (not local list mode)', () => {
91
- const wrapper = shallowWithIntl(
92
- <Creatives
93
- {...baseProps}
94
- localTemplatesConfig={{ useLocalTemplates: false }}
95
- useLocalTemplates
96
- />,
97
- );
98
- expect(wrapper.instance().state.slidBoxContent).toBe('createTemplate');
99
- });
100
-
101
- it('uses top-level useLocalTemplates when localTemplatesConfig omits the flag', () => {
102
- const wrapper = shallowWithIntl(
103
- <Creatives
104
- {...baseProps}
105
- localTemplatesConfig={{}}
106
- useLocalTemplates
107
- />,
108
- );
109
- expect(wrapper.instance().state.slidBoxContent).toBe('templates');
110
- });
111
-
112
- it('resets template store when nested useLocalTemplates is false even if top-level is true', () => {
113
- const wrapper = shallowWithIntl(
114
- <Creatives
115
- {...baseProps}
116
- location={{ query: { type: 'embedded' } }}
117
- localTemplatesConfig={{ useLocalTemplates: false }}
118
- useLocalTemplates
119
- />,
120
- );
121
- wrapper.unmount();
122
- expect(baseProps.templateActions.resetTemplateStoreData).toHaveBeenCalled();
123
- expect(baseProps.globalActions.clearMetaEntities).toHaveBeenCalled();
124
- });
125
- });
@@ -1,205 +0,0 @@
1
- import isEmpty from 'lodash/isEmpty';
2
- import get from 'lodash/get';
3
- import { RCS_SMS_FALLBACK_VAR_MAPPED_PROP } from '../../v2Components/CommonTestAndPreview/constants';
4
-
5
- /**
6
- * Nested `versions…smsFallBackContent` and root `smsFallBackContent` (CreativesContainer mirror)
7
- * can diverge. Merge explicitly (avoid `get(..., {}) || root` — `{}` is truthy and blocks fallback).
8
- *
9
- * When both exist, **nested wins on overlap**: the canonical RCS path is what `createPayload` / submit
10
- * update; the root mirror can lag behind campaign parent state and would otherwise keep old
11
- * `message` / `rcsSmsFallbackVarMapped` in hydration and approval payloads.
12
- */
13
- export function mergeRcsSmsFallBackContentFromDetails(details) {
14
- if (!details || typeof details !== 'object') return {};
15
- const nestedSmsFallback = details?.versions?.base?.content?.RCS?.smsFallBackContent;
16
- const rootSmsFallback = details?.smsFallBackContent;
17
- const nestedRecord =
18
- nestedSmsFallback != null && typeof nestedSmsFallback === 'object' ? nestedSmsFallback : {};
19
- const rootRecord =
20
- rootSmsFallback != null && typeof rootSmsFallback === 'object' ? rootSmsFallback : {};
21
- return { ...rootRecord, ...nestedRecord };
22
- }
23
-
24
- /**
25
- * Merge SMS fallback slot maps from API/templateData (`apiShape`) and editor state (`localShape`).
26
- * Spreading `{ ...api, ...local }` lets `rcsSmsFallbackVarMapped: {}` on local wipe a populated API map,
27
- * which keeps Done disabled in DLT campaigns until fixed.
28
- */
29
- export function mergeRcsSmsFallbackVarMapLayers(apiShape = {}, localShape = {}) {
30
- const readMap = (o) => {
31
- if (!o || typeof o !== 'object') return {};
32
- const camel = o.rcsSmsFallbackVarMapped;
33
- const kebab = o['rcs-sms-fallback-var-mapped'];
34
- const src =
35
- camel && typeof camel === 'object'
36
- ? camel
37
- : kebab && typeof kebab === 'object'
38
- ? kebab
39
- : {};
40
- return { ...src };
41
- };
42
- return { ...readMap(apiShape), ...readMap(localShape) };
43
- }
44
-
45
- /**
46
- * First non-empty trimmed string for SMS fallback body used in DLT slot checks / payload `templateContent`.
47
- * Prefer **raw** template fields before resolved `message` so `{#…#}` / `{{…}}` tokens are not lost
48
- * when `message` is consumer-resolved text (campaigns).
49
- */
50
- /**
51
- * Whether an SMS fallback object carries template body, name, or var-map data (same rule as Rcs `createPayload`).
52
- */
53
- export function hasMeaningfulSmsFallbackShape(s) {
54
- return !!(
55
- s
56
- && (
57
- String(
58
- s.content
59
- || s.templateContent
60
- || s.message
61
- || s.smsContent
62
- || s.smsTemplateContent
63
- || '',
64
- ).trim() !== ''
65
- || String(s.templateName || s.smsTemplateName || '').trim() !== ''
66
- || (s.rcsSmsFallbackVarMapped && Object.keys(s.rcsSmsFallbackVarMapped).length > 0)
67
- || (s[RCS_SMS_FALLBACK_VAR_MAPPED_PROP]
68
- && Object.keys(s[RCS_SMS_FALLBACK_VAR_MAPPED_PROP]).length > 0)
69
- )
70
- );
71
- }
72
-
73
- /**
74
- * Library `templateData`: merged root + nested `smsFallBackContent` (nested wins), matching `createPayload`.
75
- */
76
- export function getLibrarySmsFallbackApiBaselineFromTemplateData(templateData) {
77
- const smsFromTemplateRoot = get(
78
- templateData,
79
- 'versions.base.content.RCS.smsFallBackContent',
80
- );
81
- return {
82
- ...(templateData?.smsFallBackContent && typeof templateData.smsFallBackContent === 'object'
83
- ? templateData.smsFallBackContent
84
- : {}),
85
- ...(smsFromTemplateRoot && typeof smsFromTemplateRoot === 'object'
86
- ? smsFromTemplateRoot
87
- : {}),
88
- };
89
- }
90
-
91
- export function pickFirstSmsFallbackTemplateString(sms = {}) {
92
- if (!sms || typeof sms !== 'object') return '';
93
- const keys = [
94
- 'templateContent',
95
- 'smsTemplateContent',
96
- 'content',
97
- 'smsContent',
98
- 'message',
99
- ];
100
- for (let i = 0; i < keys.length; i += 1) {
101
- const v = sms[keys[i]];
102
- if (v == null) continue;
103
- const s = String(v).trim();
104
- if (s) return s;
105
- }
106
- return '';
107
- }
108
-
109
- /**
110
- * Campaign reopen: payloads often keep tag/label values on numeric keys (`"1"`, `"2"`, …) while
111
- * semantic keys (`user_name`, …) stay `""`. Copy non-empty slot values onto empty semantic keys so
112
- * VarSegment editors prepopulate after Done → Edit without changing global resolve behavior.
113
- */
114
- export function syncCardVarMappedSemanticsFromSlots(
115
- cardVarMappedInput,
116
- templateTitle,
117
- templateDesc,
118
- rcsVarRegex,
119
- ) {
120
- const cardVarMappedSynced =
121
- cardVarMappedInput != null && typeof cardVarMappedInput === 'object'
122
- ? { ...cardVarMappedInput }
123
- : {};
124
- const getVarNameFromToken = (token = '') => token.replace(/^\{\{|\}\}$/g, '');
125
- const templateVarTokens = [
126
- ...(templateTitle?.match(rcsVarRegex) ?? []),
127
- ...(templateDesc?.match(rcsVarRegex) ?? []),
128
- ];
129
- templateVarTokens.forEach((token, slotIndexZeroBased) => {
130
- const semanticVarName = getVarNameFromToken(token);
131
- if (!semanticVarName) return;
132
- const numericSlotKey = String(slotIndexZeroBased + 1);
133
- const semanticValueTrimmed = String(cardVarMappedSynced[semanticVarName] ?? '').trim();
134
- const numericSlotValueTrimmed = String(cardVarMappedSynced[numericSlotKey] ?? '').trim();
135
- if (!semanticValueTrimmed && numericSlotValueTrimmed) {
136
- cardVarMappedSynced[semanticVarName] = cardVarMappedSynced[numericSlotKey];
137
- }
138
- });
139
- return cardVarMappedSynced;
140
- }
141
-
142
- /**
143
- * Maps resolved campaign values back to `{{semanticKey}}` using `cardVarMapped` keys.
144
- * Used when hydrating library/journey RCS edit from payloads without existing `{{…}}` tokens.
145
- */
146
- export function getUnmappedDesc(str, mapping) {
147
- if (!str) return '';
148
- if (!mapping || Object.keys(mapping).length === 0) return str;
149
- let result = str;
150
- const replacements = [];
151
- Object.entries(mapping).forEach(([key, value]) => {
152
- const raw = (value ?? '').toString();
153
- if (!raw || raw?.trim?.() === '') return;
154
- const braced = /^\{\{[\s\S]*\}\}$/.test(raw) ? raw : `{{${raw}}}`;
155
- replacements.push({ key, needle: raw });
156
- if (braced !== raw) replacements.push({ key, needle: braced });
157
- });
158
- const seen = new Set();
159
- const uniq = replacements
160
- .filter(({ key, needle }) => {
161
- const id = `${key}::${needle}`;
162
- if (seen.has(id)) return false;
163
- seen.add(id);
164
- return true;
165
- })
166
- .sort((a, b) => (b.needle.length - a.needle.length));
167
-
168
- uniq.forEach(({ key, needle }) => {
169
- if (!needle) return;
170
- const escaped = needle.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
171
- const regex = new RegExp(escaped, 'g');
172
- result = result.replace(regex, `{{${key}}}`);
173
- });
174
- return result;
175
- }
176
-
177
- export function hasRcsVarTokens(s, rcsVarRegex) {
178
- return (s?.match(rcsVarRegex) ?? []).length > 0;
179
- }
180
-
181
- /**
182
- * Library / journey: only run `getUnmappedDesc` when the loaded copy has no `{{…}}` tokens
183
- * (e.g. fully resolved campaign text). If the API already has numeric or named slots, keep as-is.
184
- */
185
- export function normalizeLibraryLoadedTitleDesc({
186
- loadedTitle,
187
- loadedDesc,
188
- isFullMode,
189
- cardVarMappedAfterHydration,
190
- rcsVarRegex,
191
- }) {
192
- const normalizedTitle =
193
- !isFullMode
194
- && !isEmpty(cardVarMappedAfterHydration)
195
- && !hasRcsVarTokens(loadedTitle, rcsVarRegex)
196
- ? getUnmappedDesc(loadedTitle, cardVarMappedAfterHydration)
197
- : loadedTitle;
198
- const normalizedDesc =
199
- !isFullMode
200
- && !isEmpty(cardVarMappedAfterHydration)
201
- && !hasRcsVarTokens(loadedDesc, rcsVarRegex)
202
- ? getUnmappedDesc(loadedDesc, cardVarMappedAfterHydration)
203
- : loadedDesc;
204
- return { normalizedTitle, normalizedDesc };
205
- }