@capillarytech/creatives-library 8.0.353-alpha.6 → 8.0.354
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 +0 -29
- package/index.html +1 -0
- package/package.json +1 -1
- package/services/tests/api.test.js +20 -35
- package/utils/cdnTransformation.js +63 -3
- package/utils/commonUtils.js +1 -19
- package/utils/tests/cdnTransformation.test.js +111 -0
- package/v2Components/CapActionButton/constants.js +0 -7
- package/v2Components/CapActionButton/index.js +108 -166
- package/v2Components/CapActionButton/index.scss +6 -157
- package/v2Components/CapActionButton/messages.js +3 -19
- package/v2Components/CapActionButton/tests/index.test.js +17 -41
- package/v2Components/CapTagList/index.js +0 -10
- package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +49 -72
- package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +2 -8
- package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +21 -213
- package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +0 -16
- package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +10 -85
- package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +0 -30
- package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +11 -79
- package/v2Components/CommonTestAndPreview/SendTestMessage.js +5 -10
- package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +15 -157
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +76 -346
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +4 -133
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +0 -11
- package/v2Components/CommonTestAndPreview/constants.js +2 -38
- package/v2Components/CommonTestAndPreview/index.js +186 -691
- package/v2Components/CommonTestAndPreview/messages.js +3 -45
- package/v2Components/CommonTestAndPreview/sagas.js +6 -25
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +284 -308
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +65 -231
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +5 -118
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +0 -341
- package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +1 -8
- package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +13 -34
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +283 -281
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +1 -199
- package/v2Components/CommonTestAndPreview/tests/index.test.js +4 -132
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +26 -36
- package/v2Components/FormBuilder/index.js +6 -11
- package/v2Components/TemplatePreview/_templatePreview.scss +23 -38
- package/v2Components/TemplatePreview/index.js +31 -143
- package/v2Components/TemplatePreview/tests/index.test.js +0 -142
- package/v2Components/TestAndPreviewSlidebox/index.js +1 -13
- package/v2Components/TestAndPreviewSlidebox/sagas.js +4 -11
- package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +1 -3
- package/v2Containers/CreativesContainer/SlideBoxContent.js +4 -36
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +1 -10
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +4 -29
- package/v2Containers/CreativesContainer/constants.js +0 -9
- package/v2Containers/CreativesContainer/index.js +103 -322
- package/v2Containers/CreativesContainer/index.scss +1 -51
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +34 -78
- package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +16 -79
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -8
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +98 -357
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +15 -20
- package/v2Containers/CreativesContainer/tests/index.test.js +9 -71
- package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
- package/v2Containers/Rcs/constants.js +10 -119
- package/v2Containers/Rcs/index.js +818 -2450
- package/v2Containers/Rcs/index.scss +8 -280
- package/v2Containers/Rcs/messages.js +3 -34
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +70073 -98018
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +5 -0
- package/v2Containers/Rcs/tests/index.test.js +121 -152
- package/v2Containers/Rcs/tests/mockData.js +0 -38
- package/v2Containers/Rcs/tests/utils.test.js +30 -646
- package/v2Containers/Rcs/utils.js +11 -478
- package/v2Containers/Sms/Create/index.js +40 -106
- package/v2Containers/SmsTrai/Create/index.js +4 -9
- package/v2Containers/SmsTrai/Edit/constants.js +0 -2
- package/v2Containers/SmsTrai/Edit/index.js +130 -640
- package/v2Containers/SmsTrai/Edit/messages.js +4 -14
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +2296 -4249
- package/v2Containers/SmsWrapper/index.js +8 -37
- package/v2Containers/TagList/index.js +0 -6
- package/v2Containers/Templates/_templates.scss +9 -166
- package/v2Containers/Templates/actions.js +0 -11
- package/v2Containers/Templates/constants.js +0 -2
- package/v2Containers/Templates/index.js +52 -120
- package/v2Containers/Templates/sagas.js +18 -57
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1017 -1062
- package/v2Containers/Templates/tests/sagas.test.js +39 -205
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +1 -72
- package/v2Containers/TemplatesV2/index.js +23 -86
- package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
- package/v2Containers/Whatsapp/index.js +20 -3
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -578
- package/utils/rcsPayloadUtils.js +0 -92
- package/utils/templateVarUtils.js +0 -201
- package/utils/tests/rcsPayloadUtils.test.js +0 -226
- package/utils/tests/templateVarUtils.test.js +0 -204
- package/v2Components/CommonTestAndPreview/previewApiUtils.js +0 -59
- package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +0 -67
- package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +0 -91
- package/v2Components/SmsFallback/constants.js +0 -73
- package/v2Components/SmsFallback/index.js +0 -956
- package/v2Components/SmsFallback/index.scss +0 -265
- package/v2Components/SmsFallback/messages.js +0 -78
- package/v2Components/SmsFallback/smsFallbackUtils.js +0 -119
- package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +0 -50
- package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +0 -147
- package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +0 -304
- package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +0 -223
- package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +0 -309
- package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +0 -422
- package/v2Components/SmsFallback/useLocalTemplateList.js +0 -92
- package/v2Components/TemplatePreview/constants.js +0 -2
- package/v2Components/VarSegmentMessageEditor/constants.js +0 -2
- package/v2Components/VarSegmentMessageEditor/index.js +0 -125
- package/v2Components/VarSegmentMessageEditor/index.scss +0 -46
- package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +0 -43
- package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +0 -79
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +0 -90
- package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +0 -258
- package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +0 -125
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +0 -225
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -318
- package/v2Containers/Sms/smsFormDataHelpers.js +0 -67
- package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +0 -253
- package/v2Containers/SmsTrai/Edit/index.scss +0 -121
- package/v2Containers/Templates/TemplatesActionBar.js +0 -101
- package/v2Containers/Templates/tests/TemplatesActionBar.test.js +0 -120
- package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +0 -180
- package/v2Containers/Templates/utils/smsTemplatesListApi.js +0 -79
- package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +0 -131
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
extractTemplateVariables,
|
|
3
|
-
splitTemplateVarString,
|
|
4
|
-
splitContentByOrderedVarTokens,
|
|
5
|
-
getFallbackResolvedContent,
|
|
6
|
-
getFallbackResolvedContentForCardDisplay,
|
|
7
|
-
isDltHashVarToken,
|
|
8
|
-
isAnyTemplateVarToken,
|
|
9
|
-
} from '../templateVarUtils';
|
|
10
|
-
|
|
11
|
-
describe('templateVarUtils', () => {
|
|
12
|
-
describe('splitContentByOrderedVarTokens', () => {
|
|
13
|
-
it('pushes remainder when next token is not found in string', () => {
|
|
14
|
-
expect(splitContentByOrderedVarTokens(['{{b}}'], 'hello')).toEqual(['hello']);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('handles empty token queue by pushing remainder', () => {
|
|
18
|
-
expect(splitContentByOrderedVarTokens([], 'rest')).toEqual(['rest']);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('handles null matchedVariableTokens as empty queue', () => {
|
|
22
|
-
expect(splitContentByOrderedVarTokens(null, 'abc')).toEqual(['abc']);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('stops and pushes remainder when next token in queue is empty string', () => {
|
|
26
|
-
expect(splitContentByOrderedVarTokens(['{{a}}', ''], 'x{{a}}y')).toEqual(['x', '{{a}}', 'y']);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('splits multiple ordered tokens across content', () => {
|
|
30
|
-
expect(splitContentByOrderedVarTokens(['{{a}}', '{{b}}'], 'p{{a}}q{{b}}r')).toEqual([
|
|
31
|
-
'p',
|
|
32
|
-
'{{a}}',
|
|
33
|
-
'q',
|
|
34
|
-
'{{b}}',
|
|
35
|
-
'r',
|
|
36
|
-
]);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('returns empty segment list when content is null and queue is empty', () => {
|
|
40
|
-
expect(splitContentByOrderedVarTokens([], null)).toEqual([]);
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe('splitTemplateVarString', () => {
|
|
45
|
-
it('returns empty array for falsy string', () => {
|
|
46
|
-
expect(splitTemplateVarString('')).toEqual([]);
|
|
47
|
-
expect(splitTemplateVarString(null)).toEqual([]);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('splits mustache segments', () => {
|
|
51
|
-
const parts = splitTemplateVarString('Hi {{name}}!');
|
|
52
|
-
expect(parts.some((p) => p.includes('name'))).toBe(true);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('omits empty segments after filtering', () => {
|
|
56
|
-
expect(splitTemplateVarString('a{{x}}b')).toEqual(['a', '{{x}}', 'b']);
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
describe('getFallbackResolvedContent', () => {
|
|
61
|
-
it('replaces var segments from varMapData', () => {
|
|
62
|
-
const out = getFallbackResolvedContent('{{a}}', { '{{a}}_0': 'X' });
|
|
63
|
-
expect(out).toBe('X');
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('keeps DLT token string when slot empty', () => {
|
|
67
|
-
const out = getFallbackResolvedContent('{#v#}', {});
|
|
68
|
-
expect(out).toContain('#');
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('returns empty string for mustache slot when map has no value', () => {
|
|
72
|
-
const out = getFallbackResolvedContent('Hi {{missing}}', {});
|
|
73
|
-
expect(out).toBe('Hi ');
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('treats null as empty; explicit empty string is kept (cleared input)', () => {
|
|
77
|
-
expect(getFallbackResolvedContent('{{a}}', { '{{a}}_0': null })).toBe('');
|
|
78
|
-
expect(getFallbackResolvedContent('{{a}}', { '{{a}}_0': '' })).toBe('');
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('keeps DLT token in preview when slot map has empty string (no tag yet)', () => {
|
|
82
|
-
expect(getFallbackResolvedContent('{#v#}', { '{#v#}_0': '' })).toBe('{#v#}');
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('keeps DLT token in preview when slot map has null', () => {
|
|
86
|
-
expect(getFallbackResolvedContent('{#v#}', { '{#v#}_0': null })).toBe('{#v#}');
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('uses slot replacement when value is non-empty string', () => {
|
|
90
|
-
expect(getFallbackResolvedContent('A{{b}}C', { '{{b}}_1': 'ok' })).toBe('AokC');
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
describe('getFallbackResolvedContentForCardDisplay', () => {
|
|
95
|
-
it('shows raw tokens when map is empty or slots unset', () => {
|
|
96
|
-
expect(getFallbackResolvedContentForCardDisplay('Hi {{name}}', {})).toBe('Hi {{name}}');
|
|
97
|
-
expect(getFallbackResolvedContentForCardDisplay('{#var#}', {})).toBe('{#var#}');
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('shows raw token when slot key exists but value is empty (no labels)', () => {
|
|
101
|
-
expect(getFallbackResolvedContentForCardDisplay('{#var#}', { '{#var#}_0': '' })).toBe('{#var#}');
|
|
102
|
-
expect(getFallbackResolvedContentForCardDisplay('{{a}}', { '{{a}}_0': '' })).toBe('{{a}}');
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it('replaces when slot has non-empty value', () => {
|
|
106
|
-
expect(getFallbackResolvedContentForCardDisplay('Hi {{name}}', { '{{name}}_1': 'Pat' })).toBe('Hi Pat');
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
describe('isDltHashVarToken / isAnyTemplateVarToken', () => {
|
|
111
|
-
it('detects DLT hash token', () => {
|
|
112
|
-
expect(isDltHashVarToken('{#x#}')).toBe(true);
|
|
113
|
-
expect(isDltHashVarToken('plain')).toBe(false);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('isAnyTemplateVarToken combines mustache and DLT', () => {
|
|
117
|
-
expect(isAnyTemplateVarToken('{{a}}')).toBe(true);
|
|
118
|
-
expect(isAnyTemplateVarToken('{#x#}')).toBe(true);
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
describe('extractTemplateVariables', () => {
|
|
123
|
-
it('returns empty array for empty or missing template', () => {
|
|
124
|
-
expect(extractTemplateVariables('')).toEqual([]);
|
|
125
|
-
expect(extractTemplateVariables()).toEqual([]);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it('includes DLT {#var#} names when no custom capture regex', () => {
|
|
129
|
-
const vars = extractTemplateVariables('Hello {#promo#} and {{name}}');
|
|
130
|
-
expect(vars).toEqual(expect.arrayContaining(['promo', 'name']));
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('skips DLT scan when captureRegex is provided', () => {
|
|
134
|
-
const re = /\{\{([^}]+)\}\}/g;
|
|
135
|
-
expect(extractTemplateVariables('{#x#} {{y}}', re)).toEqual(['y']);
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it('dedupes duplicate variable names', () => {
|
|
139
|
-
expect(extractTemplateVariables('{{a}} {{a}}')).toEqual(['a']);
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it('uses default name var when DLT body capture is empty', () => {
|
|
143
|
-
const vars = extractTemplateVariables('{##}');
|
|
144
|
-
expect(vars).toContain('var');
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
describe('extractTemplateVariables (regex global)', () => {
|
|
149
|
-
it('extracts all vars when caller passes a non-global capture regex (avoids infinite exec loop)', () => {
|
|
150
|
-
const nonGlobal = /\{\{([^}]+)\}\}/;
|
|
151
|
-
expect(nonGlobal.global).toBe(false);
|
|
152
|
-
expect(extractTemplateVariables('{{a}} and {{b}}', nonGlobal)).toEqual(['a', 'b']);
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it('still works when capture regex already has the global flag', () => {
|
|
156
|
-
const globalRe = /\{\{([^}]+)\}\}/g;
|
|
157
|
-
expect(extractTemplateVariables('{{x}} {{y}}', globalRe)).toEqual(['x', 'y']);
|
|
158
|
-
});
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
describe('getFallbackResolvedContent — userVarMap (third param)', () => {
|
|
162
|
-
it('falls back to userVarMap for mustache slot absent from varMapData', () => {
|
|
163
|
-
expect(getFallbackResolvedContent('Hi {{name}}', {}, { name: 'Alice' })).toBe('Hi Alice');
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it('falls back to userVarMap for DLT slot absent from varMapData', () => {
|
|
167
|
-
expect(getFallbackResolvedContent('{#city#}', {}, { city: 'Mumbai' })).toBe('Mumbai');
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it('falls back to userVarMap when mustache slot is present but blank', () => {
|
|
171
|
-
expect(getFallbackResolvedContent('{{x}}', { '{{x}}_0': '' }, { x: 'val' })).toBe('val');
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it('falls back to userVarMap when DLT slot is present but blank', () => {
|
|
175
|
-
expect(getFallbackResolvedContent('{#x#}', { '{#x#}_0': '' }, { x: 'val' })).toBe('val');
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
it('slot wins over userVarMap when mustache slot is non-empty', () => {
|
|
179
|
-
expect(getFallbackResolvedContent('{{x}}', { '{{x}}_0': 'slot-val' }, { x: 'user-val' })).toBe('slot-val');
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it('slot wins over userVarMap when DLT slot is non-empty', () => {
|
|
183
|
-
expect(getFallbackResolvedContent('{#x#}', { '{#x#}_0': 'slot' }, { x: 'user' })).toBe('slot');
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it('resolves dot-path suffix key from userVarMap', () => {
|
|
187
|
-
expect(
|
|
188
|
-
getFallbackResolvedContent('{{FORMAT_1}}', {}, { 'expiry.FORMAT_1': 'Dec 2025' }),
|
|
189
|
-
).toBe('Dec 2025');
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
it('userVarMap null behaves identically to the two-argument form', () => {
|
|
193
|
-
expect(getFallbackResolvedContent('{{a}}', { '{{a}}_0': 'x' }, null)).toBe('x');
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
it('blank userVarMap value leaves mustache token as empty string', () => {
|
|
197
|
-
expect(getFallbackResolvedContent('{{a}}', {}, { a: '' })).toBe('');
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
it('blank userVarMap value leaves DLT token as raw token', () => {
|
|
201
|
-
expect(getFallbackResolvedContent('{#a#}', {}, { a: '' })).toBe('{#a#}');
|
|
202
|
-
});
|
|
203
|
-
});
|
|
204
|
-
});
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Helpers for Liquid `/preview` (updateEmailPreview) responses.
|
|
3
|
-
* The API may nest the payload under `data` or return fields at the top level.
|
|
4
|
-
* SMS responses often use `messageBody` instead of `resolvedBody`.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { getFallbackResolvedContent } from '../../utils/templateVarUtils';
|
|
8
|
-
import { RCS_SMS_FALLBACK_VAR_MAPPED_PROP } from './constants';
|
|
9
|
-
|
|
10
|
-
export function normalizePreviewApiPayload(raw) {
|
|
11
|
-
if (!raw || typeof raw !== 'object') return raw;
|
|
12
|
-
const next = { ...raw };
|
|
13
|
-
if (next.resolvedBody == null) {
|
|
14
|
-
const alt = next.messageBody ?? next.previewMessage ?? next.previewText;
|
|
15
|
-
if (alt != null) next.resolvedBody = alt;
|
|
16
|
-
}
|
|
17
|
-
return next;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Returns a normalized preview object suitable for Redux `previewData`, or null on error / empty.
|
|
22
|
-
*/
|
|
23
|
-
export function extractPreviewFromLiquidResponse(response) {
|
|
24
|
-
if (!response || response.error) return null;
|
|
25
|
-
if (response.errors && Array.isArray(response.errors) && response.errors.length > 0) return null;
|
|
26
|
-
|
|
27
|
-
let body;
|
|
28
|
-
if (response.data !== undefined && response.data !== null && typeof response.data === 'object') {
|
|
29
|
-
body = normalizePreviewApiPayload(response.data);
|
|
30
|
-
} else if (typeof response === 'object' && !Array.isArray(response)) {
|
|
31
|
-
body = normalizePreviewApiPayload(response);
|
|
32
|
-
} else {
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (!body) return null;
|
|
37
|
-
if (body.resolvedBody === undefined && body.messageBody === undefined) {
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
return body;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* RCS SMS fallback: merge template (`templateContent` / `content`) with VarSegment
|
|
45
|
-
* `rcsSmsFallbackVarMapped` before Liquid /preview, tag extraction, or createMessageMeta.
|
|
46
|
-
* Raw template alone is stale when the user edits slot values.
|
|
47
|
-
*/
|
|
48
|
-
export function getSmsFallbackTextForTagExtraction(smsFallbackContext) {
|
|
49
|
-
const rawTemplateBody =
|
|
50
|
-
smsFallbackContext?.templateContent ?? smsFallbackContext?.content ?? '';
|
|
51
|
-
if (!rawTemplateBody) return '';
|
|
52
|
-
const rcsSmsFallbackVarMapped = smsFallbackContext?.[RCS_SMS_FALLBACK_VAR_MAPPED_PROP];
|
|
53
|
-
const hasRcsSmsFallbackVarMappedEntries =
|
|
54
|
-
Object.keys(rcsSmsFallbackVarMapped ?? {}).length > 0;
|
|
55
|
-
if (hasRcsSmsFallbackVarMappedEntries) {
|
|
56
|
-
return getFallbackResolvedContent(rawTemplateBody, rcsSmsFallbackVarMapped ?? {});
|
|
57
|
-
}
|
|
58
|
-
return rawTemplateBody;
|
|
59
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
normalizePreviewApiPayload,
|
|
3
|
-
extractPreviewFromLiquidResponse,
|
|
4
|
-
getSmsFallbackTextForTagExtraction,
|
|
5
|
-
} from '../previewApiUtils';
|
|
6
|
-
import { RCS_SMS_FALLBACK_VAR_MAPPED_PROP } from '../constants';
|
|
7
|
-
|
|
8
|
-
describe('previewApiUtils', () => {
|
|
9
|
-
describe('normalizePreviewApiPayload', () => {
|
|
10
|
-
it('maps messageBody to resolvedBody when resolvedBody is missing', () => {
|
|
11
|
-
expect(normalizePreviewApiPayload({ messageBody: 'Hello' }).resolvedBody).toBe('Hello');
|
|
12
|
-
});
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
describe('extractPreviewFromLiquidResponse', () => {
|
|
16
|
-
it('accepts nested data shape', () => {
|
|
17
|
-
const r = { data: { resolvedBody: 'ok' } };
|
|
18
|
-
expect(extractPreviewFromLiquidResponse(r)).toEqual({ resolvedBody: 'ok' });
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('accepts top-level preview (typical SMS)', () => {
|
|
22
|
-
const r = { messageBody: 'sms text' };
|
|
23
|
-
expect(extractPreviewFromLiquidResponse(r)).toMatchObject({
|
|
24
|
-
messageBody: 'sms text',
|
|
25
|
-
resolvedBody: 'sms text',
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('returns null when errors array is non-empty', () => {
|
|
30
|
-
expect(extractPreviewFromLiquidResponse({ errors: [{ code: 1 }] })).toBeNull();
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
describe('getSmsFallbackTextForTagExtraction', () => {
|
|
35
|
-
it('returns empty string when context is missing or has no template body', () => {
|
|
36
|
-
expect(getSmsFallbackTextForTagExtraction(null)).toBe('');
|
|
37
|
-
expect(getSmsFallbackTextForTagExtraction({})).toBe('');
|
|
38
|
-
expect(getSmsFallbackTextForTagExtraction({ templateContent: '', content: '' })).toBe('');
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('returns raw template when rcsSmsFallbackVarMapped is absent or empty', () => {
|
|
42
|
-
const raw = '{{optout}} {{fullname}} test SMS';
|
|
43
|
-
expect(getSmsFallbackTextForTagExtraction({ templateContent: raw })).toBe(raw);
|
|
44
|
-
expect(getSmsFallbackTextForTagExtraction({
|
|
45
|
-
content: raw,
|
|
46
|
-
[RCS_SMS_FALLBACK_VAR_MAPPED_PROP]: {},
|
|
47
|
-
})).toBe(raw);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('prefers templateContent over content when both are set', () => {
|
|
51
|
-
expect(getSmsFallbackTextForTagExtraction({
|
|
52
|
-
templateContent: 'A',
|
|
53
|
-
content: 'B',
|
|
54
|
-
})).toBe('A');
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('applies VarSegment slot map so preview / meta payloads are not stale vs raw template', () => {
|
|
58
|
-
const rawTemplateWithSlots = '{{optout}} tail';
|
|
59
|
-
const rcsSmsFallbackVarMappedSlots = { '{{optout}}_0': 'STOP' };
|
|
60
|
-
const resolvedFallbackText = getSmsFallbackTextForTagExtraction({
|
|
61
|
-
templateContent: rawTemplateWithSlots,
|
|
62
|
-
[RCS_SMS_FALLBACK_VAR_MAPPED_PROP]: rcsSmsFallbackVarMappedSlots,
|
|
63
|
-
});
|
|
64
|
-
expect(resolvedFallbackText).toBe('STOP tail');
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
});
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
|
-
import CreativesContainer from '../../v2Containers/CreativesContainer';
|
|
4
|
-
import CapPageSpinner from '../CapPageSpinner';
|
|
5
|
-
import {
|
|
6
|
-
EMBEDDED_SMS_CREATIVES_LOCATION,
|
|
7
|
-
SMS_FALLBACK_CHANNEL_KEY,
|
|
8
|
-
SMS_FALLBACK_CREATIVE_EDITOR,
|
|
9
|
-
SMS_FALLBACK_ENABLE_NEW_CHANNELS,
|
|
10
|
-
} from './constants';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Reuse the exact embedded CreativesContainer SMS flow (same as normal SMS create).
|
|
14
|
-
* Avoid overriding Templates with local config so "Create new" follows built-in createTemplate path.
|
|
15
|
-
*/
|
|
16
|
-
export function SmsFallbackLocalSelector({
|
|
17
|
-
hidden,
|
|
18
|
-
fetchDetailsLoading,
|
|
19
|
-
templateList,
|
|
20
|
-
channelsToHide,
|
|
21
|
-
smsRegister,
|
|
22
|
-
onCloseCreatives,
|
|
23
|
-
onSelectTemplate,
|
|
24
|
-
filterContent,
|
|
25
|
-
location,
|
|
26
|
-
/** Required when user completes embedded SMS create/edit — `CreativesContainer` calls this on save (see `processCentralCommsMetaId`). */
|
|
27
|
-
getCreativesData,
|
|
28
|
-
}) {
|
|
29
|
-
const rootClassName = [
|
|
30
|
-
'sms-fallback-selector',
|
|
31
|
-
hidden ? 'sms-fallback-selector--visually-hidden' : '',
|
|
32
|
-
]
|
|
33
|
-
.filter(Boolean)
|
|
34
|
-
.join(' ');
|
|
35
|
-
|
|
36
|
-
return (
|
|
37
|
-
<div
|
|
38
|
-
className={rootClassName}
|
|
39
|
-
aria-hidden={hidden}
|
|
40
|
-
inert={hidden ? '' : undefined}
|
|
41
|
-
>
|
|
42
|
-
{fetchDetailsLoading && (
|
|
43
|
-
<div className="sms-fallback-selector__loading" aria-busy="true" aria-live="polite">
|
|
44
|
-
<CapPageSpinner spinning />
|
|
45
|
-
</div>
|
|
46
|
-
)}
|
|
47
|
-
<CreativesContainer
|
|
48
|
-
creativesMode="create"
|
|
49
|
-
location={location || EMBEDDED_SMS_CREATIVES_LOCATION}
|
|
50
|
-
templateData={null}
|
|
51
|
-
handleCloseCreatives={onCloseCreatives}
|
|
52
|
-
isFullMode={false}
|
|
53
|
-
smsRegister={smsRegister}
|
|
54
|
-
editor={SMS_FALLBACK_CREATIVE_EDITOR}
|
|
55
|
-
enableNewChannels={SMS_FALLBACK_ENABLE_NEW_CHANNELS}
|
|
56
|
-
channel={SMS_FALLBACK_CHANNEL_KEY}
|
|
57
|
-
channelsToHide={channelsToHide}
|
|
58
|
-
selectedBadges={[]}
|
|
59
|
-
localTemplatesConfig={{
|
|
60
|
-
useLocalTemplates: true,
|
|
61
|
-
localTemplates: templateList.templates,
|
|
62
|
-
localTemplatesLoading: templateList.loading,
|
|
63
|
-
localTemplatesFilterContent: filterContent,
|
|
64
|
-
localTemplatesOnPageChange: templateList.loadMore,
|
|
65
|
-
localTemplatesUseSkeleton: true,
|
|
66
|
-
}}
|
|
67
|
-
onSelectTemplate={onSelectTemplate}
|
|
68
|
-
getCreativesData={getCreativesData}
|
|
69
|
-
/>
|
|
70
|
-
</div>
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
SmsFallbackLocalSelector.propTypes = {
|
|
75
|
-
hidden: PropTypes.bool,
|
|
76
|
-
fetchDetailsLoading: PropTypes.bool,
|
|
77
|
-
templateList: PropTypes.shape({
|
|
78
|
-
templates: PropTypes.array,
|
|
79
|
-
loading: PropTypes.bool,
|
|
80
|
-
loadMore: PropTypes.func,
|
|
81
|
-
}).isRequired,
|
|
82
|
-
channelsToHide: PropTypes.arrayOf(PropTypes.string),
|
|
83
|
-
smsRegister: PropTypes.any,
|
|
84
|
-
onCloseCreatives: PropTypes.func.isRequired,
|
|
85
|
-
onSelectTemplate: PropTypes.func.isRequired,
|
|
86
|
-
filterContent: PropTypes.node,
|
|
87
|
-
location: PropTypes.object,
|
|
88
|
-
getCreativesData: PropTypes.func.isRequired,
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
export default SmsFallbackLocalSelector;
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
WHATSAPP,
|
|
3
|
-
RCS,
|
|
4
|
-
ZALO,
|
|
5
|
-
WEBPUSH,
|
|
6
|
-
} from '../../v2Containers/CreativesContainer/constants';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* View modes for the SMS fallback slidebox (template list, create, edit).
|
|
10
|
-
* Used by SmsFallback and any channel that reuses it (RCS, etc.).
|
|
11
|
-
*/
|
|
12
|
-
export const SMS_FALLBACK_VIEW = {
|
|
13
|
-
SELECTING: 'selecting',
|
|
14
|
-
CREATING: 'creating',
|
|
15
|
-
EDITING: 'editing',
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Channel keys to hide in TemplatesV2 so only SMS tab is shown.
|
|
20
|
-
* Uses normalized keys matching TemplatesV2 pane.key normalization (lowercase).
|
|
21
|
-
* Parent can override via channelsToHide prop.
|
|
22
|
-
*/
|
|
23
|
-
export const CHANNELS_TO_HIDE_FOR_SMS_ONLY = [
|
|
24
|
-
'email',
|
|
25
|
-
'mobilepush',
|
|
26
|
-
'webpush',
|
|
27
|
-
'viber',
|
|
28
|
-
'whatsapp',
|
|
29
|
-
'zalo',
|
|
30
|
-
'facebook',
|
|
31
|
-
'rcs',
|
|
32
|
-
'inapp',
|
|
33
|
-
'line',
|
|
34
|
-
'wechat',
|
|
35
|
-
'call_task',
|
|
36
|
-
'ftp',
|
|
37
|
-
'assets',
|
|
38
|
-
];
|
|
39
|
-
|
|
40
|
-
/** DLT category filter values — aligned with Templates `SMS_FILTERS` / `filterSMSTemplates`. */
|
|
41
|
-
export const SMS_CATEGORY_FILTERS = {
|
|
42
|
-
ALL: 'all',
|
|
43
|
-
PROMOTIONAL: 'promo',
|
|
44
|
-
SERVICE_EXPLICIT: 'explicit',
|
|
45
|
-
SERVICE_IMPLICIT: 'implicit',
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
/** `location` for embedded SMS creatives picker (CreativesContainer / TemplatesV2). */
|
|
49
|
-
export const EMBEDDED_SMS_CREATIVES_LOCATION = {
|
|
50
|
-
pathname: '/sms/create',
|
|
51
|
-
query: { type: 'embedded', module: 'library' },
|
|
52
|
-
search: '',
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
/** `location` for embedded SMS TRAI edit inside slidebox. */
|
|
56
|
-
export const EMBEDDED_SMS_CREATIVES_EDIT_LOCATION = {
|
|
57
|
-
pathname: '/sms/edit',
|
|
58
|
-
query: { type: 'embedded', module: 'library' },
|
|
59
|
-
search: '',
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
/** API `channel` param for `getTemplateDetails` when loading an SMS template by id. */
|
|
63
|
-
export const SMS_TEMPLATE_DETAILS_API_CHANNEL = 'Sms';
|
|
64
|
-
|
|
65
|
-
export const SMS_FALLBACK_CREATIVE_EDITOR = 'BEE';
|
|
66
|
-
|
|
67
|
-
export const SMS_FALLBACK_CHANNEL_KEY = 'sms';
|
|
68
|
-
|
|
69
|
-
/** Route shape passed to SmsWrapper / SmsTraiEdit for embedded SMS flows. */
|
|
70
|
-
export const SMS_FALLBACK_ROUTE = { name: SMS_FALLBACK_CHANNEL_KEY };
|
|
71
|
-
|
|
72
|
-
/** Channels enabled in the SMS-only embedded picker (hide others via `channelsToHide`). */
|
|
73
|
-
export const SMS_FALLBACK_ENABLE_NEW_CHANNELS = [WHATSAPP, RCS, ZALO, WEBPUSH];
|