@capillarytech/creatives-library 7.12.15 → 7.12.16

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