@capillarytech/creatives-library 8.0.87-alpha.18 → 8.0.87-alpha.2

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 (41) hide show
  1. package/initialState.js +0 -1
  2. package/package.json +1 -1
  3. package/services/api.js +7 -6
  4. package/v2Components/CapWhatsappCTA/messages.js +4 -0
  5. package/v2Components/CapWhatsappCarouselButton/constant.js +51 -0
  6. package/v2Components/CapWhatsappCarouselButton/index.js +446 -0
  7. package/v2Components/CapWhatsappCarouselButton/index.scss +39 -0
  8. package/v2Components/FormBuilder/index.js +3 -7
  9. package/v2Components/TemplatePreview/_templatePreview.scss +9 -0
  10. package/v2Components/TemplatePreview/assets/images/empty_image_preview.svg +4 -0
  11. package/v2Components/TemplatePreview/assets/images/empty_video_preview.svg +4 -0
  12. package/v2Components/TemplatePreview/index.js +169 -104
  13. package/v2Containers/Cap/actions.js +0 -8
  14. package/v2Containers/Cap/constants.js +0 -4
  15. package/v2Containers/Cap/reducer.js +0 -6
  16. package/v2Containers/Cap/sagas.js +0 -23
  17. package/v2Containers/Cap/selectors.js +0 -6
  18. package/v2Containers/Cap/tests/__snapshots__/index.test.js.snap +0 -1
  19. package/v2Containers/CreativesContainer/SlideBoxContent.js +1 -11
  20. package/v2Containers/CreativesContainer/constants.js +0 -3
  21. package/v2Containers/CreativesContainer/index.js +88 -78
  22. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +0 -25
  23. package/v2Containers/CreativesContainer/tests/index.test.js +0 -2
  24. package/v2Containers/Email/index.js +0 -1
  25. package/v2Containers/EmailWrapper/index.js +0 -2
  26. package/v2Containers/MobilePush/Create/index.js +0 -1
  27. package/v2Containers/MobilePush/Edit/index.js +0 -1
  28. package/v2Containers/MobilepushWrapper/index.js +1 -2
  29. package/v2Containers/Sms/Create/index.js +0 -1
  30. package/v2Containers/Sms/Edit/index.js +0 -1
  31. package/v2Containers/SmsWrapper/index.js +0 -2
  32. package/v2Containers/Templates/_templates.scss +35 -0
  33. package/v2Containers/Templates/index.js +64 -5
  34. package/v2Containers/TemplatesV2/index.js +0 -7
  35. package/v2Containers/Whatsapp/constants.js +83 -1
  36. package/v2Containers/Whatsapp/index.js +709 -182
  37. package/v2Containers/Whatsapp/index.scss +52 -1
  38. package/v2Containers/Whatsapp/messages.js +38 -2
  39. package/v2Containers/Whatsapp/utils.js +34 -0
  40. package/v2Containers/mockdata.js +0 -3
  41. package/utils/transformerUtils.js +0 -524
@@ -5,7 +5,7 @@ import React, { useState, useEffect, useCallback } from 'react';
5
5
  import { bindActionCreators } from 'redux';
6
6
  import { createStructuredSelector } from 'reselect';
7
7
  import { injectIntl, FormattedMessage } from 'react-intl';
8
- import { get, isEmpty, cloneDeep, isEqual } from 'lodash';
8
+ import { get, isEmpty, cloneDeep, isEqual, set } from 'lodash';
9
9
  import styled from 'styled-components';
10
10
  import CapSpin from '@capillarytech/cap-ui-library/CapSpin';
11
11
  import CapRow from '@capillarytech/cap-ui-library/CapRow';
@@ -26,6 +26,10 @@ import CapAlert from '@capillarytech/cap-ui-library/CapAlert';
26
26
  import CapCheckbox from '@capillarytech/cap-ui-library/CapCheckbox';
27
27
  import CapLink from '@capillarytech/cap-ui-library/CapLink';
28
28
  import CapAskAira from '@capillarytech/cap-ui-library/CapAskAira';
29
+ import CapCard from '@capillarytech/cap-ui-library/CapCard';
30
+ import CapTab from '@capillarytech/cap-ui-library/CapTab';
31
+ import CapDivider from '@capillarytech/cap-ui-library/CapDivider';
32
+ import CapInfoNote from '@capillarytech/cap-ui-library/CapInfoNote';
29
33
  import moment from 'moment';
30
34
 
31
35
  import {
@@ -33,6 +37,8 @@ import {
33
37
  CAP_SPACE_24,
34
38
  CAP_SPACE_32,
35
39
  CAP_WHITE,
40
+ FONT_COLOR_02,
41
+ FONT_COLOR_01,
36
42
  } from '@capillarytech/cap-ui-library/styled/variables';
37
43
  import { makeSelectWhatsapp, makeSelectAccount } from './selectors';
38
44
  import {
@@ -80,6 +86,13 @@ import {
80
86
  OTP_CONFIG_URI,
81
87
  WHATSAPP_CATEGORIES,
82
88
  AI_CONTENT_BOT_DISABLED,
89
+ mediaTypeOptions,
90
+ carouselMediaOptions,
91
+ CAROUSEL_INITIAL_DATA,
92
+ MAX_CAROUSEL_ALLOWED,
93
+ BODY_TEXT,
94
+ QUICK_REPLY,
95
+ CAROUSEL_TEXT,
83
96
  ICS_CATEGORY_OPTIONS,
84
97
  CORRECT_TEMPLATE_FORMAT_URL,
85
98
  CATEGORY_OPTIONS_MAP,
@@ -105,6 +118,8 @@ import { getWhatsappDocPreview } from './utils';
105
118
  import CapWhatsappQuickReply from '../../v2Components/CapWhatsappQuickReply';
106
119
  import injectSaga from '../../utils/injectSaga';
107
120
  import injectReducer from '../../utils/injectReducer';
121
+ import CapWhatsappCarouselButton from '../../v2Components/CapWhatsappCarouselButton';
122
+ import { INITIAL_CAROUSEL_PHONE_NUMBER_DATA, INITIAL_CAROUSEL_URL_DATA, INITIAL_CAROUSEL_QUICK_REPLY_DATA } from '../../v2Components/CapWhatsappCarouselButton/constant';
108
123
 
109
124
  import { v2WhatsappSagas } from './sagas';
110
125
  import v2WhatsappReducer from './reducer';
@@ -139,6 +154,7 @@ export const Whatsapp = (props) => {
139
154
  } = props || {};
140
155
  const { formatMessage } = intl;
141
156
  const { TextArea } = CapInput;
157
+ const defaultActiveIndex = "0";
142
158
  const [templateName, setTemplateName] = useState('');
143
159
  const [templateNameError, setTemplateNameError] = useState(false);
144
160
  const [templateCategory, setTemplateCategory] = useState(
@@ -200,9 +216,14 @@ export const Whatsapp = (props) => {
200
216
  useState(false);
201
217
  const [showUrlPreview, setShowUrlPreview] = useState(false);
202
218
  const [previewUrl, setPreviewUrl] = useState('');
219
+ const [carouselMediaType, setCarouselMediaType] = useState('image');
220
+ const [carouselData, setCarouselData] = useState(CAROUSEL_INITIAL_DATA);
221
+ const [activeIndex, setActiveIndex] = useState(defaultActiveIndex);
222
+ const [carouselValidateTag, setCarouselValidateTag] = useState(false);
203
223
 
204
224
  const validVarRegex = /{{([1-9]|1[0-9])}}/g;
205
225
  const headerValidVarRegex = /{{(1)}}/g;
226
+ const carouselBodyVarRegex = /{{[1-5]}}/g;
206
227
  const previewUrlMatchingRegex = /(http|ftp|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])/g;
207
228
 
208
229
  const { accessibleFeatures = [] } = currentOrgDetails || {};
@@ -215,6 +236,7 @@ export const Whatsapp = (props) => {
215
236
  const isMediaTypeImage = templateMediaType === WHATSAPP_MEDIA_TYPES.IMAGE;
216
237
  const isMediaTypeVideo = templateMediaType === WHATSAPP_MEDIA_TYPES.VIDEO;
217
238
  const isMediaTypeDoc = templateMediaType === WHATSAPP_MEDIA_TYPES.DOCUMENT;
239
+ const isMediaTypeCarousel = templateMediaType === WHATSAPP_MEDIA_TYPES.CAROUSEL;
218
240
  const isHostIsNotTwilio = host !== HOST_TWILIO;
219
241
  const WhatsappFooter = styled.div`
220
242
  background-color: ${CAP_WHITE};
@@ -291,8 +313,9 @@ export const Whatsapp = (props) => {
291
313
  buttons = [],
292
314
  videoPreviewImg = '',
293
315
  whatsappDocParams = {},
294
- whatsappMedia: { header = '', footer = '' } = {},
316
+ whatsappMedia: { header = '', footer = '', headerVarMapped = [] } = {},
295
317
  isPreviewUrl = false,
318
+ carouselData : editCarouselData = [],
296
319
  } = editContent;
297
320
  setTemplateCategory(category);
298
321
  setTemplateStatus(status);
@@ -317,6 +340,12 @@ export const Whatsapp = (props) => {
317
340
  setTemplateFooter(footer);
318
341
  setTemplateHeader(header);
319
342
  setShowUrlPreview(isPreviewUrl);
343
+ if (mediaType === WHATSAPP_MEDIA_TYPES.CAROUSEL) {
344
+ const updatedCarouselData = handleCarouselData(editCarouselData);
345
+ setCarouselData(updatedCarouselData);
346
+ setCarouselMediaType(updatedCarouselData?.[0]?.mediaType)
347
+ setCarouselValidateTag(!carouselValidateTag);
348
+ }
320
349
  if (btnType === WHATSAPP_BUTTON_TYPES.CTA && buttons.length > 0) {
321
350
  setCtadata(
322
351
  buttons.map((cta) => {
@@ -348,11 +377,42 @@ export const Whatsapp = (props) => {
348
377
  }
349
378
  computeTempMsgArray();
350
379
  if (header && (mediaType === WHATSAPP_MEDIA_TYPES.TEXT && isHostIsNotTwilio)) {
351
- computeHeaderMsgArray();
380
+ const { clonedVarMap, updatedText, tempData } = computeTextMessage(header, headerVarMapped, headerValidVarRegex);
381
+ setTempHeaderData(tempData);
382
+ setHeaderVarMappedData(clonedVarMap);
383
+ setUpdatedHeaderData(updatedText);
352
384
  }
353
385
  }
354
386
  }, [editData.templateDetails || templateData]);
355
387
 
388
+ const handleCarouselData = (carouselData = []) => {
389
+ return (
390
+ carouselData.map((carousel) => {
391
+ const { clonedVarMap, updatedText, tempData } = computeTextMessage(carousel?.bodyText, carousel?.varMap, carouselBodyVarRegex);
392
+ return {
393
+ ...carousel,
394
+ updatedBodyText: updatedText,
395
+ textAreaId: '',
396
+ varMap: clonedVarMap,
397
+ tempBodyData: tempData,
398
+ carouselTagValidationErr: false,
399
+ carouselTagValidationErrMessage: {},
400
+ ...(carousel.mediaType === 'image' && {
401
+ imageSrc: carousel?.imageUrl,
402
+ }),
403
+ ...(carousel.mediaType === 'video' && {
404
+ videoSrc: carousel?.videoUrl,
405
+ videoPreviewImg,
406
+ }),
407
+ buttons: carousel?.buttons?.map((button) => ({
408
+ ...button,
409
+ buttonType: button?.type,
410
+ })),
411
+ };
412
+ })
413
+ );
414
+ };
415
+
356
416
  const converStringToVarArr = (validVarArr, content) => {
357
417
  const templateVarArray = [];
358
418
  while (content?.length !== 0) {
@@ -371,34 +431,32 @@ export const Whatsapp = (props) => {
371
431
  return templateVarArray;
372
432
  }
373
433
 
374
- const computeHeaderMsgArray = () => {
375
- let msg = get(editContent, `whatsappMedia.header`, '');
376
- const validVarArr = msg?.match(headerValidVarRegex) || [];
434
+ const computeTextMessage = (msg, varMap, regex) => {
435
+ const validVarArr = msg?.match(regex) || [];
377
436
  //conerting msg string to variable arr
378
437
  const templateHeaderArray = converStringToVarArr(validVarArr, msg);
379
- setTempHeaderData(templateHeaderArray);
380
438
  if (templateHeaderArray?.length !== 0) {
381
- let headerVarMap = {};
382
- const {
383
- whatsappMedia: { headerVarMapped = {} },
384
- } = editContent;
385
- if (!isEmpty(headerVarMapped)) {
386
- headerVarMap = cloneDeep(headerVarMapped);
439
+ let clonedVarMap = {};
440
+ if (!isEmpty(varMap)) {
441
+ clonedVarMap = cloneDeep(varMap);
387
442
  } else {
388
443
  templateHeaderArray?.forEach((headerValue, i) => {
389
- if (headerValue?.match(headerValidVarRegex)?.length > 0) {
390
- headerVarMap[`${headerValue}_${i}`] = '';
444
+ if (headerValue?.match(regex)?.length > 0) {
445
+ clonedVarMap[`${headerValue}_${i}`] = '';
391
446
  }
392
447
  })
393
448
  }
394
449
  const arr = [...templateHeaderArray];
395
- for (const key in headerVarMap) {
396
- if (headerVarMap[key] !== '') {
397
- arr[key.slice(key.indexOf('_') + 1)] = headerVarMap[key];
450
+ for (const key in clonedVarMap) {
451
+ if (clonedVarMap[key] !== '') {
452
+ arr[key.slice(key.indexOf('_') + 1)] = clonedVarMap[key];
398
453
  }
399
454
  }
400
- setHeaderVarMappedData(headerVarMap);
401
- setUpdatedHeaderData(arr);
455
+ return {
456
+ clonedVarMap,
457
+ updatedText: arr,
458
+ tempData: templateHeaderArray,
459
+ }
402
460
  }
403
461
  };
404
462
 
@@ -515,6 +573,8 @@ export const Whatsapp = (props) => {
515
573
  if (type === HEADER_TEXT) {
516
574
  headerTagValidationResponse = validationResponse;
517
575
  updateIsHeaderTagValidationError(unsupportedTagsLengthCheck);
576
+ } else if (type === CAROUSEL_TEXT) {
577
+ return [{fieldName: "carouselTagValidationErrMessage", value: validationResponse}, {fieldName: "carouselTagValidationErr", value: unsupportedTagsLengthCheck}];
518
578
  } else {
519
579
  tagValidationResponse = validationResponse;
520
580
  updateIsTagValidationError(unsupportedTagsLengthCheck);
@@ -566,6 +626,15 @@ export const Whatsapp = (props) => {
566
626
  tagValidation(updatedHeaderData, headerValidVarRegex, HEADER_TEXT);
567
627
  }, [updatedHeaderData, tags]);
568
628
 
629
+ useEffect(() => {
630
+ if (!isFullMode && tags?.length && carouselData?.length) {
631
+ carouselData?.forEach((carousel, carouselIndex) => {
632
+ const tagFields = tagValidation(carousel?.updatedBodyText, carouselBodyVarRegex, CAROUSEL_TEXT) || [];
633
+ handleCarouselValueChange(carouselIndex, tagFields);
634
+ })
635
+ }
636
+ }, [carouselValidateTag, tags])
637
+
569
638
  const handleOnTagsContextChange = (data) => {
570
639
  const { type } = location.query || {};
571
640
  const isEmbedded = type === EMBEDDED;
@@ -589,6 +658,7 @@ export const Whatsapp = (props) => {
589
658
  updatedData = [],
590
659
  areaId = "",
591
660
  regex,
661
+ carouselIndex,
592
662
  } = tagSelectData;
593
663
  if (mapData && updatedData) {
594
664
  const numId = Number(areaId?.slice(areaId?.indexOf("_") + 1));
@@ -600,15 +670,26 @@ export const Whatsapp = (props) => {
600
670
  }
601
671
  const messageData = `${arr[numId]}{{${data}}}`;
602
672
  arr[numId] = messageData;
603
- if (type === HEADER_TEXT) {
604
- setHeaderVarMappedData((prevState) => ({
605
- ...prevState,
606
- [areaId]: messageData,
607
- }));
608
- setUpdatedHeaderData(arr);
609
- } else {
610
- varMap[areaId] = messageData;
611
- setUpdatedSmsEditor(arr);
673
+ switch (type) {
674
+ case HEADER_TEXT:
675
+ setHeaderVarMappedData((prevState) => ({
676
+ ...prevState,
677
+ [areaId]: messageData,
678
+ }));
679
+ setUpdatedHeaderData(arr);
680
+ break;
681
+ case CAROUSEL_TEXT:
682
+ const carouselVarMap = carouselData?.[carouselIndex]?.varMap || {};
683
+ carouselVarMap[areaId] = messageData;
684
+ let tagFields = []
685
+ if (!isFullMode) {
686
+ tagFields = tagValidation(arr, carouselBodyVarRegex, CAROUSEL_TEXT) || [];
687
+ }
688
+ handleCarouselValueChange(carouselIndex, [...tagFields, {fieldName: "varMap", value: carouselVarMap}, {fieldName: "updatedBodyText", value: arr}])
689
+ break;
690
+ default:
691
+ varMap[areaId] = messageData;
692
+ setUpdatedSmsEditor(arr);
612
693
  }
613
694
  }
614
695
  }
@@ -636,10 +717,25 @@ export const Whatsapp = (props) => {
636
717
  });
637
718
  };
638
719
 
720
+ const onCarouselBodyTagSelect = (data, carouselData, carouselIndex) => {
721
+ const { updatedBodyText, varMap: headerVarMap, textAreaId } = carouselData;
722
+ onTagSelect({
723
+ data,
724
+ type: CAROUSEL_TEXT,
725
+ mapData: headerVarMap,
726
+ updatedData: updatedBodyText,
727
+ areaId: textAreaId,
728
+ regex: carouselBodyVarRegex,
729
+ carouselIndex
730
+ });
731
+ }
732
+
639
733
  //setting the id of currently selected text area, is used onTagSelect
640
- const setTextAreaId = ({ target: { id } }, type) => {
734
+ const setTextAreaId = ({ target: { id } }, type, carouselIndex) => {
641
735
  if (type === HEADER_TEXT) {
642
736
  setHeaderTextAreaId(id);
737
+ } else if (type === CAROUSEL_TEXT) {
738
+ handleCarouselValueChange(carouselIndex, [{fieldName: "textAreaId", value: id}])
643
739
  } else {
644
740
  updateTextAreaId(id);
645
741
  }
@@ -678,55 +774,6 @@ export const Whatsapp = (props) => {
678
774
  label: renderTemplateCategoryLabel(option.tooltipLabel, option.label),
679
775
  }));
680
776
 
681
- const mediaRadioOptions = [
682
- {
683
- value: WHATSAPP_MEDIA_TYPES.TEXT,
684
- label: formatMessage(messages.mediaText),
685
- },
686
- {
687
- value: WHATSAPP_MEDIA_TYPES.IMAGE,
688
- label: (
689
- <CapTooltip
690
- title={
691
- host === HOST_TWILIO
692
- ? formatMessage(messages.disabledFeatureTooltip)
693
- : ''
694
- }
695
- >
696
- {formatMessage(messages.mediaImage)}
697
- </CapTooltip>
698
- ),
699
- disabled: host === HOST_TWILIO,
700
- },
701
- {
702
- value: WHATSAPP_MEDIA_TYPES.VIDEO,
703
- label: (
704
- <CapTooltip
705
- title={
706
- host === HOST_TWILIO
707
- ? formatMessage(messages.disabledFeatureTooltip)
708
- : ''
709
- }>
710
- {formatMessage(messages.mediaVideo)}
711
- </CapTooltip>
712
- ),
713
- disabled: host === HOST_TWILIO,
714
- },
715
- {
716
- value: WHATSAPP_MEDIA_TYPES.DOCUMENT,
717
- label: (
718
- <CapTooltip
719
- title={
720
- host === HOST_TWILIO
721
- ? formatMessage(messages.disabledFeatureTooltip)
722
- : ''
723
- }>
724
- {formatMessage(messages.mediaDocument)}
725
- </CapTooltip>
726
- ),
727
- disabled: host === HOST_TWILIO,
728
- },
729
- ];
730
777
  const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.authentication);
731
778
  const onChangeButtonType = ({ target: { value } }) => {
732
779
  setButtonType(value);
@@ -757,7 +804,7 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
757
804
  });
758
805
  };
759
806
 
760
- const computeTextLength = (type) => {
807
+ const computeTextLength = (type, carousel) => {
761
808
  switch (type) {
762
809
  case MESSAGE_TEXT:
763
810
  let whatsappContentLen = 0;
@@ -774,6 +821,12 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
774
821
  return headerContentLen || 0;
775
822
  case FOOTER_TEXT:
776
823
  return templateFooter?.length || 0;
824
+ case CAROUSEL_TEXT:
825
+ let carouselContentLen = 0;
826
+ carouselContentLen = isEditFlow
827
+ ? carousel?.updatedBodyText?.join("")?.length
828
+ : carousel?.bodyText?.length;
829
+ return carouselContentLen;
777
830
  default:
778
831
  let overallLength =
779
832
  computeTextLength(MESSAGE_TEXT) +
@@ -784,10 +837,10 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
784
837
  };
785
838
 
786
839
  //used by create and edit
787
- const renderMessageLength = (type, currentLength) => (
840
+ const renderMessageLength = (type, currentLength, carousel) => (
788
841
  <CapHeading type="label1" className="whatsapp-render-message-length">
789
842
  {formatMessage(messages.templateMessageLength, {
790
- currentLength: currentLength ? currentLength : computeTextLength(type),
843
+ currentLength: currentLength ? currentLength : computeTextLength(type, carousel),
791
844
  maxLength: maxLengthByType(type),
792
845
  })}
793
846
  </CapHeading>
@@ -934,6 +987,7 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
934
987
  const maxLengthByType = (type) => {
935
988
  switch (type) {
936
989
  case MESSAGE_TEXT:
990
+ case CAROUSEL_TEXT:
937
991
  return TEMPLATE_MESSAGE_MAX_LENGTH;
938
992
  case HEADER_TEXT:
939
993
  case FOOTER_TEXT:
@@ -982,37 +1036,57 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
982
1036
  hostName: host,
983
1037
  };
984
1038
  if (isFullMode && !isEditFlow && host === HOST_GUPSHUP) {
985
- setGupshupMediaFile(file);
1039
+ if (isMediaTypeCarousel) {
1040
+ setGupshupMediaFile((prevState) => {
1041
+ const newArray = [...prevState];
1042
+ newArray[activeIndex] = file;
1043
+ return newArray;
1044
+ });
1045
+ } else {
1046
+ setGupshupMediaFile(file);
1047
+ }
986
1048
  }
987
1049
  actions.uploadWhatsappAsset(file, type, fileParams, 0, whatsappParams);
988
1050
  };
989
1051
 
990
1052
  const setUpdateWhatsappImageSrc = useCallback(
991
1053
  (filePath, fileHandle) => {
992
- setWhatsappImageSrc(filePath);
993
- setKarixFileHandle(fileHandle);
1054
+ if (isMediaTypeCarousel) {
1055
+ handleCarouselValueChange(parseInt(activeIndex), [{fieldName: "imageSrc", value: filePath}, {fieldName: "karixFileHandle", value: fileHandle}]);
1056
+ } else {
1057
+ setWhatsappImageSrc(filePath);
1058
+ setKarixFileHandle(fileHandle);
1059
+ }
994
1060
  actions.clearWhatsappAsset(0);
995
1061
  },
996
- [whatsappImageSrc],
1062
+ [whatsappImageSrc, isMediaTypeCarousel, activeIndex, carouselData],
997
1063
  );
998
1064
 
999
1065
  const updateOnWhatsappImageReUpload = useCallback(() => {
1000
- setWhatsappImageSrc('');
1001
- setKarixFileHandle('');
1002
- }, [whatsappImageSrc]);
1066
+ if (isMediaTypeCarousel) {
1067
+ handleCarouselValueChange(parseInt(activeIndex), [{fieldName: "imageSrc", value: ''}, {fieldName: "karixFileHandle", value: ''}]);
1068
+ } else {
1069
+ setWhatsappImageSrc('');
1070
+ setKarixFileHandle('');
1071
+ }
1072
+ }, [whatsappImageSrc, isMediaTypeCarousel, activeIndex, carouselData]);
1003
1073
 
1004
1074
  const setUpdateWhatsappVideoSrc = useCallback(
1005
1075
  (index, data) => {
1006
1076
  const { videoSrc = '', previewUrl = '', fileHandle = '' } = data;
1007
- setWhatsappVideoSrcAndPreview({
1008
- whatsappVideoSrc: videoSrc,
1009
- whatsappVideoPreviewImg: previewUrl,
1010
- });
1011
- setKarixFileHandle(fileHandle);
1012
- updateAssetList(data);
1077
+ if (isMediaTypeCarousel) {
1078
+ handleCarouselValueChange(parseInt(activeIndex), [{fieldName: "videoSrc", value: videoSrc}, {fieldName: "videoPreviewImg", value: previewUrl}, {fieldName: "assetList", value: data}, {fieldName: "karixFileHandle", value: fileHandle}]);
1079
+ } else {
1080
+ setWhatsappVideoSrcAndPreview({
1081
+ whatsappVideoSrc: videoSrc,
1082
+ whatsappVideoPreviewImg: previewUrl,
1083
+ });
1084
+ setKarixFileHandle(fileHandle);
1085
+ updateAssetList(data);
1086
+ }
1013
1087
  actions.clearWhatsappAsset(0);
1014
1088
  },
1015
- [whatsappVideoSrcAndPreview?.whatsappVideoSrc],
1089
+ [whatsappVideoSrcAndPreview?.whatsappVideoSrc, isMediaTypeCarousel, activeIndex],
1016
1090
  );
1017
1091
 
1018
1092
  const setUpdateWhatsappDocSrc = useCallback(
@@ -1029,14 +1103,14 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
1029
1103
  setKarixFileHandle('');
1030
1104
  }, [whatsappDocSource]);
1031
1105
 
1032
- const renderImageComponent = () => (
1106
+ const renderImageComponent = (carouselIndex) => (
1033
1107
  <CapImageUpload
1034
1108
  style={{ paddingTop: '20px' }}
1035
1109
  allowedExtensionsRegex={ALLOWED_IMAGE_EXTENSIONS_REGEX}
1036
1110
  imgSize={WHATSAPP_IMG_SIZE}
1037
1111
  uploadAsset={uploadWhatsappAsset}
1038
1112
  isFullMode={isFullMode}
1039
- imageSrc={whatsappImageSrc}
1113
+ imageSrc={isMediaTypeCarousel ? (carouselData?.[carouselIndex]?.imageSrc || '') : whatsappImageSrc}
1040
1114
  updateImageSrc={setUpdateWhatsappImageSrc}
1041
1115
  updateOnReUpload={updateOnWhatsappImageReUpload}
1042
1116
  index={0}
@@ -1054,7 +1128,7 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
1054
1128
  videoSize={WHATSAPP_VIDEO_SIZE}
1055
1129
  isFullMode={isFullMode}
1056
1130
  uploadAsset={uploadWhatsappAsset}
1057
- uploadedAssetList={assetList}
1131
+ uploadedAssetList={carouselData?.[activeIndex]?.assetList || []}
1058
1132
  onVideoUploadUpdateAssestList={setUpdateWhatsappVideoSrc}
1059
1133
  videoData={editData}
1060
1134
  className="cap-custom-video-upload"
@@ -1128,6 +1202,13 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
1128
1202
  setTemplateMessage(formatMessage(messages.authenticationMsg));
1129
1203
  } else {
1130
1204
  setTemplateMessage('');
1205
+ }
1206
+ if (templateCategory === WHATSAPP_CATEGORIES.marketing && templateMediaType === WHATSAPP_MEDIA_TYPES.CAROUSEL) {
1207
+ setTemplateMediaType(WHATSAPP_MEDIA_TYPES.TEXT);
1208
+ setCarouselData(CAROUSEL_INITIAL_DATA);
1209
+ }
1210
+ if (value === WHATSAPP_CATEGORIES.marketing) {
1211
+ setGupshupMediaFile([]);
1131
1212
  }
1132
1213
  setTemplateCategory(value);
1133
1214
  };
@@ -1140,7 +1221,8 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
1140
1221
  setTemplateLanguage(value);
1141
1222
  };
1142
1223
 
1143
- const onTemplateMediaTypeChange = ({ target: { value } }) => {
1224
+ const onTemplateMediaTypeChange = (value) => {
1225
+ setCarouselData(CAROUSEL_INITIAL_DATA);
1144
1226
  setTemplateMediaType(value);
1145
1227
  };
1146
1228
 
@@ -1215,7 +1297,27 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
1215
1297
  return errorMessage;
1216
1298
  };
1217
1299
 
1218
- const variableErrorHandling = (value, type) => {
1300
+ const handleCarouselValueChange = (carouselIndex, fields) => {
1301
+ const updateCarouselData = cloneDeep(carouselData);
1302
+ fields.forEach((field) => {
1303
+ updateCarouselData[carouselIndex][field.fieldName] = field.value;
1304
+ });
1305
+ setCarouselData(updateCarouselData);
1306
+ }
1307
+
1308
+ const carouselBodyTextErrorHandler = (value, carouselIndex) => {
1309
+ let errorMessage = false;
1310
+ if (value === "") {
1311
+ errorMessage = formatMessage(messages.emptyCardBodyeErrorMessage);
1312
+ } else if(value?.length > TEMPLATE_MESSAGE_MAX_LENGTH) {
1313
+ errorMessage = formatMessage(messages.templateMessageLengthError);
1314
+ } else {
1315
+ errorMessage = variableErrorHandling(value, BODY_TEXT, carouselIndex);
1316
+ }
1317
+ return errorMessage;
1318
+ }
1319
+
1320
+ const variableErrorHandling = (value, type, carouselIndex) => {
1219
1321
  let errorMessage = false;
1220
1322
  const validVarArr = value.match(type === HEADER_TEXT ? headerValidVarRegex : validVarRegex) || [];
1221
1323
  const validVarSet = [...new Set(validVarArr)];
@@ -1258,6 +1360,7 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
1258
1360
  errorMessage = formatMessage(messages.sequenceVars, { one: "{{1}}" });
1259
1361
  } else {
1260
1362
  if (type === MESSAGE_TEXT) setAddedVarCount(validVarSet?.length || 0);
1363
+ if (type === BODY_TEXT) handleCarouselValueChange(carouselIndex, [{ fieldName: 'addedVarCount', value: validVarSet?.length || 0 }]);
1261
1364
  }
1262
1365
  }
1263
1366
  }
@@ -1317,6 +1420,43 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
1317
1420
  };
1318
1421
  });
1319
1422
 
1423
+ const getCarouselPayload = () => {
1424
+ return carouselData.map((carousel) => {
1425
+ const { bodyText = '', imageSrc = '', videoSrc = '', videoPreviewImg = '', karixFileHandle = '', buttons = [], varMap: carouselVarMap = {}, updatedBodyText = [], tempBodyData = [] } = carousel || {};
1426
+ const carouselButtons = buttons.map((button) => {
1427
+ const { text = '', buttonType: type = '', url = '', phone_number = '', urlType = '' } = button;
1428
+ return {
1429
+ text,
1430
+ type,
1431
+ ...(type === PHONE_NUMBER && {
1432
+ phone_number: `+${phone_number}`,
1433
+ }),
1434
+ ...(type === 'URL' && {
1435
+ urlType,
1436
+ url
1437
+ })
1438
+ };
1439
+ });
1440
+ return {
1441
+ bodyText: isEditFlow && !isFullMode ? updatedBodyText.join("") : bodyText,
1442
+ ...(carouselMediaType === "image" && {
1443
+ imageUrl: getCdnUrl({ url: imageSrc, channelName: WHATSAPP }),
1444
+ }),
1445
+ ...(carouselMediaType === "video" && {
1446
+ videoUrl: videoSrc,
1447
+ videoPreviewImg,
1448
+ }),
1449
+ karixFileHandle,
1450
+ buttons: carouselButtons,
1451
+ mediaType: carouselMediaType,
1452
+ ...(!isFullMode && {
1453
+ cardVarMapped: carouselVarMap,
1454
+ cardTemplate: tempBodyData.join(""),
1455
+ })
1456
+ };
1457
+ });
1458
+ }
1459
+
1320
1460
  const createPayload = () => {
1321
1461
  let mediaParams = {};
1322
1462
  const { whatsappVideoSrc = '', whatsappVideoPreviewImg = '' } = whatsappVideoSrcAndPreview;
@@ -1387,6 +1527,9 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
1387
1527
  }),
1388
1528
  securityRecommendation: unsubscribeRequired,
1389
1529
  codeExpiryMinutes: expiryMinutes,
1530
+ ...(isMediaTypeCarousel && {
1531
+ carouselData: getCarouselPayload()
1532
+ })
1390
1533
  },
1391
1534
  },
1392
1535
  },
@@ -1486,23 +1629,22 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
1486
1629
  if (isBtnTypeQuickReply) {
1487
1630
  return !quickReplyData.every((quickReply) => quickReply?.isSaved === true);
1488
1631
  }
1632
+ if (isMediaTypeCarousel) {
1633
+ const carouselDisableCheck = carouselData.some((data) => {
1634
+ return (
1635
+ data.bodyError ||
1636
+ data.bodyText === "" ||
1637
+ (carouselMediaType === "image" && !data.imageSrc) ||
1638
+ (carouselMediaType === "video" && !data.videoSrc) ||
1639
+ !data?.buttons.every((button) => button?.isSaved === true)
1640
+ );
1641
+ });
1642
+ return carouselDisableCheck;
1643
+ }
1644
+
1489
1645
  return false;
1490
1646
  };
1491
1647
 
1492
- const renderMediaSection = () => (
1493
- <>
1494
- {!isAuthenticationTemplate && <>{renderLabel('mediaLabel')}
1495
- <CapRadioGroup
1496
- id="whatsapp-media-radio"
1497
- options={mediaRadioOptions}
1498
- value={templateMediaType}
1499
- onChange={onTemplateMediaTypeChange}
1500
- className="whatsapp-media-radio"
1501
- />
1502
- </>}
1503
- </>
1504
- );
1505
-
1506
1648
  const renderMediaComponent = () => (
1507
1649
  <>
1508
1650
  {isMediaTypeImage && renderImageComponent()}
@@ -1511,7 +1653,245 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
1511
1653
  </>
1512
1654
  );
1513
1655
 
1514
- const createModeContent = (
1656
+ const handleCarouselMediaOptions = ({ target: { value = ''} = {} }) => {
1657
+ setCarouselData(CAROUSEL_INITIAL_DATA);
1658
+ setCarouselMediaType(value);
1659
+ }
1660
+
1661
+ const onTabChange = (index) => {
1662
+ setActiveIndex(index);
1663
+ }
1664
+
1665
+ const handleCarouselBodyText = ({ target: { value } }, carouselIndex) => {
1666
+ const error = carouselBodyTextErrorHandler(value, carouselIndex);
1667
+ handleCarouselValueChange(carouselIndex, [{ fieldName: 'bodyText', value }, {fieldName: 'bodyError', value: error}]);
1668
+ };
1669
+
1670
+ const onCarouselBodyAddVar = (carouselIndex) => {
1671
+ const updateCarouselData = cloneDeep(carouselData);
1672
+ const { bodyText } = updateCarouselData[carouselIndex];
1673
+ const validVarArr = bodyText.match(validVarRegex) || [];
1674
+ const tempMsg = `${bodyText}{{${validVarArr.length + 1}}}`;
1675
+ const error = carouselBodyTextErrorHandler(tempMsg, carouselIndex);
1676
+ handleCarouselValueChange(carouselIndex, [{ fieldName: 'bodyText', value: tempMsg }, {fieldName: 'bodyError', value: error}]);
1677
+ }
1678
+
1679
+ const deleteCarouselCard = (index) => {
1680
+ const updateCarouselData = cloneDeep(carouselData);
1681
+ updateCarouselData.splice(index, 1);
1682
+ setCarouselData(updateCarouselData);
1683
+ }
1684
+
1685
+ const getTabPanes = (isEditMode) => {
1686
+ return carouselData.map((data, index) => {
1687
+ return {
1688
+ key: index,
1689
+ tab: index + 1,
1690
+ content: (
1691
+ <CapCard
1692
+ title={`${formatMessage(messages.card)} ${index + 1}`}
1693
+ extra={
1694
+ !isEditMode && (
1695
+ <CapButton
1696
+ type="flat"
1697
+ onClick={() => {
1698
+ deleteCarouselCard(index);
1699
+ }}
1700
+ disabled={carouselData.length === 1}
1701
+ >
1702
+ <CapIcon type="delete"></CapIcon>
1703
+ </CapButton>
1704
+ )
1705
+ }
1706
+ className="whatsapp-carousel-card"
1707
+ >
1708
+ <CapRow>
1709
+ {carouselMediaType === "image" ? (
1710
+ <CapRow>
1711
+ <CapHeading type="h4">
1712
+ {formatMessage(messages.mediaImage)}
1713
+ </CapHeading>
1714
+ {renderImageComponent(index)}
1715
+ </CapRow>
1716
+ ) : (
1717
+ <CapRow>
1718
+ <CapHeading type="h4">
1719
+ {formatMessage(messages.mediaVideo)}
1720
+ </CapHeading>
1721
+ {renderVideoComonent()}
1722
+ </CapRow>
1723
+ )}
1724
+ </CapRow>
1725
+ <CapRow>
1726
+ <CapHeader
1727
+ className={`${
1728
+ isMediaTypeImage ? "whatsapp-heading-spacing" : ""
1729
+ }`}
1730
+ title={
1731
+ <CapHeading
1732
+ type="h4"
1733
+ className="whatsapp-carousel-message-heading"
1734
+ >
1735
+ {formatMessage(messages.carouselCardBodyMessageLabel)}
1736
+ <CapTooltipWithInfo
1737
+ placement="right"
1738
+ className="whatsapp-text-field_spacing"
1739
+ autoAdjustOverflow
1740
+ title={
1741
+ <FormattedMessage
1742
+ {...messages.templateMessageTooltip}
1743
+ values={{
1744
+ br: <br />,
1745
+ var: "{{1}}"
1746
+ }}
1747
+ />
1748
+ }
1749
+ />
1750
+ </CapHeading>
1751
+ }
1752
+ suffix={
1753
+ <>
1754
+ {isEditMode
1755
+ ? templateStatus === WHATSAPP_STATUSES.approved &&
1756
+ !isAuthenticationTemplate && (
1757
+ <TagList
1758
+ label={formatMessage(globalMessages.addLabels)}
1759
+ onTagSelect={(tag) => onCarouselBodyTagSelect(tag, data, index)}
1760
+ location={location}
1761
+ tags={tags || []}
1762
+ onContextChange={handleOnTagsContextChange}
1763
+ injectedTags={injectedTags || {}}
1764
+ selectedOfferDetails={selectedOfferDetails}
1765
+ eventContextTags={eventContextTags}
1766
+ />
1767
+ )
1768
+ : !isAuthenticationTemplate && (
1769
+ <CapButton
1770
+ data-testid="suffix-button"
1771
+ type="flat"
1772
+ isAddBtn
1773
+ onClick={() => onCarouselBodyAddVar(index)}
1774
+ disabled={
1775
+ (data?.addedVarCount >= 5 || data?.bodyError) &&
1776
+ data?.bodyText
1777
+ }
1778
+ >
1779
+ {formatMessage(messages.addVar)}
1780
+ </CapButton>
1781
+ )}
1782
+ </>
1783
+ }
1784
+ />
1785
+ {isEditMode ?
1786
+ <>
1787
+ <CapTooltip placement="bottom" title={disabledEditTooltipRender()}>
1788
+ <CapRow
1789
+ className={`whatsapp-edit-template-message-input ${
1790
+ templateStatus !== WHATSAPP_STATUSES.approved &&
1791
+ "whatsapp-edit-disabled"
1792
+ }`}
1793
+ >
1794
+ {renderedEditMessage(data?.tempBodyData, CAROUSEL_TEXT, {carouselIndex: index, data: data})}
1795
+ </CapRow>
1796
+ </CapTooltip>
1797
+ {renderMessageLength(CAROUSEL_TEXT, 0, data)}
1798
+ {data?.carouselTagValidationErr && tagValidationErrorMessage(CAROUSEL_TEXT, data)}
1799
+ {computeTextLength(CAROUSEL_TEXT, data) > TEMPLATE_MESSAGE_MAX_LENGTH && (
1800
+ <CapError>
1801
+ {formatMessage(messages.templateMessageLengthError)}
1802
+ </CapError>
1803
+ )}
1804
+ </>
1805
+ :
1806
+ <CapRow>
1807
+ <div className="whatsapp-create-template-message-input-wrapper">
1808
+ <TextArea
1809
+ autosize={{ minRows: 3, maxRows: 5 }}
1810
+ placeholder={formatMessage(
1811
+ messages.carouselCardBodyMessagePlaceholder
1812
+ )}
1813
+ onChange={e => handleCarouselBodyText(e, index)}
1814
+ errorMessage={
1815
+ data?.bodyError && <CapError>{data?.bodyError}</CapError>
1816
+ }
1817
+ value={data?.bodyText || ""}
1818
+ disabled={isAuthenticationTemplate}
1819
+ />
1820
+ </div>
1821
+ {renderMessageLength(CAROUSEL_TEXT, 0, data)}
1822
+ </CapRow>
1823
+ }
1824
+ </CapRow>
1825
+ <CapRow>
1826
+ <CapHeading
1827
+ className="whatsapp-carousel-message-heading"
1828
+ type="h4"
1829
+ >
1830
+ {formatMessage(messages.btnLabel)}
1831
+ </CapHeading>
1832
+ {index === 0 && (
1833
+ <CapRow>
1834
+ <CapInfoNote
1835
+ message={formatMessage(messages.carouselButtonInfo)}
1836
+ />
1837
+ </CapRow>
1838
+ )}
1839
+ <CapRow>
1840
+ <CapWhatsappCarouselButton
1841
+ carouselData={carouselData}
1842
+ setCarouselData={setCarouselData}
1843
+ carouselIndex={index}
1844
+ isEditFlow={isEditMode}
1845
+ tags={tags || []}
1846
+ injectedTags={injectedTags || {}}
1847
+ selectedOfferDetails={selectedOfferDetails}
1848
+ />
1849
+ </CapRow>
1850
+ </CapRow>
1851
+ </CapCard>
1852
+ )
1853
+ };
1854
+ })
1855
+ }
1856
+
1857
+ const addContent = () => {
1858
+ const updatedCarouselData = cloneDeep(carouselData); // Shallow copy, assuming carouselData isn't deeply nested
1859
+ const firstCarouselButtonData = updatedCarouselData[0]?.buttons;
1860
+
1861
+ const buttonArray = firstCarouselButtonData.map((button) => {
1862
+ switch (button?.buttonType) {
1863
+ case PHONE_NUMBER:
1864
+ return INITIAL_CAROUSEL_PHONE_NUMBER_DATA;
1865
+ case QUICK_REPLY:
1866
+ return INITIAL_CAROUSEL_QUICK_REPLY_DATA;
1867
+ default:
1868
+ return INITIAL_CAROUSEL_URL_DATA;
1869
+ }
1870
+ });
1871
+
1872
+ CAROUSEL_INITIAL_DATA[0].buttons = buttonArray;
1873
+ setCarouselData([...updatedCarouselData, CAROUSEL_INITIAL_DATA[0]]);
1874
+ };
1875
+
1876
+ const checkDisableAddCarouselButton = () => {
1877
+ return carouselData?.[0]?.buttons.some((button) => button?.isSaved === true);
1878
+ }
1879
+
1880
+ const operations = (
1881
+ <>
1882
+ <CapDivider type="vertical" />
1883
+ <CapButton
1884
+ onClick={addContent}
1885
+ type="flat"
1886
+ className="add-carousel-content-button"
1887
+ disabled={MAX_CAROUSEL_ALLOWED === carouselData.length || !checkDisableAddCarouselButton()}
1888
+ >
1889
+ <CapIcon type="plus" />
1890
+ </CapButton>
1891
+ </>
1892
+ )
1893
+
1894
+ const createModeContent = () => (
1515
1895
  <>
1516
1896
  {/* template name */}
1517
1897
  <CapHeader
@@ -1556,8 +1936,32 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
1556
1936
  onChange={onTemplateLanguageChange}
1557
1937
  value={templateLanguage}
1558
1938
  />
1559
- {/* template media type */}
1560
- {renderMediaSection()}
1939
+ <CapRow>
1940
+ {/* template category */}
1941
+ <CapColumn span={12}>
1942
+ {renderLabel("templateCategoryLabel")}
1943
+ <CapSelect
1944
+ id="select-whatsapp-category"
1945
+ options={
1946
+ host === HOST_TWILIO
1947
+ ? twilioCategoryOptions
1948
+ : karixGupshupCategoryOptions
1949
+ }
1950
+ onChange={onTemplateCategoryChange}
1951
+ value={templateCategory}
1952
+ />
1953
+ </CapColumn>
1954
+ {/* template media type */}
1955
+ <CapColumn span={12}>
1956
+ {renderLabel("mediaLabel")}
1957
+ <CapSelect
1958
+ id="select-whatsapp-media"
1959
+ options={mediaTypeOptions({host, templateCategory})}
1960
+ onChange={onTemplateMediaTypeChange}
1961
+ value={templateMediaType}
1962
+ />
1963
+ </CapColumn>
1964
+ </CapRow>
1561
1965
  {renderMediaComponent()}
1562
1966
  {/* this section is for header section in create mode */}
1563
1967
  {isMediaTypeText && isHostIsNotTwilio && !isAuthenticationTemplate && (
@@ -1689,8 +2093,39 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
1689
2093
  {renderUnsubscribeText()}
1690
2094
  </CapRow>
1691
2095
  {renderMessageLength(MESSAGE_TEXT)}
2096
+ {
2097
+ isMediaTypeCarousel && (
2098
+ <CapRow>
2099
+ <CapRow className="carousel-media-selection">
2100
+ <CapColumn className="carousel-media-selection-heading">
2101
+ <CapHeading type="h4">
2102
+ {formatMessage(messages.carouselMediaType)}
2103
+ </CapHeading>
2104
+ </CapColumn>
2105
+ <CapColumn>
2106
+ <CapRadioGroup
2107
+ id="carousel-media-radio"
2108
+ options={carouselMediaOptions}
2109
+ value={carouselMediaType}
2110
+ onChange={handleCarouselMediaOptions}
2111
+ className="whatsapp-media-radio"
2112
+ />
2113
+ </CapColumn>
2114
+ </CapRow>
2115
+ <CapRow className="whatsapp-carousel-tab">
2116
+ <CapTab
2117
+ defaultActiveKey={`${defaultActiveIndex}`}
2118
+ activeKey={activeIndex}
2119
+ tabBarExtraContent={operations}
2120
+ onChange={onTabChange}
2121
+ panes={getTabPanes(false)}
2122
+ />
2123
+ </CapRow>
2124
+ </CapRow>
2125
+ )
2126
+ }
1692
2127
  {/* this section if for footer in create mode */}
1693
- {isHostIsNotTwilio && (
2128
+ {isHostIsNotTwilio && !isMediaTypeCarousel && (
1694
2129
  <>
1695
2130
  <CapHeader
1696
2131
  className={`${isMediaTypeImage ? "whatsapp-heading-spacing" : ""}`}
@@ -1796,7 +2231,7 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
1796
2231
  {renderMessageLength(FOOTER_TEXT)}
1797
2232
  </>
1798
2233
  )}
1799
- {renderButtonsSection()}
2234
+ {!isMediaTypeCarousel && renderButtonsSection()}
1800
2235
  </>
1801
2236
  );
1802
2237
  //create methods end
@@ -1910,7 +2345,7 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
1910
2345
  };
1911
2346
 
1912
2347
  // on change event of Text Area
1913
- const textAreaValueChange = ({ target: { value, id } }, type) => {
2348
+ const textAreaValueChange = ({ target: { value, id } }, type, carousel) => {
1914
2349
  const numId = Number(id.slice(id.indexOf("_") + 1));
1915
2350
  //assign entered value to varMap
1916
2351
  if (type === HEADER_TEXT) {
@@ -1925,6 +2360,21 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
1925
2360
  arr[numId] = value;
1926
2361
  }
1927
2362
  setUpdatedHeaderData(arr);
2363
+ } else if (type === CAROUSEL_TEXT) {
2364
+ const carouselUpdatedBodyTextData = carousel?.data?.updatedBodyText || [];
2365
+ const arr = [...carouselUpdatedBodyTextData];
2366
+ if (value === "") {
2367
+ arr[numId] = id.slice(0, id.indexOf("_"));
2368
+ } else {
2369
+ arr[numId] = value;
2370
+ }
2371
+ const clonedCarouselBodyvarMap = carousel?.data?.varMap || {};
2372
+ const bodyVarMapData = {...clonedCarouselBodyvarMap, [id]: value};
2373
+ let tagFields = [];
2374
+ if (!isFullMode) {
2375
+ tagFields = tagValidation(arr, carouselBodyVarRegex, CAROUSEL_TEXT) || [];
2376
+ }
2377
+ handleCarouselValueChange(carousel?.carouselIndex, [...tagFields, {fieldName: "varMap", value: bodyVarMapData}, {fieldName: 'updatedBodyText', value: arr}])
1928
2378
  } else {
1929
2379
  const arr = [...updatedSmsEditor];
1930
2380
  varMap[id] = value;
@@ -1938,27 +2388,51 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
1938
2388
  }
1939
2389
  };
1940
2390
 
1941
- const textAreaValue = (idValue, type) => {
2391
+ const textAreaValue = (idValue, type, carousel) => {
1942
2392
  if (idValue >= 0) {
1943
- const value =
1944
- type === HEADER_TEXT
1945
- ? updatedHeaderData[idValue]
1946
- : updatedSmsEditor[idValue];
2393
+ let value = [];
2394
+ let regex = '';
2395
+ switch (type) {
2396
+ case HEADER_TEXT:
2397
+ value = updatedHeaderData[idValue];
2398
+ regex = headerValidVarRegex;
2399
+ break;
2400
+ case CAROUSEL_TEXT:
2401
+ value = carousel?.data?.updatedBodyText?.[idValue];
2402
+ regex = carouselBodyVarRegex;
2403
+ break;
2404
+ default:
2405
+ value = updatedSmsEditor[idValue];
2406
+ regex = validVarRegex;
2407
+ break;
2408
+ }
1947
2409
  //if value is there and it is not a variable return it
1948
- if (value && (value.match(type === HEADER_TEXT ? headerValidVarRegex : validVarRegex) || []).length === 0) {
2410
+ if (value && (value.match(regex) || []).length === 0) {
1949
2411
  return value;
1950
2412
  }
1951
2413
  }
1952
2414
  return "";
1953
2415
  };
1954
2416
 
1955
- const renderedEditMessage = (messageData, type) => {
2417
+ const renderedEditMessage = (messageData, type, carousel) => {
1956
2418
  const renderArray = [];
1957
- if (messageData?.length !== 0) {
2419
+ if (messageData && messageData?.length !== 0) {
1958
2420
  let varCount = 0;
1959
2421
  messageData.forEach((elem, index) => {
1960
2422
  // if var return textarea else return text
1961
- if (elem.match(type === HEADER_TEXT ? headerValidVarRegex : validVarRegex)?.length > 0) {
2423
+ let validRegex = '';
2424
+ switch (type) {
2425
+ case HEADER_TEXT:
2426
+ validRegex = headerValidVarRegex;
2427
+ break;
2428
+ case CAROUSEL_TEXT:
2429
+ validRegex = carouselBodyVarRegex;
2430
+ break;
2431
+ default:
2432
+ validRegex = validVarRegex;
2433
+ break;
2434
+ }
2435
+ if (elem.match(validRegex)?.length > 0) {
1962
2436
  varCount += 1;
1963
2437
  renderArray.push(
1964
2438
  <TextArea
@@ -1968,9 +2442,9 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
1968
2442
  value: `{{${varCount}}}`,
1969
2443
  })}
1970
2444
  autosize={{ minRows: 1, maxRows: 3 }}
1971
- onChange={(e) => textAreaValueChange(e, type)}
1972
- value={textAreaValue(index, type)}
1973
- onFocus={(e) => setTextAreaId(e, type)}
2445
+ onChange={(e) => textAreaValueChange(e, type, carousel)}
2446
+ value={textAreaValue(index, type, carousel)}
2447
+ onFocus={(e) => setTextAreaId(e, type, carousel?.carouselIndex)}
1974
2448
  disabled={templateStatus !== WHATSAPP_STATUSES.approved}
1975
2449
  />
1976
2450
  );
@@ -1987,7 +2461,7 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
1987
2461
  }
1988
2462
  });
1989
2463
  }
1990
- if (type !== HEADER_TEXT) {
2464
+ if (type !== HEADER_TEXT && type !== CAROUSEL_TEXT) {
1991
2465
  renderArray.push(renderUnsubscribeText());
1992
2466
  }
1993
2467
  return renderArray;
@@ -2008,9 +2482,17 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
2008
2482
  }
2009
2483
  };
2010
2484
 
2011
- const tagValidationErrorMessage = (type) => {
2012
- const { unsupportedTags = [], isBraceError } =
2013
- type === HEADER_TEXT ? headerTagValidationResponse : tagValidationResponse;
2485
+ const tagValidationErrorMessage = (type, carousel) => {
2486
+ let validationResponse = {};
2487
+ if (type === HEADER_TEXT) {
2488
+ validationResponse = headerTagValidationResponse;
2489
+ } else if (type === CAROUSEL_TEXT) {
2490
+ validationResponse = carousel?.carouselTagValidationErrMessage;
2491
+ } else {
2492
+ validationResponse = tagValidationResponse;
2493
+ }
2494
+ const { unsupportedTags = [], isBraceError } = validationResponse;
2495
+
2014
2496
  let tagError = "";
2015
2497
  if (unsupportedTags.length > 0) {
2016
2498
  tagError = formatMessage(globalMessages.unsupportedTagsValidationError, {
@@ -2023,7 +2505,7 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
2023
2505
  return <CapError>{tagError}</CapError>;
2024
2506
  };
2025
2507
 
2026
- const editModeContent = (
2508
+ const editModeContent = () => (
2027
2509
  <>
2028
2510
  {templateStatus && (
2029
2511
  <CapAlert
@@ -2155,51 +2637,77 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
2155
2637
  </>
2156
2638
  )}
2157
2639
  {/* button section view in edit mode*/}
2158
- <CapRow>
2159
- {isBtnTypeQuickReply ? (
2160
- <CapHeading type="h4" className="whatsapp-render-heading">
2161
- {formatMessage(messages.quickReplyButtons)}
2162
- </CapHeading>
2163
- ) : (
2164
- <>
2640
+ {isMediaTypeCarousel &&
2641
+ (
2642
+ <CapRow>
2643
+ <CapRow className="carousel-media-selection">
2644
+ <CapColumn className="carousel-media-selection-heading">
2645
+ <CapHeading type="h4">
2646
+ {formatMessage(messages.carouselMediaType)}
2647
+ </CapHeading>
2648
+ </CapColumn>
2649
+ <CapColumn>
2650
+ <CapLabel type="label15">{carouselData?.[0]?.mediaType}</CapLabel>
2651
+ </CapColumn>
2652
+ </CapRow>
2653
+ <CapRow className="whatsapp-carousel-tab">
2654
+ <CapTab
2655
+ defaultActiveKey={`${defaultActiveIndex}`}
2656
+ activeKey={activeIndex}
2657
+ onChange={onTabChange}
2658
+ panes={getTabPanes(true)}
2659
+ />
2660
+ </CapRow>
2661
+ </CapRow>
2662
+ )
2663
+ }
2664
+ {!isMediaTypeCarousel &&
2665
+ <CapRow>
2666
+ {isBtnTypeQuickReply ? (
2165
2667
  <CapHeading type="h4" className="whatsapp-render-heading">
2166
- {formatMessage(messages.btnLabel)}
2668
+ {formatMessage(messages.quickReplyButtons)}
2167
2669
  </CapHeading>
2670
+ ) : (
2671
+ <>
2672
+ <CapHeading type="h4" className="whatsapp-render-heading">
2673
+ {formatMessage(messages.btnLabel)}
2674
+ </CapHeading>
2675
+ <CapLabel type="label15">
2676
+ {isBtnTypeCta
2677
+ ? formatMessage(messages.btnTypeCTA)
2678
+ : !isAuthenticationTemplate && formatMessage(messages.btnTypeNone)}
2679
+ </CapLabel>
2680
+ </>
2681
+ )}
2682
+ {isAuthenticationTemplate && (
2168
2683
  <CapLabel type="label15">
2169
- {isBtnTypeCta
2170
- ? formatMessage(messages.btnTypeCTA)
2171
- : !isAuthenticationTemplate && formatMessage(messages.btnTypeNone)}
2684
+ <CapWhatsappQuickReply
2685
+ authenticationFlow={true}
2686
+ />
2172
2687
  </CapLabel>
2173
- </>
2174
- )}
2175
- {isAuthenticationTemplate && (
2176
- <CapLabel type="label15">
2688
+ )}
2689
+ {isBtnTypeCta && (
2690
+ <CapWhatsappCTA
2691
+ ctaData={ctaData}
2692
+ updateHandler={updateHandler}
2693
+ deleteHandler={deleteHandler}
2694
+ isEditFlow={isEditFlow}
2695
+ hostName={host}
2696
+ tags={tags || []}
2697
+ injectedTags={injectedTags || {}}
2698
+ selectedOfferDetails={selectedOfferDetails}
2699
+ />
2700
+ )}
2701
+ {isBtnTypeQuickReply && (
2177
2702
  <CapWhatsappQuickReply
2178
- authenticationFlow={true}
2703
+ quickReplyData={quickReplyData}
2704
+ isEditFlow={isEditFlow}
2705
+ renderMessageLength={renderMessageLength}
2706
+ setQuickReplyData={setQuickReplyData}
2179
2707
  />
2180
- </CapLabel>
2181
- )}
2182
- {isBtnTypeCta && (
2183
- <CapWhatsappCTA
2184
- ctaData={ctaData}
2185
- updateHandler={updateHandler}
2186
- deleteHandler={deleteHandler}
2187
- isEditFlow={isEditFlow}
2188
- hostName={host}
2189
- tags={tags || []}
2190
- injectedTags={injectedTags || {}}
2191
- selectedOfferDetails={selectedOfferDetails}
2192
- />
2193
- )}
2194
- {isBtnTypeQuickReply && (
2195
- <CapWhatsappQuickReply
2196
- quickReplyData={quickReplyData}
2197
- isEditFlow={isEditFlow}
2198
- renderMessageLength={renderMessageLength}
2199
- setQuickReplyData={setQuickReplyData}
2200
- />
2201
- )}
2202
- </CapRow>
2708
+ )}
2709
+ </CapRow>
2710
+ }
2203
2711
  </>
2204
2712
  );
2205
2713
  //edit methods end
@@ -2265,6 +2773,11 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
2265
2773
  showUrlPreview,
2266
2774
  metaTagsDetails,
2267
2775
  }),
2776
+ ...(isMediaTypeCarousel && {
2777
+ carouselData,
2778
+ carouselMediaType,
2779
+ isEditFlow,
2780
+ }),
2268
2781
  }}
2269
2782
  whatsappContentLen={computeTextLength()}
2270
2783
  whatsappAccountName={accountName}
@@ -2272,20 +2785,34 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
2272
2785
  );
2273
2786
  };
2274
2787
 
2275
- const isEditDoneDisabled = () =>
2276
- isTagValidationError ||
2788
+ const isEditDoneDisabled = () => {
2789
+ let carouselDisableCheck = false;
2790
+ if (isMediaTypeCarousel) {
2791
+ carouselDisableCheck = carouselData.some((data) => {
2792
+ return (
2793
+ data.carouselTagValidationErr ||
2794
+ Object.values(data.varMap).some((inputValue) => inputValue === "") ||
2795
+ computeTextLength(CAROUSEL_TEXT, data) > TEMPLATE_MESSAGE_MAX_LENGTH ||
2796
+ (carouselMediaType === "image" && !data.imageSrc) ||
2797
+ (carouselMediaType === "video" && !data.videoSrc) ||
2798
+ data?.buttons.some((btn) => btn?.url?.includes("{{1}}"))
2799
+ );
2800
+ });
2801
+ }
2802
+ return (isTagValidationError ||
2277
2803
  isHeaderTagValidationError ||
2278
2804
  Object.values(varMap).some((inputValue) => inputValue === "") ||
2279
2805
  Object.values(headerVarMappedData).some((inputValue) => inputValue === "") ||
2280
2806
  computeTextLength(MESSAGE_TEXT) > TEMPLATE_MESSAGE_MAX_LENGTH ||
2281
2807
  computeTextLength(HEADER_TEXT) > TEMPLATE_HEADER_MAX_LENGTH ||
2282
- (isBtnTypeCta && ctaData.some((btn) => btn?.url?.includes("{{1}}"))) || isMediatypeValid();
2808
+ (isBtnTypeCta && ctaData.some((btn) => btn?.url?.includes("{{1}}"))) || isMediatypeValid()) || carouselDisableCheck;
2809
+ }
2283
2810
 
2284
2811
  return (
2285
2812
  <CapSpin spinning={spin}>
2286
2813
  <CapRow className="cap-whatsapp-creatives">
2287
2814
  <CapColumn span={14}>
2288
- {isEditFlow ? editModeContent : createModeContent}
2815
+ {isEditFlow ? editModeContent() : createModeContent()}
2289
2816
  <div className="whatsapp-scroll-div" />
2290
2817
  </CapColumn>
2291
2818
  <CapColumn span={10} className="whatsapp-preview-container">
@@ -2322,7 +2849,7 @@ const isAuthenticationTemplate = isEqual(templateCategory, WHATSAPP_CATEGORIES.a
2322
2849
  </CapButton>
2323
2850
  </>
2324
2851
  )}
2325
- {!isFullMode && isEditFlow && (
2852
+ {isEditFlow && (
2326
2853
  <CapTooltip
2327
2854
  title={
2328
2855
  isEditDoneDisabled()