@capillarytech/creatives-library 9.0.73-alpha.sprint-testpreview.22 → 9.0.73-alpha.sprint-testpreview.23
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/package.json +1 -1
- package/v2Components/CommonTestAndPreview/index.js +37 -10
- package/v2Components/CommonTestAndPreview/tests/index.test.js +60 -0
- package/v2Components/CommonTestAndPreview/tests/utils.test.js +79 -0
- package/v2Components/CommonTestAndPreview/utils.js +46 -2
- package/v2Containers/Whatsapp/index.js +8 -7
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +2 -2
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capillarytech/creatives-library",
|
|
3
3
|
"author": "meharaj",
|
|
4
|
-
"version": "9.0.73-alpha.sprint-testpreview.
|
|
4
|
+
"version": "9.0.73-alpha.sprint-testpreview.23",
|
|
5
5
|
"description": "Capillary creatives ui",
|
|
6
6
|
"main": "./index.js",
|
|
7
7
|
"module": "./index.es.js",
|
|
@@ -40,7 +40,9 @@ import {
|
|
|
40
40
|
getRcsPrimaryTagExtractionText,
|
|
41
41
|
mergeSyntheticMustacheTags,
|
|
42
42
|
getWhatsappTagExtractionText,
|
|
43
|
+
getWhatsappCarouselCardBodyText,
|
|
43
44
|
mergeZaloUnfilledParamTags,
|
|
45
|
+
fillSlotMapFromCustomValues,
|
|
44
46
|
} from './utils';
|
|
45
47
|
import AddTestCustomerButton from './AddTestCustomer';
|
|
46
48
|
import ExistingCustomerModal from './ExistingCustomerModal';
|
|
@@ -1090,9 +1092,10 @@ const CommonTestAndPreview = (props) => {
|
|
|
1090
1092
|
};
|
|
1091
1093
|
|
|
1092
1094
|
case CHANNELS.WHATSAPP:
|
|
1095
|
+
// contentStr is templateMsg alone; carousel card bodies live in carouselData[].
|
|
1093
1096
|
return {
|
|
1094
1097
|
templateSubject: formDataObj?.title || '',
|
|
1095
|
-
templateContent: contentStr,
|
|
1098
|
+
templateContent: getWhatsappTagExtractionText(formDataObj) || contentStr,
|
|
1096
1099
|
};
|
|
1097
1100
|
|
|
1098
1101
|
case CHANNELS.RCS: {
|
|
@@ -1189,9 +1192,10 @@ const CommonTestAndPreview = (props) => {
|
|
|
1189
1192
|
* Updated to match API structure with ouId, sourceEntityId, module, deliverySettings, etc.
|
|
1190
1193
|
*/
|
|
1191
1194
|
|
|
1192
|
-
const getCarouselMappedData = (carouselData = []) => carouselData.map((carousel) => {
|
|
1195
|
+
const getCarouselMappedData = (carouselData = [], customValuesObj = {}) => carouselData.map((carousel) => {
|
|
1193
1196
|
const {
|
|
1194
|
-
|
|
1197
|
+
imageUrl, videoUrl, videoPreviewImg, buttons, mediaType, cardVarMapped, bodyTemplate,
|
|
1198
|
+
varMap, tempBodyData,
|
|
1195
1199
|
} = carousel || {};
|
|
1196
1200
|
const buttonData = buttons.map((button, index) => {
|
|
1197
1201
|
const {
|
|
@@ -1214,10 +1218,14 @@ const CommonTestAndPreview = (props) => {
|
|
|
1214
1218
|
}
|
|
1215
1219
|
return buttonObj;
|
|
1216
1220
|
});
|
|
1221
|
+
// Overview state keys a card's slot map `varMap` / `tempBodyData`; the saved-template shape
|
|
1222
|
+
// uses cardVarMapped / bodyTemplate. Read both, as whatsappMedia does for the header.
|
|
1223
|
+
// varMap wins: the editor seeds it from carousel.varMap and never from cardVarMapped, so on a
|
|
1224
|
+
// library-saved template the saved map is stale relative to what the user sees on Overview.
|
|
1217
1225
|
return {
|
|
1218
|
-
body:
|
|
1219
|
-
cardVarMapped,
|
|
1220
|
-
bodyTemplate,
|
|
1226
|
+
body: resolveTagsInText(getWhatsappCarouselCardBodyText(carousel), customValuesObj),
|
|
1227
|
+
cardVarMapped: fillSlotMapFromCustomValues(varMap ?? cardVarMapped, customValuesObj),
|
|
1228
|
+
bodyTemplate: Array.isArray(tempBodyData) ? tempBodyData.join('') : bodyTemplate,
|
|
1221
1229
|
media: {
|
|
1222
1230
|
...(mediaType?.toLowerCase() === IMAGE.toLowerCase() && {
|
|
1223
1231
|
url: imageUrl,
|
|
@@ -1289,7 +1297,9 @@ const CommonTestAndPreview = (props) => {
|
|
|
1289
1297
|
...(suggestionsFormattedForTestMeta.length > 0 && {
|
|
1290
1298
|
suggestions: suggestionsFormattedForTestMeta,
|
|
1291
1299
|
}),
|
|
1292
|
-
...(singleRcsCardPayload?.cardVarMapped && {
|
|
1300
|
+
...(singleRcsCardPayload?.cardVarMapped && {
|
|
1301
|
+
cardVarMapped: fillSlotMapFromCustomValues(singleRcsCardPayload.cardVarMapped, customValuesObj),
|
|
1302
|
+
}),
|
|
1293
1303
|
};
|
|
1294
1304
|
});
|
|
1295
1305
|
// Use the component-level smsFallbackContent prop (has rcsSmsFallbackVarMapped) so DLT
|
|
@@ -1524,7 +1534,7 @@ const CommonTestAndPreview = (props) => {
|
|
|
1524
1534
|
const language = formDataObj?.language || formDataObj?.templateLanguage || 'en';
|
|
1525
1535
|
const mediaType = formDataObj?.mediaType || formDataObj?.templateMediaType || MEDIA_TYPE_TEXT;
|
|
1526
1536
|
const buttonType = formDataObj?.buttonType || BUTTON_TYPE_NONE;
|
|
1527
|
-
const varMapped = formDataObj?.varMapped || {};
|
|
1537
|
+
const varMapped = fillSlotMapFromCustomValues(formDataObj?.varMapped || {}, customValuesObj);
|
|
1528
1538
|
const isPreviewUrl = formDataObj?.isPreviewUrl || false;
|
|
1529
1539
|
|
|
1530
1540
|
// Extract buttons from ctaData or quickReplyData
|
|
@@ -1559,7 +1569,10 @@ const CommonTestAndPreview = (props) => {
|
|
|
1559
1569
|
const whatsappMedia = {
|
|
1560
1570
|
header: resolveTagsInText(formDataObj?.templateHeader || formDataObj?.header || '', customValuesObj),
|
|
1561
1571
|
footer: formDataObj?.templateFooter || formDataObj?.footer || '',
|
|
1562
|
-
headerVarMapped:
|
|
1572
|
+
headerVarMapped: fillSlotMapFromCustomValues(
|
|
1573
|
+
formDataObj?.headerVarMapped || formDataObj?.headerVarMappedData || {},
|
|
1574
|
+
customValuesObj,
|
|
1575
|
+
),
|
|
1563
1576
|
headerTemplate: formDataObj?.headerTemplate || formDataObj?.templateHeader || '',
|
|
1564
1577
|
buttons: modifiedButtons,
|
|
1565
1578
|
language,
|
|
@@ -1632,7 +1645,7 @@ const CommonTestAndPreview = (props) => {
|
|
|
1632
1645
|
|
|
1633
1646
|
// Add carousel data if mediaType is CAROUSEL
|
|
1634
1647
|
if (mediaType === MEDIA_TYPE_CAROUSEL && formDataObj?.carouselData) {
|
|
1635
|
-
templateConfigs.cards = getCarouselMappedData(formDataObj.carouselData);
|
|
1648
|
+
templateConfigs.cards = getCarouselMappedData(formDataObj.carouselData, customValuesObj);
|
|
1636
1649
|
templateConfigs.mediaType = formDataObj?.carouselMediaType?.toUpperCase() || MEDIA_TYPE_IMAGE;
|
|
1637
1650
|
}
|
|
1638
1651
|
|
|
@@ -2674,6 +2687,16 @@ const CommonTestAndPreview = (props) => {
|
|
|
2674
2687
|
...contentObj,
|
|
2675
2688
|
templateHeader: resolvePreviewText(contentObj.templateHeader),
|
|
2676
2689
|
templateMsg: resolvePreviewText(contentObj.templateMsg),
|
|
2690
|
+
// Carousel cards render bodyText/updatedBodyText directly, so resolve both shapes.
|
|
2691
|
+
...(Array.isArray(contentObj.carouselData) && {
|
|
2692
|
+
carouselData: contentObj.carouselData.map((card) => ({
|
|
2693
|
+
...card,
|
|
2694
|
+
bodyText: resolvePreviewText(card?.bodyText),
|
|
2695
|
+
...(Array.isArray(card?.updatedBodyText) && {
|
|
2696
|
+
updatedBodyText: card.updatedBodyText.map((segment) => resolvePreviewText(segment)),
|
|
2697
|
+
}),
|
|
2698
|
+
})),
|
|
2699
|
+
}),
|
|
2677
2700
|
};
|
|
2678
2701
|
}
|
|
2679
2702
|
} else if (channel === CHANNELS.RCS) {
|
|
@@ -3533,6 +3556,10 @@ const CommonTestAndPreview = (props) => {
|
|
|
3533
3556
|
const templateContent = currentTabData?.[activeTab]?.['template-content'];
|
|
3534
3557
|
contentToExtract = templateContent || contentToExtract;
|
|
3535
3558
|
}
|
|
3559
|
+
// Include carousel card bodies, else a carousel-only template scans as tag-free.
|
|
3560
|
+
if (channel === CHANNELS.WHATSAPP) {
|
|
3561
|
+
contentToExtract = getWhatsappTagExtractionText(formData || {}) || contentToExtract;
|
|
3562
|
+
}
|
|
3536
3563
|
return contentToExtract;
|
|
3537
3564
|
};
|
|
3538
3565
|
|
|
@@ -667,6 +667,41 @@ describe('CommonTestAndPreview', () => {
|
|
|
667
667
|
expect(payload.whatsappMessageContent.templateConfigs.mediaType).toBe('VIDEO');
|
|
668
668
|
});
|
|
669
669
|
|
|
670
|
+
it('should resolve entered values into card body and fill the card slot map', async () => {
|
|
671
|
+
const formData = {
|
|
672
|
+
templateMsg: 'Deals inside',
|
|
673
|
+
mediaType: MEDIA_TYPE_CAROUSEL,
|
|
674
|
+
carouselMediaType: 'IMAGE',
|
|
675
|
+
carouselData: [
|
|
676
|
+
{
|
|
677
|
+
bodyText: 'Save {{1}} today',
|
|
678
|
+
tempBodyData: ['Save ', '{{1}}', ' today'],
|
|
679
|
+
varMap: { '{{1}}_1': '' },
|
|
680
|
+
mediaType: 'image',
|
|
681
|
+
buttons: [],
|
|
682
|
+
},
|
|
683
|
+
],
|
|
684
|
+
};
|
|
685
|
+
render(
|
|
686
|
+
<TestWrapper>
|
|
687
|
+
<CommonTestAndPreview {...defaultProps} channel={CHANNELS.WHATSAPP} formData={formData} />
|
|
688
|
+
</TestWrapper>
|
|
689
|
+
);
|
|
690
|
+
await waitFor(() => expect(lastCustomValuesEditorProps).not.toBeNull());
|
|
691
|
+
act(() => {
|
|
692
|
+
lastCustomValuesEditorProps.handleCustomValueChange('1', '20%');
|
|
693
|
+
});
|
|
694
|
+
await waitFor(() => {
|
|
695
|
+
expect(lastSendTestMessageProps).toBeDefined();
|
|
696
|
+
});
|
|
697
|
+
lastSendTestMessageProps.handleSendTestMessage();
|
|
698
|
+
const [payload] = mockActions.createMessageMetaRequested.mock.calls[0];
|
|
699
|
+
const { cards } = payload.whatsappMessageContent.templateConfigs;
|
|
700
|
+
expect(cards[0].body).toBe('Save 20% today');
|
|
701
|
+
expect(cards[0].bodyTemplate).toBe('Save {{1}} today');
|
|
702
|
+
expect(cards[0].cardVarMapped).toEqual({ '{{1}}_1': '20%' });
|
|
703
|
+
});
|
|
704
|
+
|
|
670
705
|
it('should map button type PHONE_NUMBER to buttonObj with phoneNumber', async () => {
|
|
671
706
|
const props = {
|
|
672
707
|
...defaultProps,
|
|
@@ -3843,6 +3878,31 @@ describe('CommonTestAndPreview', () => {
|
|
|
3843
3878
|
expect(getPreviewContent().templateMsg).toBe('Hi Shash, delivered by Name');
|
|
3844
3879
|
});
|
|
3845
3880
|
|
|
3881
|
+
it('fills entered values into WhatsApp carousel card bodies', async () => {
|
|
3882
|
+
const carouselContent = {
|
|
3883
|
+
templateMsg: 'Deals inside',
|
|
3884
|
+
carouselData: [
|
|
3885
|
+
{ bodyText: 'Card A {{1}}' },
|
|
3886
|
+
{ bodyText: 'Card B {{2}}', updatedBodyText: ['Card B ', '{{2}}'] },
|
|
3887
|
+
],
|
|
3888
|
+
};
|
|
3889
|
+
render(
|
|
3890
|
+
<TestWrapper>
|
|
3891
|
+
<CommonTestAndPreview
|
|
3892
|
+
{...defaultProps}
|
|
3893
|
+
channel={CHANNELS.WHATSAPP}
|
|
3894
|
+
content={carouselContent}
|
|
3895
|
+
formData={carouselContent}
|
|
3896
|
+
/>
|
|
3897
|
+
</TestWrapper>
|
|
3898
|
+
);
|
|
3899
|
+
|
|
3900
|
+
await enterValuesAndUpdatePreview({ 1: 'Sh', 2: 'Monday' });
|
|
3901
|
+
|
|
3902
|
+
expect(getPreviewContent().carouselData[0].bodyText).toBe('Card A Sh');
|
|
3903
|
+
expect(getPreviewContent().carouselData[1].updatedBodyText.join('')).toBe('Card B Monday');
|
|
3904
|
+
});
|
|
3905
|
+
|
|
3846
3906
|
it('restores WhatsApp placeholders after Discard custom values', async () => {
|
|
3847
3907
|
render(
|
|
3848
3908
|
<TestWrapper>
|
|
@@ -12,7 +12,10 @@ import {
|
|
|
12
12
|
getCarouselButtonSlotCount,
|
|
13
13
|
mergeSyntheticMustacheTags,
|
|
14
14
|
getWhatsappTagExtractionText,
|
|
15
|
+
getWhatsappCarouselCardBodyText,
|
|
16
|
+
getWhatsappCarouselTagExtractionText,
|
|
15
17
|
mergeZaloUnfilledParamTags,
|
|
18
|
+
fillSlotMapFromCustomValues,
|
|
16
19
|
} from '../utils';
|
|
17
20
|
|
|
18
21
|
describe('CommonTestAndPreview/utils', () => {
|
|
@@ -220,6 +223,48 @@ describe('CommonTestAndPreview/utils', () => {
|
|
|
220
223
|
});
|
|
221
224
|
expect(mergeSyntheticMustacheTags(apiTags, text).map((tag) => tag.name)).toEqual(['adv', '1', '2']);
|
|
222
225
|
});
|
|
226
|
+
|
|
227
|
+
it('includes carousel card bodies', () => {
|
|
228
|
+
expect(getWhatsappTagExtractionText({
|
|
229
|
+
templateMsg: 'Hi {{1}}',
|
|
230
|
+
carouselData: [{ bodyText: 'Card A {{1}}' }, { bodyText: 'Card B {{2}}' }],
|
|
231
|
+
})).toBe('Hi {{1}} Card A {{1}} Card B {{2}}');
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('surfaces a carousel-only template as having tags', () => {
|
|
235
|
+
const text = getWhatsappTagExtractionText({
|
|
236
|
+
templateMsg: 'Hi there',
|
|
237
|
+
carouselData: [{ bodyText: 'Save {{1}} today' }],
|
|
238
|
+
});
|
|
239
|
+
expect(mergeSyntheticMustacheTags([], text).map((tag) => tag.name)).toEqual(['1']);
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
describe('getWhatsappCarouselCardBodyText', () => {
|
|
244
|
+
it('prefers the slot-resolved updatedBodyText', () => {
|
|
245
|
+
expect(getWhatsappCarouselCardBodyText({
|
|
246
|
+
bodyText: 'Hi {{1}}',
|
|
247
|
+
updatedBodyText: ['Hi ', '{{firstName}}'],
|
|
248
|
+
})).toBe('Hi {{firstName}}');
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('falls back to bodyText when no resolved text exists', () => {
|
|
252
|
+
expect(getWhatsappCarouselCardBodyText({ bodyText: 'Hi {{1}}', updatedBodyText: [] })).toBe('Hi {{1}}');
|
|
253
|
+
expect(getWhatsappCarouselCardBodyText({ bodyText: 'Hi {{1}}' })).toBe('Hi {{1}}');
|
|
254
|
+
expect(getWhatsappCarouselCardBodyText(undefined)).toBe('');
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
describe('getWhatsappCarouselTagExtractionText', () => {
|
|
259
|
+
it('skips blank card bodies', () => {
|
|
260
|
+
expect(getWhatsappCarouselTagExtractionText({
|
|
261
|
+
carouselData: [{ bodyText: ' ' }, { bodyText: 'Card B {{2}}' }, {}],
|
|
262
|
+
})).toBe('Card B {{2}}');
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('returns empty string for a non-carousel template', () => {
|
|
266
|
+
expect(getWhatsappCarouselTagExtractionText({ templateMsg: 'Hi' })).toBe('');
|
|
267
|
+
});
|
|
223
268
|
});
|
|
224
269
|
|
|
225
270
|
describe('mergeZaloUnfilledParamTags', () => {
|
|
@@ -257,6 +302,40 @@ describe('CommonTestAndPreview/utils', () => {
|
|
|
257
302
|
});
|
|
258
303
|
});
|
|
259
304
|
|
|
305
|
+
describe('fillSlotMapFromCustomValues', () => {
|
|
306
|
+
it('fills blank slots from custom values, keyed by tag name', () => {
|
|
307
|
+
expect(fillSlotMapFromCustomValues(
|
|
308
|
+
{ '{{1}}_1': '', '{{2}}_3': ' ' },
|
|
309
|
+
{ 1: 'Shash', 2: 'Name' },
|
|
310
|
+
)).toEqual({ '{{1}}_1': 'Shash', '{{2}}_3': 'Name' });
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it('keeps slots already mapped on Overview', () => {
|
|
314
|
+
expect(fillSlotMapFromCustomValues(
|
|
315
|
+
{ '{{1}}_1': '{{first_name}}', '{{adv}}_3': '' },
|
|
316
|
+
{ first_name: 'ignored', adv: 'Promo' },
|
|
317
|
+
)).toEqual({ '{{1}}_1': '{{first_name}}', '{{adv}}_3': 'Promo' });
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it('supports bare numeric and semantic slot keys (RCS cardVarMapped)', () => {
|
|
321
|
+
expect(fillSlotMapFromCustomValues({ 1: '', user_name: '' }, { 1: 'A', user_name: 'B' }))
|
|
322
|
+
.toEqual({ 1: 'A', user_name: 'B' });
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it('matches custom values given as nested tag paths', () => {
|
|
326
|
+
expect(fillSlotMapFromCustomValues({ '{{first_name}}_0': '' }, { 'customer.first_name': 'Sh' }))
|
|
327
|
+
.toEqual({ '{{first_name}}_0': 'Sh' });
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
it('returns the map unchanged when there is nothing to fill', () => {
|
|
331
|
+
const slotMap = { '{{1}}_1': '' };
|
|
332
|
+
expect(fillSlotMapFromCustomValues(slotMap, {})).toBe(slotMap);
|
|
333
|
+
expect(fillSlotMapFromCustomValues(slotMap, { 2: 'x' })).toEqual(slotMap);
|
|
334
|
+
expect(fillSlotMapFromCustomValues(null, { 1: 'x' })).toBeNull();
|
|
335
|
+
expect(fillSlotMapFromCustomValues(undefined)).toBeUndefined();
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
|
|
260
339
|
describe('mergeSyntheticMustacheTags', () => {
|
|
261
340
|
it('handles null API tags', () => {
|
|
262
341
|
expect(mergeSyntheticMustacheTags(null, 'Hi {{1}}').map((tag) => tag.name)).toEqual(['1']);
|
|
@@ -61,9 +61,25 @@ export const mergeSyntheticMustacheTags = (apiTags = [], rawText = '') => {
|
|
|
61
61
|
return [...(apiTags ?? []), ...synthetic];
|
|
62
62
|
};
|
|
63
63
|
|
|
64
|
-
/**
|
|
64
|
+
/**
|
|
65
|
+
* A WhatsApp carousel card's body as the user sees it: the slot-resolved text when Overview
|
|
66
|
+
* mapping produced one, else the raw body. Mirrors the templateHeader/headerTemplate pair.
|
|
67
|
+
*/
|
|
68
|
+
export const getWhatsappCarouselCardBodyText = (card) => {
|
|
69
|
+
const resolvedBody = Array.isArray(card?.updatedBodyText) ? card.updatedBodyText.join('') : '';
|
|
70
|
+
return resolvedBody || (card?.bodyText ?? '');
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/** Carousel card bodies joined — they live outside templateMsg, so a tag scan misses them. */
|
|
74
|
+
export const getWhatsappCarouselTagExtractionText = (formDataObj) => (
|
|
75
|
+
Array.isArray(formDataObj?.carouselData) ? formDataObj.carouselData : [])
|
|
76
|
+
.map(getWhatsappCarouselCardBodyText)
|
|
77
|
+
.filter((bodyText) => hasTrimmedText(bodyText))
|
|
78
|
+
.join(' ');
|
|
79
|
+
|
|
80
|
+
/** WhatsApp header + body + carousel card bodies, scanned for unmapped `{{N}}` slots. */
|
|
65
81
|
export const getWhatsappTagExtractionText = (formDataObj) => (
|
|
66
|
-
`${formDataObj?.templateHeader || ''} ${formDataObj?.templateMsg || ''}`.trim()
|
|
82
|
+
`${formDataObj?.templateHeader || ''} ${formDataObj?.templateMsg || ''} ${getWhatsappCarouselTagExtractionText(formDataObj)}`.trim()
|
|
67
83
|
);
|
|
68
84
|
|
|
69
85
|
/** Zalo params left empty on Overview, surfaced as fillable test values (keyed by param name). */
|
|
@@ -75,6 +91,34 @@ export const mergeZaloUnfilledParamTags = (apiTags = [], formDataObj = {}) => {
|
|
|
75
91
|
return [...(apiTags ?? []), ...unfilledParamTags];
|
|
76
92
|
};
|
|
77
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Slot key -> the variable name it holds. WhatsApp keys a slot by token and occurrence index
|
|
96
|
+
* (`<token>_<index>`); RCS keys it by the variable's own name, per card.
|
|
97
|
+
*/
|
|
98
|
+
const getSlotKeyVarName = (slotKey) => String(slotKey).replace(/^\{\{(.+?)\}\}_\d+$/, '$1');
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* A slot map holds what the user mapped on Overview, per variable of the template.
|
|
102
|
+
* Slots left blank there take the value entered in Test & Preview for the same variable, so
|
|
103
|
+
* createMessageMeta gets a complete map instead of empty slots. Mapped slots are left untouched.
|
|
104
|
+
*/
|
|
105
|
+
export const fillSlotMapFromCustomValues = (slotMap, customValues = {}) => {
|
|
106
|
+
if (!slotMap || typeof slotMap !== 'object') return slotMap;
|
|
107
|
+
const customValueByVarName = {};
|
|
108
|
+
Object.keys(customValues || {}).forEach((tagPath) => {
|
|
109
|
+
customValueByVarName[tagPath.split('.').pop()] = customValues[tagPath];
|
|
110
|
+
});
|
|
111
|
+
if (Object.keys(customValueByVarName).length === 0) return slotMap;
|
|
112
|
+
const hasValue = (value) => value != null && String(value).trim() !== '';
|
|
113
|
+
const filledSlotMap = { ...slotMap };
|
|
114
|
+
Object.keys(filledSlotMap).forEach((slotKey) => {
|
|
115
|
+
if (hasValue(filledSlotMap[slotKey])) return;
|
|
116
|
+
const customValue = customValueByVarName[getSlotKeyVarName(slotKey)];
|
|
117
|
+
if (hasValue(customValue)) filledSlotMap[slotKey] = String(customValue);
|
|
118
|
+
});
|
|
119
|
+
return filledSlotMap;
|
|
120
|
+
};
|
|
121
|
+
|
|
78
122
|
/** RCS createMessageMeta: normalize media shape (mediaUrl, thumbnailUrl, height string). */
|
|
79
123
|
export const normalizeRcsTestCardMedia = (media) => {
|
|
80
124
|
if (!media || typeof media !== 'object') return undefined;
|
|
@@ -3176,13 +3176,11 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
|
|
|
3176
3176
|
templateMsgText += `\n${formatMessage(messages.templateMessageUnsubscribeText)}`;
|
|
3177
3177
|
}
|
|
3178
3178
|
|
|
3179
|
-
//
|
|
3180
|
-
const templateEditorValue =
|
|
3181
|
-
? editData.templateEditor
|
|
3182
|
-
: templateMsgText;
|
|
3179
|
+
// Raw body, slots intact — pairs with varMapped below; templateMsg carries the resolved text.
|
|
3180
|
+
const templateEditorValue = tempMsgArray.length > 0 ? tempMsgArray.join("") : templateMsgText;
|
|
3183
3181
|
|
|
3184
|
-
//
|
|
3185
|
-
const varMappedValue =
|
|
3182
|
+
// Live slot map (`{{1}}_1` -> mapped tag/value); `editData` has no varMapped, so it was always {}.
|
|
3183
|
+
const varMappedValue = { ...varMap };
|
|
3186
3184
|
|
|
3187
3185
|
return {
|
|
3188
3186
|
// Preview structure (for WhatsAppPreviewContent component)
|
|
@@ -3220,7 +3218,8 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
|
|
|
3220
3218
|
mediaType: templateMediaType,
|
|
3221
3219
|
isPreviewUrl: false,
|
|
3222
3220
|
headerVarMapped: headerVarMappedData,
|
|
3223
|
-
|
|
3221
|
+
// Raw header, slots intact — pairs with headerVarMapped; templateHeader carries the resolved text.
|
|
3222
|
+
headerTemplate: tempHeaderData.length > 0 ? tempHeaderData.join("") : templateHeader,
|
|
3224
3223
|
whatsappVideoSrcAndPreview,
|
|
3225
3224
|
whatsappDocSource,
|
|
3226
3225
|
whatsappDocParams,
|
|
@@ -3239,6 +3238,8 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
|
|
|
3239
3238
|
docPreview,
|
|
3240
3239
|
isEditFlow,
|
|
3241
3240
|
updatedSmsEditor,
|
|
3241
|
+
tempMsgArray,
|
|
3242
|
+
tempHeaderData,
|
|
3242
3243
|
templateMessage,
|
|
3243
3244
|
unsubscribeRequired,
|
|
3244
3245
|
isAuthenticationTemplate,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap
|
|
3
|
-
size:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 57295127 bytes
|
|
4
|
+
sha256: 3ca4752bd0410b9d7f0e57070855228ef817cc04531f23794bf27e2647b4f7a2
|