@capillarytech/creatives-library 9.0.15-alpha.3 → 9.0.16-beta.0

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 (146) hide show
  1. package/AppRoot.js +80 -0
  2. package/app.js +5 -3
  3. package/constants/unified.js +0 -29
  4. package/entry.js +67 -1
  5. package/global-styles.js +1 -1
  6. package/mfe-exposed-components.js +2 -4
  7. package/package.json +2 -2
  8. package/services/api.js +1 -1
  9. package/services/tests/api.test.js +20 -35
  10. package/styles/containers/layout/_layoutPage.scss +8 -6
  11. package/utils/commonUtils.js +1 -19
  12. package/utils/getDataLayer.js +15 -0
  13. package/utils/gtmTrackers/gtmEvents/creativeDetails.js +2 -1
  14. package/utils/mfeDetect.js +1 -0
  15. package/v2Components/CapActionButton/constants.js +1 -8
  16. package/v2Components/CapActionButton/index.js +144 -202
  17. package/v2Components/CapActionButton/index.scss +14 -232
  18. package/v2Components/CapActionButton/messages.js +3 -19
  19. package/v2Components/CapActionButton/tests/index.test.js +18 -42
  20. package/v2Components/CapImageUpload/index.js +2 -2
  21. package/v2Components/CapTagList/index.js +0 -10
  22. package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +48 -70
  23. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +2 -8
  24. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +21 -214
  25. package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +0 -16
  26. package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +9 -83
  27. package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +0 -30
  28. package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +11 -60
  29. package/v2Components/CommonTestAndPreview/SendTestMessage.js +5 -10
  30. package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +22 -202
  31. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +80 -381
  32. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +8 -155
  33. package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +0 -11
  34. package/v2Components/CommonTestAndPreview/constants.js +2 -38
  35. package/v2Components/CommonTestAndPreview/index.js +222 -761
  36. package/v2Components/CommonTestAndPreview/messages.js +3 -45
  37. package/v2Components/CommonTestAndPreview/sagas.js +6 -25
  38. package/v2Components/CommonTestAndPreview/tests/CommonTestAndPreview.addTestCustomer.test.js +0 -1
  39. package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +267 -284
  40. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +65 -231
  41. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +5 -118
  42. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +0 -341
  43. package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +1 -8
  44. package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +13 -34
  45. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +283 -281
  46. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +1 -199
  47. package/v2Components/CommonTestAndPreview/tests/index.test.js +4 -133
  48. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +24 -31
  49. package/v2Components/NavigationBar/index.js +9 -7
  50. package/v2Components/NavigationBar/mfeModuleHeader.config.js +16 -0
  51. package/v2Components/Pagination/_pagination.scss +2 -0
  52. package/v2Components/TemplatePreview/_templatePreview.scss +25 -45
  53. package/v2Components/TemplatePreview/index.js +32 -147
  54. package/v2Components/TemplatePreview/tests/index.test.js +0 -142
  55. package/v2Components/TestAndPreviewSlidebox/CustomValuesEditor.js +6 -6
  56. package/v2Components/TestAndPreviewSlidebox/index.js +1 -13
  57. package/v2Components/TestAndPreviewSlidebox/sagas.js +4 -11
  58. package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +1 -3
  59. package/v2Containers/Cap/constants.js +1 -0
  60. package/v2Containers/Cap/index.js +47 -21
  61. package/v2Containers/Cap/sagas.js +19 -0
  62. package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +1 -4
  63. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +0 -4
  64. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +20 -20
  65. package/v2Containers/CreativesContainer/SlideBoxContent.js +7 -37
  66. package/v2Containers/CreativesContainer/SlideBoxFooter.js +5 -14
  67. package/v2Containers/CreativesContainer/SlideBoxHeader.js +5 -36
  68. package/v2Containers/CreativesContainer/constants.js +0 -11
  69. package/v2Containers/CreativesContainer/index.js +104 -323
  70. package/v2Containers/CreativesContainer/index.scss +1 -83
  71. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +34 -79
  72. package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +16 -79
  73. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -8
  74. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +90 -333
  75. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +15 -20
  76. package/v2Containers/CreativesContainer/tests/index.test.js +9 -71
  77. package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
  78. package/v2Containers/Rcs/constants.js +11 -131
  79. package/v2Containers/Rcs/index.js +829 -2682
  80. package/v2Containers/Rcs/index.scss +8 -443
  81. package/v2Containers/Rcs/messages.js +6 -45
  82. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +39409 -74176
  83. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +74 -10
  84. package/v2Containers/Rcs/tests/index.test.js +40 -151
  85. package/v2Containers/Rcs/tests/mockData.js +0 -38
  86. package/v2Containers/Rcs/tests/utils.test.js +30 -643
  87. package/v2Containers/Rcs/utils.js +12 -466
  88. package/v2Containers/Sms/Create/index.js +48 -115
  89. package/v2Containers/SmsTrai/Create/index.js +4 -9
  90. package/v2Containers/SmsTrai/Edit/constants.js +0 -2
  91. package/v2Containers/SmsTrai/Edit/index.js +169 -678
  92. package/v2Containers/SmsTrai/Edit/messages.js +4 -14
  93. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +2854 -5455
  94. package/v2Containers/SmsWrapper/index.js +8 -37
  95. package/v2Containers/TagList/index.js +0 -6
  96. package/v2Containers/Templates/_templates.scss +11 -196
  97. package/v2Containers/Templates/actions.js +0 -11
  98. package/v2Containers/Templates/constants.js +0 -2
  99. package/v2Containers/Templates/index.js +60 -131
  100. package/v2Containers/Templates/sagas.js +13 -57
  101. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1015 -1060
  102. package/v2Containers/Templates/tests/sagas.test.js +16 -199
  103. package/v2Containers/TemplatesV2/TemplatesV2.style.js +10 -75
  104. package/v2Containers/TemplatesV2/index.js +43 -86
  105. package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
  106. package/v2Containers/Whatsapp/index.js +25 -4
  107. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -578
  108. package/utils/rcsPayloadUtils.js +0 -92
  109. package/utils/templateVarUtils.js +0 -201
  110. package/utils/tests/rcsPayloadUtils.test.js +0 -226
  111. package/utils/tests/templateVarUtils.test.js +0 -204
  112. package/v2Components/CommonTestAndPreview/previewApiUtils.js +0 -59
  113. package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +0 -67
  114. package/v2Components/CommonTestAndPreview/utils.js +0 -84
  115. package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +0 -91
  116. package/v2Components/SmsFallback/constants.js +0 -94
  117. package/v2Components/SmsFallback/index.js +0 -958
  118. package/v2Components/SmsFallback/index.scss +0 -266
  119. package/v2Components/SmsFallback/messages.js +0 -78
  120. package/v2Components/SmsFallback/smsFallbackUtils.js +0 -120
  121. package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +0 -50
  122. package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +0 -147
  123. package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +0 -304
  124. package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +0 -208
  125. package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +0 -309
  126. package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +0 -422
  127. package/v2Components/SmsFallback/useLocalTemplateList.js +0 -92
  128. package/v2Components/TemplatePreview/constants.js +0 -2
  129. package/v2Components/VarSegmentMessageEditor/constants.js +0 -2
  130. package/v2Components/VarSegmentMessageEditor/index.js +0 -125
  131. package/v2Components/VarSegmentMessageEditor/index.scss +0 -46
  132. package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +0 -17
  133. package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +0 -79
  134. package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +0 -90
  135. package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +0 -258
  136. package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +0 -125
  137. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +0 -227
  138. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +0 -318
  139. package/v2Containers/Sms/smsFormDataHelpers.js +0 -67
  140. package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +0 -253
  141. package/v2Containers/SmsTrai/Edit/index.scss +0 -126
  142. package/v2Containers/Templates/TemplatesActionBar.js +0 -101
  143. package/v2Containers/Templates/tests/TemplatesActionBar.test.js +0 -120
  144. package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +0 -180
  145. package/v2Containers/Templates/utils/smsTemplatesListApi.js +0 -79
  146. package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +0 -131
@@ -1,958 +0,0 @@
1
- import React, { useCallback, useRef, useEffect, useMemo, useReducer } from 'react';
2
- import { connect } from 'react-redux';
3
- import ReactDOM from 'react-dom';
4
- import PropTypes from 'prop-types';
5
- import classnames from 'classnames';
6
- import { injectIntl, FormattedMessage } from 'react-intl';
7
- import get from 'lodash/get';
8
- import CapRow from '@capillarytech/cap-ui-library/CapRow';
9
- import CapHeader from '@capillarytech/cap-ui-library/CapHeader';
10
- import { CapIcons, CapLabel, CapRadio } from '@capillarytech/cap-ui-library';
11
- import CapHeading from '@capillarytech/cap-ui-library/CapHeading';
12
- import CapButton from '@capillarytech/cap-ui-library/CapButton';
13
- import CapIcon from '@capillarytech/cap-ui-library/CapIcon';
14
- import CapDropdown from '@capillarytech/cap-ui-library/CapDropdown';
15
- import CapMenu from '@capillarytech/cap-ui-library/CapMenu';
16
- import CapCustomCard from '@capillarytech/cap-ui-library/CapCustomCard';
17
- import CapSlideBox from '@capillarytech/cap-ui-library/CapSlideBox';
18
- import * as Api from '../../services/api';
19
- import globalMessages from '../../v2Containers/Cap/messages';
20
- import { isTraiDLTEnable } from '../../utils/common';
21
- import TemplatesActionBar from '../../v2Containers/Templates/TemplatesActionBar';
22
- import * as templatesActions from '../../v2Containers/Templates/actions';
23
- import templatesListMessages from '../../v2Containers/Templates/messages';
24
- import SmsWrapper from '../../v2Containers/SmsWrapper';
25
- import SmsTraiEdit from '../../v2Containers/SmsTrai/Edit';
26
-
27
- import SmsFallbackLocalSelector from './SmsFallbackLocalSelector';
28
- import { useLocalTemplateList } from './useLocalTemplateList';
29
- import {
30
- SMS_FALLBACK_VIEW,
31
- CHANNELS_TO_HIDE_FOR_SMS_ONLY,
32
- EMBEDDED_SMS_CREATIVES_LOCATION,
33
- EMBEDDED_SMS_CREATIVES_EDIT_LOCATION,
34
- SMS_FALLBACK_ROUTE,
35
- SMS_TEMPLATE_DETAILS_API_CHANNEL,
36
- SMS_CATEGORY_FILTERS,
37
- SMS_FALLBACK_ACTIONS,
38
- JS_TYPE_BOOLEAN,
39
- } from './constants';
40
- import SlideBoxFooter from '../../v2Containers/CreativesContainer/SlideBoxFooter';
41
- import CreativesSlideBoxWrapper from '../../v2Containers/CreativesContainer/CreativesSlideBoxWrapper';
42
- import {
43
- computeLiquidFooterUpdateFromFormBuilder,
44
- getSlideBoxWrapperMarginFromLiquidErrors,
45
- } from '../../v2Containers/CreativesContainer/embeddedSlideboxUtils';
46
- import { SMS } from '../../v2Containers/CreativesContainer/constants';
47
- import creativesMessages from '../../v2Containers/CreativesContainer/messages';
48
- import messages from './messages';
49
- import {
50
- buildFallbackDataFromTemplate,
51
- buildFallbackDataFromCreativesPayload,
52
- mapFallbackValueToEditTemplateData,
53
- getBaseFromSmsTraiFormData,
54
- getSmsFallbackCardDisplayContent,
55
- resolveContentFromTraiBase,
56
- filterSmsTemplatesByCategory,
57
- } from './smsFallbackUtils';
58
-
59
- import './index.scss';
60
-
61
- // ---------------------------------------------------------------------------
62
- // Reducer — replaces the 10 individual useState declarations
63
- // ---------------------------------------------------------------------------
64
-
65
- const SLIDEBOX_INITIAL_STATE = {
66
- view: null,
67
- fetchDetailsLoading: false,
68
- pendingFallbackData: null,
69
- smsCategoryFilter: SMS_CATEGORY_FILTERS.ALL,
70
- isGetFormData: false,
71
- liquidErrorMessage: { STANDARD_ERROR_MSG: [], LIQUID_ERROR_MSG: [] },
72
- isLiquidValidationError: false,
73
- isLoadingContent: true,
74
- showTestAndPreviewSlidebox: false,
75
- isTestAndPreviewMode: false,
76
- smsCreateRequiredFieldsInvalid: true,
77
- };
78
-
79
- function slideboxReducer(state, action) {
80
- switch (action.type) {
81
- case SMS_FALLBACK_ACTIONS.OPEN_SELECTOR:
82
- return { ...state, view: SMS_FALLBACK_VIEW.SELECTING };
83
- case SMS_FALLBACK_ACTIONS.OPEN_EDITING:
84
- return { ...state, view: SMS_FALLBACK_VIEW.EDITING };
85
- case SMS_FALLBACK_ACTIONS.OPEN_CREATING:
86
- return { ...state, view: SMS_FALLBACK_VIEW.CREATING, fetchDetailsLoading: false, smsCreateRequiredFieldsInvalid: true };
87
- case SMS_FALLBACK_ACTIONS.SELECT_TEMPLATE_START:
88
- return { ...state, fetchDetailsLoading: true };
89
- case SMS_FALLBACK_ACTIONS.SELECT_TEMPLATE_DONE:
90
- return { ...state, fetchDetailsLoading: false, pendingFallbackData: action.payload, view: SMS_FALLBACK_VIEW.EDITING };
91
- case SMS_FALLBACK_ACTIONS.SET_FETCH_LOADING:
92
- return { ...state, fetchDetailsLoading: action.payload };
93
- case SMS_FALLBACK_ACTIONS.GO_BACK_TO_LIST:
94
- return {
95
- ...state,
96
- fetchDetailsLoading: false,
97
- pendingFallbackData: null,
98
- smsCategoryFilter: SMS_CATEGORY_FILTERS.ALL,
99
- view: SMS_FALLBACK_VIEW.SELECTING,
100
- };
101
- case SMS_FALLBACK_ACTIONS.CLOSE:
102
- return SLIDEBOX_INITIAL_STATE;
103
- case SMS_FALLBACK_ACTIONS.SET_IS_GET_FORM_DATA:
104
- return { ...state, isGetFormData: action.payload };
105
- case SMS_FALLBACK_ACTIONS.SET_LIQUID_ERROR:
106
- return { ...state, liquidErrorMessage: action.liquidErrorMessage, isLiquidValidationError: action.isLiquidValidationError };
107
- case SMS_FALLBACK_ACTIONS.SET_LOADING_CONTENT:
108
- // Bail out when value is unchanged — prevents re-render loop: SmsCreate calls
109
- // setIsLoadingContent(true) in componentWillReceiveProps on any prop change, and a
110
- // new state object (even with the same value) would cause SmsFallbackPortalContent
111
- // to re-render, giving SmsCreate new prop references and triggering the cycle again.
112
- if (state.isLoadingContent === action.payload) return state;
113
- return { ...state, isLoadingContent: action.payload };
114
- case SMS_FALLBACK_ACTIONS.OPEN_TEST_PREVIEW:
115
- return { ...state, showTestAndPreviewSlidebox: true, isTestAndPreviewMode: true };
116
- case SMS_FALLBACK_ACTIONS.CLOSE_TEST_PREVIEW:
117
- return { ...state, showTestAndPreviewSlidebox: false, isTestAndPreviewMode: false };
118
- case SMS_FALLBACK_ACTIONS.SET_CREATE_FIELDS_INVALID:
119
- if (state.smsCreateRequiredFieldsInvalid === action.payload) return state;
120
- return { ...state, smsCreateRequiredFieldsInvalid: action.payload };
121
- case SMS_FALLBACK_ACTIONS.SET_CATEGORY_FILTER:
122
- return { ...state, smsCategoryFilter: action.payload };
123
- default:
124
- return state;
125
- }
126
- }
127
-
128
- // ---------------------------------------------------------------------------
129
- // SmsFallbackEditForm — shared by the inline editor and the EDITING slidebox
130
- // ---------------------------------------------------------------------------
131
-
132
- function SmsFallbackEditForm({
133
- skipCloseOnSave,
134
- dataSource,
135
- value,
136
- view,
137
- embeddedEditLocation,
138
- closeSlidebox,
139
- handleEditComplete,
140
- isRcsEditFlow,
141
- isFullMode,
142
- smsRegister,
143
- selectedOfferDetails,
144
- eventContextTags,
145
- onRcsFallbackEditorStateChange,
146
- }) {
147
- const templateData = mapFallbackValueToEditTemplateData(dataSource ?? value);
148
- if (!templateData) return null;
149
- return (
150
- <SmsTraiEdit
151
- location={embeddedEditLocation}
152
- route={SMS_FALLBACK_ROUTE}
153
- /* Required when embedded `module` is `library`: Sms/Create skips TAG fetch without this (see componentWillReceiveProps). */
154
- getDefaultTags="outbound"
155
- forceFullTagContext
156
- handleClose={closeSlidebox}
157
- templateData={templateData}
158
- getFormSubscriptionData={(formData) => handleEditComplete(formData, skipCloseOnSave)}
159
- isRcsSmsFallback
160
- isRcsEditFlow={isRcsEditFlow}
161
- showPreviewInRcsFallback={view === SMS_FALLBACK_VIEW.EDITING}
162
- isFullMode={isFullMode}
163
- smsRegister={smsRegister}
164
- selectedOfferDetails={selectedOfferDetails}
165
- eventContextTags={eventContextTags}
166
- onRcsFallbackEditorStateChange={onRcsFallbackEditorStateChange}
167
- />
168
- );
169
- }
170
-
171
- SmsFallbackEditForm.propTypes = {
172
- skipCloseOnSave: PropTypes.bool,
173
- dataSource: PropTypes.object,
174
- value: PropTypes.object,
175
- view: PropTypes.string,
176
- embeddedEditLocation: PropTypes.object.isRequired,
177
- closeSlidebox: PropTypes.func.isRequired,
178
- handleEditComplete: PropTypes.func.isRequired,
179
- isRcsEditFlow: PropTypes.bool,
180
- isFullMode: PropTypes.bool,
181
- smsRegister: PropTypes.any,
182
- selectedOfferDetails: PropTypes.object,
183
- eventContextTags: PropTypes.array,
184
- onRcsFallbackEditorStateChange: PropTypes.func,
185
- };
186
-
187
- // ---------------------------------------------------------------------------
188
- // SmsFallbackPortalContent — selector + slidebox overlay rendered via portal
189
- // ---------------------------------------------------------------------------
190
-
191
- function SmsFallbackPortalContent({
192
- slideboxState,
193
- slideboxDispatch,
194
- setIsLoadingContent,
195
- value,
196
- channelsToHide,
197
- smsRegister,
198
- isFullMode,
199
- selectedOfferDetails,
200
- eventContextTags,
201
- isRcsEditFlow,
202
- onRcsFallbackEditorStateChange,
203
- intl,
204
- embeddedCreateLocation,
205
- embeddedEditLocation,
206
- templateListForSelector,
207
- templateList,
208
- scheduleTemplateListSearch,
209
- flushTemplateListSearch,
210
- slideBoxWrapperMargin,
211
- closeSlidebox,
212
- goBackToTemplateList,
213
- handleSelectTemplate,
214
- handleEmbeddedCreativesSave,
215
- openSmsCreate,
216
- showLiquidErrorInFooter,
217
- saveMessage,
218
- handleFooterTestAndPreview,
219
- handleCloseTestAndPreview,
220
- handleEmbeddedSmsFooterValidity,
221
- onValidationFail,
222
- handleSmsTraiCreateComplete,
223
- handleSmsCreateFormSubscription,
224
- handleEditComplete,
225
- // Stable no-op refs kept in parent with useCallback/useMemo so SmsCreate does not
226
- // receive new prop references on every slideboxState change (prevents re-render loop).
227
- getLiquidTags,
228
- forwardedTags,
229
- onPreviewContentClicked,
230
- onTestContentClicked,
231
- }) {
232
- const { formatMessage } = intl;
233
- const {
234
- view,
235
- fetchDetailsLoading,
236
- pendingFallbackData,
237
- smsCategoryFilter,
238
- isGetFormData,
239
- liquidErrorMessage,
240
- isLiquidValidationError,
241
- isLoadingContent,
242
- showTestAndPreviewSlidebox,
243
- isTestAndPreviewMode,
244
- smsCreateRequiredFieldsInvalid,
245
- } = slideboxState;
246
-
247
- const isTrai = isTraiDLTEnable(isFullMode, smsRegister);
248
-
249
- const getSearchTerm = (input) => {
250
- if (typeof input === 'string') return input;
251
- return input?.target?.value || '';
252
- };
253
-
254
- const dltCategoryFilters = isTrai ? (
255
- <CapRadio.CapRadioGroup
256
- className="line-filters"
257
- value={smsCategoryFilter}
258
- onChange={(e) => slideboxDispatch({ type: SMS_FALLBACK_ACTIONS.SET_CATEGORY_FILTER, payload: e.target.value })}
259
- >
260
- <CapRadio.Button value={SMS_CATEGORY_FILTERS.ALL}>
261
- <CapLabel type="label2"><FormattedMessage {...templatesListMessages.all} /></CapLabel>
262
- </CapRadio.Button>
263
- <CapRadio.Button value={SMS_CATEGORY_FILTERS.PROMOTIONAL}>
264
- <CapLabel type="label2"><FormattedMessage {...templatesListMessages.promotional} /></CapLabel>
265
- </CapRadio.Button>
266
- <CapRadio.Button value={SMS_CATEGORY_FILTERS.SERVICE_EXPLICIT}>
267
- <CapLabel type="label2"><FormattedMessage {...templatesListMessages.serviceExplicit} /></CapLabel>
268
- </CapRadio.Button>
269
- <CapRadio.Button value={SMS_CATEGORY_FILTERS.SERVICE_IMPLICIT}>
270
- <CapLabel type="label2"><FormattedMessage {...templatesListMessages.serviceImplicit} /></CapLabel>
271
- </CapRadio.Button>
272
- </CapRadio.CapRadioGroup>
273
- ) : null;
274
-
275
- const filterContent = (
276
- <TemplatesActionBar
277
- searchValue={templateList.search}
278
- onSearchChange={(val) => {
279
- const term = getSearchTerm(val);
280
- templateList.setSearch(term);
281
- scheduleTemplateListSearch(term);
282
- }}
283
- onSearch={(val) => {
284
- const term = typeof val === 'string' ? val : (getSearchTerm(val) || templateList.search);
285
- flushTemplateListSearch(term);
286
- }}
287
- onClear={() => flushTemplateListSearch('')}
288
- searchPlaceholder={formatMessage(messages.searchByCreativeName)}
289
- ctaClassName="create-new-sms"
290
- ctaLabel={formatMessage(isTrai ? messages.uploadNew : messages.createNew)}
291
- onCtaClick={openSmsCreate}
292
- >
293
- {dltCategoryFilters}
294
- </TemplatesActionBar>
295
- );
296
-
297
- const showSelector =
298
- view === SMS_FALLBACK_VIEW.SELECTING ||
299
- view === SMS_FALLBACK_VIEW.EDITING ||
300
- view === SMS_FALLBACK_VIEW.CREATING;
301
-
302
- const selectorEl = showSelector ? (
303
- <SmsFallbackLocalSelector
304
- key="sms-fallback-selector"
305
- hidden={view !== SMS_FALLBACK_VIEW.SELECTING}
306
- fetchDetailsLoading={fetchDetailsLoading}
307
- templateList={templateListForSelector}
308
- channelsToHide={channelsToHide}
309
- smsRegister={smsRegister}
310
- onCloseCreatives={closeSlidebox}
311
- onSelectTemplate={handleSelectTemplate}
312
- filterContent={filterContent}
313
- getCreativesData={handleEmbeddedCreativesSave}
314
- location={embeddedCreateLocation}
315
- />
316
- ) : null;
317
-
318
- if (view !== SMS_FALLBACK_VIEW.EDITING && view !== SMS_FALLBACK_VIEW.CREATING) {
319
- return <>{selectorEl}</>;
320
- }
321
-
322
- let slideHeader = null;
323
- let slideContent = null;
324
-
325
- if (view === SMS_FALLBACK_VIEW.CREATING) {
326
- slideHeader = (
327
- <CapHeader
328
- className="support-video-elements sms-fallback-create-slidebox-header"
329
- title={(
330
- <FormattedMessage
331
- {...creativesMessages.createMessageContent}
332
- values={{ channel: <FormattedMessage {...creativesMessages.smsHeader} /> }}
333
- />
334
- )}
335
- prefix={
336
- !isFullMode ? (
337
- <span className="sms-fallback-create-slidebox-header__prefix">
338
- <CapIcons.BackIcon onClick={goBackToTemplateList} />
339
- </span>
340
- ) : null
341
- }
342
- />
343
- );
344
- slideContent = (
345
- <SmsWrapper
346
- isCreateSms
347
- embeddedSmsFallback
348
- showLiquidErrorInFooter={showLiquidErrorInFooter}
349
- setIsLoadingContent={setIsLoadingContent}
350
- location={embeddedCreateLocation}
351
- route={SMS_FALLBACK_ROUTE}
352
- isGetFormData={isGetFormData}
353
- getFormSubscriptionData={handleSmsCreateFormSubscription}
354
- onValidationFail={onValidationFail}
355
- showTestAndPreviewSlidebox={showTestAndPreviewSlidebox}
356
- handleTestAndPreview={handleFooterTestAndPreview}
357
- handleCloseTestAndPreview={handleCloseTestAndPreview}
358
- isTestAndPreviewMode={isTestAndPreviewMode}
359
- /* Same as campaign embedded SMS + library: triggers full /meta/TAG (outbound) instead of partial supportedTags-only path. */
360
- getDefaultTags="outbound"
361
- forceFullTagContext
362
- getLiquidTags={getLiquidTags}
363
- isFullMode={isFullMode}
364
- forwardedTags={forwardedTags}
365
- selectedOfferDetails={selectedOfferDetails}
366
- onPreviewContentClicked={onPreviewContentClicked}
367
- onTestContentClicked={onTestContentClicked}
368
- onCreateComplete={handleSmsTraiCreateComplete}
369
- onShowTemplates={closeSlidebox}
370
- onEmbeddedSmsFooterValidity={handleEmbeddedSmsFooterValidity}
371
- smsRegister={smsRegister}
372
- eventContextTags={eventContextTags}
373
- />
374
- );
375
- } else if (view === SMS_FALLBACK_VIEW.EDITING && (pendingFallbackData || value)) {
376
- slideHeader = (
377
- <CapHeader
378
- className="sms-fallback-slidebox-header sms-fallback-slidebox-header--edit"
379
- title={formatMessage(messages.editTitle)}
380
- description=""
381
- prefix={(
382
- <div className="sms-fallback-slidebox-header__prefix">
383
- <button
384
- type="button"
385
- className="sms-fallback-slidebox-header__back"
386
- onClick={goBackToTemplateList}
387
- aria-label={formatMessage(messages.backToTemplates)}
388
- >
389
- <CapIcon type="arrow-left" />
390
- </button>
391
- </div>
392
- )}
393
- />
394
- );
395
- slideContent = (
396
- <SmsFallbackEditForm
397
- dataSource={pendingFallbackData || value}
398
- value={value}
399
- view={view}
400
- embeddedEditLocation={embeddedEditLocation}
401
- closeSlidebox={closeSlidebox}
402
- handleEditComplete={handleEditComplete}
403
- isRcsEditFlow={isRcsEditFlow}
404
- isFullMode={isFullMode}
405
- smsRegister={smsRegister}
406
- selectedOfferDetails={selectedOfferDetails}
407
- eventContextTags={eventContextTags}
408
- onRcsFallbackEditorStateChange={onRcsFallbackEditorStateChange}
409
- />
410
- );
411
- }
412
-
413
- const showSmsFormSlideboxFooter =
414
- view === SMS_FALLBACK_VIEW.CREATING &&
415
- !isTraiDLTEnable(false, smsRegister) &&
416
- !isLoadingContent;
417
-
418
- const smsFormSlideboxFooter = showSmsFormSlideboxFooter ? (
419
- <SlideBoxFooter
420
- isFullMode={false}
421
- primarySaveButtonMessage={globalMessages.save}
422
- slidBoxContent="createTemplate"
423
- onSave={saveMessage}
424
- onDiscard={() => {}}
425
- onEditTemplate={() => {}}
426
- onCreateNextStep={() => {}}
427
- shouldShowContinueFooter={() => false}
428
- shouldShowDoneFooter={() => true}
429
- fetchingCmsData={false}
430
- isTemplateNameEmpty={smsCreateRequiredFieldsInvalid}
431
- isLiquidValidationError={isLiquidValidationError}
432
- errorMessages={liquidErrorMessage}
433
- currentTab=""
434
- onTestAndPreview={handleFooterTestAndPreview}
435
- showTestAndPreviewButton
436
- isContinueButtonDisabled={false}
437
- htmlEditorValidationState={{}}
438
- isCreatingTemplate={false}
439
- currentChannel={SMS}
440
- restrictPersonalization={false}
441
- isAnonymousType={false}
442
- templateData={{}}
443
- hasPersonalizationTokenError={false}
444
- />
445
- ) : null;
446
-
447
- return (
448
- <>
449
- {selectorEl}
450
- <CreativesSlideBoxWrapper
451
- slideBoxWrapperMargin={slideBoxWrapperMargin}
452
- shouldApplyFooterMargin={false}
453
- className={classnames(
454
- 'add-creatives-section',
455
- 'creatives-library-mode',
456
- view === SMS_FALLBACK_VIEW.CREATING && 'sms-fallback-slidebox--embedded-sms-create',
457
- )}
458
- >
459
- <CapSlideBox
460
- key="sms-fallback-edit-slidebox"
461
- className="sms-fallback-slidebox rcs-sms-fallback-slidebox"
462
- show
463
- handleClose={closeSlidebox}
464
- header={slideHeader}
465
- content={slideContent}
466
- footer={smsFormSlideboxFooter}
467
- size="size-xl"
468
- />
469
- </CreativesSlideBoxWrapper>
470
- </>
471
- );
472
- }
473
-
474
- // ---------------------------------------------------------------------------
475
- // SmsFallback — main component
476
- // ---------------------------------------------------------------------------
477
-
478
- export function SmsFallback({
479
- dispatch,
480
- value,
481
- onChange,
482
- smsRegister,
483
- selectedOfferDetails,
484
- channelsToHide = CHANNELS_TO_HIDE_FOR_SMS_ONLY,
485
- sectionTitle,
486
- intl,
487
- showAsCard = true,
488
- disableSelectTemplate = false,
489
- eventContextTags,
490
- isFullMode = false,
491
- onRcsFallbackEditorStateChange,
492
- parentLocation,
493
- /** RCS container: true when editing an existing template (Unicode toggle locked in SMS fallback). */
494
- isRcsEditFlow = false,
495
- }) {
496
- const { formatMessage } = intl;
497
- const [slideboxState, slideboxDispatch] = useReducer(slideboxReducer, SLIDEBOX_INITIAL_STATE);
498
- const { view, pendingFallbackData, isLiquidValidationError, liquidErrorMessage } = slideboxState;
499
-
500
- const slideBoxWrapperMargin = useMemo(
501
- () => getSlideBoxWrapperMarginFromLiquidErrors(liquidErrorMessage),
502
- [liquidErrorMessage],
503
- );
504
-
505
- const perPage = 25;
506
- const fetchTemplates = useCallback(
507
- ({ page, search: searchTerm }) =>
508
- new Promise((resolve, reject) => {
509
- dispatch(
510
- templatesActions.getLocalSmsTemplates(
511
- {
512
- page,
513
- perPage,
514
- sortBy: 'Most Recent',
515
- name: searchTerm || '',
516
- ...(isTraiDLTEnable(isFullMode, smsRegister) ? { traiEnable: true } : {}),
517
- },
518
- formatMessage(globalMessages.copyOf),
519
- ({ channelTemplates }) => {
520
- const templates = channelTemplates?.templates || [];
521
- const totalCount = channelTemplates?.totalCount || channelTemplates?.total || 0;
522
- resolve({ templates, totalCount });
523
- },
524
- (error) => reject(error),
525
- )
526
- );
527
- }),
528
- [dispatch, smsRegister, isFullMode, perPage, formatMessage]
529
- );
530
-
531
- const templateList = useLocalTemplateList({ fetchTemplates, perPage });
532
-
533
- /** Same 500ms debounce as `Templates.searchTemplate` (`delay` → `getAllTemplates`). */
534
- const SMS_TEMPLATE_LIST_SEARCH_DEBOUNCE_MS = 500;
535
- const templateSearchDebounceRef = useRef(null);
536
-
537
- const clearTemplateSearchDebounce = useCallback(() => {
538
- if (templateSearchDebounceRef.current != null) {
539
- clearTimeout(templateSearchDebounceRef.current);
540
- templateSearchDebounceRef.current = null;
541
- }
542
- }, []);
543
-
544
- const { reset: resetTemplateList } = templateList;
545
-
546
- const flushTemplateListSearch = useCallback(
547
- (term) => {
548
- clearTemplateSearchDebounce();
549
- resetTemplateList(term);
550
- },
551
- [clearTemplateSearchDebounce, resetTemplateList],
552
- );
553
-
554
- const scheduleTemplateListSearch = useCallback(
555
- (term) => {
556
- clearTemplateSearchDebounce();
557
- templateSearchDebounceRef.current = setTimeout(() => {
558
- templateSearchDebounceRef.current = null;
559
- resetTemplateList(term);
560
- }, SMS_TEMPLATE_LIST_SEARCH_DEBOUNCE_MS);
561
- },
562
- [clearTemplateSearchDebounce, resetTemplateList],
563
- );
564
-
565
- useEffect(() => () => clearTemplateSearchDebounce(), [clearTemplateSearchDebounce]);
566
-
567
- const filteredTemplatesForGrid = useMemo(
568
- () => filterSmsTemplatesByCategory(templateList.templates, slideboxState.smsCategoryFilter),
569
- [templateList.templates, slideboxState.smsCategoryFilter],
570
- );
571
-
572
- const templateListForSelector = useMemo(
573
- () => ({ ...templateList, templates: filteredTemplatesForGrid }),
574
- [templateList, filteredTemplatesForGrid],
575
- );
576
-
577
- const embeddedQueryBase = useMemo(() => {
578
- const parentQuery = get(parentLocation, 'query', {});
579
- const moduleFromParent = parentQuery?.module && parentQuery.module !== 'library'
580
- ? parentQuery.module
581
- : 'default';
582
- return { ...parentQuery, type: 'embedded', module: moduleFromParent };
583
- }, [parentLocation]);
584
-
585
- const embeddedCreateLocation = useMemo(() => ({
586
- ...EMBEDDED_SMS_CREATIVES_LOCATION,
587
- pathname: '/sms/create',
588
- query: embeddedQueryBase,
589
- }), [embeddedQueryBase]);
590
-
591
- const embeddedEditLocation = useMemo(() => ({
592
- ...EMBEDDED_SMS_CREATIVES_EDIT_LOCATION,
593
- pathname: '/sms/edit',
594
- query: embeddedQueryBase,
595
- }), [embeddedQueryBase]);
596
-
597
- /** Bumped when the user dismisses the slidebox or navigates away; in-flight getTemplateDetails ignores stale completions. */
598
- const templateDetailsFetchGenerationRef = useRef(0);
599
-
600
- // resetRef: lets the SELECTING useEffect call the latest templateList.reset without
601
- // adding it as a dep (which would re-run the effect on every templateList update).
602
- const didInitialFetchRef = useRef(false);
603
- const resetRef = useRef(templateList.reset);
604
- resetRef.current = templateList.reset;
605
- useEffect(() => {
606
- if (view !== SMS_FALLBACK_VIEW.SELECTING) {
607
- didInitialFetchRef.current = false;
608
- return;
609
- }
610
- if (didInitialFetchRef.current) return;
611
- didInitialFetchRef.current = true;
612
- resetRef.current();
613
- }, [view]);
614
-
615
- const openSelector = useCallback(() => {
616
- slideboxDispatch({ type: SMS_FALLBACK_ACTIONS.OPEN_SELECTOR });
617
- }, []);
618
-
619
- const closeSlidebox = useCallback(() => {
620
- clearTemplateSearchDebounce();
621
- templateDetailsFetchGenerationRef.current += 1;
622
- slideboxDispatch({ type: SMS_FALLBACK_ACTIONS.CLOSE });
623
- }, [clearTemplateSearchDebounce]);
624
-
625
- const goBackToTemplateList = useCallback(() => {
626
- clearTemplateSearchDebounce();
627
- templateDetailsFetchGenerationRef.current += 1;
628
- slideboxDispatch({ type: SMS_FALLBACK_ACTIONS.GO_BACK_TO_LIST });
629
- templateList.reset();
630
- }, [clearTemplateSearchDebounce, templateList]);
631
-
632
- const showLiquidErrorInFooter = useCallback((errorMessagesFromFormBuilder, currentFormBuilderTab) => {
633
- const next = computeLiquidFooterUpdateFromFormBuilder(errorMessagesFromFormBuilder, liquidErrorMessage, currentFormBuilderTab, {
634
- previousIsLiquidValidationError: isLiquidValidationError,
635
- currentChannelUpper: SMS,
636
- });
637
- if (next == null) return;
638
- slideboxDispatch({ type: SMS_FALLBACK_ACTIONS.SET_LIQUID_ERROR, liquidErrorMessage: next.liquidErrorMessage, isLiquidValidationError: next.isLiquidValidationError });
639
- }, [isLiquidValidationError, liquidErrorMessage]);
640
-
641
- const onValidationFail = useCallback(() => {
642
- slideboxDispatch({ type: SMS_FALLBACK_ACTIONS.SET_IS_GET_FORM_DATA, payload: false });
643
- }, []);
644
-
645
- const saveMessage = useCallback(() => {
646
- slideboxDispatch({ type: SMS_FALLBACK_ACTIONS.SET_IS_GET_FORM_DATA, payload: true });
647
- }, []);
648
-
649
- const handleFooterTestAndPreview = useCallback(() => {
650
- slideboxDispatch({ type: SMS_FALLBACK_ACTIONS.OPEN_TEST_PREVIEW });
651
- }, []);
652
-
653
- const handleCloseTestAndPreview = useCallback(() => {
654
- slideboxDispatch({ type: SMS_FALLBACK_ACTIONS.CLOSE_TEST_PREVIEW });
655
- }, []);
656
-
657
- const handleEmbeddedSmsFooterValidity = useCallback((validity) => {
658
- const { isTemplateNameEmpty, isMessageEmpty } = validity || {};
659
- slideboxDispatch({ type: SMS_FALLBACK_ACTIONS.SET_CREATE_FIELDS_INVALID, payload: !!isTemplateNameEmpty || !!isMessageEmpty });
660
- }, []);
661
-
662
- // Stable no-ops for SmsWrapper props that have no meaningful implementation in fallback context.
663
- // Must be stable refs — SmsCreate's componentWillReceiveProps calls setIsLoadingContent(true)
664
- // whenever it detects a prop reference change, so any inline arrow here restarts the loading cycle.
665
- const getLiquidTagsNoop = useCallback(() => {}, []);
666
- const onPreviewContentClickedNoop = useCallback(() => {}, []);
667
- const onTestContentClickedNoop = useCallback(() => {}, []);
668
- const emptyForwardedTags = useMemo(() => ({}), []);
669
- const stableEventContextTags = useMemo(() => eventContextTags ?? [], [eventContextTags]);
670
-
671
- // Stable reference required: SmsCreate calls setIsLoadingContent(true) in componentWillReceiveProps
672
- // when it detects a prop change. An inline arrow would create a new reference every render,
673
- // causing SmsCreate to keep resetting loading to true and the footer to never appear.
674
- const setIsLoadingContent = useCallback((v) => {
675
- slideboxDispatch({ type: SMS_FALLBACK_ACTIONS.SET_LOADING_CONTENT, payload: v });
676
- }, []);
677
-
678
- const openSmsCreate = useCallback(() => {
679
- clearTemplateSearchDebounce();
680
- templateDetailsFetchGenerationRef.current += 1;
681
- slideboxDispatch({ type: SMS_FALLBACK_ACTIONS.OPEN_CREATING });
682
- }, [clearTemplateSearchDebounce]);
683
-
684
- const handleSelectTemplate = useCallback(
685
- async (template) => {
686
- if (!template) return;
687
- const templateId = template._id;
688
- if (!templateId) {
689
- slideboxDispatch({ type: SMS_FALLBACK_ACTIONS.SELECT_TEMPLATE_DONE, payload: buildFallbackDataFromTemplate(template) });
690
- return;
691
- }
692
- const fetchGeneration = ++templateDetailsFetchGenerationRef.current;
693
- slideboxDispatch({ type: SMS_FALLBACK_ACTIONS.SELECT_TEMPLATE_START });
694
- try {
695
- const result = await Api.getTemplateDetails({ id: templateId, channel: SMS_TEMPLATE_DETAILS_API_CHANNEL });
696
- if (fetchGeneration !== templateDetailsFetchGenerationRef.current) return;
697
- slideboxDispatch({
698
- type: SMS_FALLBACK_ACTIONS.SELECT_TEMPLATE_DONE,
699
- payload: buildFallbackDataFromTemplate(get(result, 'response', template)),
700
- });
701
- } catch (err) {
702
- if (fetchGeneration !== templateDetailsFetchGenerationRef.current) return;
703
- slideboxDispatch({ type: SMS_FALLBACK_ACTIONS.SELECT_TEMPLATE_DONE, payload: buildFallbackDataFromTemplate(template) });
704
- } finally {
705
- if (fetchGeneration === templateDetailsFetchGenerationRef.current) {
706
- slideboxDispatch({ type: SMS_FALLBACK_ACTIONS.SET_FETCH_LOADING, payload: false });
707
- }
708
- }
709
- },
710
- []
711
- );
712
-
713
- /**
714
- * Non-Trai SMS create: FormBuilder submits here. Parent `onChange` updates RCS fallback state.
715
- * Do **not** call `onCreateComplete` — in Creatives-embedded Rcs it is `getCreativesData`, which would
716
- * finish the whole creative flow and send the user back to the templates list while RCS edit is still open.
717
- */
718
- const handleSmsCreateFormSubscription = useCallback(
719
- (formPayload) => {
720
- if (!formPayload?.validity) return;
721
- const base = get(formPayload, 'value.base', {});
722
- const smsEditor = base['sms-editor'] || '';
723
- const templateName = base['template-name'] || base.template_name || '';
724
- const nameOk = String(templateName || '').trim();
725
- const bodyOk = String(smsEditor || '').trim();
726
- if (!nameOk || !bodyOk) {
727
- slideboxDispatch({ type: SMS_FALLBACK_ACTIONS.SET_IS_GET_FORM_DATA, payload: false });
728
- return;
729
- }
730
- slideboxDispatch({ type: SMS_FALLBACK_ACTIONS.SET_IS_GET_FORM_DATA, payload: false });
731
- onChange({
732
- ...(value && typeof value === 'object' ? value : {}),
733
- templateName: nameOk,
734
- content: smsEditor,
735
- templateContent: smsEditor,
736
- unicodeValidity: typeof base['unicode-validity'] === JS_TYPE_BOOLEAN
737
- ? base['unicode-validity']
738
- : true,
739
- });
740
- closeSlidebox();
741
- },
742
- [onChange, closeSlidebox, value],
743
- );
744
-
745
- const handleSmsTraiCreateComplete = useCallback((uploadedTemplate) => {
746
- if (uploadedTemplate) {
747
- const base = uploadedTemplate.versions?.base || {};
748
- const content = base.template_message || base['sms-editor'] || '';
749
- const templateName = uploadedTemplate.name || base.template_name || '';
750
- if (content || templateName) {
751
- onChange({
752
- templateName,
753
- content,
754
- templateContent: content,
755
- unicodeValidity: typeof base['unicode-validity'] === JS_TYPE_BOOLEAN
756
- ? base['unicode-validity']
757
- : true,
758
- });
759
- }
760
- }
761
- closeSlidebox();
762
- }, [onChange, closeSlidebox]);
763
-
764
- /** Embedded template picker: map Creatives payload into fallback value. Same rule as create — no `onCreateComplete`. */
765
- const handleEmbeddedCreativesSave = useCallback(
766
- (creativesData) => {
767
- const next = buildFallbackDataFromCreativesPayload(creativesData);
768
- if (!next) return;
769
- onChange(next);
770
- closeSlidebox();
771
- },
772
- [onChange, closeSlidebox],
773
- );
774
-
775
- const handleEditComplete = useCallback(
776
- (formData, skipClose) => {
777
- const { base } = getBaseFromSmsTraiFormData(formData);
778
- const smsEditor = base['sms-editor'] || '';
779
- const baseForSave = pendingFallbackData || value;
780
- const rcsFallbackVarMappedFromBase = base['rcs-sms-fallback-var-mapped'];
781
- onChange({
782
- ...baseForSave,
783
- content: resolveContentFromTraiBase(base),
784
- templateContent: smsEditor,
785
- unicodeValidity: typeof base['unicode-validity'] === JS_TYPE_BOOLEAN
786
- ? base['unicode-validity']
787
- : baseForSave?.unicodeValidity,
788
- ...(Object.prototype.hasOwnProperty.call(base, 'rcs-sms-fallback-var-mapped')
789
- && rcsFallbackVarMappedFromBase != null
790
- && typeof rcsFallbackVarMappedFromBase === 'object'
791
- ? { rcsSmsFallbackVarMapped: rcsFallbackVarMappedFromBase }
792
- : {}),
793
- });
794
- if (!skipClose) closeSlidebox();
795
- },
796
- [onChange, closeSlidebox, value, pendingFallbackData]
797
- );
798
-
799
- const handleRemove = useCallback(() => {
800
- onChange(null);
801
- }, [onChange]);
802
-
803
- const handleEdit = useCallback(() => {
804
- if (!value) return;
805
- slideboxDispatch({ type: SMS_FALLBACK_ACTIONS.OPEN_EDITING });
806
- }, [value]);
807
-
808
- const extra = value
809
- ? [
810
- <CapDropdown
811
- key="more"
812
- data-testid="test-rcs-sms-fallback-template-more"
813
- overlay={
814
- <CapMenu>
815
- <CapMenu.Item data-testid="test-rcs-sms-fallback-edit" className="ant-dropdown-menu-item" onClick={handleEdit}>
816
- {formatMessage(messages.editTemplate)}
817
- </CapMenu.Item>
818
- <CapMenu.Item data-testid="test-rcs-sms-fallback-delete" className="ant-dropdown-menu-item" onClick={handleRemove}>
819
- {formatMessage(messages.removeTemplate)}
820
- </CapMenu.Item>
821
- </CapMenu>
822
- }
823
- >
824
- <CapIcon type="more" />
825
- </CapDropdown>,
826
- ]
827
- : [];
828
-
829
- const cardData = value
830
- ? {
831
- title: value.templateName?.trim()
832
- ? value.templateName
833
- : formatMessage(messages.fallbackCardUntitled),
834
- content: getSmsFallbackCardDisplayContent(value),
835
- cardType: SMS,
836
- extra,
837
- }
838
- : null;
839
-
840
- return (
841
- <>
842
- <CapRow className="sms-fallback-header-row">
843
- <CapHeader
844
- title={
845
- <CapHeading type="h4">
846
- {value
847
- ? (sectionTitle ?? formatMessage(messages.sectionTitleWithoutOptional))
848
- : (sectionTitle ?? formatMessage(messages.sectionTitle))}
849
- </CapHeading>
850
- }
851
- />
852
- </CapRow>
853
-
854
- {!value ? (
855
- <CapRow className="sms-fallback-select-wrap">
856
- <CapButton
857
- type="flat"
858
- data-testid="test-rcs-sms-fallback-select-template"
859
- className="sms-fallback-select-btn rcs-sms-fallback-select-btn"
860
- onClick={openSelector}
861
- disabled={disableSelectTemplate}
862
- >
863
- {formatMessage(messages.selectTemplate)}
864
- </CapButton>
865
- </CapRow>
866
- ) : showAsCard ? (
867
- <CapRow>
868
- <div className="sms-fallback-card-wrap">
869
- <CapCustomCard.CapCustomCardList cardList={[cardData]} className="sms-fallback-card rcs-sms-fallback-card" type={SMS} />
870
- </div>
871
- </CapRow>
872
- ) : (
873
- <CapRow className="sms-fallback-inline-editor">
874
- <SmsFallbackEditForm
875
- skipCloseOnSave
876
- value={value}
877
- view={view}
878
- embeddedEditLocation={embeddedEditLocation}
879
- closeSlidebox={closeSlidebox}
880
- handleEditComplete={handleEditComplete}
881
- isRcsEditFlow={isRcsEditFlow}
882
- isFullMode={isFullMode}
883
- smsRegister={smsRegister}
884
- selectedOfferDetails={selectedOfferDetails}
885
- eventContextTags={eventContextTags}
886
- onRcsFallbackEditorStateChange={onRcsFallbackEditorStateChange}
887
- />
888
- </CapRow>
889
- )}
890
-
891
- {view && ReactDOM.createPortal(
892
- <SmsFallbackPortalContent
893
- slideboxState={slideboxState}
894
- slideboxDispatch={slideboxDispatch}
895
- value={value}
896
- channelsToHide={channelsToHide}
897
- smsRegister={smsRegister}
898
- isFullMode={isFullMode}
899
- selectedOfferDetails={selectedOfferDetails}
900
- eventContextTags={stableEventContextTags}
901
- isRcsEditFlow={isRcsEditFlow}
902
- onRcsFallbackEditorStateChange={onRcsFallbackEditorStateChange}
903
- intl={intl}
904
- embeddedCreateLocation={embeddedCreateLocation}
905
- embeddedEditLocation={embeddedEditLocation}
906
- templateListForSelector={templateListForSelector}
907
- templateList={templateList}
908
- scheduleTemplateListSearch={scheduleTemplateListSearch}
909
- flushTemplateListSearch={flushTemplateListSearch}
910
- slideBoxWrapperMargin={slideBoxWrapperMargin}
911
- closeSlidebox={closeSlidebox}
912
- goBackToTemplateList={goBackToTemplateList}
913
- handleSelectTemplate={handleSelectTemplate}
914
- handleEmbeddedCreativesSave={handleEmbeddedCreativesSave}
915
- openSmsCreate={openSmsCreate}
916
- showLiquidErrorInFooter={showLiquidErrorInFooter}
917
- saveMessage={saveMessage}
918
- handleFooterTestAndPreview={handleFooterTestAndPreview}
919
- handleCloseTestAndPreview={handleCloseTestAndPreview}
920
- handleEmbeddedSmsFooterValidity={handleEmbeddedSmsFooterValidity}
921
- onValidationFail={onValidationFail}
922
- handleSmsTraiCreateComplete={handleSmsTraiCreateComplete}
923
- handleSmsCreateFormSubscription={handleSmsCreateFormSubscription}
924
- handleEditComplete={handleEditComplete}
925
- setIsLoadingContent={setIsLoadingContent}
926
- getLiquidTags={getLiquidTagsNoop}
927
- forwardedTags={emptyForwardedTags}
928
- onPreviewContentClicked={onPreviewContentClickedNoop}
929
- onTestContentClicked={onTestContentClickedNoop}
930
- />,
931
- document.body,
932
- )}
933
- </>
934
- );
935
- }
936
-
937
- SmsFallback.propTypes = {
938
- dispatch: PropTypes.func,
939
- value: PropTypes.object,
940
- onChange: PropTypes.func.isRequired,
941
- smsRegister: PropTypes.any,
942
- selectedOfferDetails: PropTypes.object,
943
- onPreviewTemplate: PropTypes.func,
944
- channelsToHide: PropTypes.arrayOf(PropTypes.string),
945
- sectionTitle: PropTypes.node,
946
- templateListTitle: PropTypes.node,
947
- templateListDescription: PropTypes.node,
948
- intl: PropTypes.object.isRequired,
949
- showAsCard: PropTypes.bool,
950
- disableSelectTemplate: PropTypes.bool,
951
- eventContextTags: PropTypes.array,
952
- isFullMode: PropTypes.bool,
953
- onRcsFallbackEditorStateChange: PropTypes.func,
954
- parentLocation: PropTypes.object,
955
- isRcsEditFlow: PropTypes.bool,
956
- };
957
-
958
- export default connect()(injectIntl(SmsFallback));