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