@capillarytech/creatives-library 7.12.1 → 7.12.5

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 (57) hide show
  1. package/index.js +6 -0
  2. package/package.json +1 -1
  3. package/routes.js +7 -2
  4. package/services/api.js +8 -2
  5. package/v2Components/CapImageUpload/index.js +24 -11
  6. package/v2Components/CapImageUpload/index.scss +12 -27
  7. package/v2Components/CapImageUpload/messages.js +10 -5
  8. package/v2Components/TemplatePreview/_templatePreview.scss +13 -0
  9. package/v2Components/TemplatePreview/index.js +39 -1
  10. package/v2Components/TemplatePreview/tests/__snapshots__/index.test.js.snap +33 -1
  11. package/v2Components/TemplatePreview/tests/index.test.js +7 -7
  12. package/v2Containers/App/constants.js +2 -1
  13. package/v2Containers/Assets/images/addCreativesIllustration.svg +30 -0
  14. package/v2Containers/Cap/messages.js +20 -1
  15. package/v2Containers/CreativesContainer/SlideBoxContent.js +57 -11
  16. package/v2Containers/CreativesContainer/SlideBoxHeader.js +5 -2
  17. package/v2Containers/CreativesContainer/constants.js +1 -0
  18. package/v2Containers/CreativesContainer/messages.js +4 -0
  19. package/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +24 -4
  20. package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +23 -4
  21. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +147 -2
  22. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +99 -1
  23. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +71 -0
  24. package/v2Containers/CreativesContainer/tests/index.test.js +21 -9
  25. package/v2Containers/Facebook/Advertisement/index.js +4 -2
  26. package/v2Containers/Rcs/actions.js +57 -0
  27. package/v2Containers/Rcs/constants.js +51 -0
  28. package/v2Containers/Rcs/index.js +1064 -0
  29. package/v2Containers/Rcs/index.scss +72 -0
  30. package/v2Containers/Rcs/messages.js +122 -0
  31. package/v2Containers/Rcs/reducer.js +107 -0
  32. package/v2Containers/Rcs/sagas.js +141 -0
  33. package/v2Containers/Rcs/selectors.js +8 -0
  34. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +145080 -0
  35. package/v2Containers/Rcs/tests/index.test.js +226 -0
  36. package/v2Containers/Rcs/tests/mockData.js +169 -0
  37. package/v2Containers/Rcs/utils.js +40 -0
  38. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4 -4
  39. package/v2Containers/Templates/_templates.scss +9 -1
  40. package/v2Containers/Templates/actions.js +2 -1
  41. package/v2Containers/Templates/constants.js +1 -0
  42. package/v2Containers/Templates/index.js +235 -174
  43. package/v2Containers/Templates/messages.js +20 -0
  44. package/v2Containers/Templates/reducer.js +2 -0
  45. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +520 -80
  46. package/v2Containers/TemplatesV2/index.js +2 -1
  47. package/v2Containers/TemplatesV2/messages.js +4 -0
  48. package/v2Containers/Whatsapp/constants.js +287 -0
  49. package/v2Containers/Whatsapp/index.js +39 -25
  50. package/v2Containers/Whatsapp/index.scss +3 -2
  51. package/v2Containers/Whatsapp/messages.js +284 -13
  52. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +35583 -1700
  53. package/v2Containers/Whatsapp/tests/__snapshots__/utils.test.js.snap +32 -26
  54. package/v2Containers/Whatsapp/tests/index.test.js +13 -0
  55. package/v2Containers/Whatsapp/tests/utils.test.js +15 -8
  56. package/v2Containers/mockdata.js +1190 -2181
  57. package/v2Components/CallTaskPreview/tests/__snapshots__/index.test.js.snap +0 -30
@@ -0,0 +1,1064 @@
1
+ /* eslint-disable no-unused-expressions */
2
+ import React, { useState, useEffect, useCallback } from 'react';
3
+ import { bindActionCreators } from 'redux';
4
+ import { createStructuredSelector } from 'reselect';
5
+ import { injectIntl, FormattedMessage } from 'react-intl';
6
+ import { get, isEmpty, cloneDeep } from 'lodash';
7
+ import styled from 'styled-components';
8
+ import CapSpin from '@capillarytech/cap-ui-library/CapSpin';
9
+ import CapRow from '@capillarytech/cap-ui-library/CapRow';
10
+ import CapColumn from '@capillarytech/cap-ui-library/CapColumn';
11
+ import CapButton from '@capillarytech/cap-ui-library/CapButton';
12
+ import CapInput from '@capillarytech/cap-ui-library/CapInput';
13
+ import CapHeading from '@capillarytech/cap-ui-library/CapHeading';
14
+ import CapRadioGroup from '@capillarytech/cap-ui-library/CapRadioGroup';
15
+ import CapTooltip from '@capillarytech/cap-ui-library/CapTooltip';
16
+ import CapLabel from '@capillarytech/cap-ui-library/CapLabel';
17
+ import CapHeader from '@capillarytech/cap-ui-library/CapHeader';
18
+ import CapDivider from '@capillarytech/cap-ui-library/CapDivider';
19
+ import CapIcon from '@capillarytech/cap-ui-library/CapIcon';
20
+ import CapImage from '@capillarytech/cap-ui-library/CapImage';
21
+ import CapCard from '@capillarytech/cap-ui-library/CapCard';
22
+ import CapSlideBox from '@capillarytech/cap-ui-library/CapSlideBox';
23
+ import CapCustomCard from '@capillarytech/cap-ui-library/CapCustomCard';
24
+ import CapDropdown from '@capillarytech/cap-ui-library/CapDropdown';
25
+ import CapMenu from '@capillarytech/cap-ui-library/CapMenu';
26
+ import CapNotification from '@capillarytech/cap-ui-library/CapNotification';
27
+ import CapTooltipWithInfo from '@capillarytech/cap-ui-library/CapTooltipWithInfo';
28
+ import CapError from '@capillarytech/cap-ui-library/CapError';
29
+ import {
30
+ CAP_G01,
31
+ CAP_SPACE_16,
32
+ CAP_SPACE_24,
33
+ CAP_SPACE_28,
34
+ CAP_SPACE_32,
35
+ CAP_WHITE,
36
+ CAP_SECONDARY,
37
+ } from '@capillarytech/cap-ui-library/styled/variables';
38
+ import { makeSelectRcs } from './selectors';
39
+ import {
40
+ isLoadingMetaEntities,
41
+ makeSelectMetaEntities,
42
+ setInjectedTags,
43
+ } from '../Cap/selectors';
44
+ import * as RcsActions from './actions';
45
+ import * as TemplatesActions from '../Templates/actions';
46
+ import './index.scss';
47
+ import {
48
+ RCS,
49
+ SMS,
50
+ RCS_MEDIA_TYPES,
51
+ TEMPLATE_TITLE_MAX_LENGTH,
52
+ TEMPLATE_DESC_MAX_LENGTH,
53
+ FALLBACK_MESSAGE_MAX_LENGTH,
54
+ TAG,
55
+ EMBEDDED,
56
+ DEFAULT,
57
+ FULL,
58
+ ALL,
59
+ LIBRARY,
60
+ ALLOWED_IMAGE_EXTENSIONS_REGEX,
61
+ RCS_IMG_WIDTH,
62
+ RCS_IMG_HEIGHT,
63
+ RCS_IMG_SIZE,
64
+ RCS_DLT_MODE,
65
+ MEDIUM,
66
+ VERTICAL,
67
+ RIGHT,
68
+ STANDALONE,
69
+ RICHCARD,
70
+ } from './constants';
71
+ import globalMessages from '../Cap/messages';
72
+ import messages from './messages';
73
+ import withCreatives from '../../hoc/withCreatives';
74
+ import TemplatePreview from '../../v2Components/TemplatePreview';
75
+ import CapImageUpload from '../../v2Components/CapImageUpload';
76
+ import addCreativesIcon from '../Assets/images/addCreativesIllustration.svg';
77
+ import Templates from '../Templates';
78
+ import SmsTraiEdit from '../SmsTrai/Edit';
79
+ import TagList from '../TagList';
80
+ import { validateTags } from '../../utils/tagValidations';
81
+ export const Rcs = (props) => {
82
+ const {
83
+ intl,
84
+ actions,
85
+ isFullMode,
86
+ onCreateComplete,
87
+ params,
88
+ templateData = {},
89
+ rcsData = {},
90
+ templatesActions,
91
+ globalActions,
92
+ location,
93
+ getDefaultTags,
94
+ supportedTags,
95
+ metaEntities,
96
+ injectedTags,
97
+ loadingTags,
98
+ getFormData,
99
+ isDltEnabled,
100
+ smsRegister,
101
+ } = props || {};
102
+ const { formatMessage } = intl;
103
+ const { TextArea } = CapInput;
104
+ const { CapCustomCardList } = CapCustomCard;
105
+ const [isEditFlow, setEditFlow] = useState(false);
106
+ const [tags, updateTags] = useState([]);
107
+ const [rcsImageSrc, updateRcsImageSrc] = useState('');
108
+ const [spin, setSpin] = useState(false);
109
+ //template
110
+ const [templateName, setTemplateName] = useState('');
111
+ const [templateNameError, setTemplateNameError] = useState(false);
112
+ const [templateMediaType, setTemplateMediaType] = useState(
113
+ RCS_MEDIA_TYPES.NONE,
114
+ );
115
+ const [templateTitle, setTemplateTitle] = useState('');
116
+ const [templateDesc, setTemplateDesc] = useState('');
117
+ const [templateDescError, setTemplateDescError] = useState(false);
118
+ //fallback
119
+ const [fallbackMessage, setFallbackMessage] = useState('');
120
+ const [fallbackMessageError, setFallbackMessageError] = useState(false);
121
+ //fallback dlt
122
+ const [showDltContainer, setShowDltContainer] = useState(false);
123
+ const [dltMode, setDltMode] = useState('');
124
+ const [dltEditData, setDltEditData] = useState({});
125
+ const [showDltCard, setShowDltCard] = useState(false);
126
+ const [fallbackPreviewmode, setFallbackPreviewmode] = useState(false);
127
+ const [dltPreviewData, setDltPreviewData] = useState('');
128
+
129
+ const mediaRadioOptions = [
130
+ {
131
+ value: RCS_MEDIA_TYPES.NONE,
132
+ label: formatMessage(messages.mediaNone),
133
+ },
134
+ {
135
+ value: RCS_MEDIA_TYPES.IMAGE,
136
+ label: formatMessage(messages.mediaImage),
137
+ },
138
+ {
139
+ value: RCS_MEDIA_TYPES.VIDEO,
140
+ label: (
141
+ <CapTooltip title={formatMessage(messages.disabledMediaTooltip)}>
142
+ {formatMessage(messages.mediaVideo)}
143
+ </CapTooltip>
144
+ ),
145
+ disabled: true,
146
+ },
147
+ ];
148
+
149
+ const isMediaTypeNone = templateMediaType === RCS_MEDIA_TYPES.NONE;
150
+ const RcsFooter = styled.div`
151
+ background-color: ${CAP_WHITE};
152
+ position: fixed;
153
+ bottom: 0;
154
+ width: 100%;
155
+ margin-left: -32px;
156
+ padding: ${CAP_SPACE_32} ${CAP_SPACE_24};
157
+
158
+ .ant-btn {
159
+ margin-right: ${CAP_SPACE_16};
160
+ }
161
+ }
162
+ `;
163
+
164
+ const RcsLabel = styled.div`
165
+ display: flex;
166
+ margin-top: 20px;
167
+ margin-bottom: 6px;
168
+ `;
169
+
170
+ //gets template details
171
+ const paramObj = params || {};
172
+ useEffect(() => {
173
+ const { id } = paramObj;
174
+ if (id && isFullMode) {
175
+ setSpin(true);
176
+ actions.getTemplateDetails(id, setSpin);
177
+ }
178
+ //cleanup code
179
+ return () => {
180
+ actions.clearEditResponse();
181
+ };
182
+ }, [paramObj.id]);
183
+
184
+ useEffect(() => {
185
+ const { name = '', versions = {} } = isFullMode
186
+ ? rcsData.templateDetails || {}
187
+ : templateData || {};
188
+ const editContent = get(versions, `base.content.RCS`, {});
189
+ if (!isEmpty(editContent)) {
190
+ const { cardContent = [], smsFallBackContent = {} } = editContent;
191
+ const {
192
+ media: { mediaUrl = '' } = {},
193
+ mediaType = '',
194
+ title = '',
195
+ description = '',
196
+ } = cardContent[0] || {};
197
+ const { message, templateConfigs = {} } = smsFallBackContent;
198
+ setTemplateName(name);
199
+ setTemplateMediaType(mediaType);
200
+ updateRcsImageSrc(mediaUrl);
201
+ setTemplateTitle(title);
202
+ setTemplateDesc(description);
203
+ setFallbackMessage(message);
204
+ setEditFlow(true);
205
+ // for DLT Fallback message
206
+ if (isDltEnabled) {
207
+ const {
208
+ registeredSenderIds: header = [],
209
+ template = {},
210
+ templateId = '',
211
+ templateName: tmpName = '',
212
+ templateVariableMapping = {},
213
+ } = templateConfigs;
214
+ if (header.length > 0) {
215
+ const tempData = {
216
+ versions: {
217
+ base: {
218
+ header,
219
+ 'template_id': templateId,
220
+ 'template_name': tmpName,
221
+ 'sms-editor': template,
222
+ 'var-mapped': templateVariableMapping,
223
+ },
224
+ },
225
+ };
226
+ setDltEditData(tempData);
227
+ setShowDltCard(true);
228
+ } else {
229
+ setShowDltCard(false);
230
+ }
231
+ }
232
+ }
233
+ }, [rcsData.templateDetails || templateData]);
234
+
235
+ // tag Code start from here
236
+ useEffect(() => {
237
+ if (!showDltContainer) {
238
+ //fetching tags
239
+ const { type, module } = location.query || {};
240
+ const isEmbedded = type === EMBEDDED;
241
+ const context = isEmbedded ? module : DEFAULT;
242
+ const embedded = isEmbedded ? type : FULL;
243
+ const query = {
244
+ layout: SMS,
245
+ type: TAG,
246
+ context,
247
+ embedded,
248
+ };
249
+ if (getDefaultTags) {
250
+ query.context = getDefaultTags;
251
+ }
252
+ globalActions.fetchSchemaForEntity(query);
253
+ }
254
+ }, [showDltContainer]);
255
+
256
+ useEffect(() => {
257
+ let tag = get(metaEntities, `tags.standard`, []);
258
+ const { type, module } = location.query || {};
259
+ if (type === EMBEDDED && module === LIBRARY && !getDefaultTags) {
260
+ tag = supportedTags;
261
+ }
262
+ updateTags(tag);
263
+ }, [metaEntities]);
264
+
265
+ const handleOnTagsContextChange = (data) => {
266
+ const { type } = location.query || {};
267
+ const tempData = (data || '').toLowerCase();
268
+ const isEmbedded = type === EMBEDDED;
269
+ const embedded = isEmbedded ? type : FULL;
270
+ const context = tempData === ALL ? DEFAULT : tempData;
271
+ const query = {
272
+ layout: SMS,
273
+ type: TAG,
274
+ context,
275
+ embedded,
276
+ };
277
+ globalActions.fetchSchemaForEntity(query);
278
+ };
279
+
280
+ const onTagSelect = (data) => {
281
+ const tempMsg = `${templateDesc}{{${data}}}`;
282
+ const error = templateDescErrorHandler(tempMsg);
283
+ setTemplateDesc(tempMsg);
284
+ setTemplateDescError(error);
285
+ };
286
+
287
+ const onTagSelectFallback = (data) => {
288
+ const tempMsg = `${fallbackMessage}{{${data}}}`;
289
+ const error = fallbackMessageErrorHandler(tempMsg);
290
+ setFallbackMessage(tempMsg);
291
+ setFallbackMessageError(error);
292
+ };
293
+
294
+ //removing optout tag for rcs
295
+ const getRcsTags = () => {
296
+ const tempTags = cloneDeep(tags);
297
+ // eslint-disable-next-line no-undef
298
+ if (tempTags?.length > 0 && tempTags[0]?.definition?.value === 'optout') {
299
+ tempTags.shift();
300
+ }
301
+ return tempTags;
302
+ };
303
+ // tag Code end
304
+
305
+ const renderLabel = (value, showLabel) => (
306
+ <RcsLabel>
307
+ <CapHeading type="h4">{formatMessage(messages[value])}</CapHeading>
308
+ {showLabel && (
309
+ <CapHeading type="h4" className="rcs-optional-label">
310
+ {formatMessage(messages.optional)}
311
+ </CapHeading>
312
+ )}
313
+ </RcsLabel>
314
+ );
315
+
316
+ const onTemplateNameChange = ({ target: { value } }) => {
317
+ setTemplateName(value);
318
+ templateNameErrorHandler(value);
319
+ };
320
+
321
+ const templateNameErrorHandler = (value) => {
322
+ let errorMessage = false;
323
+ if (value === '') {
324
+ errorMessage = formatMessage(
325
+ globalMessages.emptyTemplateNameErrorMessage,
326
+ );
327
+ }
328
+ setTemplateNameError(errorMessage);
329
+ };
330
+
331
+ const onTemplateMediaTypeChange = ({ target: { value } }) => {
332
+ setTemplateMediaType(value);
333
+ if (templateDesc.trim() === '') {
334
+ setTemplateDescError(false);
335
+ }
336
+ };
337
+
338
+ const onTemplateTitleChange = ({ target: { value } }) => {
339
+ setTemplateTitle(value);
340
+ };
341
+
342
+ const onTemplateDescChange = ({ target: { value } }) => {
343
+ const error = templateDescErrorHandler(value);
344
+ setTemplateDesc(value);
345
+ setTemplateDescError(error);
346
+ };
347
+
348
+ const templateDescErrorHandler = (value) => {
349
+ let errorMessage = false;
350
+ const { unsupportedTags } =
351
+ validateTags({
352
+ content: value,
353
+ tagsParam: tags,
354
+ injectedTagsParams: injectedTags,
355
+ location,
356
+ tagModule: getDefaultTags,
357
+ }) || {};
358
+ if (value === '' && isMediaTypeNone) {
359
+ errorMessage = formatMessage(messages.emptyTemplateDescErrorMessage);
360
+ } else if (value?.length > TEMPLATE_DESC_MAX_LENGTH) {
361
+ errorMessage = formatMessage(messages.templateDescLengthError);
362
+ } else if (unsupportedTags?.length > 0) {
363
+ errorMessage = formatMessage(
364
+ globalMessages.unsupportedTagsValidationError,
365
+ {
366
+ unsupportedTags,
367
+ },
368
+ );
369
+ }
370
+ return errorMessage;
371
+ };
372
+
373
+ const onFallbackMessageChange = ({ target: { value } }) => {
374
+ const error = fallbackMessageErrorHandler(value);
375
+ setFallbackMessage(value);
376
+ setFallbackMessageError(error);
377
+ };
378
+
379
+ const fallbackMessageErrorHandler = (value) => {
380
+ let errorMessage = false;
381
+ const { unsupportedTags } =
382
+ validateTags({
383
+ content: value,
384
+ tagsParam: tags,
385
+ injectedTagsParams: injectedTags,
386
+ location,
387
+ tagModule: getDefaultTags,
388
+ }) || {};
389
+ if (value?.length > FALLBACK_MESSAGE_MAX_LENGTH) {
390
+ errorMessage = formatMessage(messages.fallbackMsgLenError);
391
+ } else if (unsupportedTags?.length > 0) {
392
+ errorMessage = formatMessage(
393
+ globalMessages.unsupportedTagsValidationError,
394
+ {
395
+ unsupportedTags,
396
+ },
397
+ );
398
+ }
399
+ return errorMessage;
400
+ };
401
+
402
+ const renderTextComponent = (
403
+ <>
404
+ {/* template title */}
405
+ {renderLabel('templateTitle', true)}
406
+ <CapInput
407
+ id="rcs-template-title-input"
408
+ onChange={onTemplateTitleChange}
409
+ placeholder={formatMessage(messages.templateTitlePlaceholder)}
410
+ value={templateTitle || ''}
411
+ size="default"
412
+ maxLength={TEMPLATE_TITLE_MAX_LENGTH}
413
+ suffix={
414
+ <CapLabel type="label1">{`${templateTitle.length} / ${TEMPLATE_TITLE_MAX_LENGTH}`}</CapLabel>
415
+ }
416
+ />
417
+ {/* template message */}
418
+ <CapRow id="rcs-template-message-label">
419
+ <CapHeader
420
+ title={
421
+ <CapRow type="flex">
422
+ <CapHeading type="h4">
423
+ {formatMessage(messages.templateDescLabel)}
424
+ </CapHeading>
425
+ {!isMediaTypeNone && (
426
+ <CapHeading type="h4" className="rcs-optional-label">
427
+ {formatMessage(messages.optional)}
428
+ </CapHeading>
429
+ )}
430
+ </CapRow>
431
+ }
432
+ suffix={
433
+ <TagList
434
+ label={formatMessage(globalMessages.addLabels)}
435
+ onTagSelect={onTagSelect}
436
+ location={location}
437
+ tags={getRcsTags()}
438
+ onContextChange={handleOnTagsContextChange}
439
+ injectedTags={injectedTags || {}}
440
+ />
441
+ }
442
+ />
443
+ </CapRow>
444
+ <TextArea
445
+ id="rcs_template_message_textarea"
446
+ autosize={{ minRows: 3, maxRows: 5 }}
447
+ placeholder={formatMessage(messages.templateDescPlaceholder)}
448
+ onChange={onTemplateDescChange}
449
+ errorMessage={templateDescError}
450
+ value={templateDesc || ''}
451
+ maxLength={1000}
452
+ />
453
+ </>
454
+ );
455
+
456
+ const fallbackSmsLength = () => (
457
+ <CapLabel type="label1" className="fallback-sms-length">
458
+ {formatMessage(messages.totalCharacters, {
459
+ smsCount: Math.ceil(
460
+ fallbackMessage.length / FALLBACK_MESSAGE_MAX_LENGTH,
461
+ ),
462
+ number: fallbackMessage.length,
463
+ })}
464
+ </CapLabel>
465
+ );
466
+
467
+ //adding creative dlt fallback sms handlers
468
+ const addDltMsgHandler = () => {
469
+ setShowDltContainer(true);
470
+ setDltMode(RCS_DLT_MODE.TEMPLATES);
471
+ setDltEditData({});
472
+ setFallbackMessage('');
473
+ };
474
+
475
+ const closeDltContainerHandler = () => {
476
+ setShowDltContainer(false);
477
+ setDltMode('');
478
+ templatesActions.getAllTemplates('Rcs', { page: 1, perPage: 25 });
479
+ };
480
+
481
+ const rcsDltEditSelectHandler = (data) => {
482
+ setShowDltContainer(true);
483
+ setDltMode(RCS_DLT_MODE.EDIT);
484
+ setDltEditData(data);
485
+ };
486
+
487
+ const rcsDltEditCompletionHandler = (data) => {
488
+ const tempData = {
489
+ versions: {
490
+ // eslint-disable-next-line no-undef
491
+ base: data?.value?.base || {},
492
+ },
493
+ };
494
+ const fallMsg = get(tempData, `versions.base.updated-sms-editor`, []).join(
495
+ '',
496
+ );
497
+ closeDltContainerHandler();
498
+ setDltEditData(tempData);
499
+ setFallbackMessage(fallMsg);
500
+ setFallbackMessageError(fallMsg?.length > FALLBACK_MESSAGE_MAX_LENGTH);
501
+ setShowDltCard(true);
502
+ };
503
+
504
+ const rcsDltCardDeleteHandler = () => {
505
+ closeDltContainerHandler();
506
+ setDltEditData({});
507
+ setFallbackMessage('');
508
+ setFallbackMessageError(false);
509
+ setShowDltCard(false);
510
+ };
511
+
512
+ const dltFallbackListingPreviewhandler = (data) => {
513
+ const {
514
+ 'updated-sms-editor': updatedSmsEditor = [],
515
+ 'sms-editor': smsEditor = '',
516
+ } = data.versions.base || {};
517
+ setFallbackPreviewmode(true);
518
+ setDltPreviewData(
519
+ updatedSmsEditor === '' ? smsEditor : updatedSmsEditor.join(''),
520
+ );
521
+ };
522
+
523
+ const getDltContentCardList = (content, channel) => {
524
+ const extra = [
525
+ <CapIcon
526
+ type="edit"
527
+ style={{ marginRight: '8px' }}
528
+ onClick={() => rcsDltEditSelectHandler(dltEditData)}
529
+ />,
530
+ <CapDropdown
531
+ overlay={
532
+ <CapMenu>
533
+ <>
534
+ <CapMenu.Item
535
+ className="ant-dropdown-menu-item"
536
+ onClick={() => setFallbackPreviewmode(true)}
537
+ >
538
+ {formatMessage(globalMessages.preview)}
539
+ </CapMenu.Item>
540
+ <CapMenu.Item
541
+ className="ant-dropdown-menu-item"
542
+ onClick={rcsDltCardDeleteHandler}
543
+ >
544
+ {formatMessage(globalMessages.delete)}
545
+ </CapMenu.Item>
546
+ </>
547
+ </CapMenu>
548
+ }
549
+ >
550
+ <CapIcon type="more" />
551
+ </CapDropdown>,
552
+ ];
553
+ return {
554
+ title: channel,
555
+ content,
556
+ cardType: channel,
557
+ extra,
558
+ };
559
+ };
560
+
561
+ const getDltSlideBoxContent = () => {
562
+ const loc = {
563
+ pathname: `/sms/edit`,
564
+ query: { type: EMBEDDED, module: LIBRARY },
565
+ search: '',
566
+ };
567
+ const route = { name: SMS.toLowerCase() };
568
+ let dltHeader = '';
569
+ let dltContent = '';
570
+ if (dltMode === RCS_DLT_MODE.TEMPLATES) {
571
+ dltHeader = (
572
+ <CapHeader
573
+ title={formatMessage(messages.rcsDltTitle)}
574
+ description={formatMessage(messages.rcsDltDesc)}
575
+ />
576
+ );
577
+ dltContent = (
578
+ <Templates
579
+ location={loc}
580
+ route={route}
581
+ smsRegister={smsRegister}
582
+ isFullMode={isFullMode}
583
+ isDltFromRcs
584
+ onSelectTemplate={rcsDltEditSelectHandler}
585
+ handlePeviewTemplate={dltFallbackListingPreviewhandler}
586
+ />
587
+ );
588
+ } else if (dltMode === RCS_DLT_MODE.EDIT) {
589
+ dltHeader = formatMessage(messages.dltEditHeader);
590
+ dltContent = (
591
+ <SmsTraiEdit
592
+ location={loc}
593
+ route={route}
594
+ getDefaultTags="outbound"
595
+ handleClose={closeDltContainerHandler}
596
+ templateData={dltEditData}
597
+ getFormSubscriptionData={rcsDltEditCompletionHandler}
598
+ isFullMode={false}
599
+ />
600
+ );
601
+ }
602
+ return { dltHeader, dltContent };
603
+ };
604
+
605
+ const renderFallBackSmsComponent = () => {
606
+ const contentArr = [];
607
+ const showAddCreativeBtnForDlt = isDltEnabled && !showDltCard;
608
+ const showCardForDlt = isDltEnabled && showDltCard;
609
+ const showNonDltFallbackComp = !showAddCreativeBtnForDlt && !showCardForDlt;
610
+ //pushing common fallback sms headings
611
+ contentArr.push(
612
+ <CapRow
613
+ style={{
614
+ marginBottom: isDltEnabled ? '20px' : '10px',
615
+ }}
616
+ >
617
+ <CapHeader
618
+ title={
619
+ <CapRow type="flex">
620
+ <CapHeading type="h4">
621
+ {formatMessage(messages.fallbackLabel)}
622
+ </CapHeading>
623
+ <CapHeading type="h4" className="rcs-optional-label">
624
+ {formatMessage(messages.optional)}
625
+ </CapHeading>
626
+ <CapTooltipWithInfo
627
+ placement="right"
628
+ infoIconProps={{
629
+ style: { marginLeft: '4px', marginTop: '3px' },
630
+ }}
631
+ title={formatMessage(messages.fallbackToolTip)}
632
+ />
633
+ </CapRow>
634
+ }
635
+ description={formatMessage(messages.fallbackDesc)}
636
+ suffix={
637
+ isDltEnabled ? null : (
638
+ <CapButton
639
+ type="flat"
640
+ className="fallback-preview-btn"
641
+ prefix={<CapIcon type="eye" />}
642
+ style={{ color: CAP_SECONDARY.base }}
643
+ onClick={() => setFallbackPreviewmode(true)}
644
+ disabled={fallbackMessage === '' || fallbackMessageError}
645
+ >
646
+ {formatMessage(globalMessages.preview)}
647
+ </CapButton>
648
+ )
649
+ }
650
+ />
651
+ </CapRow>,
652
+ );
653
+
654
+ //dlt is enabled, and dlt content is not yet added, show button to add dlt creative
655
+ showAddCreativeBtnForDlt &&
656
+ contentArr.push(
657
+ <CapCard className="rcs-dlt-fallback-card">
658
+ <CapRow type="flex" justify="center" align="middle">
659
+ <CapColumn span={10}>
660
+ <CapImage src={addCreativesIcon} />
661
+ </CapColumn>
662
+ <CapColumn span={14}>
663
+ <CapButton
664
+ className="add-dlt-btn"
665
+ type="secondary"
666
+ onClick={addDltMsgHandler}
667
+ >
668
+ {formatMessage(messages.addSmsCreative)}
669
+ </CapButton>
670
+ </CapColumn>
671
+ </CapRow>
672
+ </CapCard>,
673
+ );
674
+
675
+ //dlt is enabled and dlt content is added, show it in a card
676
+ showCardForDlt &&
677
+ contentArr.push(
678
+ <CapCustomCardList
679
+ cardList={[getDltContentCardList(fallbackMessage, SMS)]}
680
+ className="rcs-dlt-card"
681
+ />,
682
+ fallbackMessageError && (
683
+ <CapError className="rcs-fallback-len-error">
684
+ {formatMessage(messages.fallbackMsgLenError)}
685
+ </CapError>
686
+ ),
687
+ );
688
+
689
+ //dlt is not enabled, show non dlt text area
690
+ showNonDltFallbackComp &&
691
+ contentArr.push(
692
+ <>
693
+ <CapRow>
694
+ <CapHeader
695
+ title={
696
+ <CapHeading type="h4">
697
+ {formatMessage(messages.fallbackTextAreaLabel)}
698
+ </CapHeading>
699
+ }
700
+ suffix={
701
+ <TagList
702
+ label={formatMessage(globalMessages.addLabels)}
703
+ onTagSelect={onTagSelectFallback}
704
+ location={location}
705
+ tags={tags || []}
706
+ onContextChange={handleOnTagsContextChange}
707
+ injectedTags={injectedTags || {}}
708
+ />
709
+ }
710
+ />
711
+ </CapRow>
712
+ <TextArea
713
+ id="rcs_fallback_message_textarea"
714
+ autosize={{ minRows: 3, maxRows: 5 }}
715
+ placeholder={formatMessage(messages.fallbackMsgPlaceholder)}
716
+ onChange={onFallbackMessageChange}
717
+ errorMessage={fallbackMessageError}
718
+ value={fallbackMessage || ''}
719
+ />
720
+ <CapRow>{fallbackSmsLength()}</CapRow>
721
+ </>,
722
+ );
723
+
724
+ return <>{contentArr}</>;
725
+ };
726
+
727
+ const uploadRcsImage = useCallback((file, type, fileParams) => {
728
+ actions.uploadRcsAsset(file, type, fileParams, 0);
729
+ }, []);
730
+
731
+ const setUpdateRcsImageSrc = useCallback(
732
+ (val) => {
733
+ updateRcsImageSrc(val);
734
+ actions.clearRcsAsset(0);
735
+ },
736
+ [rcsImageSrc],
737
+ );
738
+
739
+ const updateOnRcsImageReUpload = useCallback(() => {
740
+ updateRcsImageSrc('');
741
+ }, [rcsImageSrc]);
742
+
743
+ const getMediaBasedComponent = () => {
744
+ switch (templateMediaType) {
745
+ case RCS_MEDIA_TYPES.NONE: {
746
+ return renderTextComponent;
747
+ }
748
+ case RCS_MEDIA_TYPES.IMAGE: {
749
+ return (
750
+ <>
751
+ <CapImageUpload
752
+ style={{ paddingTop: '20px' }}
753
+ allowedExtensionsRegex={ALLOWED_IMAGE_EXTENSIONS_REGEX}
754
+ imgWidth={RCS_IMG_WIDTH}
755
+ imgHeight={RCS_IMG_HEIGHT}
756
+ imgSize={RCS_IMG_SIZE}
757
+ uploadAsset={uploadRcsImage}
758
+ isFullMode={isFullMode}
759
+ imageSrc={rcsImageSrc}
760
+ updateImageSrc={setUpdateRcsImageSrc}
761
+ updateOnReUpload={updateOnRcsImageReUpload}
762
+ index={0}
763
+ className="cap-custom-image-upload"
764
+ key="rcs-uploaded-image"
765
+ imageData={rcsData}
766
+ channel={RCS}
767
+ />
768
+ {renderTextComponent}
769
+ </>
770
+ );
771
+ }
772
+ default:
773
+ return null;
774
+ }
775
+ };
776
+
777
+ const getRcsPreview = () => (
778
+ <TemplatePreview
779
+ channel={RCS}
780
+ content={{
781
+ rcsPreviewContent: {
782
+ rcsTitle: templateTitle,
783
+ rcsDesc: templateDesc,
784
+ ...(!isMediaTypeNone && {
785
+ rcsImageSrc,
786
+ }),
787
+ },
788
+ }}
789
+ />
790
+ );
791
+
792
+ const createPayload = () => {
793
+ const base = get(dltEditData, `versions.base`, {});
794
+ const {
795
+ template_id: templateId = '',
796
+ // eslint-disable-next-line camelcase
797
+ template_name = '',
798
+ 'sms-editor': template = '',
799
+ header: registeredSenderIds = [],
800
+ 'var-mapped': templateVariableMapping = {},
801
+ } = base;
802
+ const tempMediaSrc = !isMediaTypeNone ? rcsImageSrc : '';
803
+
804
+ return {
805
+ name: templateName,
806
+ versions: {
807
+ base: {
808
+ content: {
809
+ RCS: {
810
+ cardContent: [
811
+ {
812
+ title: templateTitle,
813
+ description: templateDesc,
814
+ mediaType: templateMediaType,
815
+ media: {
816
+ mediaUrl: tempMediaSrc,
817
+ height: MEDIUM,
818
+ },
819
+ },
820
+ ],
821
+ cardSettings: {
822
+ cardOrientation: VERTICAL,
823
+ mediaAlignment: RIGHT,
824
+ },
825
+ cardType: STANDALONE,
826
+ contentType: RICHCARD,
827
+ smsFallBackContent: {
828
+ message: fallbackMessage,
829
+ ...(isDltEnabled && {
830
+ templateConfigs: {
831
+ templateId,
832
+ templateName: template_name,
833
+ template,
834
+ registeredSenderIds,
835
+ templateVariableMapping,
836
+ },
837
+ }),
838
+ },
839
+ },
840
+ },
841
+ },
842
+ },
843
+ type: RCS,
844
+ };
845
+ };
846
+
847
+ const actionCallback = ({ errorMessage, resp }, isEdit) => {
848
+ // eslint-disable-next-line no-undef
849
+ const error = errorMessage?.message || errorMessage;
850
+ if (!error) {
851
+ CapNotification.success({
852
+ message: isEdit
853
+ ? formatMessage(messages.rcsEditNotification)
854
+ : formatMessage(messages.rcsCreateNotification),
855
+ });
856
+ if (isEdit) {
857
+ actions.clearEditResponse();
858
+ } else {
859
+ actions.clearCreateResponse();
860
+ }
861
+ } else {
862
+ CapNotification.error({
863
+ message: error,
864
+ });
865
+ }
866
+ };
867
+
868
+ const onCreateRcs = () => {
869
+ setSpin(true);
870
+ actions.createTemplate(createPayload(), (resp, errorMessage) => {
871
+ actionCallback({ resp, errorMessage });
872
+ if (!errorMessage) {
873
+ onCreateComplete();
874
+ } else {
875
+ setSpin(false);
876
+ }
877
+ });
878
+ };
879
+
880
+ const onEditRcs = () => {
881
+ setSpin(true);
882
+ actions.editTemplate(
883
+ {
884
+ ...createPayload(),
885
+ _id: params.id,
886
+ },
887
+ (resp, errorMessage) => {
888
+ actionCallback({ resp, errorMessage }, true);
889
+ if (!errorMessage) {
890
+ onCreateComplete();
891
+ } else {
892
+ setSpin(false);
893
+ }
894
+ },
895
+ );
896
+ };
897
+
898
+ const onDoneCallback = () => {
899
+ if (isFullMode) {
900
+ if (isEditFlow) {
901
+ return onEditRcs;
902
+ }
903
+ return onCreateRcs;
904
+ }
905
+ return () => getFormData({});
906
+ };
907
+
908
+ const isDisableDone = () => {
909
+ //if template name is not entered
910
+ if (templateName.trim() === '' || templateNameError) {
911
+ return true;
912
+ }
913
+ //if template message is not entered
914
+ if (isMediaTypeNone && templateDesc.trim() === '') {
915
+ return true;
916
+ }
917
+ //if image is not uploaded
918
+ if (!isMediaTypeNone && rcsImageSrc === '') {
919
+ return true;
920
+ }
921
+ if (templateDescError || fallbackMessageError) {
922
+ return true;
923
+ }
924
+ return false;
925
+ };
926
+
927
+ const getMainContent = () => {
928
+ if (showDltContainer && !fallbackPreviewmode) {
929
+ const dltSlideBoxContent = showDltContainer && getDltSlideBoxContent();
930
+ const { dltHeader = '', dltContent = '' } = dltSlideBoxContent;
931
+ return (
932
+ <CapSlideBox
933
+ show={showDltContainer}
934
+ header={dltHeader}
935
+ content={dltContent}
936
+ handleClose={closeDltContainerHandler}
937
+ size="size-xl"
938
+ />
939
+ );
940
+ }
941
+ const tempMsg = dltPreviewData === '' ? fallbackMessage : dltPreviewData;
942
+ const mediaTypeMsg = isMediaTypeNone ? 'textMessage' : 'image';
943
+ return (
944
+ <>
945
+ <CapRow className="cap-rcs-creatives">
946
+ <CapColumn span={14}>
947
+ {/* template name */}
948
+ {isFullMode && (
949
+ <CapInput
950
+ id="rcs_template_name_input"
951
+ onChange={onTemplateNameChange}
952
+ errorMessage={templateNameError}
953
+ placeholder={formatMessage(
954
+ globalMessages.templateNamePlaceholder,
955
+ )}
956
+ value={templateName || ''}
957
+ size="default"
958
+ label={formatMessage(globalMessages.creativeNameLabel)}
959
+ />
960
+ )}
961
+ {/* template mdeia type */}
962
+ {renderLabel('mediaLabel')}
963
+ <CapRadioGroup
964
+ options={mediaRadioOptions || []}
965
+ value={templateMediaType}
966
+ onChange={onTemplateMediaTypeChange}
967
+ className="rcs-radio"
968
+ />
969
+ {getMediaBasedComponent()}
970
+ <CapDivider style={{ margin: `${CAP_SPACE_28} 0` }} />
971
+ {renderFallBackSmsComponent()}
972
+ <div className="rcs-scroll-div" />
973
+ </CapColumn>
974
+ <CapColumn span={10} className="rcs-preview-container">
975
+ {getRcsPreview()}
976
+ </CapColumn>
977
+ </CapRow>
978
+ <RcsFooter>
979
+ {/* show tooltip only if button is disabled */}
980
+ <CapTooltip
981
+ title={
982
+ isDisableDone()
983
+ ? formatMessage(messages.rcsDoneBtnToolTip, {
984
+ type: formatMessage(messages[mediaTypeMsg]),
985
+ })
986
+ : ''
987
+ }
988
+ placement={'right'}
989
+ >
990
+ <div className="button-disabled-tooltip-wrapper">
991
+ <CapButton
992
+ onClick={onDoneCallback()}
993
+ disabled={isDisableDone()}
994
+ className="rcs-done-btn"
995
+ >
996
+ <FormattedMessage {...globalMessages.done} />
997
+ </CapButton>
998
+ </div>
999
+ </CapTooltip>
1000
+ </RcsFooter>
1001
+
1002
+ {fallbackPreviewmode && (
1003
+ <CapSlideBox
1004
+ className="rcs-fallback-preview"
1005
+ show={fallbackPreviewmode}
1006
+ header={
1007
+ <CapHeading type="h7" style={{ color: CAP_G01 }}>
1008
+ {formatMessage(messages.fallbackPreviewtitle)}
1009
+ </CapHeading>
1010
+ }
1011
+ content={
1012
+ <>
1013
+ <TemplatePreview
1014
+ channel={RCS}
1015
+ content={{
1016
+ rcsPreviewContent: {
1017
+ rcsDesc: tempMsg,
1018
+ },
1019
+ }}
1020
+ />
1021
+ <CapHeading
1022
+ type="h3"
1023
+ style={{ textAlign: 'center' }}
1024
+ className="margin-t-16"
1025
+ >
1026
+ {formatMessage(messages.totalCharacters, {
1027
+ smsCount: Math.ceil(
1028
+ tempMsg.length / FALLBACK_MESSAGE_MAX_LENGTH,
1029
+ ),
1030
+ number: tempMsg.length,
1031
+ })}
1032
+ </CapHeading>
1033
+ </>
1034
+ }
1035
+ handleClose={() => {
1036
+ setFallbackPreviewmode(false);
1037
+ setDltPreviewData('');
1038
+ }}
1039
+ />
1040
+ )}
1041
+ </>
1042
+ );
1043
+ };
1044
+ return <CapSpin spinning={loadingTags || spin}>{getMainContent()}</CapSpin>;
1045
+ };
1046
+
1047
+ const mapStateToProps = createStructuredSelector({
1048
+ rcsData: makeSelectRcs(),
1049
+ metaEntities: makeSelectMetaEntities(),
1050
+ loadingTags: isLoadingMetaEntities(),
1051
+ injectedTags: setInjectedTags(),
1052
+ });
1053
+
1054
+ const mapDispatchToProps = (dispatch) => ({
1055
+ actions: bindActionCreators(RcsActions, dispatch),
1056
+ templatesActions: bindActionCreators(TemplatesActions, dispatch),
1057
+ });
1058
+
1059
+ export default withCreatives({
1060
+ WrappedComponent: injectIntl(Rcs),
1061
+ mapStateToProps,
1062
+ mapDispatchToProps,
1063
+ userAuth: true,
1064
+ });