@capillarytech/creatives-library 8.0.319 → 8.0.321
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 +14 -0
- package/package.json +1 -1
- package/utils/templateVarUtils.js +172 -0
- package/utils/tests/tagValidations.test.js +34 -0
- package/utils/tests/templateVarUtils.test.js +160 -0
- package/v2Components/CapTagList/index.js +25 -22
- package/v2Components/CapTagList/style.scss +48 -0
- package/v2Components/CapTagListWithInput/__tests__/CapTagListWithInput.test.js +63 -0
- package/v2Components/CapTagListWithInput/index.js +4 -0
- package/v2Components/CapWhatsappCTA/index.js +2 -0
- package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +70 -49
- package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +8 -2
- package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +207 -21
- package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +16 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +85 -10
- package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +30 -0
- package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +79 -11
- package/v2Components/CommonTestAndPreview/SendTestMessage.js +11 -5
- package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +20 -1
- package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +133 -4
- package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +12 -0
- package/v2Components/CommonTestAndPreview/constants.js +38 -0
- package/v2Components/CommonTestAndPreview/index.js +693 -155
- package/v2Components/CommonTestAndPreview/messages.js +41 -3
- package/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
- package/v2Components/CommonTestAndPreview/sagas.js +15 -6
- package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +352 -0
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +269 -1
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +118 -5
- package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +341 -0
- package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +25 -4
- package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +199 -1
- package/v2Components/CommonTestAndPreview/tests/index.test.js +132 -4
- package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
- package/v2Components/CommonTestAndPreview/tests/sagas.test.js +2 -2
- package/v2Components/FormBuilder/index.js +14 -1
- package/v2Components/HtmlEditor/HTMLEditor.js +6 -1
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +927 -2
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +3 -0
- package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +87 -0
- package/v2Components/SmsFallback/constants.js +73 -0
- package/v2Components/SmsFallback/index.js +956 -0
- package/v2Components/SmsFallback/index.scss +265 -0
- package/v2Components/SmsFallback/messages.js +78 -0
- package/v2Components/SmsFallback/smsFallbackUtils.js +107 -0
- package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +50 -0
- package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +147 -0
- package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +304 -0
- package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +197 -0
- package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +261 -0
- package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +422 -0
- package/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
- package/v2Components/TestAndPreviewSlidebox/index.js +8 -1
- package/v2Components/TestAndPreviewSlidebox/sagas.js +11 -4
- package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +3 -1
- package/v2Components/VarSegmentMessageEditor/constants.js +2 -0
- package/v2Components/VarSegmentMessageEditor/index.js +125 -0
- package/v2Components/VarSegmentMessageEditor/index.scss +46 -0
- package/v2Containers/BeeEditor/index.js +3 -0
- package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +43 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +64 -5
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +10 -1
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +29 -4
- package/v2Containers/CreativesContainer/constants.js +9 -0
- package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +67 -0
- package/v2Containers/CreativesContainer/index.js +292 -99
- package/v2Containers/CreativesContainer/index.scss +51 -1
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +104 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +110 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +8 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +363 -0
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +20 -10
- package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
- package/v2Containers/CreativesContainer/tests/index.test.js +71 -9
- package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +125 -0
- package/v2Containers/Email/index.js +1 -0
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +7 -1
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +3 -0
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +20 -2
- package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +16 -1
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +3 -0
- package/v2Containers/EmailWrapper/index.js +4 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +1 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +9 -0
- package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +19 -0
- package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +3 -0
- package/v2Containers/InAppWrapper/index.js +3 -0
- package/v2Containers/MobilePush/Create/index.js +2 -0
- package/v2Containers/MobilePush/Edit/index.js +2 -0
- package/v2Containers/MobilepushWrapper/index.js +3 -1
- package/v2Containers/Rcs/constants.js +32 -1
- package/v2Containers/Rcs/index.js +951 -873
- package/v2Containers/Rcs/index.scss +85 -6
- package/v2Containers/Rcs/messages.js +10 -1
- package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +205 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +40834 -1963
- package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +0 -5
- package/v2Containers/Rcs/tests/index.test.js +41 -38
- package/v2Containers/Rcs/tests/mockData.js +38 -0
- package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +251 -0
- package/v2Containers/Rcs/tests/utils.test.js +379 -1
- package/v2Containers/Rcs/utils.js +358 -10
- package/v2Containers/Sms/Create/index.js +83 -36
- package/v2Containers/Sms/Edit/index.js +2 -0
- package/v2Containers/Sms/smsFormDataHelpers.js +67 -0
- package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +253 -0
- package/v2Containers/SmsTrai/Create/index.js +9 -4
- package/v2Containers/SmsTrai/Edit/constants.js +2 -0
- package/v2Containers/SmsTrai/Edit/index.js +611 -128
- package/v2Containers/SmsTrai/Edit/index.scss +121 -0
- package/v2Containers/SmsTrai/Edit/messages.js +9 -4
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4327 -2374
- package/v2Containers/SmsWrapper/index.js +39 -8
- package/v2Containers/TagList/index.js +47 -2
- package/v2Containers/TagList/messages.js +4 -0
- package/v2Containers/TagList/tests/TagList.test.js +122 -20
- package/v2Containers/TagList/tests/mockdata.js +17 -0
- package/v2Containers/Templates/TemplatesActionBar.js +101 -0
- package/v2Containers/Templates/_templates.scss +61 -2
- package/v2Containers/Templates/actions.js +11 -0
- package/v2Containers/Templates/constants.js +2 -0
- package/v2Containers/Templates/index.js +90 -40
- package/v2Containers/Templates/sagas.js +57 -12
- package/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1043 -1079
- package/v2Containers/Templates/tests/sagas.test.js +193 -12
- package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +180 -0
- package/v2Containers/Templates/utils/smsTemplatesListApi.js +79 -0
- package/v2Containers/TemplatesV2/TemplatesV2.style.js +72 -1
- package/v2Containers/TemplatesV2/index.js +86 -23
- package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +131 -0
- package/v2Containers/Viber/index.js +5 -0
- package/v2Containers/WebPush/Create/hooks/useTagManagement.js +0 -2
- package/v2Containers/WebPush/Create/index.js +9 -1
- package/v2Containers/Whatsapp/index.js +8 -20
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +598 -34
- package/v2Containers/Zalo/index.js +2 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/* eslint-disable no-restricted-syntax */
|
|
2
2
|
/* eslint-disable no-undef */
|
|
3
|
-
import React, { useState, useEffect } from 'react';
|
|
3
|
+
import React, { useState, useEffect, useMemo, useRef } from 'react';
|
|
4
|
+
import PropTypes from 'prop-types';
|
|
4
5
|
import { createStructuredSelector } from 'reselect';
|
|
5
6
|
import { bindActionCreators } from 'redux';
|
|
6
7
|
import { FormattedMessage } from 'react-intl';
|
|
7
|
-
import { get, cloneDeep, isEmpty
|
|
8
|
+
import { get, cloneDeep, isEmpty } from 'lodash';
|
|
8
9
|
import styled from 'styled-components';
|
|
9
10
|
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
10
11
|
import CapColumn from '@capillarytech/cap-ui-library/CapColumn';
|
|
@@ -27,13 +28,13 @@ import {
|
|
|
27
28
|
CAP_SPACE_32,
|
|
28
29
|
CAP_SPACE_04,
|
|
29
30
|
CAP_WHITE,
|
|
30
|
-
CAP_G10,
|
|
31
31
|
} from '@capillarytech/cap-ui-library/styled/variables';
|
|
32
32
|
import { makeSelectTemplateDetailsResponse } from '../../Sms/Edit/selectors';
|
|
33
33
|
import { makeSelectMetaEntities, selectLiquidStateDetails, setInjectedTags } from '../../Cap/selectors';
|
|
34
34
|
import * as smsEditActions from '../../Sms/Edit/actions';
|
|
35
35
|
import * as globalActions from '../../Cap/actions';
|
|
36
36
|
import messages from './messages';
|
|
37
|
+
import globalMessages from '../../Cap/messages';
|
|
37
38
|
import TagList from '../../TagList';
|
|
38
39
|
import formBuilderMessages from '../../../v2Components/FormBuilder/messages';
|
|
39
40
|
import UnifiedPreview from '../../../v2Components/CommonTestAndPreview/UnifiedPreview';
|
|
@@ -41,6 +42,8 @@ import TestAndPreviewSlidebox from '../../../v2Components/TestAndPreviewSlidebox
|
|
|
41
42
|
import withCreatives from '../../../hoc/withCreatives';
|
|
42
43
|
import {
|
|
43
44
|
CHARLIMIT,
|
|
45
|
+
SMS,
|
|
46
|
+
SMS_TRAI_CONTENT_MAX_LENGTH,
|
|
44
47
|
SMS_TRAI_VAR,
|
|
45
48
|
TAG,
|
|
46
49
|
EMBEDDED,
|
|
@@ -49,24 +52,39 @@ import {
|
|
|
49
52
|
ALL,
|
|
50
53
|
LIBRARY,
|
|
51
54
|
} from './constants';
|
|
52
|
-
import { SMS } from '../../CreativesContainer/constants';
|
|
53
55
|
import v2EditSmsReducer from '../../Sms/Edit/reducer';
|
|
54
56
|
import { v2SmsEditSagas } from '../../Sms/Edit/sagas';
|
|
55
57
|
import ErrorInfoNote from '../../../v2Components/ErrorInfoNote';
|
|
58
|
+
import { isTraiDLTEnable, hasTraiDltFeature } from '../../../utils/common';
|
|
56
59
|
import { validateLiquidTemplateContent } from '../../../utils/commonUtils';
|
|
57
60
|
import { validateTags } from '../../../utils/tagValidations';
|
|
58
|
-
import globalMessages from '../../Cap/messages';
|
|
59
61
|
import { ANDROID } from '../../../v2Components/CommonTestAndPreview/constants';
|
|
62
|
+
import {
|
|
63
|
+
getFallbackResolvedContent,
|
|
64
|
+
splitTemplateVarString,
|
|
65
|
+
COMBINED_SMS_TEMPLATE_VAR_REGEX,
|
|
66
|
+
isAnyTemplateVarToken,
|
|
67
|
+
isDltHashVarToken,
|
|
68
|
+
} from '../../../utils/templateVarUtils';
|
|
69
|
+
import VarSegmentMessageEditor from '../../../v2Components/VarSegmentMessageEditor';
|
|
70
|
+
import rcsMessages from '../../Rcs/messages';
|
|
71
|
+
|
|
72
|
+
import './index.scss';
|
|
60
73
|
|
|
61
|
-
let varMap = {};
|
|
62
|
-
let traiData = {};
|
|
63
74
|
const { TextArea } = CapInput;
|
|
64
75
|
const { CapLabelInline } = CapLabel;
|
|
65
76
|
|
|
77
|
+
/** Redux `metaEntities` may be an Immutable.Map; TagList needs plain `tags.standard`. */
|
|
78
|
+
const getStandardTagsFromMeta = (metaEntities) => {
|
|
79
|
+
if (!metaEntities) return [];
|
|
80
|
+
const plain = typeof metaEntities.toJS === 'function' ? metaEntities.toJS() : metaEntities;
|
|
81
|
+
const standard = get(plain, 'tags.standard');
|
|
82
|
+
return Array.isArray(standard) ? standard : [];
|
|
83
|
+
};
|
|
84
|
+
|
|
66
85
|
export const SmsTraiEdit = (props) => {
|
|
67
86
|
const {
|
|
68
87
|
intl,
|
|
69
|
-
handleClose,
|
|
70
88
|
params,
|
|
71
89
|
actions,
|
|
72
90
|
templateDetails,
|
|
@@ -82,9 +100,21 @@ export const SmsTraiEdit = (props) => {
|
|
|
82
100
|
templateData = {},
|
|
83
101
|
selectedOfferDetails,
|
|
84
102
|
eventContextTags,
|
|
103
|
+
waitEventContextTags,
|
|
85
104
|
fetchingLiquidTags,
|
|
86
105
|
getLiquidTags,
|
|
87
106
|
showLiquidErrorInFooter,
|
|
107
|
+
smsRegister,
|
|
108
|
+
// RCS -> SMS fallback edit mode
|
|
109
|
+
isRcsSmsFallback = false,
|
|
110
|
+
/** When editing an existing RCS template, lock Unicode (matches product: no mid-edit toggle). */
|
|
111
|
+
isRcsEditFlow = false,
|
|
112
|
+
showPreviewInRcsFallback = false,
|
|
113
|
+
hidePreview = false,
|
|
114
|
+
isOverview = false,
|
|
115
|
+
forceFullTagContext = false,
|
|
116
|
+
/** RCS parent: merge `rcsSmsFallbackVarMapped` into `smsFallbackData` (same idea as `cardVarMapped`). */
|
|
117
|
+
onRcsFallbackEditorStateChange,
|
|
88
118
|
} = props || {};
|
|
89
119
|
|
|
90
120
|
const { formatMessage } = intl;
|
|
@@ -94,14 +124,149 @@ export const SmsTraiEdit = (props) => {
|
|
|
94
124
|
const [tags, updateTags] = useState([]);
|
|
95
125
|
const [textAreaId, updateTextAreaId] = useState();
|
|
96
126
|
const [isValidationError, updateIsValidationError] = useState(false);
|
|
127
|
+
const [isTagValidationError, updateIsTagValidationError] = useState(false);
|
|
97
128
|
const [totalMessageLength, setTotalMessageLength] = useState(0);
|
|
98
129
|
const [isUnicodeAllowed, updateIsUnicodeAllowed] = useState(true);
|
|
130
|
+
const [fallbackText, setFallbackText] = useState('');
|
|
131
|
+
const [fallbackVarMappedData, setFallbackVarMappedData] = useState({});
|
|
132
|
+
const [fallbackFocusedId, setFallbackFocusedId] = useState('');
|
|
99
133
|
const [showMsgLengthNote, updateshowMsgLengthNote] = useState(false);
|
|
100
134
|
const [liquidErrorMessages, setLiquidErrorMessages] = useState({});
|
|
101
135
|
const [isLiquidValidationError, setIsLiquidValidationError] = useState(false);
|
|
102
136
|
/** After user closes the validation panel, keep it hidden until Save is clicked again (even if ErrorInfoNote remounts). */
|
|
103
137
|
const [liquidErrorPanelDismissed, setLiquidErrorPanelDismissed] = useState(false);
|
|
104
138
|
const [showTestAndPreviewSlidebox, setShowTestAndPreviewSlidebox] = useState(false);
|
|
139
|
+
|
|
140
|
+
/** Per-instance only — was module-level (leaked across mounts / multiple editors). */
|
|
141
|
+
const varMapRef = useRef({});
|
|
142
|
+
const traiDataRef = useRef({});
|
|
143
|
+
const tagValidationResponseRef = useRef({});
|
|
144
|
+
/** De-dupe repeated /meta/TAG fetches from popover/context callbacks. */
|
|
145
|
+
const lastTagSchemaQueryKeyRef = useRef(null);
|
|
146
|
+
/** Latest template props for RCS fallback init — avoids effect deps on unstable `templateData` references. */
|
|
147
|
+
const rcsFallbackTemplateSourceRef = useRef({ isFullMode, templateDetails, templateData });
|
|
148
|
+
rcsFallbackTemplateSourceRef.current = { isFullMode, templateDetails, templateData };
|
|
149
|
+
|
|
150
|
+
const fetchTagSchemaIfNewQuery = (query) => {
|
|
151
|
+
const key = JSON.stringify(query);
|
|
152
|
+
if (lastTagSchemaQueryKeyRef.current === key) return;
|
|
153
|
+
lastTagSchemaQueryKeyRef.current = key;
|
|
154
|
+
globalActions.fetchSchemaForEntity(query);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const traiDltEnabled = useMemo(
|
|
158
|
+
() => isTraiDLTEnable(isFullMode, smsRegister),
|
|
159
|
+
[isFullMode, smsRegister],
|
|
160
|
+
);
|
|
161
|
+
/**
|
|
162
|
+
* VarSegment for RCS SMS fallback when:
|
|
163
|
+
* - `isTraiDLTEnable` passes (library + `smsRegister === 'DLT'`, or full-mode library), or
|
|
164
|
+
* - org has TRAI DLT (`hasTraiDltFeature`) — needed when slidebox used to force `isFullMode={false}`
|
|
165
|
+
* or `smsRegister` is missing so `isTraiDLTEnable` alone is false, or
|
|
166
|
+
* - RCS template inline edit (`isRcsEditFlow`).
|
|
167
|
+
*/
|
|
168
|
+
const useRcsFallbackVarSegment = useMemo(() => {
|
|
169
|
+
if (!isRcsSmsFallback) return false;
|
|
170
|
+
return traiDltEnabled || hasTraiDltFeature() || isRcsEditFlow;
|
|
171
|
+
}, [isRcsSmsFallback, traiDltEnabled, isRcsEditFlow]);
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* RCS SMS fallback: always show character count vs TRAI max (`SMS_TRAI_CONTENT_MAX_LENGTH`).
|
|
175
|
+
* Do not use `totalCharacters` ({smsCount} SMS via length/160) here: resolved template + variable
|
|
176
|
+
* values can exceed one GSM segment while DLT still shows a single registered template — length/160
|
|
177
|
+
* is only a rough segment hint and reads as “wrong SMS count” in campaigns.
|
|
178
|
+
*/
|
|
179
|
+
const renderDescriptionCharacterCount = (className = "rcs-character-count") => (
|
|
180
|
+
<CapLabel type="label1" className={className}>
|
|
181
|
+
{formatMessage(messages.charactersCountLabel, {
|
|
182
|
+
current: totalMessageLength,
|
|
183
|
+
max: SMS_TRAI_CONTENT_MAX_LENGTH,
|
|
184
|
+
})}
|
|
185
|
+
</CapLabel>
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
const dltConsecutiveRunLength = (segments, index) => {
|
|
189
|
+
if (!Array.isArray(segments) || typeof segments[index] !== 'string' || !isDltHashVarToken(segments[index])) {
|
|
190
|
+
return 0;
|
|
191
|
+
}
|
|
192
|
+
let lo = index;
|
|
193
|
+
while (lo > 0 && isDltHashVarToken(segments[lo - 1])) lo -= 1;
|
|
194
|
+
let hi = index;
|
|
195
|
+
while (hi < segments.length - 1 && isDltHashVarToken(segments[hi + 1])) hi += 1;
|
|
196
|
+
return hi - lo + 1;
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const renderRcsFallbackMessage = (str = '') => {
|
|
200
|
+
if (!useRcsFallbackVarSegment) {
|
|
201
|
+
return (
|
|
202
|
+
<CapRow className="rcs-create-template-message-input">
|
|
203
|
+
<div className="rcs_text_area_wrapper">
|
|
204
|
+
<TextArea
|
|
205
|
+
id="rcs_fallback_message_textarea"
|
|
206
|
+
autosize={{ minRows: 4, maxRows: 12 }}
|
|
207
|
+
value={fallbackText}
|
|
208
|
+
onChange={(e) => setFallbackText(e.target.value)}
|
|
209
|
+
placeholder={formatMessage(rcsMessages.fallbackMsgPlaceholder)}
|
|
210
|
+
data-testid="rcs_fallback_plain_text_area"
|
|
211
|
+
/>
|
|
212
|
+
{renderDescriptionCharacterCount()}
|
|
213
|
+
</div>
|
|
214
|
+
</CapRow>
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
return (
|
|
218
|
+
<CapRow className="rcs-create-template-message-input">
|
|
219
|
+
<div className="rcs_text_area_wrapper">
|
|
220
|
+
<VarSegmentMessageEditor
|
|
221
|
+
templateString={str}
|
|
222
|
+
valueMap={fallbackVarMappedData || {}}
|
|
223
|
+
onChange={(varSegmentFieldId, nextSlotValue) => {
|
|
224
|
+
setFallbackVarMappedData((previousSlotMap) => ({
|
|
225
|
+
...(previousSlotMap || {}),
|
|
226
|
+
[varSegmentFieldId]: nextSlotValue,
|
|
227
|
+
}));
|
|
228
|
+
}}
|
|
229
|
+
onFocus={setFallbackFocusedId}
|
|
230
|
+
varRegex={COMBINED_SMS_TEMPLATE_VAR_REGEX}
|
|
231
|
+
placeholderPrefix=""
|
|
232
|
+
getPlaceholder={() => formatMessage(rcsMessages.fallbackMsgPlaceholder)}
|
|
233
|
+
renderVarFooter={(dltSegmentToken, dltSegmentIndex) => {
|
|
234
|
+
if (!isDltHashVarToken(dltSegmentToken)) return null;
|
|
235
|
+
const segments = splitTemplateVarString(str, COMBINED_SMS_TEMPLATE_VAR_REGEX);
|
|
236
|
+
const varCounts = dltConsecutiveRunLength(segments, dltSegmentIndex);
|
|
237
|
+
if (varCounts < 1) return null;
|
|
238
|
+
/* Inline layout/color so hint is visible even if CapSpin / load order blocks SCSS */
|
|
239
|
+
const dltVarSlotHintStyle = {
|
|
240
|
+
display: 'block',
|
|
241
|
+
marginTop: CAP_SPACE_04,
|
|
242
|
+
marginLeft: 'auto',
|
|
243
|
+
marginRight: 0,
|
|
244
|
+
width: 'fit-content',
|
|
245
|
+
maxWidth: '100%',
|
|
246
|
+
textAlign: 'right',
|
|
247
|
+
color: 'rgba(0, 0, 0, 0.45)',
|
|
248
|
+
fontSize: 12,
|
|
249
|
+
fontWeight: 400,
|
|
250
|
+
lineHeight: '16px',
|
|
251
|
+
};
|
|
252
|
+
return (
|
|
253
|
+
<span className="sms-trai-rcs-fallback-var-hint" style={dltVarSlotHintStyle}>
|
|
254
|
+
{formatMessage(messages.textAreaCounts, {
|
|
255
|
+
varCounts,
|
|
256
|
+
var: SMS_TRAI_VAR,
|
|
257
|
+
charCounts: varCounts * CHARLIMIT,
|
|
258
|
+
})}
|
|
259
|
+
</span>
|
|
260
|
+
);
|
|
261
|
+
}}
|
|
262
|
+
/>
|
|
263
|
+
{(!isFullMode)
|
|
264
|
+
? renderDescriptionCharacterCount('rcs-character-count rcs-character-count--compact')
|
|
265
|
+
: (isFullMode && renderDescriptionCharacterCount())}
|
|
266
|
+
</div>
|
|
267
|
+
</CapRow>
|
|
268
|
+
);
|
|
269
|
+
};
|
|
105
270
|
const SMSTraiFooter = styled.div`
|
|
106
271
|
background-color: ${CAP_WHITE};
|
|
107
272
|
padding: ${CAP_SPACE_32} ${CAP_SPACE_24};
|
|
@@ -117,7 +282,6 @@ export const SmsTraiEdit = (props) => {
|
|
|
117
282
|
.ant-btn {
|
|
118
283
|
margin-right: ${CAP_SPACE_16};
|
|
119
284
|
}
|
|
120
|
-
}
|
|
121
285
|
`;
|
|
122
286
|
const TraiEditTemplateDetails = styled.div`
|
|
123
287
|
margin-bottom: ${CAP_SPACE_16};
|
|
@@ -126,41 +290,127 @@ export const SmsTraiEdit = (props) => {
|
|
|
126
290
|
}
|
|
127
291
|
`;
|
|
128
292
|
|
|
293
|
+
/**
|
|
294
|
+
* RCS embedded SMS fallback receives a new `templateData` object from `mapFallbackValueToEditTemplateData`
|
|
295
|
+
* on every parent render. Depending on `[templateDetails || templateData]` re-ran init and wiped
|
|
296
|
+
* VarSegmentMessageEditor state whenever Test & Preview (or any) re-rendered Rcs. Key only changes
|
|
297
|
+
* when template id / sms-editor / header actually change.
|
|
298
|
+
*
|
|
299
|
+
* Do NOT include `unicode-validity` in the key: parent merges `onRcsFallbackEditorStateChange`
|
|
300
|
+
* unicode patches into `templateData`, which would change the key every toggle and re-run init —
|
|
301
|
+
* resetting local checkbox state (visible as the unicode control flipping).
|
|
302
|
+
*
|
|
303
|
+
* Do NOT include `rcs-sms-fallback-var-mapped` in the key: the parent merges slot edits into
|
|
304
|
+
* `templateData` on every change, so the key would change each keystroke and this effect would
|
|
305
|
+
* re-run and reset slots — visible as toggling between old and new values.
|
|
306
|
+
*/
|
|
307
|
+
const rcsFallbackTemplateInitKey = useMemo(() => {
|
|
308
|
+
if (!isRcsSmsFallback) return null;
|
|
309
|
+
// RCS fallback slidebox always passes `templateData` from `mapFallbackValueToEditTemplateData`.
|
|
310
|
+
// `templateDetails` stays empty there (no route id fetch) — do not branch on `isFullMode` or init
|
|
311
|
+
// key is null, the effect never runs, and `loading` stays true forever.
|
|
312
|
+
const activeSmsTemplateSource = templateData;
|
|
313
|
+
if (!activeSmsTemplateSource || isEmpty(activeSmsTemplateSource)) return null;
|
|
314
|
+
const templateBase = get(activeSmsTemplateSource, 'versions.base', {}) || {};
|
|
315
|
+
const smsEditorTemplateString = templateBase?.['sms-editor'] ?? '';
|
|
316
|
+
const registeredSenderHeaderList = templateBase?.header;
|
|
317
|
+
const headerListFingerprint = Array.isArray(registeredSenderHeaderList)
|
|
318
|
+
? registeredSenderHeaderList.join('\u001f')
|
|
319
|
+
: '';
|
|
320
|
+
const templateRecordId = activeSmsTemplateSource?._id ?? '';
|
|
321
|
+
return [
|
|
322
|
+
templateRecordId,
|
|
323
|
+
smsEditorTemplateString,
|
|
324
|
+
headerListFingerprint,
|
|
325
|
+
].join('\u0000');
|
|
326
|
+
}, [isRcsSmsFallback, templateData]);
|
|
327
|
+
|
|
129
328
|
useEffect(() => {
|
|
130
|
-
//fetching tags
|
|
131
329
|
const { type, module } = location.query || {};
|
|
132
330
|
const isEmbedded = type === EMBEDDED;
|
|
133
331
|
const query = {
|
|
134
332
|
layout: SMS,
|
|
135
333
|
type: TAG,
|
|
136
334
|
context: isEmbedded ? module : DEFAULT,
|
|
137
|
-
embedded: isEmbedded ? type : FULL,
|
|
335
|
+
embedded: forceFullTagContext ? FULL : (isEmbedded ? type : FULL),
|
|
138
336
|
};
|
|
139
337
|
if (getDefaultTags) {
|
|
140
338
|
query.context = getDefaultTags;
|
|
141
339
|
}
|
|
142
|
-
|
|
143
|
-
//fetching template data in fullmode
|
|
340
|
+
fetchTagSchemaIfNewQuery(query);
|
|
144
341
|
const { id } = params || {};
|
|
145
342
|
if (id) {
|
|
146
343
|
actions.getTemplateDetails(id);
|
|
147
344
|
}
|
|
148
|
-
//cleanup code
|
|
149
345
|
return () => {
|
|
150
346
|
actions.resetEditTemplate();
|
|
151
|
-
|
|
347
|
+
varMapRef.current = {};
|
|
152
348
|
};
|
|
153
349
|
}, []);
|
|
154
350
|
|
|
155
|
-
//computing placeholder array for mapping values and rendering dynamic form
|
|
156
351
|
useEffect(() => {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
352
|
+
if (!isRcsSmsFallback || rcsFallbackTemplateInitKey == null) return;
|
|
353
|
+
const {
|
|
354
|
+
isFullMode: isFullModeFromRef,
|
|
355
|
+
templateDetails: templateDetailsFromRef,
|
|
356
|
+
templateData: templateDataFromRef,
|
|
357
|
+
} = rcsFallbackTemplateSourceRef.current;
|
|
358
|
+
const activeTemplateSourceForInit = isRcsSmsFallback
|
|
359
|
+
? templateDataFromRef
|
|
360
|
+
: (isFullModeFromRef ? templateDetailsFromRef : templateDataFromRef);
|
|
361
|
+
if (!activeTemplateSourceForInit || isEmpty(activeTemplateSourceForInit)) return;
|
|
362
|
+
traiDataRef.current = activeTemplateSourceForInit;
|
|
363
|
+
const templateBase = get(activeTemplateSourceForInit, 'versions.base', {});
|
|
364
|
+
const unicodeValidity = get(templateBase, 'unicode-validity', true);
|
|
365
|
+
const templateMsg = get(activeTemplateSourceForInit, 'versions.base.sms-editor', '') || '';
|
|
366
|
+
if (!useRcsFallbackVarSegment) {
|
|
367
|
+
setFallbackText(templateMsg);
|
|
368
|
+
setFallbackVarMappedData({});
|
|
369
|
+
setUpdatedSmsEditor(String(templateMsg).split(''));
|
|
370
|
+
setTotalMessageLength(String(templateMsg).length);
|
|
371
|
+
updateIsUnicodeAllowed(unicodeValidity);
|
|
372
|
+
updateLoading(false);
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
const savedVarMap = get(templateBase, 'rcs-sms-fallback-var-mapped', {}) || {};
|
|
376
|
+
const initialVarMap = {};
|
|
377
|
+
const templateSegments = splitTemplateVarString(templateMsg, COMBINED_SMS_TEMPLATE_VAR_REGEX);
|
|
378
|
+
let varOrdinal = 0;
|
|
379
|
+
templateSegments.forEach((segmentToken, segmentIndexInTemplate) => {
|
|
380
|
+
const isVar =
|
|
381
|
+
typeof segmentToken === 'string' && isAnyTemplateVarToken(segmentToken);
|
|
382
|
+
if (!isVar) return;
|
|
383
|
+
varOrdinal += 1;
|
|
384
|
+
const varSegmentSlotId = `${segmentToken}_${segmentIndexInTemplate}`;
|
|
385
|
+
const persistedSlotValue =
|
|
386
|
+
savedVarMap?.[varSegmentSlotId]
|
|
387
|
+
?? savedVarMap?.[`${segmentToken}_${varOrdinal}`];
|
|
388
|
+
// Persisted '' means the user cleared the slot — must not fall back to `segmentToken` for mustache
|
|
389
|
+
// (that would resurrect {{…}} in the input and look like the tag "came back").
|
|
390
|
+
if (typeof persistedSlotValue === 'string') {
|
|
391
|
+
initialVarMap[varSegmentSlotId] = persistedSlotValue;
|
|
392
|
+
} else if (isDltHashVarToken(segmentToken)) {
|
|
393
|
+
initialVarMap[varSegmentSlotId] = '';
|
|
394
|
+
} else {
|
|
395
|
+
initialVarMap[varSegmentSlotId] = segmentToken;
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
setFallbackText(templateMsg);
|
|
399
|
+
setFallbackVarMappedData(initialVarMap);
|
|
400
|
+
const initialResolvedFallbackDisplay = getFallbackResolvedContent(templateMsg, initialVarMap);
|
|
401
|
+
setUpdatedSmsEditor(initialResolvedFallbackDisplay.split(''));
|
|
402
|
+
setTotalMessageLength(initialResolvedFallbackDisplay.length);
|
|
403
|
+
updateIsUnicodeAllowed(unicodeValidity);
|
|
404
|
+
updateLoading(false);
|
|
405
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- init only when semantic key changes; template props are read from ref
|
|
406
|
+
}, [isRcsSmsFallback, rcsFallbackTemplateInitKey, useRcsFallbackVarSegment]);
|
|
407
|
+
|
|
408
|
+
useEffect(() => {
|
|
409
|
+
if (isRcsSmsFallback) return;
|
|
410
|
+
traiDataRef.current = isFullMode ? templateDetails : templateData;
|
|
411
|
+
if (traiDataRef.current && !isEmpty(traiDataRef.current)) {
|
|
412
|
+
let msg = get(traiDataRef.current, `versions.base.sms-editor`, '');
|
|
160
413
|
const templateMessageArray = [];
|
|
161
|
-
//converting sms-editor string to an array split at '{#var#}'
|
|
162
|
-
//split and push string before '{#var#}[0 to index]', push '{#var#}',
|
|
163
|
-
//split and repeat for remaining string[index+7 to length]
|
|
164
414
|
while (msg.length !== 0) {
|
|
165
415
|
const index = msg.search(SMS_TRAI_VAR);
|
|
166
416
|
if (index !== -1) {
|
|
@@ -174,30 +424,59 @@ export const SmsTraiEdit = (props) => {
|
|
|
174
424
|
}
|
|
175
425
|
const filteredTemplateMessageArray = templateMessageArray.filter((i) => i === 0 || i);
|
|
176
426
|
updateTempMsgArray(filteredTemplateMessageArray);
|
|
177
|
-
//stop spinner
|
|
178
427
|
updateLoading(false);
|
|
179
428
|
}
|
|
180
|
-
}, [templateDetails || templateData]);
|
|
429
|
+
}, [templateDetails || templateData, isRcsSmsFallback, isFullMode]);
|
|
181
430
|
|
|
182
|
-
//compute/get varMapped and updated-sms-editor
|
|
183
431
|
useEffect(() => {
|
|
432
|
+
if (!isRcsSmsFallback) return;
|
|
433
|
+
if (!useRcsFallbackVarSegment) {
|
|
434
|
+
const plainFallbackSmsText = fallbackText || '';
|
|
435
|
+
setUpdatedSmsEditor(plainFallbackSmsText.split(''));
|
|
436
|
+
setTotalMessageLength(plainFallbackSmsText.length);
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
const resolvedFallbackDisplay = getFallbackResolvedContent(
|
|
440
|
+
fallbackText || '',
|
|
441
|
+
fallbackVarMappedData || {},
|
|
442
|
+
);
|
|
443
|
+
setUpdatedSmsEditor(resolvedFallbackDisplay.split(''));
|
|
444
|
+
setTotalMessageLength(resolvedFallbackDisplay.length);
|
|
445
|
+
}, [isRcsSmsFallback, useRcsFallbackVarSegment, fallbackText, fallbackVarMappedData]);
|
|
446
|
+
|
|
447
|
+
useEffect(() => {
|
|
448
|
+
if (!isRcsSmsFallback) return;
|
|
449
|
+
if (typeof onRcsFallbackEditorStateChange !== 'function') return;
|
|
450
|
+
onRcsFallbackEditorStateChange({
|
|
451
|
+
rcsSmsFallbackVarMapped: fallbackVarMappedData || {},
|
|
452
|
+
});
|
|
453
|
+
}, [isRcsSmsFallback, fallbackVarMappedData, onRcsFallbackEditorStateChange]);
|
|
454
|
+
|
|
455
|
+
useEffect(() => {
|
|
456
|
+
if (!isRcsSmsFallback) return;
|
|
457
|
+
if (typeof onRcsFallbackEditorStateChange !== 'function') return;
|
|
458
|
+
onRcsFallbackEditorStateChange({
|
|
459
|
+
unicodeValidity: isUnicodeAllowed,
|
|
460
|
+
});
|
|
461
|
+
}, [isRcsSmsFallback, isUnicodeAllowed, onRcsFallbackEditorStateChange]);
|
|
462
|
+
|
|
463
|
+
useEffect(() => {
|
|
464
|
+
if (isRcsSmsFallback) return;
|
|
184
465
|
if (tempMsgArray.length !== 0) {
|
|
185
|
-
const traiBase =
|
|
466
|
+
const traiBase = traiDataRef.current?.versions?.base || {};
|
|
186
467
|
const {
|
|
187
468
|
'var-mapped': varMapped = {},
|
|
188
469
|
'updated-sms-editor': traiSmsEditor = '',
|
|
189
470
|
'unicode-validity': unicodeValidity = true,
|
|
190
471
|
} = traiBase;
|
|
191
|
-
//if varMap and updated-sms-editor is already present on non first edits,use those values
|
|
192
472
|
if (!isEmpty(varMapped)) {
|
|
193
|
-
|
|
473
|
+
varMapRef.current = cloneDeep(varMapped);
|
|
194
474
|
if (isFullMode) {
|
|
195
475
|
setUpdatedSmsEditor(traiSmsEditor);
|
|
196
476
|
} else {
|
|
197
477
|
computeUpdatedSmsEditor();
|
|
198
478
|
}
|
|
199
479
|
} else {
|
|
200
|
-
//computing and setting varMap for first edit
|
|
201
480
|
let varCount = 1;
|
|
202
481
|
let horizontalSpaceCount = 0;
|
|
203
482
|
for (let i = 0; i < tempMsgArray.length; i += 1) {
|
|
@@ -208,7 +487,7 @@ export const SmsTraiEdit = (props) => {
|
|
|
208
487
|
horizontalSpaceCount += 1;
|
|
209
488
|
}
|
|
210
489
|
if (tempMsgArray[i] !== nextElem && nextElem?.replace(/[^\S\r\n]/gm, '') !== '') {
|
|
211
|
-
|
|
490
|
+
varMapRef.current[`${tempMsgArray[i]}_${(i - varCount - horizontalSpaceCount) + 1}`] = {
|
|
212
491
|
data: '',
|
|
213
492
|
count: varCount,
|
|
214
493
|
};
|
|
@@ -222,7 +501,6 @@ export const SmsTraiEdit = (props) => {
|
|
|
222
501
|
setUpdatedSmsEditor(tempMsgArray);
|
|
223
502
|
}
|
|
224
503
|
updateIsUnicodeAllowed(unicodeValidity);
|
|
225
|
-
// calcaulate message length here
|
|
226
504
|
calculateTotalMessageLength();
|
|
227
505
|
}
|
|
228
506
|
}, [tempMsgArray]);
|
|
@@ -236,17 +514,84 @@ export const SmsTraiEdit = (props) => {
|
|
|
236
514
|
}
|
|
237
515
|
}, []);
|
|
238
516
|
|
|
517
|
+
useEffect(() => {
|
|
518
|
+
const runValidateTags = (content) =>
|
|
519
|
+
validateTags({
|
|
520
|
+
content,
|
|
521
|
+
tagsParam: tags,
|
|
522
|
+
location,
|
|
523
|
+
tagModule: getDefaultTags,
|
|
524
|
+
isFullMode,
|
|
525
|
+
}) || {};
|
|
526
|
+
|
|
527
|
+
if (isRcsSmsFallback) {
|
|
528
|
+
if (isFullMode) {
|
|
529
|
+
tagValidationResponseRef.current = {};
|
|
530
|
+
updateIsTagValidationError(false);
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
// TRAI/DLT VarSegment: `validateIfTagClosed` only understands paired `{{…}}` and breaks on
|
|
534
|
+
// legitimate `{#…#}` / mixed TRAI shapes (extra `{`/`}` counts). Do not tie Done to it;
|
|
535
|
+
// slot completeness is enforced by `areAllRcsSmsFallbackVarSlotsFilled` on the RCS screen.
|
|
536
|
+
if (useRcsFallbackVarSegment) {
|
|
537
|
+
tagValidationResponseRef.current = {};
|
|
538
|
+
updateIsTagValidationError(false);
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
const validationContent = fallbackText || '';
|
|
542
|
+
if (!validationContent.trim()) {
|
|
543
|
+
tagValidationResponseRef.current = {};
|
|
544
|
+
updateIsTagValidationError(false);
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
tagValidationResponseRef.current = validateTags({
|
|
548
|
+
content: validationContent,
|
|
549
|
+
tagsParam: tags,
|
|
550
|
+
location,
|
|
551
|
+
tagModule: getDefaultTags,
|
|
552
|
+
isFullMode: true,
|
|
553
|
+
}) || {};
|
|
554
|
+
const braceErr = !!tagValidationResponseRef.current.isBraceError;
|
|
555
|
+
// Plain (non-VarSegment) fallback textarea: only unbalanced `{{…}}` disables Done.
|
|
556
|
+
updateIsTagValidationError(braceErr);
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
if (
|
|
560
|
+
!isFullMode &&
|
|
561
|
+
updatedSmsEditor?.length > 0 &&
|
|
562
|
+
!updatedSmsEditor.includes(SMS_TRAI_VAR)
|
|
563
|
+
) {
|
|
564
|
+
tagValidationResponseRef.current = runValidateTags(updatedSmsEditor.join(''));
|
|
565
|
+
const missing = (tagValidationResponseRef.current.missingTags || []).length > 0;
|
|
566
|
+
const braceErr = !!tagValidationResponseRef.current.isBraceError;
|
|
567
|
+
updateIsTagValidationError(missing || braceErr);
|
|
568
|
+
} else if (!isRcsSmsFallback) {
|
|
569
|
+
tagValidationResponseRef.current = {};
|
|
570
|
+
updateIsTagValidationError(false);
|
|
571
|
+
}
|
|
572
|
+
}, [
|
|
573
|
+
updatedSmsEditor,
|
|
574
|
+
tags,
|
|
575
|
+
isRcsSmsFallback,
|
|
576
|
+
isFullMode,
|
|
577
|
+
useRcsFallbackVarSegment,
|
|
578
|
+
fallbackText,
|
|
579
|
+
fallbackVarMappedData,
|
|
580
|
+
getDefaultTags,
|
|
581
|
+
location,
|
|
582
|
+
]);
|
|
583
|
+
|
|
239
584
|
const computeUpdatedSmsEditor = () => {
|
|
240
585
|
const arr = [...tempMsgArray];
|
|
241
|
-
const varMapKeys = Object.keys(
|
|
242
|
-
for (const key in
|
|
243
|
-
if (
|
|
586
|
+
const varMapKeys = Object.keys(varMapRef.current)?.map((key) => Number(key.slice(8)))?.sort((a, b) => a - b) || [];
|
|
587
|
+
for (const key in varMapRef.current) {
|
|
588
|
+
if (varMapRef.current[key].data !== '') {
|
|
244
589
|
const _id = Number(key.slice(8)); //Eg: -> extracting index 1 from keys like {#var# } _1
|
|
245
590
|
const loopIndex =
|
|
246
591
|
varMapKeys[varMapKeys?.indexOf(_id) + 1] || arr.length;
|
|
247
592
|
for (let i = _id; i < loopIndex; i += 1) {
|
|
248
593
|
if (i === _id) {
|
|
249
|
-
arr[i] =
|
|
594
|
+
arr[i] = varMapRef.current[key].data; //data for first #var# of the textbox
|
|
250
595
|
} else if (arr[i] === SMS_TRAI_VAR) {
|
|
251
596
|
arr[i] = ''; //'' for remaining #var# of a textbox
|
|
252
597
|
}
|
|
@@ -256,8 +601,8 @@ export const SmsTraiEdit = (props) => {
|
|
|
256
601
|
setUpdatedSmsEditor(arr);
|
|
257
602
|
};
|
|
258
603
|
|
|
259
|
-
//Saving on done start
|
|
260
604
|
const onUpdateTemplateComplete = (editResponse, errorMsg) => {
|
|
605
|
+
updateLoading(false);
|
|
261
606
|
if (editResponse?.templateId) {
|
|
262
607
|
CapNotification.success({
|
|
263
608
|
message: formatMessage(messages.smsEditNotification),
|
|
@@ -336,66 +681,121 @@ export const SmsTraiEdit = (props) => {
|
|
|
336
681
|
};
|
|
337
682
|
|
|
338
683
|
const onDoneCallback = () => {
|
|
339
|
-
|
|
340
|
-
|
|
684
|
+
// RCS fallback: allow Save when only "missing tags" ({{name}} may not be in TagList); still block unbalanced braces.
|
|
685
|
+
if (isTagValidationError) {
|
|
686
|
+
if (!isRcsSmsFallback) return;
|
|
687
|
+
const tagValidationSnapshot = tagValidationResponseRef.current ?? {};
|
|
688
|
+
if (tagValidationSnapshot.isBraceError) return;
|
|
689
|
+
}
|
|
690
|
+
const editorJoined = Array.isArray(updatedSmsEditor)
|
|
691
|
+
? updatedSmsEditor.join('')
|
|
692
|
+
: String(updatedSmsEditor || '');
|
|
693
|
+
if (!isRcsSmsFallback && editorJoined.includes(SMS_TRAI_VAR) && !isFullMode) {
|
|
341
694
|
updateIsValidationError(true);
|
|
342
695
|
} else {
|
|
343
|
-
//
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
696
|
+
// Only show full-screen spinner when waiting on full-mode SMS edit API — not for RCS SMS fallback
|
|
697
|
+
// handoff (getFormSubscriptionData → SmsFallback closeSlidebox) and not for embedded sync handoff.
|
|
698
|
+
if (isFullMode && !isRcsSmsFallback) {
|
|
699
|
+
updateLoading(true);
|
|
700
|
+
}
|
|
701
|
+
if (!traiDataRef.current.versions) {
|
|
702
|
+
traiDataRef.current.versions = { base: {}, history: [] };
|
|
703
|
+
}
|
|
704
|
+
const traiVersions = traiDataRef.current.versions;
|
|
705
|
+
if (isRcsSmsFallback) {
|
|
706
|
+
const {
|
|
707
|
+
'var-mapped': _ignoredVarMapped,
|
|
708
|
+
'updated-sms-editor': _ignoredUpdatedSmsEditor,
|
|
709
|
+
'rcs-sms-fallback-var-mapped': _ignoredFallbackVarMapped,
|
|
710
|
+
...baseWithoutDerivedFields
|
|
711
|
+
} = traiVersions.base || {};
|
|
712
|
+
traiVersions.base = {
|
|
713
|
+
...baseWithoutDerivedFields,
|
|
714
|
+
'sms-editor': fallbackText || '',
|
|
715
|
+
'unicode-validity': isUnicodeAllowed,
|
|
716
|
+
...(useRcsFallbackVarSegment && {
|
|
717
|
+
'rcs-sms-fallback-var-mapped': fallbackVarMappedData || {},
|
|
718
|
+
}),
|
|
719
|
+
};
|
|
720
|
+
} else {
|
|
721
|
+
traiVersions.base = {
|
|
722
|
+
...traiVersions.base,
|
|
723
|
+
'var-mapped': varMapRef.current,
|
|
724
|
+
'updated-sms-editor': updatedSmsEditor,
|
|
725
|
+
'unicode-validity': isUnicodeAllowed,
|
|
726
|
+
};
|
|
727
|
+
}
|
|
352
728
|
traiVersions.history = [traiVersions.base];
|
|
353
|
-
|
|
354
|
-
|
|
729
|
+
// RCS → SMS fallback (slidebox / inline): always hand off via getFormSubscriptionData so parent
|
|
730
|
+
// can persist fallback state and close the slide — never the standalone TRAI editTemplate API here.
|
|
731
|
+
if (isFullMode && !isRcsSmsFallback) {
|
|
732
|
+
actions.editTemplate(traiDataRef.current, onUpdateTemplateComplete);
|
|
355
733
|
} else {
|
|
356
734
|
getFormSubscriptionData({
|
|
357
|
-
value:
|
|
735
|
+
value: traiVersions,
|
|
736
|
+
// Consumers/tests read `versions.base` first (see getBaseFromSmsTraiFormData, rcsDltEditCompletionHandler).
|
|
737
|
+
versions: traiVersions,
|
|
358
738
|
_id: params && params.id,
|
|
359
739
|
validity: true,
|
|
360
740
|
type: SMS,
|
|
361
741
|
});
|
|
742
|
+
updateLoading(false);
|
|
362
743
|
}
|
|
363
744
|
}
|
|
364
745
|
};
|
|
365
|
-
//Saving on done end
|
|
366
746
|
|
|
367
|
-
|
|
747
|
+
const locationQueryType = location?.query?.type;
|
|
748
|
+
const locationQueryModule = location?.query?.module;
|
|
749
|
+
|
|
368
750
|
useEffect(() => {
|
|
369
|
-
let tag =
|
|
370
|
-
|
|
371
|
-
const { type, module } = location.query || {};
|
|
372
|
-
if (type === EMBEDDED && module === LIBRARY && !getDefaultTags) {
|
|
751
|
+
let tag = getStandardTagsFromMeta(metaEntities);
|
|
752
|
+
if ((!Array.isArray(tag) || tag.length === 0) && Array.isArray(supportedTags) && supportedTags.length > 0) {
|
|
373
753
|
tag = supportedTags;
|
|
374
754
|
}
|
|
375
|
-
|
|
376
|
-
|
|
755
|
+
if (
|
|
756
|
+
locationQueryType === EMBEDDED &&
|
|
757
|
+
locationQueryModule === LIBRARY &&
|
|
758
|
+
!getDefaultTags
|
|
759
|
+
) {
|
|
760
|
+
tag = supportedTags || [];
|
|
761
|
+
}
|
|
762
|
+
updateTags(Array.isArray(tag) ? tag : []);
|
|
763
|
+
}, [metaEntities, getDefaultTags, supportedTags, locationQueryType, locationQueryModule]);
|
|
377
764
|
|
|
378
765
|
const handleOnTagsContextChange = (data) => {
|
|
766
|
+
// CapTagList passes "Outbound" | "Loyalty" from the module filter; TagList may pass "Outbound" on init.
|
|
767
|
+
if (data == null || data === '') return;
|
|
768
|
+
const normalizedContext = String(data).toLowerCase();
|
|
379
769
|
const { type } = location.query || {};
|
|
380
770
|
const isEmbedded = type === EMBEDDED;
|
|
381
771
|
const query = {
|
|
382
772
|
layout: SMS,
|
|
383
773
|
type: TAG,
|
|
384
|
-
context:
|
|
385
|
-
|
|
386
|
-
? DEFAULT
|
|
387
|
-
: (data || '').toLowerCase(),
|
|
388
|
-
embedded: isEmbedded ? type : FULL,
|
|
774
|
+
context: normalizedContext === ALL ? DEFAULT : normalizedContext,
|
|
775
|
+
embedded: forceFullTagContext ? FULL : (isEmbedded ? type : FULL),
|
|
389
776
|
};
|
|
390
|
-
|
|
777
|
+
fetchTagSchemaIfNewQuery(query);
|
|
391
778
|
};
|
|
392
779
|
|
|
393
780
|
const onTagSelect = (data) => {
|
|
394
|
-
if (
|
|
781
|
+
if (isRcsSmsFallback) {
|
|
782
|
+
if (!useRcsFallbackVarSegment) {
|
|
783
|
+
setFallbackText((prev) => `${prev || ''}{{${data}}}`);
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
if (!fallbackFocusedId) return;
|
|
787
|
+
const prevVal = fallbackVarMappedData?.[fallbackFocusedId] ?? '';
|
|
788
|
+
const nextVal = `${prevVal}{{${data}}}`;
|
|
789
|
+
setFallbackVarMappedData((prev) => ({
|
|
790
|
+
...(prev || {}),
|
|
791
|
+
[fallbackFocusedId]: nextVal,
|
|
792
|
+
}));
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
if (textAreaId >= 0 && varMapRef.current && updatedSmsEditor) {
|
|
395
796
|
const arr = [...updatedSmsEditor];
|
|
396
|
-
const varMapKeys = Object.keys(
|
|
797
|
+
const varMapKeys = Object.keys(varMapRef.current)?.map((key) => Number(key.slice(8)))?.sort((a, b) => a - b) || [];
|
|
397
798
|
const loopIndex = varMapKeys[varMapKeys?.indexOf(textAreaId) + 1] || arr.length;
|
|
398
|
-
//when trying to insert tag in empty textarea,{#var#} is replaced with "" and then tag is added
|
|
399
799
|
for (let i = textAreaId; i < loopIndex; i += 1) {
|
|
400
800
|
if (arr[i] === SMS_TRAI_VAR) {
|
|
401
801
|
arr[i] = '';
|
|
@@ -403,26 +803,23 @@ export const SmsTraiEdit = (props) => {
|
|
|
403
803
|
}
|
|
404
804
|
const messageData = `${arr[textAreaId]}{{${data}}}`;
|
|
405
805
|
arr[textAreaId] = messageData;
|
|
406
|
-
|
|
806
|
+
varMapRef.current[`${SMS_TRAI_VAR}_${textAreaId}`].data = messageData;
|
|
407
807
|
setUpdatedSmsEditor(arr);
|
|
408
808
|
}
|
|
409
809
|
};
|
|
410
|
-
|
|
810
|
+
|
|
411
811
|
const setTextAreaId = (event) => {
|
|
412
812
|
updateTextAreaId(Number(event.target.id));
|
|
413
813
|
};
|
|
414
|
-
// tag code end
|
|
415
814
|
|
|
416
|
-
// on change event of Text Area
|
|
417
815
|
const textAreaValueChange = ({ target: { value, id } }) => {
|
|
816
|
+
if (isRcsSmsFallback) return;
|
|
418
817
|
const _id = Number(id);
|
|
419
818
|
const arr = [...updatedSmsEditor];
|
|
420
|
-
const varMapKeys = Object.keys(
|
|
819
|
+
const varMapKeys = Object.keys(varMapRef.current)?.map((key) => Number(key.slice(8)))?.sort((a, b) => a - b) || [];
|
|
421
820
|
const loopIndex = varMapKeys[varMapKeys?.indexOf(_id) + 1] || arr.length;
|
|
422
821
|
|
|
423
|
-
|
|
424
|
-
varMap[`${SMS_TRAI_VAR}_${_id}`].data = value;
|
|
425
|
-
//based on entered value update updatedSmsEditor
|
|
822
|
+
varMapRef.current[`${SMS_TRAI_VAR}_${_id}`].data = value;
|
|
426
823
|
if (value === '') {
|
|
427
824
|
for (let i = _id; i < loopIndex; i += 1) {
|
|
428
825
|
if (i === _id || arr[i] === '') {
|
|
@@ -432,7 +829,7 @@ export const SmsTraiEdit = (props) => {
|
|
|
432
829
|
} else {
|
|
433
830
|
for (let i = _id; i < loopIndex; i += 1) {
|
|
434
831
|
if (i === _id) {
|
|
435
|
-
arr[i] =
|
|
832
|
+
arr[i] = varMapRef.current[`${SMS_TRAI_VAR}_${_id}`].data;
|
|
436
833
|
} else if (arr[i] === SMS_TRAI_VAR) {
|
|
437
834
|
arr[i] = '';
|
|
438
835
|
}
|
|
@@ -535,18 +932,33 @@ export const SmsTraiEdit = (props) => {
|
|
|
535
932
|
};
|
|
536
933
|
|
|
537
934
|
const smsLengthForVar = () => (
|
|
538
|
-
<CapHeading
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
935
|
+
<CapHeading
|
|
936
|
+
type="h5"
|
|
937
|
+
className={isRcsSmsFallback ? 'rcs-character-count rcs-character-count--compact' : ''}
|
|
938
|
+
style={isRcsSmsFallback ? {} : { marginTop: CAP_SPACE_04, marginBottom: 0 }}
|
|
939
|
+
>
|
|
940
|
+
{isRcsSmsFallback
|
|
941
|
+
? formatMessage(messages.charactersCountLabel, {
|
|
942
|
+
current: totalMessageLength,
|
|
943
|
+
max: SMS_TRAI_CONTENT_MAX_LENGTH,
|
|
944
|
+
})
|
|
945
|
+
: formatMessage(messages.totalCharacters, {
|
|
946
|
+
smsCount: Math.ceil(totalMessageLength / 160),
|
|
947
|
+
number: totalMessageLength,
|
|
948
|
+
})}
|
|
543
949
|
</CapHeading>
|
|
544
950
|
);
|
|
545
951
|
|
|
546
|
-
// to compute the length of the message
|
|
547
|
-
//40 characters is blocked per'{#var#}' if textbox is empty otherwise it will be textbox length
|
|
548
|
-
// and the remaining string length is added to it
|
|
549
952
|
const calculateTotalMessageLength = () => {
|
|
953
|
+
if (isRcsSmsFallback) {
|
|
954
|
+
if (useRcsFallbackVarSegment) {
|
|
955
|
+
const resolved = getFallbackResolvedContent(fallbackText || '', fallbackVarMappedData || {});
|
|
956
|
+
setTotalMessageLength(resolved.length);
|
|
957
|
+
} else {
|
|
958
|
+
setTotalMessageLength((fallbackText || '').length);
|
|
959
|
+
}
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
550
962
|
const msgLenWithoutVar = tempMsgArray
|
|
551
963
|
?.filter((i) => i !== SMS_TRAI_VAR)
|
|
552
964
|
.join('');
|
|
@@ -557,22 +969,43 @@ export const SmsTraiEdit = (props) => {
|
|
|
557
969
|
|
|
558
970
|
const calculateLenForTextBox = () => {
|
|
559
971
|
let countVarChar = 0;
|
|
560
|
-
Object.keys(
|
|
561
|
-
if (
|
|
562
|
-
countVarChar +=
|
|
563
|
-
if (!showMsgLengthNote &&
|
|
972
|
+
Object.keys(varMapRef.current).forEach((i) => {
|
|
973
|
+
if (varMapRef.current[i].data) {
|
|
974
|
+
countVarChar += varMapRef.current[i].data?.length;
|
|
975
|
+
if (!showMsgLengthNote && varMapRef.current[i].data?.length > varMapRef.current[i].count * CHARLIMIT) {
|
|
564
976
|
updateshowMsgLengthNote(true);
|
|
565
977
|
}
|
|
566
978
|
} else {
|
|
567
|
-
countVarChar +=
|
|
979
|
+
countVarChar += varMapRef.current[i].count * CHARLIMIT;
|
|
568
980
|
}
|
|
569
981
|
});
|
|
570
982
|
return countVarChar;
|
|
571
983
|
};
|
|
572
984
|
|
|
985
|
+
const tagValidationErrorMessage = () => {
|
|
986
|
+
const { missingTags = [], unsupportedTags = [], isBraceError } = tagValidationResponseRef.current || {};
|
|
987
|
+
const listForMessage = (unsupportedTags && unsupportedTags.length > 0)
|
|
988
|
+
? unsupportedTags
|
|
989
|
+
: missingTags;
|
|
990
|
+
if (isBraceError) {
|
|
991
|
+
return <CapError>{formatMessage(globalMessages.unbalanacedCurlyBraces)}</CapError>;
|
|
992
|
+
}
|
|
993
|
+
if (listForMessage.length > 0) {
|
|
994
|
+
return (
|
|
995
|
+
<CapError>
|
|
996
|
+
{formatMessage(messages.unsupportedTagsValidationError, {
|
|
997
|
+
unsupportedTags: listForMessage,
|
|
998
|
+
})}
|
|
999
|
+
</CapError>
|
|
1000
|
+
);
|
|
1001
|
+
}
|
|
1002
|
+
return null;
|
|
1003
|
+
};
|
|
1004
|
+
|
|
573
1005
|
const disablehandler = () => {
|
|
574
|
-
if (
|
|
575
|
-
|
|
1006
|
+
if (isRcsSmsFallback) return false;
|
|
1007
|
+
if (traiDataRef.current && !isEmpty(traiDataRef.current)) {
|
|
1008
|
+
const msg = get(traiDataRef.current, `versions.base.sms-editor`, '');
|
|
576
1009
|
const index = msg.search(SMS_TRAI_VAR);
|
|
577
1010
|
if (index === -1) {
|
|
578
1011
|
return true;
|
|
@@ -586,7 +1019,6 @@ export const SmsTraiEdit = (props) => {
|
|
|
586
1019
|
updateIsUnicodeAllowed(checked);
|
|
587
1020
|
};
|
|
588
1021
|
|
|
589
|
-
// Get template content for test and preview
|
|
590
1022
|
const getTemplateContent = () => {
|
|
591
1023
|
if (!updatedSmsEditor || updatedSmsEditor.length === 0) {
|
|
592
1024
|
return '';
|
|
@@ -594,42 +1026,69 @@ export const SmsTraiEdit = (props) => {
|
|
|
594
1026
|
return updatedSmsEditor.join('');
|
|
595
1027
|
};
|
|
596
1028
|
|
|
597
|
-
// Build formData for TestAndPreviewSlidebox - templateConfigs with templateId and template for DLT test
|
|
598
1029
|
const getFormDataForTestAndPreview = () => {
|
|
599
|
-
const smsBase = get(
|
|
1030
|
+
const smsBase = get(traiDataRef.current, 'versions.base') || get(templateDetails, 'versions.base') || get(templateData, 'versions.base');
|
|
600
1031
|
if (!smsBase || !smsBase.template_id) {
|
|
601
1032
|
return {};
|
|
602
1033
|
}
|
|
603
1034
|
const templateRaw = smsBase['updated-sms-editor'] || smsBase['sms-editor'] || '';
|
|
604
1035
|
const template = Array.isArray(templateRaw) ? templateRaw.join('') : templateRaw;
|
|
1036
|
+
const traiDlt = isTraiDLTEnable(isFullMode, smsRegister);
|
|
1037
|
+
const headerIds = get(traiDataRef.current, 'versions.base.header', []) || [];
|
|
605
1038
|
return {
|
|
606
1039
|
templateConfigs: {
|
|
607
|
-
templateId: smsBase.template_id,
|
|
1040
|
+
templateId: smsBase.template_id,
|
|
1041
|
+
template,
|
|
1042
|
+
traiDltEnabled: traiDlt,
|
|
1043
|
+
registeredSenderIds: traiDlt ? headerIds : [],
|
|
608
1044
|
},
|
|
609
1045
|
};
|
|
610
1046
|
};
|
|
611
1047
|
|
|
612
|
-
// Handle test and preview button click
|
|
613
1048
|
const handleTestAndPreview = () => {
|
|
614
1049
|
setShowTestAndPreviewSlidebox(true);
|
|
615
1050
|
};
|
|
616
1051
|
|
|
617
|
-
// Handle close test and preview slidebox
|
|
618
1052
|
const handleCloseTestAndPreview = () => {
|
|
619
1053
|
setShowTestAndPreviewSlidebox(false);
|
|
620
1054
|
};
|
|
621
1055
|
|
|
1056
|
+
const shouldShowPreview =
|
|
1057
|
+
!isRcsSmsFallback || (showPreviewInRcsFallback && !hidePreview);
|
|
1058
|
+
const smsSidePreviewColumn = (
|
|
1059
|
+
<CapColumn span={8} offset={1}>
|
|
1060
|
+
<UnifiedPreview
|
|
1061
|
+
channel={SMS}
|
|
1062
|
+
content={updatedSmsEditor.join('')}
|
|
1063
|
+
device={ANDROID}
|
|
1064
|
+
showDeviceToggle={false}
|
|
1065
|
+
showHeader={false}
|
|
1066
|
+
formatMessage={formatMessage}
|
|
1067
|
+
senderId={isUnicodeAllowed ? 'Unicode' : 'ASCII'}
|
|
1068
|
+
/>
|
|
1069
|
+
</CapColumn>
|
|
1070
|
+
);
|
|
1071
|
+
|
|
622
1072
|
return (
|
|
623
1073
|
<>
|
|
624
|
-
<CapSpin
|
|
1074
|
+
<CapSpin
|
|
1075
|
+
spinning={loading || fetchingLiquidTags}
|
|
1076
|
+
tip={fetchingLiquidTags && formatMessage(formBuilderMessages.liquidSpinText)}
|
|
1077
|
+
className={[
|
|
1078
|
+
isRcsSmsFallback && 'sms-trai-edit-rcs-fallback',
|
|
1079
|
+
isOverview && 'sms-trai-edit--overview',
|
|
1080
|
+
]
|
|
1081
|
+
.filter(Boolean)
|
|
1082
|
+
.join(' ') || undefined}
|
|
1083
|
+
>
|
|
625
1084
|
<CapRow>
|
|
626
|
-
{
|
|
1085
|
+
{traiDataRef.current && !isEmpty(traiDataRef.current) && !isRcsSmsFallback && (
|
|
627
1086
|
<TraiEditTemplateDetails>
|
|
628
1087
|
<CapLabelInline type="label1">
|
|
629
1088
|
{formatMessage(messages.templateLabel)}
|
|
630
1089
|
</CapLabelInline>
|
|
631
1090
|
<CapLabelInline type="label2">
|
|
632
|
-
{get(
|
|
1091
|
+
{get(traiDataRef.current, `versions.base.template_name`, '')}
|
|
633
1092
|
</CapLabelInline>
|
|
634
1093
|
|
|
635
1094
|
<CapLabelInline type="label1">
|
|
@@ -640,15 +1099,15 @@ export const SmsTraiEdit = (props) => {
|
|
|
640
1099
|
{formatMessage(messages.senderIdlabel)}
|
|
641
1100
|
</CapLabelInline>
|
|
642
1101
|
<CapLabelInline type="label2">
|
|
643
|
-
{[...get(
|
|
1102
|
+
{[...get(traiDataRef.current, `versions.base.header`, [])].join(', ')}
|
|
644
1103
|
</CapLabelInline>
|
|
645
1104
|
</TraiEditTemplateDetails>
|
|
646
1105
|
)}
|
|
647
|
-
<CapColumn span={14}>
|
|
1106
|
+
<CapColumn span={shouldShowPreview ? 14 : 24}>
|
|
648
1107
|
<CapRow>
|
|
649
1108
|
<CapHeader
|
|
650
1109
|
title={formatMessage(messages.traiEditTitle)}
|
|
651
|
-
size=
|
|
1110
|
+
size={isRcsSmsFallback ? 'label1' : 'regular'}
|
|
652
1111
|
suffix={(
|
|
653
1112
|
<TagList
|
|
654
1113
|
label={formatMessage(messages.addLabels)}
|
|
@@ -657,42 +1116,56 @@ export const SmsTraiEdit = (props) => {
|
|
|
657
1116
|
tags={tags || []}
|
|
658
1117
|
onContextChange={handleOnTagsContextChange}
|
|
659
1118
|
injectedTags={injectedTags || {}}
|
|
660
|
-
|
|
1119
|
+
channel={SMS}
|
|
1120
|
+
hidePopover={false}
|
|
1121
|
+
disabled={!isRcsSmsFallback && disablehandler()}
|
|
661
1122
|
selectedOfferDetails={selectedOfferDetails}
|
|
662
1123
|
eventContextTags={eventContextTags}
|
|
1124
|
+
waitEventContextTags={waitEventContextTags}
|
|
1125
|
+
popoverOverlayStyle={isRcsSmsFallback ? { zIndex: 10020 } : undefined}
|
|
1126
|
+
popoverOverlayClassName={isRcsSmsFallback ? 'sms-fallback-taglist-popover rcs-sms-fallback-taglist-popover' : undefined}
|
|
663
1127
|
/>
|
|
664
1128
|
)}
|
|
665
1129
|
/>
|
|
666
1130
|
</CapRow>
|
|
667
1131
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
1132
|
+
{isRcsSmsFallback ? (
|
|
1133
|
+
<>
|
|
1134
|
+
{renderRcsFallbackMessage(fallbackText)}
|
|
1135
|
+
</>
|
|
1136
|
+
) : (
|
|
1137
|
+
<>
|
|
1138
|
+
<CapRow className="sms-trai-editor-segment-row">
|
|
1139
|
+
<div className="sms-trai-segmented-editor">
|
|
1140
|
+
{renderedContent()}
|
|
1141
|
+
</div>
|
|
1142
|
+
</CapRow>
|
|
1143
|
+
<CapRow className="sms-trai-length-row">
|
|
1144
|
+
{smsLengthForVar()}
|
|
1145
|
+
</CapRow>
|
|
1146
|
+
</>
|
|
1147
|
+
)}
|
|
1148
|
+
{isRcsSmsFallback && isTagValidationError && (
|
|
1149
|
+
<CapRow>
|
|
1150
|
+
{tagValidationErrorMessage()}
|
|
1151
|
+
</CapRow>
|
|
1152
|
+
)}
|
|
1153
|
+
{!isRcsSmsFallback && isTagValidationError && tagValidationErrorMessage()}
|
|
1154
|
+
<CapCheckbox
|
|
1155
|
+
onChange={unicodeHandler}
|
|
1156
|
+
checked={isUnicodeAllowed}
|
|
1157
|
+
disabled={
|
|
1158
|
+
isRcsSmsFallback
|
|
1159
|
+
? isRcsEditFlow
|
|
1160
|
+
: disablehandler()
|
|
1161
|
+
}
|
|
673
1162
|
>
|
|
674
|
-
{renderedContent()}
|
|
675
|
-
</CapRow>
|
|
676
|
-
<CapRow>
|
|
677
|
-
{smsLengthForVar()}
|
|
678
|
-
</CapRow>
|
|
679
|
-
<CapCheckbox onChange={unicodeHandler} checked={isUnicodeAllowed} disabled={disablehandler()}>
|
|
680
1163
|
{formatMessage(messages.unicodeLabel)}
|
|
681
1164
|
</CapCheckbox>
|
|
682
1165
|
{showMsgLengthNote && <CapInfoNote message={<FormattedMessage {...messages.msgLengthNote} values={{ var: '{#var#}' }} />} />}
|
|
683
|
-
<div
|
|
684
|
-
</CapColumn>
|
|
685
|
-
<CapColumn span={8} offset={1}>
|
|
686
|
-
<UnifiedPreview
|
|
687
|
-
channel={SMS}
|
|
688
|
-
content={updatedSmsEditor.join('')}
|
|
689
|
-
device={ANDROID}
|
|
690
|
-
showDeviceToggle={false}
|
|
691
|
-
showHeader={false}
|
|
692
|
-
formatMessage={formatMessage}
|
|
693
|
-
senderId={isUnicodeAllowed ? 'Unicode' : 'ASCII'}
|
|
694
|
-
/>
|
|
1166
|
+
<div className="sms-trai-edit-bottom-spacer" />
|
|
695
1167
|
</CapColumn>
|
|
1168
|
+
{shouldShowPreview && smsSidePreviewColumn}
|
|
696
1169
|
</CapRow>
|
|
697
1170
|
<SMSTraiFooter>
|
|
698
1171
|
{isLiquidValidationError && !liquidErrorPanelDismissed && (
|
|
@@ -718,8 +1191,9 @@ export const SmsTraiEdit = (props) => {
|
|
|
718
1191
|
<FormattedMessage {...messages.testAndPreviewButtonLabel} />
|
|
719
1192
|
</CapButton>
|
|
720
1193
|
<CapButton
|
|
721
|
-
onClick={
|
|
1194
|
+
onClick={onDoneCallback}
|
|
722
1195
|
className="create-msg"
|
|
1196
|
+
disabled={isTagValidationError}
|
|
723
1197
|
>
|
|
724
1198
|
<FormattedMessage {...messages.saveButtonLabel} />
|
|
725
1199
|
</CapButton>
|
|
@@ -736,6 +1210,15 @@ export const SmsTraiEdit = (props) => {
|
|
|
736
1210
|
);
|
|
737
1211
|
};
|
|
738
1212
|
|
|
1213
|
+
SmsTraiEdit.propTypes = {
|
|
1214
|
+
isRcsSmsFallback: PropTypes.bool,
|
|
1215
|
+
isRcsEditFlow: PropTypes.bool,
|
|
1216
|
+
showPreviewInRcsFallback: PropTypes.bool,
|
|
1217
|
+
hidePreview: PropTypes.bool,
|
|
1218
|
+
isOverview: PropTypes.bool,
|
|
1219
|
+
onRcsFallbackEditorStateChange: PropTypes.func,
|
|
1220
|
+
};
|
|
1221
|
+
|
|
739
1222
|
const mapStateToProps = createStructuredSelector({
|
|
740
1223
|
templateDetails: makeSelectTemplateDetailsResponse(),
|
|
741
1224
|
metaEntities: makeSelectMetaEntities(),
|