@capillarytech/creatives-library 7.10.9 → 7.10.11

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.
@@ -18,7 +18,6 @@ import CapNotification from '@capillarytech/cap-ui-library/CapNotification';
18
18
  import Papa from 'papaparse';
19
19
  import cloneDeep from 'lodash/cloneDeep';
20
20
  import {
21
- CAP_SPACE_12,
22
21
  CAP_SPACE_16,
23
22
  CAP_SPACE_24,
24
23
  CAP_SPACE_32,
@@ -38,8 +37,10 @@ import {
38
37
  CAPILLARY_REJECTION_REASON,
39
38
  APPROVAL_STATUS,
40
39
  APPROVED,
40
+ ACTIVE,
41
41
  TEMPLATE_ID_ALIASES,
42
42
  TEMPLATE_MESSAGE_ALIASES,
43
+ STATUS_ALIASES,
43
44
  SAVED_COLUMNS,
44
45
  MAPPED_SAVED_COLUMN,
45
46
  SMS,
@@ -48,7 +49,13 @@ import messages from './messages';
48
49
  import withCreatives from '../../../hoc/withCreatives';
49
50
 
50
51
  export const SmsTraiCreate = (props) => {
51
- const { intl, actions, onCreateComplete } = props;
52
+ const {
53
+ intl,
54
+ actions,
55
+ onCreateComplete,
56
+ isFullMode,
57
+ onShowTemplates,
58
+ } = props;
52
59
  const { formatMessage } = intl;
53
60
  const [files, setFiles] = useState([]);
54
61
  const [errorText, setErrorText] = useState('');
@@ -90,13 +97,13 @@ export const SmsTraiCreate = (props) => {
90
97
  const numbersOnly = /^\d+$/;
91
98
  let isError = false;
92
99
  senderIdString.split(',').forEach((value) => {
93
- value = value.trim();
94
- if (value) {
95
- if (value.length !== 6) {
100
+ const _value = value.trim();
101
+ if (_value) {
102
+ if (_value.length !== 6) {
96
103
  isError = true;
97
104
  return;
98
105
  }
99
- if (!(lettersOnly.test(value) || numbersOnly.test(value))) {
106
+ if (!(lettersOnly.test(_value) || numbersOnly.test(_value))) {
100
107
  isError = true;
101
108
  }
102
109
  }
@@ -104,7 +111,16 @@ export const SmsTraiCreate = (props) => {
104
111
  return isError;
105
112
  };
106
113
 
107
- const checkCSVRowsValidation = (transformedResults, selectedHeaderAlias) => {
114
+ const templateIdValidation = (templateId) => {
115
+ let isError = false;
116
+ const numbersOnly = /^\d+$/;
117
+ if (templateId.length !== 20 || !numbersOnly.test(templateId)) {
118
+ isError = true;
119
+ }
120
+ return isError;
121
+ };
122
+
123
+ const checkCSVRowsValidation = (transformedResults, selectedHeaderAlias, selectedTemplateIdAlias, selectedStatusAlias) => {
108
124
  const headerIndex = getIndexofColumn(
109
125
  transformedResults[0],
110
126
  selectedHeaderAlias,
@@ -113,21 +129,34 @@ export const SmsTraiCreate = (props) => {
113
129
  transformedResults[0],
114
130
  APPROVAL_STATUS,
115
131
  );
132
+ const templateIdIndex = getIndexofColumn(
133
+ transformedResults[0],
134
+ selectedTemplateIdAlias,
135
+ );
136
+ const statusIndex = getIndexofColumn(
137
+ transformedResults[0],
138
+ selectedStatusAlias,
139
+ );
116
140
 
117
- for (let row = 1; row < transformedResults.length; row++) {
141
+ for (let row = 1; row < transformedResults.length; row += 1) {
118
142
  const errorArray = [];
119
- const headerErrorArray = [];
120
- const approvalErrorArray = [];
143
+ const columnErrorArray = [];
121
144
  let rejectionReasons = '';
122
145
  //adding rejection reasons
123
146
  transformedResults[row].forEach((cell, index) => {
124
147
  if (index === headerIndex && headerValidationHandler(cell)) {
125
- headerErrorArray.push(
126
- `${selectedHeaderAlias.toUpperCase()} is mandatory and each ${selectedHeaderAlias.toUpperCase()} must contain either 6 letters or 6 numbers. It cannot contain special characters`,
148
+ columnErrorArray.push(
149
+ `${selectedHeaderAlias.toUpperCase()} is mandatory and each ${selectedHeaderAlias.toUpperCase()} must contain either 6 letters or 6 digits. It cannot contain special characters. `,
127
150
  );
128
151
  } else if (index === approvalIndex && cell.toLowerCase() !== APPROVED) {
129
- approvalErrorArray.push(`Templates will be created for only approved/ registered templates.`);
130
- } else if (!cell && index !== headerIndex && index !== approvalIndex) {
152
+ columnErrorArray.push(`Templates will be created for only approved/ registered templates.`);
153
+ } else if (index === statusIndex && cell.toLowerCase() !== ACTIVE) {
154
+ columnErrorArray.push(`Only Templates with active status will be created.`);
155
+ } else if (index === templateIdIndex && templateIdValidation(cell)) {
156
+ columnErrorArray.push(
157
+ `${selectedTemplateIdAlias.toUpperCase()} is mandatory and ${selectedTemplateIdAlias.toUpperCase()} must contain only 20 digits.`,
158
+ );
159
+ } else if (!cell && ![headerIndex, approvalIndex, templateIdIndex, statusIndex].includes(index)) {
131
160
  errorArray.push(`"${transformedResults[0][index]}"`);
132
161
  }
133
162
  });
@@ -137,12 +166,12 @@ export const SmsTraiCreate = (props) => {
137
166
  ' ',
138
167
  )}.`;
139
168
  }
140
- if (headerErrorArray.length !== 0 || approvalErrorArray.length !== 0) {
141
- rejectionReasons = `${rejectionReasons} ${headerErrorArray.toString()} ${approvalErrorArray.toString()}`;
169
+ if (columnErrorArray.length !== 0) {
170
+ rejectionReasons = `${rejectionReasons} ${columnErrorArray.toString().replace(',', ' ')}`;
142
171
  }
143
172
  transformedResults[row].push(rejectionReasons);
144
173
  //if there are rejected reasons present in this row at column 6(where we store rejected reasons), consider it as failure
145
- if (transformedResults[row][6]) {
174
+ if (transformedResults[row][7]) {
146
175
  setTotalFailCount((prev) => prev + 1);
147
176
  }
148
177
  }
@@ -156,6 +185,7 @@ export const SmsTraiCreate = (props) => {
156
185
  const headerAliasPresent = [];
157
186
  const templateIdAliasPresent = [];
158
187
  const templateMessageAliasPresent = [];
188
+ const statusAliasPresent = [];
159
189
  const colCounts = {};
160
190
  //removing last empty row if each cell is empty
161
191
  if (results?.data[results.data.length - 1]?.every((cell) => !cell)) {
@@ -172,25 +202,23 @@ export const SmsTraiCreate = (props) => {
172
202
  setErrorText(formatMessage(messages.fileMaxlengthError));
173
203
  return;
174
204
  }
175
- // mandatory 3 header name should be available.
205
+
176
206
  const cols = getAllColumnNames(results.data[0]);
177
207
 
178
- for (let i = 0; i < MANDATORY_COLUMNS.length; i++) {
208
+ for (let i = 0; i < MANDATORY_COLUMNS.length; i += 1) {
179
209
  if (!cols.includes(MANDATORY_COLUMNS[i])) {
180
210
  mandatoryColNotPresent.push(MANDATORY_COLUMNS[i]);
181
211
  }
182
212
  }
183
213
  if (mandatoryColNotPresent.length > 0) {
184
214
  setErrorText(
185
- formatMessage(messages.invalidFileErrorDescription, {
186
- columns: mandatoryColNotPresent.join(','),
187
- }),
215
+ formatMessage(messages.mandatoryColsErrorDescription),
188
216
  );
189
217
  return;
190
218
  }
191
219
 
192
220
  //one of the mandatory header alias should be available.
193
- for (let i = 0; i < HEADER_ALIASES.length; i++) {
221
+ for (let i = 0; i < HEADER_ALIASES.length; i += 1) {
194
222
  if (cols.includes(HEADER_ALIASES[i])) {
195
223
  headerAliasPresent.push(HEADER_ALIASES[i]);
196
224
  }
@@ -204,7 +232,7 @@ export const SmsTraiCreate = (props) => {
204
232
  return;
205
233
  }
206
234
  //one of the mandatory template id alias should be available.
207
- for (let i = 0; i < TEMPLATE_ID_ALIASES.length; i++) {
235
+ for (let i = 0; i < TEMPLATE_ID_ALIASES.length; i += 1) {
208
236
  if (cols.includes(TEMPLATE_ID_ALIASES[i])) {
209
237
  templateIdAliasPresent.push(TEMPLATE_ID_ALIASES[i]);
210
238
  }
@@ -218,7 +246,7 @@ export const SmsTraiCreate = (props) => {
218
246
  return;
219
247
  }
220
248
  //one of the mandatory template message alias should be available.
221
- for (let i = 0; i < TEMPLATE_MESSAGE_ALIASES.length; i++) {
249
+ for (let i = 0; i < TEMPLATE_MESSAGE_ALIASES.length; i += 1) {
222
250
  if (cols.includes(TEMPLATE_MESSAGE_ALIASES[i])) {
223
251
  templateMessageAliasPresent.push(TEMPLATE_MESSAGE_ALIASES[i]);
224
252
  }
@@ -231,6 +259,20 @@ export const SmsTraiCreate = (props) => {
231
259
  );
232
260
  return;
233
261
  }
262
+ //one of the mandatory status alias should be available.
263
+ for (let i = 0; i < STATUS_ALIASES.length; i += 1) {
264
+ if (cols.includes(STATUS_ALIASES[i])) {
265
+ statusAliasPresent.push(STATUS_ALIASES[i]);
266
+ }
267
+ }
268
+ if (statusAliasPresent.length === 0) {
269
+ setErrorText(
270
+ formatMessage(messages.statusAliasErrorDescription, {
271
+ statusAliases: STATUS_ALIASES.join(' / '),
272
+ }),
273
+ );
274
+ return;
275
+ }
234
276
  // count of each col to validate blank and repetitive cols
235
277
  for (const num of cols) {
236
278
  colCounts[num] = colCounts[num] ? colCounts[num] + 1 : 1;
@@ -247,27 +289,28 @@ export const SmsTraiCreate = (props) => {
247
289
  if (repetitiveColsArray.length !== 0) {
248
290
  setErrorText(
249
291
  formatMessage(messages.repetitiveColsErrorDescription, {
250
- repetitiveCols: repetitiveColsArray,
292
+ repetitiveCols: repetitiveColsArray.join(", "),
251
293
  }),
252
294
  );
253
295
  return;
254
296
  }
255
297
  //perform required data transformation
256
- return dataTransformHandler(cols, results, headerAliasPresent);
298
+ return dataTransformHandler(cols, results, headerAliasPresent, templateIdAliasPresent, statusAliasPresent);
257
299
  } else {
258
300
  setErrorText(formatMessage(messages.nonCsvErrorDescription));
259
301
  }
260
302
  };
261
303
 
262
- const dataTransformHandler = (cols, results, headerAliasPresent) => {
263
- //getting the index of the cols for 6 mandatory cols and also taking care of alias of headers of mandatory columns
304
+ const dataTransformHandler = (cols, results, headerAliasPresent, templateIdAliasPresent, statusAliasPresent) => {
305
+ //getting the index of the cols for 7 mandatory cols and also taking care of alias of headers of mandatory columns
264
306
  const indexArray = [];
265
- for (let i = 0; i < cols.length; i++) {
307
+ for (let i = 0; i < cols.length; i += 1) {
266
308
  if (
267
309
  MANDATORY_COLUMNS.includes(cols[i]) ||
268
310
  HEADER_ALIASES.includes(cols[i]) ||
269
311
  TEMPLATE_ID_ALIASES.includes(cols[i]) ||
270
- TEMPLATE_MESSAGE_ALIASES.includes(cols[i])
312
+ TEMPLATE_MESSAGE_ALIASES.includes(cols[i]) ||
313
+ STATUS_ALIASES.includes(cols[i])
271
314
  ) {
272
315
  indexArray.push(i);
273
316
  }
@@ -279,7 +322,7 @@ export const SmsTraiCreate = (props) => {
279
322
  }
280
323
  //add rejection header
281
324
  transformedResults[0].push(CAPILLARY_REJECTION_REASON);
282
- return checkCSVRowsValidation(transformedResults, headerAliasPresent[0]);
325
+ return checkCSVRowsValidation(transformedResults, headerAliasPresent[0], templateIdAliasPresent[0], statusAliasPresent[0]);
283
326
  };
284
327
 
285
328
  //returns the headers(first row) of the uploaded file in lowercase
@@ -306,8 +349,8 @@ export const SmsTraiCreate = (props) => {
306
349
  });
307
350
  }
308
351
  //adding validated rejection reason column to original results
309
- for (let i = 0; i < validatedResults.length; i++) {
310
- results.data[i].push(validatedResults[i][6]);
352
+ for (let i = 0; i < validatedResults.length; i += 1) {
353
+ results.data[i].push(validatedResults[i][7]);
311
354
  }
312
355
  updateSaveTemplate(true);
313
356
  }
@@ -356,7 +399,7 @@ export const SmsTraiCreate = (props) => {
356
399
 
357
400
  if (rejectionIndex !== -1) {
358
401
  tempArray.push(fileData[0]);
359
- for (let row = 1; row < fileData.length; row++) {
402
+ for (let row = 1; row < fileData.length; row += 1) {
360
403
  if (fileData[row][rejectionIndex]) {
361
404
  tempArray.push(fileData[row]);
362
405
  }
@@ -392,16 +435,15 @@ export const SmsTraiCreate = (props) => {
392
435
  tempArray.push(fileData[0]);
393
436
 
394
437
  // filter out non rejected rows
395
- for (let row = 1; row < fileData.length; row++) {
438
+ for (let row = 1; row < fileData.length; row += 1) {
396
439
  if (!fileData[row][rejectionIndex]) {
397
440
  tempArray.push(fileData[row]);
398
441
  }
399
442
  }
400
-
401
443
  // Filter out the columns index that needs to save
402
444
  const cols = getAllColumnNames(tempArray[0]);
403
445
  const indexArray = [];
404
- for (let i = 0; i < cols.length; i++) {
446
+ for (let i = 0; i < cols.length; i += 1) {
405
447
  if (
406
448
  SAVED_COLUMNS.includes(cols[i]) ||
407
449
  HEADER_ALIASES.includes(cols[i]) ||
@@ -418,7 +460,7 @@ export const SmsTraiCreate = (props) => {
418
460
  transformedResults.push(
419
461
  indexArray.map((i) => {
420
462
  if (key === '0') {
421
- return MAPPED_SAVED_COLUMN[tempArray[key][i]];
463
+ return MAPPED_SAVED_COLUMN[tempArray[key][i]?.toUpperCase()];
422
464
  }
423
465
  return tempArray[key][i];
424
466
  }),
@@ -433,7 +475,7 @@ export const SmsTraiCreate = (props) => {
433
475
  arr.forEach((data, i) => {
434
476
  obj[transformedResults[0][i]] = arr[i];
435
477
  });
436
- obj['unicode-validity'] = false;
478
+ obj['unicode-validity'] = true;
437
479
  obj['updated-sms-editor'] = '';
438
480
  obj['var-mapped'] = {};
439
481
  obj.header = obj.header.split(',');
@@ -452,7 +494,11 @@ export const SmsTraiCreate = (props) => {
452
494
  { templates: savedData },
453
495
  (resp, errorMessage) => {
454
496
  createCallback({ errorMessage });
455
- onCreateComplete();
497
+ if (isFullMode) {
498
+ onCreateComplete();
499
+ } else {
500
+ onShowTemplates();
501
+ }
456
502
  },
457
503
  );
458
504
  };
@@ -530,7 +576,7 @@ export const SmsTraiCreate = (props) => {
530
576
  {previewFileIndex !== null && (
531
577
  <>
532
578
  <CapRow span={24} className="upload-type-group-create-container">
533
- <div className="upload-file-preview">
579
+ <>
534
580
  <CapDivider
535
581
  type="horizontal"
536
582
  className="upload-file-preview-divider-1"
@@ -635,7 +681,7 @@ export const SmsTraiCreate = (props) => {
635
681
  className="upload-file-preview-divider-2"
636
682
  />
637
683
  {errorText && <CapError>{errorText}</CapError>}
638
- </div>
684
+ </>
639
685
  </CapRow>
640
686
  </>
641
687
  )}
@@ -665,14 +711,18 @@ export const SmsTraiCreate = (props) => {
665
711
  />
666
712
  <InstructionComp
667
713
  number={2}
668
- message={formatMessage(messages.firstRowInstruction)}
714
+ message={formatMessage(messages.uploadLimitInstruction)}
669
715
  />
670
716
  <InstructionComp
671
717
  number={3}
672
- message={formatMessage(messages.secondRowInstruction)}
718
+ message={formatMessage(messages.mandatoryColsInstruction)}
673
719
  />
674
720
  <InstructionComp
675
721
  number={4}
722
+ message={formatMessage(messages.statusInstruction)}
723
+ />
724
+ <InstructionComp
725
+ number={5}
676
726
  message={formatMessage(messages.duplicateEntriesInstruction)}
677
727
  />
678
728
  </div>
@@ -1,11 +1,5 @@
1
- /*
2
- * SmsTrai Messages
3
- *
4
- * This contains all the text for the SmsTrai component.
5
- */
6
1
  import { defineMessages } from 'react-intl';
7
2
  const prefix = 'app.v2containers.SmsTrai.Create';
8
-
9
3
  export default defineMessages({
10
4
  uploadFile: {
11
5
  id: `${prefix}.uploadFile`,
@@ -37,16 +31,20 @@ export default defineMessages({
37
31
  },
38
32
  downloadInstruction: {
39
33
  id: `${prefix}.downloadInstruction`,
40
- defaultMessage: 'Download {link} file',
34
+ defaultMessage: 'Download {link} file.',
41
35
  },
42
- firstRowInstruction: {
43
- id: `${prefix}.firstRowInstruction`,
36
+ uploadLimitInstruction: {
37
+ id: `${prefix}.uploadLimitInstruction`,
38
+ defaultMessage: 'Upload a file of <= 500 rows.',
39
+ },
40
+ mandatoryColsInstruction: {
41
+ id: `${prefix}.mandatoryColsInstruction`,
44
42
  defaultMessage:
45
- 'Please ensure that each template has the following mandatory fields: Template name,Template ID, Type, Sender ID, Approval status, Template message.',
43
+ 'Please ensure that each template has the following mandatory fields: Template name,Template ID, Type, Sender ID, Approval status, Status, Template message.',
46
44
  },
47
- secondRowInstruction: {
48
- id: `${prefix}.secondRowInstruction`,
49
- defaultMessage: 'Only the "Approved" templates will be uploaded.',
45
+ statusInstruction: {
46
+ id: `${prefix}.statusInstruction`,
47
+ defaultMessage: 'Only the "Approved" and “Active” templates will be uploaded.',
50
48
  },
51
49
  duplicateEntriesInstruction: {
52
50
  id: `${prefix}.duplicateEntriesInstruction`,
@@ -54,16 +52,16 @@ export default defineMessages({
54
52
  },
55
53
  fileMinlengthError: {
56
54
  id: `${prefix}.fileMinlengthError`,
57
- defaultMessage: 'Please select a CSV file with minimum 1 row of data and 1 row of headers',
55
+ defaultMessage: 'Please select a CSV file with minimum 1 row of data and 1 row of headers.',
58
56
  },
59
57
  fileMaxlengthError: {
60
58
  id: `${prefix}.fileMaxlengthError`,
61
59
  defaultMessage:
62
60
  'More then 500 records are not allowed for the selected file.',
63
61
  },
64
- invalidFileErrorDescription: {
65
- id: `${prefix}.invalidFileErrorDescription`,
66
- defaultMessage: 'Mandatory fields ({columns}) are required for templates.',
62
+ mandatoryColsErrorDescription: {
63
+ id: `${prefix}.mandatoryColsErrorDescription`,
64
+ defaultMessage: 'Mandatory fields: Template name, Template ID, Type, Sender ID, Approval status, Status and Template message are required for templates.',
67
65
  },
68
66
  repetitiveColsErrorDescription: {
69
67
  id: `${prefix}.repetitiveColsErrorDescription`,
@@ -85,6 +83,11 @@ export default defineMessages({
85
83
  defaultMessage:
86
84
  'Please include mandatory field template message. It can be {templateMessageAliases}.',
87
85
  },
86
+ statusAliasErrorDescription: {
87
+ id: `${prefix}.statusAliasErrorDescription`,
88
+ defaultMessage:
89
+ 'Please include mandatory field status. It can be {statusAliases}.',
90
+ },
88
91
  nonCsvErrorDescription: {
89
92
  id: `${prefix}.nonCsvErrorDescription`,
90
93
  defaultMessage: 'Please select a csv file.',