@capillarytech/creatives-library 8.0.329 → 8.0.330-alpha.0
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 +4 -0
- package/package.json +1 -1
- package/utils/commonUtils.js +19 -1
- package/utils/templateVarUtils.js +35 -6
- package/utils/tests/templateVarUtils.test.js +44 -0
- package/v2Components/CommonTestAndPreview/index.js +49 -57
- package/v2Components/SmsFallback/smsFallbackUtils.js +14 -3
- package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +16 -0
- package/v2Components/TestAndPreviewSlidebox/index.js +5 -0
- package/v2Containers/CreativesContainer/index.js +9 -3
- package/v2Containers/Rcs/constants.js +6 -2
- package/v2Containers/Rcs/index.js +218 -83
- package/v2Containers/Rcs/messages.js +2 -1
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +20 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +484 -4
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +67 -0
- package/v2Containers/Rcs/tests/utils.test.js +56 -0
- package/v2Containers/Rcs/utils.js +53 -6
- package/v2Containers/SmsTrai/Edit/index.js +27 -0
- package/v2Containers/SmsTrai/Edit/messages.js +5 -0
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +6 -6
|
@@ -8,6 +8,8 @@ import {
|
|
|
8
8
|
syncCardVarMappedSemanticsFromSlots,
|
|
9
9
|
hasMeaningfulSmsFallbackShape,
|
|
10
10
|
getLibrarySmsFallbackApiBaselineFromTemplateData,
|
|
11
|
+
extractRegisteredSenderIdsFromSmsFallbackRecord,
|
|
12
|
+
pickRcsCardVarMappedEntries,
|
|
11
13
|
} from '../rcsLibraryHydrationUtils';
|
|
12
14
|
import { rcsVarRegex } from '../constants';
|
|
13
15
|
|
|
@@ -103,6 +105,41 @@ describe('rcsLibraryHydrationUtils', () => {
|
|
|
103
105
|
});
|
|
104
106
|
});
|
|
105
107
|
|
|
108
|
+
describe('extractRegisteredSenderIdsFromSmsFallbackRecord', () => {
|
|
109
|
+
it('returns null for missing / empty', () => {
|
|
110
|
+
expect(extractRegisteredSenderIdsFromSmsFallbackRecord(null)).toBe(null);
|
|
111
|
+
expect(extractRegisteredSenderIdsFromSmsFallbackRecord({})).toBe(null);
|
|
112
|
+
expect(
|
|
113
|
+
extractRegisteredSenderIdsFromSmsFallbackRecord({ registeredSenderIds: [] }),
|
|
114
|
+
).toBe(null);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('prefers top-level registeredSenderIds', () => {
|
|
118
|
+
expect(
|
|
119
|
+
extractRegisteredSenderIdsFromSmsFallbackRecord({
|
|
120
|
+
registeredSenderIds: ['A'],
|
|
121
|
+
templateConfigs: { registeredSenderIds: ['B'] },
|
|
122
|
+
}),
|
|
123
|
+
).toEqual(['A']);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('reads templateConfigs.registeredSenderIds when top-level absent', () => {
|
|
127
|
+
expect(
|
|
128
|
+
extractRegisteredSenderIdsFromSmsFallbackRecord({
|
|
129
|
+
templateConfigs: { registeredSenderIds: ['DLT1', 'DLT2'] },
|
|
130
|
+
}),
|
|
131
|
+
).toEqual(['DLT1', 'DLT2']);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('falls back to templateConfigs.header array', () => {
|
|
135
|
+
expect(
|
|
136
|
+
extractRegisteredSenderIdsFromSmsFallbackRecord({
|
|
137
|
+
templateConfigs: { header: ['H1'] },
|
|
138
|
+
}),
|
|
139
|
+
).toEqual(['H1']);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
106
143
|
describe('pickFirstSmsFallbackTemplateString', () => {
|
|
107
144
|
it('prefers smsTemplateContent over resolved message so DLT tokens stay in the string', () => {
|
|
108
145
|
const sms = {
|
|
@@ -173,6 +210,7 @@ describe('rcsLibraryHydrationUtils', () => {
|
|
|
173
210
|
it('is true when string contains {{word}} tokens', () => {
|
|
174
211
|
expect(hasRcsVarTokens('{{1}} hi', rcsVarRegex)).toBe(true);
|
|
175
212
|
expect(hasRcsVarTokens('{{user_id}}', rcsVarRegex)).toBe(true);
|
|
213
|
+
expect(hasRcsVarTokens('{{dynamic_expiry_date_after_3_days.FORMAT_1}}', rcsVarRegex)).toBe(true);
|
|
176
214
|
});
|
|
177
215
|
});
|
|
178
216
|
|
|
@@ -248,4 +286,33 @@ describe('rcsLibraryHydrationUtils', () => {
|
|
|
248
286
|
expect(out.user_name).toBe('kept');
|
|
249
287
|
});
|
|
250
288
|
});
|
|
289
|
+
|
|
290
|
+
describe('pickRcsCardVarMappedEntries', () => {
|
|
291
|
+
it('returns {} for null, undefined, and array inputs', () => {
|
|
292
|
+
expect(pickRcsCardVarMappedEntries(null)).toEqual({});
|
|
293
|
+
expect(pickRcsCardVarMappedEntries(undefined)).toEqual({});
|
|
294
|
+
expect(pickRcsCardVarMappedEntries(['{#v#}_0', 'x'])).toEqual({});
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it('keeps numeric slot keys', () => {
|
|
298
|
+
expect(pickRcsCardVarMappedEntries({ 1: 'a', 2: 'b' })).toEqual({ 1: 'a', 2: 'b' });
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it('keeps semantic word keys', () => {
|
|
302
|
+
expect(pickRcsCardVarMappedEntries({ user_name: 'Alice', gt: '{{tag}}' })).toEqual({
|
|
303
|
+
user_name: 'Alice',
|
|
304
|
+
gt: '{{tag}}',
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('strips SMS fallback slot keys like {#var#}_0', () => {
|
|
309
|
+
const input = { 1: 'x', user_name: 'y', '{#promo#}_0': 'z', '{{name}}_1': 'w' };
|
|
310
|
+
const out = pickRcsCardVarMappedEntries(input);
|
|
311
|
+
expect(out).toEqual({ 1: 'x', user_name: 'y' });
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it('returns {} for an empty object', () => {
|
|
315
|
+
expect(pickRcsCardVarMappedEntries({})).toEqual({});
|
|
316
|
+
});
|
|
317
|
+
});
|
|
251
318
|
});
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
getTemplateStatusType,
|
|
8
8
|
normalizeCardVarMapped,
|
|
9
9
|
coalesceCardVarMappedToTemplate,
|
|
10
|
+
getRcsSemanticVarNamesSpanningTitleAndDesc,
|
|
10
11
|
resolveCardVarMappedSlotValue,
|
|
11
12
|
isRcsTextOnlyCardMediaType,
|
|
12
13
|
mapRcsCardContentForConsumerWithResolvedTags,
|
|
@@ -215,7 +216,39 @@ describe('RCS utils', () => {
|
|
|
215
216
|
});
|
|
216
217
|
});
|
|
217
218
|
|
|
219
|
+
describe('getRcsSemanticVarNamesSpanningTitleAndDesc', () => {
|
|
220
|
+
it('returns names that appear in both title and description', () => {
|
|
221
|
+
const set = getRcsSemanticVarNamesSpanningTitleAndDesc(
|
|
222
|
+
'Hello {{adv}}',
|
|
223
|
+
'Body {{adv}} x {{other}}',
|
|
224
|
+
rcsVarRegex,
|
|
225
|
+
);
|
|
226
|
+
expect(Array.from(set).sort()).toEqual(['adv']);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('is empty when the same name is only repeated in the title', () => {
|
|
230
|
+
const set = getRcsSemanticVarNamesSpanningTitleAndDesc(
|
|
231
|
+
'{{user_name}} and {{user_name}}',
|
|
232
|
+
'Hi',
|
|
233
|
+
rcsVarRegex,
|
|
234
|
+
);
|
|
235
|
+
expect(set.size).toBe(0);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
218
239
|
describe('coalesceCardVarMappedToTemplate', () => {
|
|
240
|
+
it('does not copy a shared semantic value into the second slot when the tag spans title and description', () => {
|
|
241
|
+
const out = coalesceCardVarMappedToTemplate(
|
|
242
|
+
{ adv: 'shared' },
|
|
243
|
+
'T {{adv}}',
|
|
244
|
+
'D {{adv}}',
|
|
245
|
+
rcsVarRegex,
|
|
246
|
+
);
|
|
247
|
+
expect(out[1]).toBe('shared');
|
|
248
|
+
expect(out[2]).toBe('');
|
|
249
|
+
expect(out.adv).toBe('shared');
|
|
250
|
+
});
|
|
251
|
+
|
|
219
252
|
it('maps slot 1 to first token name from title', () => {
|
|
220
253
|
expect(
|
|
221
254
|
coalesceCardVarMappedToTemplate(
|
|
@@ -332,6 +365,24 @@ describe('RCS utils', () => {
|
|
|
332
365
|
),
|
|
333
366
|
).toBe('{{loyalty_points}}');
|
|
334
367
|
});
|
|
368
|
+
|
|
369
|
+
it('omitSemanticFallback: duplicate title+desc tag does not read shared semantic for either slot', () => {
|
|
370
|
+
expect(
|
|
371
|
+
resolveCardVarMappedSlotValue({ adv: '{{adv}}', 1: '', 2: '' }, 'adv', 0, false, true),
|
|
372
|
+
).toBe('');
|
|
373
|
+
expect(
|
|
374
|
+
resolveCardVarMappedSlotValue({ adv: '{{adv}}', 1: 'A', 2: 'B' }, 'adv', 0, false, true),
|
|
375
|
+
).toBe('A');
|
|
376
|
+
expect(
|
|
377
|
+
resolveCardVarMappedSlotValue({ adv: '{{adv}}', 1: 'A', 2: 'B' }, 'adv', 1, false, true),
|
|
378
|
+
).toBe('B');
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
it('omitSemanticFallback: cleared semantic does not force empty when numeric slot has a value', () => {
|
|
382
|
+
expect(
|
|
383
|
+
resolveCardVarMappedSlotValue({ adv: '', 1: 'first', 2: 'second' }, 'adv', 1, false, true),
|
|
384
|
+
).toBe('second');
|
|
385
|
+
});
|
|
335
386
|
});
|
|
336
387
|
|
|
337
388
|
describe('mapRcsCardContentForConsumerWithResolvedTags', () => {
|
|
@@ -374,6 +425,11 @@ describe('RCS utils', () => {
|
|
|
374
425
|
expect(out[0].title).toBe('Hi {{customer_name}}');
|
|
375
426
|
expect(out[0].description).toBe('Pts {{loyalty_points}}');
|
|
376
427
|
});
|
|
428
|
+
|
|
429
|
+
it('passes through null or non-object items in the card array unchanged', () => {
|
|
430
|
+
const out = mapRcsCardContentForConsumerWithResolvedTags([null, 'string', 42], {}, false);
|
|
431
|
+
expect(out).toEqual([null, 'string', 42]);
|
|
432
|
+
});
|
|
377
433
|
});
|
|
378
434
|
|
|
379
435
|
describe('isRcsTextOnlyCardMediaType', () => {
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
COMBINED_SMS_TEMPLATE_VAR_REGEX,
|
|
23
23
|
isAnyTemplateVarToken,
|
|
24
24
|
} from '../../utils/templateVarUtils';
|
|
25
|
+
import { pickRcsCardVarMappedEntries } from './rcsLibraryHydrationUtils';
|
|
25
26
|
|
|
26
27
|
export const getRcsStatusType = (status) => {
|
|
27
28
|
switch (status) {
|
|
@@ -130,6 +131,27 @@ export function normalizeCardVarMapped(rawCardVarMapped, orderedTagNames) {
|
|
|
130
131
|
return normalizedMap;
|
|
131
132
|
}
|
|
132
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Semantic names that appear in both title and description (e.g. `{{adv}}` in header and body).
|
|
136
|
+
* Those slots must not share one semantic `cardVarMapped` key — otherwise VarSegment inputs mirror.
|
|
137
|
+
*/
|
|
138
|
+
export function getRcsSemanticVarNamesSpanningTitleAndDesc(
|
|
139
|
+
templateTitle,
|
|
140
|
+
templateDesc,
|
|
141
|
+
rcsVarRegex,
|
|
142
|
+
) {
|
|
143
|
+
const getVarNameFromToken = (token = '') => token.replace(RCS_STRIP_MUSTACHE_DELIMITERS_REGEX, '');
|
|
144
|
+
const titleTokens = templateTitle?.match(rcsVarRegex) ?? [];
|
|
145
|
+
const descTokens = templateDesc?.match(rcsVarRegex) ?? [];
|
|
146
|
+
const titleNames = new Set(titleTokens.map(getVarNameFromToken).filter(Boolean));
|
|
147
|
+
const descNames = new Set(descTokens.map(getVarNameFromToken).filter(Boolean));
|
|
148
|
+
const spanning = new Set();
|
|
149
|
+
titleNames.forEach((n) => {
|
|
150
|
+
if (descNames.has(n)) spanning.add(n);
|
|
151
|
+
});
|
|
152
|
+
return spanning;
|
|
153
|
+
}
|
|
154
|
+
|
|
133
155
|
/**
|
|
134
156
|
* Rebuild `cardVarMapped` so keys match the current title/description tokens (title tokens first,
|
|
135
157
|
* then description), in order. Values are taken from the matching key, else from legacy slot
|
|
@@ -151,15 +173,25 @@ export function coalesceCardVarMappedToTemplate(
|
|
|
151
173
|
if (!templateVarTokens.length) {
|
|
152
174
|
return { ...lookupSourceMap };
|
|
153
175
|
}
|
|
176
|
+
const semanticNamesSpanningTitleAndDesc = getRcsSemanticVarNamesSpanningTitleAndDesc(
|
|
177
|
+
templateTitle,
|
|
178
|
+
templateDesc,
|
|
179
|
+
rcsVarRegex,
|
|
180
|
+
);
|
|
154
181
|
const coalescedMap = { ...lookupSourceMap };
|
|
155
182
|
const seenSemanticVarNames = new Set();
|
|
156
183
|
templateVarTokens.forEach((token, slotIndexZeroBased) => {
|
|
157
184
|
const semanticVarName = getVarNameFromToken(token);
|
|
158
185
|
if (!semanticVarName) return;
|
|
159
186
|
const numericSlotKey = String(slotIndexZeroBased + 1);
|
|
187
|
+
const isRepeatOfSemanticName = seenSemanticVarNames.has(semanticVarName);
|
|
188
|
+
const skipSharedSemanticLookup =
|
|
189
|
+
isRepeatOfSemanticName && semanticNamesSpanningTitleAndDesc.has(semanticVarName);
|
|
160
190
|
let valueFromSource = lookupSourceMap[numericSlotKey];
|
|
161
191
|
if (valueFromSource === undefined || valueFromSource === null) {
|
|
162
|
-
|
|
192
|
+
if (!skipSharedSemanticLookup) {
|
|
193
|
+
valueFromSource = lookupSourceMap[semanticVarName];
|
|
194
|
+
}
|
|
163
195
|
}
|
|
164
196
|
if (valueFromSource === undefined || valueFromSource === null) {
|
|
165
197
|
valueFromSource = lookupSourceMap[String(slotIndexZeroBased + 1)];
|
|
@@ -189,12 +221,17 @@ export function coalesceCardVarMappedToTemplate(
|
|
|
189
221
|
* When a numeric slot is present but only whitespace / empty (common after hydration), do not
|
|
190
222
|
* treat it as authoritative — fall through to the semantic key so preview and payload match the
|
|
191
223
|
* tag the user selected (e.g. `1: ''` but `promotion_points: '{{newTag}}'`).
|
|
224
|
+
*
|
|
225
|
+
* @param {boolean} [omitSemanticFallback=false] When true, do not read `varName` on the map (and do
|
|
226
|
+
* not apply the early `semanticEmpty` short-circuit). Use when the same semantic name appears in
|
|
227
|
+
* both title and description so each global slot stays independent.
|
|
192
228
|
*/
|
|
193
229
|
export function resolveCardVarMappedSlotValue(
|
|
194
230
|
cardVarMapped,
|
|
195
231
|
varName,
|
|
196
232
|
globalSlotIndexZeroBased,
|
|
197
233
|
isLibraryMode = false,
|
|
234
|
+
omitSemanticFallback = false,
|
|
198
235
|
) {
|
|
199
236
|
const varMap = cardVarMapped ?? {};
|
|
200
237
|
const slotKey = String(globalSlotIndexZeroBased + 1);
|
|
@@ -205,7 +242,7 @@ export function resolveCardVarMappedSlotValue(
|
|
|
205
242
|
Object.prototype.hasOwnProperty.call(varMap, slotKey)
|
|
206
243
|
&& String(varMap[slotKey] ?? '').trim() !== '';
|
|
207
244
|
|
|
208
|
-
if (semanticEmpty && !(isLibraryMode && slotNonEmpty)) {
|
|
245
|
+
if (semanticEmpty && !(isLibraryMode && slotNonEmpty) && !omitSemanticFallback) {
|
|
209
246
|
return '';
|
|
210
247
|
}
|
|
211
248
|
let numericSlotValue = '';
|
|
@@ -217,7 +254,7 @@ export function resolveCardVarMappedSlotValue(
|
|
|
217
254
|
if (numericSlotValue.trim() !== '') {
|
|
218
255
|
return numericSlotValue;
|
|
219
256
|
}
|
|
220
|
-
if (Object.prototype.hasOwnProperty.call(varMap, varName)) {
|
|
257
|
+
if (!omitSemanticFallback && Object.prototype.hasOwnProperty.call(varMap, varName)) {
|
|
221
258
|
return String(varMap[varName] ?? '');
|
|
222
259
|
}
|
|
223
260
|
return '';
|
|
@@ -247,6 +284,9 @@ export function resolveRcsCardPreviewStrings(
|
|
|
247
284
|
const splitTemplateVarStringRcs = (str) => splitTemplateVarString(str, rcsVarRegex);
|
|
248
285
|
const getVarNameFromToken = (token = '') =>
|
|
249
286
|
token.replace(RCS_STRIP_MUSTACHE_DELIMITERS_REGEX, '');
|
|
287
|
+
const semanticNamesSpanningTitleAndDesc = textOnlyCard
|
|
288
|
+
? new Set()
|
|
289
|
+
: getRcsSemanticVarNamesSpanningTitleAndDesc(title, description, rcsVarRegex);
|
|
250
290
|
|
|
251
291
|
const resolveTemplateWithMap = (str = '', slotOffset = 0) => {
|
|
252
292
|
if (!str) return '';
|
|
@@ -258,11 +298,13 @@ export function resolveRcsCardPreviewStrings(
|
|
|
258
298
|
const key = getVarNameFromToken(elem);
|
|
259
299
|
const globalSlot = slotOffset + varOrdinal;
|
|
260
300
|
varOrdinal += 1;
|
|
301
|
+
const omitSemantic = semanticNamesSpanningTitleAndDesc.has(key);
|
|
261
302
|
const v = resolveCardVarMappedSlotValue(
|
|
262
303
|
cardVarMapped,
|
|
263
304
|
key,
|
|
264
305
|
globalSlot,
|
|
265
306
|
isLibraryMode,
|
|
307
|
+
omitSemantic,
|
|
266
308
|
);
|
|
267
309
|
if (v == null || String(v).trim() === '') return elem;
|
|
268
310
|
return String(v);
|
|
@@ -285,7 +327,8 @@ export function resolveRcsCardPreviewStrings(
|
|
|
285
327
|
/**
|
|
286
328
|
* Campaign consumer payload: replace each card's `title` / `description` with VarSegment-resolved
|
|
287
329
|
* tag strings (same rules as {@link resolveRcsCardPreviewStrings}). Root `rcsCardVarMapped` merges
|
|
288
|
-
* with per-card `cardVarMapped
|
|
330
|
+
* with per-card `cardVarMapped` for resolution; emitted `cardVarMapped` omits SMS-fallback slot keys
|
|
331
|
+
* (root/nested merged with {@link pickRcsCardVarMappedEntries} per side).
|
|
289
332
|
*/
|
|
290
333
|
export function mapRcsCardContentForConsumerWithResolvedTags(
|
|
291
334
|
cardContentArray,
|
|
@@ -304,7 +347,9 @@ export function mapRcsCardContentForConsumerWithResolvedTags(
|
|
|
304
347
|
card.cardVarMapped != null && typeof card.cardVarMapped === 'object'
|
|
305
348
|
? card.cardVarMapped
|
|
306
349
|
: {};
|
|
307
|
-
const
|
|
350
|
+
const rootClean = pickRcsCardVarMappedEntries(rootRecord);
|
|
351
|
+
const nestedClean = pickRcsCardVarMappedEntries(nested);
|
|
352
|
+
const merged = { ...rootClean, ...nestedClean };
|
|
308
353
|
const textOnly = isRcsTextOnlyCardMediaType(card.mediaType);
|
|
309
354
|
const { rcsTitle, rcsDesc } = resolveRcsCardPreviewStrings(
|
|
310
355
|
card.title ?? '',
|
|
@@ -313,10 +358,12 @@ export function mapRcsCardContentForConsumerWithResolvedTags(
|
|
|
313
358
|
isLibraryMode,
|
|
314
359
|
textOnly,
|
|
315
360
|
);
|
|
361
|
+
const { cardVarMapped: _drop, ...cardRest } = card;
|
|
316
362
|
return {
|
|
317
|
-
...
|
|
363
|
+
...cardRest,
|
|
318
364
|
title: rcsTitle,
|
|
319
365
|
description: rcsDesc,
|
|
366
|
+
...(Object.keys(nestedClean).length > 0 ? { cardVarMapped: nestedClean } : {}),
|
|
320
367
|
};
|
|
321
368
|
});
|
|
322
369
|
}
|
|
@@ -1102,6 +1102,33 @@ export const SmsTraiEdit = (props) => {
|
|
|
1102
1102
|
</CapLabelInline>
|
|
1103
1103
|
</TraiEditTemplateDetails>
|
|
1104
1104
|
)}
|
|
1105
|
+
{isRcsSmsFallback &&
|
|
1106
|
+
traiDataRef.current &&
|
|
1107
|
+
!isEmpty(traiDataRef.current) &&
|
|
1108
|
+
!loading && (
|
|
1109
|
+
<TraiEditTemplateDetails className="sms-trai-edit-rcs-fallback__template-meta">
|
|
1110
|
+
<CapLabelInline type="label1">
|
|
1111
|
+
{formatMessage(messages.templateNameLabel)}
|
|
1112
|
+
</CapLabelInline>
|
|
1113
|
+
<CapLabelInline type="label2">
|
|
1114
|
+
{get(traiDataRef.current, 'versions.base.template_name', '')
|
|
1115
|
+
|| get(traiDataRef.current, 'name', '')}
|
|
1116
|
+
</CapLabelInline>
|
|
1117
|
+
{traiDltEnabled ? (
|
|
1118
|
+
<>
|
|
1119
|
+
<CapLabelInline type="label1">
|
|
1120
|
+
{formatMessage(messages.traiEditSeperator)}
|
|
1121
|
+
</CapLabelInline>
|
|
1122
|
+
<CapLabelInline type="label1">
|
|
1123
|
+
{formatMessage(messages.senderIdlabel)}
|
|
1124
|
+
</CapLabelInline>
|
|
1125
|
+
<CapLabelInline type="label2">
|
|
1126
|
+
{[...get(traiDataRef.current, 'versions.base.header', [])].join(', ')}
|
|
1127
|
+
</CapLabelInline>
|
|
1128
|
+
</>
|
|
1129
|
+
) : null}
|
|
1130
|
+
</TraiEditTemplateDetails>
|
|
1131
|
+
)}
|
|
1105
1132
|
<CapColumn span={shouldShowPreview ? 14 : 24}>
|
|
1106
1133
|
<CapRow>
|
|
1107
1134
|
<CapHeader
|
|
@@ -48,6 +48,11 @@ export default defineMessages({
|
|
|
48
48
|
id: `${prefix}.templateLabel`,
|
|
49
49
|
defaultMessage: 'Template',
|
|
50
50
|
},
|
|
51
|
+
/** RCS → SMS fallback slidebox: label above selected template metadata. */
|
|
52
|
+
templateNameLabel: {
|
|
53
|
+
id: `${prefix}.templateNameLabel`,
|
|
54
|
+
defaultMessage: 'Template name',
|
|
55
|
+
},
|
|
51
56
|
traiEditSeperator: {
|
|
52
57
|
id: `${prefix}.traiEditSeperator`,
|
|
53
58
|
defaultMessage: '|',
|
|
@@ -3292,7 +3292,7 @@ FREE GIFTS-
|
|
|
3292
3292
|
</div>
|
|
3293
3293
|
</Edit__TraiEditTemplateDetails>
|
|
3294
3294
|
<CapColumn
|
|
3295
|
-
key=".
|
|
3295
|
+
key=".2"
|
|
3296
3296
|
span={14}
|
|
3297
3297
|
>
|
|
3298
3298
|
<Col
|
|
@@ -4552,7 +4552,7 @@ FREE GIFTS-
|
|
|
4552
4552
|
</Col>
|
|
4553
4553
|
</CapColumn>
|
|
4554
4554
|
<CapColumn
|
|
4555
|
-
key=".
|
|
4555
|
+
key=".3"
|
|
4556
4556
|
offset={1}
|
|
4557
4557
|
span={8}
|
|
4558
4558
|
>
|
|
@@ -14962,7 +14962,7 @@ FREE GIFTS-
|
|
|
14962
14962
|
</div>
|
|
14963
14963
|
</Edit__TraiEditTemplateDetails>
|
|
14964
14964
|
<CapColumn
|
|
14965
|
-
key=".
|
|
14965
|
+
key=".2"
|
|
14966
14966
|
span={14}
|
|
14967
14967
|
>
|
|
14968
14968
|
<Col
|
|
@@ -16222,7 +16222,7 @@ FREE GIFTS-
|
|
|
16222
16222
|
</Col>
|
|
16223
16223
|
</CapColumn>
|
|
16224
16224
|
<CapColumn
|
|
16225
|
-
key=".
|
|
16225
|
+
key=".3"
|
|
16226
16226
|
offset={1}
|
|
16227
16227
|
span={8}
|
|
16228
16228
|
>
|
|
@@ -26632,7 +26632,7 @@ FREE GIFTS-
|
|
|
26632
26632
|
</div>
|
|
26633
26633
|
</Edit__TraiEditTemplateDetails>
|
|
26634
26634
|
<CapColumn
|
|
26635
|
-
key=".
|
|
26635
|
+
key=".2"
|
|
26636
26636
|
span={14}
|
|
26637
26637
|
>
|
|
26638
26638
|
<Col
|
|
@@ -27892,7 +27892,7 @@ FREE GIFTS-
|
|
|
27892
27892
|
</Col>
|
|
27893
27893
|
</CapColumn>
|
|
27894
27894
|
<CapColumn
|
|
27895
|
-
key=".
|
|
27895
|
+
key=".3"
|
|
27896
27896
|
offset={1}
|
|
27897
27897
|
span={8}
|
|
27898
27898
|
>
|