@capillarytech/creatives-library 9.0.36-alpha.0 → 9.0.36
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.
- package/app.js +175 -10
- package/entry.js +1 -67
- package/mfe-exposed-components.js +4 -2
- package/package.json +2 -2
- package/services/api.js +1 -9
- package/styles/containers/layout/_layoutPage.scss +6 -8
- package/utils/gtmTrackers/gtmEvents/creativeDetails.js +1 -2
- package/utils/rcsPayloadUtils.js +2 -5
- package/utils/tests/rcsPayloadUtils.test.js +2 -54
- package/v2Components/CapActionButton/constants.js +0 -1
- package/v2Components/CapActionButton/index.js +9 -77
- package/v2Components/CapActionButton/index.scss +0 -13
- package/v2Components/CapActionButton/messages.js +0 -13
- package/v2Components/CapActionButton/tests/index.test.js +1 -32
- package/v2Components/CommonTestAndPreview/UnifiedPreview/ViberPreviewContent.js +15 -108
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +1 -139
- package/v2Components/CommonTestAndPreview/index.js +41 -284
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/ViberPreviewContent.test.js +0 -364
- package/v2Components/CommonTestAndPreview/tests/index.test.js +0 -78
- package/v2Components/CommonTestAndPreview/utils.js +0 -34
- package/v2Components/NavigationBar/index.js +7 -9
- package/v2Components/NavigationBar/tests/index.test.js +19 -39
- package/v2Components/SmsFallback/index.js +0 -6
- package/v2Containers/Cap/constants.js +0 -1
- package/v2Containers/Cap/index.js +27 -57
- package/v2Containers/CreativesContainer/index.js +8 -11
- package/v2Containers/CreativesContainer/tests/index.test.js +0 -53
- package/v2Containers/Rcs/carouselUtils.js +73 -46
- package/v2Containers/Rcs/components/CarouselCard.js +9 -11
- package/v2Containers/Rcs/components/CarouselCardButtons.js +0 -20
- package/v2Containers/Rcs/constants.js +7 -2
- package/v2Containers/Rcs/index.js +205 -226
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +47 -60
- package/v2Containers/Rcs/tests/CarouselCard.test.js +2 -1
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +0 -286
- package/v2Containers/Rcs/tests/carouselUtils.test.js +32 -28
- package/v2Containers/Rcs/tests/index.test.js +238 -151
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -110
- package/v2Containers/Rcs/tests/utils.test.js +17 -36
- package/v2Containers/Rcs/utils.js +55 -28
- package/v2Containers/SmsTrai/Edit/index.js +24 -35
- package/v2Containers/Templates/_templates.scss +1 -115
- package/v2Containers/Templates/index.js +10 -91
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +0 -5
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +3 -8
- package/v2Containers/TemplatesV2/index.js +9 -22
- package/v2Containers/Viber/constants.js +0 -21
- package/v2Containers/Viber/index.js +49 -719
- package/v2Containers/Viber/index.scss +0 -175
- package/v2Containers/Viber/messages.js +0 -121
- package/v2Containers/Viber/tests/index.test.js +0 -80
- package/AppRoot.js +0 -124
- package/app-config.js +0 -61
- package/bootstrap.js +0 -185
- package/utils/getDataLayer.js +0 -15
- package/utils/mfeDetect.js +0 -1
- package/utils/mfeFirstPaintReady.js +0 -29
- package/utils/mfeHistory.js +0 -62
- package/v2Components/CommonTestAndPreview/UnifiedPreview/ViberCarouselPreviewCards.js +0 -132
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_viberCarouselPreviewCards.scss +0 -131
- package/v2Components/NavigationBar/mfeModuleHeader.config.js +0 -16
|
@@ -200,370 +200,6 @@ describe('ViberPreviewContent', () => {
|
|
|
200
200
|
|
|
201
201
|
expect(screen.getByText('Click Here')).toBeTruthy();
|
|
202
202
|
});
|
|
203
|
-
|
|
204
|
-
it('should not render button when buttonText has only whitespace', () => {
|
|
205
|
-
const props = {
|
|
206
|
-
...defaultProps,
|
|
207
|
-
content: {
|
|
208
|
-
viberPreviewContent: {
|
|
209
|
-
messageContent: 'Message',
|
|
210
|
-
buttonText: ' ',
|
|
211
|
-
},
|
|
212
|
-
},
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
const { container } = render(
|
|
216
|
-
<TestWrapper>
|
|
217
|
-
<ComponentToRender {...props} />
|
|
218
|
-
</TestWrapper>
|
|
219
|
-
);
|
|
220
|
-
|
|
221
|
-
expect(container.querySelector('.viber-button-base')).toBeFalsy();
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
describe('Carousel Content', () => {
|
|
226
|
-
it('should render no content when carousel is selected but cards are empty', () => {
|
|
227
|
-
const props = {
|
|
228
|
-
...defaultProps,
|
|
229
|
-
content: {
|
|
230
|
-
viberPreviewContent: {
|
|
231
|
-
type: 'CAROUSEL',
|
|
232
|
-
cards: [
|
|
233
|
-
{
|
|
234
|
-
text: '',
|
|
235
|
-
mediaUrl: '',
|
|
236
|
-
buttons: [
|
|
237
|
-
{ title: '', action: '' },
|
|
238
|
-
],
|
|
239
|
-
},
|
|
240
|
-
{
|
|
241
|
-
text: ' ',
|
|
242
|
-
mediaUrl: ' ',
|
|
243
|
-
buttons: [
|
|
244
|
-
{ title: ' ', action: 'https://example.com/2' },
|
|
245
|
-
],
|
|
246
|
-
},
|
|
247
|
-
],
|
|
248
|
-
},
|
|
249
|
-
},
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
render(
|
|
253
|
-
<TestWrapper>
|
|
254
|
-
<ComponentToRender {...props} />
|
|
255
|
-
</TestWrapper>
|
|
256
|
-
);
|
|
257
|
-
|
|
258
|
-
expect(screen.getByText('No content available')).toBeTruthy();
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
it('should render carousel cards when type is CAROUSEL', () => {
|
|
262
|
-
const props = {
|
|
263
|
-
...defaultProps,
|
|
264
|
-
content: {
|
|
265
|
-
viberPreviewContent: {
|
|
266
|
-
type: 'CAROUSEL',
|
|
267
|
-
cards: [
|
|
268
|
-
{
|
|
269
|
-
text: 'Card 1 text',
|
|
270
|
-
mediaUrl: 'https://image.url/card1.jpg',
|
|
271
|
-
buttons: [
|
|
272
|
-
{ title: 'Button 1', action: 'https://example.com/1' },
|
|
273
|
-
],
|
|
274
|
-
},
|
|
275
|
-
{
|
|
276
|
-
text: 'Card 2 text',
|
|
277
|
-
mediaUrl: 'https://image.url/card2.jpg',
|
|
278
|
-
buttons: [
|
|
279
|
-
{ title: 'Button 2', action: 'https://example.com/2' },
|
|
280
|
-
],
|
|
281
|
-
},
|
|
282
|
-
],
|
|
283
|
-
},
|
|
284
|
-
},
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
render(
|
|
288
|
-
<TestWrapper>
|
|
289
|
-
<ComponentToRender {...props} />
|
|
290
|
-
</TestWrapper>
|
|
291
|
-
);
|
|
292
|
-
|
|
293
|
-
expect(screen.getByText('Card 1 text')).toBeTruthy();
|
|
294
|
-
expect(screen.getByText('Card 2 text')).toBeTruthy();
|
|
295
|
-
expect(screen.getByText('Button 1')).toBeTruthy();
|
|
296
|
-
expect(screen.getByText('Button 2')).toBeTruthy();
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
it('should not render empty carousel button placeholder', () => {
|
|
300
|
-
const props = {
|
|
301
|
-
...defaultProps,
|
|
302
|
-
content: {
|
|
303
|
-
viberPreviewContent: {
|
|
304
|
-
type: 'CAROUSEL',
|
|
305
|
-
cards: [
|
|
306
|
-
{
|
|
307
|
-
text: 'Card 1 text',
|
|
308
|
-
mediaUrl: 'https://image.url/card1.jpg',
|
|
309
|
-
buttons: [
|
|
310
|
-
{ title: '', action: 'https://example.com/1' },
|
|
311
|
-
{ title: ' ', action: 'https://example.com/2' },
|
|
312
|
-
],
|
|
313
|
-
},
|
|
314
|
-
],
|
|
315
|
-
},
|
|
316
|
-
},
|
|
317
|
-
};
|
|
318
|
-
|
|
319
|
-
const { container } = render(
|
|
320
|
-
<TestWrapper>
|
|
321
|
-
<ComponentToRender {...props} />
|
|
322
|
-
</TestWrapper>
|
|
323
|
-
);
|
|
324
|
-
|
|
325
|
-
expect(container.querySelector('.viber-carousel-preview-button')).toBeNull();
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
it('should show carousel shell when showCarouselEditorPreview is true even if cards are empty', () => {
|
|
329
|
-
const props = {
|
|
330
|
-
...defaultProps,
|
|
331
|
-
content: {
|
|
332
|
-
viberPreviewContent: {
|
|
333
|
-
type: 'CAROUSEL',
|
|
334
|
-
showCarouselEditorPreview: true,
|
|
335
|
-
cards: [
|
|
336
|
-
{ text: '', mediaUrl: '', buttons: [{ title: '', action: '' }] },
|
|
337
|
-
{ text: '', mediaUrl: '', buttons: [{ title: '', action: '' }] },
|
|
338
|
-
],
|
|
339
|
-
},
|
|
340
|
-
},
|
|
341
|
-
};
|
|
342
|
-
|
|
343
|
-
const { container } = render(
|
|
344
|
-
<TestWrapper>
|
|
345
|
-
<ComponentToRender {...props} />
|
|
346
|
-
</TestWrapper>
|
|
347
|
-
);
|
|
348
|
-
|
|
349
|
-
expect(screen.queryByText('No content available')).toBeNull();
|
|
350
|
-
expect(container.querySelector('.viber-carousel-preview-scroll')).toBeTruthy();
|
|
351
|
-
expect(container.querySelector('.viber-carousel-message-box-placeholder')).toBeTruthy();
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
it('should render carousel message text in message box when type is CAROUSEL', () => {
|
|
355
|
-
const props = {
|
|
356
|
-
...defaultProps,
|
|
357
|
-
content: {
|
|
358
|
-
viberPreviewContent: {
|
|
359
|
-
type: 'CAROUSEL',
|
|
360
|
-
messageContent: 'Carousel intro copy',
|
|
361
|
-
cards: [
|
|
362
|
-
{
|
|
363
|
-
text: 'Card text',
|
|
364
|
-
mediaUrl: 'https://image.url/c.jpg',
|
|
365
|
-
buttons: [{ title: 'Go', action: 'https://example.com' }],
|
|
366
|
-
},
|
|
367
|
-
],
|
|
368
|
-
},
|
|
369
|
-
},
|
|
370
|
-
};
|
|
371
|
-
|
|
372
|
-
const { container } = render(
|
|
373
|
-
<TestWrapper>
|
|
374
|
-
<ComponentToRender {...props} />
|
|
375
|
-
</TestWrapper>
|
|
376
|
-
);
|
|
377
|
-
|
|
378
|
-
expect(container.querySelector('.viber-carousel-message-box-text')).toHaveTextContent('Carousel intro copy');
|
|
379
|
-
expect(screen.queryByText('Carousel intro copy')).toBeTruthy();
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
it('should hide account icon when carousel is shown', () => {
|
|
383
|
-
const props = {
|
|
384
|
-
...defaultProps,
|
|
385
|
-
content: {
|
|
386
|
-
viberPreviewContent: {
|
|
387
|
-
type: 'CAROUSEL',
|
|
388
|
-
cards: [
|
|
389
|
-
{
|
|
390
|
-
text: 'Carousel card line',
|
|
391
|
-
mediaUrl: '',
|
|
392
|
-
buttons: [{ title: 'Open link', action: 'https://x.com' }],
|
|
393
|
-
},
|
|
394
|
-
],
|
|
395
|
-
},
|
|
396
|
-
},
|
|
397
|
-
};
|
|
398
|
-
|
|
399
|
-
const { container } = render(
|
|
400
|
-
<TestWrapper>
|
|
401
|
-
<ComponentToRender {...props} />
|
|
402
|
-
</TestWrapper>
|
|
403
|
-
);
|
|
404
|
-
|
|
405
|
-
expect(container.querySelector('.viber-account-icon')).toBeNull();
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
it('should use image placeholder when carousel card mediaUrl is whitespace only', () => {
|
|
409
|
-
const props = {
|
|
410
|
-
...defaultProps,
|
|
411
|
-
content: {
|
|
412
|
-
viberPreviewContent: {
|
|
413
|
-
type: 'CAROUSEL',
|
|
414
|
-
cards: [
|
|
415
|
-
{
|
|
416
|
-
text: 'Only text',
|
|
417
|
-
mediaUrl: ' ',
|
|
418
|
-
buttons: [{ title: 'Btn', action: 'https://example.com' }],
|
|
419
|
-
},
|
|
420
|
-
],
|
|
421
|
-
},
|
|
422
|
-
},
|
|
423
|
-
};
|
|
424
|
-
|
|
425
|
-
const { container } = render(
|
|
426
|
-
<TestWrapper>
|
|
427
|
-
<ComponentToRender {...props} />
|
|
428
|
-
</TestWrapper>
|
|
429
|
-
);
|
|
430
|
-
|
|
431
|
-
expect(container.querySelector('.viber-carousel-preview-image-placeholder')).toBeTruthy();
|
|
432
|
-
expect(container.querySelector('.viber-carousel-preview-image')).toBeNull();
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
it('should render at most two carousel buttons per card', () => {
|
|
436
|
-
const props = {
|
|
437
|
-
...defaultProps,
|
|
438
|
-
content: {
|
|
439
|
-
viberPreviewContent: {
|
|
440
|
-
type: 'CAROUSEL',
|
|
441
|
-
cards: [
|
|
442
|
-
{
|
|
443
|
-
text: 'Card',
|
|
444
|
-
mediaUrl: 'https://image.url/c.jpg',
|
|
445
|
-
buttons: [
|
|
446
|
-
{ title: 'One', action: 'https://a.com' },
|
|
447
|
-
{ title: 'Two', action: 'https://b.com' },
|
|
448
|
-
{ title: 'Three', action: 'https://c.com' },
|
|
449
|
-
],
|
|
450
|
-
},
|
|
451
|
-
],
|
|
452
|
-
},
|
|
453
|
-
},
|
|
454
|
-
};
|
|
455
|
-
|
|
456
|
-
const { container } = render(
|
|
457
|
-
<TestWrapper>
|
|
458
|
-
<ComponentToRender {...props} />
|
|
459
|
-
</TestWrapper>
|
|
460
|
-
);
|
|
461
|
-
|
|
462
|
-
expect(container.querySelectorAll('.viber-carousel-preview-button')).toHaveLength(2);
|
|
463
|
-
expect(screen.getByText('One')).toBeTruthy();
|
|
464
|
-
expect(screen.getByText('Two')).toBeTruthy();
|
|
465
|
-
expect(screen.queryByText('Three')).toBeNull();
|
|
466
|
-
});
|
|
467
|
-
|
|
468
|
-
it('should apply secondary class to second carousel button', () => {
|
|
469
|
-
const props = {
|
|
470
|
-
...defaultProps,
|
|
471
|
-
content: {
|
|
472
|
-
viberPreviewContent: {
|
|
473
|
-
type: 'CAROUSEL',
|
|
474
|
-
cards: [
|
|
475
|
-
{
|
|
476
|
-
text: 'Card',
|
|
477
|
-
mediaUrl: 'https://image.url/c.jpg',
|
|
478
|
-
buttons: [
|
|
479
|
-
{ title: 'Primary', action: 'https://a.com' },
|
|
480
|
-
{ title: 'Secondary', action: 'https://b.com' },
|
|
481
|
-
],
|
|
482
|
-
},
|
|
483
|
-
],
|
|
484
|
-
},
|
|
485
|
-
},
|
|
486
|
-
};
|
|
487
|
-
|
|
488
|
-
const { container } = render(
|
|
489
|
-
<TestWrapper>
|
|
490
|
-
<ComponentToRender {...props} />
|
|
491
|
-
</TestWrapper>
|
|
492
|
-
);
|
|
493
|
-
|
|
494
|
-
const buttons = container.querySelectorAll('.viber-carousel-preview-button');
|
|
495
|
-
expect(buttons[0].className).toContain('viber-carousel-preview-button');
|
|
496
|
-
expect(buttons[0].className).not.toContain('viber-carousel-preview-button-secondary');
|
|
497
|
-
expect(buttons[1].className).toContain('viber-carousel-preview-button-secondary');
|
|
498
|
-
});
|
|
499
|
-
|
|
500
|
-
it('should show carousel when only a button title is present on a card', () => {
|
|
501
|
-
const props = {
|
|
502
|
-
...defaultProps,
|
|
503
|
-
content: {
|
|
504
|
-
viberPreviewContent: {
|
|
505
|
-
type: 'CAROUSEL',
|
|
506
|
-
cards: [
|
|
507
|
-
{
|
|
508
|
-
text: '',
|
|
509
|
-
mediaUrl: '',
|
|
510
|
-
buttons: [{ title: 'Tap me', action: 'https://example.com' }],
|
|
511
|
-
},
|
|
512
|
-
],
|
|
513
|
-
},
|
|
514
|
-
},
|
|
515
|
-
};
|
|
516
|
-
|
|
517
|
-
render(
|
|
518
|
-
<TestWrapper>
|
|
519
|
-
<ComponentToRender {...props} />
|
|
520
|
-
</TestWrapper>
|
|
521
|
-
);
|
|
522
|
-
|
|
523
|
-
expect(screen.getByText('Tap me')).toBeTruthy();
|
|
524
|
-
expect(screen.queryByText('No content available')).toBeNull();
|
|
525
|
-
});
|
|
526
|
-
|
|
527
|
-
it('should show one placeholder card when editor preview and cards array is empty', () => {
|
|
528
|
-
const props = {
|
|
529
|
-
...defaultProps,
|
|
530
|
-
content: {
|
|
531
|
-
viberPreviewContent: {
|
|
532
|
-
type: 'CAROUSEL',
|
|
533
|
-
showCarouselEditorPreview: true,
|
|
534
|
-
cards: [],
|
|
535
|
-
},
|
|
536
|
-
},
|
|
537
|
-
};
|
|
538
|
-
|
|
539
|
-
const { container } = render(
|
|
540
|
-
<TestWrapper>
|
|
541
|
-
<ComponentToRender {...props} />
|
|
542
|
-
</TestWrapper>
|
|
543
|
-
);
|
|
544
|
-
|
|
545
|
-
expect(container.querySelectorAll('.viber-carousel-preview-card')).toHaveLength(1);
|
|
546
|
-
});
|
|
547
|
-
|
|
548
|
-
it('should show no content when CAROUSEL has empty cards and no editor preview flag', () => {
|
|
549
|
-
const props = {
|
|
550
|
-
...defaultProps,
|
|
551
|
-
content: {
|
|
552
|
-
viberPreviewContent: {
|
|
553
|
-
type: 'CAROUSEL',
|
|
554
|
-
cards: [],
|
|
555
|
-
},
|
|
556
|
-
},
|
|
557
|
-
};
|
|
558
|
-
|
|
559
|
-
render(
|
|
560
|
-
<TestWrapper>
|
|
561
|
-
<ComponentToRender {...props} />
|
|
562
|
-
</TestWrapper>
|
|
563
|
-
);
|
|
564
|
-
|
|
565
|
-
expect(screen.getByText('No content available')).toBeTruthy();
|
|
566
|
-
});
|
|
567
203
|
});
|
|
568
204
|
|
|
569
205
|
describe('Account and Brand Name', () => {
|
|
@@ -3561,84 +3561,6 @@ describe('CommonTestAndPreview', () => {
|
|
|
3561
3561
|
});
|
|
3562
3562
|
});
|
|
3563
3563
|
|
|
3564
|
-
describe('RCS primary card content synthetic tag fallback', () => {
|
|
3565
|
-
const rcsCardFormData = (description) => ({
|
|
3566
|
-
rcsTitle: '',
|
|
3567
|
-
rcsDesc: description,
|
|
3568
|
-
versions: {
|
|
3569
|
-
base: {
|
|
3570
|
-
content: {
|
|
3571
|
-
RCS: {
|
|
3572
|
-
rcsContent: {
|
|
3573
|
-
cardContent: [{ title: '', description }],
|
|
3574
|
-
},
|
|
3575
|
-
},
|
|
3576
|
-
},
|
|
3577
|
-
},
|
|
3578
|
-
},
|
|
3579
|
-
});
|
|
3580
|
-
|
|
3581
|
-
it('should surface a {{tag}} from RCS card description as a fillable field when the extract-tags API returns nothing (no SMS fallback)', async () => {
|
|
3582
|
-
render(
|
|
3583
|
-
<TestWrapper>
|
|
3584
|
-
<CommonTestAndPreview
|
|
3585
|
-
{...defaultProps}
|
|
3586
|
-
channel={CHANNELS.RCS}
|
|
3587
|
-
formData={rcsCardFormData('Visit store for offer {{user_id_b64}}')}
|
|
3588
|
-
extractedTags={[]}
|
|
3589
|
-
/>
|
|
3590
|
-
</TestWrapper>
|
|
3591
|
-
);
|
|
3592
|
-
|
|
3593
|
-
await waitFor(() => expect(lastLeftPanelContentProps).not.toBeNull());
|
|
3594
|
-
|
|
3595
|
-
const tags = lastLeftPanelContentProps.extractedTags;
|
|
3596
|
-
expect(tags.some((tag) => tag.name === 'user_id_b64')).toBe(true);
|
|
3597
|
-
});
|
|
3598
|
-
|
|
3599
|
-
it('should surface an RCS card tag alongside a merged fallback SMS tag when both are present', async () => {
|
|
3600
|
-
render(
|
|
3601
|
-
<TestWrapper>
|
|
3602
|
-
<CommonTestAndPreview
|
|
3603
|
-
{...defaultProps}
|
|
3604
|
-
channel={CHANNELS.RCS}
|
|
3605
|
-
formData={rcsCardFormData('Visit store for offer {{user_id_b64}}')}
|
|
3606
|
-
extractedTags={[]}
|
|
3607
|
-
smsFallbackContent={{
|
|
3608
|
-
templateContent: 'Fallback {{name}}',
|
|
3609
|
-
content: 'Fallback {{name}}',
|
|
3610
|
-
}}
|
|
3611
|
-
/>
|
|
3612
|
-
</TestWrapper>
|
|
3613
|
-
);
|
|
3614
|
-
|
|
3615
|
-
await waitFor(() => expect(lastLeftPanelContentProps).not.toBeNull());
|
|
3616
|
-
|
|
3617
|
-
const tags = lastLeftPanelContentProps.extractedTags;
|
|
3618
|
-
expect(tags.some((tag) => tag.name === 'user_id_b64')).toBe(true);
|
|
3619
|
-
expect(tags.some((tag) => tag.name === 'name')).toBe(true);
|
|
3620
|
-
});
|
|
3621
|
-
|
|
3622
|
-
it('should not duplicate a tag the extract-tags API already returned for RCS card content', async () => {
|
|
3623
|
-
const apiTags = [{ name: 'user_id_b64', metaData: { userDriven: false }, children: [] }];
|
|
3624
|
-
render(
|
|
3625
|
-
<TestWrapper>
|
|
3626
|
-
<CommonTestAndPreview
|
|
3627
|
-
{...defaultProps}
|
|
3628
|
-
channel={CHANNELS.RCS}
|
|
3629
|
-
formData={rcsCardFormData('Visit store for offer {{user_id_b64}}')}
|
|
3630
|
-
extractedTags={apiTags}
|
|
3631
|
-
/>
|
|
3632
|
-
</TestWrapper>
|
|
3633
|
-
);
|
|
3634
|
-
|
|
3635
|
-
await waitFor(() => expect(lastLeftPanelContentProps).not.toBeNull());
|
|
3636
|
-
|
|
3637
|
-
const tags = lastLeftPanelContentProps.extractedTags;
|
|
3638
|
-
expect(tags.filter((tag) => tag.name === 'user_id_b64')).toHaveLength(1);
|
|
3639
|
-
});
|
|
3640
|
-
});
|
|
3641
|
-
|
|
3642
3564
|
describe('handleDiscardCustomValues — preview reset', () => {
|
|
3643
3565
|
it('should call updatePreviewRequested when handleDiscardCustomValues is invoked', async () => {
|
|
3644
3566
|
render(
|
|
@@ -27,40 +27,6 @@ export const buildSyntheticSmsMustacheTags = (body = '') => {
|
|
|
27
27
|
}));
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
/**
|
|
31
|
-
* Raw RCS primary-card text (title + description across all cards) to scan for `{{…}}` tags.
|
|
32
|
-
* Mirrors the carousel/standalone branching in prepareTagExtractionPayload's RCS case so both
|
|
33
|
-
* the extract-tags API payload and the client-side synthetic tag fallback agree on card text.
|
|
34
|
-
*/
|
|
35
|
-
export const getRcsPrimaryTagExtractionText = (formDataObj) => {
|
|
36
|
-
const rcsCardContentArr =
|
|
37
|
-
formDataObj?.versions?.base?.content?.RCS?.rcsContent?.cardContent
|
|
38
|
-
?? formDataObj?.content?.RCS?.rcsContent?.cardContent;
|
|
39
|
-
if (Array.isArray(rcsCardContentArr) && rcsCardContentArr.length > 0) {
|
|
40
|
-
const carouselTagText = rcsCardContentArr
|
|
41
|
-
.map((card) => `${card.title || ''} ${card.description || ''}`)
|
|
42
|
-
.join(' ')
|
|
43
|
-
.trim();
|
|
44
|
-
if (carouselTagText) return carouselTagText;
|
|
45
|
-
}
|
|
46
|
-
return `${formDataObj?.rcsTitle || ''} ${formDataObj?.rcsDesc || ''}`.trim();
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Combine tags the extract-tags API returned with tags synthesized client-side from a raw
|
|
51
|
-
* `{{…}}` scan of `rawText`, so a tag the backend's catalog doesn't recognize (e.g. a reserved
|
|
52
|
-
* token like `user_id_b64`) still surfaces as a fillable field instead of silently disappearing.
|
|
53
|
-
* Dedupes by name so API-recognized tags (which carry richer metaData) are never overridden.
|
|
54
|
-
*/
|
|
55
|
-
export const mergeSyntheticMustacheTags = (apiTags = [], rawText = '') => {
|
|
56
|
-
if (!smsTemplateHasMustacheTags(rawText)) return apiTags ?? [];
|
|
57
|
-
const existingNames = new Set((apiTags ?? []).map((tag) => tag?.name));
|
|
58
|
-
const synthetic = buildSyntheticSmsMustacheTags(rawText).filter(
|
|
59
|
-
(tag) => !existingNames.has(tag.name),
|
|
60
|
-
);
|
|
61
|
-
return [...(apiTags ?? []), ...synthetic];
|
|
62
|
-
};
|
|
63
|
-
|
|
64
30
|
/** RCS createMessageMeta: normalize media shape (mediaUrl, thumbnailUrl, height string). */
|
|
65
31
|
export const normalizeRcsTestCardMedia = (media) => {
|
|
66
32
|
if (!media || typeof media !== 'object') return undefined;
|
|
@@ -12,10 +12,8 @@ import { loadItem } from 'services/localStorageApi';
|
|
|
12
12
|
import { intlShape, injectIntl } from 'react-intl';
|
|
13
13
|
import { withRouter } from 'react-router-dom';
|
|
14
14
|
import { get } from 'lodash';
|
|
15
|
-
import CapNavigation from '@capillarytech/cap-ui-library/
|
|
15
|
+
import CapNavigation from '@capillarytech/cap-ui-library/CapNavigation';
|
|
16
16
|
import { CAP_WHITE } from '@capillarytech/cap-ui-library/styled/variables';
|
|
17
|
-
import { MFEModuleHeader } from '@capillarytech/cap-ui-utils';
|
|
18
|
-
import { MFE_MODULE_HEADER } from './mfeModuleHeader.config';
|
|
19
17
|
import injectSaga from '../../utils/injectSaga';
|
|
20
18
|
import sagas from './saga';
|
|
21
19
|
import messages from './messages';
|
|
@@ -32,11 +30,12 @@ import { CapLeftNavigatioOpenCss, CapLeftNavigationCss } from './style';
|
|
|
32
30
|
import { EMBEDDED } from './constants';
|
|
33
31
|
|
|
34
32
|
const CapWrapper = styled.div`
|
|
33
|
+
position: absolute;
|
|
35
34
|
padding: 0;
|
|
36
35
|
background-color: ${CAP_WHITE};
|
|
37
36
|
width: 100%;
|
|
38
37
|
display: flex;
|
|
39
|
-
|
|
38
|
+
margin-top: ${(props) => props.isEmbedded ? '0px' : '64px'};
|
|
40
39
|
|
|
41
40
|
.sidebar-container {
|
|
42
41
|
margin-right: 10px;
|
|
@@ -47,8 +46,10 @@ const CapWrapper = styled.div`
|
|
|
47
46
|
`;
|
|
48
47
|
|
|
49
48
|
const ComponentWrapper = styled.div`
|
|
49
|
+
max-width: 1140px;
|
|
50
|
+
margin: 0 auto;
|
|
50
51
|
width: 100%;
|
|
51
|
-
padding: 0;
|
|
52
|
+
padding: 24px 0;
|
|
52
53
|
`;
|
|
53
54
|
|
|
54
55
|
export class NavigationBar extends React.Component {
|
|
@@ -57,7 +58,6 @@ export class NavigationBar extends React.Component {
|
|
|
57
58
|
this.state = this.initializeSelectedProduct();
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
|
|
61
61
|
initializeSelectedProduct = () => {
|
|
62
62
|
const { location, intl: { formatMessage } } = this.props;
|
|
63
63
|
const { pathname } = location;
|
|
@@ -179,7 +179,6 @@ export class NavigationBar extends React.Component {
|
|
|
179
179
|
const topbarIcons = this.getTopbarIcons(showDocumentationBot);
|
|
180
180
|
const headerOverideCss = leftNavbarExpandedProp ? CapLeftNavigatioOpenCss : CapLeftNavigationCss;
|
|
181
181
|
return (
|
|
182
|
-
<>
|
|
183
182
|
<CapNavigation
|
|
184
183
|
className="creatives-main-container"
|
|
185
184
|
showContent
|
|
@@ -213,8 +212,7 @@ export class NavigationBar extends React.Component {
|
|
|
213
212
|
</CapWrapper>
|
|
214
213
|
</div>
|
|
215
214
|
</CapNavigation>
|
|
216
|
-
|
|
217
|
-
</>
|
|
215
|
+
|
|
218
216
|
);
|
|
219
217
|
}
|
|
220
218
|
}
|
|
@@ -3,7 +3,7 @@ import { injectIntl } from 'react-intl';
|
|
|
3
3
|
import '@testing-library/jest-dom';
|
|
4
4
|
import cloneDeep from 'lodash/cloneDeep';
|
|
5
5
|
import { BrowserRouter as Router } from 'react-router-dom';
|
|
6
|
-
import { render, screen
|
|
6
|
+
import { render, screen } from '../../../utils/test-utils';
|
|
7
7
|
|
|
8
8
|
import { NavigationBar } from '../index';
|
|
9
9
|
import * as mockdata from './mockData';
|
|
@@ -30,7 +30,7 @@ const renderComponent = (props) => {
|
|
|
30
30
|
describe('NavigationBar', () => {
|
|
31
31
|
const props = {
|
|
32
32
|
topbarMenuData: [{}],
|
|
33
|
-
history,
|
|
33
|
+
history: [{}],
|
|
34
34
|
userData,
|
|
35
35
|
loggedIn: true,
|
|
36
36
|
isCreativesAccessible: true,
|
|
@@ -42,72 +42,52 @@ describe('NavigationBar', () => {
|
|
|
42
42
|
},
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
// getNavigationConfigApi call settles, so nav content (icons, dividers,
|
|
47
|
-
// product labels) only mounts after that resolves — queries must wait for it.
|
|
48
|
-
|
|
49
|
-
// cap-ui-library's CapNavigationSPA bump changed how `topbarIcons` is
|
|
50
|
-
// consumed: it's now only read to find a `question-circle` icon's click
|
|
51
|
-
// handler for the built-in Help button. Custom icon entries (the "aira"
|
|
52
|
-
// doc-bot icon NavigationBar pushes via getTopbarIcons) are no longer
|
|
53
|
-
// rendered at all, so this feature no longer has any DOM to assert on.
|
|
54
|
-
it.skip('Show aria documentation bot icon if showDocumentationBot is true', async () => {
|
|
45
|
+
it('Show aria documentation bot icon if showDocumentationBot is true', () => {
|
|
55
46
|
renderComponent(props);
|
|
56
|
-
const ariaBotIcon =
|
|
47
|
+
const ariaBotIcon = screen.getByLabelText('open-aira');
|
|
57
48
|
expect(ariaBotIcon).toBeInTheDocument();
|
|
58
49
|
});
|
|
59
50
|
|
|
60
|
-
it('Should not show aria documentation bot icon if showDocumentationBot is false',
|
|
51
|
+
it('Should not show aria documentation bot icon if showDocumentationBot is false', () => {
|
|
61
52
|
const updatedProps = cloneDeep(props);
|
|
62
53
|
delete updatedProps.userData.currentOrgDetails.accessibleFeatures;
|
|
63
54
|
renderComponent(updatedProps);
|
|
64
|
-
await screen.findByLabelText('Help');
|
|
65
55
|
const ariaBotIcon = screen.queryByLabelText('open-aira');
|
|
66
|
-
expect(ariaBotIcon).
|
|
56
|
+
expect(ariaBotIcon).toBeInTheDocument();
|
|
67
57
|
});
|
|
68
|
-
|
|
69
|
-
it('Should contains top vertical',
|
|
58
|
+
|
|
59
|
+
it('Should contains top vertical', () => {
|
|
70
60
|
const updatedProps = {...props} ;
|
|
71
61
|
delete updatedProps.userData.currentOrgDetails.accessibleFeatures;
|
|
72
62
|
renderComponent(updatedProps);
|
|
73
|
-
// cap-ui-library v6 renders the vertical divider with `.cap-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
});
|
|
63
|
+
// cap-ui-library v6 renders the vertical divider with `.cap-navbar-vertical`
|
|
64
|
+
const topVaerticalBar = document.querySelector('.cap-navbar-vertical');
|
|
65
|
+
expect(topVaerticalBar).toBeInTheDocument();
|
|
77
66
|
});
|
|
78
|
-
|
|
79
|
-
// `selectedProduct` only renders (via CapSecondaryTopBar) when
|
|
80
|
-
// `showSecondaryTopBar` is passed — NavigationBar never passes it, so the
|
|
81
|
-
// "Loyalty+" label has no DOM to assert on under current props.
|
|
82
|
-
it.skip('Should have loyalty product selected', async () => {
|
|
67
|
+
it('Should have loyalty product selected', () => {
|
|
83
68
|
const updatedProps = {...props};
|
|
84
69
|
updatedProps.location.pathname = '/creatives/ui/v2/loyalty';
|
|
85
70
|
renderComponent(updatedProps);
|
|
86
|
-
const loyaltyProduct =
|
|
71
|
+
const loyaltyProduct = screen.getByText('Loyalty+');
|
|
87
72
|
expect(loyaltyProduct).toBeInTheDocument();
|
|
88
73
|
});
|
|
89
74
|
|
|
90
75
|
// Regression: AntD v3 -> v6 migration (CAP-183930) dropped the settings (gear)
|
|
91
76
|
// icon from the top nav. These tests ensure the gear keeps rendering.
|
|
92
|
-
it('Should render the settings (gear) icon in the top nav bar',
|
|
77
|
+
it('Should render the settings (gear) icon in the top nav bar', () => {
|
|
93
78
|
const updatedProps = cloneDeep(props);
|
|
94
79
|
updatedProps.location.pathname = '/creatives/ui/v2';
|
|
95
80
|
updatedProps.settingsUrl = '/campaigns/ui/creatives/settings/message';
|
|
96
81
|
renderComponent(updatedProps);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
});
|
|
82
|
+
const settingsIcon = document.querySelector('.cap-icon-v2-settings');
|
|
83
|
+
expect(settingsIcon).toBeInTheDocument();
|
|
100
84
|
});
|
|
101
85
|
|
|
102
|
-
|
|
103
|
-
// icon config (with className `navigation-setting-icon`) NavigationBar
|
|
104
|
-
// builds for the loyalty route is never rendered by the current library.
|
|
105
|
-
it.skip('Should render the settings (gear) icon for the loyalty product', async () => {
|
|
86
|
+
it('Should render the settings (gear) icon for the loyalty product', () => {
|
|
106
87
|
const updatedProps = cloneDeep(props);
|
|
107
88
|
updatedProps.location.pathname = '/creatives/ui/v2/loyalty';
|
|
108
89
|
renderComponent(updatedProps);
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
});
|
|
90
|
+
const settingsIcon = document.querySelector('.cap-icon-v2-settings.navigation-setting-icon');
|
|
91
|
+
expect(settingsIcon).toBeInTheDocument();
|
|
112
92
|
});
|
|
113
93
|
});
|
|
@@ -747,17 +747,11 @@ export function SmsFallback({
|
|
|
747
747
|
const base = uploadedTemplate.versions?.base || {};
|
|
748
748
|
const content = base.template_message || base['sms-editor'] || '';
|
|
749
749
|
const templateName = uploadedTemplate.name || base.template_name || '';
|
|
750
|
-
// DLT-registered sender IDs for this newly-created template — same field
|
|
751
|
-
// buildFallbackDataFromTemplate reads. Without it, Test & Preview's delivery-settings
|
|
752
|
-
// filter sees an empty registeredSenderIds and falls back to showing every sender.
|
|
753
|
-
const registeredSenderIds = Array.isArray(base.header) ? base.header : [];
|
|
754
750
|
if (content || templateName) {
|
|
755
751
|
onChange({
|
|
756
|
-
smsTemplateId: base.template_id || uploadedTemplate._id || '',
|
|
757
752
|
templateName,
|
|
758
753
|
content,
|
|
759
754
|
templateContent: content,
|
|
760
|
-
registeredSenderIds,
|
|
761
755
|
unicodeValidity: typeof base['unicode-validity'] === JS_TYPE_BOOLEAN
|
|
762
756
|
? base['unicode-validity']
|
|
763
757
|
: true,
|