@capillarytech/creatives-library 8.0.182 → 8.0.183

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.
@@ -1,6 +1,6 @@
1
1
  import { fromJS } from 'immutable';
2
2
 
3
- import { makeSelectDemoVideoAndLink, setInjectedTags } from 'v2Containers/Cap/selectors';
3
+ import { makeSelectDemoVideoAndLink } from 'v2Containers/Cap/selectors';
4
4
 
5
5
  describe('CapSelectors', () => {
6
6
  const mockState = fromJS({
@@ -11,6 +11,7 @@ describe('CapSelectors', () => {
11
11
  },
12
12
  });
13
13
 
14
+
14
15
  //not need now :Temp
15
16
  // describe('makeSelectLocationState', () => {
16
17
  // it.concurrent('should select the route as a plain JS object', () => {
@@ -49,443 +50,4 @@ describe('CapSelectors', () => {
49
50
  });
50
51
  });
51
52
  });
52
-
53
- describe('setInjectedTags selector', () => {
54
- // Helper function to safely convert result to plain object
55
- const toPlainObject = (result) => {
56
- return result && typeof result.toJS === 'function' ? result.toJS() : result;
57
- };
58
- it('should merge all tag types when all are present', () => {
59
- // Arrange
60
- const state = fromJS({
61
- cap: {
62
- injectedTags: { existing: 'tag1' },
63
- metaEntities: {
64
- tags: {
65
- custom: { customTag: 'customValue' },
66
- extended: { extendedTag: 'extendedValue' },
67
- loyaltyTags: { loyaltyTag: 'loyaltyValue' },
68
- },
69
- },
70
- },
71
- });
72
- // Due to destructuring bug in selector: const { tags } = metaEntities; fails with Immutable Maps
73
- // So tags becomes undefined and only injectedTags is returned
74
- const expected = {
75
- existing: 'tag1',
76
- };
77
- const selector = setInjectedTags();
78
-
79
- // Act
80
- const result = selector(state);
81
-
82
- // Assert
83
- expect(toPlainObject(result)).toEqual(expected);
84
- });
85
-
86
- it('should handle empty globalState with default parameter', () => {
87
- // Arrange
88
- const state = fromJS({ cap: {} });
89
- const expected = {};
90
- const selector = setInjectedTags();
91
-
92
- // Act
93
- const result = selector(state);
94
-
95
- // Assert
96
- expect(toPlainObject(result)).toEqual(expected);
97
- });
98
-
99
- it('should handle undefined injectedTags', () => {
100
- // Arrange
101
- const state = fromJS({
102
- cap: {
103
- metaEntities: {
104
- tags: {
105
- custom: { customTag: 'customValue' },
106
- },
107
- },
108
- },
109
- });
110
- // Since metaEntities is an Immutable Map, destructuring { tags } = metaEntities returns undefined
111
- // So tags will be undefined, and customTags will be undefined
112
- const expected = {};
113
- const selector = setInjectedTags();
114
-
115
- // Act
116
- const result = selector(state);
117
-
118
- // Assert
119
- expect(toPlainObject(result)).toEqual(expected);
120
- });
121
-
122
- it('should handle null injectedTags', () => {
123
- // Arrange
124
- const state = fromJS({
125
- cap: {
126
- injectedTags: null,
127
- metaEntities: {
128
- tags: {
129
- custom: { customTag: 'customValue' },
130
- },
131
- },
132
- },
133
- });
134
- // Same issue - destructuring doesn't work with Immutable Maps
135
- const expected = {};
136
- const selector = setInjectedTags();
137
-
138
- // Act
139
- const result = selector(state);
140
-
141
- // Assert
142
- expect(toPlainObject(result)).toEqual(expected);
143
- });
144
-
145
- it('should handle undefined metaEntities', () => {
146
- // Arrange
147
- const state = fromJS({
148
- cap: {
149
- injectedTags: { existing: 'tag1' },
150
- },
151
- });
152
- const expected = {
153
- existing: 'tag1',
154
- };
155
- const selector = setInjectedTags();
156
-
157
- // Act
158
- const result = selector(state);
159
-
160
- // Assert
161
- expect(toPlainObject(result)).toEqual(expected);
162
- });
163
-
164
- it('should handle null metaEntities', () => {
165
- // Arrange
166
- const state = fromJS({
167
- cap: {
168
- injectedTags: { existing: 'tag1' },
169
- metaEntities: null,
170
- },
171
- });
172
- const expected = {
173
- existing: 'tag1',
174
- };
175
- const selector = setInjectedTags();
176
-
177
- // Act
178
- const result = selector(state);
179
-
180
- // Assert
181
- expect(toPlainObject(result)).toEqual(expected);
182
- });
183
-
184
- it('should handle undefined tags', () => {
185
- // Arrange
186
- const state = fromJS({
187
- cap: {
188
- injectedTags: { existing: 'tag1' },
189
- metaEntities: {},
190
- },
191
- });
192
- const expected = {
193
- existing: 'tag1',
194
- };
195
- const selector = setInjectedTags();
196
-
197
- // Act
198
- const result = selector(state);
199
-
200
- // Assert
201
- expect(toPlainObject(result)).toEqual(expected);
202
- });
203
-
204
- it('should handle null tags', () => {
205
- // Arrange
206
- const state = fromJS({
207
- cap: {
208
- injectedTags: { existing: 'tag1' },
209
- metaEntities: {
210
- tags: null,
211
- },
212
- },
213
- });
214
- // Destructuring { tags } = metaEntities will return undefined because metaEntities is Immutable Map
215
- const expected = {
216
- existing: 'tag1',
217
- };
218
- const selector = setInjectedTags();
219
-
220
- // Act
221
- const result = selector(state);
222
-
223
- // Assert
224
- expect(toPlainObject(result)).toEqual(expected);
225
- });
226
-
227
- it('should handle undefined custom tags', () => {
228
- // Arrange
229
- const state = fromJS({
230
- cap: {
231
- injectedTags: { existing: 'tag1' },
232
- metaEntities: {
233
- tags: {
234
- extended: { extendedTag: 'extendedValue' },
235
- loyaltyTags: { loyaltyTag: 'loyaltyValue' },
236
- },
237
- },
238
- },
239
- });
240
- // Destructuring issue - tags will be undefined
241
- const expected = {
242
- existing: 'tag1',
243
- };
244
- const selector = setInjectedTags();
245
-
246
- // Act
247
- const result = selector(state);
248
-
249
- // Assert
250
- expect(toPlainObject(result)).toEqual(expected);
251
- });
252
-
253
- it('should handle undefined extended tags', () => {
254
- // Arrange
255
- const state = fromJS({
256
- cap: {
257
- injectedTags: { existing: 'tag1' },
258
- metaEntities: {
259
- tags: {
260
- custom: { customTag: 'customValue' },
261
- loyaltyTags: { loyaltyTag: 'loyaltyValue' },
262
- },
263
- },
264
- },
265
- });
266
- // Destructuring issue - tags will be undefined
267
- const expected = {
268
- existing: 'tag1',
269
- };
270
- const selector = setInjectedTags();
271
-
272
- // Act
273
- const result = selector(state);
274
-
275
- // Assert
276
- expect(toPlainObject(result)).toEqual(expected);
277
- });
278
-
279
- it('should handle undefined loyalty tags', () => {
280
- // Arrange
281
- const state = fromJS({
282
- cap: {
283
- injectedTags: { existing: 'tag1' },
284
- metaEntities: {
285
- tags: {
286
- custom: { customTag: 'customValue' },
287
- extended: { extendedTag: 'extendedValue' },
288
- },
289
- },
290
- },
291
- });
292
- // Destructuring issue - tags will be undefined
293
- const expected = {
294
- existing: 'tag1',
295
- };
296
- const selector = setInjectedTags();
297
-
298
- // Act
299
- const result = selector(state);
300
-
301
- // Assert
302
- expect(toPlainObject(result)).toEqual(expected);
303
- });
304
-
305
- it('should handle empty tag objects', () => {
306
- // Arrange
307
- const state = fromJS({
308
- cap: {
309
- injectedTags: { existing: 'tag1' },
310
- metaEntities: {
311
- tags: {
312
- custom: {},
313
- extended: {},
314
- loyaltyTags: {},
315
- },
316
- },
317
- },
318
- });
319
- // Destructuring issue - tags will be undefined
320
- const expected = {
321
- existing: 'tag1',
322
- };
323
- const selector = setInjectedTags();
324
-
325
- // Act
326
- const result = selector(state);
327
-
328
- // Assert
329
- expect(toPlainObject(result)).toEqual(expected);
330
- });
331
-
332
- it('should handle merge with overlapping keys (later values override)', () => {
333
- // Arrange
334
- const state = fromJS({
335
- cap: {
336
- injectedTags: { shared: 'injected', unique1: 'value1' },
337
- metaEntities: {
338
- tags: {
339
- custom: { shared: 'custom', unique2: 'value2' },
340
- extended: { shared: 'extended', unique3: 'value3' },
341
- loyaltyTags: { shared: 'loyalty', unique4: 'value4' },
342
- },
343
- },
344
- },
345
- });
346
- // Destructuring issue - tags will be undefined, so only injectedTags will be returned
347
- const expected = {
348
- shared: 'injected',
349
- unique1: 'value1',
350
- };
351
- const selector = setInjectedTags();
352
-
353
- // Act
354
- const result = selector(state);
355
-
356
- // Assert
357
- expect(toPlainObject(result)).toEqual(expected);
358
- });
359
-
360
- it('should handle only injectedTags with no metaEntities', () => {
361
- // Arrange
362
- const state = fromJS({
363
- cap: {
364
- injectedTags: { onlyInjected: 'value' },
365
- },
366
- });
367
- const expected = {
368
- onlyInjected: 'value',
369
- };
370
- const selector = setInjectedTags();
371
-
372
- // Act
373
- const result = selector(state);
374
-
375
- // Assert
376
- expect(toPlainObject(result)).toEqual(expected);
377
- });
378
-
379
- it('should handle only custom tags with no injectedTags', () => {
380
- // Arrange
381
- const state = fromJS({
382
- cap: {
383
- metaEntities: {
384
- tags: {
385
- custom: { onlyCustom: 'value' },
386
- },
387
- },
388
- },
389
- });
390
- // Destructuring issue - tags will be undefined
391
- const expected = {};
392
- const selector = setInjectedTags();
393
-
394
- // Act
395
- const result = selector(state);
396
-
397
- // Assert
398
- expect(toPlainObject(result)).toEqual(expected);
399
- });
400
-
401
- it('should handle only extended tags with no injectedTags', () => {
402
- // Arrange
403
- const state = fromJS({
404
- cap: {
405
- metaEntities: {
406
- tags: {
407
- extended: { onlyExtended: 'value' },
408
- },
409
- },
410
- },
411
- });
412
- // Destructuring issue - tags will be undefined
413
- const expected = {};
414
- const selector = setInjectedTags();
415
-
416
- // Act
417
- const result = selector(state);
418
-
419
- // Assert
420
- expect(toPlainObject(result)).toEqual(expected);
421
- });
422
-
423
- it('should handle only loyalty tags with no injectedTags', () => {
424
- // Arrange
425
- const state = fromJS({
426
- cap: {
427
- metaEntities: {
428
- tags: {
429
- loyaltyTags: { onlyLoyalty: 'value' },
430
- },
431
- },
432
- },
433
- });
434
- // Destructuring issue - tags will be undefined
435
- const expected = {};
436
- const selector = setInjectedTags();
437
-
438
- // Act
439
- const result = selector(state);
440
-
441
- // Assert
442
- expect(toPlainObject(result)).toEqual(expected);
443
- });
444
-
445
- it('should handle completely empty state', () => {
446
- // Arrange
447
- const state = fromJS({ cap: {} });
448
- const expected = {};
449
- const selector = setInjectedTags();
450
-
451
- // Act
452
- const result = selector(state);
453
-
454
- // Assert
455
- expect(toPlainObject(result)).toEqual(expected);
456
- });
457
-
458
- it('should handle nested object values in tags', () => {
459
- // Arrange
460
- const state = fromJS({
461
- cap: {
462
- injectedTags: {
463
- nested: { level1: { level2: 'deep' } },
464
- simple: 'value',
465
- },
466
- metaEntities: {
467
- tags: {
468
- custom: {
469
- customNested: { customLevel1: 'customDeep' },
470
- customSimple: 'customValue',
471
- },
472
- },
473
- },
474
- },
475
- });
476
- // Destructuring issue - tags will be undefined
477
- const expected = {
478
- nested: { level1: { level2: 'deep' } },
479
- simple: 'value',
480
- };
481
- const selector = setInjectedTags();
482
-
483
- // Act
484
- const result = selector(state);
485
-
486
- // Assert
487
- expect(toPlainObject(result)).toEqual(expected);
488
- });
489
- });
490
53
  });
491
-
@@ -8,7 +8,6 @@ import {
8
8
  DEFAULT_ACTION,
9
9
  HIDE_CONTAINER_LOADER,
10
10
  SHOW_CONTANER_LOADER,
11
- STORE_LOYALTY_TAG_PROPS,
12
11
  } from './constants';
13
12
 
14
13
  export function defaultAction() {
@@ -25,11 +24,4 @@ export function hideCreativesContanerLoader() {
25
24
  return {
26
25
  type: HIDE_CONTAINER_LOADER,
27
26
  };
28
- }
29
-
30
- export function storeLoyaltyTagProps(props) {
31
- return {
32
- type: STORE_LOYALTY_TAG_PROPS,
33
- props,
34
- };
35
- }
27
+ }
@@ -29,7 +29,6 @@ export const LOYALTY_SUPPORTED_ACTION = "SEND_COMMUNICATION_ACTION";
29
29
 
30
30
  export const SHOW_CONTANER_LOADER = "app/CreativesContainer/SHOW_CONTANER_LOADER";
31
31
  export const HIDE_CONTAINER_LOADER = "app/CreativesContainer/HIDE_CONTAINER_LOADER";
32
- export const STORE_LOYALTY_TAG_PROPS = "app/CreativesContainer/STORE_LOYALTY_TAG_PROPS";
33
32
 
34
33
  export const WHATSAPP_HELP_DOC_LINK = "https://docs.capillarytech.com/docs/create-whatsapp-template";
35
34
 
@@ -125,12 +125,6 @@ export class Creatives extends React.Component {
125
125
  if (!this.props?.isFullMode) {
126
126
  this.props?.templateActions.getCdnTransformationConfig();
127
127
  }
128
-
129
- // Store loyalty tag props if loyaltyTagFetchingDependencies is provided
130
- const { loyaltyTagFetchingDependencies } = this.props;
131
- if (loyaltyTagFetchingDependencies) {
132
- this.props.actions.storeLoyaltyTagProps({ ...loyaltyTagFetchingDependencies });
133
- }
134
128
  }
135
129
 
136
130
  onEnterTemplateName = () => {
@@ -1695,7 +1689,6 @@ Creatives.propTypes = {
1695
1689
  orgUnitId: PropTypes.number,
1696
1690
  hostName: PropTypes.string,
1697
1691
  eventContextTags: PropTypes.array,
1698
- loyaltyTagFetchingDependencies: PropTypes.object,
1699
1692
  intl: PropTypes.shape({
1700
1693
  formatMessage: PropTypes.func,
1701
1694
  }),
@@ -9,15 +9,11 @@ import {
9
9
  DEFAULT_ACTION,
10
10
  SHOW_CONTANER_LOADER,
11
11
  HIDE_CONTAINER_LOADER,
12
- STORE_LOYALTY_TAG_PROPS,
13
12
  } from './constants';
14
13
 
15
14
  const initialState = fromJS({containerLoader: true});
16
15
 
17
16
  function creativesContainerReducer(state = initialState, action) {
18
- if (!action || !action.type) {
19
- return state;
20
- }
21
17
  switch (action.type) {
22
18
  case DEFAULT_ACTION:
23
19
  return state;
@@ -25,8 +21,6 @@ function creativesContainerReducer(state = initialState, action) {
25
21
  return state.set('containerLoader', true);
26
22
  case HIDE_CONTAINER_LOADER:
27
23
  return state.set('containerLoader', false);
28
- case STORE_LOYALTY_TAG_PROPS:
29
- return state.set('loyaltyTagProps', action.props);
30
24
  default:
31
25
  return state;
32
26
  }
@@ -22,14 +22,9 @@ const isLoading = () => createSelector(
22
22
  makeSelectCreativesContainer(),
23
23
  (substate) => substate?.containerLoader
24
24
  );
25
- const loyaltyTagProps = () => createSelector(
26
- makeSelectCreativesContainer(),
27
- (substate) => substate?.loyaltyTagProps
28
- );
29
25
 
30
26
  export default makeSelectCreativesContainer;
31
27
  export {
32
28
  selectCreativesContainerDomain,
33
29
  isLoading,
34
- loyaltyTagProps,
35
30
  };
@@ -149,22 +149,6 @@ const MediaUploaders = ({
149
149
  )));
150
150
  }, [getCurrentCarouselData, setCurrentCarouselData]);
151
151
 
152
- // Create carousel button tag select callback at component level to avoid hooks violation
153
- const createCarouselButtonTagSelectCallback = useCallback((cardIndex) => {
154
- return (value) => {
155
- const currentData = getCurrentCarouselData();
156
- const card = currentData[cardIndex];
157
- const button = card?.buttons?.[0];
158
- if (button) {
159
- const newUrl = `${button?.externalLinkValue}{{${value}}}`;
160
- // Update carousel card directly using updateCarouselCard
161
- const updatedButtons = [...card?.buttons];
162
- updatedButtons[0] = { ...updatedButtons[0], externalLinkValue: newUrl };
163
- updateCarouselCard(cardIndex, { buttons: updatedButtons });
164
- }
165
- };
166
- }, [getCurrentCarouselData, updateCarouselCard]);
167
-
168
152
  // Clear previous media data when switching media types
169
153
  useEffect(() => {
170
154
  // Clear carousel data when switching to non-carousel media types
@@ -585,8 +569,13 @@ const MediaUploaders = ({
585
569
 
586
570
  const button = card?.buttons[0]; // We're handling only one button for now
587
571
 
588
- // Use the callback creator instead of useCallback inside render function
589
- const onButtonTagSelect = createCarouselButtonTagSelectCallback(cardIndex);
572
+ const onButtonTagSelect = useCallback(
573
+ (value) => {
574
+ const newUrl = `${button?.externalLinkValue}{{${value}}}`;
575
+ handleCarouselExternalLinkChange(cardIndex, newUrl);
576
+ },
577
+ [handleCarouselExternalLinkChange, button?.externalLinkValue]
578
+ );
590
579
 
591
580
  return (
592
581
  <>
@@ -658,7 +647,7 @@ const MediaUploaders = ({
658
647
  )}
659
648
  {button?.linkType === EXTERNAL_LINK && (
660
649
  <CapColumn span={14}>
661
- <CapRow className="buttons-heading-container">
650
+ <CapRow>
662
651
  <CapHeading type="h4" className="buttons-heading">
663
652
  {formatMessage(messages.externalLink)}
664
653
  </CapHeading>
@@ -148,15 +148,10 @@
148
148
  margin-bottom: $CAP_SPACE_16;
149
149
  }
150
150
 
151
- .buttons-heading-container {
152
- display: flex;
153
- justify-content: space-between;
154
- }
155
-
156
151
  .buttons-heading {
157
152
  margin-bottom: $CAP_SPACE_12;
158
153
  margin-top: $CAP_SPACE_12;
159
- margin-right: 43%;
154
+ margin-right: 48%;
160
155
  }
161
156
 
162
157
  .helper-text {
@@ -7,8 +7,7 @@ import * as Api from '../../services/api';
7
7
  import * as types from './constants';
8
8
  import { saveCdnConfigs, removeAllCdnLocalStorageItems } from '../../utils/cdnTransformation';
9
9
  import { COPY_OF } from '../../constants/unified';
10
- import { ZALO_TEMPLATE_INFO_REQUEST } from '../Zalo/constants';
11
- import { getTemplateInfoById } from '../Zalo/saga';
10
+ // Removed Zalo imports - handled by Zalo component's own saga
12
11
  import { watchCreateTemplate } from '../MobilePushNew/sagas';
13
12
  // Individual exports for testing
14
13
  export function* getAllTemplates(channel, queryParams) {
@@ -227,9 +226,6 @@ export function* watchGetCdnTransformationConfig() {
227
226
  );
228
227
  }
229
228
 
230
- export function* watchForGetTemplateInfoById() {
231
- yield takeLatest(ZALO_TEMPLATE_INFO_REQUEST, getTemplateInfoById);
232
- }
233
229
 
234
230
  // All sagas to be loaded
235
231
  export default [
@@ -255,7 +251,7 @@ export function* v2TemplateSaga() {
255
251
  watchGetCdnTransformationConfig(),
256
252
  watchFetchWeCrmAccounts(),
257
253
  watchGetSenderDetails(),
258
- watchForGetTemplateInfoById(),
254
+ // Removed watchForGetTemplateInfoById() - this is handled by Zalo component's own saga
259
255
  ]);
260
256
  }
261
257