@capillarytech/creatives-library 8.0.353-alpha.6 → 8.0.354

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/constants/unified.js +0 -29
  2. package/index.html +1 -0
  3. package/package.json +1 -1
  4. package/services/tests/api.test.js +20 -35
  5. package/utils/cdnTransformation.js +63 -3
  6. package/utils/commonUtils.js +1 -19
  7. package/utils/tests/cdnTransformation.test.js +111 -0
  8. package/v2Components/CapActionButton/constants.js +0 -7
  9. package/v2Components/CapActionButton/index.js +108 -166
  10. package/v2Components/CapActionButton/index.scss +6 -157
  11. package/v2Components/CapActionButton/messages.js +3 -19
  12. package/v2Components/CapActionButton/tests/index.test.js +17 -41
  13. package/v2Components/CapTagList/index.js +0 -10
  14. package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +49 -72
  15. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +2 -8
  16. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +21 -213
  17. package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +0 -16
  18. package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +10 -85
  19. package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +0 -30
  20. package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +11 -79
  21. package/v2Components/CommonTestAndPreview/SendTestMessage.js +5 -10
  22. package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +15 -157
  23. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +76 -346
  24. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +4 -133
  25. package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +0 -11
  26. package/v2Components/CommonTestAndPreview/constants.js +2 -38
  27. package/v2Components/CommonTestAndPreview/index.js +186 -691
  28. package/v2Components/CommonTestAndPreview/messages.js +3 -45
  29. package/v2Components/CommonTestAndPreview/sagas.js +6 -25
  30. package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +284 -308
  31. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +65 -231
  32. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +5 -118
  33. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +0 -341
  34. package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +1 -8
  35. package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +13 -34
  36. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +283 -281
  37. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +1 -199
  38. package/v2Components/CommonTestAndPreview/tests/index.test.js +4 -132
  39. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +26 -36
  40. package/v2Components/FormBuilder/index.js +6 -11
  41. package/v2Components/TemplatePreview/_templatePreview.scss +23 -38
  42. package/v2Components/TemplatePreview/index.js +31 -143
  43. package/v2Components/TemplatePreview/tests/index.test.js +0 -142
  44. package/v2Components/TestAndPreviewSlidebox/index.js +1 -13
  45. package/v2Components/TestAndPreviewSlidebox/sagas.js +4 -11
  46. package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +1 -3
  47. package/v2Containers/CreativesContainer/SlideBoxContent.js +4 -36
  48. package/v2Containers/CreativesContainer/SlideBoxFooter.js +1 -10
  49. package/v2Containers/CreativesContainer/SlideBoxHeader.js +4 -29
  50. package/v2Containers/CreativesContainer/constants.js +0 -9
  51. package/v2Containers/CreativesContainer/index.js +103 -322
  52. package/v2Containers/CreativesContainer/index.scss +1 -51
  53. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +34 -78
  54. package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +16 -79
  55. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -8
  56. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +98 -357
  57. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +15 -20
  58. package/v2Containers/CreativesContainer/tests/index.test.js +9 -71
  59. package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
  60. package/v2Containers/Rcs/constants.js +10 -119
  61. package/v2Containers/Rcs/index.js +818 -2450
  62. package/v2Containers/Rcs/index.scss +8 -280
  63. package/v2Containers/Rcs/messages.js +3 -34
  64. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +70073 -98018
  65. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +5 -0
  66. package/v2Containers/Rcs/tests/index.test.js +121 -152
  67. package/v2Containers/Rcs/tests/mockData.js +0 -38
  68. package/v2Containers/Rcs/tests/utils.test.js +30 -646
  69. package/v2Containers/Rcs/utils.js +11 -478
  70. package/v2Containers/Sms/Create/index.js +40 -106
  71. package/v2Containers/SmsTrai/Create/index.js +4 -9
  72. package/v2Containers/SmsTrai/Edit/constants.js +0 -2
  73. package/v2Containers/SmsTrai/Edit/index.js +130 -640
  74. package/v2Containers/SmsTrai/Edit/messages.js +4 -14
  75. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +2296 -4249
  76. package/v2Containers/SmsWrapper/index.js +8 -37
  77. package/v2Containers/TagList/index.js +0 -6
  78. package/v2Containers/Templates/_templates.scss +9 -166
  79. package/v2Containers/Templates/actions.js +0 -11
  80. package/v2Containers/Templates/constants.js +0 -2
  81. package/v2Containers/Templates/index.js +52 -120
  82. package/v2Containers/Templates/sagas.js +18 -57
  83. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1017 -1062
  84. package/v2Containers/Templates/tests/sagas.test.js +39 -205
  85. package/v2Containers/TemplatesV2/TemplatesV2.style.js +1 -72
  86. package/v2Containers/TemplatesV2/index.js +23 -86
  87. package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
  88. package/v2Containers/Whatsapp/index.js +20 -3
  89. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -578
  90. package/utils/rcsPayloadUtils.js +0 -92
  91. package/utils/templateVarUtils.js +0 -201
  92. package/utils/tests/rcsPayloadUtils.test.js +0 -226
  93. package/utils/tests/templateVarUtils.test.js +0 -204
  94. package/v2Components/CommonTestAndPreview/previewApiUtils.js +0 -59
  95. package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +0 -67
  96. package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +0 -91
  97. package/v2Components/SmsFallback/constants.js +0 -73
  98. package/v2Components/SmsFallback/index.js +0 -956
  99. package/v2Components/SmsFallback/index.scss +0 -265
  100. package/v2Components/SmsFallback/messages.js +0 -78
  101. package/v2Components/SmsFallback/smsFallbackUtils.js +0 -119
  102. package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +0 -50
  103. package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +0 -147
  104. package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +0 -304
  105. package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +0 -223
  106. package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +0 -309
  107. package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +0 -422
  108. package/v2Components/SmsFallback/useLocalTemplateList.js +0 -92
  109. package/v2Components/TemplatePreview/constants.js +0 -2
  110. package/v2Components/VarSegmentMessageEditor/constants.js +0 -2
  111. package/v2Components/VarSegmentMessageEditor/index.js +0 -125
  112. package/v2Components/VarSegmentMessageEditor/index.scss +0 -46
  113. package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +0 -43
  114. package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +0 -79
  115. package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +0 -90
  116. package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +0 -258
  117. package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +0 -125
  118. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +0 -225
  119. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -318
  120. package/v2Containers/Sms/smsFormDataHelpers.js +0 -67
  121. package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +0 -253
  122. package/v2Containers/SmsTrai/Edit/index.scss +0 -121
  123. package/v2Containers/Templates/TemplatesActionBar.js +0 -101
  124. package/v2Containers/Templates/tests/TemplatesActionBar.test.js +0 -120
  125. package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +0 -180
  126. package/v2Containers/Templates/utils/smsTemplatesListApi.js +0 -79
  127. package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +0 -131
@@ -1,11 +1,10 @@
1
1
  /* eslint-disable no-restricted-syntax */
2
2
  /* eslint-disable no-undef */
3
- import React, { useState, useEffect, useMemo, useRef } from 'react';
4
- import PropTypes from 'prop-types';
3
+ import React, { useState, useEffect } from 'react';
5
4
  import { createStructuredSelector } from 'reselect';
6
5
  import { bindActionCreators } from 'redux';
7
6
  import { FormattedMessage } from 'react-intl';
8
- import { get, cloneDeep, isEmpty } from 'lodash';
7
+ import { get, cloneDeep, isEmpty, isObject } from 'lodash';
9
8
  import styled from 'styled-components';
10
9
  import CapRow from '@capillarytech/cap-ui-library/CapRow';
11
10
  import CapColumn from '@capillarytech/cap-ui-library/CapColumn';
@@ -28,13 +27,13 @@ import {
28
27
  CAP_SPACE_32,
29
28
  CAP_SPACE_04,
30
29
  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';
38
37
  import TagList from '../../TagList';
39
38
  import formBuilderMessages from '../../../v2Components/FormBuilder/messages';
40
39
  import UnifiedPreview from '../../../v2Components/CommonTestAndPreview/UnifiedPreview';
@@ -42,8 +41,6 @@ import TestAndPreviewSlidebox from '../../../v2Components/TestAndPreviewSlidebox
42
41
  import withCreatives from '../../../hoc/withCreatives';
43
42
  import {
44
43
  CHARLIMIT,
45
- SMS,
46
- SMS_TRAI_CONTENT_MAX_LENGTH,
47
44
  SMS_TRAI_VAR,
48
45
  TAG,
49
46
  EMBEDDED,
@@ -52,39 +49,24 @@ import {
52
49
  ALL,
53
50
  LIBRARY,
54
51
  } from './constants';
52
+ import { SMS } from '../../CreativesContainer/constants';
55
53
  import v2EditSmsReducer from '../../Sms/Edit/reducer';
56
54
  import { v2SmsEditSagas } from '../../Sms/Edit/sagas';
57
55
  import ErrorInfoNote from '../../../v2Components/ErrorInfoNote';
58
- import { isTraiDLTEnable, hasTraiDltFeature } from '../../../utils/common';
59
56
  import { validateLiquidTemplateContent } from '../../../utils/commonUtils';
60
57
  import { validateTags } from '../../../utils/tagValidations';
58
+ import globalMessages from '../../Cap/messages';
61
59
  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';
73
60
 
61
+ let varMap = {};
62
+ let traiData = {};
74
63
  const { TextArea } = CapInput;
75
64
  const { CapLabelInline } = CapLabel;
76
65
 
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
-
85
66
  export const SmsTraiEdit = (props) => {
86
67
  const {
87
68
  intl,
69
+ handleClose,
88
70
  params,
89
71
  actions,
90
72
  templateDetails,
@@ -100,20 +82,10 @@ export const SmsTraiEdit = (props) => {
100
82
  templateData = {},
101
83
  selectedOfferDetails,
102
84
  eventContextTags,
85
+ waitEventContextTags,
103
86
  fetchingLiquidTags,
104
87
  getLiquidTags,
105
88
  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,
117
89
  } = props || {};
118
90
 
119
91
  const { formatMessage } = intl;
@@ -123,149 +95,14 @@ export const SmsTraiEdit = (props) => {
123
95
  const [tags, updateTags] = useState([]);
124
96
  const [textAreaId, updateTextAreaId] = useState();
125
97
  const [isValidationError, updateIsValidationError] = useState(false);
126
- const [isTagValidationError, updateIsTagValidationError] = useState(false);
127
98
  const [totalMessageLength, setTotalMessageLength] = useState(0);
128
99
  const [isUnicodeAllowed, updateIsUnicodeAllowed] = useState(true);
129
- const [fallbackText, setFallbackText] = useState('');
130
- const [fallbackVarMappedData, setFallbackVarMappedData] = useState({});
131
- const [fallbackFocusedId, setFallbackFocusedId] = useState('');
132
100
  const [showMsgLengthNote, updateshowMsgLengthNote] = useState(false);
133
101
  const [liquidErrorMessages, setLiquidErrorMessages] = useState({});
134
102
  const [isLiquidValidationError, setIsLiquidValidationError] = useState(false);
135
103
  /** After user closes the validation panel, keep it hidden until Save is clicked again (even if ErrorInfoNote remounts). */
136
104
  const [liquidErrorPanelDismissed, setLiquidErrorPanelDismissed] = useState(false);
137
105
  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 lo = index;
192
- while (lo > 0 && isDltHashVarToken(segments[lo - 1])) lo -= 1;
193
- let hi = index;
194
- while (hi < segments.length - 1 && isDltHashVarToken(segments[hi + 1])) hi += 1;
195
- return hi - lo + 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: 12,
248
- fontWeight: 400,
249
- lineHeight: '16px',
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
- };
269
106
  const SMSTraiFooter = styled.div`
270
107
  background-color: ${CAP_WHITE};
271
108
  padding: ${CAP_SPACE_32} ${CAP_SPACE_24};
@@ -281,6 +118,7 @@ export const SmsTraiEdit = (props) => {
281
118
  .ant-btn {
282
119
  margin-right: ${CAP_SPACE_16};
283
120
  }
121
+ }
284
122
  `;
285
123
  const TraiEditTemplateDetails = styled.div`
286
124
  margin-bottom: ${CAP_SPACE_16};
@@ -289,127 +127,41 @@ export const SmsTraiEdit = (props) => {
289
127
  }
290
128
  `;
291
129
 
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
-
327
130
  useEffect(() => {
131
+ //fetching tags
328
132
  const { type, module } = location.query || {};
329
133
  const isEmbedded = type === EMBEDDED;
330
134
  const query = {
331
135
  layout: SMS,
332
136
  type: TAG,
333
137
  context: isEmbedded ? module : DEFAULT,
334
- embedded: forceFullTagContext ? FULL : (isEmbedded ? type : FULL),
138
+ embedded: isEmbedded ? type : FULL,
335
139
  };
336
140
  if (getDefaultTags) {
337
141
  query.context = getDefaultTags;
338
142
  }
339
- fetchTagSchemaIfNewQuery(query);
143
+ globalActions.fetchSchemaForEntity(query);
144
+ //fetching template data in fullmode
340
145
  const { id } = params || {};
341
146
  if (id) {
342
147
  actions.getTemplateDetails(id);
343
148
  }
149
+ //cleanup code
344
150
  return () => {
345
151
  actions.resetEditTemplate();
346
- varMapRef.current = {};
152
+ varMap = {};
347
153
  };
348
154
  }, []);
349
155
 
156
+ //computing placeholder array for mapping values and rendering dynamic form
350
157
  useEffect(() => {
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`, '');
158
+ traiData = isFullMode ? templateDetails : templateData;
159
+ if (traiData && !isEmpty(traiData)) {
160
+ let msg = get(traiData, `versions.base.sms-editor`, '');
412
161
  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]
413
165
  while (msg.length !== 0) {
414
166
  const index = msg.search(SMS_TRAI_VAR);
415
167
  if (index !== -1) {
@@ -423,59 +175,30 @@ export const SmsTraiEdit = (props) => {
423
175
  }
424
176
  const filteredTemplateMessageArray = templateMessageArray.filter((i) => i === 0 || i);
425
177
  updateTempMsgArray(filteredTemplateMessageArray);
178
+ //stop spinner
426
179
  updateLoading(false);
427
180
  }
428
- }, [templateDetails || templateData, isRcsSmsFallback, isFullMode]);
181
+ }, [templateDetails || templateData]);
429
182
 
183
+ //compute/get varMapped and updated-sms-editor
430
184
  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;
464
185
  if (tempMsgArray.length !== 0) {
465
- const traiBase = traiDataRef.current?.versions?.base || {};
186
+ const traiBase = traiData?.versions?.base || {};
466
187
  const {
467
188
  'var-mapped': varMapped = {},
468
189
  'updated-sms-editor': traiSmsEditor = '',
469
190
  'unicode-validity': unicodeValidity = true,
470
191
  } = traiBase;
192
+ //if varMap and updated-sms-editor is already present on non first edits,use those values
471
193
  if (!isEmpty(varMapped)) {
472
- varMapRef.current = cloneDeep(varMapped);
194
+ varMap = cloneDeep(varMapped);
473
195
  if (isFullMode) {
474
196
  setUpdatedSmsEditor(traiSmsEditor);
475
197
  } else {
476
198
  computeUpdatedSmsEditor();
477
199
  }
478
200
  } else {
201
+ //computing and setting varMap for first edit
479
202
  let varCount = 1;
480
203
  let horizontalSpaceCount = 0;
481
204
  for (let i = 0; i < tempMsgArray.length; i += 1) {
@@ -486,7 +209,7 @@ export const SmsTraiEdit = (props) => {
486
209
  horizontalSpaceCount += 1;
487
210
  }
488
211
  if (tempMsgArray[i] !== nextElem && nextElem?.replace(/[^\S\r\n]/gm, '') !== '') {
489
- varMapRef.current[`${tempMsgArray[i]}_${(i - varCount - horizontalSpaceCount) + 1}`] = {
212
+ varMap[`${tempMsgArray[i]}_${(i - varCount - horizontalSpaceCount) + 1}`] = {
490
213
  data: '',
491
214
  count: varCount,
492
215
  };
@@ -500,6 +223,7 @@ export const SmsTraiEdit = (props) => {
500
223
  setUpdatedSmsEditor(tempMsgArray);
501
224
  }
502
225
  updateIsUnicodeAllowed(unicodeValidity);
226
+ // calcaulate message length here
503
227
  calculateTotalMessageLength();
504
228
  }
505
229
  }, [tempMsgArray]);
@@ -513,84 +237,17 @@ export const SmsTraiEdit = (props) => {
513
237
  }
514
238
  }, []);
515
239
 
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
-
583
240
  const computeUpdatedSmsEditor = () => {
584
241
  const arr = [...tempMsgArray];
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 !== '') {
242
+ const varMapKeys = Object.keys(varMap)?.map((key) => Number(key.slice(8)))?.sort((a, b) => a - b) || [];
243
+ for (const key in varMap) {
244
+ if (varMap[key].data !== '') {
588
245
  const _id = Number(key.slice(8)); //Eg: -> extracting index 1 from keys like {#var# } _1
589
246
  const loopIndex =
590
247
  varMapKeys[varMapKeys?.indexOf(_id) + 1] || arr.length;
591
248
  for (let i = _id; i < loopIndex; i += 1) {
592
249
  if (i === _id) {
593
- arr[i] = varMapRef.current[key].data; //data for first #var# of the textbox
250
+ arr[i] = varMap[key].data; //data for first #var# of the textbox
594
251
  } else if (arr[i] === SMS_TRAI_VAR) {
595
252
  arr[i] = ''; //'' for remaining #var# of a textbox
596
253
  }
@@ -600,8 +257,8 @@ export const SmsTraiEdit = (props) => {
600
257
  setUpdatedSmsEditor(arr);
601
258
  };
602
259
 
260
+ //Saving on done start
603
261
  const onUpdateTemplateComplete = (editResponse, errorMsg) => {
604
- updateLoading(false);
605
262
  if (editResponse?.templateId) {
606
263
  CapNotification.success({
607
264
  message: formatMessage(messages.smsEditNotification),
@@ -680,121 +337,66 @@ export const SmsTraiEdit = (props) => {
680
337
  };
681
338
 
682
339
  const onDoneCallback = () => {
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) {
340
+ if (updatedSmsEditor.includes(SMS_TRAI_VAR) && !isFullMode) {
341
+ //during save textbox should not be empty
693
342
  updateIsValidationError(true);
694
343
  } else {
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
- }
344
+ //start spinner
345
+ updateLoading(true);
346
+ const traiVersions = traiData.versions || {};
347
+ traiVersions.base = {
348
+ ...traiVersions.base,
349
+ 'var-mapped': varMap,
350
+ 'updated-sms-editor': updatedSmsEditor,
351
+ 'unicode-validity': isUnicodeAllowed,
352
+ };
727
353
  traiVersions.history = [traiVersions.base];
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);
354
+ if (isFullMode) {
355
+ actions.editTemplate(traiData, onUpdateTemplateComplete);
732
356
  } else {
733
357
  getFormSubscriptionData({
734
- value: traiVersions,
735
- // Consumers/tests read `versions.base` first (see getBaseFromSmsTraiFormData, rcsDltEditCompletionHandler).
736
- versions: traiVersions,
358
+ value: traiData.versions,
737
359
  _id: params && params.id,
738
360
  validity: true,
739
361
  type: SMS,
740
362
  });
741
- updateLoading(false);
742
363
  }
743
364
  }
744
365
  };
366
+ //Saving on done end
745
367
 
746
- const locationQueryType = location?.query?.type;
747
- const locationQueryModule = location?.query?.module;
748
-
368
+ // tag code start
749
369
  useEffect(() => {
750
- let tag = getStandardTagsFromMeta(metaEntities);
751
- if ((!Array.isArray(tag) || tag.length === 0) && Array.isArray(supportedTags) && supportedTags.length > 0) {
370
+ let tag =
371
+ metaEntities && metaEntities.tags ? metaEntities.tags.standard : [];
372
+ const { type, module } = location.query || {};
373
+ if (type === EMBEDDED && module === LIBRARY && !getDefaultTags) {
752
374
  tag = supportedTags;
753
375
  }
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]);
376
+ updateTags(tag);
377
+ }, [metaEntities]);
763
378
 
764
379
  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();
768
380
  const { type } = location.query || {};
769
381
  const isEmbedded = type === EMBEDDED;
770
382
  const query = {
771
383
  layout: SMS,
772
384
  type: TAG,
773
- context: normalizedContext === ALL ? DEFAULT : normalizedContext,
774
- embedded: forceFullTagContext ? FULL : (isEmbedded ? type : FULL),
385
+ context:
386
+ (data || '').toLowerCase() === ALL
387
+ ? DEFAULT
388
+ : (data || '').toLowerCase(),
389
+ embedded: isEmbedded ? type : FULL,
775
390
  };
776
- fetchTagSchemaIfNewQuery(query);
391
+ globalActions.fetchSchemaForEntity(query);
777
392
  };
778
393
 
779
394
  const onTagSelect = (data) => {
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) {
395
+ if (textAreaId >= 0 && varMap && updatedSmsEditor) {
795
396
  const arr = [...updatedSmsEditor];
796
- const varMapKeys = Object.keys(varMapRef.current)?.map((key) => Number(key.slice(8)))?.sort((a, b) => a - b) || [];
397
+ const varMapKeys = Object.keys(varMap)?.map((key) => Number(key.slice(8)))?.sort((a, b) => a - b) || [];
797
398
  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
798
400
  for (let i = textAreaId; i < loopIndex; i += 1) {
799
401
  if (arr[i] === SMS_TRAI_VAR) {
800
402
  arr[i] = '';
@@ -802,23 +404,26 @@ export const SmsTraiEdit = (props) => {
802
404
  }
803
405
  const messageData = `${arr[textAreaId]}{{${data}}}`;
804
406
  arr[textAreaId] = messageData;
805
- varMapRef.current[`${SMS_TRAI_VAR}_${textAreaId}`].data = messageData;
407
+ varMap[`${SMS_TRAI_VAR}_${textAreaId}`].data = messageData;
806
408
  setUpdatedSmsEditor(arr);
807
409
  }
808
410
  };
809
-
411
+ //setting the id of currently selected text area, is used onTagSelect
810
412
  const setTextAreaId = (event) => {
811
413
  updateTextAreaId(Number(event.target.id));
812
414
  };
415
+ // tag code end
813
416
 
417
+ // on change event of Text Area
814
418
  const textAreaValueChange = ({ target: { value, id } }) => {
815
- if (isRcsSmsFallback) return;
816
419
  const _id = Number(id);
817
420
  const arr = [...updatedSmsEditor];
818
- const varMapKeys = Object.keys(varMapRef.current)?.map((key) => Number(key.slice(8)))?.sort((a, b) => a - b) || [];
421
+ const varMapKeys = Object.keys(varMap)?.map((key) => Number(key.slice(8)))?.sort((a, b) => a - b) || [];
819
422
  const loopIndex = varMapKeys[varMapKeys?.indexOf(_id) + 1] || arr.length;
820
423
 
821
- varMapRef.current[`${SMS_TRAI_VAR}_${_id}`].data = value;
424
+ //assign entered value to varMap
425
+ varMap[`${SMS_TRAI_VAR}_${_id}`].data = value;
426
+ //based on entered value update updatedSmsEditor
822
427
  if (value === '') {
823
428
  for (let i = _id; i < loopIndex; i += 1) {
824
429
  if (i === _id || arr[i] === '') {
@@ -828,7 +433,7 @@ export const SmsTraiEdit = (props) => {
828
433
  } else {
829
434
  for (let i = _id; i < loopIndex; i += 1) {
830
435
  if (i === _id) {
831
- arr[i] = varMapRef.current[`${SMS_TRAI_VAR}_${_id}`].data;
436
+ arr[i] = varMap[`${SMS_TRAI_VAR}_${_id}`].data;
832
437
  } else if (arr[i] === SMS_TRAI_VAR) {
833
438
  arr[i] = '';
834
439
  }
@@ -931,33 +536,18 @@ export const SmsTraiEdit = (props) => {
931
536
  };
932
537
 
933
538
  const smsLengthForVar = () => (
934
- <CapHeading
935
- type="h5"
936
- className={isRcsSmsFallback ? 'rcs-character-count rcs-character-count--compact' : ''}
937
- style={isRcsSmsFallback ? {} : { marginTop: CAP_SPACE_04, marginBottom: 0 }}
938
- >
939
- {isRcsSmsFallback
940
- ? formatMessage(messages.charactersCountLabel, {
941
- current: totalMessageLength,
942
- max: SMS_TRAI_CONTENT_MAX_LENGTH,
943
- })
944
- : formatMessage(messages.totalCharacters, {
945
- smsCount: Math.ceil(totalMessageLength / 160),
946
- number: totalMessageLength,
947
- })}
539
+ <CapHeading type="h5" style={{ marginTop: CAP_SPACE_04, float: 'right' }}>
540
+ {formatMessage(messages.totalCharacters, {
541
+ smsCount: Math.ceil(totalMessageLength / 160),
542
+ number: totalMessageLength,
543
+ })}
948
544
  </CapHeading>
949
545
  );
950
546
 
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
951
550
  const calculateTotalMessageLength = () => {
952
- if (isRcsSmsFallback) {
953
- if (useRcsFallbackVarSegment) {
954
- const resolved = getFallbackResolvedContent(fallbackText || '', fallbackVarMappedData || {});
955
- setTotalMessageLength(resolved.length);
956
- } else {
957
- setTotalMessageLength((fallbackText || '').length);
958
- }
959
- return;
960
- }
961
551
  const msgLenWithoutVar = tempMsgArray
962
552
  ?.filter((i) => i !== SMS_TRAI_VAR)
963
553
  .join('');
@@ -968,43 +558,22 @@ export const SmsTraiEdit = (props) => {
968
558
 
969
559
  const calculateLenForTextBox = () => {
970
560
  let countVarChar = 0;
971
- Object.keys(varMapRef.current).forEach((i) => {
972
- if (varMapRef.current[i].data) {
973
- countVarChar += varMapRef.current[i].data?.length;
974
- if (!showMsgLengthNote && varMapRef.current[i].data?.length > varMapRef.current[i].count * CHARLIMIT) {
561
+ Object.keys(varMap).forEach((i) => {
562
+ if (varMap[i].data) {
563
+ countVarChar += varMap[i].data?.length;
564
+ if (!showMsgLengthNote && varMap[i].data?.length > varMap[i].count * CHARLIMIT) {
975
565
  updateshowMsgLengthNote(true);
976
566
  }
977
567
  } else {
978
- countVarChar += varMapRef.current[i].count * CHARLIMIT;
568
+ countVarChar += varMap[i].count * CHARLIMIT;
979
569
  }
980
570
  });
981
571
  return countVarChar;
982
572
  };
983
573
 
984
- const tagValidationErrorMessage = () => {
985
- const { missingTags = [], unsupportedTags = [], isBraceError } = tagValidationResponseRef.current || {};
986
- const listForMessage = (unsupportedTags && unsupportedTags.length > 0)
987
- ? unsupportedTags
988
- : missingTags;
989
- if (isBraceError) {
990
- return <CapError>{formatMessage(globalMessages.unbalanacedCurlyBraces)}</CapError>;
991
- }
992
- if (listForMessage.length > 0) {
993
- return (
994
- <CapError>
995
- {formatMessage(messages.unsupportedTagsValidationError, {
996
- unsupportedTags: listForMessage,
997
- })}
998
- </CapError>
999
- );
1000
- }
1001
- return null;
1002
- };
1003
-
1004
574
  const disablehandler = () => {
1005
- if (isRcsSmsFallback) return false;
1006
- if (traiDataRef.current && !isEmpty(traiDataRef.current)) {
1007
- const msg = get(traiDataRef.current, `versions.base.sms-editor`, '');
575
+ if (traiData && !isEmpty(traiData)) {
576
+ const msg = get(traiData, `versions.base.sms-editor`, '');
1008
577
  const index = msg.search(SMS_TRAI_VAR);
1009
578
  if (index === -1) {
1010
579
  return true;
@@ -1018,6 +587,7 @@ export const SmsTraiEdit = (props) => {
1018
587
  updateIsUnicodeAllowed(checked);
1019
588
  };
1020
589
 
590
+ // Get template content for test and preview
1021
591
  const getTemplateContent = () => {
1022
592
  if (!updatedSmsEditor || updatedSmsEditor.length === 0) {
1023
593
  return '';
@@ -1025,73 +595,42 @@ export const SmsTraiEdit = (props) => {
1025
595
  return updatedSmsEditor.join('');
1026
596
  };
1027
597
 
598
+ // Build formData for TestAndPreviewSlidebox - templateConfigs with templateId and template for DLT test
1028
599
  const getFormDataForTestAndPreview = () => {
1029
- const smsBase = get(traiDataRef.current, 'versions.base') || get(templateDetails, 'versions.base') || get(templateData, 'versions.base');
600
+ const smsBase = get(traiData, 'versions.base') || get(templateDetails, 'versions.base') || get(templateData, 'versions.base');
1030
601
  if (!smsBase || !smsBase.template_id) {
1031
602
  return {};
1032
603
  }
1033
604
  const templateRaw = smsBase['updated-sms-editor'] || smsBase['sms-editor'] || '';
1034
605
  const template = Array.isArray(templateRaw) ? templateRaw.join('') : templateRaw;
1035
- const headerIds = get(traiDataRef.current, 'versions.base.header', []) || [];
1036
- // For RCS SMS fallback, use the broader `useRcsFallbackVarSegment` flag (covers hasTraiDltFeature
1037
- // and isRcsEditFlow cases where isTraiDLTEnable alone is false). For regular TRAI SMS edit,
1038
- // use `traiDltEnabled` derived from isTraiDLTEnable — useRcsFallbackVarSegment is always false
1039
- // when isRcsSmsFallback is false and would incorrectly disable DLT mode in Test & Preview.
1040
- const effectiveDltEnabled = isRcsSmsFallback ? useRcsFallbackVarSegment : traiDltEnabled;
1041
606
  return {
1042
607
  templateConfigs: {
1043
- templateId: smsBase.template_id,
1044
- template,
1045
- traiDltEnabled: effectiveDltEnabled,
1046
- registeredSenderIds: effectiveDltEnabled ? headerIds : [],
608
+ templateId: smsBase.template_id, template, traiDltEnabled: true, registeredSenderIds: get(traiData, `versions.base.header`, []),
1047
609
  },
1048
610
  };
1049
611
  };
1050
612
 
613
+ // Handle test and preview button click
1051
614
  const handleTestAndPreview = () => {
1052
615
  setShowTestAndPreviewSlidebox(true);
1053
616
  };
1054
617
 
618
+ // Handle close test and preview slidebox
1055
619
  const handleCloseTestAndPreview = () => {
1056
620
  setShowTestAndPreviewSlidebox(false);
1057
621
  };
1058
622
 
1059
- const shouldShowPreview =
1060
- !isRcsSmsFallback || (showPreviewInRcsFallback && !hidePreview);
1061
- const smsSidePreviewColumn = (
1062
- <CapColumn span={8} offset={1}>
1063
- <UnifiedPreview
1064
- channel={SMS}
1065
- content={updatedSmsEditor.join('')}
1066
- device={ANDROID}
1067
- showDeviceToggle={false}
1068
- showHeader={false}
1069
- formatMessage={formatMessage}
1070
- senderId={isUnicodeAllowed ? 'Unicode' : 'ASCII'}
1071
- />
1072
- </CapColumn>
1073
- );
1074
-
1075
623
  return (
1076
624
  <>
1077
- <CapSpin
1078
- spinning={loading || fetchingLiquidTags}
1079
- tip={fetchingLiquidTags && formatMessage(formBuilderMessages.liquidSpinText)}
1080
- className={[
1081
- isRcsSmsFallback && 'sms-trai-edit-rcs-fallback',
1082
- isOverview && 'sms-trai-edit--overview',
1083
- ]
1084
- .filter(Boolean)
1085
- .join(' ') || undefined}
1086
- >
625
+ <CapSpin spinning={loading || fetchingLiquidTags} tip={fetchingLiquidTags && formatMessage(formBuilderMessages.liquidSpinText)}>
1087
626
  <CapRow>
1088
- {traiDataRef.current && !isEmpty(traiDataRef.current) && !isRcsSmsFallback && (
627
+ {traiData && !isEmpty(traiData) && (
1089
628
  <TraiEditTemplateDetails>
1090
629
  <CapLabelInline type="label1">
1091
630
  {formatMessage(messages.templateLabel)}
1092
631
  </CapLabelInline>
1093
632
  <CapLabelInline type="label2">
1094
- {get(traiDataRef.current, `versions.base.template_name`, '')}
633
+ {get(traiData, `versions.base.template_name`, '')}
1095
634
  </CapLabelInline>
1096
635
 
1097
636
  <CapLabelInline type="label1">
@@ -1102,42 +641,15 @@ export const SmsTraiEdit = (props) => {
1102
641
  {formatMessage(messages.senderIdlabel)}
1103
642
  </CapLabelInline>
1104
643
  <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', '')}
644
+ {[...get(traiData, `versions.base.header`, [])].join(', ')}
1120
645
  </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
646
  </TraiEditTemplateDetails>
1135
647
  )}
1136
- <CapColumn span={shouldShowPreview ? 14 : 24}>
648
+ <CapColumn span={14}>
1137
649
  <CapRow>
1138
650
  <CapHeader
1139
651
  title={formatMessage(messages.traiEditTitle)}
1140
- size={isRcsSmsFallback ? 'label1' : 'regular'}
652
+ size="regular"
1141
653
  suffix={(
1142
654
  <TagList
1143
655
  label={formatMessage(messages.addLabels)}
@@ -1146,55 +658,43 @@ export const SmsTraiEdit = (props) => {
1146
658
  tags={tags || []}
1147
659
  onContextChange={handleOnTagsContextChange}
1148
660
  injectedTags={injectedTags || {}}
1149
- channel={SMS}
1150
- hidePopover={false}
1151
- disabled={!isRcsSmsFallback && disablehandler()}
661
+ hidePopover={disablehandler()}
1152
662
  selectedOfferDetails={selectedOfferDetails}
1153
663
  eventContextTags={eventContextTags}
1154
- popoverOverlayStyle={isRcsSmsFallback ? { zIndex: 10020 } : undefined}
1155
- popoverOverlayClassName={isRcsSmsFallback ? 'sms-fallback-taglist-popover rcs-sms-fallback-taglist-popover' : undefined}
664
+ waitEventContextTags={waitEventContextTags}
1156
665
  />
1157
666
  )}
1158
667
  />
1159
668
  </CapRow>
1160
669
 
1161
- {isRcsSmsFallback ? (
1162
- <>
1163
- {renderRcsFallbackMessage(fallbackText)}
1164
- </>
1165
- ) : (
1166
- <>
1167
- <CapRow className="sms-trai-editor-segment-row">
1168
- <div className="sms-trai-segmented-editor">
1169
- {renderedContent()}
1170
- </div>
1171
- </CapRow>
1172
- <CapRow className="sms-trai-length-row">
1173
- {smsLengthForVar()}
1174
- </CapRow>
1175
- </>
1176
- )}
1177
- {isRcsSmsFallback && isTagValidationError && (
1178
- <CapRow>
1179
- {tagValidationErrorMessage()}
1180
- </CapRow>
1181
- )}
1182
- {!isRcsSmsFallback && isTagValidationError && tagValidationErrorMessage()}
1183
- <CapCheckbox
1184
- onChange={unicodeHandler}
1185
- checked={isUnicodeAllowed}
1186
- disabled={
1187
- isRcsSmsFallback
1188
- ? isRcsEditFlow
1189
- : disablehandler()
1190
- }
670
+ <CapRow
671
+ style={{
672
+ backgroundColor: CAP_G10,
673
+ padding: CAP_SPACE_16,
674
+ }}
1191
675
  >
676
+ {renderedContent()}
677
+ </CapRow>
678
+ <CapRow>
679
+ {smsLengthForVar()}
680
+ </CapRow>
681
+ <CapCheckbox onChange={unicodeHandler} checked={isUnicodeAllowed} disabled={disablehandler()}>
1192
682
  {formatMessage(messages.unicodeLabel)}
1193
683
  </CapCheckbox>
1194
684
  {showMsgLengthNote && <CapInfoNote message={<FormattedMessage {...messages.msgLengthNote} values={{ var: '{#var#}' }} />} />}
1195
- <div className="sms-trai-edit-bottom-spacer" />
685
+ <div style={{ marginBottom: '100px' }} />
686
+ </CapColumn>
687
+ <CapColumn span={8} offset={1}>
688
+ <UnifiedPreview
689
+ channel={SMS}
690
+ content={updatedSmsEditor.join('')}
691
+ device={ANDROID}
692
+ showDeviceToggle={false}
693
+ showHeader={false}
694
+ formatMessage={formatMessage}
695
+ senderId={isUnicodeAllowed ? 'Unicode' : 'ASCII'}
696
+ />
1196
697
  </CapColumn>
1197
- {shouldShowPreview && smsSidePreviewColumn}
1198
698
  </CapRow>
1199
699
  <SMSTraiFooter>
1200
700
  {isLiquidValidationError && !liquidErrorPanelDismissed && (
@@ -1220,9 +720,8 @@ export const SmsTraiEdit = (props) => {
1220
720
  <FormattedMessage {...messages.testAndPreviewButtonLabel} />
1221
721
  </CapButton>
1222
722
  <CapButton
1223
- onClick={onDoneCallback}
723
+ onClick={onSubmitWrapper}
1224
724
  className="create-msg"
1225
- disabled={isTagValidationError}
1226
725
  >
1227
726
  <FormattedMessage {...messages.saveButtonLabel} />
1228
727
  </CapButton>
@@ -1239,15 +738,6 @@ export const SmsTraiEdit = (props) => {
1239
738
  );
1240
739
  };
1241
740
 
1242
- SmsTraiEdit.propTypes = {
1243
- isRcsSmsFallback: PropTypes.bool,
1244
- isRcsEditFlow: PropTypes.bool,
1245
- showPreviewInRcsFallback: PropTypes.bool,
1246
- hidePreview: PropTypes.bool,
1247
- isOverview: PropTypes.bool,
1248
- onRcsFallbackEditorStateChange: PropTypes.func,
1249
- };
1250
-
1251
741
  const mapStateToProps = createStructuredSelector({
1252
742
  templateDetails: makeSelectTemplateDetailsResponse(),
1253
743
  metaEntities: makeSelectMetaEntities(),