@capillarytech/creatives-library 7.17.81 → 7.17.82-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -57,6 +57,7 @@ import {
57
57
  WHATSAPP_MEDIA_TYPES,
58
58
  WHATSAPP_BUTTON_TYPES,
59
59
  INITIAL_CTA_DATA,
60
+ INITIAL_QUICK_REPLY_DATA,
60
61
  ALLOWED_IMAGE_EXTENSIONS_REGEX,
61
62
  WHATSAPP_IMG_SIZE,
62
63
  HOST_TWILIO,
@@ -68,6 +69,11 @@ import {
68
69
  WHATSAPP_VIDEO_SIZE,
69
70
  DOCUMENT_FORMAT,
70
71
  DOCUMENT_SIZE,
72
+ TEMPLATE_HEADER_MAX_LENGTH,
73
+ TEMPLATE_BUTTON_TEXT_MAX_LENGTH,
74
+ HEADER_TEXT,
75
+ FOOTER_TEXT,
76
+ MESSAGE_TEXT
71
77
  } from './constants';
72
78
  import { DATE_DISPLAY_FORMAT, TIME_DISPLAY_FORMAT } from '../App/constants';
73
79
  import messages from './messages';
@@ -87,10 +93,12 @@ import { getCdnUrl } from '../../utils/cdnTransformation';
87
93
  import CapVideoUpload from '../../v2Components/CapVideoUpload';
88
94
  import CapDocumentUpload from '../../v2Components/CapDocumentUpload';
89
95
  import { getWhatsappDocPreview } from './utils';
96
+ import CapWhatsappQuickReply from '../../v2Components/CapWhatsappQuickReply';
90
97
 
91
98
  let varMap = {};
92
99
  let editContent = {};
93
100
  let tagValidationResponse = {};
101
+ let headerTagValidationResponse = {};
94
102
 
95
103
  export const Whatsapp = (props) => {
96
104
  const {
@@ -127,6 +135,10 @@ export const Whatsapp = (props) => {
127
135
  WHATSAPP_MEDIA_TYPES.TEXT,
128
136
  );
129
137
  const [templateMessage, setTemplateMessage] = useState('');
138
+ const [templateHeader, setTemplateHeader] = useState('');
139
+ const [templateHeaderError, setTemplateHeaderError] = useState(false);
140
+ const [templateFooter, setTemplateFooter] = useState('');
141
+ const [templateFooterError, setTemplateFooterError] = useState(false);
130
142
  const [templateMessageError, setTemplateMessageError] = useState(false);
131
143
  const [addedVarCount, setAddedVarCount] = useState(0);
132
144
  const [accountId, setAccountId] = useState('');
@@ -159,10 +171,20 @@ export const Whatsapp = (props) => {
159
171
  //buttons
160
172
  const [buttonType, setButtonType] = useState(WHATSAPP_BUTTON_TYPES.NONE);
161
173
  const [ctaData, setCtadata] = useState(INITIAL_CTA_DATA);
174
+ const [quickReplyData, setQuickReplyData] = useState(
175
+ INITIAL_QUICK_REPLY_DATA
176
+ );
177
+ const [tempHeaderData, setTempHeaderData] = useState([]);
178
+ const [headerVarMappedData, setHeaderVarMappedData] = useState({});
179
+ const [updatedHeaderData, setUpdatedHeaderData] = useState([]);
180
+ const [headerTextAreaId, setHeaderTextAreaId] = useState();
181
+ const [isHeaderTagValidationError, updateIsHeaderTagValidationError] =
182
+ useState(false);
162
183
 
163
184
  const validVarRegex = /{{([1-9]|1[0-9])}}/g;
164
185
 
165
186
  const isBtnTypeCta = buttonType === WHATSAPP_BUTTON_TYPES.CTA;
187
+ const isBtnTypeQuickReply = buttonType === WHATSAPP_BUTTON_TYPES.QUICK_REPLY;
166
188
  const isMediaTypeText = templateMediaType === WHATSAPP_MEDIA_TYPES.TEXT;
167
189
  const isMediaTypeImage = templateMediaType === WHATSAPP_MEDIA_TYPES.IMAGE;
168
190
  const isMediaTypeVideo = templateMediaType === WHATSAPP_MEDIA_TYPES.VIDEO;
@@ -213,6 +235,7 @@ export const Whatsapp = (props) => {
213
235
  return () => {
214
236
  actions.resetEditTemplate();
215
237
  varMap = {};
238
+ setHeaderVarMappedData({});
216
239
  };
217
240
  }, [paramObj.id]);
218
241
 
@@ -241,6 +264,7 @@ export const Whatsapp = (props) => {
241
264
  buttons = [],
242
265
  videoPreviewImg = '',
243
266
  whatsappDocParams = {},
267
+ whatsappMedia: { header = '', footer = '' } = {},
244
268
  } = editContent;
245
269
  setTemplateCategory(category);
246
270
  setTemplateStatus(status);
@@ -262,6 +286,8 @@ export const Whatsapp = (props) => {
262
286
  });
263
287
  setKarixFileHandle(karixFileHandle);
264
288
  setButtonType(btnType);
289
+ setTemplateFooter(footer);
290
+ setTemplateHeader(header);
265
291
  if (btnType === WHATSAPP_BUTTON_TYPES.CTA && buttons.length > 0) {
266
292
  setCtadata(
267
293
  buttons.map((cta) => {
@@ -288,10 +314,59 @@ export const Whatsapp = (props) => {
288
314
  }),
289
315
  );
290
316
  }
317
+ if (btnType === WHATSAPP_BUTTON_TYPES.QUICK_REPLY && buttons.length > 0) {
318
+ setQuickReplyData(buttons);
319
+ }
291
320
  computeTempMsgArray();
321
+ if (header) {
322
+ computeHeaderMsgArray();
323
+ }
292
324
  }
293
325
  }, [editData.templateDetails || templateData]);
294
326
 
327
+ const computeHeaderMsgArray = () => {
328
+ let msg = get(editContent, `whatsappMedia.header`, '');
329
+ const validVarArr = msg.match(validVarRegex) || [];
330
+ const templateHeaderArray = [];
331
+ while (msg.length !== 0) {
332
+ //converting content string to an array split at var
333
+ const index = msg.indexOf(validVarArr[0]);
334
+ if (index !== -1) {
335
+ templateHeaderArray.push(msg.substring(0, index)); //push string before var
336
+ templateHeaderArray.push(validVarArr[0]); //push var
337
+ msg = msg.substring(index + validVarArr[0].length, msg.length); //remaining str
338
+ validVarArr.shift(); //remove considered var
339
+ } else {
340
+ templateHeaderArray.push(msg); //remaining str
341
+ break;
342
+ }
343
+ }
344
+ setTempHeaderData(templateHeaderArray);
345
+ if (templateHeaderArray.length !== 0) {
346
+ let headerVarMap = {};
347
+ const {
348
+ whatsappMedia: { headerVarMapped = {} },
349
+ } = editContent;
350
+ if (!isEmpty(headerVarMapped)) {
351
+ headerVarMap = cloneDeep(headerVarMapped);
352
+ } else {
353
+ for (let i = 0; i < templateHeaderArray.length; i += 1) {
354
+ if (templateHeaderArray[i].match(validVarRegex)?.length > 0) {
355
+ headerVarMap[`${templateHeaderArray[i]}_${i}`] = '';
356
+ }
357
+ }
358
+ }
359
+ const arr = [...templateHeaderArray];
360
+ for (const key in headerVarMap) {
361
+ if (headerVarMap[key] !== '') {
362
+ arr[key.slice(key.indexOf('_') + 1)] = headerVarMap[key];
363
+ }
364
+ }
365
+ setHeaderVarMappedData(headerVarMap);
366
+ setUpdatedHeaderData(arr);
367
+ }
368
+ };
369
+
295
370
  const computeTempMsgArray = () => {
296
371
  let msg = get(editContent, `languages[0].content`, '');
297
372
  const validVarArr = msg.match(validVarRegex) || [];
@@ -358,10 +433,10 @@ export const Whatsapp = (props) => {
358
433
  }, [tempMsgArray]);
359
434
 
360
435
  useEffect(() => {
361
- if (tempMsgArray?.length && !loadingTags) {
436
+ if ((tempMsgArray?.length || tempHeaderData?.length) && !loadingTags) {
362
437
  setSpin(false);
363
438
  }
364
- }, [tempMsgArray, loadingTags]);
439
+ }, [tempMsgArray, loadingTags, tempHeaderData]);
365
440
 
366
441
  // tag Code start from here
367
442
  useEffect(() => {
@@ -414,6 +489,26 @@ export const Whatsapp = (props) => {
414
489
  }
415
490
  }, [updatedSmsEditor, tags]);
416
491
 
492
+ useEffect(() => {
493
+ if (
494
+ !isFullMode &&
495
+ updatedHeaderData?.length > 0 &&
496
+ !updatedHeaderData.join('').match(validVarRegex)
497
+ ) {
498
+ headerTagValidationResponse =
499
+ validateTags({
500
+ content: updatedHeaderData.join(''),
501
+ tagsParam: tags,
502
+ injectedTagsParams: injectedTags,
503
+ location,
504
+ tagModule: getDefaultTags,
505
+ }) || {};
506
+ updateIsHeaderTagValidationError(
507
+ headerTagValidationResponse.unsupportedTags.length > 0
508
+ );
509
+ }
510
+ }, [updatedHeaderData, tags]);
511
+
417
512
  const handleOnTagsContextChange = (data) => {
418
513
  const { type } = location.query || {};
419
514
  const isEmbedded = type === EMBEDDED;
@@ -446,9 +541,35 @@ export const Whatsapp = (props) => {
446
541
  }
447
542
  };
448
543
 
544
+ const onHeaderTagSelect = (data) => {
545
+ if (headerVarMappedData && updatedHeaderData) {
546
+ const numId = Number(
547
+ headerTextAreaId?.slice(headerTextAreaId?.indexOf('_') + 1)
548
+ );
549
+ if (!isNaN(numId)) {
550
+ const arr = [...updatedHeaderData];
551
+ //when trying to insert tag in empty textarea,{#var#} is replaced with "" and then tag is added
552
+ if (arr[numId]?.match(validVarRegex)?.length > 0) {
553
+ arr[numId] = '';
554
+ }
555
+ const messageData = `${arr[numId]}{{${data}}}`;
556
+ arr[numId] = messageData;
557
+ setHeaderVarMappedData((prevState) => ({
558
+ ...prevState,
559
+ [textAreaId]: messageData,
560
+ }));
561
+ setUpdatedHeaderData(arr);
562
+ }
563
+ }
564
+ };
565
+
449
566
  //setting the id of currently selected text area, is used onTagSelect
450
- const setTextAreaId = ({ target: { id } }) => {
451
- updateTextAreaId(id);
567
+ const setTextAreaId = ({ target: { id } }, type) => {
568
+ if (type === HEADER_TEXT) {
569
+ setHeaderTextAreaId(id);
570
+ } else {
571
+ updateTextAreaId(id);
572
+ }
452
573
  };
453
574
  // tag Code end
454
575
 
@@ -532,6 +653,7 @@ export const Whatsapp = (props) => {
532
653
  const onChangeButtonType = ({ target: { value } }) => {
533
654
  setButtonType(value);
534
655
  setCtadata(INITIAL_CTA_DATA);
656
+ setQuickReplyData(INITIAL_QUICK_REPLY_DATA);
535
657
  };
536
658
 
537
659
  const updateHandler = (data, index, full) => {
@@ -557,6 +679,16 @@ export const Whatsapp = (props) => {
557
679
  });
558
680
  };
559
681
 
682
+ //used by create and edit
683
+ const renderMessageLength = (type, currentLength) => (
684
+ <CapHeading type="label1" className="whatsapp-render-message-length">
685
+ {formatMessage(messages.templateMessageLength, {
686
+ currentLength: currentLength ? currentLength : computeTextLength(type),
687
+ maxLength: maxLengthByType(type),
688
+ })}
689
+ </CapHeading>
690
+ );
691
+
560
692
  const buttonRadioOptions = [
561
693
  {
562
694
  value: WHATSAPP_BUTTON_TYPES.NONE,
@@ -591,15 +723,11 @@ export const Whatsapp = (props) => {
591
723
  {
592
724
  value: WHATSAPP_BUTTON_TYPES.QUICK_REPLY,
593
725
  label: (
594
- <CapTooltip
595
- placement="bottom"
596
- title={!isEditFlow && formatMessage(messages.disabledFeatureTooltip)}
597
- >
726
+ <>
598
727
  <div
599
728
  className="whatsapp-button-quick-reply"
600
729
  style={{
601
- marginTop: isBtnTypeCta ? '0px' : '24px',
602
- opacity: isEditFlow ? '' : '0.4',
730
+ marginTop: "24px",
603
731
  }}
604
732
  >
605
733
  <CapHeading type="h4">
@@ -607,9 +735,16 @@ export const Whatsapp = (props) => {
607
735
  </CapHeading>
608
736
  <CapLabel>{formatMessage(messages.quickReplyDesc)}</CapLabel>
609
737
  </div>
610
- </CapTooltip>
738
+ {isBtnTypeQuickReply && (
739
+ <CapWhatsappQuickReply
740
+ quickReplyData={quickReplyData}
741
+ isEditFlow={isEditFlow}
742
+ renderMessageLength={renderMessageLength}
743
+ setQuickReplyData={setQuickReplyData}
744
+ />
745
+ )}
746
+ </>
611
747
  ),
612
- disabled: true,
613
748
  },
614
749
  ];
615
750
 
@@ -664,24 +799,43 @@ export const Whatsapp = (props) => {
664
799
  );
665
800
  };
666
801
 
667
- const computeTextLength = () => {
668
- let whatsappContentLen = 0;
669
- whatsappContentLen = isEditFlow
670
- ? updatedSmsEditor.join('').length
671
- : templateMessage.length;
672
- whatsappContentLen += unsubscribeRequired ? UNSUBSCRIBE_TEXT_LENGTH : 0;
673
- return whatsappContentLen;
802
+ const computeTextLength = (type) => {
803
+ switch (type) {
804
+ case MESSAGE_TEXT:
805
+ let whatsappContentLen = 0;
806
+ whatsappContentLen = isEditFlow
807
+ ? updatedSmsEditor.join("").length
808
+ : templateMessage.length;
809
+ whatsappContentLen += unsubscribeRequired ? UNSUBSCRIBE_TEXT_LENGTH : 0;
810
+ return whatsappContentLen;
811
+ case HEADER_TEXT:
812
+ let headerContentLen = 0;
813
+ headerContentLen = isEditFlow
814
+ ? updatedHeaderData.join("").length
815
+ : templateHeader.length;
816
+ return headerContentLen || 0;
817
+ case FOOTER_TEXT:
818
+ return templateFooter.length || 0;
819
+ default:
820
+ let overallLength =
821
+ computeTextLength(MESSAGE_TEXT) +
822
+ computeTextLength(HEADER_TEXT) +
823
+ computeTextLength(FOOTER_TEXT);
824
+ return overallLength;
825
+ }
674
826
  };
675
827
 
676
- //used by create and edit
677
- const renderMessageLength = () => (
678
- <CapHeading type="label1" className="whatsapp-render-message-length">
679
- {formatMessage(messages.templateMessageLength, {
680
- currentLength: computeTextLength(),
681
- maxLength: TEMPLATE_MESSAGE_MAX_LENGTH,
682
- })}
683
- </CapHeading>
684
- );
828
+ const maxLengthByType = (type) => {
829
+ switch (type) {
830
+ case MESSAGE_TEXT:
831
+ return TEMPLATE_MESSAGE_MAX_LENGTH;
832
+ case HEADER_TEXT:
833
+ case FOOTER_TEXT:
834
+ return TEMPLATE_HEADER_MAX_LENGTH;
835
+ case "buttonText":
836
+ return TEMPLATE_BUTTON_TEXT_MAX_LENGTH;
837
+ }
838
+ };
685
839
 
686
840
  const renderButtonsSection = () => (
687
841
  <>
@@ -866,12 +1020,45 @@ export const Whatsapp = (props) => {
866
1020
  setTemplateMessageError(error);
867
1021
  };
868
1022
 
1023
+ const onHeaderAddVar = () => {
1024
+ const validVarArr = templateHeader.match(validVarRegex) || [];
1025
+ const tempMsg = `${templateHeader}{{${validVarArr.length + 1}}}`;
1026
+ const error = templateHeaderErrorHandler(tempMsg);
1027
+ setTemplateHeader(tempMsg);
1028
+ setTemplateHeaderError(error);
1029
+ };
1030
+
869
1031
  const onTemplateMessageChange = ({ target: { value } }) => {
870
1032
  const error = templateMessageErrorHandler(value);
871
1033
  setTemplateMessage(value);
872
1034
  setTemplateMessageError(error);
873
1035
  };
874
1036
 
1037
+ const onTemplateHeaderChanges = ({ target: { value } }) => {
1038
+ const error = templateHeaderErrorHandler(value);
1039
+ setTemplateHeader(value);
1040
+ setTemplateHeaderError(error);
1041
+ };
1042
+
1043
+ const onTemplateFooterChanges = ({ target: { value } }) => {
1044
+ let error = false;
1045
+ if (value?.length > TEMPLATE_HEADER_MAX_LENGTH) {
1046
+ error = formatMessage(messages.templateFooterLengthError);
1047
+ }
1048
+ setTemplateFooter(value);
1049
+ setTemplateFooterError(error);
1050
+ };
1051
+
1052
+ const templateHeaderErrorHandler = (value) => {
1053
+ let errorMessage = false;
1054
+ if (value?.length > TEMPLATE_HEADER_MAX_LENGTH) {
1055
+ errorMessage = formatMessage(messages.templateHeaderLengthError);
1056
+ } else {
1057
+ errorMessage = variableErrorHandling(value, HEADER_TEXT);
1058
+ }
1059
+ return errorMessage;
1060
+ };
1061
+
875
1062
  const templateMessageErrorHandler = (value) => {
876
1063
  let errorMessage = false;
877
1064
  if (value === '') {
@@ -882,41 +1069,50 @@ export const Whatsapp = (props) => {
882
1069
  ) {
883
1070
  errorMessage = formatMessage(messages.templateMessageLengthError);
884
1071
  } else {
885
- const validVarArr = value.match(validVarRegex) || [];
886
- const validVarSet = [...new Set(validVarArr)];
887
-
888
- const invalidVarRegex = /{{(.*?)}}/g;
889
- const invalidVarArr = value.match(invalidVarRegex) || [];
890
- const invalidVarSet = [...new Set(invalidVarArr)];
891
-
892
- const noContentBetweenVars = /}}\s*{{/g;
893
- const moreThanTwoBrackets = /{{3,}([1-9]|1[0-9])}{3,}/g;
894
- const consecutiveNewLines = /\n\s*\n\s*\n/;
895
- if (value.match(consecutiveNewLines)) {
896
- errorMessage = formatMessage(messages.removeMultinewlineChars);
897
- } else if (validVarArr?.length > 0 || invalidVarArr?.length > 0) {
898
- if (validVarArr?.length !== validVarSet?.length) {
899
- //checks for repetations like Hi {{1}}, offer for you {{1}}
900
- errorMessage = formatMessage(messages.repetativeVars);
901
- } else if (invalidVarSet?.length !== validVarSet?.length) {
902
- //checks for invalid vars like Hi {{abcd}}, offer for you {{^_^}}
903
- errorMessage = formatMessage(messages.unknownVars, {one: '{{1}}', nineteen: '{{19}}'});
904
- } else if (value.match(noContentBetweenVars)?.length > 0) {
905
- //checks for text between vars like Hi {{1}}{{2}}
906
- errorMessage = formatMessage(messages.noContentBetweenVars);
907
- } else if (value.match(moreThanTwoBrackets)?.length > 0) {
908
- //checks for >2 brackets {{{1}}}
909
- errorMessage = formatMessage(messages.useTwoBracketsOnly);
1072
+ errorMessage = variableErrorHandling(value, MESSAGE_TEXT);
1073
+ }
1074
+ return errorMessage;
1075
+ };
1076
+
1077
+ const variableErrorHandling = (value, type) => {
1078
+ let errorMessage = false;
1079
+ const validVarArr = value.match(validVarRegex) || [];
1080
+ const validVarSet = [...new Set(validVarArr)];
1081
+
1082
+ const invalidVarRegex = /{{(.*?)}}/g;
1083
+ const invalidVarArr = value.match(invalidVarRegex) || [];
1084
+ const invalidVarSet = [...new Set(invalidVarArr)];
1085
+
1086
+ const noContentBetweenVars = /}}\s*{{/g;
1087
+ const moreThanTwoBrackets = /{{3,}([1-9]|1[0-9])}{3,}/g;
1088
+ const consecutiveNewLines = /\n\s*\n\s*\n/;
1089
+ if (value.match(consecutiveNewLines)) {
1090
+ errorMessage = formatMessage(messages.removeMultinewlineChars);
1091
+ } else if (validVarArr?.length > 0 || invalidVarArr?.length > 0) {
1092
+ if (validVarArr?.length !== validVarSet?.length) {
1093
+ //checks for repetations like Hi {{1}}, offer for you {{1}}
1094
+ errorMessage = formatMessage(messages.repetativeVars);
1095
+ } else if (invalidVarSet?.length !== validVarSet?.length) {
1096
+ //checks for invalid vars like Hi {{abcd}}, offer for you {{^_^}}
1097
+ errorMessage = formatMessage(messages.unknownVars, {
1098
+ one: "{{1}}",
1099
+ nineteen: "{{19}}",
1100
+ });
1101
+ } else if (value.match(noContentBetweenVars)?.length > 0) {
1102
+ //checks for text between vars like Hi {{1}}{{2}}
1103
+ errorMessage = formatMessage(messages.noContentBetweenVars);
1104
+ } else if (value.match(moreThanTwoBrackets)?.length > 0) {
1105
+ //checks for >2 brackets {{{1}}}
1106
+ errorMessage = formatMessage(messages.useTwoBracketsOnly);
1107
+ } else {
1108
+ //checks if vars are added sequentially like, Hi {{1}}, offer for you {{2}} today {{3}}
1109
+ const checkSequence = [...validVarSet].filter(
1110
+ (validVar, index) => `{{${index + 1}}}` !== validVar
1111
+ );
1112
+ if (checkSequence?.length > 0) {
1113
+ errorMessage = formatMessage(messages.sequenceVars, { one: "{{1}}" });
910
1114
  } else {
911
- //checks if vars are added sequentially like, Hi {{1}}, offer for you {{2}} today {{3}}
912
- const checkSequence = [...validVarSet].filter(
913
- (validVar, index) => `{{${index + 1}}}` !== validVar,
914
- );
915
- if (checkSequence?.length > 0) {
916
- errorMessage = formatMessage(messages.sequenceVars, {one: '{{1}}'});
917
- } else {
918
- setAddedVarCount(validVarSet?.length || 0);
919
- }
1115
+ if (type === MESSAGE_TEXT) setAddedVarCount(validVarSet?.length || 0);
920
1116
  }
921
1117
  }
922
1118
  }
@@ -965,13 +1161,23 @@ export const Whatsapp = (props) => {
965
1161
  };
966
1162
  });
967
1163
 
1164
+ const getQuickReplyData = () =>
1165
+ quickReplyData.map((quickReply) => {
1166
+ const { index, text, type } = quickReply;
1167
+ return {
1168
+ index,
1169
+ text,
1170
+ type,
1171
+ };
1172
+ });
1173
+
968
1174
  const createPayload = () => {
969
1175
  let mediaParams = {};
970
1176
  const { whatsappVideoSrc = '', whatsappVideoPreviewImg = '' } = whatsappVideoSrcAndPreview;
971
1177
  switch (templateMediaType) {
972
1178
  case WHATSAPP_MEDIA_TYPES.IMAGE:
973
1179
  mediaParams = {
974
- imageUrl: getCdnUrl({url: whatsappImageSrc, channelName: WHATSAPP }),
1180
+ imageUrl: getCdnUrl({ url: whatsappImageSrc, channelName: WHATSAPP }),
975
1181
  karixFileHandle,
976
1182
  };
977
1183
  break;
@@ -992,7 +1198,7 @@ export const Whatsapp = (props) => {
992
1198
  default:
993
1199
  break;
994
1200
  }
995
- return ({
1201
+ return {
996
1202
  name: templateName,
997
1203
  versions: {
998
1204
  base: {
@@ -1012,16 +1218,25 @@ export const Whatsapp = (props) => {
1012
1218
  mediaType: templateMediaType,
1013
1219
  ...mediaParams,
1014
1220
  varMapped: !isFullMode ? varMap : {},
1015
- templateEditor: !isFullMode && tempMsgArray.join(''),
1221
+ templateEditor: !isFullMode && tempMsgArray.join(""),
1016
1222
  accountId,
1017
1223
  accessToken,
1018
1224
  hostName: host,
1225
+ ...(isBtnTypeQuickReply && {
1226
+ buttonType,
1227
+ buttons: getQuickReplyData(),
1228
+ }),
1229
+ whatsappMedia: {
1230
+ header: isEditFlow && !isFullMode ? updatedHeaderData.join("") : templateHeader,
1231
+ headerVarMapped: !isFullMode ? headerVarMappedData : {},
1232
+ footer: templateFooter || "",
1233
+ },
1019
1234
  },
1020
1235
  },
1021
1236
  },
1022
1237
  },
1023
1238
  type: WHATSAPP,
1024
- });
1239
+ };
1025
1240
  };
1026
1241
 
1027
1242
  const actionCallback = ({ errorMessage }) => {
@@ -1103,6 +1318,10 @@ export const Whatsapp = (props) => {
1103
1318
  //if button type is cta and there are no buttons saved
1104
1319
  return true;
1105
1320
  }
1321
+
1322
+ if (isBtnTypeQuickReply) {
1323
+ return !quickReplyData.every((quickReply) => quickReply.isSaved === true);
1324
+ }
1106
1325
  return false;
1107
1326
  };
1108
1327
 
@@ -1154,22 +1373,24 @@ export const Whatsapp = (props) => {
1154
1373
  onChange={onTemplateNameChange}
1155
1374
  errorMessage={templateNameError}
1156
1375
  placeholder={formatMessage(globalMessages.templateNamePlaceholder)}
1157
- defaultValue={templateName || ''}
1158
- value={templateName || ''}
1376
+ defaultValue={templateName || ""}
1377
+ value={templateName || ""}
1159
1378
  size="default"
1160
1379
  />
1161
1380
  {/* template category */}
1162
- {renderLabel('templateCategoryLabel')}
1381
+ {renderLabel("templateCategoryLabel")}
1163
1382
  <CapSelect
1164
1383
  id="select-whatsapp-category"
1165
1384
  options={
1166
- host === HOST_TWILIO ? twilioCategoryOptions : karixGupshupCategoryOptions
1385
+ host === HOST_TWILIO
1386
+ ? twilioCategoryOptions
1387
+ : karixGupshupCategoryOptions
1167
1388
  }
1168
1389
  onChange={onTemplateCategoryChange}
1169
1390
  value={templateCategory}
1170
1391
  />
1171
1392
  {/* template language */}
1172
- {renderLabel('messageLanguageLabel')}
1393
+ {renderLabel("messageLanguageLabel")}
1173
1394
  <CapSelect
1174
1395
  id="select-whatsapp-language"
1175
1396
  options={LANGUAGE_OPTIONS || []}
@@ -1181,7 +1402,53 @@ export const Whatsapp = (props) => {
1181
1402
  {renderMediaComponent()}
1182
1403
  {/* template message create flow */}
1183
1404
  <CapHeader
1184
- className={`${isMediaTypeImage ? 'whatsapp-heading-spacing' : ''}`}
1405
+ className={`${isMediaTypeImage ? "whatsapp-heading-spacing" : ""}`}
1406
+ title={
1407
+ <CapHeading type="h4" className="whatsapp-create-mode-heading">
1408
+ {formatMessage(messages.templateHeaderLabel)}
1409
+ <CapTooltipWithInfo
1410
+ placement="right"
1411
+ infoIconProps={{
1412
+ style: { marginLeft: CAP_SPACE_04 },
1413
+ }}
1414
+ autoAdjustOverflow
1415
+ title={<FormattedMessage {...messages.templateHeaderTooltip} />}
1416
+ />
1417
+ <CapHeading className="whatsapp-optional-label1 align-item-center">
1418
+ {formatMessage(messages.optional)}
1419
+ </CapHeading>
1420
+ </CapHeading>
1421
+ }
1422
+ suffix={
1423
+ <CapButton
1424
+ type="flat"
1425
+ isAddBtn
1426
+ onClick={onHeaderAddVar}
1427
+ disabled={templateHeaderError && templateHeader}
1428
+ >
1429
+ {formatMessage(messages.addVar)}
1430
+ </CapButton>
1431
+ }
1432
+ />
1433
+ <CapRow className="whatsapp-create-template-message-input whatsapp-create-template-header-input">
1434
+ <TextArea
1435
+ id="whatsapp-create-template-message-input"
1436
+ autosize={{ minRows: 1, maxRows: 5 }}
1437
+ placeholder={formatMessage(messages.templateMessagePlaceholder)}
1438
+ onChange={onTemplateHeaderChanges}
1439
+ errorMessage={
1440
+ templateHeaderError && (
1441
+ <CapError className="whatsapp-template-message-error">
1442
+ {templateHeaderError}
1443
+ </CapError>
1444
+ )
1445
+ }
1446
+ value={templateHeader || ""}
1447
+ />
1448
+ </CapRow>
1449
+ {renderMessageLength(HEADER_TEXT)}
1450
+ <CapHeader
1451
+ className={`${isMediaTypeImage ? "whatsapp-heading-spacing" : ""}`}
1185
1452
  title={
1186
1453
  <CapHeading type="h4" className="whatsapp-render-heading">
1187
1454
  {formatMessage(messages.templateMessageLabel)}
@@ -1196,7 +1463,7 @@ export const Whatsapp = (props) => {
1196
1463
  {...messages.templateMessageTooltip}
1197
1464
  values={{
1198
1465
  br: <br />,
1199
- var: '{{1}}',
1466
+ var: "{{1}}",
1200
1467
  }}
1201
1468
  />
1202
1469
  }
@@ -1229,11 +1496,47 @@ export const Whatsapp = (props) => {
1229
1496
  </CapError>
1230
1497
  )
1231
1498
  }
1232
- value={templateMessage || ''}
1499
+ value={templateMessage || ""}
1233
1500
  />
1234
1501
  {renderUnsubscribeText()}
1235
1502
  </CapRow>
1236
- {renderMessageLength()}
1503
+ {renderMessageLength(MESSAGE_TEXT)}
1504
+ <CapHeader
1505
+ className={`${isMediaTypeImage ? "whatsapp-heading-spacing" : ""}`}
1506
+ title={
1507
+ <CapHeading type="h4" className="whatsapp-create-mode-heading">
1508
+ {formatMessage(messages.templateFooterLabel)}
1509
+ <CapTooltipWithInfo
1510
+ placement="right"
1511
+ infoIconProps={{
1512
+ style: { marginLeft: CAP_SPACE_04 },
1513
+ }}
1514
+ autoAdjustOverflow
1515
+ title={<FormattedMessage {...messages.templateFooterTooltip} />}
1516
+ />
1517
+ <CapHeading className="whatsapp-optional-label1 align-item-center">
1518
+ {formatMessage(messages.optional)}
1519
+ </CapHeading>
1520
+ </CapHeading>
1521
+ }
1522
+ />
1523
+ <CapRow className="whatsapp-create-template-message-input whatsapp-create-template-header-input">
1524
+ <TextArea
1525
+ id="whatsapp-create-template-message-input"
1526
+ autosize={{ minRows: 1, maxRows: 5 }}
1527
+ placeholder={formatMessage(messages.templateMessagePlaceholder)}
1528
+ onChange={onTemplateFooterChanges}
1529
+ errorMessage={
1530
+ templateFooterError && (
1531
+ <CapError className="whatsapp-template-message-error">
1532
+ {templateFooterError}
1533
+ </CapError>
1534
+ )
1535
+ }
1536
+ value={templateFooter || ""}
1537
+ />
1538
+ </CapRow>
1539
+ {renderMessageLength(FOOTER_TEXT)}
1237
1540
  {renderButtonsSection()}
1238
1541
  </>
1239
1542
  );
@@ -1317,37 +1620,53 @@ export const Whatsapp = (props) => {
1317
1620
  };
1318
1621
 
1319
1622
  // on change event of Text Area
1320
- const textAreaValueChange = ({ target: { value, id } }) => {
1321
- const numId = Number(id.slice(id.indexOf('_') + 1));
1322
- const arr = [...updatedSmsEditor];
1323
-
1623
+ const textAreaValueChange = ({ target: { value, id } }, type) => {
1624
+ const numId = Number(id.slice(id.indexOf("_") + 1));
1324
1625
  //assign entered value to varMap
1325
- varMap[id] = value;
1326
- //based on entered value update updatedSmsEditor
1327
- if (value === '') {
1328
- arr[numId] = id.slice(0, id.indexOf('_'));
1626
+ if (type === HEADER_TEXT) {
1627
+ const arr = [...updatedHeaderData];
1628
+ setHeaderVarMappedData((prevState) => ({
1629
+ ...prevState,
1630
+ [id]: value,
1631
+ }));
1632
+ if (value === "") {
1633
+ arr[numId] = id.slice(0, id.indexOf("_"));
1634
+ } else {
1635
+ arr[numId] = value;
1636
+ }
1637
+ setUpdatedHeaderData(arr);
1329
1638
  } else {
1330
- arr[numId] = value;
1639
+ const arr = [...updatedSmsEditor];
1640
+ varMap[id] = value;
1641
+ //based on entered value update updatedSmsEditor
1642
+ if (value === "") {
1643
+ arr[numId] = id.slice(0, id.indexOf("_"));
1644
+ } else {
1645
+ arr[numId] = value;
1646
+ }
1647
+ setUpdatedSmsEditor(arr);
1331
1648
  }
1332
- setUpdatedSmsEditor(arr);
1333
1649
  };
1334
1650
 
1335
- const textAreaValue = (idValue) => {
1336
- if (idValue >= 0 && updatedSmsEditor) {
1337
- const value = updatedSmsEditor[idValue];
1651
+ const textAreaValue = (idValue, type) => {
1652
+ if (idValue >= 0) {
1653
+ const value =
1654
+ type === HEADER_TEXT
1655
+ ? updatedHeaderData[idValue]
1656
+ : updatedSmsEditor[idValue];
1338
1657
  //if value is there and it is not a variable return it
1339
1658
  if (value && (value.match(validVarRegex) || []).length === 0) {
1340
1659
  return value;
1341
1660
  }
1342
1661
  }
1343
- return '';
1662
+ return "";
1344
1663
  };
1345
1664
 
1346
- const renderedEditMessage = () => {
1665
+ const renderedEditMessage = (messageData, type) => {
1347
1666
  const renderArray = [];
1348
- if (tempMsgArray?.length !== 0) {
1667
+ if (messageData?.length !== 0) {
1349
1668
  let varCount = 0;
1350
- tempMsgArray.forEach((elem, index) => {
1669
+ messageData.forEach((elem, index) => {
1351
1670
  // if var return textarea else return text
1352
1671
  if (elem.match(validVarRegex)?.length > 0) {
1353
1672
  varCount += 1;
@@ -1359,11 +1678,11 @@ export const Whatsapp = (props) => {
1359
1678
  value: `{{${varCount}}}`,
1360
1679
  })}
1361
1680
  autosize={{ minRows: 1, maxRows: 3 }}
1362
- onChange={textAreaValueChange}
1363
- value={textAreaValue(index)}
1364
- onFocus={setTextAreaId}
1681
+ onChange={(e) => textAreaValueChange(e, type)}
1682
+ value={textAreaValue(index, type)}
1683
+ onFocus={(e) => setTextAreaId(e, type)}
1365
1684
  disabled={templateStatus !== WHATSAPP_STATUSES.approved}
1366
- />,
1685
+ />
1367
1686
  );
1368
1687
  } else {
1369
1688
  renderArray.push(
@@ -1373,7 +1692,7 @@ export const Whatsapp = (props) => {
1373
1692
  className="whatsapp-edit-template-message-heading"
1374
1693
  >
1375
1694
  {elem}
1376
- </CapHeading>,
1695
+ </CapHeading>
1377
1696
  );
1378
1697
  }
1379
1698
  });
@@ -1385,7 +1704,7 @@ export const Whatsapp = (props) => {
1385
1704
  const disabledEditTooltipRender = () => {
1386
1705
  switch (templateStatus) {
1387
1706
  case WHATSAPP_STATUSES.approved:
1388
- return '';
1707
+ return "";
1389
1708
  case WHATSAPP_STATUSES.rejected:
1390
1709
  return formatMessage(messages.disabledEditTooltip, {
1391
1710
  status: templateStatus,
@@ -1397,9 +1716,10 @@ export const Whatsapp = (props) => {
1397
1716
  }
1398
1717
  };
1399
1718
 
1400
- const tagValidationErrorMessage = () => {
1401
- const { unsupportedTags = [], isBraceError} = tagValidationResponse;
1402
- let tagError = '';
1719
+ const tagValidationErrorMessage = (type) => {
1720
+ const { unsupportedTags = [], isBraceError } =
1721
+ type === HEADER_TEXT ? headerTagValidationResponse : tagValidationResponse;
1722
+ let tagError = "";
1403
1723
  if (unsupportedTags.length > 0) {
1404
1724
  tagError = formatMessage(globalMessages.unsupportedTagsValidationError, {
1405
1725
  unsupportedTags,
@@ -1420,9 +1740,54 @@ export const Whatsapp = (props) => {
1420
1740
  />
1421
1741
  )}
1422
1742
  {/* template media type */}
1423
- {renderLabel('mediaLabel')}
1743
+ {renderLabel("mediaLabel")}
1424
1744
  <CapLabel type="label15">{capitalizeString(templateMediaType)}</CapLabel>
1425
1745
  {renderMediaComponent()}
1746
+ {templateHeader && (
1747
+ <>
1748
+ <CapRow className="whatsapp-render-heading">
1749
+ <CapHeader
1750
+ title={
1751
+ <CapHeading type="h4">
1752
+ {formatMessage(messages.templateHeaderLabel)}
1753
+ </CapHeading>
1754
+ }
1755
+ suffix={
1756
+ templateStatus === WHATSAPP_STATUSES.approved && (
1757
+ <TagList
1758
+ label={formatMessage(globalMessages.addLabels)}
1759
+ onTagSelect={onHeaderTagSelect}
1760
+ location={location}
1761
+ tags={tags || []}
1762
+ onContextChange={handleOnTagsContextChange}
1763
+ injectedTags={injectedTags || {}}
1764
+ selectedOfferDetails={selectedOfferDetails}
1765
+ />
1766
+ )
1767
+ }
1768
+ />
1769
+ </CapRow>
1770
+ <CapTooltip placement="bottom" title={disabledEditTooltipRender()}>
1771
+ <CapRow
1772
+ className={`whatsapp-edit-template-message-input ${
1773
+ templateStatus !== WHATSAPP_STATUSES.approved &&
1774
+ "whatsapp-edit-disabled"
1775
+ }`}
1776
+ >
1777
+ {renderedEditMessage(tempHeaderData, HEADER_TEXT)}
1778
+ </CapRow>
1779
+ </CapTooltip>
1780
+ {renderMessageLength(HEADER_TEXT)}
1781
+ {isHeaderTagValidationError && tagValidationErrorMessage(HEADER_TEXT)}
1782
+ {computeTextLength(HEADER_TEXT) > TEMPLATE_HEADER_MAX_LENGTH ? (
1783
+ <CapError>
1784
+ {formatMessage(messages.templateMessageLengthError)}
1785
+ </CapError>
1786
+ ) : (
1787
+ ""
1788
+ )}
1789
+ </>
1790
+ )}
1426
1791
  <CapRow className="whatsapp-render-heading">
1427
1792
  <CapHeader
1428
1793
  title={
@@ -1452,29 +1817,55 @@ export const Whatsapp = (props) => {
1452
1817
  'whatsapp-edit-disabled'
1453
1818
  }`}
1454
1819
  >
1455
- {renderedEditMessage()}
1820
+ {renderedEditMessage(tempMsgArray)}
1456
1821
  </CapRow>
1457
1822
  </CapTooltip>
1458
1823
 
1459
- {renderMessageLength()}
1460
- {isTagValidationError && tagValidationErrorMessage()}
1461
- {computeTextLength() > TEMPLATE_MESSAGE_MAX_LENGTH ? (
1824
+ {renderMessageLength(MESSAGE_TEXT)}
1825
+ {isTagValidationError && tagValidationErrorMessage(MESSAGE_TEXT)}
1826
+ {computeTextLength(MESSAGE_TEXT) > TEMPLATE_MESSAGE_MAX_LENGTH ? (
1462
1827
  <CapError>
1463
1828
  {formatMessage(messages.templateMessageLengthError)}
1464
1829
  </CapError>
1465
1830
  ) : (
1466
- ''
1831
+ ""
1832
+ )}
1833
+ {templateFooter && (
1834
+ <>
1835
+ <CapHeader
1836
+ className={`${isMediaTypeImage ? "whatsapp-heading-spacing" : ""}`}
1837
+ title={
1838
+ <CapHeading type="h4" className="whatsapp-render-heading">
1839
+ {formatMessage(messages.templateFooterLabel)}
1840
+ </CapHeading>
1841
+ }
1842
+ />
1843
+ <CapRow className="whatsapp-footer-edit-container">
1844
+ <CapHeading type="h4" className="whatsapp-footer-edit-text">
1845
+ {templateFooter}
1846
+ </CapHeading>
1847
+ </CapRow>
1848
+ {renderMessageLength(FOOTER_TEXT)}
1849
+ </>
1467
1850
  )}
1468
1851
  {/* button section view in edit mode*/}
1469
1852
  <CapRow>
1470
- <CapHeading type="h4" className="whatsapp-render-heading">
1471
- {formatMessage(messages.btnLabel)}
1472
- </CapHeading>
1473
- <CapLabel type="label15">
1474
- {isBtnTypeCta
1475
- ? formatMessage(messages.btnTypeCTA)
1476
- : formatMessage(messages.btnTypeNone)}
1477
- </CapLabel>
1853
+ {isBtnTypeQuickReply ? (
1854
+ <CapHeading type="h4" className="whatsapp-render-heading">
1855
+ {formatMessage(messages.quickReplyButtons)}
1856
+ </CapHeading>
1857
+ ) : (
1858
+ <>
1859
+ <CapHeading type="h4" className="whatsapp-render-heading">
1860
+ {formatMessage(messages.btnLabel)}
1861
+ </CapHeading>
1862
+ <CapLabel type="label15">
1863
+ {isBtnTypeCta
1864
+ ? formatMessage(messages.btnTypeCTA)
1865
+ : formatMessage(messages.btnTypeNone)}
1866
+ </CapLabel>
1867
+ </>
1868
+ )}
1478
1869
  {isBtnTypeCta && (
1479
1870
  <CapWhatsappCTA
1480
1871
  ctaData={ctaData}
@@ -1487,6 +1878,14 @@ export const Whatsapp = (props) => {
1487
1878
  selectedOfferDetails={selectedOfferDetails}
1488
1879
  />
1489
1880
  )}
1881
+ {isBtnTypeQuickReply && (
1882
+ <CapWhatsappQuickReply
1883
+ quickReplyData={quickReplyData}
1884
+ isEditFlow={isEditFlow}
1885
+ renderMessageLength={renderMessageLength}
1886
+ setQuickReplyData={setQuickReplyData}
1887
+ />
1888
+ )}
1490
1889
  </CapRow>
1491
1890
  </>
1492
1891
  );
@@ -1497,7 +1896,7 @@ export const Whatsapp = (props) => {
1497
1896
  const templateMsg = (
1498
1897
  <>
1499
1898
  <CapLabel type="label5">
1500
- {isEditFlow ? updatedSmsEditor.join('') : templateMessage}
1899
+ {isEditFlow ? updatedSmsEditor.join("") : templateMessage}
1501
1900
  </CapLabel>
1502
1901
  {unsubscribeRequired && (
1503
1902
  <CapLabel type="label5">
@@ -1506,13 +1905,24 @@ export const Whatsapp = (props) => {
1506
1905
  )}
1507
1906
  </>
1508
1907
  );
1908
+ const templateHeaderPreview = (
1909
+ <CapLabel className="whatsapp-template-header-preview">
1910
+ {isEditFlow ? updatedHeaderData.join("") : templateHeader}
1911
+ </CapLabel>
1912
+ );
1913
+ const templateFooterPreview = (
1914
+ <CapLabel className="whatsapp-template-footer-preview">
1915
+ {templateFooter}
1916
+ </CapLabel>
1917
+ );
1509
1918
  const mediaPreview = {};
1510
1919
  switch (templateMediaType) {
1511
1920
  case WHATSAPP_MEDIA_TYPES.IMAGE:
1512
1921
  mediaPreview.whatsappImageSrc = whatsappImageSrc;
1513
1922
  break;
1514
1923
  case WHATSAPP_MEDIA_TYPES.VIDEO:
1515
- mediaPreview.whatsappVideoPreviewImg = whatsappVideoSrcAndPreview?.whatsappVideoPreviewImg;
1924
+ mediaPreview.whatsappVideoPreviewImg =
1925
+ whatsappVideoSrcAndPreview?.whatsappVideoPreviewImg;
1516
1926
  break;
1517
1927
  case WHATSAPP_MEDIA_TYPES.DOCUMENT:
1518
1928
  mediaPreview.docPreview = docPreview;
@@ -1526,9 +1936,14 @@ export const Whatsapp = (props) => {
1526
1936
  content={{
1527
1937
  ...mediaPreview,
1528
1938
  templateMsg,
1939
+ templateHeaderPreview,
1940
+ templateFooterPreview,
1529
1941
  ...(isBtnTypeCta && {
1530
1942
  ctaData,
1531
1943
  }),
1944
+ ...(isBtnTypeQuickReply && {
1945
+ quickReplyData,
1946
+ }),
1532
1947
  }}
1533
1948
  whatsappContentLen={computeTextLength()}
1534
1949
  whatsappAccountName={accountName}
@@ -1538,12 +1953,15 @@ export const Whatsapp = (props) => {
1538
1953
 
1539
1954
  const isEditDoneDisabled = () =>
1540
1955
  isTagValidationError ||
1541
- Object.values(varMap).some((inputValue) => inputValue === '') ||
1542
- computeTextLength() > TEMPLATE_MESSAGE_MAX_LENGTH ||
1543
- (isBtnTypeCta && ctaData.some((btn) => btn?.url?.includes('{{1}}'))) ||
1544
- (isMediaTypeImage && whatsappImageSrc === '') ||
1545
- (isMediaTypeVideo && whatsappVideoSrcAndPreview?.whatsappVideoSrc === '') ||
1546
- (isMediaTypeDoc && whatsappDocSource === '');
1956
+ isHeaderTagValidationError ||
1957
+ Object.values(varMap).some((inputValue) => inputValue === "") ||
1958
+ Object.values(headerVarMappedData).some((inputValue) => inputValue === "") ||
1959
+ computeTextLength(MESSAGE_TEXT) > TEMPLATE_MESSAGE_MAX_LENGTH ||
1960
+ computeTextLength(HEADER_TEXT) > TEMPLATE_HEADER_MAX_LENGTH ||
1961
+ (isBtnTypeCta && ctaData.some((btn) => btn?.url?.includes("{{1}}"))) ||
1962
+ (isMediaTypeImage && whatsappImageSrc === "") ||
1963
+ (isMediaTypeVideo && whatsappVideoSrcAndPreview?.whatsappVideoSrc === "") ||
1964
+ (isMediaTypeDoc && whatsappDocSource === "");
1547
1965
 
1548
1966
  return (
1549
1967
  <CapSpin spinning={spin}>
@@ -1563,9 +1981,9 @@ export const Whatsapp = (props) => {
1563
1981
  title={
1564
1982
  isDisableDone()
1565
1983
  ? formatMessage(messages.btnDisabledTooltip)
1566
- : ''
1984
+ : ""
1567
1985
  }
1568
- placement={'right'}
1986
+ placement={"right"}
1569
1987
  >
1570
1988
  <div className="button-disabled-tooltip-wrapper">
1571
1989
  <CapButton
@@ -1591,9 +2009,9 @@ export const Whatsapp = (props) => {
1591
2009
  title={
1592
2010
  isEditDoneDisabled()
1593
2011
  ? formatMessage(messages.btnDisabledTooltip)
1594
- : ''
2012
+ : ""
1595
2013
  }
1596
- placement={'right'}
2014
+ placement={"right"}
1597
2015
  >
1598
2016
  <div className="button-disabled-tooltip-wrapper">
1599
2017
  <CapButton