@capillarytech/creatives-library 7.10.52 → 7.10.54

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "7.10.52",
4
+ "version": "7.10.54",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -683,7 +683,7 @@ class TemplatePreview extends React.Component { // eslint-disable-line react/pre
683
683
  ) : ''
684
684
  }
685
685
  {
686
- channel && channel?.toUpperCase() === WHATSAPP ? (
686
+ channel?.toUpperCase() === WHATSAPP ? (
687
687
  <>
688
688
  <div className='shell-v2 align-center'>
689
689
  <CapImage
@@ -1,5 +1,7 @@
1
+ @import '~@capillarytech/cap-ui-library/styles/_variables.scss';
2
+
1
3
  .whatsapp-status-container {
2
- margin-top: 12px;
4
+ margin-top: $CAP_SPACE_12;
3
5
  width: 150%;
4
6
  height: 20px;
5
7
 
@@ -8,6 +10,6 @@
8
10
  }
9
11
 
10
12
  .whatsapp-category-tag {
11
- margin-left: 8px;
13
+ margin-left: $CAP_SPACE_08;
12
14
  }
13
15
  }
@@ -22,24 +22,15 @@ const StyledLabel = styled(CapLabelInline)`
22
22
  const PrefixWrapper = styled.div`
23
23
  margin-right: 16px;
24
24
  `;
25
- function getChannelLabel(channel = '') {
26
- const labels = {
27
- sms: 'SMS',
28
- email: 'Email',
29
- mobilepush: 'Push notification',
30
- wechat: 'Wechat',
31
- no_communication: 'NO_COMMUNICATION',
32
- ftp: 'FTP',
33
- whatsapp: 'WhatsApp template',
34
- };
35
- return labels[channel.toLowerCase()];
36
- }
25
+
37
26
  const renderWhatsappData = (type, value) => (
38
27
  <StyledLabel type={type}>
39
28
  {value}
40
29
  </StyledLabel>
41
30
  )
42
31
  function SlideBoxHeader(props) {
32
+
33
+
43
34
  const { slidBoxContent, templateData, onShowTemplates, creativesMode, isFullMode, showPrefix, shouldShowTemplateName, channel, templateNameRenderProp, weChatTemplateType, onWeChatMaptemplateStepChange, weChatMaptemplateStep, templateStep, smsRegister } = props;
44
35
  const showTemplateNameHeader = isFullMode && shouldShowTemplateName;
45
36
  const mapTemplateCreate = !showTemplateNameHeader && slidBoxContent === 'createTemplate' && weChatTemplateType === MAP_TEMPLATE && templateStep !== 'modeSelection';
@@ -55,6 +46,20 @@ function SlideBoxHeader(props) {
55
46
  const whatsappName = whatsappTemplateName || templateData?.name;
56
47
  const whatsappCategory = whatsappTemplateCategory || get(templateData, `versions.base.content.whatsapp.category`, '');
57
48
 
49
+
50
+ const getChannelLabel = (currentChannel = '') => {
51
+ const labels = {
52
+ sms: 'SMS',
53
+ email: 'Email',
54
+ mobilepush: 'Push notification',
55
+ wechat: 'Wechat',
56
+ no_communication: 'NO_COMMUNICATION',
57
+ ftp: 'FTP',
58
+ whatsapp: <FormattedMessage {...messages.whatsappTemplate} />,
59
+ };
60
+ return labels[currentChannel.toLowerCase()];
61
+ };
62
+
58
63
  return (
59
64
  <div key="creatives-container-slidebox-header-content">
60
65
  {slidBoxContent === 'templates' && !showTemplateNameHeader && (
@@ -310,4 +310,8 @@ export default defineMessages({
310
310
  id: `${scope}.whatsappOverview`,
311
311
  defaultMessage: `WhatsApp template overview`,
312
312
  },
313
+ "whatsappTemplate": {
314
+ id: `${scope}.whatsappTemplate`,
315
+ defaultMessage: `WhatsApp template`,
316
+ },
313
317
  });
@@ -1,8 +1,4 @@
1
- export const DEFAULT_ACTION = 'app/SmsTrai/DEFAULT_ACTION';
2
- export const STATUS = 'status';
3
1
  export const TEMPLATE_NAME = 'template name';
4
- export const HEADER = 'header';
5
- export const TEMPLATE_ID = 'template id';
6
2
  export const SMS = 'SMS';
7
3
  export const MAPPED_SAVED_COLUMN = {
8
4
  'TEMPLATE ID': 'template_id',
@@ -22,12 +18,12 @@ export const MAPPED_SAVED_COLUMN = {
22
18
  'CONSENT TYPE': 'consent-type',
23
19
  };
24
20
  export const HEADER_ALIASES = [
25
- HEADER,
21
+ 'header',
26
22
  'sender id',
27
23
  'senders',
28
24
  'header id',
29
25
  'headers',
30
- 'linked headers'
26
+ 'linked headers',
31
27
  ];
32
28
  export const TEMPLATE_ID_ALIASES = [
33
29
  'template id',
@@ -76,4 +72,4 @@ export const CHECK_TRAI_SMS_DUPLICATE_TEMPLATE_NAME_FAILURE =
76
72
  export const REQUEST = 'REQUEST';
77
73
  export const SUCCESS = 'SUCCESS';
78
74
  export const FAILURE = 'FAILURE';
79
- export const DUPLICATE = 'Duplicate';
75
+ export const DUPLICATE = 'Duplicate';
@@ -77,7 +77,8 @@ export const SmsTraiCreate = (props) => {
77
77
  const [traiFileMeta, setTraiFileMeta] = useState(null);
78
78
  const [validatedData, setValidatedData] = useState([]);
79
79
  const [files, setFiles] = useState([]);
80
- const [templateRegistrationIndex, setTemplateRegistrationIndex] = useState(null);
80
+ const [templateRegistrationIndex, setTemplateRegistrationIndex] =
81
+ useState(null);
81
82
  const [errorText, setErrorText] = useState('');
82
83
  const [dropZone, setDropZone] = useState(true);
83
84
  const [previewFileIndex, setPreviewFileIndex] = useState(null);
@@ -110,7 +111,10 @@ export const SmsTraiCreate = (props) => {
110
111
  const colCounts = {};
111
112
  const traiFileDataCopy = cloneDeep(traiFileData);
112
113
  //removing last empty row if each cell is empty
113
- if (traiFileDataCopy?.data[traiFileDataCopy?.data?.length - 1]?.every((cell) => !cell)) {
114
+ const removeLastEmptyRow = traiFileDataCopy?.data[
115
+ traiFileDataCopy?.data?.length - 1
116
+ ]?.every((cell) => !cell);
117
+ if (removeLastEmptyRow) {
114
118
  traiFileDataCopy.data.pop();
115
119
  }
116
120
  const fileLen = traiFileDataCopy?.data?.length || 0;
@@ -259,14 +263,27 @@ export const SmsTraiCreate = (props) => {
259
263
  } else if (uploadValidated && duplicateDetailsStatus === FAILURE) {
260
264
  deleteOrCancelCSV();
261
265
  CapNotification.error({ message: duplicateDetailsError || FAILURE });
262
- } else if (uploadValidated && duplicateDetailsStatus === SUCCESS && !isEmpty(validatedData)) {
263
- if (!isEmpty(duplicateDetails) && count > 0 && templateRegistrationIndex !== null) {
266
+ } else if (
267
+ uploadValidated &&
268
+ duplicateDetailsStatus === SUCCESS &&
269
+ !isEmpty(validatedData)
270
+ ) {
271
+ if (
272
+ !isEmpty(duplicateDetails) &&
273
+ count > 0 &&
274
+ templateRegistrationIndex !== null
275
+ ) {
264
276
  const clonedValidatedData = cloneDeep(validatedData);
265
277
  let duplicateTemplateNameCounts = 0;
266
278
  const apiResponseIds = [...new Set(template_ids)];
267
-
279
+
268
280
  for (let i = 1; i < clonedValidatedData.length; i += 1) {
269
- const duplicatePresent = apiResponseIds?.includes(clonedValidatedData[i][templateRegistrationIndex]?.replace(/[“”"'‘’`´]/g, ''));
281
+ const duplicatePresent = apiResponseIds?.includes(
282
+ clonedValidatedData[i][templateRegistrationIndex]?.replace(
283
+ /[“”"'‘’`´]/g,
284
+ '',
285
+ ),
286
+ );
270
287
  if (duplicatePresent) {
271
288
  //if rejection reason for this row is empty, consider as new error
272
289
  if (!clonedValidatedData[i][clonedValidatedData[i]?.length - 1]) {
@@ -291,7 +308,10 @@ export const SmsTraiCreate = (props) => {
291
308
  const selectedFiles = cloneDeep(files);
292
309
  const traiFileDataCopy = cloneDeep(traiFileData);
293
310
  //removing last empty row if each cell is empty
294
- if (traiFileDataCopy?.data[traiFileDataCopy?.data?.length - 1]?.every((cell) => !cell)) {
311
+ const removeLastEmptyRow = traiFileDataCopy?.data[
312
+ traiFileDataCopy?.data?.length - 1
313
+ ]?.every((cell) => !cell);
314
+ if (removeLastEmptyRow) {
295
315
  traiFileDataCopy.data.pop();
296
316
  }
297
317
  //remove capillary rejection reason column if already present on reupload
@@ -340,8 +360,8 @@ export const SmsTraiCreate = (props) => {
340
360
  const headerValidationHandler = (senderIdString) => {
341
361
  //each row must contain atleast 1 header
342
362
  //each header can be either 6 letters or 6 numbers, no mixing
343
- //it cannot contain special characters.
344
- //eg: valid: "123456" "abcdef" invalid: "abc123" "abc$ef" "1234567"
363
+ //it cannot contain special characters except {}
364
+ //eg: valid: "123456" "abcdef" "{123456}" invalid: "abc123" "abc$ef" "1234567"
345
365
  if (senderIdString.length < 6) {
346
366
  return true;
347
367
  }
@@ -349,7 +369,7 @@ export const SmsTraiCreate = (props) => {
349
369
  const numbersOnly = /^\d+$/;
350
370
  let isError = false;
351
371
  senderIdString.split(',').forEach((value) => {
352
- const _value = value.trim();
372
+ const _value = value.trim()?.replace(/[{}]/g, '');
353
373
  if (_value) {
354
374
  if (_value.length !== 6) {
355
375
  isError = true;
@@ -363,6 +383,19 @@ export const SmsTraiCreate = (props) => {
363
383
  return isError;
364
384
  };
365
385
 
386
+ const statusValidationHandler = (columnName, value) => {
387
+ //Approval status should be Approved or Status/Template status should be Active/Registered.
388
+ switch (columnName) {
389
+ case STATUS_ALIASES[0]:
390
+ case STATUS_ALIASES[1]:
391
+ return ![ACTIVE, REGISTERED].includes(value);
392
+ case STATUS_ALIASES[2]:
393
+ return value !== APPROVED;
394
+ default:
395
+ return true;
396
+ }
397
+ };
398
+
366
399
  const templateIdValidation = (templateId) => {
367
400
  let isError = false;
368
401
  const _templateId = templateId?.replace(/[“”"'‘’`´]/g, '');
@@ -389,7 +422,9 @@ export const SmsTraiCreate = (props) => {
389
422
  };
390
423
  }
391
424
  })
392
- ?.filter((obj) => obj && obj.template_name !== '' && obj.template_id !== '');
425
+ ?.filter(
426
+ (obj) => obj && obj.template_name !== '' && obj.template_id !== '',
427
+ );
393
428
  setUploadValidated(true);
394
429
  setValidatedData(transformedResults);
395
430
  setTemplateRegistrationIndex(templateIdIndex);
@@ -458,20 +493,26 @@ export const SmsTraiCreate = (props) => {
458
493
  const errorArray = [];
459
494
  const columnErrorArray = [];
460
495
  let rejectionReasons = '';
461
- let statusErrorIndicator = true;
496
+ let statusErrorIndicator = false;
462
497
  //adding rejection reasons
463
498
  transformedResults[row].forEach((cell, index) => {
464
499
  if (index === headerIndex && headerValidationHandler(cell)) {
465
500
  columnErrorArray.push(
466
501
  `${selectedHeaderAlias.toUpperCase()} is mandatory and each ${selectedHeaderAlias.toUpperCase()} must contain either 6 letters or 6 digits. It cannot contain special characters. `,
467
502
  );
468
- } else if (statusIndexes.includes(index) && [ACTIVE, REGISTERED, APPROVED].includes(cell.toLowerCase())) {
469
- statusErrorIndicator = false;
503
+ } else if (statusIndexes.includes(index) && !statusErrorIndicator) {
504
+ statusErrorIndicator = statusValidationHandler(
505
+ transformedResults[0][index].toLowerCase(),
506
+ cell.toLowerCase(),
507
+ );
470
508
  } else if (index === templateIdIndex && templateIdValidation(cell)) {
471
509
  columnErrorArray.push(
472
510
  `${selectedTemplateIdAlias.toUpperCase()} is mandatory and ${selectedTemplateIdAlias.toUpperCase()} must be numeric.`,
473
511
  );
474
- } else if (!cell && ![headerIndex, templateIdIndex, ...statusIndexes].includes(index)) {
512
+ } else if (
513
+ !cell &&
514
+ ![headerIndex, templateIdIndex, ...statusIndexes].includes(index)
515
+ ) {
475
516
  errorArray.push(`"${transformedResults[0][index]}"`);
476
517
  } else if (index === templateNameIndex && cell) {
477
518
  if (templateNameObj[cell]) {
@@ -485,7 +526,7 @@ export const SmsTraiCreate = (props) => {
485
526
 
486
527
  if (statusErrorIndicator) {
487
528
  columnErrorArray.push(
488
- `Only templates with active/registered/approved status will be created.`,
529
+ `Approval status should be Approved or Status/Template status should be Active/Registered.`,
489
530
  );
490
531
  }
491
532
  if (errorArray.length !== 0) {
@@ -671,7 +712,7 @@ export const SmsTraiCreate = (props) => {
671
712
  obj['unicode-validity'] = true;
672
713
  obj['updated-sms-editor'] = '';
673
714
  obj['var-mapped'] = {};
674
- obj.header = obj.header?.replace(/\s/g, '')?.split(',');
715
+ obj.header = obj.header?.replace(/[\s{}]/g, '')?.split(',');
675
716
  const history = obj;
676
717
  history.tabKey = 1;
677
718
  savedData.push({
@@ -745,7 +786,10 @@ export const SmsTraiCreate = (props) => {
745
786
  {previewFileIndex === null && dropZone && (
746
787
  <>
747
788
  <CapSpin spinning={isFileDropped}>
748
- <Dropzone onDrop={onDrop} onFileDialogCancel={deleteOrCancelCSV}>
789
+ <Dropzone
790
+ onDrop={onDrop}
791
+ onFileDialogCancel={deleteOrCancelCSV}
792
+ >
749
793
  {({ getRootProps, getInputProps }) => (
750
794
  <div {...getRootProps()} className="file-drop-zone">
751
795
  <input {...getInputProps()} />
@@ -789,16 +833,18 @@ export const SmsTraiCreate = (props) => {
789
833
  <CapLabel.CapLabelInline type="label9">
790
834
  {fileMeta.name}
791
835
  </CapLabel.CapLabelInline>
792
- {saveTemplate && <CapLabel.CapLabelInline
793
- type="label1"
794
- className="number-of-records"
795
- >
796
- (
797
- {formatMessage(messages.numberOfRecords, {
798
- value: fileData.data.length - 1,
799
- })}
800
- )
801
- </CapLabel.CapLabelInline>}
836
+ {saveTemplate && (
837
+ <CapLabel.CapLabelInline
838
+ type="label1"
839
+ className="number-of-records"
840
+ >
841
+ (
842
+ {formatMessage(messages.numberOfRecords, {
843
+ value: fileData.data.length - 1,
844
+ })}
845
+ )
846
+ </CapLabel.CapLabelInline>
847
+ )}
802
848
  </CapColumn>
803
849
  {errorText && (
804
850
  <>
@@ -4,7 +4,6 @@
4
4
  *
5
5
  */
6
6
 
7
- export const DEFAULT_ACTION = 'app/SmsTrai/DEFAULT_ACTION';
8
7
  export const CHARLIMIT = 30;
9
8
  export const SMS = 'SMS';
10
9
  export const SMS_TRAI_VAR = '{#var#}';
@@ -50,7 +50,7 @@ export class TemplatesV2 extends React.Component { // eslint-disable-line react/
50
50
  isFullMode,
51
51
  onChannelChange,
52
52
  showDisabledFBInfo,
53
- enableNewChannels,
53
+ enableNewChannels = [],
54
54
  } = props;
55
55
 
56
56
  const defaultPanes = {