@capillarytech/creatives-library 8.0.340-beta.0.5 → 8.0.340-beta.0.8
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/constants/unified.js +1 -0
- package/package.json +1 -1
- package/services/api.js +20 -0
- package/services/tests/api.test.js +59 -0
- package/utils/common.js +6 -0
- package/utils/test-utils.js +2 -2
- package/utils/tests/v2Common.test.js +46 -1
- package/utils/v2common.js +18 -0
- package/v2Components/CapTagList/index.js +5 -6
- package/v2Components/CommonTestAndPreview/UnifiedPreview/WhatsAppPreviewContent.js +18 -6
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +27 -0
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/WhatsAppPreviewContent.test.js +48 -0
- package/v2Components/TemplatePreview/_templatePreview.scss +21 -0
- package/v2Components/TemplatePreview/index.js +18 -6
- package/v2Components/TemplatePreview/tests/__snapshots__/index.test.js.snap +1 -0
- package/v2Containers/Assets/images/archive_Empty_Illustration.svg +9 -0
- package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/Tests/ChannelSelectionStep.test.js +28 -20
- package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +24 -16
- package/v2Containers/CreativesContainer/SlideBoxContent.js +16 -5
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +3 -1
- package/v2Containers/CreativesContainer/index.js +14 -1
- package/v2Containers/CreativesContainer/messages.js +4 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +2 -4
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +3 -0
- package/v2Containers/Email/reducer.js +12 -3
- package/v2Containers/Email/sagas.js +9 -4
- package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +4 -0
- package/v2Containers/Email/tests/reducer.test.js +47 -0
- package/v2Containers/Email/tests/sagas.test.js +146 -6
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +8 -1
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +1 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +7 -0
- package/v2Containers/Sms/Create/index.js +3 -0
- package/v2Containers/Templates/ChannelTypeIllustration.js +23 -6
- package/v2Containers/Templates/_templates.scss +155 -24
- package/v2Containers/Templates/actions.js +44 -0
- package/v2Containers/Templates/constants.js +31 -0
- package/v2Containers/Templates/index.js +400 -59
- package/v2Containers/Templates/messages.js +96 -0
- package/v2Containers/Templates/reducer.js +84 -1
- package/v2Containers/Templates/sagas.js +64 -0
- package/v2Containers/Templates/selectors.js +12 -0
- package/v2Containers/Templates/tests/ChannelTypeIllustration.test.js +12 -0
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1166 -1112
- package/v2Containers/Templates/tests/index.test.js +6 -0
- package/v2Containers/Templates/tests/reducer.test.js +178 -0
- package/v2Containers/Templates/tests/sagas.test.js +390 -8
- package/v2Containers/Templates/tests/selector.test.js +32 -0
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +1 -1
- package/v2Containers/Viber/constants.js +8 -0
- package/v2Containers/Viber/index.js +5 -0
- package/v2Containers/Viber/messages.js +4 -0
- package/v2Containers/Viber/reducer.js +26 -3
- package/v2Containers/Viber/sagas.js +50 -8
- package/v2Containers/Viber/tests/index.test.js +80 -0
- package/v2Containers/Viber/tests/reducer.test.js +297 -0
- package/v2Containers/Viber/tests/saga.test.js +412 -40
- package/v2Containers/WeChat/Wrapper/index.js +0 -1
- package/v2Containers/Whatsapp/constants.js +8 -0
- package/v2Containers/Whatsapp/index.js +145 -5
- package/v2Containers/Whatsapp/index.scss +12 -0
- package/v2Containers/Whatsapp/messages.js +16 -0
package/v2Containers/CommunicationFlow/steps/ChannelSelectionStep/Tests/ChannelSelectionStep.test.js
CHANGED
|
@@ -9,6 +9,14 @@ import { IntlProvider } from 'react-intl';
|
|
|
9
9
|
import ChannelSelectionStep from '../ChannelSelectionStep';
|
|
10
10
|
import { CHANNELS } from '../../../constants';
|
|
11
11
|
|
|
12
|
+
// CapDropdown opens via @rc-component portal animations that need real time;
|
|
13
|
+
// under jest -w 90% parallel load the default 5s budget is too tight for
|
|
14
|
+
// click → menu-paint → menu-item-click chains. Bump per-test timeout.
|
|
15
|
+
jest.setTimeout(30000);
|
|
16
|
+
|
|
17
|
+
// Larger wait budget for individual menu/portal transitions under parallel load.
|
|
18
|
+
const WAIT_OPTIONS = { timeout: 10000 };
|
|
19
|
+
|
|
12
20
|
jest.mock('../../../../CreativesContainer', () => function MockCreativesContainer({
|
|
13
21
|
getCreativesData,
|
|
14
22
|
handleCloseCreatives,
|
|
@@ -126,7 +134,7 @@ describe('ChannelSelectionStep', () => {
|
|
|
126
134
|
await userEvent.click(screen.getByLabelText('Show more content options icon'));
|
|
127
135
|
await waitFor(() => {
|
|
128
136
|
expect(screen.getByRole('menu')).toBeInTheDocument();
|
|
129
|
-
});
|
|
137
|
+
}, WAIT_OPTIONS);
|
|
130
138
|
await userEvent.click(within(screen.getByRole('menu')).getByText('Remove'));
|
|
131
139
|
|
|
132
140
|
expect(onChange).toHaveBeenCalledWith({ contentItems: [] });
|
|
@@ -145,12 +153,12 @@ describe('ChannelSelectionStep', () => {
|
|
|
145
153
|
await userEvent.click(screen.getByRole('button', { name: /content template/i }));
|
|
146
154
|
await waitFor(() => {
|
|
147
155
|
expect(screen.getByRole('menu')).toBeInTheDocument();
|
|
148
|
-
});
|
|
156
|
+
}, WAIT_OPTIONS);
|
|
149
157
|
await userEvent.click(within(screen.getByRole('menu')).getByText('SMS'));
|
|
150
158
|
|
|
151
159
|
await waitFor(() => {
|
|
152
160
|
expect(screen.getByTestId('creatives-mock')).toBeInTheDocument();
|
|
153
|
-
});
|
|
161
|
+
}, WAIT_OPTIONS);
|
|
154
162
|
|
|
155
163
|
expect(screen.getByTestId('creatives-mock')).toHaveAttribute('data-creatives-mode', 'create');
|
|
156
164
|
|
|
@@ -181,9 +189,9 @@ describe('ChannelSelectionStep', () => {
|
|
|
181
189
|
);
|
|
182
190
|
|
|
183
191
|
await userEvent.click(screen.getByRole('button', { name: /content template/i }));
|
|
184
|
-
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument());
|
|
192
|
+
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
185
193
|
await userEvent.click(within(screen.getByRole('menu')).getByText('SMS'));
|
|
186
|
-
await waitFor(() => expect(screen.getByTestId('creatives-mock')).toBeInTheDocument());
|
|
194
|
+
await waitFor(() => expect(screen.getByTestId('creatives-mock')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
187
195
|
|
|
188
196
|
await userEvent.click(screen.getByTestId('creatives-close'));
|
|
189
197
|
|
|
@@ -209,10 +217,10 @@ describe('ChannelSelectionStep', () => {
|
|
|
209
217
|
);
|
|
210
218
|
|
|
211
219
|
await userEvent.click(screen.getByLabelText('Show more content options icon'));
|
|
212
|
-
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument());
|
|
220
|
+
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
213
221
|
await userEvent.click(within(screen.getByRole('menu')).getByText('Edit'));
|
|
214
222
|
|
|
215
|
-
await waitFor(() => expect(screen.getByTestId('creatives-mock')).toBeInTheDocument());
|
|
223
|
+
await waitFor(() => expect(screen.getByTestId('creatives-mock')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
216
224
|
expect(screen.getByTestId('creatives-mock')).toHaveAttribute('data-creatives-mode', 'edit');
|
|
217
225
|
|
|
218
226
|
await userEvent.click(screen.getByTestId('creatives-save'));
|
|
@@ -242,7 +250,7 @@ describe('ChannelSelectionStep', () => {
|
|
|
242
250
|
);
|
|
243
251
|
|
|
244
252
|
await userEvent.click(screen.getByLabelText('Show more content options icon'));
|
|
245
|
-
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument());
|
|
253
|
+
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
246
254
|
await userEvent.click(within(screen.getByRole('menu')).getByText('Preview and Test'));
|
|
247
255
|
|
|
248
256
|
expect(console.log).toHaveBeenCalledWith('Preview content', 'p1');
|
|
@@ -288,7 +296,7 @@ describe('ChannelSelectionStep', () => {
|
|
|
288
296
|
await userEvent.click(screen.getByRole('button', { name: /^add incentive$/i }));
|
|
289
297
|
await waitFor(() => {
|
|
290
298
|
expect(screen.getByRole('menu')).toBeInTheDocument();
|
|
291
|
-
});
|
|
299
|
+
}, WAIT_OPTIONS);
|
|
292
300
|
await userEvent.click(within(screen.getByRole('menu')).getByText('Badges'));
|
|
293
301
|
|
|
294
302
|
expect(onChange).toHaveBeenCalledWith({
|
|
@@ -316,7 +324,7 @@ describe('ChannelSelectionStep', () => {
|
|
|
316
324
|
const addIncentiveLinks = screen.getAllByRole('button', { name: /add incentive/i });
|
|
317
325
|
expect(addIncentiveLinks.length).toBeGreaterThanOrEqual(1);
|
|
318
326
|
await userEvent.click(addIncentiveLinks[addIncentiveLinks.length - 1]);
|
|
319
|
-
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument());
|
|
327
|
+
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
320
328
|
await userEvent.click(within(screen.getByRole('menu')).getByText('Badges'));
|
|
321
329
|
|
|
322
330
|
expect(onChange).toHaveBeenCalledWith({
|
|
@@ -462,7 +470,7 @@ describe('ChannelSelectionStep', () => {
|
|
|
462
470
|
<ChannelSelectionStep value={{ contentItems: [] }} onChange={jest.fn()} channels={null} />,
|
|
463
471
|
);
|
|
464
472
|
await userEvent.click(screen.getByRole('button', { name: /content template/i }));
|
|
465
|
-
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument());
|
|
473
|
+
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
466
474
|
expect(within(screen.getByRole('menu')).getByText('SMS')).toBeInTheDocument();
|
|
467
475
|
});
|
|
468
476
|
|
|
@@ -485,7 +493,7 @@ describe('ChannelSelectionStep', () => {
|
|
|
485
493
|
/>,
|
|
486
494
|
);
|
|
487
495
|
await userEvent.click(screen.getByRole('button', { name: /content template/i }));
|
|
488
|
-
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument());
|
|
496
|
+
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
489
497
|
await userEvent.click(screen.getByText('Custom'));
|
|
490
498
|
expect(onChange).toHaveBeenCalledWith({ channel: 'CUSTOM', channels: [] });
|
|
491
499
|
expect(screen.queryByTestId('creatives-mock')).not.toBeInTheDocument();
|
|
@@ -497,9 +505,9 @@ describe('ChannelSelectionStep', () => {
|
|
|
497
505
|
<ChannelSelectionStep value={{ contentItems: [] }} onChange={onChange} channels={CHANNELS} />,
|
|
498
506
|
);
|
|
499
507
|
await userEvent.click(screen.getByRole('button', { name: /content template/i }));
|
|
500
|
-
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument());
|
|
508
|
+
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
501
509
|
await userEvent.click(within(screen.getByRole('menu')).getByText('SMS'));
|
|
502
|
-
await waitFor(() => expect(screen.getByTestId('creatives-mock')).toBeInTheDocument());
|
|
510
|
+
await waitFor(() => expect(screen.getByTestId('creatives-mock')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
503
511
|
|
|
504
512
|
await userEvent.click(screen.getByTestId('creatives-save-null'));
|
|
505
513
|
|
|
@@ -522,7 +530,7 @@ describe('ChannelSelectionStep', () => {
|
|
|
522
530
|
);
|
|
523
531
|
|
|
524
532
|
await userEvent.click(screen.getByLabelText('Show more content options icon'));
|
|
525
|
-
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument());
|
|
533
|
+
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
526
534
|
await userEvent.click(within(screen.getByRole('menu')).getByText('Edit'));
|
|
527
535
|
|
|
528
536
|
expect(screen.queryByTestId('creatives-mock')).not.toBeInTheDocument();
|
|
@@ -538,9 +546,9 @@ describe('ChannelSelectionStep', () => {
|
|
|
538
546
|
/>,
|
|
539
547
|
);
|
|
540
548
|
await userEvent.click(screen.getByRole('button', { name: /content template/i }));
|
|
541
|
-
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument());
|
|
549
|
+
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
542
550
|
await userEvent.click(within(screen.getByRole('menu')).getByText('SMS'));
|
|
543
|
-
await waitFor(() => expect(screen.getByTestId('creatives-mock')).toBeInTheDocument());
|
|
551
|
+
await waitFor(() => expect(screen.getByTestId('creatives-mock')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
544
552
|
expect(screen.getByTestId('creatives-mock')).toHaveAttribute('data-creatives-mode', 'preview');
|
|
545
553
|
});
|
|
546
554
|
|
|
@@ -558,7 +566,7 @@ describe('ChannelSelectionStep', () => {
|
|
|
558
566
|
/>,
|
|
559
567
|
);
|
|
560
568
|
await userEvent.click(screen.getByRole('button', { name: /^add incentive$/i }));
|
|
561
|
-
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument());
|
|
569
|
+
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
562
570
|
await userEvent.click(within(screen.getByRole('menu')).getByText('Badges'));
|
|
563
571
|
expect(onChange).toHaveBeenCalledWith({
|
|
564
572
|
selectedOfferDetails: [{ type: 'existing' }, { type: 'badges' }],
|
|
@@ -712,7 +720,7 @@ describe('ChannelSelectionStep', () => {
|
|
|
712
720
|
/>,
|
|
713
721
|
);
|
|
714
722
|
await userEvent.click(screen.getByRole('button', { name: /content template/i }));
|
|
715
|
-
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument());
|
|
723
|
+
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
716
724
|
// SMS is in channelsToDisable — clicking it should not call onChange or show creatives
|
|
717
725
|
await userEvent.click(within(screen.getByRole('menu')).getByText('SMS'));
|
|
718
726
|
expect(screen.queryByTestId('creatives-mock')).not.toBeInTheDocument();
|
|
@@ -767,7 +775,7 @@ describe('ChannelSelectionStep', () => {
|
|
|
767
775
|
/>,
|
|
768
776
|
);
|
|
769
777
|
await userEvent.click(screen.getByRole('button', { name: /content template/i }));
|
|
770
|
-
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument());
|
|
778
|
+
await waitFor(() => expect(screen.getByRole('menu')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
771
779
|
// Click the disabled EMAIL menu item — handleChannelSelect should return early
|
|
772
780
|
await userEvent.click(within(screen.getByRole('menu')).getByText('Email'));
|
|
773
781
|
expect(onChange).not.toHaveBeenCalled();
|
package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js
CHANGED
|
@@ -9,6 +9,11 @@ import SenderDetails, { parseSenderDetailsFromEntity } from '../SenderDetails';
|
|
|
9
9
|
import * as deliverySettingsConfig from '../deliverySettingsConfig';
|
|
10
10
|
import { findVisibleSelectOption } from '../../../../../utils/test-utils';
|
|
11
11
|
|
|
12
|
+
// antd v6 Selects rely on real-time animations + portal mounts; under the full
|
|
13
|
+
// parallel suite (jest -w 90%) the default 5s budget is too tight for
|
|
14
|
+
// click → listbox-paint → option-click chains. Bump per-test timeout.
|
|
15
|
+
jest.setTimeout(30000);
|
|
16
|
+
|
|
12
17
|
const { parseEntityForDisplay } = deliverySettingsConfig;
|
|
13
18
|
|
|
14
19
|
/** Shared domainProperties entity shapes (see deliverySettingsConfig). */
|
|
@@ -173,11 +178,14 @@ function renderSenderDetails(override = {}) {
|
|
|
173
178
|
return { ...view, onClose, onSave };
|
|
174
179
|
}
|
|
175
180
|
|
|
181
|
+
// Larger wait budget for individual portal/listbox transitions under parallel load.
|
|
182
|
+
const WAIT_OPTIONS = { timeout: 10000 };
|
|
183
|
+
|
|
176
184
|
async function openSelectAndChoose(root, comboIndex, optionText) {
|
|
177
185
|
const combos = within(root).getAllByRole('combobox');
|
|
178
186
|
await userEvent.click(combos[comboIndex]);
|
|
179
|
-
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument());
|
|
180
|
-
await userEvent.click(await findVisibleSelectOption(optionText));
|
|
187
|
+
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
188
|
+
await userEvent.click(await findVisibleSelectOption(optionText, WAIT_OPTIONS));
|
|
181
189
|
}
|
|
182
190
|
|
|
183
191
|
describe('SenderDetails', () => {
|
|
@@ -266,8 +274,8 @@ describe('SenderDetails', () => {
|
|
|
266
274
|
|
|
267
275
|
const combos = within(root).getAllByRole('combobox');
|
|
268
276
|
await userEvent.click(combos[1]);
|
|
269
|
-
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument());
|
|
270
|
-
await userEvent.click(await findVisibleSelectOption('+1002003002'));
|
|
277
|
+
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
278
|
+
await userEvent.click(await findVisibleSelectOption('+1002003002', WAIT_OPTIONS));
|
|
271
279
|
|
|
272
280
|
const saveBtn = within(root).getByRole('button', { name: /save changes/i });
|
|
273
281
|
await waitFor(() => expect(saveBtn).not.toBeDisabled());
|
|
@@ -342,8 +350,8 @@ describe('SenderDetails', () => {
|
|
|
342
350
|
|
|
343
351
|
const combos = within(root).getAllByRole('combobox');
|
|
344
352
|
await userEvent.click(combos[1]);
|
|
345
|
-
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument());
|
|
346
|
-
await userEvent.click(await findVisibleSelectOption('+1002003002'));
|
|
353
|
+
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
354
|
+
await userEvent.click(await findVisibleSelectOption('+1002003002', WAIT_OPTIONS));
|
|
347
355
|
|
|
348
356
|
const resetLinks = within(root).getAllByText('Reset');
|
|
349
357
|
await userEvent.click(resetLinks[1]);
|
|
@@ -363,8 +371,8 @@ describe('SenderDetails', () => {
|
|
|
363
371
|
|
|
364
372
|
const combos = within(root).getAllByRole('combobox');
|
|
365
373
|
await userEvent.click(combos[combos.length - 1]);
|
|
366
|
-
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument());
|
|
367
|
-
await userEvent.click(await findVisibleSelectOption('+91900111333'));
|
|
374
|
+
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
375
|
+
await userEvent.click(await findVisibleSelectOption('+91900111333', WAIT_OPTIONS));
|
|
368
376
|
|
|
369
377
|
const saveBtn = within(root).getByRole('button', { name: /save changes/i });
|
|
370
378
|
await waitFor(() => expect(saveBtn).not.toBeDisabled());
|
|
@@ -418,8 +426,8 @@ describe('SenderDetails', () => {
|
|
|
418
426
|
|
|
419
427
|
const combos = within(root).getAllByRole('combobox');
|
|
420
428
|
await userEvent.click(combos[0]);
|
|
421
|
-
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument());
|
|
422
|
-
await userEvent.click(await findVisibleSelectOption('Gateway B'));
|
|
429
|
+
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
430
|
+
await userEvent.click(await findVisibleSelectOption('Gateway B', WAIT_OPTIONS));
|
|
423
431
|
|
|
424
432
|
// The sender ID should now auto-update to Gateway B's sender
|
|
425
433
|
await waitFor(() => expect(within(root).getByText('+222')).toBeInTheDocument());
|
|
@@ -437,8 +445,8 @@ describe('SenderDetails', () => {
|
|
|
437
445
|
// Switch to Mail Beta domain
|
|
438
446
|
const combos = within(root).getAllByRole('combobox');
|
|
439
447
|
await userEvent.click(combos[0]);
|
|
440
|
-
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument());
|
|
441
|
-
await userEvent.click(await findVisibleSelectOption('Mail Beta'));
|
|
448
|
+
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
449
|
+
await userEvent.click(await findVisibleSelectOption('Mail Beta', WAIT_OPTIONS));
|
|
442
450
|
|
|
443
451
|
// Sender ID should auto-update to beta@other.com
|
|
444
452
|
await waitFor(() => expect(within(root).getByText('beta@other.com')).toBeInTheDocument());
|
|
@@ -461,8 +469,8 @@ describe('SenderDetails', () => {
|
|
|
461
469
|
const combos = within(root).getAllByRole('combobox');
|
|
462
470
|
const senderCombo = combos[combos.length - 1];
|
|
463
471
|
await userEvent.click(senderCombo);
|
|
464
|
-
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument());
|
|
465
|
-
await userEvent.click(await findVisibleSelectOption('+91900111333'));
|
|
472
|
+
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
473
|
+
await userEvent.click(await findVisibleSelectOption('+91900111333', WAIT_OPTIONS));
|
|
466
474
|
|
|
467
475
|
const saveBtn = within(root).getByRole('button', { name: /save changes/i });
|
|
468
476
|
await waitFor(() => expect(saveBtn).not.toBeDisabled());
|
|
@@ -500,8 +508,8 @@ describe('SenderDetails', () => {
|
|
|
500
508
|
const combos = within(root).getAllByRole('combobox');
|
|
501
509
|
const senderCombo = combos[combos.length - 1];
|
|
502
510
|
await userEvent.click(senderCombo);
|
|
503
|
-
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument());
|
|
504
|
-
await userEvent.click(await findVisibleSelectOption('+viber-alt'));
|
|
511
|
+
await waitFor(() => expect(screen.getByRole('listbox')).toBeInTheDocument(), WAIT_OPTIONS);
|
|
512
|
+
await userEvent.click(await findVisibleSelectOption('+viber-alt', WAIT_OPTIONS));
|
|
505
513
|
|
|
506
514
|
// antd v6 also renders selected option in an aria-live polite region for
|
|
507
515
|
// screen readers, so the text appears twice. Match only the visible select
|
|
@@ -698,9 +698,16 @@ export function SlideBoxContent(props) {
|
|
|
698
698
|
{(isEditEmailWithId || isEmailEditWithContent) && (
|
|
699
699
|
(() => {
|
|
700
700
|
const supportCKEditor = commonUtil.hasSupportCKEditor();
|
|
701
|
-
//
|
|
702
|
-
//
|
|
703
|
-
|
|
701
|
+
// BEE templates always use the <Email> component directly (the same
|
|
702
|
+
// path the SUPPORT_CK_EDITOR=true branch uses). EmailWrapper's
|
|
703
|
+
// useEmailWrapper strips templateData from props, so library-mode
|
|
704
|
+
// pencil-edit on a BEE template would never reach startTemplateCreation
|
|
705
|
+
// and getDetails?type=BEE_PLUGIN would never fire. Routing BEE
|
|
706
|
+
// templates through the direct <Email> path — which is already
|
|
707
|
+
// battle-tested for the CKEditor flow — sidesteps that entirely.
|
|
708
|
+
const isBEETemplate = templateData?.base?.is_drag_drop === true
|
|
709
|
+
|| templateData?.base?.is_drag_drop === 1;
|
|
710
|
+
if (supportCKEditor || isBEETemplate) {
|
|
704
711
|
return (
|
|
705
712
|
<Email
|
|
706
713
|
key="cretives-container-email-edit"
|
|
@@ -776,8 +783,12 @@ export function SlideBoxContent(props) {
|
|
|
776
783
|
isTestAndPreviewMode={isTestAndPreviewMode}
|
|
777
784
|
onHtmlEditorValidationStateChange={onHtmlEditorValidationStateChange}
|
|
778
785
|
location={{
|
|
779
|
-
pathname: `/email/edit/${templateData._id}`,
|
|
780
|
-
query: {
|
|
786
|
+
pathname: `/email/edit/${templateData._id || ''}`,
|
|
787
|
+
query: {
|
|
788
|
+
type: 'embedded',
|
|
789
|
+
module: 'library',
|
|
790
|
+
...(templateData._id ? { id: templateData._id } : {}),
|
|
791
|
+
},
|
|
781
792
|
}}
|
|
782
793
|
params={{ id: templateData._id }}
|
|
783
794
|
/>
|
|
@@ -24,6 +24,7 @@ function SlideBoxFooter(props) {
|
|
|
24
24
|
slidBoxContent,
|
|
25
25
|
onSave,
|
|
26
26
|
onEditTemplate,
|
|
27
|
+
isTemplateArchived,
|
|
27
28
|
onCreateNextStep,
|
|
28
29
|
isFullMode,
|
|
29
30
|
fetchingCmsData,
|
|
@@ -214,7 +215,7 @@ function SlideBoxFooter(props) {
|
|
|
214
215
|
<FormattedMessage {...(continueButtonLabel || messages.continue)} />
|
|
215
216
|
</CapButton>
|
|
216
217
|
)}
|
|
217
|
-
{slidBoxContent === PREVIEW && (
|
|
218
|
+
{slidBoxContent === PREVIEW && !isTemplateArchived && (
|
|
218
219
|
<CapButton onClick={onEditTemplate} type="secondary">
|
|
219
220
|
<FormattedMessage {...messages.creativesTemplatesEdit} />
|
|
220
221
|
</CapButton>
|
|
@@ -227,6 +228,7 @@ SlideBoxFooter.propTypes = {
|
|
|
227
228
|
slidBoxContent: PropTypes.node,
|
|
228
229
|
onSave: PropTypes.func,
|
|
229
230
|
onEditTemplate: PropTypes.func,
|
|
231
|
+
isTemplateArchived: PropTypes.bool,
|
|
230
232
|
onCreateNextStep: PropTypes.func,
|
|
231
233
|
shouldShowContinueFooter: PropTypes.func,
|
|
232
234
|
shouldShowDoneFooter: PropTypes.func,
|
|
@@ -50,7 +50,7 @@ import { RCS_STATUSES } from '../Rcs/constants';
|
|
|
50
50
|
import { CREATIVE } from '../Facebook/constants';
|
|
51
51
|
import { LOYALTY } from '../App/constants';
|
|
52
52
|
import {
|
|
53
|
-
WHATSAPP_STATUSES, WHATSAPP_MEDIA_TYPES, PHONE_NUMBER, URL,
|
|
53
|
+
WHATSAPP_STATUSES, WHATSAPP_MEDIA_TYPES, PHONE_NUMBER, URL, ADD_IMAGE_URL_PREVIEW_MARKER,
|
|
54
54
|
} from '../Whatsapp/constants';
|
|
55
55
|
import { updateImagesInHtml } from '../../utils/cdnTransformation';
|
|
56
56
|
|
|
@@ -260,6 +260,10 @@ export class Creatives extends React.Component {
|
|
|
260
260
|
};
|
|
261
261
|
|
|
262
262
|
onEditTemplate = () => {
|
|
263
|
+
if (commonUtil.hasCreativesArchivalEnabled() && this.props.templateData?.isArchived) {
|
|
264
|
+
CapNotification.error({ message: this.props.intl.formatMessage(messages.cannotEditArchivedTemplate) });
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
263
267
|
this.setState({ slidBoxContent: 'editTemplate', showSlideBox: true, templateNameExists: true });
|
|
264
268
|
};
|
|
265
269
|
|
|
@@ -684,6 +688,8 @@ export class Creatives extends React.Component {
|
|
|
684
688
|
switch (mediaType) {
|
|
685
689
|
case (WHATSAPP_MEDIA_TYPES.IMAGE):
|
|
686
690
|
mediaParams.imageUrl = url;
|
|
691
|
+
// Detect isAddImageUrl from previewUrl marker (previewUrl is unused for IMAGE type)
|
|
692
|
+
mediaParams.isAddImageUrl = previewUrl === ADD_IMAGE_URL_PREVIEW_MARKER;
|
|
687
693
|
break;
|
|
688
694
|
case (WHATSAPP_MEDIA_TYPES.VIDEO):
|
|
689
695
|
mediaParams.videoUrl = url;
|
|
@@ -1142,6 +1148,7 @@ export class Creatives extends React.Component {
|
|
|
1142
1148
|
headerTemplate = '',
|
|
1143
1149
|
} = {},
|
|
1144
1150
|
isPreviewUrl = false,
|
|
1151
|
+
isAddImageUrl = false,
|
|
1145
1152
|
carouselData = [],
|
|
1146
1153
|
} = cloneDeep(versions.base.content.whatsapp);
|
|
1147
1154
|
|
|
@@ -1178,6 +1185,11 @@ export class Creatives extends React.Component {
|
|
|
1178
1185
|
switch (mediaType) {
|
|
1179
1186
|
case (WHATSAPP_MEDIA_TYPES.IMAGE):
|
|
1180
1187
|
whatsappMedia.url = imageUrl;
|
|
1188
|
+
// previewUrl is unused for IMAGE type — reuse it to persist isAddImageUrl flag
|
|
1189
|
+
// without adding any new field that the backend would reject
|
|
1190
|
+
if (isAddImageUrl) {
|
|
1191
|
+
whatsappMedia.previewUrl = ADD_IMAGE_URL_PREVIEW_MARKER;
|
|
1192
|
+
}
|
|
1181
1193
|
break;
|
|
1182
1194
|
case (WHATSAPP_MEDIA_TYPES.VIDEO):
|
|
1183
1195
|
whatsappMedia.url = videoUrl;
|
|
@@ -2136,6 +2148,7 @@ export class Creatives extends React.Component {
|
|
|
2136
2148
|
onSave={this.saveMessage}
|
|
2137
2149
|
onDiscard={this.discardMessage}
|
|
2138
2150
|
onEditTemplate={this.onEditTemplate}
|
|
2151
|
+
isTemplateArchived={!!(commonUtil.hasCreativesArchivalEnabled() && this.props.templateData && this.props.templateData.isArchived)}
|
|
2139
2152
|
slidBoxContent={slidBoxContent}
|
|
2140
2153
|
onCreateNextStep={this.onCreateNextStep}
|
|
2141
2154
|
currentChannel={currentChannel.toUpperCase()}
|
|
@@ -390,4 +390,8 @@ export default defineMessages({
|
|
|
390
390
|
id: `${scope}.personalizationTokensErrorMessage`,
|
|
391
391
|
defaultMessage: `Personalization tags are not supported for anonymous customers, please remove the tags.`,
|
|
392
392
|
},
|
|
393
|
+
"cannotEditArchivedTemplate": {
|
|
394
|
+
id: `${scope}.cannotEditArchivedTemplate`,
|
|
395
|
+
defaultMessage: 'Cannot edit an archived template. Please unarchive it first.',
|
|
396
|
+
},
|
|
393
397
|
});
|
|
@@ -120,9 +120,8 @@ exports[`Test SlideBoxContent container Email component isTestAndPreviewMode IIF
|
|
|
120
120
|
key="cretives-container-email-edit-wrapper"
|
|
121
121
|
location={
|
|
122
122
|
Object {
|
|
123
|
-
"pathname": "/email/edit/
|
|
123
|
+
"pathname": "/email/edit/",
|
|
124
124
|
"query": Object {
|
|
125
|
-
"id": undefined,
|
|
126
125
|
"module": "library",
|
|
127
126
|
"type": "embedded",
|
|
128
127
|
},
|
|
@@ -171,9 +170,8 @@ exports[`Test SlideBoxContent container Email component isTestAndPreviewMode IIF
|
|
|
171
170
|
key="cretives-container-email-edit-wrapper"
|
|
172
171
|
location={
|
|
173
172
|
Object {
|
|
174
|
-
"pathname": "/email/edit/
|
|
173
|
+
"pathname": "/email/edit/",
|
|
175
174
|
"query": Object {
|
|
176
|
-
"id": undefined,
|
|
177
175
|
"module": "library",
|
|
178
176
|
"type": "embedded",
|
|
179
177
|
},
|
|
@@ -284,6 +284,7 @@ exports[`Test SlideBoxContent container campaign message, whatsapp edit all data
|
|
|
284
284
|
isEmptyContent={false}
|
|
285
285
|
isFullMode={false}
|
|
286
286
|
isLiquidValidationError={false}
|
|
287
|
+
isTemplateArchived={false}
|
|
287
288
|
isTemplateNameEmpty={false}
|
|
288
289
|
onCreateNextStep={[Function]}
|
|
289
290
|
onDiscard={[Function]}
|
|
@@ -419,6 +420,7 @@ exports[`Test SlideBoxContent container campaign message, whatsapp edit min data
|
|
|
419
420
|
isEmptyContent={false}
|
|
420
421
|
isFullMode={false}
|
|
421
422
|
isLiquidValidationError={false}
|
|
423
|
+
isTemplateArchived={false}
|
|
422
424
|
isTemplateNameEmpty={false}
|
|
423
425
|
onCreateNextStep={[Function]}
|
|
424
426
|
onDiscard={[Function]}
|
|
@@ -554,6 +556,7 @@ exports[`Test SlideBoxContent container it should clear the url, on channel chan
|
|
|
554
556
|
isEmptyContent={false}
|
|
555
557
|
isFullMode={false}
|
|
556
558
|
isLiquidValidationError={false}
|
|
559
|
+
isTemplateArchived={false}
|
|
557
560
|
isTemplateNameEmpty={false}
|
|
558
561
|
onCreateNextStep={[Function]}
|
|
559
562
|
onDiscard={[Function]}
|
|
@@ -12,6 +12,8 @@ const initialState = fromJS({
|
|
|
12
12
|
createTemplateInProgress: false,
|
|
13
13
|
createResponse: {},
|
|
14
14
|
isBeeEnabled: null,
|
|
15
|
+
fetchingCmsAccounts: false,
|
|
16
|
+
cmsAccountsLoaded: false,
|
|
15
17
|
});
|
|
16
18
|
|
|
17
19
|
function emailReducer(state = initialState, action) {
|
|
@@ -85,6 +87,7 @@ function emailReducer(state = initialState, action) {
|
|
|
85
87
|
case types.GET_CMS_EDITOR_DETAILS_SUCCESS:
|
|
86
88
|
return state
|
|
87
89
|
.set('fetchingCmsSettings', false)
|
|
90
|
+
.set('isBeeEnabled', action.isBeeEnabled)
|
|
88
91
|
.set('CmsSettings', fromJS(action.settings));
|
|
89
92
|
case types.GET_CMS_EDITOR_DETAILS_FAILURE:
|
|
90
93
|
return state
|
|
@@ -110,13 +113,19 @@ function emailReducer(state = initialState, action) {
|
|
|
110
113
|
.set('fetchingCmsDataFailed', true);
|
|
111
114
|
case types.GET_CMS_ACCOUNTS_REQUEST:
|
|
112
115
|
return state
|
|
113
|
-
.set('isBeeEnabled', false)
|
|
116
|
+
.set('isBeeEnabled', false)
|
|
117
|
+
.set('fetchingCmsAccounts', true)
|
|
118
|
+
.set('cmsAccountsLoaded', false);
|
|
114
119
|
case types.GET_CMS_ACCOUNTS_SUCCESS:
|
|
115
120
|
return state
|
|
116
|
-
.set('isBeeEnabled', action.isBeeEnabled)
|
|
121
|
+
.set('isBeeEnabled', action.isBeeEnabled)
|
|
122
|
+
.set('fetchingCmsAccounts', false)
|
|
123
|
+
.set('cmsAccountsLoaded', true);
|
|
117
124
|
case types.GET_CMS_ACCOUNTS_FAILURE:
|
|
118
125
|
return state
|
|
119
|
-
.set('isBeeEnabled', false)
|
|
126
|
+
.set('isBeeEnabled', false)
|
|
127
|
+
.set('fetchingCmsAccounts', false)
|
|
128
|
+
.set('cmsAccountsLoaded', true);
|
|
120
129
|
case types.CLEAR_EMAIL_CRUD_RESPONSE_REQUEST:
|
|
121
130
|
return state
|
|
122
131
|
.set('createResponse', fromJS({}));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
call, put, takeLatest, takeEvery, all,
|
|
2
|
+
call, put, takeLatest, takeEvery, all, select, take,
|
|
3
3
|
} from 'redux-saga/effects';
|
|
4
4
|
import CapNotification from '@capillarytech/cap-ui-library/CapNotification';
|
|
5
5
|
import * as Api from '../../services/api';
|
|
@@ -103,14 +103,19 @@ export function* getAllAssets(assetType, queryParams) {
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
export function* getCmsSetting({
|
|
106
|
-
cmsType, projectId, cmsMode, langId, isEdmSupport, isBEEAppEnable,
|
|
106
|
+
cmsType, projectId, cmsMode, langId, isEdmSupport, isBEEAppEnable: isBEEAppEnableFromAction,
|
|
107
107
|
}) {
|
|
108
108
|
try {
|
|
109
|
+
const emailState = yield select((state) => state.get('email'));
|
|
110
|
+
if (!emailState.get('cmsAccountsLoaded') && emailState.get('fetchingCmsAccounts')) {
|
|
111
|
+
yield take([types.GET_CMS_ACCOUNTS_SUCCESS, types.GET_CMS_ACCOUNTS_FAILURE]);
|
|
112
|
+
}
|
|
113
|
+
const updatedState = yield select((state) => state.get('email'));
|
|
114
|
+
const isBEEAppEnable = updatedState.get('isBeeEnabled') ?? isBEEAppEnableFromAction;
|
|
109
115
|
const result = yield call(Api.getCmsTemplateSettingsV2, cmsType, projectId, cmsMode, langId, isEdmSupport, isBEEAppEnable);
|
|
110
116
|
const cmsAccountDetail = result.data?.response.cmsDetails || {};
|
|
111
117
|
const isBeeEnabled = cmsAccountDetail?.type === cmsType;
|
|
112
|
-
yield put({ type: types.
|
|
113
|
-
yield put({ type: types.GET_CMS_EDITOR_DETAILS_SUCCESS, settings: result.data.response.cmsDetails });
|
|
118
|
+
yield put({ type: types.GET_CMS_EDITOR_DETAILS_SUCCESS, settings: cmsAccountDetail, isBeeEnabled });
|
|
114
119
|
} catch (error) {
|
|
115
120
|
yield put({ type: types.GET_CMS_EDITOR_DETAILS_FAILURE, error });
|
|
116
121
|
}
|
|
@@ -5,6 +5,8 @@ Immutable.Map {
|
|
|
5
5
|
"createTemplateInProgress": false,
|
|
6
6
|
"createResponse": Immutable.Map {},
|
|
7
7
|
"isBeeEnabled": null,
|
|
8
|
+
"fetchingCmsAccounts": false,
|
|
9
|
+
"cmsAccountsLoaded": false,
|
|
8
10
|
}
|
|
9
11
|
`;
|
|
10
12
|
|
|
@@ -13,5 +15,7 @@ Immutable.Map {
|
|
|
13
15
|
"createTemplateInProgress": true,
|
|
14
16
|
"createResponse": Immutable.Map {},
|
|
15
17
|
"isBeeEnabled": null,
|
|
18
|
+
"fetchingCmsAccounts": false,
|
|
19
|
+
"cmsAccountsLoaded": false,
|
|
16
20
|
}
|
|
17
21
|
`;
|
|
@@ -16,6 +16,53 @@ describe('emailReducer', () => {
|
|
|
16
16
|
expect(emailReducer(undefined, action)).toMatchSnapshot();
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
+
it.concurrent('it handles GET_CMS_EDITOR_DETAILS_SUCCESS action — sets isBeeEnabled true and CmsSettings', () => {
|
|
20
|
+
const initialState = fromJS({ isBeeEnabled: null, fetchingCmsSettings: true });
|
|
21
|
+
const action = {
|
|
22
|
+
type: types.GET_CMS_EDITOR_DETAILS_SUCCESS,
|
|
23
|
+
isBeeEnabled: true,
|
|
24
|
+
settings: { isDragDrop: true, editorType: 'bee' },
|
|
25
|
+
};
|
|
26
|
+
const result = emailReducer(initialState, action);
|
|
27
|
+
expect(result.get('fetchingCmsSettings')).toBe(false);
|
|
28
|
+
expect(result.get('isBeeEnabled')).toBe(true);
|
|
29
|
+
expect(result.getIn(['CmsSettings', 'isDragDrop'])).toBe(true);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it.concurrent('it handles GET_CMS_EDITOR_DETAILS_SUCCESS action — sets isBeeEnabled false', () => {
|
|
33
|
+
const initialState = fromJS({ isBeeEnabled: true, fetchingCmsSettings: true });
|
|
34
|
+
const action = {
|
|
35
|
+
type: types.GET_CMS_EDITOR_DETAILS_SUCCESS,
|
|
36
|
+
isBeeEnabled: false,
|
|
37
|
+
settings: {},
|
|
38
|
+
};
|
|
39
|
+
const result = emailReducer(initialState, action);
|
|
40
|
+
expect(result.get('fetchingCmsSettings')).toBe(false);
|
|
41
|
+
expect(result.get('isBeeEnabled')).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it.concurrent('it handles GET_CMS_EDITOR_DETAILS_SUCCESS action — overwrites stale isBeeEnabled from CLEAR_ALL_VALUES (null)', () => {
|
|
45
|
+
const initialState = fromJS({ isBeeEnabled: null, fetchingCmsSettings: true });
|
|
46
|
+
const action = {
|
|
47
|
+
type: types.GET_CMS_EDITOR_DETAILS_SUCCESS,
|
|
48
|
+
isBeeEnabled: true,
|
|
49
|
+
settings: { type: 'bee' },
|
|
50
|
+
};
|
|
51
|
+
const result = emailReducer(initialState, action);
|
|
52
|
+
expect(result.get('isBeeEnabled')).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it.concurrent('it handles GET_CMS_EDITOR_DETAILS_SUCCESS action — sets CmsSettings to empty object when settings is {}', () => {
|
|
56
|
+
const initialState = fromJS({ CmsSettings: { old: 'data' } });
|
|
57
|
+
const action = {
|
|
58
|
+
type: types.GET_CMS_EDITOR_DETAILS_SUCCESS,
|
|
59
|
+
isBeeEnabled: false,
|
|
60
|
+
settings: {},
|
|
61
|
+
};
|
|
62
|
+
const result = emailReducer(initialState, action);
|
|
63
|
+
expect(result.get('CmsSettings').toJS()).toEqual({});
|
|
64
|
+
});
|
|
65
|
+
|
|
19
66
|
it.concurrent('it handles GET_CMS_ACCOUNTS_REQUEST action (line 111-113)', () => {
|
|
20
67
|
const initialState = fromJS({
|
|
21
68
|
isBeeEnabled: true, // Start with true to verify it gets set to false
|