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