@capillarytech/creatives-library 8.0.90 → 8.0.91

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