@capillarytech/creatives-library 8.0.329 → 8.0.330
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 -14
- package/package.json +1 -1
- package/services/api.js +0 -17
- package/services/tests/api.test.js +0 -85
- package/utils/commonUtils.js +0 -10
- package/utils/tests/commonUtil.test.js +0 -169
- package/v2Components/CapTagList/index.js +0 -10
- package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +49 -70
- package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +2 -8
- package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +21 -207
- 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 +53 -87
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +1 -20
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +4 -133
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +34 -145
- package/v2Components/CommonTestAndPreview/actions.js +0 -10
- package/v2Components/CommonTestAndPreview/constants.js +1 -53
- package/v2Components/CommonTestAndPreview/index.js +168 -1006
- package/v2Components/CommonTestAndPreview/messages.js +3 -147
- package/v2Components/CommonTestAndPreview/reducer.js +0 -10
- package/v2Components/CommonTestAndPreview/sagas.js +6 -15
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +286 -328
- 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/SendTestMessage.test.js +24 -65
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +1 -199
- package/v2Components/CommonTestAndPreview/tests/constants.test.js +1 -31
- package/v2Components/CommonTestAndPreview/tests/index.test.js +4 -168
- package/v2Components/CommonTestAndPreview/tests/reducer.test.js +0 -71
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +2 -2
- package/v2Components/CommonTestAndPreview/tests/selectors.test.js +0 -17
- package/v2Components/FormBuilder/index.js +1 -7
- package/v2Components/TestAndPreviewSlidebox/index.js +1 -8
- 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 +93 -286
- 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 +10 -20
- package/v2Containers/CreativesContainer/tests/index.test.js +9 -71
- package/v2Containers/Rcs/constants.js +1 -34
- package/v2Containers/Rcs/index.js +884 -999
- package/v2Containers/Rcs/index.scss +6 -85
- package/v2Containers/Rcs/messages.js +1 -10
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +2453 -41456
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +5 -0
- package/v2Containers/Rcs/tests/index.test.js +38 -41
- package/v2Containers/Rcs/tests/mockData.js +0 -38
- package/v2Containers/Rcs/tests/utils.test.js +1 -379
- package/v2Containers/Rcs/utils.js +10 -358
- package/v2Containers/Sms/Create/index.js +38 -100
- package/v2Containers/SmsTrai/Create/index.js +4 -9
- package/v2Containers/SmsTrai/Edit/constants.js +0 -2
- package/v2Containers/SmsTrai/Edit/index.js +128 -609
- package/v2Containers/SmsTrai/Edit/messages.js +4 -9
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +2600 -4586
- package/v2Containers/SmsWrapper/index.js +8 -37
- package/v2Containers/TagList/index.js +0 -6
- package/v2Containers/Templates/_templates.scss +2 -63
- package/v2Containers/Templates/actions.js +0 -11
- package/v2Containers/Templates/constants.js +0 -2
- package/v2Containers/Templates/index.js +40 -90
- package/v2Containers/Templates/sagas.js +12 -57
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1079 -1043
- package/v2Containers/Templates/tests/sagas.test.js +123 -193
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +1 -72
- package/v2Containers/TemplatesV2/index.js +23 -86
- package/v2Containers/Whatsapp/index.js +20 -3
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +4872 -5790
- package/utils/templateVarUtils.js +0 -172
- package/utils/tests/templateVarUtils.test.js +0 -160
- package/v2Components/CommonTestAndPreview/AddTestCustomer.js +0 -42
- package/v2Components/CommonTestAndPreview/CustomerCreationModal.js +0 -155
- package/v2Components/CommonTestAndPreview/ExistingCustomerModal.js +0 -93
- package/v2Components/CommonTestAndPreview/previewApiUtils.js +0 -59
- package/v2Components/CommonTestAndPreview/tests/AddTestCustomer.test.js +0 -66
- package/v2Components/CommonTestAndPreview/tests/CommonTestAndPreview.addTestCustomer.test.js +0 -648
- package/v2Components/CommonTestAndPreview/tests/CustomerCreationModal.test.js +0 -174
- package/v2Components/CommonTestAndPreview/tests/ExistingCustomerModal.test.js +0 -114
- package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +0 -67
- package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +0 -87
- package/v2Components/SmsFallback/constants.js +0 -73
- package/v2Components/SmsFallback/index.js +0 -955
- package/v2Components/SmsFallback/index.scss +0 -265
- package/v2Components/SmsFallback/messages.js +0 -78
- package/v2Components/SmsFallback/smsFallbackUtils.js +0 -107
- 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 -197
- package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +0 -261
- package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +0 -422
- package/v2Components/SmsFallback/useLocalTemplateList.js +0 -92
- 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 -67
- 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 -205
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -251
- 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,27 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import {CapIcon, CapImage, CapLabel, CapDivider } from '@capillarytech/cap-ui-library';
|
|
3
|
-
import {
|
|
4
|
-
RCS,
|
|
5
|
-
RCS_MEDIA_TYPES,
|
|
6
|
-
RCS_NUMERIC_VAR_NAME_REGEX,
|
|
7
|
-
RCS_REGEX_META_CHARS_PATTERN,
|
|
8
|
-
RCS_STRIP_MUSTACHE_DELIMITERS_REGEX,
|
|
9
|
-
} from './constants';
|
|
3
|
+
import { RCS } from './constants';
|
|
10
4
|
import './index.scss';
|
|
11
5
|
// import { formatMessage } from '../../../utils/intl';
|
|
12
6
|
import messages from './messages';
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
RCS_BUTTON_TYPES,
|
|
16
|
-
RCS_STATUSES,
|
|
17
|
-
rcsVarRegex,
|
|
18
|
-
rcsVarTestRegex,
|
|
19
|
-
} from './constants';
|
|
20
|
-
import {
|
|
21
|
-
splitTemplateVarString,
|
|
22
|
-
COMBINED_SMS_TEMPLATE_VAR_REGEX,
|
|
23
|
-
isAnyTemplateVarToken,
|
|
24
|
-
} from '../../utils/templateVarUtils';
|
|
7
|
+
import { STATUS_OPTIONS, RCS_BUTTON_TYPES, RCS_STATUSES, RCS_MEDIA_TYPES } from './constants';
|
|
8
|
+
|
|
25
9
|
|
|
26
10
|
export const getRcsStatusType = (status) => {
|
|
27
11
|
switch (status) {
|
|
@@ -49,334 +33,6 @@ export const getTemplateStatusType = (templateStatus) => {
|
|
|
49
33
|
}
|
|
50
34
|
};
|
|
51
35
|
|
|
52
|
-
/**
|
|
53
|
-
* Global RegExp matching `{{numericVarName}}` in RCS template strings.
|
|
54
|
-
* `numericVarName` is escaped for regex metacharacters.
|
|
55
|
-
*/
|
|
56
|
-
export function buildRcsNumericMustachePlaceholderRegex(numericVarName) {
|
|
57
|
-
const escaped = String(numericVarName).replace(RCS_REGEX_META_CHARS_PATTERN, '\\$&');
|
|
58
|
-
return new RegExp(`\\{\\{${escaped}\\}\\}`, 'g');
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function normalizeCardVarMapped(rawCardVarMapped, orderedTagNames) {
|
|
62
|
-
if (!rawCardVarMapped || typeof rawCardVarMapped !== 'object') return {};
|
|
63
|
-
const normalizedMap = {};
|
|
64
|
-
const templateVarNamesInOrder = Array.isArray(orderedTagNames) ? orderedTagNames : null;
|
|
65
|
-
const hasOrderedSlots =
|
|
66
|
-
Boolean(templateVarNamesInOrder?.length);
|
|
67
|
-
Object.entries(rawCardVarMapped).forEach(([entryKey, entryValue]) => {
|
|
68
|
-
const trimmedValue = entryValue == null ? '' : String(entryValue).trim();
|
|
69
|
-
const entryKeyIsNumericSlot = RCS_NUMERIC_VAR_NAME_REGEX.test(String(entryKey));
|
|
70
|
-
const mustacheInnerMatch = trimmedValue.match(/^\{\{([^}]+)\}\}$/);
|
|
71
|
-
const innerFromMustache =
|
|
72
|
-
mustacheInnerMatch?.[1] != null ? String(mustacheInnerMatch[1]).trim() : null;
|
|
73
|
-
|
|
74
|
-
if (innerFromMustache !== null && entryKeyIsNumericSlot) {
|
|
75
|
-
const slotIndexZeroBased = parseInt(String(entryKey), 10) - 1;
|
|
76
|
-
const expectedVarForSlot =
|
|
77
|
-
hasOrderedSlots
|
|
78
|
-
&& slotIndexZeroBased >= 0
|
|
79
|
-
&& slotIndexZeroBased < templateVarNamesInOrder.length
|
|
80
|
-
? templateVarNamesInOrder[slotIndexZeroBased]
|
|
81
|
-
: null;
|
|
82
|
-
const innerMatchesSlotToken =
|
|
83
|
-
expectedVarForSlot != null && innerFromMustache === expectedVarForSlot;
|
|
84
|
-
const legacyUnorderedPlaceholder = !hasOrderedSlots;
|
|
85
|
-
/* Library: slot "1" + {{user_id_b64}} when token is user_id_b64 → empty semantic. With ordered
|
|
86
|
-
* slots, only clear when inner matches that slot's template token; else keep (e.g. {{1}}+{{FirstName}}). */
|
|
87
|
-
const clearNumericSlotMustacheAsUnfilled =
|
|
88
|
-
!RCS_NUMERIC_VAR_NAME_REGEX.test(innerFromMustache)
|
|
89
|
-
&& (legacyUnorderedPlaceholder || innerMatchesSlotToken);
|
|
90
|
-
if (clearNumericSlotMustacheAsUnfilled) {
|
|
91
|
-
const outputKey = innerFromMustache;
|
|
92
|
-
const existingValue = normalizedMap[outputKey];
|
|
93
|
-
if (existingValue != null && String(existingValue).trim() !== '') {
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
normalizedMap[outputKey] = '';
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
if (RCS_NUMERIC_VAR_NAME_REGEX.test(innerFromMustache)) {
|
|
100
|
-
const outputKey = innerFromMustache;
|
|
101
|
-
const existingValue = normalizedMap[outputKey];
|
|
102
|
-
if (existingValue != null && String(existingValue).trim() !== '') {
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
normalizedMap[outputKey] = '';
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (innerFromMustache !== null && !entryKeyIsNumericSlot) {
|
|
111
|
-
if (innerFromMustache === String(entryKey)) {
|
|
112
|
-
const existingValue = normalizedMap[entryKey];
|
|
113
|
-
if (existingValue != null && String(existingValue).trim() !== '') {
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
normalizedMap[entryKey] = '';
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (entryKeyIsNumericSlot && templateVarNamesInOrder?.length) {
|
|
122
|
-
const slotIndexZeroBased = parseInt(String(entryKey), 10) - 1;
|
|
123
|
-
if (slotIndexZeroBased >= 0 && slotIndexZeroBased < templateVarNamesInOrder.length) {
|
|
124
|
-
normalizedMap[templateVarNamesInOrder[slotIndexZeroBased]] = trimmedValue;
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
normalizedMap[entryKey] = trimmedValue;
|
|
129
|
-
});
|
|
130
|
-
return normalizedMap;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Rebuild `cardVarMapped` so keys match the current title/description tokens (title tokens first,
|
|
135
|
-
* then description), in order. Values are taken from the matching key, else from legacy slot
|
|
136
|
-
* `1`, `2`, … by index. If there are no `{{...}}` tokens, returns a shallow clone of `raw`.
|
|
137
|
-
*/
|
|
138
|
-
export function coalesceCardVarMappedToTemplate(
|
|
139
|
-
sourceCardVarMap,
|
|
140
|
-
templateTitle,
|
|
141
|
-
templateDesc,
|
|
142
|
-
rcsVarRegex,
|
|
143
|
-
) {
|
|
144
|
-
const getVarNameFromToken = (token = '') => token.replace(RCS_STRIP_MUSTACHE_DELIMITERS_REGEX, '');
|
|
145
|
-
const templateVarTokens = [
|
|
146
|
-
...(templateTitle?.match(rcsVarRegex) ?? []),
|
|
147
|
-
...(templateDesc?.match(rcsVarRegex) ?? []),
|
|
148
|
-
];
|
|
149
|
-
const lookupSourceMap =
|
|
150
|
-
sourceCardVarMap != null && typeof sourceCardVarMap === 'object' ? sourceCardVarMap : {};
|
|
151
|
-
if (!templateVarTokens.length) {
|
|
152
|
-
return { ...lookupSourceMap };
|
|
153
|
-
}
|
|
154
|
-
const coalescedMap = { ...lookupSourceMap };
|
|
155
|
-
const seenSemanticVarNames = new Set();
|
|
156
|
-
templateVarTokens.forEach((token, slotIndexZeroBased) => {
|
|
157
|
-
const semanticVarName = getVarNameFromToken(token);
|
|
158
|
-
if (!semanticVarName) return;
|
|
159
|
-
const numericSlotKey = String(slotIndexZeroBased + 1);
|
|
160
|
-
let valueFromSource = lookupSourceMap[numericSlotKey];
|
|
161
|
-
if (valueFromSource === undefined || valueFromSource === null) {
|
|
162
|
-
valueFromSource = lookupSourceMap[semanticVarName];
|
|
163
|
-
}
|
|
164
|
-
if (valueFromSource === undefined || valueFromSource === null) {
|
|
165
|
-
valueFromSource = lookupSourceMap[String(slotIndexZeroBased + 1)];
|
|
166
|
-
}
|
|
167
|
-
if (valueFromSource === undefined || valueFromSource === null) {
|
|
168
|
-
valueFromSource = lookupSourceMap[slotIndexZeroBased + 1];
|
|
169
|
-
}
|
|
170
|
-
const trimmedSlotValue = valueFromSource == null ? '' : String(valueFromSource).trim();
|
|
171
|
-
coalescedMap[numericSlotKey] = trimmedSlotValue;
|
|
172
|
-
if (!seenSemanticVarNames.has(semanticVarName)) {
|
|
173
|
-
seenSemanticVarNames.add(semanticVarName);
|
|
174
|
-
coalescedMap[semanticVarName] = trimmedSlotValue;
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
return coalescedMap;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Resolve the personalization value for a variable slot — aligned with createPayload:
|
|
182
|
-
* per-slot numeric keys `1`, `2`, … win over legacy semantic keys when both exist (duplicate
|
|
183
|
-
* `{{name}}` in title+desc). If semantic is explicitly cleared to '', that still wins over a
|
|
184
|
-
* stale numeric value (see tests) — except in embedded library / journey mode (`isLibraryMode`).
|
|
185
|
-
*
|
|
186
|
-
* In library mode, campaign payloads often set semantic keys to '' while numeric slot `1`,`2`,…
|
|
187
|
-
* still holds the value selected in the library; prefer that so VarSegment prepopulates.
|
|
188
|
-
*
|
|
189
|
-
* When a numeric slot is present but only whitespace / empty (common after hydration), do not
|
|
190
|
-
* treat it as authoritative — fall through to the semantic key so preview and payload match the
|
|
191
|
-
* tag the user selected (e.g. `1: ''` but `promotion_points: '{{newTag}}'`).
|
|
192
|
-
*/
|
|
193
|
-
export function resolveCardVarMappedSlotValue(
|
|
194
|
-
cardVarMapped,
|
|
195
|
-
varName,
|
|
196
|
-
globalSlotIndexZeroBased,
|
|
197
|
-
isLibraryMode = false,
|
|
198
|
-
) {
|
|
199
|
-
const varMap = cardVarMapped ?? {};
|
|
200
|
-
const slotKey = String(globalSlotIndexZeroBased + 1);
|
|
201
|
-
const semanticEmpty =
|
|
202
|
-
Object.prototype.hasOwnProperty.call(varMap, varName)
|
|
203
|
-
&& String(varMap[varName] ?? '') === '';
|
|
204
|
-
const slotNonEmpty =
|
|
205
|
-
Object.prototype.hasOwnProperty.call(varMap, slotKey)
|
|
206
|
-
&& String(varMap[slotKey] ?? '').trim() !== '';
|
|
207
|
-
|
|
208
|
-
if (semanticEmpty && !(isLibraryMode && slotNonEmpty)) {
|
|
209
|
-
return '';
|
|
210
|
-
}
|
|
211
|
-
let numericSlotValue = '';
|
|
212
|
-
if (Object.prototype.hasOwnProperty.call(varMap, slotKey)) {
|
|
213
|
-
numericSlotValue = String(varMap[slotKey] ?? '');
|
|
214
|
-
} else if (Object.prototype.hasOwnProperty.call(varMap, globalSlotIndexZeroBased + 1)) {
|
|
215
|
-
numericSlotValue = String(varMap[globalSlotIndexZeroBased + 1] ?? '');
|
|
216
|
-
}
|
|
217
|
-
if (numericSlotValue.trim() !== '') {
|
|
218
|
-
return numericSlotValue;
|
|
219
|
-
}
|
|
220
|
-
if (Object.prototype.hasOwnProperty.call(varMap, varName)) {
|
|
221
|
-
return String(varMap[varName] ?? '');
|
|
222
|
-
}
|
|
223
|
-
return '';
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/** Text-only RCS card: editor shows a single “Text message” field (description); title row is hidden. */
|
|
227
|
-
export function isRcsTextOnlyCardMediaType(mediaType) {
|
|
228
|
-
return (
|
|
229
|
-
mediaType === RCS_MEDIA_TYPES.NONE
|
|
230
|
-
|| String(mediaType || '').toUpperCase() === 'TEXT'
|
|
231
|
-
);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Resolve RCS card title/description for TemplatePreview (e.g. campaign slidebox preview).
|
|
236
|
-
* Mirrors `resolveTemplateWithMap` in the Rcs editor: title vars use global slots 0..n-1, then description.
|
|
237
|
-
* For text-only cards (`textOnlyCard`), ignore persisted `title` and resolve description from slot 0 — matches
|
|
238
|
-
* the editor where only the message body is shown.
|
|
239
|
-
*/
|
|
240
|
-
export function resolveRcsCardPreviewStrings(
|
|
241
|
-
title,
|
|
242
|
-
description,
|
|
243
|
-
cardVarMapped,
|
|
244
|
-
isLibraryMode = false,
|
|
245
|
-
textOnlyCard = false,
|
|
246
|
-
) {
|
|
247
|
-
const splitTemplateVarStringRcs = (str) => splitTemplateVarString(str, rcsVarRegex);
|
|
248
|
-
const getVarNameFromToken = (token = '') =>
|
|
249
|
-
token.replace(RCS_STRIP_MUSTACHE_DELIMITERS_REGEX, '');
|
|
250
|
-
|
|
251
|
-
const resolveTemplateWithMap = (str = '', slotOffset = 0) => {
|
|
252
|
-
if (!str) return '';
|
|
253
|
-
const arr = splitTemplateVarStringRcs(str);
|
|
254
|
-
let varOrdinal = 0;
|
|
255
|
-
return arr
|
|
256
|
-
.map((elem) => {
|
|
257
|
-
if (rcsVarTestRegex.test(elem)) {
|
|
258
|
-
const key = getVarNameFromToken(elem);
|
|
259
|
-
const globalSlot = slotOffset + varOrdinal;
|
|
260
|
-
varOrdinal += 1;
|
|
261
|
-
const v = resolveCardVarMappedSlotValue(
|
|
262
|
-
cardVarMapped,
|
|
263
|
-
key,
|
|
264
|
-
globalSlot,
|
|
265
|
-
isLibraryMode,
|
|
266
|
-
);
|
|
267
|
-
if (v == null || String(v).trim() === '') return elem;
|
|
268
|
-
return String(v);
|
|
269
|
-
}
|
|
270
|
-
return elem;
|
|
271
|
-
})
|
|
272
|
-
.join('');
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
const effectiveTitle = textOnlyCard ? '' : String(title || '');
|
|
276
|
-
const titleVarCount = textOnlyCard
|
|
277
|
-
? 0
|
|
278
|
-
: (effectiveTitle.match(rcsVarRegex) || []).length;
|
|
279
|
-
return {
|
|
280
|
-
rcsTitle: textOnlyCard ? '' : resolveTemplateWithMap(effectiveTitle, 0),
|
|
281
|
-
rcsDesc: resolveTemplateWithMap(String(description || ''), titleVarCount),
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Campaign consumer payload: replace each card's `title` / `description` with VarSegment-resolved
|
|
287
|
-
* tag strings (same rules as {@link resolveRcsCardPreviewStrings}). Root `rcsCardVarMapped` merges
|
|
288
|
-
* with per-card `cardVarMapped`; `cardVarMapped` on each card is left unchanged for round-trip.
|
|
289
|
-
*/
|
|
290
|
-
export function mapRcsCardContentForConsumerWithResolvedTags(
|
|
291
|
-
cardContentArray,
|
|
292
|
-
rootRcsCardVarMapped,
|
|
293
|
-
isFullMode,
|
|
294
|
-
) {
|
|
295
|
-
const rootRecord =
|
|
296
|
-
rootRcsCardVarMapped != null && typeof rootRcsCardVarMapped === 'object'
|
|
297
|
-
? rootRcsCardVarMapped
|
|
298
|
-
: {};
|
|
299
|
-
const list = Array.isArray(cardContentArray) ? cardContentArray : [];
|
|
300
|
-
const isLibraryMode = isFullMode !== true;
|
|
301
|
-
return list.map((card) => {
|
|
302
|
-
if (!card || typeof card !== 'object') return card;
|
|
303
|
-
const nested =
|
|
304
|
-
card.cardVarMapped != null && typeof card.cardVarMapped === 'object'
|
|
305
|
-
? card.cardVarMapped
|
|
306
|
-
: {};
|
|
307
|
-
const merged = { ...rootRecord, ...nested };
|
|
308
|
-
const textOnly = isRcsTextOnlyCardMediaType(card.mediaType);
|
|
309
|
-
const { rcsTitle, rcsDesc } = resolveRcsCardPreviewStrings(
|
|
310
|
-
card.title ?? '',
|
|
311
|
-
card.description ?? '',
|
|
312
|
-
merged,
|
|
313
|
-
isLibraryMode,
|
|
314
|
-
textOnly,
|
|
315
|
-
);
|
|
316
|
-
return {
|
|
317
|
-
...card,
|
|
318
|
-
title: rcsTitle,
|
|
319
|
-
description: rcsDesc,
|
|
320
|
-
};
|
|
321
|
-
});
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* Before save: strip only legacy numeric self-placeholders (`{{1}}`, `{{2}}`, …) mistakenly stored as
|
|
326
|
-
* slot values. Preserve semantic tokens like `{{FirstName}}` from TagList — those are valid mappings.
|
|
327
|
-
*/
|
|
328
|
-
export function sanitizeCardVarMappedValue(val) {
|
|
329
|
-
if (val == null) return '';
|
|
330
|
-
const trimmedDisplayString = String(val).trim();
|
|
331
|
-
if (/^\{\{\d+\}\}$/.test(trimmedDisplayString)) return '';
|
|
332
|
-
return String(val);
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* Same completion rule as SmsTraiEdit RCS fallback — used by `isDisableDone` from
|
|
337
|
-
* `smsFallbackData.rcsSmsFallbackVarMapped` + template string.
|
|
338
|
-
* Every variable token (DLT {#…#} or mustache {{…}}) must have a non-empty trimmed value in the map.
|
|
339
|
-
*
|
|
340
|
-
* Slot keys are usually `${token}_${segmentIndex}` (same as VarSegmentMessageEditor). Persisted / API
|
|
341
|
-
* payloads may use `${token}_${varOrdinal}` with a 1-based occurrence index (see SmsTraiEdit init).
|
|
342
|
-
* We try segment index first, then ordinal — so e.g. template `{#var#}` (segment index 0) still matches
|
|
343
|
-
* map `{#var#}_1`.
|
|
344
|
-
*
|
|
345
|
-
* @param {string} templateText
|
|
346
|
-
* @param {Record<string, string>} [varSlotValueMap={}]
|
|
347
|
-
* @returns {boolean}
|
|
348
|
-
*/
|
|
349
|
-
export function areAllRcsSmsFallbackVarSlotsFilled(templateText, varSlotValueMap = {}) {
|
|
350
|
-
if (!templateText || typeof templateText !== 'string') return true;
|
|
351
|
-
const segments = splitTemplateVarString(templateText, COMBINED_SMS_TEMPLATE_VAR_REGEX);
|
|
352
|
-
const hasVarToken = segments.some(
|
|
353
|
-
(segment) =>
|
|
354
|
-
typeof segment === 'string'
|
|
355
|
-
&& isAnyTemplateVarToken(segment),
|
|
356
|
-
);
|
|
357
|
-
if (!hasVarToken) return true;
|
|
358
|
-
let varOrdinal = 0;
|
|
359
|
-
return segments.every((segment, segmentIndex) => {
|
|
360
|
-
if (
|
|
361
|
-
typeof segment !== 'string'
|
|
362
|
-
|| !isAnyTemplateVarToken(segment)
|
|
363
|
-
) return true;
|
|
364
|
-
varOrdinal += 1;
|
|
365
|
-
const indexKey = `${segment}_${segmentIndex}`;
|
|
366
|
-
const ordinalKey = `${segment}_${varOrdinal}`;
|
|
367
|
-
let mappedSlotValue;
|
|
368
|
-
if (Object.prototype.hasOwnProperty.call(varSlotValueMap, indexKey)) {
|
|
369
|
-
mappedSlotValue = varSlotValueMap[indexKey];
|
|
370
|
-
} else if (Object.prototype.hasOwnProperty.call(varSlotValueMap, ordinalKey)) {
|
|
371
|
-
mappedSlotValue = varSlotValueMap[ordinalKey];
|
|
372
|
-
} else {
|
|
373
|
-
mappedSlotValue = undefined;
|
|
374
|
-
}
|
|
375
|
-
if (mappedSlotValue == null) return false;
|
|
376
|
-
return String(mappedSlotValue).trim() !== '';
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
|
|
380
36
|
export const getRCSContent = (template) => {
|
|
381
37
|
const renderRcsSuggestionsPreview = (rcsSuggestions) => {
|
|
382
38
|
const renderArray = [];
|
|
@@ -428,10 +84,8 @@ export const getRCSContent = (template) => {
|
|
|
428
84
|
media = {},
|
|
429
85
|
description,
|
|
430
86
|
title,
|
|
431
|
-
mediaType,
|
|
432
87
|
suggestions = [],
|
|
433
88
|
} = cardContent[0];
|
|
434
|
-
const isTextOnlyCard = isRcsTextOnlyCardMediaType(mediaType);
|
|
435
89
|
const mediaPreview = media?.thumbnailUrl ? media.thumbnailUrl : media.mediaUrl;
|
|
436
90
|
return (
|
|
437
91
|
<div className="cap-rcs-creatives">
|
|
@@ -441,15 +95,13 @@ export const getRCSContent = (template) => {
|
|
|
441
95
|
className="rcs-listing-image"
|
|
442
96
|
/>
|
|
443
97
|
)}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
</CapLabel>
|
|
452
|
-
)}
|
|
98
|
+
<CapLabel
|
|
99
|
+
type="label19"
|
|
100
|
+
className="rcs-listing-content title"
|
|
101
|
+
fontWeight="bold"
|
|
102
|
+
>
|
|
103
|
+
{title}
|
|
104
|
+
</CapLabel>
|
|
453
105
|
<CapLabel type="label19" className="rcs-listing-content desc">
|
|
454
106
|
{description}
|
|
455
107
|
</CapLabel>
|
|
@@ -33,10 +33,6 @@ import injectReducer from '../../../utils/injectReducer';
|
|
|
33
33
|
import v2SmsCreateReducer from './reducer';
|
|
34
34
|
import * as globalActions from '../../Cap/actions';
|
|
35
35
|
import TestAndPreviewSlidebox from '../../../v2Components/TestAndPreviewSlidebox';
|
|
36
|
-
import {
|
|
37
|
-
getSmsEmbeddedFooterValidity,
|
|
38
|
-
getSmsMessageFromFormData,
|
|
39
|
-
} from '../smsFormDataHelpers';
|
|
40
36
|
|
|
41
37
|
export class Create extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
|
42
38
|
constructor(props) {
|
|
@@ -57,11 +53,6 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
57
53
|
isTestAndPreviewMode: false,
|
|
58
54
|
pendingGetFormData: false,
|
|
59
55
|
};
|
|
60
|
-
// Tracks the last validity value reported to SmsFallback so componentDidUpdate
|
|
61
|
-
// does not dispatch on every render and create an infinite update loop.
|
|
62
|
-
// Intentionally undefined (not true) so the first render always reports the
|
|
63
|
-
// real validity rather than assuming the form starts invalid.
|
|
64
|
-
this._lastReportedSmsFooterInvalid = undefined;
|
|
65
56
|
this.saveFormData = this.saveFormData.bind(this);
|
|
66
57
|
this.onFormDataChange = this.onFormDataChange.bind(this);
|
|
67
58
|
this.onTemplateNameChange = this.onTemplateNameChange.bind(this);
|
|
@@ -168,9 +159,7 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
168
159
|
layout: 'SMS',
|
|
169
160
|
type: 'TAG',
|
|
170
161
|
context: this.props.location.query.type === 'embedded' ? this.props.location.query.module : 'default',
|
|
171
|
-
embedded: this.props.
|
|
172
|
-
? 'full'
|
|
173
|
-
: (this.props.location.query.type === 'embedded' ? this.props.location.query.type : 'full'),
|
|
162
|
+
embedded: this.props.location.query.type === 'embedded' ? this.props.location.query.type : 'full',
|
|
174
163
|
};
|
|
175
164
|
if (this.props.getDefaultTags) {
|
|
176
165
|
query.context = this.props.getDefaultTags;
|
|
@@ -183,22 +172,6 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
183
172
|
}
|
|
184
173
|
}
|
|
185
174
|
|
|
186
|
-
componentDidUpdate() {
|
|
187
|
-
if (!this.props.embeddedSmsFallback || typeof this.props.onEmbeddedSmsFooterValidity !== 'function') {
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
const validity = getSmsEmbeddedFooterValidity(this.state.formData, this.state.tabCount);
|
|
191
|
-
const isInvalid = !!validity.isTemplateNameEmpty || !!validity.isMessageEmpty;
|
|
192
|
-
// Only dispatch when the validity value changes. Dispatching unconditionally caused
|
|
193
|
-
// an infinite loop: componentDidUpdate → dispatch → SmsFallback re-render →
|
|
194
|
-
// SmsCreate re-render → componentDidUpdate → ... even when state was unchanged.
|
|
195
|
-
// The instance variable handles both reference-based and mutation-based FormBuilder
|
|
196
|
-
// updates: validity is recomputed from current formData content, not by reference.
|
|
197
|
-
if (this._lastReportedSmsFooterInvalid === isInvalid) return;
|
|
198
|
-
this._lastReportedSmsFooterInvalid = isInvalid;
|
|
199
|
-
this.props.onEmbeddedSmsFooterValidity(validity);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
175
|
componentWillUnmount() {
|
|
203
176
|
if (this.pendingGetFormDataTimeout) {
|
|
204
177
|
clearTimeout(this.pendingGetFormDataTimeout);
|
|
@@ -302,10 +275,6 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
302
275
|
}
|
|
303
276
|
const result = {};
|
|
304
277
|
result.base = baseData;
|
|
305
|
-
/* Root field used by FormBuilder; embedded getFormSubscriptionData reads value.base */
|
|
306
|
-
if (formData['template-name'] !== undefined) {
|
|
307
|
-
result.base['template-name'] = formData['template-name'];
|
|
308
|
-
}
|
|
309
278
|
if (this.state.isValid) {
|
|
310
279
|
const msgObj = charCount.updateCharCount(baseData['sms-editor']);
|
|
311
280
|
result.base.msg_count = msgObj.msgCount;
|
|
@@ -912,9 +881,7 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
912
881
|
layout: 'SMS',
|
|
913
882
|
type: 'TAG',
|
|
914
883
|
context: (data && data.toLowerCase() === 'all') ? 'default' : (data && data.toLowerCase()),
|
|
915
|
-
embedded: this.props.
|
|
916
|
-
? 'full'
|
|
917
|
-
: (this.props.location.query.type === 'embedded' ? this.props.location.query.type : 'full'),
|
|
884
|
+
embedded: this.props.location.query.type === 'embedded' ? this.props.location.query.type : 'full',
|
|
918
885
|
};
|
|
919
886
|
this.props.globalActions.fetchSchemaForEntity(query);
|
|
920
887
|
}
|
|
@@ -922,29 +889,11 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
922
889
|
removeStandAlone() {
|
|
923
890
|
const schema = _.cloneDeep(this.state.schema);
|
|
924
891
|
const childSections = _.get(schema, 'standalone.sections[0].childSections');
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
/*
|
|
931
|
-
* Creatives library drops the standalone template-name block because `SlideBoxHeader`
|
|
932
|
-
* shows the name. This is independent of the section count — guard it separately so
|
|
933
|
-
* it still runs even when childSections.length <= 2 (e.g. schema arrives pre-trimmed).
|
|
934
|
-
* RCS SMS fallback uses the same slidebox footer but keeps the name in the form.
|
|
935
|
-
*/
|
|
936
|
-
if (!this.props.embeddedSmsFallback) {
|
|
937
|
-
const fields = _.get(childSections, '[1].childSections[0].childSections');
|
|
938
|
-
if (fields && fields.length > 0) {
|
|
939
|
-
fields.splice(0, 1);
|
|
940
|
-
_.set(childSections, '[1].childSections[0].childSections', fields);
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
|
-
_.set(schema, 'standalone.sections[0].childSections', childSections);
|
|
944
|
-
}
|
|
945
|
-
// Always increment loadingStatus — isSmsLoading() requires >= 2 in library mode
|
|
946
|
-
// (isFullMode=false). The early return previously skipped this, leaving the
|
|
947
|
-
// spinner stuck forever when the schema had <= 2 childSections.
|
|
892
|
+
childSections.splice(2, 1);
|
|
893
|
+
const fields = _.get(childSections, '[1].childSections[0].childSections');//removing template name section
|
|
894
|
+
fields.splice(0, 1);
|
|
895
|
+
_.set(childSections, '[1].childSections[0].childSections', fields);
|
|
896
|
+
_.set(schema, 'standalone.sections[0].childSections', childSections);
|
|
948
897
|
this.setState({ schema, loadingStatus: this.state.loadingStatus + 1 });
|
|
949
898
|
}
|
|
950
899
|
|
|
@@ -989,8 +938,37 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
989
938
|
this.setState({startValidation: false});
|
|
990
939
|
}
|
|
991
940
|
|
|
992
|
-
getTemplateContent = () =>
|
|
993
|
-
|
|
941
|
+
getTemplateContent = () => {
|
|
942
|
+
// Get SMS content from formData
|
|
943
|
+
if (!this.state.formData || !Array.isArray(this.state.formData) || this.state.formData.length === 0) {
|
|
944
|
+
return '';
|
|
945
|
+
}
|
|
946
|
+
const currentTabData = this.state.formData[this.state.currentTab - 1];
|
|
947
|
+
if (!currentTabData) {
|
|
948
|
+
return '';
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
// PRIORITY 1: Check direct path first (most common for SMS)
|
|
952
|
+
// This handles: formData[0]['sms-editor']
|
|
953
|
+
if (currentTabData['sms-editor']) {
|
|
954
|
+
return currentTabData['sms-editor'];
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
// PRIORITY 2: Check activeTab structure (for versioned templates)
|
|
958
|
+
// This handles: formData[0][activeTab]['sms-editor']
|
|
959
|
+
const activeTab = currentTabData?.activeTab || 'base';
|
|
960
|
+
if (currentTabData[activeTab]?.['sms-editor']) {
|
|
961
|
+
return currentTabData[activeTab]['sms-editor'];
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
// PRIORITY 3: Check base explicitly (fallback)
|
|
965
|
+
// This handles: formData[0]['base']['sms-editor']
|
|
966
|
+
if (currentTabData['base']?.['sms-editor']) {
|
|
967
|
+
return currentTabData['base']['sms-editor'];
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
return '';
|
|
971
|
+
}
|
|
994
972
|
|
|
995
973
|
handleTestAndPreview = () => {
|
|
996
974
|
// If parent is managing state (props exist), call parent handler
|
|
@@ -1019,35 +997,6 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
1019
997
|
}
|
|
1020
998
|
|
|
1021
999
|
saveFormData() {
|
|
1022
|
-
/*
|
|
1023
|
-
* RCS SMS fallback slidebox (embeddedSmsFallback): parent passes isFullMode from RCS, but we must not
|
|
1024
|
-
* call createTemplate — that spins CapSpin on createTemplateInProgress and is not the embedded contract.
|
|
1025
|
-
* Same as library: hand off form payload via getFormSubscriptionData.
|
|
1026
|
-
*/
|
|
1027
|
-
if (this.props.embeddedSmsFallback && this.props.getFormSubscriptionData) {
|
|
1028
|
-
const { isTemplateNameEmpty, isMessageEmpty } = getSmsEmbeddedFooterValidity(
|
|
1029
|
-
this.state.formData,
|
|
1030
|
-
this.state.tabCount,
|
|
1031
|
-
);
|
|
1032
|
-
if (isTemplateNameEmpty || isMessageEmpty) {
|
|
1033
|
-
this.setState({ startValidation: true, pendingGetFormData: false });
|
|
1034
|
-
if (this.props.onValidationFail) {
|
|
1035
|
-
this.props.onValidationFail();
|
|
1036
|
-
}
|
|
1037
|
-
return;
|
|
1038
|
-
}
|
|
1039
|
-
const payload = this.getFormData();
|
|
1040
|
-
if (!payload.validity) {
|
|
1041
|
-
if (this.props.onValidationFail) {
|
|
1042
|
-
this.props.onValidationFail();
|
|
1043
|
-
}
|
|
1044
|
-
this.setState({ pendingGetFormData: false, startValidation: false });
|
|
1045
|
-
return;
|
|
1046
|
-
}
|
|
1047
|
-
this.props.getFormSubscriptionData(payload);
|
|
1048
|
-
this.setState({ pendingGetFormData: false, startValidation: false });
|
|
1049
|
-
return;
|
|
1050
|
-
}
|
|
1051
1000
|
// In library mode: FormBuilder calls onSubmit only after liquid validation succeeds.
|
|
1052
1001
|
// Submit to parent here so the slidebox can close with valid data.
|
|
1053
1002
|
if (!this.props.isFullMode) {
|
|
@@ -1147,9 +1096,6 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
1147
1096
|
onTestContentClicked={this.props.onTestContentClicked}
|
|
1148
1097
|
onPreviewContentClicked={this.props.onPreviewContentClicked}
|
|
1149
1098
|
eventContextTags={this.props?.eventContextTags}
|
|
1150
|
-
tagListGetPopupContainer={this.props.tagListGetPopupContainer}
|
|
1151
|
-
tagListPopoverOverlayStyle={this.props.tagListPopoverOverlayStyle}
|
|
1152
|
-
tagListPopoverOverlayClassName={this.props.tagListPopoverOverlayClassName}
|
|
1153
1099
|
/>
|
|
1154
1100
|
</CapColumn>
|
|
1155
1101
|
</CapRow>
|
|
@@ -1162,7 +1108,6 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
1162
1108
|
formData={this.state.formData}
|
|
1163
1109
|
content={this.getTemplateContent()}
|
|
1164
1110
|
currentChannel={SMS}
|
|
1165
|
-
smsRegister={this.props.smsRegister}
|
|
1166
1111
|
/>
|
|
1167
1112
|
</div>
|
|
1168
1113
|
);
|
|
@@ -1191,13 +1136,6 @@ Create.propTypes = {
|
|
|
1191
1136
|
handleTestAndPreview: PropTypes.func,
|
|
1192
1137
|
handleCloseTestAndPreview: PropTypes.func,
|
|
1193
1138
|
isTestAndPreviewMode: PropTypes.bool,
|
|
1194
|
-
smsRegister: PropTypes.any,
|
|
1195
|
-
forceFullTagContext: PropTypes.bool,
|
|
1196
|
-
embeddedSmsFallback: PropTypes.bool,
|
|
1197
|
-
onEmbeddedSmsFooterValidity: PropTypes.func,
|
|
1198
|
-
tagListGetPopupContainer: PropTypes.func,
|
|
1199
|
-
tagListPopoverOverlayStyle: PropTypes.object,
|
|
1200
|
-
tagListPopoverOverlayClassName: PropTypes.string,
|
|
1201
1139
|
};
|
|
1202
1140
|
|
|
1203
1141
|
const mapStateToProps = createStructuredSelector({
|
|
@@ -70,7 +70,6 @@ export const SmsTraiCreate = (props) => {
|
|
|
70
70
|
onCreateComplete,
|
|
71
71
|
isFullMode,
|
|
72
72
|
onShowTemplates,
|
|
73
|
-
embeddedSmsFallback,
|
|
74
73
|
traiSms: {
|
|
75
74
|
duplicateDetails = {},
|
|
76
75
|
duplicateDetailsError = '',
|
|
@@ -660,11 +659,9 @@ export const SmsTraiCreate = (props) => {
|
|
|
660
659
|
|
|
661
660
|
const createCallback = ({ errorMessage }) => {
|
|
662
661
|
if (!errorMessage) {
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
});
|
|
667
|
-
}
|
|
662
|
+
CapNotification.success({
|
|
663
|
+
message: formatMessage(messages.smsCreateNotification),
|
|
664
|
+
});
|
|
668
665
|
actions.clearCreateResponse();
|
|
669
666
|
} else {
|
|
670
667
|
CapNotification.error({
|
|
@@ -744,9 +741,7 @@ export const SmsTraiCreate = (props) => {
|
|
|
744
741
|
{ templates: savedData },
|
|
745
742
|
(resp, errorMessage) => {
|
|
746
743
|
createCallback({ errorMessage });
|
|
747
|
-
if (
|
|
748
|
-
if (!errorMessage) onCreateComplete(savedData[0]);
|
|
749
|
-
} else if (isFullMode) {
|
|
744
|
+
if (isFullMode) {
|
|
750
745
|
onCreateComplete();
|
|
751
746
|
} else {
|
|
752
747
|
onShowTemplates();
|
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
export const CHARLIMIT = 40;
|
|
8
|
-
/** Display / soft cap label for DLT SMS body length (matches product UI). */
|
|
9
|
-
export const SMS_TRAI_CONTENT_MAX_LENGTH = 1024;
|
|
10
8
|
export const SMS = 'SMS';
|
|
11
9
|
export const SMS_TRAI_VAR = '{#var#}';
|
|
12
10
|
export const TAG = 'TAG';
|